fish-lsp
Version:
LSP implementation for fish/fish-shell
141 lines (140 loc) • 4.84 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getFlagCommand = getFlagCommand;
exports.getFlagDocumentationAsMarkup = getFlagDocumentationAsMarkup;
exports.getFlagDocumentationString = getFlagDocumentationString;
const node_1 = require("vscode-languageserver-protocol/node");
const exec_1 = require("./exec");
const findFirstFlagIndex = (cmdline) => {
for (let i = 0; i < cmdline.length; i++) {
const arg = cmdline[i];
if (arg.startsWith('-')) {
return i;
}
}
return -1;
};
const findFlagStopToken = (inputArray) => {
for (let i = 0; i < inputArray.length; i++) {
const arg = inputArray[i];
if (arg === '--') {
return i;
}
}
return -1;
};
const ensureEndOfArgs = (inputArray) => {
const stopToken = findFlagStopToken(inputArray);
return stopToken === -1 ? inputArray : inputArray.slice(0, stopToken);
};
const removeStrings = (input) => {
let output = input.replace(/^\s+/, '');
output = output.replace(/^if\s+/, '');
output = output.replace(/^else {2}if\s+/, '');
output = output.replace(/"(.+)"/, '');
output = output.replace(/'(.+)'/, '');
return output;
};
const tokenizeInput = (input) => {
const removed = removeStrings(input);
const tokenized = ensureEndOfArgs(removed.split(/\s/));
return tokenized.filter(t => t.length > 0);
};
const generateShellCommandToComplete = (cmdline) => {
const firstFlag = findFirstFlagIndex(cmdline);
const cmd = cmdline.slice(0, firstFlag);
cmd.push('-');
return cmd.join(' ');
};
const outputFlags = async (inputArray) => {
const toExec = generateShellCommandToComplete(inputArray);
const output = await (0, exec_1.execCompleteLine)(toExec);
return output.filter((line) => line.startsWith('-'));
};
const shortFlag = (flag) => {
return flag.startsWith('-') && !flag.startsWith('--');
};
const longFlag = (flag) => {
return flag.startsWith('--') && flag.length > 2;
};
const hasUnixFlags = (allFlagLines) => {
for (const line of allFlagLines) {
const [flag, _doc] = line.split('\t') || [];
if (!flag) {
continue;
}
if (shortFlag(flag) && flag.length > 2) {
return true;
}
}
return false;
};
const parseInputFlags = (inputArray, separateShort) => {
const result = [];
for (let i = 0; i < inputArray.length; i++) {
const arg = inputArray[i];
if (arg && shortFlag(arg)) {
if (separateShort) {
const shortFlags = arg.slice(1).split('').map(ch => '-' + ch);
result.push(...shortFlags);
}
else {
result.push(arg);
}
}
else if (arg && longFlag(arg)) {
result.push(arg);
}
}
return result;
};
const findMatchingFlags = (inputFlags, allFlagLines) => {
const output = [];
for (const line of allFlagLines) {
const [flag, _doc] = line.split('\t');
if (flag && inputFlags.includes(flag)) {
output.push(line);
}
}
return output;
};
async function getFlagDocumentationStrings(input) {
const splitInputArray = tokenizeInput(input);
const outputFlagLines = await outputFlags(splitInputArray);
const shouldSeparateShortFlags = !hasUnixFlags(outputFlagLines);
const parsedInputFlags = parseInputFlags(splitInputArray, shouldSeparateShortFlags);
const matchingFlags = findMatchingFlags(parsedInputFlags, outputFlagLines);
return matchingFlags
.map(line => line.split('\t'))
.map(([flag, doc]) => `**\`${flag}\`** *\`${doc}\`*`)
.reverse();
}
function getFlagCommand(input) {
const splitInputArray = tokenizeInput(input);
const firstFlag = findFirstFlagIndex(splitInputArray);
let cmd = splitInputArray;
if (firstFlag !== -1) {
cmd = splitInputArray.slice(0, firstFlag);
}
return cmd.join(' ');
}
async function getFlagDocumentationAsMarkup(input) {
const docString = await getFlagDocumentationString(input);
return {
kind: node_1.MarkupKind.Markdown,
value: docString,
};
}
async function getFlagDocumentationString(input) {
const cmdName = getFlagCommand(input);
const flagLines = await getFlagDocumentationStrings(input);
const flagString = flagLines.join('\n');
const manpage = await (0, exec_1.execCommandDocs)(cmdName.replaceAll(' ', '-'));
const flagDoc = flagString.trim().length > 0 ? ['___', ' ***Flags***', flagString].join('\n') : '';
const manDoc = manpage.trim().length > 0 ? ['___', '```man', manpage, '```'].join('\n') : '';
const afterString = [flagDoc, manDoc].join('\n').trim();
return [
`***\`${cmdName}\`***`,
afterString,
].join('\n');
}