Use type-safe VSCode commands
This commit is contained in:
@@ -11,6 +11,7 @@ import type {
|
||||
VariantAnalysisScannedRepository,
|
||||
VariantAnalysisScannedRepositoryResult,
|
||||
} from "../variant-analysis/shared/variant-analysis";
|
||||
import { QLDebugConfiguration } from "../debugger/debug-configuration";
|
||||
|
||||
// A command function matching the signature that VS Code calls when
|
||||
// a command on a selection is invoked.
|
||||
@@ -52,6 +53,15 @@ export type BuiltInVsCodeCommands = {
|
||||
) => Promise<void>;
|
||||
"vscode.open": (uri: Uri) => Promise<void>;
|
||||
"vscode.openFolder": (uri: Uri) => Promise<void>;
|
||||
// We type the `config` property specifically as a CodeQL debug configuration, since that's the
|
||||
// only kinds we specify anyway.
|
||||
"workbench.action.debug.start": (options?: {
|
||||
config?: Partial<QLDebugConfiguration>;
|
||||
noDebug?: boolean;
|
||||
}) => Promise<void>;
|
||||
"workbench.action.debug.stepInto": () => Promise<void>;
|
||||
"workbench.action.debug.stepOver": () => Promise<void>;
|
||||
"workbench.action.debug.stepOut": () => Promise<void>;
|
||||
};
|
||||
|
||||
// Commands that are available before the extension is fully activated.
|
||||
|
||||
@@ -6,7 +6,6 @@ import {
|
||||
debug,
|
||||
Uri,
|
||||
CancellationTokenSource,
|
||||
commands,
|
||||
} from "vscode";
|
||||
import { DebuggerCommands } from "../common/commands";
|
||||
import { isCanary } from "../config";
|
||||
@@ -24,6 +23,7 @@ import {
|
||||
} from "../run-queries-shared";
|
||||
import { QLResolvedDebugConfiguration } from "./debug-configuration";
|
||||
import * as CodeQLProtocol from "./debug-protocol";
|
||||
import { App } from "../common/app";
|
||||
|
||||
/**
|
||||
* Listens to messages passing between VS Code and the debug adapter, so that we can supplement the
|
||||
@@ -144,6 +144,7 @@ export class DebuggerUI
|
||||
private readonly sessions = new Map<string, QLDebugAdapterTracker>();
|
||||
|
||||
constructor(
|
||||
private readonly app: App,
|
||||
private readonly localQueryResultsView: ResultsView,
|
||||
private readonly localQueries: LocalQueries,
|
||||
private readonly dbm: DatabaseManager,
|
||||
@@ -204,7 +205,7 @@ export class DebuggerUI
|
||||
|
||||
private async startDebuggingSelection(): Promise<void> {
|
||||
// Launch the currently selected debug configuration, but specifying QuickEval mode.
|
||||
await commands.executeCommand("workbench.action.debug.start", {
|
||||
await this.app.commands.execute("workbench.action.debug.start", {
|
||||
config: {
|
||||
quickEval: true,
|
||||
},
|
||||
|
||||
@@ -873,7 +873,12 @@ async function activateWithInstalledDistribution(
|
||||
);
|
||||
|
||||
void extLogger.log("Initializing debugger UI.");
|
||||
const debuggerUI = new DebuggerUI(localQueryResultsView, localQueries, dbm);
|
||||
const debuggerUI = new DebuggerUI(
|
||||
app,
|
||||
localQueryResultsView,
|
||||
localQueries,
|
||||
dbm,
|
||||
);
|
||||
ctx.subscriptions.push(debuggerUI);
|
||||
|
||||
const dataExtensionsEditorModule =
|
||||
|
||||
@@ -4,13 +4,10 @@ import {
|
||||
DebugSession,
|
||||
ProviderResult,
|
||||
Uri,
|
||||
commands,
|
||||
debug,
|
||||
workspace,
|
||||
} from "vscode";
|
||||
import * as CodeQLProtocol from "../../../src/debugger/debug-protocol";
|
||||
import { DebuggerCommands } from "../../../src/common/commands";
|
||||
import { CommandManager } from "../../../src/packages/commands";
|
||||
import { DisposableObject } from "../../../src/pure/disposable-object";
|
||||
import { QueryResultType } from "../../../src/pure/legacy-messages";
|
||||
import { CoreCompletedQuery } from "../../../src/queryRunner";
|
||||
@@ -22,6 +19,7 @@ import {
|
||||
import { join } from "path";
|
||||
import { writeFile } from "fs-extra";
|
||||
import { expect } from "@jest/globals";
|
||||
import { AppCommandManager } from "../../../src/common/commands";
|
||||
|
||||
type Resolver<T> = (value: T) => void;
|
||||
|
||||
@@ -190,9 +188,7 @@ export class DebugController
|
||||
*/
|
||||
private resolver: Resolver<AnyDebugEvent> | undefined = undefined;
|
||||
|
||||
public constructor(
|
||||
private readonly debuggerCommands: CommandManager<DebuggerCommands>,
|
||||
) {
|
||||
public constructor(private readonly appCommands: AppCommandManager) {
|
||||
super();
|
||||
this.push(debug.registerDebugAdapterTrackerFactory("codeql", this));
|
||||
this.push(
|
||||
@@ -232,7 +228,7 @@ export class DebugController
|
||||
* Starts a debug session via the "codeQL.debugQuery" copmmand.
|
||||
*/
|
||||
public debugQuery(uri: Uri): Promise<void> {
|
||||
return this.debuggerCommands.execute("codeQL.debugQuery", uri);
|
||||
return this.appCommands.execute("codeQL.debugQuery", uri);
|
||||
}
|
||||
|
||||
public async startDebugging(
|
||||
@@ -251,7 +247,7 @@ export class DebugController
|
||||
}
|
||||
: {};
|
||||
|
||||
return await commands.executeCommand("workbench.action.debug.start", {
|
||||
return await this.appCommands.execute("workbench.action.debug.start", {
|
||||
config: fullConfig,
|
||||
...options,
|
||||
});
|
||||
@@ -265,21 +261,19 @@ export class DebugController
|
||||
}
|
||||
|
||||
public async continueDebuggingSelection(): Promise<void> {
|
||||
return await this.debuggerCommands.execute(
|
||||
"codeQL.continueDebuggingSelection",
|
||||
);
|
||||
return await this.appCommands.execute("codeQL.continueDebuggingSelection");
|
||||
}
|
||||
|
||||
public async stepInto(): Promise<void> {
|
||||
return await commands.executeCommand("workbench.action.debug.stepInto");
|
||||
return await this.appCommands.execute("workbench.action.debug.stepInto");
|
||||
}
|
||||
|
||||
public async stepOver(): Promise<void> {
|
||||
return await commands.executeCommand("workbench.action.debug.stepOver");
|
||||
return await this.appCommands.execute("workbench.action.debug.stepOver");
|
||||
}
|
||||
|
||||
public async stepOut(): Promise<void> {
|
||||
return await commands.executeCommand("workbench.action.debug.stepOut");
|
||||
return await this.appCommands.execute("workbench.action.debug.stepOut");
|
||||
}
|
||||
|
||||
public handleEvent(event: AnyDebugEvent): void {
|
||||
@@ -411,12 +405,12 @@ export class DebugController
|
||||
* debug controller is cleaned up.
|
||||
*/
|
||||
export async function withDebugController<T>(
|
||||
debuggerCommands: CommandManager<DebuggerCommands>,
|
||||
appCommands: AppCommandManager,
|
||||
op: (controller: DebugController) => Promise<T>,
|
||||
): Promise<T> {
|
||||
await workspace.getConfiguration().update("codeQL.canary", true);
|
||||
try {
|
||||
const controller = new DebugController(debuggerCommands);
|
||||
const controller = new DebugController(appCommands);
|
||||
try {
|
||||
try {
|
||||
const result = await op(controller);
|
||||
|
||||
@@ -8,13 +8,13 @@ import {
|
||||
getActivatedExtension,
|
||||
} from "../global.helper";
|
||||
import { describeWithCodeQL } from "../cli";
|
||||
import { createVSCodeCommandManager } from "../../../src/common/vscode/commands";
|
||||
import { DebuggerCommands } from "../../../src/common/commands";
|
||||
import { withDebugController } from "./debug-controller";
|
||||
import { CodeQLCliServer } from "../../../src/cli";
|
||||
import { QueryOutputDir } from "../../../src/run-queries-shared";
|
||||
import { createVSCodeCommandManager } from "../../../src/common/vscode/commands";
|
||||
import { AllCommands } from "../../../src/common/commands";
|
||||
|
||||
jest.setTimeout(2000_000);
|
||||
jest.setTimeout(20_000);
|
||||
|
||||
async function selectForQuickEval(
|
||||
path: string,
|
||||
@@ -43,7 +43,7 @@ async function getResultCount(
|
||||
describeWithCodeQL()("Debugger", () => {
|
||||
let databaseManager: DatabaseManager;
|
||||
let cli: CodeQLCliServer;
|
||||
const debuggerCommands = createVSCodeCommandManager<DebuggerCommands>();
|
||||
const appCommands = createVSCodeCommandManager<AllCommands>();
|
||||
const simpleQueryPath = join(__dirname, "data", "simple-query.ql");
|
||||
const quickEvalQueryPath = join(__dirname, "data", "QuickEvalQuery.ql");
|
||||
const quickEvalLibPath = join(__dirname, "data", "QuickEvalLib.qll");
|
||||
@@ -62,7 +62,7 @@ describeWithCodeQL()("Debugger", () => {
|
||||
});
|
||||
|
||||
it("should debug a query and keep the session active", async () => {
|
||||
await withDebugController(debuggerCommands, async (controller) => {
|
||||
await withDebugController(appCommands, async (controller) => {
|
||||
await controller.debugQuery(Uri.file(simpleQueryPath));
|
||||
await controller.expectLaunched();
|
||||
await controller.expectSucceeded();
|
||||
@@ -71,7 +71,7 @@ describeWithCodeQL()("Debugger", () => {
|
||||
});
|
||||
|
||||
it("should run a query and then stop debugging", async () => {
|
||||
await withDebugController(debuggerCommands, async (controller) => {
|
||||
await withDebugController(appCommands, async (controller) => {
|
||||
await controller.startDebugging(
|
||||
{
|
||||
query: simpleQueryPath,
|
||||
@@ -87,7 +87,7 @@ describeWithCodeQL()("Debugger", () => {
|
||||
});
|
||||
|
||||
it("should run a quick evaluation", async () => {
|
||||
await withDebugController(debuggerCommands, async (controller) => {
|
||||
await withDebugController(appCommands, async (controller) => {
|
||||
await selectForQuickEval(quickEvalQueryPath, 18, 5, 18, 22);
|
||||
|
||||
// Don't specify a query path, so we'll default to the active document ("QuickEvalQuery.ql")
|
||||
@@ -105,7 +105,7 @@ describeWithCodeQL()("Debugger", () => {
|
||||
});
|
||||
|
||||
it("should run a quick evaluation on a library without any query context", async () => {
|
||||
await withDebugController(debuggerCommands, async (controller) => {
|
||||
await withDebugController(appCommands, async (controller) => {
|
||||
await selectForQuickEval(quickEvalLibPath, 4, 15, 4, 32);
|
||||
|
||||
// Don't specify a query path, so we'll default to the active document ("QuickEvalLib.qll")
|
||||
@@ -123,7 +123,7 @@ describeWithCodeQL()("Debugger", () => {
|
||||
});
|
||||
|
||||
it("should run a quick evaluation on a library in the context of a specific query", async () => {
|
||||
await withDebugController(debuggerCommands, async (controller) => {
|
||||
await withDebugController(appCommands, async (controller) => {
|
||||
await selectForQuickEval(quickEvalLibPath, 4, 15, 4, 32);
|
||||
|
||||
await controller.startDebuggingSelection({
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { debug, CancellationToken, ExtensionContext, Range, Uri } from "vscode";
|
||||
import { CancellationToken, ExtensionContext, Range, Uri } from "vscode";
|
||||
import { join, dirname } from "path";
|
||||
import {
|
||||
pathExistsSync,
|
||||
@@ -24,19 +24,18 @@ import { QueryResultType } from "../../../src/pure/new-messages";
|
||||
import { createVSCodeCommandManager } from "../../../src/common/vscode/commands";
|
||||
import {
|
||||
AllCommands,
|
||||
DebuggerCommands,
|
||||
AppCommandManager,
|
||||
QueryServerCommands,
|
||||
} from "../../../src/common/commands";
|
||||
import { ProgressCallback } from "../../../src/progress";
|
||||
import { CommandManager } from "../../../src/packages/commands";
|
||||
import { withDebugController } from "./debug-controller";
|
||||
|
||||
type DebugMode = "localQueries" | "launch";
|
||||
type DebugMode = "localQueries" | "debug";
|
||||
|
||||
async function compileAndRunQuery(
|
||||
mode: DebugMode,
|
||||
appCommands: AppCommandManager,
|
||||
localQueries: LocalQueries,
|
||||
debuggerCommands: CommandManager<DebuggerCommands>,
|
||||
quickEval: boolean,
|
||||
queryUri: Uri,
|
||||
progress: ProgressCallback,
|
||||
@@ -55,14 +54,17 @@ async function compileAndRunQuery(
|
||||
range,
|
||||
);
|
||||
|
||||
case "launch":
|
||||
return await withDebugController(debuggerCommands, async (controller) => {
|
||||
await controller.debugQuery(queryUri);
|
||||
case "debug":
|
||||
return await withDebugController(appCommands, async (controller) => {
|
||||
await controller.startDebugging(
|
||||
{
|
||||
query: queryUri.fsPath,
|
||||
},
|
||||
true,
|
||||
);
|
||||
await controller.expectLaunched();
|
||||
const succeeded = await controller.expectSucceeded();
|
||||
await controller.expectStopped();
|
||||
expect(debug.activeDebugSession?.name).not.toBeUndefined();
|
||||
await debug.stopDebugging();
|
||||
await controller.expectExited();
|
||||
await controller.expectTerminated();
|
||||
await controller.expectSessionClosed();
|
||||
|
||||
@@ -71,9 +73,9 @@ async function compileAndRunQuery(
|
||||
}
|
||||
}
|
||||
|
||||
jest.setTimeout(2000_000);
|
||||
jest.setTimeout(20_000);
|
||||
|
||||
const MODES: DebugMode[] = ["localQueries", "launch"];
|
||||
const MODES: DebugMode[] = ["localQueries", "debug"];
|
||||
|
||||
/**
|
||||
* Integration tests for queries
|
||||
@@ -90,7 +92,6 @@ describeWithCodeQL()("Queries", () => {
|
||||
const appCommandManager = createVSCodeCommandManager<AllCommands>();
|
||||
const queryServerCommandManager =
|
||||
createVSCodeCommandManager<QueryServerCommands>();
|
||||
const debuggerCommands = createVSCodeCommandManager<DebuggerCommands>();
|
||||
|
||||
let qlpackFile: string;
|
||||
let qlpackLockFile: string;
|
||||
@@ -174,8 +175,8 @@ describeWithCodeQL()("Queries", () => {
|
||||
async function runQueryWithExtensions() {
|
||||
const result = await compileAndRunQuery(
|
||||
mode,
|
||||
appCommandManager,
|
||||
localQueries,
|
||||
debuggerCommands,
|
||||
false,
|
||||
Uri.file(queryUsingExtensionPath),
|
||||
progress,
|
||||
@@ -208,8 +209,8 @@ describeWithCodeQL()("Queries", () => {
|
||||
const queryPath = join(__dirname, "data", "simple-query.ql");
|
||||
const result = await compileAndRunQuery(
|
||||
mode,
|
||||
appCommandManager,
|
||||
localQueries,
|
||||
debuggerCommands,
|
||||
false,
|
||||
Uri.file(queryPath),
|
||||
progress,
|
||||
@@ -228,8 +229,8 @@ describeWithCodeQL()("Queries", () => {
|
||||
const queryPath = join(__dirname, "data", "simple-query.ql");
|
||||
const result = await compileAndRunQuery(
|
||||
mode,
|
||||
appCommandManager,
|
||||
localQueries,
|
||||
debuggerCommands,
|
||||
false,
|
||||
Uri.file(queryPath),
|
||||
progress,
|
||||
|
||||
Reference in New Issue
Block a user