UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

132 lines (131 loc) 4.98 kB
"use strict"; 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; }