fish-lsp
Version:
LSP implementation for fish/fish-shell
248 lines (247 loc) • 9.38 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.VariableDefinitionFlag = exports.DefinitionScope = void 0;
exports.getVariableScope = getVariableScope;
exports.getScope = getScope;
exports.expandEntireVariableLine = expandEntireVariableLine;
exports.setQuery = setQuery;
const NodeTypes = __importStar(require("./node-types"));
const translation_1 = require("./translation");
const tree_sitter_1 = require("./tree-sitter");
class DefinitionScope {
scopeNode;
scopeTag;
constructor(scopeNode, scopeTag) {
this.scopeNode = scopeNode;
this.scopeTag = scopeTag;
}
static create(scopeNode, scopeTag) {
return new DefinitionScope(scopeNode, scopeTag);
}
containsPosition(position) {
return (0, tree_sitter_1.isPositionWithinRange)(position, (0, tree_sitter_1.getRange)(this.scopeNode));
}
isBeforePosition(position) {
return this.scopeNode.startPosition.row < position.line ||
this.scopeNode.startPosition.row === position.line && this.scopeNode.startPosition.column < position.character;
}
isAfterPosition(position) {
return this.scopeNode.endPosition.row > position.line ||
this.scopeNode.endPosition.row === position.line && this.scopeNode.endPosition.column > position.character;
}
isBeforeNode(node) {
const range = (0, tree_sitter_1.getRange)(node);
return this.scopeNode.startPosition.row < range.start.line ||
this.scopeNode.startPosition.row === range.start.line && this.scopeNode.startPosition.column < range.start.character;
}
isAfterNode(node) {
const range = (0, tree_sitter_1.getRange)(node);
return this.scopeNode.endPosition.row > range.end.line ||
this.scopeNode.endPosition.row === range.end.line && this.scopeNode.endPosition.column > range.end.character;
}
containsNode(node) {
const range = (0, tree_sitter_1.getRange)(node);
return this.containsPosition(range.start);
}
get tag() {
const tag = this.scopeTag;
return DefinitionScope.ScopeTags[tag] || 0;
}
static get ScopeTags() {
return {
universal: 5,
global: 4,
function: 3,
local: 2,
inherit: 1,
'': 0,
};
}
}
exports.DefinitionScope = DefinitionScope;
class VariableDefinitionFlag {
short;
long;
constructor(short, long) {
this.short = short;
this.long = long;
}
isMatch(node) {
if (!NodeTypes.isOption(node)) {
return false;
}
if (NodeTypes.isShortOption(node)) {
return node.text.slice(1).split('').includes(this.short);
}
if (NodeTypes.isLongOption(node)) {
return node.text.slice(2) === this.long;
}
return false;
}
get kind() {
return this.long;
}
}
exports.VariableDefinitionFlag = VariableDefinitionFlag;
const variableDefinitionFlags = [
new VariableDefinitionFlag('g', 'global'),
new VariableDefinitionFlag('l', 'local'),
new VariableDefinitionFlag('', 'inherit'),
new VariableDefinitionFlag('f', 'function'),
new VariableDefinitionFlag('U', 'universal'),
];
const hasParentFunction = (node) => {
return !!(0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isFunctionDefinition);
};
function getMatchingFlags(focusedNode, nodes) {
for (const node of nodes) {
const match = variableDefinitionFlags.find(flag => flag.isMatch(node));
if (match) {
return match;
}
}
return hasParentFunction(focusedNode)
? new VariableDefinitionFlag('f', 'function')
: new VariableDefinitionFlag('', 'inherit');
}
function findScopeFromFlag(node, flag) {
let scopeNode = node.parent;
let scopeFlag = flag.kind;
switch (flag.kind) {
case 'global':
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isProgram);
scopeFlag = 'global';
break;
case 'universal':
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isProgram);
scopeFlag = 'universal';
break;
case 'local':
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isScope);
break;
case 'function':
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isFunctionDefinition);
scopeFlag = 'function';
break;
case 'for_scope':
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isFunctionDefinition);
scopeFlag = 'function';
if (!scopeNode) {
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isProgram);
scopeFlag = 'global';
}
break;
case 'inherit':
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isScope);
scopeFlag = 'inherit';
break;
default:
scopeNode = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isScope);
break;
}
const finalScopeNode = scopeNode || node.parent;
return DefinitionScope.create(finalScopeNode, scopeFlag);
}
function getVariableScope(node) {
const definitionNodes = expandEntireVariableLine(node);
const keywordNode = definitionNodes[0];
let matchingFlag = null;
switch (keywordNode.text) {
case 'for':
matchingFlag = new VariableDefinitionFlag('', 'for_scope');
break;
case 'set':
case 'read':
case 'function':
default:
matchingFlag = getMatchingFlags(node, definitionNodes);
break;
}
const scope = findScopeFromFlag(node, matchingFlag);
return scope;
}
function getScope(document, node) {
if (NodeTypes.isEmittedEventDefinitionName(node)) {
return DefinitionScope.create(node, 'global');
}
if (NodeTypes.isAliasDefinitionName(node)) {
const isAutoloadedName = (0, translation_1.isAutoloadedUriLoadsAliasName)(document);
if (isAutoloadedName(node)) {
return DefinitionScope.create(node, 'global');
}
const parents = (0, tree_sitter_1.getParentNodes)(node.parent.parent) || (0, tree_sitter_1.getParentNodes)(node.parent);
const firstParent = parents
.filter(n => NodeTypes.isProgram(n) || NodeTypes.isFunctionDefinition(n))
.at(0);
return DefinitionScope.create(firstParent, 'local');
}
else if (NodeTypes.isFunctionDefinitionName(node)) {
const isAutoloadedName = (0, translation_1.isAutoloadedUriLoadsFunctionName)(document);
const parents = (0, tree_sitter_1.getParentNodes)(node.parent.parent) || (0, tree_sitter_1.getParentNodes)(node.parent);
const firstParent = parents
.filter(n => NodeTypes.isProgram(n) || NodeTypes.isFunctionDefinition(n))
.at(0);
if (isAutoloadedName(node)) {
const program = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isProgram);
return DefinitionScope.create(program, 'global');
}
return DefinitionScope.create(firstParent, 'local');
}
else if (NodeTypes.isVariableDefinitionName(node)) {
return getVariableScope(node);
}
const scope = (0, tree_sitter_1.firstAncestorMatch)(node, NodeTypes.isScope);
return DefinitionScope.create(scope, 'local');
}
function expandEntireVariableLine(node) {
const results = [node];
let current = node.previousSibling;
while (current !== null) {
if (!current || NodeTypes.isNewline(current)) {
break;
}
results.unshift(current);
current = current.previousSibling;
}
current = node.nextSibling;
while (current !== null) {
if (!current || NodeTypes.isNewline(current)) {
break;
}
results.push(current);
current = current.nextSibling;
}
return results;
}
function setQuery(searchNodes) {
const queryFlag = new VariableDefinitionFlag('q', 'query');
for (const flag of searchNodes) {
if (queryFlag.isMatch(flag)) {
return true;
}
}
return false;
}