fish-lsp
Version:
LSP implementation for fish/fish-shell
169 lines (168 loc) • 6.22 kB
JavaScript
"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 = {}));