Press n or j to go to the next uncovered block, b, p or k for the previous block.
| 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 | 1666x 919x 919x 919x 919x 919x 919x 492x 492x 492x 492x 6x 10x 281x 10x 654x 278x 263x 263x 15x 15x 15x 15x 12x 3x 2x 1x 4x 3x 1x 8x 1x 49x 49x 59x 59x 22x 37x 27x 1567x 13x 2x 11x 10x 1x | import * as vscode from 'vscode';
import { DefinitionQueryOptions } from '@faubulous/mentor-rdf';
import { container } from 'tsyringe';
import { ServiceToken } from '@src/services/tokens';
import { ISettingsService } from '@src/services/core';
import { IDocumentContext } from '@src/services/document/document-context.interface';
import { Label } from '@src/services/document/document-context';
import { TreeNodeBase } from '@src/views/trees/tree-node';
import { getIriFromNodeId } from '@src/utilities';
/**
* Base class for a node in the definition tree.
*/
export class DefinitionTreeNode extends TreeNodeBase {
protected get settings() {
return container.resolve<ISettingsService>(ServiceToken.SettingsService);
}
initialCollapsibleState = vscode.TreeItemCollapsibleState.Collapsed;
/**
* The parent node in the tree, or undefined if this is a root node.
*/
parent: DefinitionTreeNode | undefined;
/**
* The documet context used to query definitions.
*/
document: IDocumentContext;
/**
* The options for querying the children of the tree item.
*/
private _queryOptions?: DefinitionQueryOptions;
constructor(context: IDocumentContext, id: string, uri: string, options?: DefinitionQueryOptions) {
super();
this.id = id;
this.uri = uri;
this.document = context;
this._queryOptions = options;
}
/**
* Create a child node of the definition tree node.
* @param NodeConstructor Constructor of the child node.
* @param iri IRI of the child node.
* @param options Optional query options for querying the children of the created node.
* @returns A new instance of the child node.
*/
createChildNode<NodeType extends DefinitionTreeNode>(
NodeConstructor: new (document: IDocumentContext, id: string, iri: string, options?: any) => NodeType,
iri: string,
options?: any
): NodeType {
// TODO: Move ID creation to a separate method in uri module.
const id = `${this.id}/<${iri}>`;
const node = new NodeConstructor(this.document, id, iri, this.getQueryOptions(options));
node.parent = this;
return node;
}
getCommand(): vscode.Command | undefined {
return {
command: 'mentor.command.revealDefinition',
title: '',
arguments: [this.id, true]
};
}
getContextValue(): string {
return 'resource';
}
/**
* Whether the node has children, computed once per node by {@link hasChildrenCached}.
*/
private _hasChildren: boolean | undefined;
/**
* Indicates whether the node has children, running {@link hasChildren} at most once per node.
* Container nodes test their child nodes before listing them, and the tree tests the same
* nodes again to get their collapsible state; the cache lets both share one set of store
* queries. Safe to memoize because the provider recreates all nodes on refresh.
* @returns `true` if the node has children, `false` otherwise.
*/
hasChildrenCached(): boolean {
return this._hasChildren ??= this.hasChildren();
}
override getCollapsibleState(): vscode.TreeItemCollapsibleState {
return this.hasChildrenCached() ? this.initialCollapsibleState : vscode.TreeItemCollapsibleState.None;
}
getDocumentGraphs(): string[] {
return this.document.graphs;
}
/**
* The resolved resource label, computed once per node. Resolving runs store
* queries per annotation predicate, and both {@link getLabel} and
* {@link getDescription} need the result — without the cache every tree node
* would run those queries twice per refresh. Safe to memoize because the
* provider recreates all nodes on refresh.
*/
private _resourceLabel: Label | undefined;
private _getResourceLabel(): Label {
return this._resourceLabel ??= this.document.getResourceLabel(this.uri);
}
getLabel(): vscode.TreeItemLabel {
const label = this._getResourceLabel().value;
return { label }
}
getDescription(): string {
const label = this._getResourceLabel();
const activeLanguageTag = this.document.activeLanguageTag;
const activeLanguage = this.document.activeLanguage;
if (!label.language || !activeLanguageTag || !activeLanguage) {
return "";
}
// We return the language tag as a description if it differs from the active language,
// or if the selected language tag is non-regional but the returned label is.
if (!label.language.startsWith(activeLanguage) || label.language.length > activeLanguageTag.length) {
return "@" + label.language;
} else {
return "";
}
}
getTooltip(): vscode.MarkdownString | undefined {
if (this.uri) {
return this.document.getResourceTooltip(this.uri);
} else {
return undefined;
}
}
/**
* Get the resolved resourceUri of the tree item. This is either the `resourceUri` or the `uri` of the tree item.
* @returns The URI of the tree item or undefined if the tree item is not associated with a URI.
*/
getResourceUri(): vscode.Uri | undefined {
return vscode.Uri.parse(this.uri);
}
/**
* Resolve a descendant node matching the given IRI. Override in container nodes
* to provide efficient, type-aware resolution instead of brute-force traversal.
* @param iri The resource IRI to search for.
* @returns The matching tree node, or `undefined` if this subtree cannot resolve it.
*/
resolveNodeForUri(iri: string): DefinitionTreeNode | undefined {
return undefined;
}
/**
* Walk a hierarchy path of IRIs through the children of this node, expanding
* each level lazily. Returns the node matching the last IRI in the path.
* @param path An array of IRIs ordered from root ancestor to target.
* @returns The node at the end of the path, or `undefined` if any step fails.
*/
walkHierarchyPath(path: string[]): DefinitionTreeNode | undefined {
let children = this.getChildren() as DefinitionTreeNode[];
let found: DefinitionTreeNode | undefined;
for (const pathIri of path) {
found = children.find(n => n.uri === pathIri);
if (!found) {
return undefined;
}
children = found.getChildren() as DefinitionTreeNode[];
}
return found;
}
/**
* Get the query options for the tree item.
* @param additionalOptions Query options that will override or be added to the associated query options.
* @returns A query options object.
*/
getQueryOptions(additionalOptions?: any): DefinitionQueryOptions {
return {
...this._queryOptions,
includeReferenced: this.settings.get('view.showReferences', true),
...additionalOptions,
}
}
}
export function getIriFromArgument(arg: DefinitionTreeNode | string): string {
if (arg instanceof DefinitionTreeNode) {
return getIriFromNodeId(arg.id);
} else if (typeof arg === 'string') {
return getIriFromNodeId(arg);
} else {
throw new Error('Invalid argument type: ' + typeof arg);
}
} |