fish-lsp
Version:
LSP implementation for fish/fish-shell
628 lines (627 loc) • 21.4 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.findMatchingOptions = exports.isMatchingOption = exports.isDefinitionName = exports.isEmittedEventDefinitionName = exports.isArgparseVariableDefinitionName = exports.isExportVariableDefinitionName = exports.isAliasDefinitionName = exports.isFunctionDefinitionName = exports.isVariableDefinitionName = void 0;
exports.isVariableDefinition = isVariableDefinition;
exports.isComment = isComment;
exports.isShebang = isShebang;
exports.isFunctionDefinition = isFunctionDefinition;
exports.isCommand = isCommand;
exports.isTopLevelFunctionDefinition = isTopLevelFunctionDefinition;
exports.isTopLevelDefinition = isTopLevelDefinition;
exports.isDefinition = isDefinition;
exports.isCommandName = isCommandName;
exports.isProgram = isProgram;
exports.isError = isError;
exports.isForLoop = isForLoop;
exports.isIfStatement = isIfStatement;
exports.isElseStatement = isElseStatement;
exports.isConditional = isConditional;
exports.isIfOrElseIfConditional = isIfOrElseIfConditional;
exports.isPossibleUnreachableStatement = isPossibleUnreachableStatement;
exports.isClause = isClause;
exports.isStatement = isStatement;
exports.isBlock = isBlock;
exports.isEnd = isEnd;
exports.isScope = isScope;
exports.isSemicolon = isSemicolon;
exports.isNewline = isNewline;
exports.isBlockBreak = isBlockBreak;
exports.isString = isString;
exports.isStringCharacter = isStringCharacter;
exports.isEmptyString = isEmptyString;
exports.isEndStdinCharacter = isEndStdinCharacter;
exports.isEscapeSequence = isEscapeSequence;
exports.isLongOption = isLongOption;
exports.isShortOption = isShortOption;
exports.isOption = isOption;
exports.isOptionValue = isOptionValue;
exports.isJoinedShortOption = isJoinedShortOption;
exports.hasShortOptionCharacter = hasShortOptionCharacter;
exports.isPipe = isPipe;
exports.gatherSiblingsTillEol = gatherSiblingsTillEol;
exports.isBeforeCommand = isBeforeCommand;
exports.isVariableExpansion = isVariableExpansion;
exports.isVariableExpansionWithName = isVariableExpansionWithName;
exports.isVariable = isVariable;
exports.isCompleteFlagCommandName = isCompleteFlagCommandName;
exports.findPreviousSibling = findPreviousSibling;
exports.findParentCommand = findParentCommand;
exports.isConcatenation = isConcatenation;
exports.isAliasWithName = isAliasWithName;
exports.findParentFunction = findParentFunction;
exports.findParentVariableDefinitionKeyword = findParentVariableDefinitionKeyword;
exports.findForLoopVariable = findForLoopVariable;
exports.findSetDefinedVariable = findSetDefinedVariable;
exports.hasParent = hasParent;
exports.findParent = findParent;
exports.hasParentFunction = hasParentFunction;
exports.findFunctionScope = findFunctionScope;
exports.scopeCheck = scopeCheck;
exports.wordNodeIsCommand = wordNodeIsCommand;
exports.isSwitchStatement = isSwitchStatement;
exports.isCaseClause = isCaseClause;
exports.isReturn = isReturn;
exports.isConditionalCommand = isConditionalCommand;
exports.isCommandFlag = isCommandFlag;
exports.isRegexArgument = isRegexArgument;
exports.isUnmatchedStringCharacter = isUnmatchedStringCharacter;
exports.isPartialForLoop = isPartialForLoop;
exports.isInlineComment = isInlineComment;
exports.isCommandWithName = isCommandWithName;
exports.isArgumentThatCanContainCommandCalls = isArgumentThatCanContainCommandCalls;
exports.isStringWithCommandCall = isStringWithCommandCall;
exports.isReturnStatusNumber = isReturnStatusNumber;
exports.isCompleteCommandName = isCompleteCommandName;
const tree_sitter_1 = require("./tree-sitter");
const barrel_1 = require("../parsing/barrel");
Object.defineProperty(exports, "isDefinitionName", { enumerable: true, get: function () { return barrel_1.isDefinitionName; } });
Object.defineProperty(exports, "isEmittedEventDefinitionName", { enumerable: true, get: function () { return barrel_1.isEmittedEventDefinitionName; } });
const options_1 = require("../parsing/options");
const barrel_2 = require("../parsing/barrel");
Object.defineProperty(exports, "isVariableDefinitionName", { enumerable: true, get: function () { return barrel_2.isVariableDefinitionName; } });
Object.defineProperty(exports, "isFunctionDefinitionName", { enumerable: true, get: function () { return barrel_2.isFunctionDefinitionName; } });
Object.defineProperty(exports, "isAliasDefinitionName", { enumerable: true, get: function () { return barrel_2.isAliasDefinitionName; } });
Object.defineProperty(exports, "isExportVariableDefinitionName", { enumerable: true, get: function () { return barrel_2.isExportVariableDefinitionName; } });
Object.defineProperty(exports, "isArgparseVariableDefinitionName", { enumerable: true, get: function () { return barrel_2.isArgparseVariableDefinitionName; } });
function isVariableDefinition(node) {
return (0, barrel_2.isVariableDefinitionName)(node);
}
function isComment(node) {
return node.type === 'comment' && !isShebang(node);
}
function isShebang(node) {
const parent = node.parent;
if (!parent || !isProgram(parent)) {
return false;
}
const firstLine = parent.firstChild;
if (!firstLine) {
return false;
}
if (!node.equals(firstLine)) {
return false;
}
return (firstLine.type === 'comment' &&
firstLine.text.startsWith('#!') &&
firstLine.text.includes('fish'));
}
function isFunctionDefinition(node) {
return node.type === 'function_definition';
}
function isCommand(node) {
return [
'command',
'test_command',
'command_substitution',
].includes(node.type);
}
function isTopLevelFunctionDefinition(node) {
if (isFunctionDefinition(node)) {
return !!(node.parent && isTopLevelDefinition(node.parent));
}
if ((0, barrel_2.isFunctionDefinitionName)(node)) {
return !!(node.parent && node.parent.parent && isTopLevelDefinition(node.parent.parent));
}
return false;
}
function isTopLevelDefinition(node) {
let currentNode = node;
while (currentNode) {
if (!currentNode)
break;
if (isProgram(currentNode)) {
return true;
}
if (isFunctionDefinition(currentNode)) {
return false;
}
currentNode = currentNode.parent;
}
return true;
}
function isDefinition(node) {
return (0, barrel_2.isFunctionDefinitionName)(node) || (0, barrel_2.isVariableDefinitionName)(node);
}
function isCommandName(node) {
const parent = node.parent || node;
const cmdName = parent?.firstNamedChild || node?.firstNamedChild;
if (!parent || !cmdName) {
return false;
}
if (!isCommand(parent)) {
return false;
}
return node.type === 'word' && node.equals(cmdName);
}
function isProgram(node) {
return node.type === 'program' || node.parent === null;
}
function isError(node = null) {
if (node) {
return node.type === 'ERROR';
}
return false;
}
function isForLoop(node) {
return node.type === 'for_statement';
}
function isIfStatement(node) {
return node.type === 'if_statement';
}
function isElseStatement(node) {
return node.type === 'else_clause';
}
function isConditional(node) {
return ['if_statement', 'else_if_clause', 'else_clause'].includes(node.type);
}
function isIfOrElseIfConditional(node) {
return ['if_statement', 'else_if_clause'].includes(node.type);
}
function isPossibleUnreachableStatement(node) {
if (isIfStatement(node)) {
return node.lastNamedChild?.type === 'else_clause';
}
else if (node.type === 'for_statement') {
return true;
}
else if (node.type === 'switch_statement') {
return false;
}
return false;
}
function isClause(node) {
return [
'case_clause',
'else_clause',
'else_if_clause',
].includes(node.type);
}
function isStatement(node) {
return [
'for_statement',
'switch_statement',
'while_statement',
'if_statement',
'begin_statement',
].includes(node.type);
}
function isBlock(node) {
return isClause(node) || isStatement(node);
}
function isEnd(node) {
return node.type === 'end';
}
function isScope(node) {
return isProgram(node) || isFunctionDefinition(node) || isStatement(node);
}
function isSemicolon(node) {
return node.type === ';' && node.text === ';';
}
function isNewline(node) {
return node.type === '\n';
}
function isBlockBreak(node) {
return isEnd(node) || isSemicolon(node) || isNewline(node);
}
function isString(node) {
return [
'double_quote_string',
'single_quote_string',
].includes(node.type);
}
function isStringCharacter(node) {
return [
"'",
'"',
].includes(node.type);
}
function isEmptyString(node) {
return isString(node) && node.text.length === 2;
}
function isEndStdinCharacter(node) {
return '--' === node.text && node.type === 'word';
}
function isEscapeSequence(node) {
return node.type === 'escape_sequence';
}
function isLongOption(node) {
return node.text.startsWith('--') && !isEndStdinCharacter(node);
}
function isShortOption(node) {
return node.text.startsWith('-') && !isLongOption(node) && node.text !== '-';
}
function isOption(node) {
if (isEndStdinCharacter(node))
return false;
return isShortOption(node) || isLongOption(node);
}
function isOptionValue(node) {
if (isEndStdinCharacter(node))
return false;
if ((0, barrel_1.isDefinitionName)(node))
return false;
if (!node.parent)
return false;
if (isOption(node) && node.text.includes('=') && node.type === 'word') {
return true;
}
if (isString(node) && node.previousNamedSibling && isOption(node.previousNamedSibling)) {
return true;
}
if (node.type === 'word' && node.previousSibling && isOption(node.previousSibling)) {
return true;
}
return false;
}
function isJoinedShortOption(node) {
if (isLongOption(node))
return false;
return isShortOption(node) && node.text.slice(1).length > 1;
}
function hasShortOptionCharacter(node, findChar) {
if (isLongOption(node))
return false;
return isShortOption(node) && node.text.slice(1).includes(findChar);
}
var options_2 = require("../parsing/options");
Object.defineProperty(exports, "isMatchingOption", { enumerable: true, get: function () { return options_2.isMatchingOption; } });
Object.defineProperty(exports, "findMatchingOptions", { enumerable: true, get: function () { return options_2.findMatchingOptions; } });
function isPipe(node) {
return node.type === 'pipe';
}
function gatherSiblingsTillEol(node) {
const siblings = [];
let next = node.nextSibling;
while (next && !isNewline(next)) {
siblings.push(next);
next = next.nextSibling;
}
return siblings;
}
function isBeforeCommand(node) {
return [
'file_redirect',
'redirect',
'redirected_statement',
'conditional_execution',
'stream_redirect',
'pipe',
].includes(node.type) || isFunctionDefinition(node) || isStatement(node) || isSemicolon(node) || isNewline(node) || isEnd(node);
}
function isVariableExpansion(node) {
return node.type === 'variable_expansion';
}
function isVariableExpansionWithName(node, variableName) {
return node.type === 'variable_expansion' && node.text === `$${variableName}`;
}
function isVariable(node) {
if (isVariableDefinition(node)) {
return true;
}
else {
return ['variable_expansion', 'variable_name'].includes(node.type);
}
}
function isCompleteFlagCommandName(node) {
if (node.parent && isCommandWithName(node, 'set')) {
const children = node.parent.childrenForFieldName('arguments').filter(n => !isOption(n));
if (children && children.at(0)?.equals(node)) {
return node.text.startsWith('_flag_');
}
}
return false;
}
function findPreviousSibling(node) {
let currentNode = node;
if (!currentNode) {
return null;
}
while (currentNode !== null) {
if (isCommand(currentNode)) {
return currentNode;
}
currentNode = currentNode.parent;
}
return null;
}
function findParentCommand(node) {
let currentNode = node;
if (!currentNode) {
return null;
}
while (currentNode !== null) {
if (isCommand(currentNode)) {
return currentNode;
}
currentNode = currentNode.parent;
}
return null;
}
function isConcatenation(node) {
return node.type === 'concatenation';
}
function isAliasWithName(node, aliasName) {
if ((0, barrel_2.isAliasDefinitionName)(node)) {
return node.text.split('=').at(0) === aliasName;
}
return false;
}
function findParentFunction(node) {
let currentNode = node;
if (!currentNode) {
return null;
}
while (currentNode !== null) {
if (isFunctionDefinition(currentNode)) {
return currentNode;
}
currentNode = currentNode.parent;
}
return null;
}
function findParentVariableDefinitionKeyword(node) {
if (!node || !(0, barrel_2.isVariableDefinitionName)(node))
return null;
const currentNode = node;
const parent = currentNode?.parent;
if (!currentNode || !parent) {
return null;
}
const varKeyword = parent.firstChild?.text.trim() || '';
if (!varKeyword) {
return null;
}
if (barrel_1.VariableDefinitionKeywords.includes(varKeyword)) {
return parent;
}
return null;
}
function findForLoopVariable(node) {
for (let i = 0; i < node.children.length; i++) {
const child = node.children[i];
if (child?.type === 'variable_name') {
return child;
}
}
return null;
}
function findSetDefinedVariable(node) {
const parent = findParentCommand(node);
if (!parent) {
return null;
}
const children = parent.children;
let i = 1;
let child = children[i];
while (child !== undefined) {
if (!child.text.startsWith('-')) {
return child;
}
if (i === children.length - 1) {
return null;
}
child = children[i++];
}
return child;
}
function hasParent(node, callbackfn) {
let currentNode = node;
while (currentNode !== null) {
if (callbackfn(currentNode)) {
return true;
}
currentNode = currentNode.parent;
}
return false;
}
function findParent(node, callbackfn) {
let currentNode = node;
while (currentNode !== null) {
if (callbackfn(currentNode)) {
return currentNode;
}
currentNode = currentNode.parent;
}
return null;
}
function hasParentFunction(node) {
let currentNode = node;
while (currentNode !== null) {
if (isFunctionDefinition(currentNode) || currentNode.type === 'function') {
return true;
}
if (currentNode.parent === null) {
return false;
}
currentNode = currentNode?.parent;
}
return false;
}
function findFunctionScope(node) {
while (node.parent !== null) {
if (isFunctionDefinition(node)) {
return node;
}
node = node.parent;
}
return node;
}
function scopeCheck(node1, node2) {
const scope1 = findFunctionScope(node1);
const scope2 = findFunctionScope(node2);
if (isProgram(scope1)) {
return true;
}
return scope1 === scope2;
}
function wordNodeIsCommand(node) {
if (node.type !== 'word') {
return false;
}
return node.parent ? isCommand(node.parent) && node.parent.firstChild?.text === node.text : false;
}
function isSwitchStatement(node) {
return node.type === 'switch_statement';
}
function isCaseClause(node) {
return node.type === 'case_clause';
}
function isReturn(node) {
return node.type === 'return' && node.firstChild?.text === 'return';
}
function isConditionalCommand(node) {
return node.type === 'conditional_execution';
}
function isCommandFlag(node) {
return [
'test_option',
'word',
'escape_sequence',
].includes(node.type) || node.text.startsWith('-') || findParentCommand(node) !== null;
}
function isRegexArgument(n) {
return n.text === '--regex' || n.text === '-r';
}
function isUnmatchedStringCharacter(node) {
if (!isStringCharacter(node)) {
return false;
}
if (node.parent && isString(node.parent)) {
return false;
}
return true;
}
function isPartialForLoop(node) {
const semiCompleteForLoop = ['for', 'i', 'in', '_'];
const errorNode = node.parent;
if (node.text === 'for' && node.type === 'for') {
if (!errorNode) {
return true;
}
if ((0, tree_sitter_1.getLeafNodes)(errorNode).length < semiCompleteForLoop.length) {
return true;
}
return false;
}
if (!errorNode) {
return false;
}
return (errorNode.hasError &&
errorNode.text.startsWith('for') &&
!errorNode.text.includes(' in '));
}
function isInlineComment(node) {
if (!isComment(node))
return false;
const previousSibling = node.previousNamedSibling;
if (!previousSibling)
return false;
return previousSibling?.startPosition.row === node.startPosition.row && previousSibling?.type !== 'comment';
}
function isCommandWithName(node, ...commandNames) {
if (node.type !== 'command')
return false;
return !!node.firstChild && commandNames.includes(node.firstChild.text);
}
function isArgumentThatCanContainCommandCalls(node) {
if ((0, barrel_1.isDefinitionName)(node)
|| isCommand(node)
|| isCommandName(node)
|| !node.isNamed)
return false;
const parent = findParent(node, (n) => isCommand(n) || isFunctionDefinition(n));
if (!parent)
return false;
if (isFunctionDefinition(parent)) {
return (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-w', '--wraps').withValue());
}
const commandName = parent.firstNamedChild?.text;
if (!commandName)
return false;
switch (commandName) {
case 'complete':
return (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-w', '--wraps').withValue())
|| (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-c', '--command').withValue())
|| (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-a', '--arguments').withValue())
|| (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-n', '--condition').withValue());
case 'alias':
case 'bind':
return true;
case 'abbr':
return (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-f', '--function').withValue())
|| (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-c', '--command').withValue());
case 'argparse':
return (0, options_1.isMatchingOptionValue)(node, options_1.Option.create('-n', '--name').withValue());
default:
return false;
}
}
function isStringWithCommandCall(node) {
if (!isString(node))
return false;
const parent = findParent(node, (n) => isFunctionDefinition(n) || isCommand(n));
if (!parent)
return false;
if (isFunctionDefinition(parent)) {
return (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-w', '--wraps').withValue());
}
if (isCommand(parent)) {
const parentCommandName = parent.firstChild?.text;
if (!parentCommandName)
return false;
switch (parentCommandName) {
case 'complete':
return (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-w', '--wraps').withValue())
|| (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-c', '--command').withValue())
|| (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-a', '--arguments').withValue())
|| (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-n', '--condition').withValue());
case 'alias':
case 'bind':
return true;
case 'abbr':
return (0, options_1.isMatchingOptionOrOptionValue)(node, options_1.Option.create('-f', '--function').withValue());
}
}
return false;
}
function isReturnStatusNumber(node) {
if (node.type !== 'integer')
return false;
const parent = node.parent;
if (!parent)
return false;
return parent.type === 'return';
}
function isCompleteCommandName(node) {
if (!node.parent || !isCommand(node.parent))
return false;
if (!isCommandWithName(node.parent, 'complete'))
return false;
const previousSibling = node.previousNamedSibling;
if (!previousSibling)
return false;
if ((0, options_1.isMatchingOption)(previousSibling, options_1.Option.create('-c', '--command').withValue())) {
return !isOption(node);
}
return false;
}