fish-lsp
Version:
LSP implementation for fish/fish-shell
181 lines (180 loc) • 5.45 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", { value: true });
exports.GenericTree = void 0;
exports.filterTree = filterTree;
const defaultRemoveOptions = {
keepChildren: true,
};
class GenericTree {
_tree = [];
constructor(tree) {
this._tree = tree;
}
copy() {
return new GenericTree(Array.from(this._tree));
}
forEach(callback) {
for (const n of this.iter()) {
callback(n);
}
}
iter() {
function* iterNode(...nodes) {
for (const n of nodes) {
yield n;
yield* iterNode(...n.children);
}
}
return iterNode(...Array.from(this._tree));
}
filter(callback) {
function innerFilter(nodes, callback) {
const result = [];
for (const n of nodes) {
const children = innerFilter(n.children, callback);
if (callback(n)) {
const newNode = { ...n, children };
result.push(newNode);
continue;
}
if (children.length > 0) {
result.push(...children);
}
}
return result;
}
return innerFilter(this._tree, callback);
}
filterToTree(callback) {
return new GenericTree(this.filter(callback));
}
includes(callback) {
for (const n of this.iter()) {
if (callback(n)) {
return true;
}
}
return false;
}
map(callback) {
const result = [];
for (const n of this.iter()) {
result.push(callback(n));
}
return result;
}
find(callback) {
for (const n of this.iter()) {
if (callback(n)) {
return n;
}
}
return undefined;
}
findAll(callback) {
const result = [];
for (const n of this.iter()) {
if (callback(n)) {
result.push(n);
}
}
return result;
}
toArray() {
return Array.from(this._tree);
}
toFlatArray() {
const result = [];
for (const n of this.iter()) {
result.push(n);
}
return result;
}
get flatLength() {
return this.toFlatArray().length;
}
findParents(toFind, equalsCallback) {
function hasChild(node, toFind) {
if (equalsCallback(node, toFind)) {
return true;
}
for (const n of node.children) {
if (hasChild(n, toFind)) {
return true;
}
}
return false;
}
return this.filterToTree((node) => hasChild(node, toFind)).toFlatArray();
}
remove(toRemove, equalsCallback, options = defaultRemoveOptions) {
function innerRemove(nodes) {
const result = [];
for (const n of nodes) {
const children = innerRemove(n.children);
if (!equalsCallback(n, toRemove)) {
const newNode = { ...n, children };
result.push(newNode);
continue;
}
if (options.keepChildren && children.length > 0) {
result.push(...children);
}
}
return result;
}
this._tree = innerRemove(this._tree);
}
removeAll(toRemove, equalsCallback, options = defaultRemoveOptions) {
for (const rmv of toRemove) {
this.remove(rmv, equalsCallback, options);
}
}
toString(callback = (node) => node.toString()) {
function toStringHelper(indent = 0, ...nodes) {
let result = '';
for (const n of nodes) {
result += ' '.repeat(indent) + callback(n) + '\n';
result += toStringHelper(indent + 2, ...n.children);
}
return result;
}
return toStringHelper(0, ...Array.from(this._tree));
}
}
exports.GenericTree = GenericTree;
//// Example usage with SyntaxNode
//const rootNode: SyntaxNode = [> ... <];
//const abstractSyntaxTree = new AbstractTree<SyntaxNode>([rootNode]);
//
//const allNodes = abstractSyntaxTree.flattenAllChildren();
//const filteredNodes = abstractSyntaxTree.filter((node) => node.type === 'Identifier');
//abstractSyntaxTree.removeChild(rootNode);
//
//// Example usage with DocumentSymbol
//const rootSymbol: DocumentSymbol = [> ... <];
//const abstractSymbolTree = new AbstractTree<DocumentSymbol>([rootSymbol]);
//
//const allSymbols = abstractSymbolTree.flattenAllChildren();
//const filteredSymbols = abstractSymbolTree.filter((symbol) => symbol.kind === 'Class');
//abstractSymbolTree.removeChild(rootSymbol);
function filterTree(nodes, callbackfn) {
function inner(nodes, callbackfn) {
const result = [];
for (const n of nodes) {
let children = [];
if ('children' in n) {
children = inner(n.children, callbackfn);
}
if (callbackfn(n)) {
result.push(n);
continue;
}
if (children.length > 0) {
result.push(...children);
}
}
return result;
}
return inner(nodes, callbackfn);
}