fish-lsp
Version:
LSP implementation for fish/fish-shell
135 lines (134 loc) • 5.42 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.SourceResource = void 0;
exports.isSourceCommandName = isSourceCommandName;
exports.isSourceCommandWithArgument = isSourceCommandWithArgument;
exports.isSourceCommandArgumentName = isSourceCommandArgumentName;
exports.isSourcedFilename = isSourcedFilename;
exports.isExistingSourceFilenameNode = isExistingSourceFilenameNode;
exports.getExpandedSourcedFilenameNode = getExpandedSourcedFilenameNode;
exports.createSourceResources = createSourceResources;
exports.reachableSources = reachableSources;
exports.symbolsFromResource = symbolsFromResource;
const node_types_1 = require("../utils/node-types");
const file_operations_1 = require("../utils/file-operations");
const tree_sitter_1 = require("../utils/tree-sitter");
const definition_scope_1 = require("../utils/definition-scope");
function isSourceCommandName(node) {
return (0, node_types_1.isCommandWithName)(node, 'source') || (0, node_types_1.isCommandWithName)(node, '.');
}
function isSourceCommandWithArgument(node) {
return isSourceCommandName(node) && node.childCount > 1 && node.child(1)?.text !== '-';
}
function isSourceCommandArgumentName(node) {
if (node.parent && isSourceCommandWithArgument(node.parent)) {
return node.parent?.child(1)?.equals(node) && node.isNamed && node.text !== '-';
}
return false;
}
function isSourcedFilename(node) {
if (node.parent && isSourceCommandName(node.parent)) {
return node.parent?.child(1)?.equals(node) && node.isNamed && node.text !== '-';
}
return false;
}
function isExistingSourceFilenameNode(node) {
if (!isSourcedFilename(node))
return false;
return file_operations_1.SyncFileHelper.exists(node.text) && !file_operations_1.SyncFileHelper.isDirectory(node.text) && file_operations_1.SyncFileHelper.isFile(node.text);
}
function getExpandedSourcedFilenameNode(node) {
if (isExistingSourceFilenameNode(node)) {
return file_operations_1.SyncFileHelper.expandEnvVars(node.text);
}
return undefined;
}
class SourceResource {
from;
to;
range;
node;
definitionScope;
sources;
constructor(from, to, range, node, definitionScope, sources) {
this.from = from;
this.to = to;
this.range = range;
this.node = node;
this.definitionScope = definitionScope;
this.sources = sources;
}
static create(from, to, range, node, sources) {
let scopeParent = node.parent;
for (const parent of (0, tree_sitter_1.getParentNodesGen)(node)) {
if ((0, node_types_1.isFunctionDefinition)(parent) || (0, node_types_1.isProgram)(parent)) {
scopeParent = parent;
break;
}
}
const definitionScope = definition_scope_1.DefinitionScope.create(scopeParent, 'local');
return new SourceResource(from, to, range, node, definitionScope, sources);
}
scopeReachableFromNode(node) {
const parent = (0, node_types_1.findParentFunction)(node);
const isTopLevel = (0, node_types_1.isTopLevelDefinition)(this.node);
if (parent && !isTopLevel)
return this.definitionScope.containsNode(node);
return this.definitionScope.containsNode(node) && node.startIndex >= this.definitionScope.scopeNode.startIndex;
}
}
exports.SourceResource = SourceResource;
function createSourceResources(analyzer, from) {
const result = [];
const nodes = analyzer.getNodes(from.uri).filter(n => {
return isSourceCommandArgumentName(n) && !!isExistingSourceFilenameNode(n);
});
if (nodes.length === 0)
return result;
for (const node of nodes) {
const sourcedFile = getExpandedSourcedFilenameNode(node);
if (!sourcedFile)
continue;
const to = analyzer.getDocumentFromPath(sourcedFile) ||
file_operations_1.SyncFileHelper.toLspDocument(sourcedFile);
const range = (0, tree_sitter_1.getRange)(node);
analyzer.analyze(to);
const sources = createSourceResources(analyzer, to);
result.push(SourceResource.create(from, to, range, node, sources));
}
return result;
}
function reachableSources(resources, uniqueUris = new Set()) {
const result = [];
const sourceShouldInclude = (child, parent) => {
return child.definitionScope.containsNode(parent.node)
&& (0, tree_sitter_1.precedesRange)(parent.range, child.range)
&& !uniqueUris.has(child.to.uri);
};
for (const resource of resources) {
const children = reachableSources(resource.sources);
if (!uniqueUris.has(resource.to.uri)) {
uniqueUris.add(resource.to.uri);
result.push(resource);
}
for (const child of children) {
if (sourceShouldInclude(child, resource)) {
uniqueUris.add(child.to.uri);
result.push(child);
}
}
}
return result;
}
function symbolsFromResource(analyzer, resources, uniqueNames = new Set()) {
const result = [];
const symbols = analyzer.getFlatDocumentSymbols(resources.to.uri);
for (const symbol of symbols) {
if (uniqueNames.has(symbol.name))
continue;
if (symbol.isGlobal() || symbol.isRootLevel()) {
result.push(symbol);
}
}
return result;
}