All files / languages/sparql/providers sparql-code-lens-provider.ts

91.66% Statements 33/36
81.25% Branches 13/16
100% Functions 6/6
91.66% Lines 33/36

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                      24x   24x     24x 24x 24x 24x     24x 1x     24x 1x                   11x   11x 1x     10x 10x                 10x 1x             9x                 10x 3x 3x 3x 3x       3x             3x       10x                         10x   10x                 10x               10x       10x     10x                 3x    
import * as vscode from 'vscode';
import { ISparqlConnectionRegistry, ISparqlQueryService, IDocumentConnectionService } from '@src/languages/sparql/services';
import { ITripleStoreConfigService } from '@src/languages/sparql/services';
import { WORKSPACE_CONNECTION } from '../services/sparql-connection-registry';
import { SparqlConnection } from '../services/sparql-connection';
import { isTemplate } from 'triplate';
 
/**
 * Provides a CodeLens to display and change the current SPARQL endpoint.
 */
export class SparqlCodeLensProvider implements vscode.CodeLensProvider {
	private _onDidChangeCodeLenses = new vscode.EventEmitter<void>();
 
	public readonly onDidChangeCodeLenses = this._onDidChangeCodeLenses.event;
 
	constructor(
		private readonly _connectionRegistry: ISparqlConnectionRegistry,
		private readonly _documentConnectionService: IDocumentConnectionService,
		private readonly _storeConfigService: ITripleStoreConfigService,
		private readonly _queryService: ISparqlQueryService
	) {
 
		this._documentConnectionService.onDidChangeConnectionForDocument(() => {
			this.refresh();
		});
 
		this._connectionRegistry.onDidChangeConnections(() => {
			this.refresh();
		});
	}
 
	/**
	 * Computes the CodeLens for a given document.
	 * @param document The document to compute the CodeLens for.
	 * @returns A promise that resolves to an array of CodeLenses.
	 */
	public async provideCodeLenses(document: vscode.TextDocument): Promise<vscode.CodeLens[]> {
		const connection = this._documentConnectionService.getConnectionForDocument(document.uri);
 
		if (!connection) {
			return [];
		}
 
		const range = new vscode.Range(new vscode.Position(0, 0), new vscode.Position(0, 0));
		const codeLenses: vscode.CodeLens[] = [];
 
		// Run CodeLens, pushed first so it always leads the document-wide lens group. VS Code
		// does not merge same-range CodeLenses from multiple providers in provider-registration
		// order, so for `.sparql`-language Triplate templates this provider supplies the Run
		// lens itself (delegating to the template command) instead of relying on
		// TriplateCodeLensProvider's lens landing first, which empirically it doesn't.
		// The Run lens is shown in notebook cells too, so the lens group is consistent with
		// how it appears in a standalone editor.
		if (isTemplate(document.getText())) {
			codeLenses.push(new vscode.CodeLens(range, {
				title: '$(play)\u00A0Run',
				tooltip: 'Render this template with parameter values',
				command: 'mentor.command.executeTriplateTemplate',
				arguments: [document.uri.toString()],
			}));
		} else {
			codeLenses.push(new vscode.CodeLens(range, {
				title: '$(play)\u00A0Run',
				command: 'mentor.command.executeSparqlQuery',
				tooltip: 'Execute this SPARQL query',
				arguments: [this._queryService.createQueryFromDocument(document)],
			}));
		}
 
		// Inference status CodeLens (only for connections that support inference)
		if (this._storeConfigService.supportsInference(connection)) {
			const inferenceEnabled = this._documentConnectionService.getInferenceEnabledForDocument(document.uri);
			const inferenceIcon = '$(lightbulb)';
			const inferenceText = inferenceEnabled ? 'on' : 'off';
			const inferenceTooltip = inferenceEnabled
				? 'Inferred triples are included. Click to exclude them.'
				: 'Inferred triples are excluded. Click to include them.';
 
			const inferenceCodeLens = new vscode.CodeLens(range, {
				title: `${inferenceIcon}\u00A0Inference: ${inferenceText}`,
				tooltip: inferenceTooltip,
				command: 'mentor.command.toggleDocumentInference',
				arguments: [document.uri],
			});
 
			codeLenses.push(inferenceCodeLens);
		}
 
		// List Graphs CodeLens (only when a listGraphs query is configured for the connection)
		Iif (this._storeConfigService.getQueryTemplate(connection, 'listGraphs')) {
			codeLenses.push(new vscode.CodeLens(range, {
				title: '$(list-flat) List Graphs',
				tooltip: 'List the named graphs available on this connection',
				command: 'mentor.command.listGraphs',
				arguments: [connection],
			}));
		}
 
		// Connection CodeLens, always last in the group. A stored binding that no
		// longer resolves (deleted connection, or one defined in the user settings
		// of another machine) silently falls back to the workspace store \u2014 make
		// that visible instead of presenting the fallback as the configured state.
		const unresolvedConnectionId = this._documentConnectionService.getUnresolvedConnectionId(document.uri);
 
		Iif (unresolvedConnectionId) {
			codeLenses.push(new vscode.CodeLens(range, {
				title: `$(warning)\u00A0Connection unavailable: ${unresolvedConnectionId}`,
				tooltip: `The connection "${unresolvedConnectionId}" configured for this file is not available on this machine. `
					+ 'Queries run against the in-memory workspace store instead. Click to pick a connection.',
				command: 'mentor.command.selectSparqlConnection',
				arguments: [document],
			}));
		} else {
			codeLenses.push(new vscode.CodeLens(range, {
				title: `$(arrow-swap)\u00A0Connection: ${this._getConnectionLabel(connection)}`,
				tooltip: 'Click to change the SPARQL endpoint for this file',
				command: 'mentor.command.selectSparqlConnection',
				arguments: [document],
			}));
		}
 
		return codeLenses;
	}
 
	private _getConnectionLabel(connection: SparqlConnection): string {
		Iif (connection.id === WORKSPACE_CONNECTION.id) {
			return connection.id;
		} else {
			return connection.endpointUrl;
		}
	}
 
	/**
	 * Public method to manually trigger a refresh of the CodeLenses.
	 * This is useful after a command changes the source for a notebook.
	 */
	public refresh(): void {
		this._onDidChangeCodeLenses.fire();
	}
}