Skip to content

Commit d384943

Browse files
Add code lens for quick eval command
1 parent c590e2f commit d384943

File tree

4 files changed

+86
-16
lines changed

4 files changed

+86
-16
lines changed

extensions/ql-vscode/package-lock.json

+1
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
import {
2+
CodeLensProvider,
3+
TextDocument,
4+
CodeLens,
5+
Command,
6+
Range
7+
} from 'vscode';
8+
9+
class MyCodeLensProvider implements CodeLensProvider {
10+
// Each provider requires a provideCodeLenses function which will give the various documents
11+
// the code lenses
12+
async provideCodeLenses(document: TextDocument): Promise<CodeLens[]> {
13+
14+
const codeLenses: CodeLens[] = [];
15+
16+
for (let index = 0; index < document.lineCount; index++) {
17+
const textLine = document.lineAt(index);
18+
const regex = new RegExp(/(?=(\w+\(\s*.*(?:,\s*)*\)))\1/g);
19+
if (textLine.text.match(regex)) {
20+
const uri = document.uri;
21+
const startIndex = textLine.text.search(regex);
22+
const range: Range = new Range(
23+
textLine.range.start.line, startIndex,
24+
textLine.range.end.line, startIndex + 1
25+
);
26+
27+
const command: Command = {
28+
command: 'codeQL.codeLensQuickEval',
29+
title: 'CodeQL: Quick Evaluation',
30+
arguments: [uri, range]
31+
};
32+
const codeLens = new CodeLens(range, command);
33+
codeLenses.push(codeLens);
34+
}
35+
}
36+
return codeLenses;
37+
}
38+
}
39+
40+
export default MyCodeLensProvider;

extensions/ql-vscode/src/extension.ts

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,8 @@ import {
1111
window as Window,
1212
env,
1313
window,
14-
QuickPickItem
14+
QuickPickItem,
15+
Range
1516
} from 'vscode';
1617
import { LanguageClient } from 'vscode-languageclient';
1718
import * as os from 'os';
@@ -20,6 +21,7 @@ import { testExplorerExtensionId, TestHub } from 'vscode-test-adapter-api';
2021

2122
import { AstViewer } from './astViewer';
2223
import * as archiveFilesystemProvider from './archive-filesystem-provider';
24+
import MyCodeLensProvider from './CodeLensProvider';
2325
import { CodeQLCliServer, CliVersionConstraint } from './cli';
2426
import {
2527
CliConfigListener,
@@ -154,6 +156,11 @@ export interface CodeQLExtensionInterface {
154156
* @returns CodeQLExtensionInterface
155157
*/
156158
export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionInterface | Record<string, never>> {
159+
160+
const codelensProvider = new MyCodeLensProvider();
161+
162+
languages.registerCodeLensProvider('*', codelensProvider);
163+
157164
void logger.log(`Starting ${extensionId} extension`);
158165
if (extension === undefined) {
159166
throw new Error(`Can't find extension ${extensionId}`);
@@ -469,6 +476,7 @@ async function activateWithInstalledDistribution(
469476
progress: ProgressCallback,
470477
token: CancellationToken,
471478
databaseItem: DatabaseItem | undefined,
479+
args?: Range
472480
): Promise<void> {
473481
if (qs !== undefined) {
474482
// If no databaseItem is specified, use the database currently selected in the Databases UI
@@ -483,7 +491,9 @@ async function activateWithInstalledDistribution(
483491
quickEval,
484492
selectedQuery,
485493
progress,
486-
token
494+
token,
495+
undefined,
496+
args
487497
);
488498
const item = qhm.buildCompletedQuery(info);
489499
await showResultsForCompletedQuery(item, WebviewReveal.NotForced);
@@ -705,6 +715,22 @@ async function activateWithInstalledDistribution(
705715
cancellable: true
706716
})
707717
);
718+
719+
ctx.subscriptions.push(
720+
commandRunnerWithProgress(
721+
'codeQL.codeLensQuickEval',
722+
async (
723+
progress: ProgressCallback,
724+
token: CancellationToken,
725+
uri: Uri | undefined,
726+
args: Range
727+
) => await compileAndRunQuery(true, uri, progress, token, undefined, args),
728+
{
729+
title: 'Running query',
730+
cancellable: true
731+
})
732+
);
733+
708734
ctx.subscriptions.push(
709735
commandRunnerWithProgress('codeQL.quickQuery', async (
710736
progress: ProgressCallback,

extensions/ql-vscode/src/run-queries.ts

+17-14
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ import * as tmp from 'tmp-promise';
55
import {
66
CancellationToken,
77
ConfigurationTarget,
8+
Range,
89
TextDocument,
910
TextEditor,
1011
Uri,
@@ -327,17 +328,18 @@ async function convertToQlPath(filePath: string): Promise<string> {
327328

328329

329330
/** Gets the selected position within the given editor. */
330-
async function getSelectedPosition(editor: TextEditor): Promise<messages.Position> {
331-
const pos = editor.selection.start;
332-
const posEnd = editor.selection.end;
333-
// Convert from 0-based to 1-based line and column numbers.
334-
return {
335-
fileName: await convertToQlPath(editor.document.fileName),
336-
line: pos.line + 1,
337-
column: pos.character + 1,
338-
endLine: posEnd.line + 1,
339-
endColumn: posEnd.character + 1
340-
};
331+
async function getSelectedPosition(editor: TextEditor, args?: Range): Promise<messages.Position> {
332+
const range = args || editor.selection;
333+
const pos = range.start;
334+
const posEnd = range.end;
335+
// Convert from 0-based to 1-based line and column numbers.
336+
return {
337+
fileName: await convertToQlPath(editor.document.fileName),
338+
line: pos.line + 1,
339+
column: pos.character + 1,
340+
endLine: posEnd.line + 1,
341+
endColumn: posEnd.character + 1
342+
};
341343
}
342344

343345
/**
@@ -485,7 +487,7 @@ type SelectedQuery = {
485487
* @param selectedResourceUri The selected resource when the command was run.
486488
* @param quickEval Whether the command being run is `Quick Evaluation`.
487489
*/
488-
export async function determineSelectedQuery(selectedResourceUri: Uri | undefined, quickEval: boolean): Promise<SelectedQuery> {
490+
export async function determineSelectedQuery(selectedResourceUri: Uri | undefined, quickEval: boolean, args?: Range): Promise<SelectedQuery> {
489491
const editor = window.activeTextEditor;
490492

491493
// Choose which QL file to use.
@@ -539,7 +541,7 @@ export async function determineSelectedQuery(selectedResourceUri: Uri | undefine
539541
// Report an error if we end up in this (hopefully unlikely) situation.
540542
throw new Error('The selected resource for quick evaluation should match the active editor.');
541543
}
542-
quickEvalPosition = await getSelectedPosition(editor);
544+
quickEvalPosition = await getSelectedPosition(editor, args);
543545
quickEvalText = editor.document.getText(editor.selection);
544546
}
545547

@@ -555,13 +557,14 @@ export async function compileAndRunQueryAgainstDatabase(
555557
progress: ProgressCallback,
556558
token: CancellationToken,
557559
templates?: messages.TemplateDefinitions,
560+
args?: Range
558561
): Promise<QueryWithResults> {
559562
if (!db.contents || !db.contents.dbSchemeUri) {
560563
throw new Error(`Database ${db.databaseUri} does not have a CodeQL database scheme.`);
561564
}
562565

563566
// Determine which query to run, based on the selection and the active editor.
564-
const { queryPath, quickEvalPosition, quickEvalText } = await determineSelectedQuery(selectedQueryUri, quickEval);
567+
const { queryPath, quickEvalPosition, quickEvalText } = await determineSelectedQuery(selectedQueryUri, quickEval, args);
565568

566569
const historyItemOptions: QueryHistoryItemOptions = {};
567570
historyItemOptions.isQuickQuery === isQuickQueryPath(queryPath);

0 commit comments

Comments
 (0)