Rename and move `commandRunner`
The `commandRunner` name doesn't really make sense since it doesn't "run" a command, but rather registers a command. This renames it to `registerCommandWithErrorHandling` and moves it to the `common/vscode` directory.
This commit is contained in:
Родитель
aca0489fdc
Коммит
aa268cfc5f
|
@ -1,76 +0,0 @@
|
|||
import { commands, Disposable } from "vscode";
|
||||
import {
|
||||
showAndLogExceptionWithTelemetry,
|
||||
showAndLogWarningMessage,
|
||||
} from "./helpers";
|
||||
import { extLogger } from "./common";
|
||||
import { asError, getErrorMessage, getErrorStack } from "./pure/helpers-pure";
|
||||
import { telemetryListener } from "./telemetry";
|
||||
import { redactableError } from "./pure/errors";
|
||||
import { UserCancellationException } from "./progress";
|
||||
|
||||
/**
|
||||
* A task that handles command invocations from `commandRunner`.
|
||||
* Arguments passed to the command handler are passed along,
|
||||
* untouched to this `NoProgressTask` instance.
|
||||
*
|
||||
* @param args arguments passed to this task passed on from
|
||||
* `commands.registerCommand`.
|
||||
*/
|
||||
export type NoProgressTask = (...args: any[]) => Promise<any>;
|
||||
|
||||
/**
|
||||
* A generic wrapper for command registration. This wrapper adds uniform error handling for commands.
|
||||
*
|
||||
* In this variant of the command runner, no progress monitor is used.
|
||||
*
|
||||
* @param commandId The ID of the command to register.
|
||||
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
|
||||
* arguments to the command handler are passed on to the task.
|
||||
*/
|
||||
export function commandRunner(
|
||||
commandId: string,
|
||||
task: NoProgressTask,
|
||||
outputLogger = extLogger,
|
||||
): Disposable {
|
||||
return commands.registerCommand(commandId, async (...args: any[]) => {
|
||||
const startTime = Date.now();
|
||||
let error: Error | undefined;
|
||||
|
||||
try {
|
||||
return await task(...args);
|
||||
} catch (e) {
|
||||
error = asError(e);
|
||||
const errorMessage = redactableError(error)`${
|
||||
getErrorMessage(e) || e
|
||||
} (${commandId})`;
|
||||
const errorStack = getErrorStack(e);
|
||||
if (e instanceof UserCancellationException) {
|
||||
// User has cancelled this action manually
|
||||
if (e.silent) {
|
||||
void outputLogger.log(errorMessage.fullMessage);
|
||||
} else {
|
||||
void showAndLogWarningMessage(errorMessage.fullMessage, {
|
||||
outputLogger,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Include the full stack in the error log only.
|
||||
const fullMessage = errorStack
|
||||
? `${errorMessage.fullMessage}\n${errorStack}`
|
||||
: errorMessage.fullMessage;
|
||||
void showAndLogExceptionWithTelemetry(errorMessage, {
|
||||
outputLogger,
|
||||
fullMessage,
|
||||
extraTelemetryProperties: {
|
||||
command: commandId,
|
||||
},
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
} finally {
|
||||
const executionTime = Date.now() - startTime;
|
||||
telemetryListener?.sendCommandUsage(commandId, executionTime, error);
|
||||
}
|
||||
});
|
||||
}
|
|
@ -1,7 +1,18 @@
|
|||
import { commands } from "vscode";
|
||||
import { commandRunner, NoProgressTask } from "../../commandRunner";
|
||||
import { commands, Disposable } from "vscode";
|
||||
import { CommandFunction, CommandManager } from "../../packages/commands";
|
||||
import { OutputChannelLogger } from "../logging";
|
||||
import { extLogger, OutputChannelLogger } from "../logging";
|
||||
import {
|
||||
asError,
|
||||
getErrorMessage,
|
||||
getErrorStack,
|
||||
} from "../../pure/helpers-pure";
|
||||
import { redactableError } from "../../pure/errors";
|
||||
import { UserCancellationException } from "../../progress";
|
||||
import {
|
||||
showAndLogExceptionWithTelemetry,
|
||||
showAndLogWarningMessage,
|
||||
} from "../../helpers";
|
||||
import { telemetryListener } from "../../telemetry";
|
||||
|
||||
/**
|
||||
* Create a command manager for VSCode, wrapping the commandRunner
|
||||
|
@ -10,11 +21,65 @@ import { OutputChannelLogger } from "../logging";
|
|||
export function createVSCodeCommandManager<
|
||||
Commands extends Record<string, CommandFunction>,
|
||||
>(outputLogger?: OutputChannelLogger): CommandManager<Commands> {
|
||||
return new CommandManager((commandId, task: NoProgressTask) => {
|
||||
return commandRunner(commandId, task, outputLogger);
|
||||
return new CommandManager((commandId, task) => {
|
||||
return registerCommandWithErrorHandling(commandId, task, outputLogger);
|
||||
}, wrapExecuteCommand);
|
||||
}
|
||||
|
||||
/**
|
||||
* A wrapper for command registration. This wrapper adds uniform error handling for commands.
|
||||
*
|
||||
* @param commandId The ID of the command to register.
|
||||
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
|
||||
* arguments to the command handler are passed on to the task.
|
||||
*/
|
||||
export function registerCommandWithErrorHandling(
|
||||
commandId: string,
|
||||
task: (...args: any[]) => Promise<any>,
|
||||
outputLogger = extLogger,
|
||||
): Disposable {
|
||||
return commands.registerCommand(commandId, async (...args: any[]) => {
|
||||
const startTime = Date.now();
|
||||
let error: Error | undefined;
|
||||
|
||||
try {
|
||||
return await task(...args);
|
||||
} catch (e) {
|
||||
error = asError(e);
|
||||
const errorMessage = redactableError(error)`${
|
||||
getErrorMessage(e) || e
|
||||
} (${commandId})`;
|
||||
const errorStack = getErrorStack(e);
|
||||
if (e instanceof UserCancellationException) {
|
||||
// User has cancelled this action manually
|
||||
if (e.silent) {
|
||||
void outputLogger.log(errorMessage.fullMessage);
|
||||
} else {
|
||||
void showAndLogWarningMessage(errorMessage.fullMessage, {
|
||||
outputLogger,
|
||||
});
|
||||
}
|
||||
} else {
|
||||
// Include the full stack in the error log only.
|
||||
const fullMessage = errorStack
|
||||
? `${errorMessage.fullMessage}\n${errorStack}`
|
||||
: errorMessage.fullMessage;
|
||||
void showAndLogExceptionWithTelemetry(errorMessage, {
|
||||
outputLogger,
|
||||
fullMessage,
|
||||
extraTelemetryProperties: {
|
||||
command: commandId,
|
||||
},
|
||||
});
|
||||
}
|
||||
return undefined;
|
||||
} finally {
|
||||
const executionTime = Date.now() - startTime;
|
||||
telemetryListener?.sendCommandUsage(commandId, executionTime, error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* wrapExecuteCommand wraps commands.executeCommand to satisfy that the
|
||||
* type is a Promise. Type script does not seem to be smart enough
|
||||
|
|
|
@ -87,7 +87,6 @@ import { QLTestAdapterFactory } from "./test-adapter";
|
|||
import { TestUIService } from "./test-ui";
|
||||
import { CompareView } from "./compare/compare-view";
|
||||
import { initializeTelemetry } from "./telemetry";
|
||||
import { commandRunner } from "./commandRunner";
|
||||
import { ProgressCallback, withProgress } from "./progress";
|
||||
import { CodeQlStatusBarHandler } from "./status-bar";
|
||||
import { getPackagingCommands } from "./packaging";
|
||||
|
@ -123,6 +122,7 @@ import {
|
|||
import { getAstCfgCommands } from "./ast-cfg-commands";
|
||||
import { getQueryEditorCommands } from "./query-editor";
|
||||
import { App } from "./common/app";
|
||||
import { registerCommandWithErrorHandling } from "./common/vscode/commands";
|
||||
|
||||
/**
|
||||
* extension.ts
|
||||
|
@ -238,7 +238,9 @@ function registerErrorStubs(
|
|||
if (excludedCommands.indexOf(command) === -1) {
|
||||
// This is purposefully using `commandRunner` instead of the command manager because these
|
||||
// commands are untyped and registered pre-activation.
|
||||
errorStubs.push(commandRunner(command, stubGenerator(command)));
|
||||
errorStubs.push(
|
||||
registerCommandWithErrorHandling(command, stubGenerator(command)),
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
@ -341,7 +343,7 @@ export async function activate(
|
|||
ctx.subscriptions.push(
|
||||
// This is purposefully using `commandRunner` directly instead of the command manager
|
||||
// because this command is registered pre-activation.
|
||||
commandRunner(checkForUpdatesCommand, () =>
|
||||
registerCommandWithErrorHandling(checkForUpdatesCommand, () =>
|
||||
installOrUpdateThenTryActivate(
|
||||
ctx,
|
||||
app,
|
||||
|
|
Загрузка…
Ссылка в новой задаче