All files / views/trees/workspace-tree workspace-node-provider.ts

97.61% Statements 41/42
100% Branches 24/24
90.9% Functions 10/11
97.43% Lines 38/39

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                            21x   21x     28x         21x 3x           3x   3x 1x   2x           1x       3x   3x                 6x 2x     4x 3x     4x   4x   1x   1x 3x   1x   1x     2x 2x   2x 1x         4x       8x 8x   8x 8x         9x 8x 8x   8x 2x             8x            
import * as vscode from 'vscode';
import { Utils } from 'vscode-uri';
import { container } from 'tsyringe';
import { ServiceToken } from '@src/services/tokens';
import { IWorkspaceFileService } from '@src/services/core';
 
// For a complete implementation of the FileSystemProvider API, see:
// https://github.com/boltex/revealRangeTest/blob/main/src/fileExplorer.ts#L185
 
/**
 * A tree node provider for RDF files in the Visual Studio Code workspace.
 */
export class WorkspaceNodeProvider implements vscode.TreeDataProvider<string> {
 
	private _onDidChangeTreeData = new vscode.EventEmitter<string | undefined>();
 
	readonly onDidChangeTreeData = this._onDidChangeTreeData.event;
 
	private get workspaceFileService() {
		return container.resolve<IWorkspaceFileService>(ServiceToken.WorkspaceFileService);
	}
 
	constructor() {
		// Monitor for changes in the workspace folders.
		this.workspaceFileService.onDidChangeFiles((e) => {
			const uri = e.uri.toString();
 
			// In a single-folder workspace the root folder is not itself a tree
			// node; its contents are the top-level nodes. Firing a change for that
			// folder URI is a no-op because VS Code has no matching element, so a
			// change affecting the root must trigger a full refresh instead.
			const isWorkspaceRoot = vscode.workspace.workspaceFolders?.some(f => f.uri.toString() === uri);
 
			if (isWorkspaceRoot && !vscode.workspace.workspaceFile) {
				this._onDidChangeTreeData.fire(undefined);
			} else {
				this._onDidChangeTreeData.fire(uri);
			}
		});
	}
 
	refresh(): void {
		this._onDidChangeTreeData.fire(undefined);
	}
 
	getParent(uri: string): string | undefined {
		let resourceUri = vscode.Uri.parse(uri);
 
		return uri ? Utils.dirname(resourceUri).toString() : undefined;
	}
 
	/**
	 * Get the children of a folder.
	 * @param uri The URI of the folder to get children for or `undefined` for the root.
	 * @returns An array of child URIs, sorted by folders first and then by name.
	 */
	async getChildren(uri?: string): Promise<string[]> {
		if (!vscode.workspace.name || !vscode.workspace.workspaceFolders?.length) {
			return [];
		}
 
		if (!uri) {
			await this.workspaceFileService.waitForDiscovery();
		}
 
		const result = [];
 
		if (uri) {
			// If the URI is provided, get the contents of the specified folder.
			const folder = vscode.Uri.parse(uri);
 
			result.push(...(await this.workspaceFileService.getFolderContents(folder)));
		} else if (!vscode.workspace.workspaceFile) {
			// If this is not a workspace, then return the contents of the first folder.
			const folder = vscode.workspace.workspaceFolders[0].uri;
 
			result.push(...(await this.workspaceFileService.getFolderContents(folder)));
		} else {
			// Iterate the workspace folders and push only the ones that have contents.
			for (const folder of vscode.workspace.workspaceFolders) {
				const contents = await this.workspaceFileService.getFolderContents(folder.uri);
 
				if (contents.length > 0) {
					result.push(folder.uri);
				}
			}
		}
 
		return result.map((resource) => resource.toString());
	}
 
	getTreeItem(uri: string): vscode.TreeItem {
		const resourceUri = vscode.Uri.parse(uri);
		const isDirectory = Utils.extname(resourceUri) == '';
 
		const item = new vscode.TreeItem(uri);
		item.resourceUri = resourceUri;
 
		// Use the workspace folder name when the URI matches a top-level workspace folder.
		// This respects custom folder names defined in a .code-workspace file,
		// keeping the tree consistent with the VS Code Explorer.
		const workspaceFolder = vscode.workspace.workspaceFolders?.find(f => f.uri.toString() === uri);
		item.label = workspaceFolder?.name ?? decodeURIComponent(Utils.basename(resourceUri));
		item.collapsibleState = isDirectory ? vscode.TreeItemCollapsibleState.Collapsed : vscode.TreeItemCollapsibleState.None;
 
		if (!isDirectory) {
			item.command = {
				command: 'vscode.open',
				arguments: [uri],
				title: 'Open File'
			};
		}
 
		return item;
	}
 
	getTotalItemCount(): number {
		return 0;
	}
}