fish-lsp
Version:
LSP implementation for fish/fish-shell
234 lines (233 loc) • 10.7 kB
JavaScript
"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.isSymbolReference = void 0;
const Locations = __importStar(require("../utils/locations"));
const tree_sitter_1 = require("../utils/tree-sitter");
const emit_1 = require("./emit");
const node_types_1 = require("../utils/node-types");
const complete_1 = require("./complete");
const argparse_1 = require("./argparse");
const options_1 = require("./options");
const set_1 = require("./set");
const nested_strings_1 = require("./nested-strings");
const node_types_2 = require("../diagnostics/node-types");
const bind_1 = require("./bind");
const alias_1 = require("./alias");
const shouldSkipNode = ({ symbol, document, node, excludeEqualNode }) => {
if (excludeEqualNode && symbol.equalsNode(node))
return true;
if (excludeEqualNode && document.uri === symbol.uri) {
if ((0, tree_sitter_1.equalRanges)((0, tree_sitter_1.getRange)(symbol.focusedNode), (0, tree_sitter_1.getRange)(node))) {
return true;
}
}
if (excludeEqualNode && symbol.isEvent() && symbol.focusedNode.equals(node)) {
return true;
}
return false;
};
const checkEventReference = ({ symbol, node }) => {
if (symbol.isEventHook() && symbol.name === node.text && (0, emit_1.isEmittedEventDefinitionName)(node)) {
return true;
}
if (symbol.isEmittedEvent() && symbol.name === node.text && !(0, emit_1.isEmittedEventDefinitionName)(node)) {
return true;
}
return false;
};
const isInValidScope = ({ symbol, document, node }) => {
if (symbol.isLocal() && !symbol.isArgparse()) {
return symbol.scopeContainsNode(node) && symbol.uri === document.uri;
}
return true;
};
const matchesFunctionName = ({ symbol, node }) => {
if (symbol.isFunction()) {
if ((0, node_types_1.isArgumentThatCanContainCommandCalls)(node))
return true;
if (symbol.name !== node.text && !(0, node_types_1.isString)(node)) {
return false;
}
}
return true;
};
const checkCompleteCommandReference = ({ symbol, node }) => {
const parentNode = node.parent ? (0, node_types_1.findParentCommand)(node) : null;
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'complete')) {
return (0, complete_1.isMatchingCompletionFlagNodeWithFishSymbol)(symbol, node);
}
return false;
};
const checkArgparseReference = ({ symbol, node }) => {
if (!symbol.isArgparse())
return false;
const parentName = symbol.parent?.name
|| symbol.scopeNode.firstNamedChild?.text
|| symbol.scopeNode.text;
if ((0, argparse_1.isCompletionArgparseFlagWithCommandName)(node, parentName, symbol.argparseFlagName)) {
return true;
}
if ((0, node_types_1.isOption)(node) && node.parent && (0, node_types_1.isCommandWithName)(node.parent, parentName)) {
return (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.fromRaw(symbol.argparseFlag));
}
if (symbol.name === node.text && symbol.parent?.scopeContainsNode(node)) {
return true;
}
const parentFunction = (0, node_types_1.findParentFunction)(node);
const parentNode = node.parent ? (0, node_types_1.findParentCommand)(node) : null;
if ((0, node_types_1.isVariable)(node) || (0, node_types_1.isVariableDefinitionName)(node) || (0, set_1.isSetVariableDefinitionName)(node, false)) {
return symbol.name === node.text && symbol.scopeContainsNode(node);
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'set', 'read', 'for', 'export', 'argparse')) {
return !!(symbol.name === node.text
&& symbol.scopeContainsNode(node)
&& parentFunction?.equals(symbol.scopeNode));
}
return false;
};
const checkFunctionReference = ({ symbol, node }) => {
if (!symbol.isFunction())
return false;
const parentNode = node.parent ? (0, node_types_1.findParentCommand)(node) : null;
const prevNode = node.previousNamedSibling;
if ((0, node_types_1.isCommand)(node) && node.text === symbol.name)
return true;
if ((0, node_types_1.isFunctionDefinitionName)(node) && symbol.isGlobal()) {
return symbol.equalsNode(node);
}
if (parentNode
&& (0, node_types_1.isCommandWithName)(parentNode, symbol.name)
&& parentNode.firstNamedChild?.equals(node)) {
return true;
}
if ((0, node_types_1.isCommandWithName)(node, symbol.name))
return true;
if ((0, node_types_1.isArgumentThatCanContainCommandCalls)(node)) {
if ((0, node_types_1.isString)(node) || (0, node_types_1.isOption)(node)) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
return node.text === symbol.name;
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'type', 'functions')) {
const firstChild = parentNode.namedChildren.find(n => !(0, node_types_1.isOption)(n));
return firstChild?.text === symbol.name;
}
if (prevNode && (0, options_1.isMatchingOption)(prevNode, options_1.Option.create('-w', '--wraps')) ||
node.parent && (0, node_types_1.isFunctionDefinition)(node.parent) &&
(0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-w', '--wraps'))) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'abbr')) {
if (prevNode && (0, node_types_2.isMatchingAbbrFunction)(node)) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
const namedChild = (0, tree_sitter_1.getChildNodes)(parentNode).find(n => (0, node_types_2.isAbbrDefinitionName)(n));
if (namedChild &&
Locations.Range.isAfter((0, tree_sitter_1.getRange)(namedChild), symbol.selectionRange) &&
!(0, node_types_1.isOption)(node) && node.text === symbol.name) {
return true;
}
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'bind')) {
if ((0, node_types_1.isOption)(node))
return false;
if ((0, bind_1.isBindFunctionCall)(node)) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
if ((0, node_types_1.isString)(node) && (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name)) {
return true;
}
const cmd = parentNode.childrenForFieldName('argument').slice(1)
.filter(n => !(0, node_types_1.isOption)(n) && !(0, node_types_1.isEndStdinCharacter)(n))
.find(n => n.equals(node) && n.text === symbol.name);
if (cmd)
return true;
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'alias')) {
if ((0, alias_1.isAliasDefinitionValue)(node)) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'argparse')) {
if ((0, node_types_1.isOption)(node) || (0, node_types_1.isString)(node)) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'export', 'set', 'read', 'for', 'argparse')) {
if ((0, node_types_1.isOption)(node) || (0, node_types_1.isString)(node)) {
return (0, nested_strings_1.extractCommands)(node).some(cmd => cmd === symbol.name);
}
if ((0, node_types_1.isVariableDefinitionName)(node))
return false;
return symbol.name === node.text;
}
return symbol.name === node.text && symbol.scopeContainsNode(node);
};
const checkVariableReference = ({ symbol, node }) => {
if (!symbol.isVariable() || node.text !== symbol.name)
return false;
if ((0, node_types_1.isVariable)(node) || (0, node_types_1.isVariableDefinitionName)(node))
return true;
const parentNode = node.parent ? (0, node_types_1.findParentCommand)(node) : null;
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, symbol.name)) {
return false;
}
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'export', 'set', 'read', 'for', 'argparse')) {
if ((0, node_types_1.isOption)(node))
return false;
if ((0, node_types_1.isVariableDefinitionName)(node))
return symbol.name === node.text;
}
return symbol.name === node.text && symbol.scopeContainsNode(node);
};
const referenceCheckers = [
checkEventReference,
checkArgparseReference,
checkFunctionReference,
checkVariableReference,
];
const isSymbolReference = (symbol, document, node, excludeEqualNode = false) => {
const ctx = { symbol, document, node, excludeEqualNode };
if (shouldSkipNode(ctx))
return false;
if (symbol.isEvent()) {
return checkEventReference(ctx);
}
if (!isInValidScope(ctx))
return false;
if (!matchesFunctionName(ctx))
return false;
const parentNode = node.parent ? (0, node_types_1.findParentCommand)(node) : null;
if (parentNode && (0, node_types_1.isCommandWithName)(parentNode, 'complete')) {
return checkCompleteCommandReference(ctx);
}
for (const checker of referenceCheckers) {
if (checker(ctx))
return true;
}
return false;
};
exports.isSymbolReference = isSymbolReference;