fish-lsp
Version:
LSP implementation for fish/fish-shell
175 lines (174 loc) • 7.3 kB
JavaScript
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fishSymbolNameEqualsNodeText = exports.isFishSymbol = exports.equalSymbolScopes = exports.symbolContainsScope = exports.symbolContainsPosition = exports.symbolContainsNode = exports.symbolScopeContainsNode = exports.symbolEqualsNode = exports.equalSymbolDefinitions = exports.symbolEqualsLocation = exports.equalSymbols = exports.rangeContainsSyntaxNode = exports.rangeContainsPosition = exports.rangesEqual = void 0;
const node_types_1 = require("../utils/node-types");
const tree_sitter_1 = require("../utils/tree-sitter");
const rangesEqual = (range1, range2) => {
return range1.start.line === range2.start.line &&
range1.start.character === range2.start.character &&
range1.end.line === range2.end.line &&
range1.end.character === range2.end.character;
};
exports.rangesEqual = rangesEqual;
const rangeContainsPosition = (range, position) => {
const { line, character } = position;
const { start, end } = range;
if (line < start.line || line > end.line)
return false;
if (line === start.line && character < start.character)
return false;
if (line === end.line && character > end.character)
return false;
return true;
};
exports.rangeContainsPosition = rangeContainsPosition;
const rangeContainsSyntaxNode = (range, node) => {
return range.start.line <= node.startPosition.row &&
range.end.line >= node.endPosition.row;
};
exports.rangeContainsSyntaxNode = rangeContainsSyntaxNode;
const hasEqualNames = ({ a, b }) => {
if (a.name === b.name)
return true;
return a.aliasedNames.includes(b.name) || b.aliasedNames.includes(a.name);
};
const hasEqualRanges = ({ a, b }) => {
return (0, exports.rangesEqual)(a.range, b.range) && (0, exports.rangesEqual)(a.selectionRange, b.selectionRange);
};
const hasEqualBasicProperties = ({ a, b }) => {
return a.kind === b.kind &&
a.uri === b.uri &&
a.fishKind === b.fishKind;
};
const equalSymbols = (symbolA, symbolB) => {
const pair = { a: symbolA, b: symbolB };
return hasEqualNames(pair) &&
hasEqualBasicProperties(pair) &&
hasEqualRanges(pair);
};
exports.equalSymbols = equalSymbols;
const symbolEqualsLocation = (symbol, location) => {
return symbol.uri === location.uri &&
(0, exports.rangesEqual)(symbol.selectionRange, location.range);
};
exports.symbolEqualsLocation = symbolEqualsLocation;
const equalSymbolDefinitions = (symbolA, symbolB) => {
return symbolA.name === symbolB.name &&
symbolA.kind === symbolB.kind &&
symbolA.uri === symbolB.uri &&
(0, exports.symbolContainsScope)(symbolA, symbolB);
};
exports.equalSymbolDefinitions = equalSymbolDefinitions;
const symbolEqualsNode = (symbol, node, strict = false) => {
if (strict)
return symbol.focusedNode.equals(node);
return symbol.node.equals(node) || symbol.focusedNode.equals(node);
};
exports.symbolEqualsNode = symbolEqualsNode;
const symbolScopeContainsNode = (symbol, node) => {
return symbol.scope.containsPosition((0, tree_sitter_1.getRange)(node).start);
};
exports.symbolScopeContainsNode = symbolScopeContainsNode;
const symbolContainsNode = (symbol, node) => {
return (0, exports.rangeContainsSyntaxNode)(symbol.range, node);
};
exports.symbolContainsNode = symbolContainsNode;
const symbolContainsPosition = (symbol, position) => {
const { line, character } = position;
const { start, end } = symbol.selectionRange;
return start.line === line &&
start.character <= character &&
end.character >= character;
};
exports.symbolContainsPosition = symbolContainsPosition;
const haveSameScopeNode = ({ a, b }) => {
if (a.scopeTag === 'inherit' || b.scopeTag === 'inherit') {
return a.scopeContainsNode(b.node) || b.scopeContainsNode(a.node);
}
if (a.isLocal() && b.isLocal() && a.kind === b.kind && a.isVariable() && b.isVariable()) {
return a.scopeContainsNode(b.node) || b.scopeContainsNode(a.node);
}
return a.scope.scopeNode.equals(b.scope.scopeNode);
};
const haveCompatibleScopeTags = ({ a, b }) => {
const scopeTags = [a.scope.scopeTag, b.scope.scopeTag];
if (scopeTags.includes('inherit'))
return true;
if (a.isLocal() && b.isLocal() && a.kind === b.kind && a.isVariable() && b.isVariable())
return true;
if (a.isGlobal() && b.isGlobal())
return true;
if (a.isLocal() && b.isLocal())
return true;
return a.scope.scopeTag === b.scope.scopeTag;
};
const haveEqualScopes = ({ a, b }) => {
if (!haveSameScopeNode({ a, b }) || a.kind !== b.kind)
return false;
return haveCompatibleScopeTags({ a, b });
};
const checkVariableScopeContainment = ({ a, b }) => {
if (!a.isVariable() || !b.isVariable())
return false;
if (a.isGlobal() && b.isGlobal())
return true;
if (a.isGlobal() && b.isLocal() || a.isLocal() && b.isGlobal()) {
return false;
}
const isSameScope = haveSameScopeNode({ a, b });
const scopeContains = (0, tree_sitter_1.containsNode)(a.scope.scopeNode, b.scope.scopeNode);
if ((0, node_types_1.isFunctionDefinition)(a.scopeNode) && (0, node_types_1.isFunctionDefinition)(b.scopeNode)) {
return isSameScope;
}
return isSameScope || scopeContains;
};
const checkGeneralScopeContainment = ({ a, b }) => {
if (!haveSameScopeNode({ a, b }) || a.kind !== b.kind)
return false;
const scopeTags = [a.scope.scopeTag, b.scope.scopeTag];
if (scopeTags.includes('inherit') ||
a.isLocal() && b.isLocal() && a.kind === b.kind && a.isVariable() && b.isVariable()) {
if ((0, node_types_1.isFunctionDefinition)(a.scope.scopeNode) && (0, node_types_1.isFunctionDefinition)(b.scope.scopeNode)) {
return true;
}
return haveSameScopeNode({ a, b }) || (0, tree_sitter_1.containsNode)(a.scope.scopeNode, b.scope.scopeNode);
}
if (a.isGlobal() && b.isGlobal())
return true;
if (a.isLocal() && b.isLocal())
return true;
return a.scope.scopeTag === b.scope.scopeTag;
};
const symbolContainsScope = (symbolA, symbolB) => {
const pair = { a: symbolA, b: symbolB };
if (haveEqualScopes(pair))
return true;
if (symbolA.isVariable() && symbolB.isVariable()) {
return checkVariableScopeContainment(pair);
}
return checkGeneralScopeContainment(pair);
};
exports.symbolContainsScope = symbolContainsScope;
const equalSymbolScopes = (symbolA, symbolB) => {
return haveEqualScopes({ a: symbolA, b: symbolB });
};
exports.equalSymbolScopes = equalSymbolScopes;
const isFishSymbol = (obj) => {
return typeof obj === 'object'
&& obj !== null
&& 'name' in obj
&& 'fishKind' in obj
&& 'uri' in obj
&& 'node' in obj
&& 'focusedNode' in obj
&& 'scope' in obj
&& 'children' in obj
&& typeof obj.name === 'string'
&& typeof obj.uri === 'string'
&& Array.isArray(obj.children);
};
exports.isFishSymbol = isFishSymbol;
const fishSymbolNameEqualsNodeText = (symbol, node) => {
return symbol.name === node.text;
};
exports.fishSymbolNameEqualsNodeText = fishSymbolNameEqualsNodeText;