UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

298 lines (297 loc) 11.9 kB
"use strict"; var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) { if (k2 === undefined) k2 = k; var desc = Object.getOwnPropertyDescriptor(m, k); if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) { desc = { enumerable: true, get: function() { return m[k]; } }; } Object.defineProperty(o, k2, desc); }) : (function(o, m, k, k2) { if (k2 === undefined) k2 = k; o[k2] = m[k]; })); var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) { Object.defineProperty(o, "default", { enumerable: true, value: v }); }) : function(o, v) { o["default"] = v; }); var __importStar = (this && this.__importStar) || function (mod) { if (mod && mod.__esModule) return mod; var result = {}; if (mod != null) for (var k in mod) if (k !== "default" && Object.prototype.hasOwnProperty.call(mod, k)) __createBinding(result, mod, k); __setModuleDefault(result, mod); return result; }; Object.defineProperty(exports, "__esModule", { value: true }); exports.isUri = isUri; exports.isPath = isPath; exports.isTextDocument = isTextDocument; exports.isTextDocumentItem = isTextDocumentItem; exports.uriToPath = uriToPath; exports.pathToUri = pathToUri; exports.normalizePath = normalizePath; exports.normalizeFsPath = normalizeFsPath; exports.pathToRelativeFunctionName = pathToRelativeFunctionName; exports.uriInUserFunctions = uriInUserFunctions; exports.nodeToSymbolInformation = nodeToSymbolInformation; exports.nodeToDocumentSymbol = nodeToDocumentSymbol; exports.createRange = createRange; exports.toSelectionRange = toSelectionRange; exports.toLspDocument = toLspDocument; exports.toSymbolKind = toSymbolKind; exports.symbolKindToString = symbolKindToString; exports.uriToReadablePath = uriToReadablePath; exports.symbolKindsFromNode = symbolKindsFromNode; exports.isAutoloadedUriLoadsFunction = isAutoloadedUriLoadsFunction; exports.isAutoloadedUriLoadsFunctionName = isAutoloadedUriLoadsFunctionName; exports.isAutoloadedUriLoadsAliasName = isAutoloadedUriLoadsAliasName; exports.shouldHaveAutoloadedFunction = shouldHaveAutoloadedFunction; exports.formatTextWithIndents = formatTextWithIndents; const vscode_languageserver_1 = require("vscode-languageserver"); const vscode_uri_1 = require("vscode-uri"); const node_types_1 = require("./node-types"); const document_1 = require("../document"); const tree_sitter_1 = require("./tree-sitter"); const LocationNamespace = __importStar(require("./locations")); const os = __importStar(require("os")); const builtins_1 = require("./builtins"); const env_manager_1 = require("./env-manager"); const RE_PATHSEP_WINDOWS = /\\/g; function isUri(stringOrUri) { if (typeof stringOrUri !== 'string') { return false; } const uri = vscode_uri_1.URI.parse(stringOrUri); return vscode_uri_1.URI.isUri(uri); } function isPath(pathOrUri) { return typeof pathOrUri === 'string' && !isUri(pathOrUri); } function isTextDocument(value) { return (typeof value === 'object' && value !== null && typeof value.uri === 'string' && typeof value.languageId === 'string' && typeof value.version === 'number' && typeof value.lineCount === 'number' && typeof value.getText === 'function' && typeof value.positionAt === 'function' && typeof value.offsetAt === 'function' && value.text === undefined); } function isTextDocumentItem(value) { return (typeof value === 'object' && value !== null && typeof value.uri === 'string' && typeof value.languageId === 'string' && typeof value.version === 'number' && typeof value.text === 'string' && value.getText === undefined && value.positionAt === undefined && value.offsetAt === undefined && value.lineCount === undefined); } function uriToPath(stringUri) { const uri = vscode_uri_1.URI.parse(stringUri); return normalizeFsPath(uri.fsPath); } function pathToUri(filepath, documents) { if (filepath.startsWith('zipfile:')) { return filepath; } const fileUri = vscode_uri_1.URI.file(filepath); const normalizedFilepath = normalizePath(fileUri.fsPath); const document = documents && documents.get(normalizedFilepath); return document ? document.uri : fileUri.toString(); } function normalizePath(filePath) { const fsPath = vscode_uri_1.URI.file(filePath).fsPath; return normalizeFsPath(fsPath); } function normalizeFsPath(fsPath) { return fsPath.replace(RE_PATHSEP_WINDOWS, '/'); } function pathToRelativeFunctionName(filepath) { const relativeName = filepath.split('/').at(-1) || filepath; return relativeName.replace('.fish', ''); } function uriInUserFunctions(uri) { const path = uriToPath(uri); return path?.startsWith(`${os.homedir}/.config/fish`) || false; } function nodeToSymbolInformation(node, uri) { let name = node.text; const kind = toSymbolKind(node); const range = (0, tree_sitter_1.getRange)(node); switch (kind) { case vscode_languageserver_1.SymbolKind.Namespace: name = pathToRelativeFunctionName(uri); break; case vscode_languageserver_1.SymbolKind.Function: case vscode_languageserver_1.SymbolKind.Variable: case vscode_languageserver_1.SymbolKind.File: case vscode_languageserver_1.SymbolKind.Class: case vscode_languageserver_1.SymbolKind.Null: default: break; } return vscode_languageserver_1.SymbolInformation.create(name, kind, range, uri); } function nodeToDocumentSymbol(node) { const name = node.text; let detail = node.text; const kind = toSymbolKind(node); let range = (0, tree_sitter_1.getRange)(node); const selectionRange = (0, tree_sitter_1.getRange)(node); const children = []; let parent = node.parent || node; switch (kind) { case vscode_languageserver_1.SymbolKind.Variable: parent = (0, node_types_1.findParentVariableDefinitionKeyword)(node) || node; detail = (0, tree_sitter_1.getPrecedingComments)(parent); range = (0, tree_sitter_1.getRange)(parent); break; case vscode_languageserver_1.SymbolKind.Function: detail = (0, tree_sitter_1.getPrecedingComments)(parent); range = (0, tree_sitter_1.getRange)(parent); break; case vscode_languageserver_1.SymbolKind.File: case vscode_languageserver_1.SymbolKind.Class: case vscode_languageserver_1.SymbolKind.Namespace: case vscode_languageserver_1.SymbolKind.Null: default: break; } return vscode_languageserver_1.DocumentSymbol.create(name, detail, kind, range, selectionRange, children); } function createRange(startLine, startCharacter, endLine, endCharacter) { return { start: { line: startLine, character: startCharacter, }, end: { line: endLine, character: endCharacter, }, }; } function toSelectionRange(range) { const span = LocationNamespace.Range.toTextSpan(range.range); return vscode_languageserver_1.SelectionRange.create(LocationNamespace.Range.fromTextSpan(span), range.parent ? toSelectionRange(range.parent) : undefined); } function toLspDocument(filename, content) { const doc = vscode_languageserver_1.TextDocumentItem.create(pathToUri(filename), 'fish', 0, content); return new document_1.LspDocument(doc); } function toSymbolKind(node) { if ((0, node_types_1.isVariable)(node)) { return vscode_languageserver_1.SymbolKind.Variable; } else if ((0, node_types_1.isFunctionDefinitionName)(node)) { return vscode_languageserver_1.SymbolKind.Function; } else if ((0, node_types_1.isString)(node)) { return vscode_languageserver_1.SymbolKind.String; } else if ((0, node_types_1.isProgram)(node) || (0, node_types_1.isFunctionDefinition)(node) || (0, node_types_1.isStatement)(node)) { return vscode_languageserver_1.SymbolKind.Namespace; } else if ((0, builtins_1.isBuiltin)(node.text) || (0, node_types_1.isCommandName)(node) || (0, node_types_1.isCommand)(node)) { return vscode_languageserver_1.SymbolKind.Class; } return vscode_languageserver_1.SymbolKind.Null; } function symbolKindToString(kind) { switch (kind) { case vscode_languageserver_1.SymbolKind.Variable: return 'variable'; case vscode_languageserver_1.SymbolKind.Function: return 'function'; case vscode_languageserver_1.SymbolKind.String: return 'string'; case vscode_languageserver_1.SymbolKind.Namespace: return 'namespace'; case vscode_languageserver_1.SymbolKind.Class: return 'class'; case vscode_languageserver_1.SymbolKind.Null: return 'null'; default: return 'other'; } } function uriToReadablePath(uri) { const path = uriToPath(uri); const autoloadedKeys = env_manager_1.env.getAutoloadedKeys(); for (const key of autoloadedKeys) { const values = env_manager_1.env.getAsArray(key); for (const value of values) { if (path.startsWith(value)) { return path.replace(value, `$${key}`); } } } const homeDir = os.homedir(); if (path.startsWith(homeDir)) { return path.replace(homeDir, '~'); } return path; } function symbolKindsFromNode(node) { const kindType = toSymbolKind(node); const kindString = symbolKindToString(kindType); return { kindType, kindString, }; } function isAutoloadedUriLoadsFunction(document) { const callbackmap = { 'conf.d': (node) => (0, node_types_1.isTopLevelFunctionDefinition)(node) && (0, node_types_1.isFunctionDefinition)(node), config: (node) => (0, node_types_1.isTopLevelFunctionDefinition)(node) && (0, node_types_1.isFunctionDefinition)(node), functions: (node) => { if ((0, node_types_1.isTopLevelFunctionDefinition)(node) && (0, node_types_1.isFunctionDefinition)(node)) { return node.firstChild?.text === document.getAutoLoadName(); } return false; }, completions: (_) => false, '': (_) => false, }; return callbackmap[document.getAutoloadType()]; } function isAutoloadedUriLoadsFunctionName(document) { const callbackmap = { 'conf.d': (node) => (0, node_types_1.isTopLevelFunctionDefinition)(node) && (0, node_types_1.isFunctionDefinitionName)(node), config: (node) => (0, node_types_1.isTopLevelFunctionDefinition)(node) && (0, node_types_1.isFunctionDefinitionName)(node), functions: (node) => { if ((0, node_types_1.isTopLevelFunctionDefinition)(node) && (0, node_types_1.isFunctionDefinitionName)(node)) { return node?.text === document.getAutoLoadName(); } return false; }, completions: (_) => false, '': (_) => false, }; return callbackmap[document.getAutoloadType()]; } function isAutoloadedUriLoadsAliasName(document) { const callbackmap = { 'conf.d': (node) => (0, node_types_1.isTopLevelDefinition)(node), config: (node) => (0, node_types_1.isTopLevelDefinition)(node), functions: (_) => false, completions: (_) => false, '': (_) => false, }; return callbackmap[document.getAutoloadType()]; } function shouldHaveAutoloadedFunction(document) { return 'functions' === document.getAutoloadType(); } function formatTextWithIndents(doc, line, text) { const indent = doc.getIndentAtLine(line); return text .split('\n') .map(line => indent + line) .join('\n'); }