fish-lsp
Version:
LSP implementation for fish/fish-shell
674 lines (673 loc) • 32.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.currentDocument = exports.enableWorkspaceFolderSupport = exports.hasWorkspaceFolderCapability = void 0;
const analyze_1 = require("./analyze");
const vscode_languageserver_1 = require("vscode-languageserver");
const document_1 = require("./document");
const formatting_1 = require("./formatting");
const logger_1 = require("./logger");
const translation_1 = require("./utils/translation");
const tree_sitter_1 = require("./utils/tree-sitter");
const hover_1 = require("./hover");
const documentation_cache_1 = require("./utils/documentation-cache");
const workspace_1 = require("./utils/workspace");
const workspace_manager_1 = require("./utils/workspace-manager");
const symbol_1 = require("./parsing/symbol");
const pager_1 = require("./utils/completion/pager");
const documentation_1 = require("./utils/completion/documentation");
const list_1 = require("./utils/completion/list");
const snippets_1 = require("./utils/snippets");
const node_types_1 = require("./utils/node-types");
const config_1 = require("./config");
const documentation_2 = require("./documentation");
const signature_1 = require("./signature");
const startup_cache_1 = require("./utils/completion/startup-cache");
const document_highlight_1 = require("./document-highlight");
const comment_completions_1 = require("./utils/completion/comment-completions");
const code_action_handler_1 = require("./code-actions/code-action-handler");
const command_1 = require("./command");
const inlay_hints_1 = require("./inlay-hints");
const process_env_1 = require("./utils/process-env");
const flatten_1 = require("./utils/flatten");
const argparse_1 = require("./parsing/argparse");
const source_1 = require("./parsing/source");
const references_1 = require("./references");
const renames_1 = require("./renames");
const code_lens_1 = require("./code-lens");
const startup_1 = require("./utils/startup");
exports.hasWorkspaceFolderCapability = false;
const enableWorkspaceFolderSupport = () => {
exports.hasWorkspaceFolderCapability = true;
};
exports.enableWorkspaceFolderSupport = enableWorkspaceFolderSupport;
exports.currentDocument = null;
class FishServer {
completion;
completionMap;
documentationCache;
static async create(connection, params) {
await (0, process_env_1.setupProcessEnvExecFile)();
const capabilities = params.capabilities;
const initializeResult = config_1.Config.initialize(params, connection);
logger_1.logger.log({
server: 'FishServer',
rootUri: params.rootUri,
rootPath: params.rootPath,
workspaceFolders: params.workspaceFolders,
});
exports.hasWorkspaceFolderCapability = !!(capabilities.workspace && !!capabilities.workspace.workspaceFolders);
logger_1.logger.debug('hasWorkspaceFolderCapability', exports.hasWorkspaceFolderCapability);
const initializeUris = (0, workspace_1.getWorkspacePathsFromInitializationParams)(params);
logger_1.logger.info('initializeUris', initializeUris);
const [cache, _workspaces, completionsMap,] = await Promise.all([
(0, documentation_cache_1.initializeDocumentationCache)(),
(0, workspace_1.initializeDefaultFishWorkspaces)(...initializeUris),
startup_cache_1.CompletionItemMap.initialize(),
]);
await analyze_1.Analyzer.initialize();
const completions = await (0, pager_1.initializeCompletionPager)(logger_1.logger, completionsMap);
const server = new FishServer(completions, completionsMap, cache);
server.register(connection);
return { server, initializeResult };
}
initializeParams;
features;
clientSupportsShowDocument;
backgroundAnalysisComplete;
constructor(completion, completionMap, documentationCache) {
this.completion = completion;
this.completionMap = completionMap;
this.documentationCache = documentationCache;
this.features = { codeActionDisabledSupport: true };
this.clientSupportsShowDocument = false;
this.backgroundAnalysisComplete = false;
}
register(connection) {
const { onCodeAction } = (0, code_action_handler_1.codeActionHandlers)(document_1.documents, analyze_1.analyzer);
const documentHighlightHandler = (0, document_highlight_1.getDocumentHighlights)(analyze_1.analyzer);
const commandCallback = (0, command_1.createExecuteCommandHandler)(connection, document_1.documents, analyze_1.analyzer);
connection.onDidOpenTextDocument(this.didOpenTextDocument.bind(this));
connection.onDidChangeTextDocument(this.didChangeTextDocument.bind(this));
connection.onDidCloseTextDocument(this.didCloseTextDocument.bind(this));
connection.onDidSaveTextDocument(this.didSaveTextDocument.bind(this));
connection.onCompletion(this.onCompletion.bind(this));
connection.onCompletionResolve(this.onCompletionResolve.bind(this));
connection.onDocumentSymbol(this.onDocumentSymbols.bind(this));
connection.onWorkspaceSymbol(this.onWorkspaceSymbol.bind(this));
connection.onWorkspaceSymbolResolve(this.onWorkspaceSymbolResolve.bind(this));
connection.onDefinition(this.onDefinition.bind(this));
connection.onImplementation(this.onImplementation.bind(this));
connection.onReferences(this.onReferences.bind(this));
connection.onHover(this.onHover.bind(this));
connection.onRenameRequest(this.onRename.bind(this));
connection.onDocumentFormatting(this.onDocumentFormatting.bind(this));
connection.onDocumentRangeFormatting(this.onDocumentRangeFormatting.bind(this));
connection.onDocumentOnTypeFormatting(this.onDocumentTypeFormatting.bind(this));
connection.onCodeAction(onCodeAction);
connection.onCodeLens(this.onCodeLens.bind(this));
connection.onFoldingRanges(this.onFoldingRanges.bind(this));
connection.onDocumentHighlight(documentHighlightHandler);
connection.languages.inlayHint.on(this.onInlayHints.bind(this));
connection.onSignatureHelp(this.onShowSignatureHelp.bind(this));
connection.onExecuteCommand(commandCallback);
connection.onInitialized(this.onInitialized.bind(this));
connection.onShutdown(this.onShutdown.bind(this));
logger_1.logger.log({ 'server.register': 'registered' });
}
async didOpenTextDocument(params) {
this.logParams('didOpenTextDocument', params);
const path = (0, translation_1.uriToPath)(params.textDocument.uri);
const doc = document_1.documents.openPath(path, params.textDocument);
workspace_manager_1.workspaceManager.handleOpenDocument(doc);
exports.currentDocument = doc;
this.analyzeDocument({ uri: doc.uri });
workspace_manager_1.workspaceManager.handleUpdateDocument(doc);
if (workspace_manager_1.workspaceManager.needsAnalysis() && workspace_manager_1.workspaceManager.allAnalysisDocuments().length > 0) {
const progress = await startup_1.connection.window.createWorkDoneProgress();
progress.begin('[fish-lsp] analysis');
await workspace_manager_1.workspaceManager.analyzePendingDocuments(progress, (str) => logger_1.logger.info('didOpen', str));
progress.done();
}
}
async didChangeTextDocument(params) {
this.logParams('didChangeTextDocument', params);
const progress = await startup_1.connection.window.createWorkDoneProgress();
const path = (0, translation_1.uriToPath)(params.textDocument.uri);
let doc = document_1.documents.get(path);
if (!doc) {
doc = analyze_1.analyzer.analyzePath(path)?.document;
}
if (!doc) {
logger_1.logger.warning('didChangeTextDocument: document not found', { path });
return;
}
exports.currentDocument = doc;
doc = doc.update(params.contentChanges);
document_1.documents.set(doc);
this.analyzeDocument({ uri: doc.uri });
if (!this.backgroundAnalysisComplete) {
await workspace_manager_1.workspaceManager.analyzePendingDocuments(progress);
progress.done();
return;
}
await workspace_manager_1.workspaceManager.analyzePendingDocuments();
progress.done();
}
didCloseTextDocument(params) {
this.logParams('didCloseTextDocument', params);
workspace_manager_1.workspaceManager.handleCloseDocument(params.textDocument.uri);
}
async didSaveTextDocument(params) {
this.logParams('didSaveTextDocument', params);
const path = (0, translation_1.uriToPath)(params.textDocument.uri);
const doc = document_1.documents.get(path);
if (doc) {
this.analyzeDocument({ uri: doc.uri });
workspace_manager_1.workspaceManager.handleOpenDocument(doc);
workspace_manager_1.workspaceManager.handleUpdateDocument(doc);
await workspace_manager_1.workspaceManager.analyzePendingDocuments();
}
}
async onShutdown() {
workspace_manager_1.workspaceManager.clear();
document_1.documents.clear();
exports.currentDocument = null;
this.backgroundAnalysisComplete = false;
}
async onInitialized(params) {
logger_1.logger.log('onInitialized', params);
if (exports.hasWorkspaceFolderCapability) {
startup_1.connection.workspace.onDidChangeWorkspaceFolders(event => {
logger_1.logger.info({
'connection.workspace.onDidChangeWorkspaceFolders': 'analyzer.onInitialized',
added: event.added.map(folder => folder.name),
removed: event.removed.map(folder => folder.name),
hasWorkspaceFolderCapability: exports.hasWorkspaceFolderCapability,
});
this.handleWorkspaceFolderChanges(event);
});
}
const result = await startup_1.connection.window.createWorkDoneProgress().then(async (progress) => {
progress.begin('[fish-lsp] analyzing workspaces');
const { totalDocuments } = await workspace_manager_1.workspaceManager.analyzePendingDocuments(progress, (str) => logger_1.logger.info('onInitialized', str));
progress.done();
this.backgroundAnalysisComplete = true;
return totalDocuments;
});
return {
result,
};
}
async handleWorkspaceFolderChanges(event) {
this.logParams('handleWorkspaceFolderChanges', event);
const progress = await startup_1.connection.window.createWorkDoneProgress();
progress.begin(`[fish-lsp] analyzing workspaces [${event.added.map(s => s.name).join(',')}] added`);
workspace_manager_1.workspaceManager.handleWorkspaceChangeEvent(event, progress);
workspace_manager_1.workspaceManager.analyzePendingDocuments(progress);
}
onCommand(params) {
const callback = (0, command_1.createExecuteCommandHandler)(startup_1.connection, document_1.documents, analyze_1.analyzer);
return callback(params);
}
async onCompletion(params) {
this.logParams('onCompletion', params);
if (!this.backgroundAnalysisComplete) {
return await this.completion.completeEmpty([]);
}
const { doc, path, current } = this.getDefaults(params);
let list = list_1.FishCompletionList.empty();
if (!path || !doc) {
logger_1.logger.logAsJson('onComplete got [NOT FOUND]: ' + path);
return this.completion.empty();
}
const symbols = analyze_1.analyzer.allSymbolsAccessibleAtPosition(doc, params.position);
const { line, word } = analyze_1.analyzer.parseCurrentLine(doc, params.position);
logger_1.logger.log({
symbols: symbols.map(s => s.name),
});
if (!line)
return await this.completion.completeEmpty(symbols);
const fishCompletionData = {
uri: doc.uri,
position: params.position,
context: {
triggerKind: params.context?.triggerKind || vscode_languageserver_1.CompletionTriggerKind.Invoked,
triggerCharacter: params.context?.triggerCharacter,
},
};
try {
if (line.trim().startsWith('#') && current) {
logger_1.logger.log('completeComment');
return (0, comment_completions_1.buildCommentCompletions)(line, params.position, current, fishCompletionData, word);
}
if (word.trim().endsWith('$') || line.trim().endsWith('$') || word.trim() === '$' && !word.startsWith('$$')) {
logger_1.logger.log('completeVariables');
return this.completion.completeVariables(line, word, fishCompletionData, symbols);
}
}
catch (error) {
logger_1.logger.warning('ERROR: onComplete ' + error?.toString() || 'error');
}
try {
logger_1.logger.log('complete');
list = await this.completion.complete(line, fishCompletionData, symbols);
}
catch (error) {
logger_1.logger.logAsJson('ERROR: onComplete ' + error?.toString() || 'error');
}
return list;
}
async onCompletionResolve(item) {
const fishItem = item;
logger_1.logger.log({ onCompletionResolve: fishItem });
try {
if (fishItem.useDocAsDetail || fishItem.local) {
item.documentation = {
kind: vscode_languageserver_1.MarkupKind.Markdown,
value: fishItem.documentation.toString(),
};
return item;
}
const doc = await (0, documentation_1.getDocumentationResolver)(fishItem);
if (doc) {
item.documentation = doc;
}
}
catch (err) {
logger_1.logger.error('onCompletionResolve', err);
}
return item;
}
onDocumentSymbols(params) {
this.logParams('onDocumentSymbols', params);
const { doc } = this.getDefaultsForPartialParams(params);
if (!doc)
return [];
const symbols = analyze_1.analyzer.cache.getDocumentSymbols(doc.uri);
return (0, symbol_1.filterLastPerScopeSymbol)(symbols).map(s => s.toDocumentSymbol()).filter(s => !!s);
}
get supportHierarchicalDocumentSymbol() {
const textDocument = this.initializeParams?.capabilities.textDocument;
const documentSymbol = textDocument && textDocument.documentSymbol;
return (!!documentSymbol &&
!!documentSymbol.hierarchicalDocumentSymbolSupport);
}
async onWorkspaceSymbol(params) {
this.logParams('onWorkspaceSymbol', params.query);
const symbols = [];
const workspace = workspace_manager_1.workspaceManager.current;
for (const uri of workspace?.allUris || []) {
const doc = document_1.documents.get(uri);
if (doc) {
const docSymbols = analyze_1.analyzer.getFlatDocumentSymbols(doc.uri);
symbols.push(...(0, symbol_1.filterLastPerScopeSymbol)(docSymbols));
}
}
logger_1.logger.log('symbols', {
uris: workspace?.allUris,
symbols: symbols.map(s => s.name),
});
return analyze_1.analyzer.getWorkspaceSymbols(params.query) || [];
}
async onWorkspaceSymbolResolve(symbol) {
this.logParams('onWorkspaceSymbolResolve', symbol);
const { uri } = symbol.location;
const foundSymbol = analyze_1.analyzer.getFlatDocumentSymbols(uri)
.find(s => s.name === symbol.name && s.isGlobal());
if (foundSymbol) {
return {
...foundSymbol.toWorkspaceSymbol(),
...foundSymbol.toDocumentSymbol(),
};
}
return symbol;
}
async onDefinition(params) {
this.logParams('onDefinition', params);
const { doc } = this.getDefaults(params);
if (!doc)
return [];
const newDefs = analyze_1.analyzer.getDefinitionLocation(doc, params.position);
for (const location of newDefs) {
workspace_manager_1.workspaceManager.handleOpenDocument(location.uri);
workspace_manager_1.workspaceManager.handleUpdateDocument(location.uri);
}
if (workspace_manager_1.workspaceManager.needsAnalysis()) {
await workspace_manager_1.workspaceManager.analyzePendingDocuments();
}
return newDefs;
}
async onReferences(params) {
this.logParams('onReference', params);
const { doc } = this.getDefaults(params);
if (!doc)
return [];
const progress = await startup_1.connection.window.createWorkDoneProgress();
const defSymbol = analyze_1.analyzer.getDefinition(doc, params.position);
if (!defSymbol) {
logger_1.logger.log('onReferences: no definition found at position', params.position);
return [];
}
const results = (0, references_1.getReferences)(defSymbol.document, defSymbol.toPosition(), {
reporter: progress,
});
logger_1.logger.info({
onReferences: 'found references',
uri: defSymbol.uri,
count: results.length,
position: params.position,
symbol: defSymbol.name,
});
if (results.length === 0) {
logger_1.logger.warning('onReferences: no references found', { uri: params.textDocument.uri, position: params.position });
return [];
}
return results;
}
async onImplementation(params) {
this.logParams('onImplementation', params);
const { doc } = this.getDefaults(params);
if (!doc)
return [];
const symbols = analyze_1.analyzer.cache.getDocumentSymbols(doc.uri);
const lastSymbols = (0, symbol_1.filterLastPerScopeSymbol)(symbols);
logger_1.logger.log('symbols', (0, symbol_1.formatFishSymbolTree)(lastSymbols));
const result = analyze_1.analyzer.getImplementation(doc, params.position);
logger_1.logger.log('implementationResult', { result });
return result;
}
async onHover(params) {
this.logParams('onHover', params);
const { doc, path, root, current } = this.getDefaults(params);
if (!doc || !path || !root || !current) {
return null;
}
let result = null;
if ((0, source_1.isSourceCommandArgumentName)(current)) {
result = (0, documentation_2.handleSourceArgumentHover)(analyze_1.analyzer, current);
if (result)
return result;
}
if (current.parent && (0, source_1.isSourceCommandArgumentName)(current.parent)) {
result = (0, documentation_2.handleSourceArgumentHover)(analyze_1.analyzer, current.parent);
if (result)
return result;
}
if ((0, node_types_1.isAliasDefinitionName)(current)) {
result = analyze_1.analyzer.getDefinition(doc, params.position)?.toHover(doc.uri) || null;
if (result)
return result;
}
if ((0, argparse_1.isArgparseVariableDefinitionName)(current)) {
logger_1.logger.log('isArgparseDefinition');
result = analyze_1.analyzer.getDefinition(doc, params.position)?.toHover(doc.uri) || null;
return result;
}
if ((0, node_types_1.isOption)(current)) {
result = analyze_1.analyzer.getDefinition(doc, params.position)?.toHover(doc.uri) || null;
if (result)
return result;
result = await (0, hover_1.handleHover)(analyze_1.analyzer, doc, params.position, current, this.documentationCache);
if (result)
return result;
}
const { kindType, kindString } = (0, translation_1.symbolKindsFromNode)(current);
logger_1.logger.log({ currentText: current.text, currentType: current.type, symbolKind: kindString });
const prebuiltSkipType = [
...snippets_1.PrebuiltDocumentationMap.getByType('pipe'),
...(0, node_types_1.isReturnStatusNumber)(current) ? snippets_1.PrebuiltDocumentationMap.getByType('status') : [],
].find(obj => obj.name === current.text);
const isPrebuiltVariableWithoutDefinition = (0, hover_1.getVariableExpansionDocs)(analyze_1.analyzer, doc, params.position);
const prebuiltHover = isPrebuiltVariableWithoutDefinition(current);
if (prebuiltHover)
return prebuiltHover;
const symbolItem = analyze_1.analyzer.getHover(doc, params.position);
if (symbolItem)
return symbolItem;
if (prebuiltSkipType) {
return {
contents: (0, documentation_2.enrichToMarkdown)([
`___${current.text}___ - _${(0, snippets_1.getPrebuiltDocUrl)(prebuiltSkipType)}_`,
'___',
`type - __(${prebuiltSkipType.type})__`,
'___',
`${prebuiltSkipType.description}`,
].join('\n')),
};
}
const definition = analyze_1.analyzer.getDefinition(doc, params.position);
const allowsGlobalDocs = !definition || definition?.isGlobal();
const symbolType = [
'function',
'class',
'variable',
].includes(kindString) ? kindType : undefined;
const globalItem = await this.documentationCache.resolve(current.text.trim(), path, symbolType);
logger_1.logger.log(`this.documentationCache.resolve() found ${!!globalItem}`, { docs: globalItem.docs });
if (globalItem && globalItem.docs && allowsGlobalDocs) {
logger_1.logger.log(globalItem.docs);
return {
contents: {
kind: vscode_languageserver_1.MarkupKind.Markdown,
value: globalItem.docs,
},
};
}
const fallbackHover = await (0, hover_1.handleHover)(analyze_1.analyzer, doc, params.position, current, this.documentationCache);
logger_1.logger.log(fallbackHover?.contents);
return fallbackHover;
}
async onRename(params) {
this.logParams('onRename', params);
const { doc } = this.getDefaults(params);
if (!doc)
return null;
const locations = (0, renames_1.getRenames)(doc, params.position, params.newName);
const changes = {};
for (const location of locations) {
const range = location.range;
const uri = location.uri;
const edits = changes[uri] || [];
edits.push(vscode_languageserver_1.TextEdit.replace(range, location.newText));
changes[uri] = edits;
}
const workspaceEdit = {
changes,
};
return workspaceEdit;
}
async onDocumentFormatting(params) {
this.logParams('onDocumentFormatting', params);
const { doc } = this.getDefaultsForPartialParams(params);
if (!doc)
return [];
const formattedText = await (0, formatting_1.formatDocumentContent)(doc.getText()).catch(error => {
if (config_1.config.fish_lsp_show_client_popups) {
startup_1.connection.window.showErrorMessage(`Failed to format range: ${error}`);
}
return doc.getText();
});
const fullRange = {
start: doc.positionAt(0),
end: doc.positionAt(doc.getText().length),
};
return [vscode_languageserver_1.TextEdit.replace(fullRange, formattedText)];
}
async onDocumentTypeFormatting(params) {
this.logParams('onDocumentTypeFormatting', params);
const { doc } = this.getDefaultsForPartialParams(params);
if (!doc)
return [];
const formattedText = await (0, formatting_1.formatDocumentContent)(doc.getText()).catch(error => {
startup_1.connection.console.error(`Formatting error: ${error}`);
if (config_1.config.fish_lsp_show_client_popups) {
startup_1.connection.window.showErrorMessage(`Failed to format range: ${error}`);
}
return doc.getText();
});
const fullRange = {
start: doc.positionAt(0),
end: doc.positionAt(doc.getText().length),
};
return [vscode_languageserver_1.TextEdit.replace(fullRange, formattedText)];
}
async onDocumentRangeFormatting(params) {
this.logParams('onDocumentRangeFormatting', params);
const { doc } = this.getDefaultsForPartialParams(params);
if (!doc)
return [];
const range = params.range;
const startOffset = doc.offsetAt(range.start);
const endOffset = doc.offsetAt(range.end);
const originalText = doc.getText();
const selectedText = doc.getText().slice(startOffset, endOffset).trimStart();
const allText = await (0, formatting_1.formatDocumentContent)(originalText).catch((error) => {
logger_1.logger.error(`FormattingRange error: ${error}`);
return selectedText;
});
const formattedText = await (0, formatting_1.formatDocumentContent)(selectedText).catch(error => {
logger_1.logger.error(`FormattingRange error: ${error}`, {
input: selectedText,
range: range,
});
if (config_1.config.fish_lsp_show_client_popups) {
startup_1.connection.window.showErrorMessage(`Failed to format range: ${params.textDocument.uri}`);
}
return selectedText;
});
const newDoc = document_1.LspDocument.createTextDocumentItem(doc.uri, allText);
const output = (0, translation_1.formatTextWithIndents)(newDoc, range.start.line, formattedText.trim()) + '\n';
return [
vscode_languageserver_1.TextEdit.replace(params.range, output),
];
}
async onFoldingRanges(params) {
this.logParams('onFoldingRanges', params);
const { path, doc } = this.getDefaultsForPartialParams(params);
if (!doc) {
throw new Error(`The document should not be opened in the folding range, file: ${path}`);
}
const symbols = analyze_1.analyzer.getDocumentSymbols(doc.uri);
const flatSymbols = (0, flatten_1.flattenNested)(...symbols);
logger_1.logger.logPropertiesForEachObject(flatSymbols.filter((s) => s.kind === vscode_languageserver_1.SymbolKind.Function), 'name', 'range');
const folds = flatSymbols
.filter((symbol) => symbol.kind === vscode_languageserver_1.SymbolKind.Function)
.map((symbol) => symbol.toFoldingRange());
folds.forEach((fold) => logger_1.logger.log({ fold }));
return folds;
}
async onInlayHints(params) {
logger_1.logger.log({ params });
const { doc } = this.getDefaultsForPartialParams(params);
if (!doc)
return [];
return (0, inlay_hints_1.getAllInlayHints)(analyze_1.analyzer, doc);
}
async onCodeLens(params) {
logger_1.logger.log('onCodeLens', params);
const path = (0, translation_1.uriToPath)(params.textDocument.uri);
const doc = document_1.documents.get(path);
if (!doc)
return [];
return (0, code_lens_1.getReferenceCountCodeLenses)(analyze_1.analyzer, doc);
}
onShowSignatureHelp(params) {
this.logParams('onShowSignatureHelp', params);
const { doc, path } = this.getDefaults(params);
if (!doc || !path)
return null;
const { line, lineRootNode, lineLastNode } = analyze_1.analyzer.parseCurrentLine(doc, params.position);
if (line.trim() === '')
return null;
const currentCmd = (0, node_types_1.findParentCommand)(lineLastNode);
const aliasSignature = this.completionMap.allOfKinds('alias').find(a => a.label === currentCmd.text);
if (aliasSignature)
return (0, signature_1.getAliasedCompletionItemSignature)(aliasSignature);
const varNode = (0, tree_sitter_1.getChildNodes)(lineRootNode).find(c => (0, node_types_1.isVariableDefinition)(c));
const lastCmd = (0, tree_sitter_1.getChildNodes)(lineRootNode).filter(c => (0, node_types_1.isCommand)(c)).pop();
logger_1.logger.log({ line, lastCmds: lastCmd?.text });
if (varNode && (line.startsWith('set') || line.startsWith('read')) && lastCmd?.text === lineRootNode.text.trim()) {
const varName = varNode.text;
const varDocs = snippets_1.PrebuiltDocumentationMap.getByName(varNode.text);
if (!varDocs.length)
return null;
return {
signatures: [
{
label: varName,
documentation: {
kind: 'markdown',
value: varDocs.map(d => d.description).join('\n'),
},
},
],
activeSignature: 0,
activeParameter: 0,
};
}
if ((0, signature_1.isRegexStringSignature)(line)) {
const signature = (0, signature_1.getDefaultSignatures)();
logger_1.logger.log('signature', signature);
const cursorLineOffset = line.length - lineLastNode.endIndex;
const { activeParameter } = (0, signature_1.findActiveParameterStringRegex)(line, cursorLineOffset);
signature.activeParameter = activeParameter;
return signature;
}
const functionSignature = (0, signature_1.getFunctionSignatureHelp)(analyze_1.analyzer, lineLastNode, line, params.position);
if (functionSignature)
return functionSignature;
return null;
}
clearDiagnostics(document) {
startup_1.connection.sendDiagnostics({ uri: document.uri, diagnostics: [] });
}
analyzeDocument(document) {
const { path, doc: foundDoc } = this.getDefaultsForPartialParams({ textDocument: document });
let analyzedDoc;
if (!foundDoc) {
const pathDoc = analyze_1.analyzer.analyzePath(path);
if (pathDoc) {
analyzedDoc = pathDoc;
}
else {
logger_1.logger.log('analyzeDocument: document not found', { path });
return;
}
}
else {
analyzedDoc = analyze_1.analyzer.analyze(foundDoc);
}
const doc = analyzedDoc.document;
const diagnostics = analyze_1.analyzer.getDiagnostics(doc.uri);
logger_1.logger.log('Sending Diagnostics', {
uri: doc.uri,
diagnostics: diagnostics.map(d => d.code),
});
startup_1.connection.sendDiagnostics({ uri: doc.uri, diagnostics });
workspace_manager_1.workspaceManager.handleUpdateDocument(doc);
return {
uri: document.uri,
path: path,
doc: doc,
};
}
logParams(methodName, ...params) {
logger_1.logger.log({ handler: methodName, params });
}
getDefaults(params) {
const path = (0, translation_1.uriToPath)(params.textDocument.uri);
const doc = document_1.documents.get(path);
if (!doc || !path)
return { path };
const root = analyze_1.analyzer.getRootNode(doc.uri);
const current = analyze_1.analyzer.nodeAtPoint(doc.uri, params.position.line, params.position.character);
return { doc, path, root, current };
}
getDefaultsForPartialParams(params) {
const path = (0, translation_1.uriToPath)(params.textDocument.uri);
const doc = document_1.documents.get(path);
const root = doc ? analyze_1.analyzer.getRootNode(doc.uri) : undefined;
return { doc, path, root };
}
}
exports.default = FishServer;