fish-lsp
Version:
LSP implementation for fish/fish-shell
329 lines (328 loc) • 11.3 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.Option = exports.stringIsUnixFlag = exports.stringIsLongFlag = exports.stringIsShortFlag = void 0;
exports.findOptionsSet = findOptionsSet;
exports.findOptions = findOptions;
exports.isMatchingOption = isMatchingOption;
exports.findMatchingOptions = findMatchingOptions;
exports.isMatchingOptionOrOptionValue = isMatchingOptionOrOptionValue;
exports.isMatchingOptionValue = isMatchingOptionValue;
const node_types_1 = require("../utils/node-types");
const tree_sitter_1 = require("../utils/tree-sitter");
const LSP = __importStar(require("vscode-languageserver"));
const stringIsShortFlag = (str) => str.startsWith('-') && str.length === 2;
exports.stringIsShortFlag = stringIsShortFlag;
const stringIsLongFlag = (str) => str.startsWith('--');
exports.stringIsLongFlag = stringIsLongFlag;
const stringIsUnixFlag = (str) => str.startsWith('-') && str.length > 2 && !str.startsWith('--');
exports.stringIsUnixFlag = stringIsUnixFlag;
class Option {
shortOptions = [];
unixOptions = [];
longOptions = [];
requiresArgument = false;
acceptsMultipleArguments = false;
optionalArgument = false;
static create(shortOption, longOption) {
const option = new Option();
if (shortOption) {
option.shortOptions.push(shortOption);
}
if (longOption) {
option.longOptions.push(longOption);
}
return option;
}
static long(longOption) {
const option = new Option();
option.longOptions.push(longOption);
return option;
}
static short(shortOption) {
const option = new Option();
option.shortOptions.push(shortOption);
return option;
}
static unix(unixOption) {
const option = new Option();
option.unixOptions.push(unixOption);
return option;
}
static fromRaw(...str) {
const option = new Option();
for (const s of str) {
if ((0, exports.stringIsLongFlag)(s)) {
option.longOptions.push(s);
}
else if ((0, exports.stringIsShortFlag)(s)) {
option.shortOptions.push(s);
}
else if ((0, exports.stringIsUnixFlag)(s)) {
option.unixOptions.push(s);
}
}
return option;
}
addUnixFlag(...options) {
this.unixOptions.push(...options);
return this;
}
withAliases(...optionAlias) {
for (const alias of optionAlias) {
if ((0, exports.stringIsLongFlag)(alias)) {
this.longOptions.push(alias);
continue;
}
if ((0, exports.stringIsShortFlag)(alias)) {
this.shortOptions.push(alias);
continue;
}
}
return this;
}
isOption(shortOption, longOption) {
if (shortOption) {
return this.shortOptions.includes(shortOption);
}
else if (longOption) {
return this.longOptions.includes(longOption);
}
return false;
}
withValue() {
this.requiresArgument = true;
this.optionalArgument = false;
this.acceptsMultipleArguments = false;
return this;
}
withOptionalValue() {
this.optionalArgument = true;
this.requiresArgument = false;
this.acceptsMultipleArguments = false;
return this;
}
withMultipleValues() {
this.acceptsMultipleArguments = true;
this.requiresArgument = true;
this.optionalArgument = false;
return this;
}
isSwitch() {
return !this.requiresArgument && !this.optionalArgument;
}
matchesValue(node) {
if (this.isSwitch()) {
return false;
}
if ((0, node_types_1.isOption)(node) && node.text.includes('=')) {
const [flag] = node.text.split('=');
return this.matches({ ...node, text: flag });
}
let prev = node.previousSibling;
if (this.acceptsMultipleArguments) {
while (prev) {
if ((0, node_types_1.isOption)(prev) && !prev.text.includes('=')) {
return this.matches(prev);
}
if ((0, node_types_1.isOption)(prev))
return false;
prev = prev.previousSibling;
}
}
return !!prev && this.matches(prev);
}
matches(node, checkWithEquals = true) {
if (!(0, node_types_1.isOption)(node))
return false;
const nodeText = checkWithEquals && node.text.includes('=')
? node.text.slice(0, node.text.indexOf('='))
: node.text;
if ((0, node_types_1.isLongOption)(node)) {
return this.matchesLongFlag(nodeText);
}
if ((0, node_types_1.isShortOption)(node) && this.unixOptions.length >= 1) {
return this.matchesUnixFlag(nodeText);
}
if ((0, node_types_1.isShortOption)(node)) {
return this.matchesShortFlag(nodeText);
}
return false;
}
matchesLongFlag(text) {
if (!text.startsWith('--'))
return false;
if ((0, exports.stringIsLongFlag)(text)) {
return this.longOptions.includes(text);
}
return false;
}
matchesUnixFlag(text) {
if ((0, exports.stringIsUnixFlag)(text) && text.length > 2) {
return this.unixOptions.includes(text);
}
return false;
}
matchesShortFlag(text) {
if (!text.startsWith('-') || text.startsWith('--'))
return false;
const chars = text.slice(1).split('').map(char => `-${char}`);
return chars.some(char => this.shortOptions.includes(char));
}
equals(node, allowEquals = false) {
if (!(0, node_types_1.isOption)(node))
false;
const text = allowEquals ? node.text.slice(0, node.text.indexOf('=')) : node.text;
if ((0, node_types_1.isLongOption)(node))
return this.matchesLongFlag(text);
if ((0, node_types_1.isShortOption)(node) && this.unixOptions.length >= 1)
return this.matchesUnixFlag(text);
if ((0, node_types_1.isShortOption)(node))
return this.matchesShortFlag(text);
return false;
}
equalsRawOption(...rawOption) {
for (const option of rawOption) {
if ((0, exports.stringIsLongFlag)(option) && this.longOptions.includes(option)) {
return true;
}
if ((0, exports.stringIsShortFlag)(option) && this.shortOptions.includes(option)) {
return true;
}
}
return false;
}
equalsRawShortOption(...rawOption) {
return rawOption.some(option => this.shortOptions.includes(option));
}
equalsRawLongOption(...rawOption) {
return rawOption.some(option => this.longOptions.includes(option));
}
equalsOption(other) {
const flags = other.getAllFlags();
return this.equalsRawOption(...flags);
}
findValueRangeAfterEquals(node) {
if (!(0, node_types_1.isOption)(node))
return null;
if (!node.text.includes('='))
return null;
const range = (0, tree_sitter_1.getRange)(node);
if (!range)
return null;
const equalsIndex = node.text.indexOf('=');
return LSP.Range.create(range.start.line, range.start.character + equalsIndex + 1, range.end.line, range.end.character);
}
isSet(node) {
if ((0, node_types_1.isOption)(node)) {
return this.equals(node) && this.isSwitch();
}
return this.matchesValue(node);
}
getAllFlags() {
const result = [];
if (this.shortOptions)
result.push(...this.shortOptions);
if (this.unixOptions)
result.push(...this.unixOptions);
if (this.longOptions)
result.push(...this.longOptions);
return result;
}
toString() {
return this.getAllFlags().join(', ');
}
}
exports.Option = Option;
function findOptionsSet(nodes, options) {
const result = [];
for (const node of nodes) {
const values = options.filter(o => o.isSet(node));
if (!values) {
continue;
}
values.forEach(option => result.push({ option, value: node }));
}
return result;
}
function findOptions(nodes, options) {
const remaining = [];
const found = [];
const unused = Array.from(options);
for (const node of nodes) {
const values = options.filter(o => o.isSet(node));
if (values.length === 0 && !(0, node_types_1.isOption)(node)) {
remaining.push(node);
continue;
}
values.forEach(option => {
unused.splice(unused.indexOf(option), 1);
found.push({ option, value: node });
});
}
return {
remaining,
found,
unused,
};
}
function isMatchingOption(node, ...option) {
if (!(0, node_types_1.isOption)(node))
return false;
for (const opt of option) {
if (opt.matches(node))
return true;
}
return false;
}
function findMatchingOptions(node, ...options) {
if (!(0, node_types_1.isOption)(node))
return;
return options.find((opt) => opt.matches(node));
}
function isMatchingOptionOrOptionValue(node, option) {
if (isMatchingOption(node, option)) {
return true;
}
const prevNode = node.previousNamedSibling;
if (prevNode?.text.includes('=')) {
return false;
}
if (prevNode && isMatchingOption(prevNode, option) && !(0, node_types_1.isOption)(node)) {
return true;
}
return false;
}
function isMatchingOptionValue(node, ...options) {
if (!node?.isNamed)
return false;
if ((0, node_types_1.isOption)(node)) {
return options.some((option) => option.equals(node, true));
}
if (node.previousNamedSibling && (0, node_types_1.isOption)(node.previousNamedSibling)) {
return options.some(option => option.matchesValue(node));
}
return false;
}