All files / providers notebook-cell-slug-codelens-provider.ts

93.1% Statements 27/29
80% Branches 8/10
85.71% Functions 6/7
96.15% Lines 25/26

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                              22x   22x   22x     15x       8x       8x     8x       8x       8x   8x 1x             7x 7x   8x 2x 2x 1x 1x 1x 1x         7x 1x     6x   6x                     1x      
import * as vscode from 'vscode';
import { container } from 'tsyringe';
import { ServiceToken } from '@src/services/tokens';
import { IDocumentContextService } from '@src/services/document';
 
/**
 * Provides a CodeLens on line 0 of every data cell (Turtle, TriG, N-Triples, etc.)
 * inside a Mentor notebook, showing the cell's current slug. Clicking the CodeLens
 * opens the slug edit input box.
 *
 * This provider is intentionally narrow in scope: it only emits a CodeLens when the
 * document URI scheme is `vscode-notebook-cell` AND the cell has a loaded context
 * with a non-empty slug. All other documents (regular files) are ignored.
 */
export class NotebookCellSlugCodeLensProvider implements vscode.CodeLensProvider {
	private _initialized = false;
 
	private readonly _onDidChangeCodeLenses = new vscode.EventEmitter<void>();
 
	public readonly onDidChangeCodeLenses = this._onDidChangeCodeLenses.event;
 
	private get _contextService() {
		return container.resolve<IDocumentContextService>(ServiceToken.DocumentContextService);
	}
 
	private _initialize(): void {
		Iif (this._initialized) {
			return;
		}
 
		this._initialized = true;
 
		// Refresh CodeLenses whenever any document context changes (slug may have been updated).
		this._contextService.onDidChangeDocumentContext(() => this._onDidChangeCodeLenses.fire());
 
		// Refresh CodeLenses when a notebook is opened so cells indexed in the background
		// are reflected once the workspace indexer finishes.
		vscode.workspace.onDidOpenNotebookDocument(() => this._onDidChangeCodeLenses.fire());
	}
 
	public provideCodeLenses(document: vscode.TextDocument): vscode.CodeLens[] {
		this._initialize();
		// Only emit for notebook cells, not for standalone files.
		if (document.uri.scheme !== 'vscode-notebook-cell') {
			return [];
		}
 
		// Prefer the slug from the indexed document context. When the workspace
		// indexer has not yet run (e.g. on first render), fall back to the slug
		// stored directly in the notebook cell's metadata so the CodeLens appears
		// immediately without waiting for background indexing to complete.
		const ctx = this._contextService.contexts[document.uri.toString()];
		let slug = ctx?.slug;
 
		if (!slug) {
			const uriStr = document.uri.toString();
			for (const nb of vscode.workspace.notebookDocuments) {
				const cell = nb.getCells().find(c => c.document.uri.toString() === uriStr);
				Eif (cell) {
					slug = cell.metadata?.slug as string | undefined;
					break;
				}
			}
		}
 
		if (!slug) {
			return [];
		}
 
		const range = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0));
 
		return [
			new vscode.CodeLens(range, {
				title: `#${slug}`,
				tooltip: 'Click to edit slug or copy cell URI',
				command: 'mentor.command.triggerNotebookCellSlugAction',
				arguments: [document.uri],
			})
		];
	}
 
	public refresh(): void {
		this._onDidChangeCodeLenses.fire();
	}
}