fish-lsp
Version:
LSP implementation for fish/fish-shell
132 lines (131 loc) • 4.98 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.getStatusInlayHints = getStatusInlayHints;
exports.findReturnNodes = findReturnNodes;
exports.getReturnStatusValue = getReturnStatusValue;
exports.getGlobalReferencesInlayHints = getGlobalReferencesInlayHints;
exports.invalidateInlayHintsCache = invalidateInlayHintsCache;
exports.getAllInlayHints = getAllInlayHints;
const vscode_languageserver_1 = require("vscode-languageserver");
const snippets_1 = require("./utils/snippets");
const node_types_1 = require("./utils/node-types");
const tree_sitter_1 = require("./utils/tree-sitter");
const references_1 = require("./references");
const logger_1 = require("./logger");
function getStatusInlayHints(root) {
const hints = [];
const returnStatements = (0, tree_sitter_1.findChildNodes)(root, node_types_1.isReturn);
for (const returnStmt of returnStatements) {
const status = getReturnStatusValue(returnStmt);
if (status) {
hints.push({
position: {
line: returnStmt.endPosition.row,
character: returnStmt.endPosition.column,
},
kind: vscode_languageserver_1.InlayHintKind.Parameter,
label: ` → ${status.inlineValue}`,
paddingLeft: true,
tooltip: {
kind: 'markdown',
value: `Status code ${status.tooltip.code}: ${status.tooltip.description}`,
},
});
}
}
return hints;
}
function findReturnNodes(root) {
const nodes = [];
const queue = [root];
while (queue.length > 0) {
const node = queue.shift();
if ((0, node_types_1.isReturn)(node)) {
nodes.push(node);
}
queue.push(...node.children);
}
return nodes;
}
function getStatusDescription(status) {
const statusMap = {
0: 'Success',
1: 'General error',
2: 'Misuse of shell builtins',
126: 'Command invoked cannot execute',
127: 'Command not found',
128: 'Invalid exit argument',
130: 'Script terminated by Control-C',
};
return statusMap[status] || `Exit code ${status}`;
}
function getReturnStatusValue(returnNode) {
const statusArg = returnNode.children.find(child => !(0, node_types_1.isCommand)(child) && !(0, node_types_1.isCommandName)(child) && child.type === 'integer');
if (!statusArg?.text)
return undefined;
const statusInfo = snippets_1.PrebuiltDocumentationMap.getByName(statusArg.text).pop();
const statusInfoShort = getStatusDescription(statusArg.text);
return statusInfoShort ? {
inlineValue: statusInfoShort,
tooltip: {
code: statusInfo?.name || statusArg.text,
description: statusInfo?.description || statusInfoShort,
},
} : undefined;
}
const inlayHintsCache = new Map();
const INLAY_HINTS_TTL = 1500;
function getCachedInlayHints(uri, documentVersion) {
const entry = inlayHintsCache.get(uri);
if (!entry)
return undefined;
if (entry.version !== documentVersion ||
Date.now() - entry.timestamp > INLAY_HINTS_TTL) {
inlayHintsCache.delete(uri);
return undefined;
}
return entry.hints;
}
function setCachedInlayHints(uri, hints, documentVersion) {
inlayHintsCache.set(uri, {
hints,
timestamp: Date.now(),
version: documentVersion,
});
}
function getGlobalReferencesInlayHints(analyzer, document) {
const cachedHints = getCachedInlayHints(document.uri, document.version);
if (cachedHints) {
logger_1.logger?.log('Using cached inlay hints');
return cachedHints;
}
logger_1.logger?.log('Computing new inlay hints');
const hints = analyzer.getFlatDocumentSymbols(document.uri)
.filter(symbol => symbol.scope.scopeTag === 'global' || symbol.scope.scopeTag === 'universal')
.map(symbol => {
const referenceCount = (0, references_1.getReferences)(document, symbol.selectionRange.start).length;
return {
position: document.getLineEnd(symbol.selectionRange.start.line),
kind: vscode_languageserver_1.InlayHintKind.Type,
label: `${referenceCount} reference${referenceCount === 1 ? '' : 's'}`,
paddingLeft: true,
tooltip: {
kind: 'markdown',
value: `${symbol.name} is referenced ${referenceCount} time${referenceCount === 1 ? '' : 's'} across the workspace`,
},
};
});
setCachedInlayHints(document.uri, hints, document.version);
return hints;
}
function invalidateInlayHintsCache(uri) {
inlayHintsCache.delete(uri);
}
function getAllInlayHints(analyzer, document) {
const results = [];
const root = analyzer.getRootNode(document.uri);
if (root) {
results.push(...getStatusInlayHints(root));
}
return results;
}