Skip to content

Commit 539284b

Browse files
authored
Merge pull request #2511 from github/koesie10/show-and-log-without-vscode
Make the showAndLog family of functions usable without the `vscode` module
2 parents 8803433 + 108d526 commit 539284b

56 files changed

Lines changed: 547 additions & 343 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

extensions/ql-vscode/src/codeql-cli/distribution.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ import {
2525
import {
2626
showAndLogErrorMessage,
2727
showAndLogWarningMessage,
28-
} from "../common/vscode/log";
28+
} from "../common/logging";
2929

3030
/**
3131
* distribution.ts
@@ -160,6 +160,7 @@ export class DistributionManager implements DistributionProvider {
160160
if (this.config.customCodeQlPath) {
161161
if (!(await pathExists(this.config.customCodeQlPath))) {
162162
void showAndLogErrorMessage(
163+
extLogger,
163164
`The CodeQL executable path is specified as "${this.config.customCodeQlPath}" ` +
164165
"by a configuration setting, but a CodeQL executable could not be found at that path. Please check " +
165166
"that a CodeQL executable exists at the specified path or remove the setting.",
@@ -852,6 +853,7 @@ export async function getExecutableFromDirectory(
852853

853854
function warnDeprecatedLauncher() {
854855
void showAndLogWarningMessage(
856+
extLogger,
855857
`The "${deprecatedCodeQlLauncherName()!}" launcher has been deprecated and will be removed in a future version. ` +
856858
`Please use "${codeQlLauncherName()}" instead. It is recommended to update to the latest CodeQL binaries.`,
857859
);

extensions/ql-vscode/src/codeql-cli/query-language.ts

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ import { isQueryLanguage, QueryLanguage } from "../common/query-language";
44
import { getOnDiskWorkspaceFolders } from "../common/vscode/workspace-folders";
55
import { extLogger } from "../common";
66
import { UserCancellationException } from "../common/vscode/progress";
7-
import { showAndLogErrorMessage } from "../common/vscode/log";
7+
import { showAndLogErrorMessage } from "../common/logging";
88

99
/**
1010
* Finds the language that a query targets.
@@ -59,6 +59,7 @@ export async function askForLanguage(
5959
throw new UserCancellationException("Cancelled.");
6060
} else {
6161
void showAndLogErrorMessage(
62+
extLogger,
6263
"Language not found. Language must be specified manually.",
6364
);
6465
}
@@ -67,6 +68,7 @@ export async function askForLanguage(
6768

6869
if (!isQueryLanguage(language)) {
6970
void showAndLogErrorMessage(
71+
extLogger,
7072
`Language '${language}' is not supported. Only languages ${Object.values(
7173
QueryLanguage,
7274
).join(", ")} are supported.`,

extensions/ql-vscode/src/common/app.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
import { Credentials } from "./authentication";
22
import { Disposable } from "../pure/disposable-object";
33
import { AppEventEmitter } from "./events";
4-
import { Logger } from "./logging";
4+
import { NotificationLogger } from "./logging";
55
import { Memento } from "./memento";
66
import { AppCommandManager } from "./commands";
77

88
export interface App {
99
createEventEmitter<T>(): AppEventEmitter<T>;
1010
readonly mode: AppMode;
11-
readonly logger: Logger;
11+
readonly logger: NotificationLogger;
1212
readonly subscriptions: Disposable[];
1313
readonly extensionPath: string;
1414
readonly globalStoragePath: string;
Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
11
export * from "./logger";
2+
export * from "./notification-logger";
3+
export * from "./notifications";
24
export * from "./tee-logger";
35
export * from "./vscode/loggers";
46
export * from "./vscode/output-channel-logger";
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
import { Logger } from "./logger";
2+
3+
export interface NotificationLogger extends Logger {
4+
showErrorMessage(message: string): Promise<void>;
5+
showWarningMessage(message: string): Promise<void>;
6+
showInformationMessage(message: string): Promise<void>;
7+
}
Lines changed: 89 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,89 @@
1+
import { NotificationLogger } from "./notification-logger";
2+
3+
export interface ShowAndLogOptions {
4+
/**
5+
* An alternate message that is added to the log, but not displayed in the popup.
6+
* This is useful for adding extra detail to the logs that would be too noisy for the popup.
7+
*/
8+
fullMessage?: string;
9+
}
10+
11+
/**
12+
* Show an error message and log it to the console
13+
*
14+
* @param logger The logger that will receive the message.
15+
* @param message The message to show.
16+
* @param options? See individual fields on `ShowAndLogOptions` type.
17+
*
18+
* @return A promise that resolves to the selected item or undefined when being dismissed.
19+
*/
20+
export async function showAndLogErrorMessage(
21+
logger: NotificationLogger,
22+
message: string,
23+
options?: ShowAndLogOptions,
24+
): Promise<void> {
25+
return internalShowAndLog(
26+
logger,
27+
dropLinesExceptInitial(message),
28+
logger.showErrorMessage,
29+
{ fullMessage: message, ...options },
30+
);
31+
}
32+
33+
function dropLinesExceptInitial(message: string, n = 2) {
34+
return message.toString().split(/\r?\n/).slice(0, n).join("\n");
35+
}
36+
37+
/**
38+
* Show a warning message and log it to the console
39+
*
40+
* @param logger The logger that will receive the message.
41+
* @param message The message to show.
42+
* @param options? See individual fields on `ShowAndLogOptions` type.
43+
*
44+
* @return A promise that resolves to the selected item or undefined when being dismissed.
45+
*/
46+
export async function showAndLogWarningMessage(
47+
logger: NotificationLogger,
48+
message: string,
49+
options?: ShowAndLogOptions,
50+
): Promise<void> {
51+
return internalShowAndLog(
52+
logger,
53+
message,
54+
logger.showWarningMessage,
55+
options,
56+
);
57+
}
58+
59+
/**
60+
* Show an information message and log it to the console
61+
*
62+
* @param logger The logger that will receive the message.
63+
* @param message The message to show.
64+
* @param options? See individual fields on `ShowAndLogOptions` type.
65+
*
66+
* @return A promise that resolves to the selected item or undefined when being dismissed.
67+
*/
68+
export async function showAndLogInformationMessage(
69+
logger: NotificationLogger,
70+
message: string,
71+
options?: ShowAndLogOptions,
72+
): Promise<void> {
73+
return internalShowAndLog(
74+
logger,
75+
message,
76+
logger.showInformationMessage,
77+
options,
78+
);
79+
}
80+
81+
async function internalShowAndLog(
82+
logger: NotificationLogger,
83+
message: string,
84+
fn: (message: string) => Promise<void>,
85+
{ fullMessage }: ShowAndLogOptions = {},
86+
): Promise<void> {
87+
void logger.log(fullMessage || message);
88+
await fn.bind(logger)(message);
89+
}

extensions/ql-vscode/src/common/logging/vscode/output-channel-logger.ts

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,15 @@
11
import { window as Window, OutputChannel, Progress } from "vscode";
22
import { Logger, LogOptions } from "../logger";
33
import { DisposableObject } from "../../../pure/disposable-object";
4+
import { NotificationLogger } from "../notification-logger";
45

56
/**
67
* A logger that writes messages to an output channel in the VS Code Output tab.
78
*/
8-
export class OutputChannelLogger extends DisposableObject implements Logger {
9+
export class OutputChannelLogger
10+
extends DisposableObject
11+
implements Logger, NotificationLogger
12+
{
913
public readonly outputChannel: OutputChannel;
1014
isCustomLogDirectory: boolean;
1115

@@ -42,6 +46,30 @@ export class OutputChannelLogger extends DisposableObject implements Logger {
4246
show(preserveFocus?: boolean): void {
4347
this.outputChannel.show(preserveFocus);
4448
}
49+
50+
async showErrorMessage(message: string): Promise<void> {
51+
await this.showMessage(message, Window.showErrorMessage);
52+
}
53+
54+
async showInformationMessage(message: string): Promise<void> {
55+
await this.showMessage(message, Window.showInformationMessage);
56+
}
57+
58+
async showWarningMessage(message: string): Promise<void> {
59+
await this.showMessage(message, Window.showWarningMessage);
60+
}
61+
62+
private async showMessage(
63+
message: string,
64+
show: (message: string, ...items: string[]) => Thenable<string | undefined>,
65+
): Promise<void> {
66+
const label = "Show Log";
67+
const result = await show(message, label);
68+
69+
if (result === label) {
70+
this.show();
71+
}
72+
}
4573
}
4674

4775
export type ProgressReporter = Progress<{ message: string }>;

extensions/ql-vscode/src/common/vscode/commands.ts

Lines changed: 13 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11
import { commands, Disposable } from "vscode";
22
import { CommandFunction, CommandManager } from "../../packages/commands";
3-
import { extLogger, OutputChannelLogger } from "../logging";
3+
import {
4+
extLogger,
5+
NotificationLogger,
6+
showAndLogWarningMessage,
7+
} from "../logging";
48
import {
59
asError,
610
getErrorMessage,
@@ -9,20 +13,17 @@ import {
913
import { redactableError } from "../../pure/errors";
1014
import { UserCancellationException } from "./progress";
1115
import { telemetryListener } from "../../telemetry";
12-
import {
13-
showAndLogExceptionWithTelemetry,
14-
showAndLogWarningMessage,
15-
} from "./log";
16+
import { showAndLogExceptionWithTelemetry } from "./logging";
1617

1718
/**
1819
* Create a command manager for VSCode, wrapping registerCommandWithErrorHandling
1920
* and vscode.executeCommand.
2021
*/
2122
export function createVSCodeCommandManager<
2223
Commands extends Record<string, CommandFunction>,
23-
>(outputLogger?: OutputChannelLogger): CommandManager<Commands> {
24+
>(logger?: NotificationLogger): CommandManager<Commands> {
2425
return new CommandManager((commandId, task) => {
25-
return registerCommandWithErrorHandling(commandId, task, outputLogger);
26+
return registerCommandWithErrorHandling(commandId, task, logger);
2627
}, wrapExecuteCommand);
2728
}
2829

@@ -32,11 +33,12 @@ export function createVSCodeCommandManager<
3233
* @param commandId The ID of the command to register.
3334
* @param task The task to run. It is passed directly to `commands.registerCommand`. Any
3435
* arguments to the command handler are passed on to the task.
36+
* @param logger The logger to use for error reporting.
3537
*/
3638
export function registerCommandWithErrorHandling(
3739
commandId: string,
3840
task: (...args: any[]) => Promise<any>,
39-
outputLogger = extLogger,
41+
logger: NotificationLogger = extLogger,
4042
): Disposable {
4143
return commands.registerCommand(commandId, async (...args: any[]) => {
4244
const startTime = Date.now();
@@ -52,20 +54,17 @@ export function registerCommandWithErrorHandling(
5254
if (e instanceof UserCancellationException) {
5355
// User has cancelled this action manually
5456
if (e.silent) {
55-
void outputLogger.log(errorMessage.fullMessage);
57+
void logger.log(errorMessage.fullMessage);
5658
} else {
57-
void showAndLogWarningMessage(errorMessage.fullMessage, {
58-
outputLogger,
59-
});
59+
void showAndLogWarningMessage(logger, errorMessage.fullMessage);
6060
}
6161
} else {
6262
// Include the full stack in the error log only.
6363
const errorStack = getErrorStack(e);
6464
const fullMessage = errorStack
6565
? `${errorMessage.fullMessage}\n${errorStack}`
6666
: errorMessage.fullMessage;
67-
void showAndLogExceptionWithTelemetry(errorMessage, {
68-
outputLogger,
67+
void showAndLogExceptionWithTelemetry(logger, errorMessage, {
6968
fullMessage,
7069
extraTelemetryProperties: {
7170
command: commandId,

extensions/ql-vscode/src/common/vscode/external-files.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ import {
77
getErrorMessage,
88
getErrorStack,
99
} from "../../pure/helpers-pure";
10-
import { showAndLogExceptionWithTelemetry } from "./log";
10+
import { extLogger } from "../logging";
11+
import { showAndLogExceptionWithTelemetry } from "./logging";
1112

1213
export async function tryOpenExternalFile(
1314
commandManager: AppCommandManager,
@@ -34,6 +35,7 @@ the file in the file explorer and dragging it into the workspace.`,
3435
await commandManager.execute("revealFileInOS", uri);
3536
} catch (e) {
3637
void showAndLogExceptionWithTelemetry(
38+
extLogger,
3739
redactableError(
3840
asError(e),
3941
)`Failed to reveal file in OS: ${getErrorMessage(e)}`,
@@ -42,6 +44,7 @@ the file in the file explorer and dragging it into the workspace.`,
4244
}
4345
} else {
4446
void showAndLogExceptionWithTelemetry(
47+
extLogger,
4548
redactableError(asError(e))`Could not open file ${fileLocation}`,
4649
{
4750
fullMessage: `${getErrorMessage(e)}\n${getErrorStack(e)}`,

0 commit comments

Comments
 (0)