UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

175 lines (174 loc) 7.3 kB
"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;