UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

228 lines (227 loc) 7.89 kB
"use strict"; 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; }