fish-lsp
Version:
LSP implementation for fish/fish-shell
298 lines (297 loc) • 11.9 kB
JavaScript
;
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');
}