fish-lsp
Version:
LSP implementation for fish/fish-shell
228 lines (227 loc) • 7.89 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getDocumentationResolver = getDocumentationResolver;
exports.getFunctionDocString = getFunctionDocString;
exports.getStaticDocString = getStaticDocString;
exports.getAbbrDocString = getAbbrDocString;
exports.getBuiltinDocString = getBuiltinDocString;
exports.getAliasDocString = getAliasDocString;
exports.getEventHandlerDocString = getEventHandlerDocString;
exports.getVariableDocString = getVariableDocString;
exports.getCommandDocString = getCommandDocString;
const types_1 = require("./types");
const exec_1 = require("../exec");
const markdown_builder_1 = require("../markdown-builder");
async function getDocumentationResolver(item) {
let docString = ['```fish', item.documentation.toString(), '```'].join('\n');
if (!item.local) {
switch (item.fishKind) {
case types_1.FishCompletionItemKind.ABBR:
docString = await getAbbrDocString(item.label) ?? docString;
break;
case types_1.FishCompletionItemKind.ALIAS:
docString = await getAliasDocString(item.label, item.documentation.toString() || `alias ${item.label}`) ?? docString;
break;
case types_1.FishCompletionItemKind.COMBINER:
case types_1.FishCompletionItemKind.STATEMENT:
case types_1.FishCompletionItemKind.BUILTIN:
docString = await getBuiltinDocString(item.label) ?? docString;
break;
case types_1.FishCompletionItemKind.COMMAND:
docString = await getCommandDocString(item.label) ?? docString;
break;
case types_1.FishCompletionItemKind.FUNCTION:
docString = await getFunctionDocString(item.label) ?? `(${markdown_builder_1.md.bold('function')}) ${item.label}`;
break;
case types_1.FishCompletionItemKind.VARIABLE:
docString = await getVariableDocString(item.label) ?? docString;
break;
case types_1.FishCompletionItemKind.EVENT:
docString = await getEventHandlerDocString(item.documentation) ?? docString;
break;
case types_1.FishCompletionItemKind.COMMENT:
case types_1.FishCompletionItemKind.SHEBANG:
case types_1.FishCompletionItemKind.DIAGNOSTIC:
docString = item.documentation.toString();
break;
case types_1.FishCompletionItemKind.STATUS:
case types_1.FishCompletionItemKind.WILDCARD:
case types_1.FishCompletionItemKind.REGEX:
case types_1.FishCompletionItemKind.FORMAT_STR:
case types_1.FishCompletionItemKind.ESC_CHARS:
case types_1.FishCompletionItemKind.PIPE:
docString ??= await getStaticDocString(item);
break;
case types_1.FishCompletionItemKind.ARGUMENT:
docString = await buildArgumentDocString(item);
break;
case types_1.FishCompletionItemKind.EMPTY:
default:
break;
}
}
if (item.local) {
return {
kind: 'markdown',
value: item.documentation.toString(),
};
}
return {
kind: 'markdown',
value: docString,
};
}
async function getFunctionDocString(name) {
function formatTitle(title) {
const ensured = ensureMinLength(title, 5, '');
const [path, autoloaded, line, scope, description] = ensured;
return [
`__\`${path}\`__`,
`- autoloaded: ${autoloaded === 'autoloaded' ? '_true_' : '_false_'}`,
`- line: _${line}_`,
`- scope: _${scope}_`,
`${description}`,
].map((str) => str.trim()).filter(l => l.trim().length).join('\n');
}
const [title, body] = await Promise.all([
(0, exec_1.execCmd)(`functions -D -v ${name}`),
(0, exec_1.execCmd)(`functions --no-details ${name}`),
]);
return [
formatTitle(title),
'___',
'```fish',
body.join('\n'),
'```',
].join('\n') || '';
}
async function getStaticDocString(item) {
let result = [
'```text',
`${item.label} - ${item.documentation}`,
'```',
].join('\n');
item.examples?.forEach((example) => {
result += [
'___',
'```fish',
`# ${example.title}`,
example.shellText,
'```',
].join('\n');
});
return result;
}
async function buildArgumentDocString(item) {
if (!item.detail) {
return markdown_builder_1.md.codeBlock('fish', item.documentation.toString());
}
return [
markdown_builder_1.md.codeBlock('fish', item.documentation.toString()),
markdown_builder_1.md.separator(),
item.detail,
].join('\n');
}
async function getAbbrDocString(name) {
const items = await (0, exec_1.execCmd)('abbr --show | string split \' -- \' -m1 -f2');
function getAbbr(items) {
const start = `${name} `;
for (const item of items) {
if (item.startsWith(start)) {
return [start.trimEnd(), item.slice(start.length)];
}
}
return ['', ''];
}
const [title, body] = getAbbr(items);
return [
`Abbreviation: \`${title}\``,
'___',
'```fish',
body.trimEnd(),
'```',
].join('\n') || '';
}
async function getBuiltinDocString(name) {
const cmdDocs = await (0, exec_1.execCommandDocs)(name);
if (!cmdDocs) {
return undefined;
}
const splitDocs = cmdDocs.split('\n');
const startIndex = splitDocs.findIndex((line) => line.trim() === 'NAME');
return [
`__${name.toUpperCase()}__ - _https://fishshell.com/docs/current/cmds/${name.trim()}.html_`,
'___',
'```man',
splitDocs.slice(startIndex).join('\n'),
'```',
].join('\n');
}
async function getAliasDocString(label, line) {
return [
`Alias: _${label}_`,
'___',
'```fish',
line.split('\t')[1],
'```',
].join('\n');
}
async function getEventHandlerDocString(documentation) {
const [label, ...commandArr] = documentation.split(/\s/, 2);
const command = commandArr.join(' ');
const doc = await getFunctionDocString(command);
if (!doc) {
return [
`Event: \`${label}\``,
'___',
`Event handler for \`${command}\``,
].join('\n');
}
return [
`Event: \`${label}\``,
'___',
doc,
].join('\n');
}
async function getVariableDocString(name) {
const vName = name.startsWith('$') ? name.slice(name.lastIndexOf('$')) : name;
const out = await (0, exec_1.execCmd)(`set --show --long ${vName}`);
const { first, middle, last } = out.reduce((acc, curr, idx, arr) => {
if (idx === 0) {
acc.first = curr;
}
else if (idx === arr.length - 1) {
acc.last = curr;
}
else {
acc.middle.push(curr);
}
return acc;
}, { first: '', middle: [], last: '' });
return [
first,
'___',
middle.join('\n'),
'___',
last,
].join('\n');
}
async function getCommandDocString(name) {
const cmdDocs = await (0, exec_1.execCommandDocs)(name);
if (!cmdDocs) {
return undefined;
}
const splitDocs = cmdDocs.split('\n');
const startIndex = splitDocs.findIndex((line) => line.trim() === 'NAME');
return [
'```man',
splitDocs.slice(startIndex).join('\n'),
'```',
].join('\n');
}
function ensureMinLength(arr, minLength, fillValue) {
while (arr.length < minLength) {
arr.push(fillValue);
}
return arr;
}