UNPKG

fish-lsp

Version:

LSP implementation for fish/fish-shell

169 lines (168 loc) 6.22 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.Line = exports.InlineParser = void 0; exports.wordPrecedesCommand = wordPrecedesCommand; const parser_1 = require("../../parser"); const tree_sitter_1 = require("../tree-sitter"); const node_types_1 = require("../node-types"); class InlineParser { parser; COMMAND_TYPES = ['command', 'for_statement', 'case', 'function']; static async create() { const parser = await (0, parser_1.initializeParser)(); return new InlineParser(parser); } constructor(parser) { this.parser = parser; this.parser = parser; } parseWord(line) { if (line.endsWith(' ') || line.endsWith('(')) { return { word: null, wordNode: null }; } const { rootNode } = this.parser.parse(line); const node = (0, tree_sitter_1.getLastLeafNode)(rootNode); if (!node || node.text.trim() === '') { return { word: null, wordNode: null }; } return { word: node.text.trim() + line.slice(node.endIndex), wordNode: node, }; } parseCommand(line) { const { word, wordNode } = this.parseWord(line.trimEnd()); if (wordPrecedesCommand(word)) { return { command: null, commandNode: null }; } const { virtualLine, maxLength } = Line.appendEndSequence(line, wordNode); const { rootNode } = this.parser.parse(virtualLine); const node = (0, tree_sitter_1.getLastLeafNode)(rootNode, maxLength); if (!node) { return { command: null, commandNode: null }; } let commandNode = (0, tree_sitter_1.firstAncestorMatch)(node, (n) => this.COMMAND_TYPES.includes(n.type)); commandNode = commandNode?.firstChild || commandNode; return { command: commandNode?.text || null, commandNode: commandNode || null, }; } parse(line) { this.parser.reset(); return this.parser.parse(line).rootNode; } getNodeContext(line) { const { word, wordNode } = this.parseWord(line); const { command, commandNode } = this.parseCommand(line); const index = this.getIndex(line); if (word === command) { return { word, wordNode, command: null, commandNode: null, index: 0 }; } return { word, wordNode, command, commandNode, index: index, }; } lastItemIsOption(line) { const { command } = this.parseCommand(line); if (!command) { return false; } const afterCommand = line.lastIndexOf(command) + 1; const lastItem = line.slice(afterCommand).trim().split(' ').at(-1); if (lastItem) { return lastItem.startsWith('-'); } return false; } getLastNode(line) { const { wordNode } = this.parseWord(line.trimEnd()); const { virtualLine, maxLength: _maxLength } = Line.appendEndSequence(line, wordNode); const rootNode = this.parse(virtualLine); const node = (0, tree_sitter_1.getLastLeafNode)(rootNode); return node; } hasOption(command, options) { return (0, tree_sitter_1.getChildNodes)(command).some(n => options.includes(n.text)); } getIndex(line) { const { commandNode } = this.parseCommand(line); if (!commandNode) { return 0; } if (commandNode) { const node = (0, tree_sitter_1.firstAncestorMatch)(commandNode, (n) => this.COMMAND_TYPES.includes(n.type)); const allLeafNodes = (0, tree_sitter_1.getLeafNodes)(node).filter(leaf => leaf.startPosition.column < line.length); return Math.max(allLeafNodes.length - 1, 1); } return 0; } async createCompletionList(line) { const result = []; const { word: _word, wordNode: _wordNode, commandNode: _commandNode } = this.getNodeContext(line); return result; } } exports.InlineParser = InlineParser; function wordPrecedesCommand(word) { if (!word) { return false; } const chars = ['(', ';']; const combiners = ['and', 'or', 'not', '!', '&&', '||']; const conditional = ['if', 'while', 'else if', 'switch']; const pipes = ['|', '&', '1>|', '2>|', '&|']; return (chars.includes(word) || combiners.includes(word) || conditional.includes(word) || pipes.includes(word)); } var Line; (function (Line) { function isEmpty(line) { return line.trim().length === 0; } Line.isEmpty = isEmpty; function isComment(line) { return line.trim().startsWith('#'); } Line.isComment = isComment; function hasMultipleLastSpaces(line) { return line.trim().endsWith(' '); } Line.hasMultipleLastSpaces = hasMultipleLastSpaces; function removeAllButLastSpace(line) { if (line.endsWith(' ')) { return line; } return line.split(' ')[-1] || line; } Line.removeAllButLastSpace = removeAllButLastSpace; function appendEndSequence(oldLine, wordNode, endSequence = ';end;') { let virtualEOLChars = endSequence; let maxLength = oldLine.length; if (wordNode && (0, node_types_1.isUnmatchedStringCharacter)(wordNode)) { virtualEOLChars = wordNode.text + endSequence; maxLength -= 1; } if (wordNode && (0, node_types_1.isPartialForLoop)(wordNode)) { const completeForLoop = ['for', 'i', 'in', '_']; const errorNode = (0, tree_sitter_1.firstAncestorMatch)(wordNode, (n) => n.hasError); const leafNodes = (0, tree_sitter_1.getLeafNodes)(errorNode); virtualEOLChars = ' ' + completeForLoop.slice(leafNodes.length).join(' ') + endSequence; } return { virtualLine: [oldLine, virtualEOLChars].join(''), virtualEOLChars: virtualEOLChars, maxLength: maxLength, }; } Line.appendEndSequence = appendEndSequence; })(Line || (exports.Line = Line = {}));