Refactor: Move commandRunner to its own module
Also, extract related functions and types. There are no behavioral changes in this commit. Only refactorings.
This commit is contained in:
4
.vscode/launch.json
vendored
4
.vscode/launch.json
vendored
@@ -8,7 +8,9 @@
|
|||||||
"request": "launch",
|
"request": "launch",
|
||||||
"runtimeExecutable": "${execPath}",
|
"runtimeExecutable": "${execPath}",
|
||||||
"args": [
|
"args": [
|
||||||
"--extensionDevelopmentPath=${workspaceRoot}/extensions/ql-vscode"
|
"--extensionDevelopmentPath=${workspaceRoot}/extensions/ql-vscode",
|
||||||
|
// Add a reference to a workspace to open. Eg-
|
||||||
|
// "${workspaceRoot}/../vscode-codeql-starter/vscode-codeql-starter.code-workspace"
|
||||||
],
|
],
|
||||||
"stopOnEntry": false,
|
"stopOnEntry": false,
|
||||||
"sourceMaps": true,
|
"sourceMaps": true,
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ import { DatabaseItem } from './databases';
|
|||||||
import { UrlValue, BqrsId } from './pure/bqrs-cli-types';
|
import { UrlValue, BqrsId } from './pure/bqrs-cli-types';
|
||||||
import { showLocation } from './interface-utils';
|
import { showLocation } from './interface-utils';
|
||||||
import { isStringLoc, isWholeFileLoc, isLineColumnLoc } from './pure/bqrs-utils';
|
import { isStringLoc, isWholeFileLoc, isLineColumnLoc } from './pure/bqrs-utils';
|
||||||
import { commandRunner } from './helpers';
|
import { commandRunner } from './commandRunner';
|
||||||
import { DisposableObject } from './vscode-utils/disposable-object';
|
import { DisposableObject } from './vscode-utils/disposable-object';
|
||||||
|
|
||||||
export interface AstItem {
|
export interface AstItem {
|
||||||
|
|||||||
215
extensions/ql-vscode/src/commandRunner.ts
Normal file
215
extensions/ql-vscode/src/commandRunner.ts
Normal file
@@ -0,0 +1,215 @@
|
|||||||
|
import {
|
||||||
|
CancellationToken,
|
||||||
|
ProgressOptions,
|
||||||
|
window as Window,
|
||||||
|
commands,
|
||||||
|
Disposable,
|
||||||
|
ProgressLocation
|
||||||
|
} from 'vscode';
|
||||||
|
import { showAndLogErrorMessage, showAndLogWarningMessage } from './helpers';
|
||||||
|
import { logger } from './logging';
|
||||||
|
|
||||||
|
export class UserCancellationException extends Error {
|
||||||
|
/**
|
||||||
|
* @param message The error message
|
||||||
|
* @param silent If silent is true, then this exception will avoid showing a warning message to the user.
|
||||||
|
*/
|
||||||
|
constructor(message?: string, public readonly silent = false) {
|
||||||
|
super(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ProgressUpdate {
|
||||||
|
/**
|
||||||
|
* The current step
|
||||||
|
*/
|
||||||
|
step: number;
|
||||||
|
/**
|
||||||
|
* The maximum step. This *should* be constant for a single job.
|
||||||
|
*/
|
||||||
|
maxStep: number;
|
||||||
|
/**
|
||||||
|
* The current progress message
|
||||||
|
*/
|
||||||
|
message: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProgressCallback = (p: ProgressUpdate) => void;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A task that handles command invocations from `commandRunner`
|
||||||
|
* and includes a progress monitor.
|
||||||
|
*
|
||||||
|
*
|
||||||
|
* Arguments passed to the command handler are passed along,
|
||||||
|
* untouched to this `ProgressTask` instance.
|
||||||
|
*
|
||||||
|
* @param progress a progress handler function. Call this
|
||||||
|
* function with a `ProgressUpdate` instance in order to
|
||||||
|
* denote some progress being achieved on this task.
|
||||||
|
* @param token a cencellation token
|
||||||
|
* @param args arguments passed to this task passed on from
|
||||||
|
* `commands.registerCommand`.
|
||||||
|
*/
|
||||||
|
export type ProgressTask<R> = (
|
||||||
|
progress: ProgressCallback,
|
||||||
|
token: CancellationToken,
|
||||||
|
...args: any[]
|
||||||
|
) => Thenable<R>;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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`.
|
||||||
|
*/
|
||||||
|
type NoProgressTask = ((...args: any[]) => Promise<any>);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This mediates between the kind of progress callbacks we want to
|
||||||
|
* write (where we *set* current progress position and give
|
||||||
|
* `maxSteps`) and the kind vscode progress api expects us to write
|
||||||
|
* (which increment progress by a certain amount out of 100%).
|
||||||
|
*
|
||||||
|
* Where possible, the `commandRunner` function below should be used
|
||||||
|
* instead of this function. The commandRunner is meant for wrapping
|
||||||
|
* top-level commands and provides error handling and other support
|
||||||
|
* automatically.
|
||||||
|
*
|
||||||
|
* Only use this function if you need a progress monitor and the
|
||||||
|
* control flow does not always come from a command (eg- during
|
||||||
|
* extension activation, or from an internal language server
|
||||||
|
* request).
|
||||||
|
*/
|
||||||
|
export function withProgress<R>(
|
||||||
|
options: ProgressOptions,
|
||||||
|
task: ProgressTask<R>,
|
||||||
|
...args: any[]
|
||||||
|
): Thenable<R> {
|
||||||
|
let progressAchieved = 0;
|
||||||
|
return Window.withProgress(options,
|
||||||
|
(progress, token) => {
|
||||||
|
return task(p => {
|
||||||
|
const { message, step, maxStep } = p;
|
||||||
|
const increment = 100 * (step - progressAchieved) / maxStep;
|
||||||
|
progressAchieved = step;
|
||||||
|
progress.report({ message, increment });
|
||||||
|
}, token, ...args);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* 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,
|
||||||
|
): Disposable {
|
||||||
|
return commands.registerCommand(commandId, async (...args: any[]) => {
|
||||||
|
try {
|
||||||
|
return await task(...args);
|
||||||
|
} catch (e) {
|
||||||
|
const errorMessage = `${e.message || e} (${commandId})`;
|
||||||
|
if (e instanceof UserCancellationException) {
|
||||||
|
// User has cancelled this action manually
|
||||||
|
if (e.silent) {
|
||||||
|
logger.log(errorMessage);
|
||||||
|
} else {
|
||||||
|
showAndLogWarningMessage(errorMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showAndLogErrorMessage(errorMessage);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* A generic wrapper for command registration. This wrapper adds uniform error handling,
|
||||||
|
* progress monitoring, and cancellation 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 after the progress callback
|
||||||
|
* and cancellation token.
|
||||||
|
* @param progressOptions Progress options to be sent to the progress monitor.
|
||||||
|
*/
|
||||||
|
export function commandRunnerWithProgress<R>(
|
||||||
|
commandId: string,
|
||||||
|
task: ProgressTask<R>,
|
||||||
|
progressOptions: Partial<ProgressOptions>
|
||||||
|
): Disposable {
|
||||||
|
return commands.registerCommand(commandId, async (...args: any[]) => {
|
||||||
|
const progressOptionsWithDefaults = {
|
||||||
|
location: ProgressLocation.Notification,
|
||||||
|
...progressOptions
|
||||||
|
};
|
||||||
|
try {
|
||||||
|
return await withProgress(progressOptionsWithDefaults, task, ...args);
|
||||||
|
} catch (e) {
|
||||||
|
const errorMessage = `${e.message || e} (${commandId})`;
|
||||||
|
if (e instanceof UserCancellationException) {
|
||||||
|
// User has cancelled this action manually
|
||||||
|
if (e.silent) {
|
||||||
|
logger.log(errorMessage);
|
||||||
|
} else {
|
||||||
|
showAndLogWarningMessage(errorMessage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
showAndLogErrorMessage(errorMessage);
|
||||||
|
}
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Displays a progress monitor that indicates how much progess has been made
|
||||||
|
* reading from a stream.
|
||||||
|
*
|
||||||
|
* @param readable The stream to read progress from
|
||||||
|
* @param messagePrefix A prefix for displaying the message
|
||||||
|
* @param totalNumBytes Total number of bytes in this stream
|
||||||
|
* @param progress The progress callback used to set messages
|
||||||
|
*/
|
||||||
|
export function reportStreamProgress(
|
||||||
|
readable: NodeJS.ReadableStream,
|
||||||
|
messagePrefix: string,
|
||||||
|
totalNumBytes?: number,
|
||||||
|
progress?: ProgressCallback
|
||||||
|
) {
|
||||||
|
if (progress && totalNumBytes) {
|
||||||
|
let numBytesDownloaded = 0;
|
||||||
|
const bytesToDisplayMB = (numBytes: number): string => `${(numBytes / (1024 * 1024)).toFixed(1)} MB`;
|
||||||
|
const updateProgress = () => {
|
||||||
|
progress({
|
||||||
|
step: numBytesDownloaded,
|
||||||
|
maxStep: totalNumBytes,
|
||||||
|
message: `${messagePrefix} [${bytesToDisplayMB(numBytesDownloaded)} of ${bytesToDisplayMB(totalNumBytes)}]`,
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
// Display the progress straight away rather than waiting for the first chunk.
|
||||||
|
updateProgress();
|
||||||
|
|
||||||
|
readable.on('data', data => {
|
||||||
|
numBytesDownloaded += data.length;
|
||||||
|
updateProgress();
|
||||||
|
});
|
||||||
|
} else if (progress) {
|
||||||
|
progress({
|
||||||
|
step: 1,
|
||||||
|
maxStep: 2,
|
||||||
|
message: `${messagePrefix} (Size unknown)`,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -8,7 +8,7 @@ import fileRangeFromURI from './fileRangeFromURI';
|
|||||||
import * as messages from '../pure/messages';
|
import * as messages from '../pure/messages';
|
||||||
import { QueryServerClient } from '../queryserver-client';
|
import { QueryServerClient } from '../queryserver-client';
|
||||||
import { QueryWithResults, compileAndRunQueryAgainstDatabase } from '../run-queries';
|
import { QueryWithResults, compileAndRunQueryAgainstDatabase } from '../run-queries';
|
||||||
import { ProgressCallback } from '../helpers';
|
import { ProgressCallback } from '../commandRunner';
|
||||||
import { KeyType } from './keyType';
|
import { KeyType } from './keyType';
|
||||||
import { qlpackOfDatabase, resolveQueries } from './queryResolver';
|
import { qlpackOfDatabase, resolveQueries } from './queryResolver';
|
||||||
|
|
||||||
|
|||||||
@@ -3,7 +3,8 @@ import * as vscode from 'vscode';
|
|||||||
import { decodeSourceArchiveUri, encodeArchiveBasePath, zipArchiveScheme } from '../archive-filesystem-provider';
|
import { decodeSourceArchiveUri, encodeArchiveBasePath, zipArchiveScheme } from '../archive-filesystem-provider';
|
||||||
import { CodeQLCliServer } from '../cli';
|
import { CodeQLCliServer } from '../cli';
|
||||||
import { DatabaseManager } from '../databases';
|
import { DatabaseManager } from '../databases';
|
||||||
import { CachedOperation, ProgressCallback, withProgress } from '../helpers';
|
import { CachedOperation } from '../helpers';
|
||||||
|
import { ProgressCallback, withProgress } from '../commandRunner';
|
||||||
import * as messages from '../pure/messages';
|
import * as messages from '../pure/messages';
|
||||||
import { QueryServerClient } from '../queryserver-client';
|
import { QueryServerClient } from '../queryserver-client';
|
||||||
import { compileAndRunQueryAgainstDatabase, QueryWithResults } from '../run-queries';
|
import { compileAndRunQueryAgainstDatabase, QueryWithResults } from '../run-queries';
|
||||||
|
|||||||
@@ -12,10 +12,12 @@ import * as path from 'path';
|
|||||||
|
|
||||||
import { DatabaseManager, DatabaseItem } from './databases';
|
import { DatabaseManager, DatabaseItem } from './databases';
|
||||||
import {
|
import {
|
||||||
reportStreamProgress,
|
|
||||||
ProgressCallback,
|
|
||||||
showAndLogInformationMessage,
|
showAndLogInformationMessage,
|
||||||
} from './helpers';
|
} from './helpers';
|
||||||
|
import {
|
||||||
|
reportStreamProgress,
|
||||||
|
ProgressCallback,
|
||||||
|
} from './commandRunner';
|
||||||
import { logger } from './logging';
|
import { logger } from './logging';
|
||||||
import { tmpDir } from './run-queries';
|
import { tmpDir } from './run-queries';
|
||||||
|
|
||||||
|
|||||||
@@ -22,8 +22,10 @@ import {
|
|||||||
import {
|
import {
|
||||||
commandRunner,
|
commandRunner,
|
||||||
commandRunnerWithProgress,
|
commandRunnerWithProgress,
|
||||||
getOnDiskWorkspaceFolders,
|
|
||||||
ProgressCallback,
|
ProgressCallback,
|
||||||
|
} from './commandRunner';
|
||||||
|
import {
|
||||||
|
getOnDiskWorkspaceFolders,
|
||||||
showAndLogErrorMessage,
|
showAndLogErrorMessage,
|
||||||
isLikelyDatabaseRoot,
|
isLikelyDatabaseRoot,
|
||||||
isLikelyDbLanguageFolder
|
isLikelyDbLanguageFolder
|
||||||
|
|||||||
@@ -9,9 +9,11 @@ import {
|
|||||||
showAndLogWarningMessage,
|
showAndLogWarningMessage,
|
||||||
showAndLogInformationMessage,
|
showAndLogInformationMessage,
|
||||||
isLikelyDatabaseRoot,
|
isLikelyDatabaseRoot,
|
||||||
|
} from './helpers';
|
||||||
|
import {
|
||||||
ProgressCallback,
|
ProgressCallback,
|
||||||
withProgress
|
withProgress
|
||||||
} from './helpers';
|
} from './commandRunner';
|
||||||
import { zipArchiveScheme, encodeArchiveBasePath, decodeSourceArchiveUri, encodeSourceArchiveUri } from './archive-filesystem-provider';
|
import { zipArchiveScheme, encodeArchiveBasePath, decodeSourceArchiveUri, encodeSourceArchiveUri } from './archive-filesystem-provider';
|
||||||
import { DisposableObject } from './vscode-utils/disposable-object';
|
import { DisposableObject } from './vscode-utils/disposable-object';
|
||||||
import { Logger, logger } from './logging';
|
import { Logger, logger } from './logging';
|
||||||
|
|||||||
@@ -7,10 +7,15 @@ import * as unzipper from 'unzipper';
|
|||||||
import * as url from 'url';
|
import * as url from 'url';
|
||||||
import { ExtensionContext, Event } from 'vscode';
|
import { ExtensionContext, Event } from 'vscode';
|
||||||
import { DistributionConfig } from './config';
|
import { DistributionConfig } from './config';
|
||||||
import { InvocationRateLimiter, InvocationRateLimiterResultKind, showAndLogErrorMessage } from './helpers';
|
import {
|
||||||
|
InvocationRateLimiter,
|
||||||
|
InvocationRateLimiterResultKind,
|
||||||
|
showAndLogErrorMessage,
|
||||||
|
showAndLogWarningMessage
|
||||||
|
} from './helpers';
|
||||||
import { logger } from './logging';
|
import { logger } from './logging';
|
||||||
import * as helpers from './helpers';
|
|
||||||
import { getCodeQlCliVersion } from './cli-version';
|
import { getCodeQlCliVersion } from './cli-version';
|
||||||
|
import { ProgressCallback, reportStreamProgress } from './commandRunner';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* distribution.ts
|
* distribution.ts
|
||||||
@@ -221,7 +226,7 @@ export class DistributionManager implements DistributionProvider {
|
|||||||
* Returns a failed promise if an unexpected error occurs during installation.
|
* Returns a failed promise if an unexpected error occurs during installation.
|
||||||
*/
|
*/
|
||||||
public installExtensionManagedDistributionRelease(release: Release,
|
public installExtensionManagedDistributionRelease(release: Release,
|
||||||
progressCallback?: helpers.ProgressCallback): Promise<void> {
|
progressCallback?: ProgressCallback): Promise<void> {
|
||||||
return this.extensionSpecificDistributionManager!.installDistributionRelease(release, progressCallback);
|
return this.extensionSpecificDistributionManager!.installDistributionRelease(release, progressCallback);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -303,14 +308,14 @@ class ExtensionSpecificDistributionManager {
|
|||||||
* Returns a failed promise if an unexpected error occurs during installation.
|
* Returns a failed promise if an unexpected error occurs during installation.
|
||||||
*/
|
*/
|
||||||
public async installDistributionRelease(release: Release,
|
public async installDistributionRelease(release: Release,
|
||||||
progressCallback?: helpers.ProgressCallback): Promise<void> {
|
progressCallback?: ProgressCallback): Promise<void> {
|
||||||
await this.downloadDistribution(release, progressCallback);
|
await this.downloadDistribution(release, progressCallback);
|
||||||
// Store the installed release within the global extension state.
|
// Store the installed release within the global extension state.
|
||||||
this.storeInstalledRelease(release);
|
this.storeInstalledRelease(release);
|
||||||
}
|
}
|
||||||
|
|
||||||
private async downloadDistribution(release: Release,
|
private async downloadDistribution(release: Release,
|
||||||
progressCallback?: helpers.ProgressCallback): Promise<void> {
|
progressCallback?: ProgressCallback): Promise<void> {
|
||||||
try {
|
try {
|
||||||
await this.removeDistribution();
|
await this.removeDistribution();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
@@ -338,7 +343,7 @@ class ExtensionSpecificDistributionManager {
|
|||||||
|
|
||||||
const contentLength = assetStream.headers.get('content-length');
|
const contentLength = assetStream.headers.get('content-length');
|
||||||
const totalNumBytes = contentLength ? parseInt(contentLength, 10) : undefined;
|
const totalNumBytes = contentLength ? parseInt(contentLength, 10) : undefined;
|
||||||
helpers.reportStreamProgress(assetStream.body, 'Downloading CodeQL CLI…', totalNumBytes, progressCallback);
|
reportStreamProgress(assetStream.body, 'Downloading CodeQL CLI…', totalNumBytes, progressCallback);
|
||||||
|
|
||||||
await new Promise((resolve, reject) =>
|
await new Promise((resolve, reject) =>
|
||||||
assetStream.body.pipe(archiveFile)
|
assetStream.body.pipe(archiveFile)
|
||||||
@@ -707,7 +712,9 @@ export async function getExecutableFromDirectory(directory: string, warnWhenNotF
|
|||||||
}
|
}
|
||||||
|
|
||||||
function warnDeprecatedLauncher() {
|
function warnDeprecatedLauncher() {
|
||||||
helpers.showAndLogWarningMessage(
|
|
||||||
|
showAndLogWarningMessage(
|
||||||
|
|
||||||
`The "${deprecatedCodeQlLauncherName()!}" launcher has been deprecated and will be removed in a future version. ` +
|
`The "${deprecatedCodeQlLauncherName()!}" launcher has been deprecated and will be removed in a future version. ` +
|
||||||
`Please use "${codeQlLauncherName()}" instead. It is recommended to update to the latest CodeQL binaries.`
|
`Please use "${codeQlLauncherName()}" instead. It is recommended to update to the latest CodeQL binaries.`
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -45,6 +45,7 @@ import {
|
|||||||
GithubRateLimitedError
|
GithubRateLimitedError
|
||||||
} from './distribution';
|
} from './distribution';
|
||||||
import * as helpers from './helpers';
|
import * as helpers from './helpers';
|
||||||
|
import { commandRunner, commandRunnerWithProgress, ProgressCallback, ProgressUpdate, withProgress } from './commandRunner';
|
||||||
import { assertNever } from './pure/helpers-pure';
|
import { assertNever } from './pure/helpers-pure';
|
||||||
import { spawnIdeServer } from './ide-server';
|
import { spawnIdeServer } from './ide-server';
|
||||||
import { InterfaceManager } from './interface';
|
import { InterfaceManager } from './interface';
|
||||||
@@ -108,7 +109,7 @@ function registerErrorStubs(excludedCommands: string[], stubGenerator: (command:
|
|||||||
|
|
||||||
stubbedCommands.forEach(command => {
|
stubbedCommands.forEach(command => {
|
||||||
if (excludedCommands.indexOf(command) === -1) {
|
if (excludedCommands.indexOf(command) === -1) {
|
||||||
errorStubs.push(helpers.commandRunner(command, stubGenerator(command)));
|
errorStubs.push(commandRunner(command, stubGenerator(command)));
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@@ -194,7 +195,7 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
|
|||||||
location: ProgressLocation.Notification,
|
location: ProgressLocation.Notification,
|
||||||
};
|
};
|
||||||
|
|
||||||
await helpers.withProgress(progressOptions, progress =>
|
await withProgress(progressOptions, progress =>
|
||||||
distributionManager.installExtensionManagedDistributionRelease(result.updatedRelease, progress));
|
distributionManager.installExtensionManagedDistributionRelease(result.updatedRelease, progress));
|
||||||
|
|
||||||
await ctx.globalState.update(shouldUpdateOnNextActivationKey, false);
|
await ctx.globalState.update(shouldUpdateOnNextActivationKey, false);
|
||||||
@@ -308,7 +309,7 @@ export async function activate(ctx: ExtensionContext): Promise<CodeQLExtensionIn
|
|||||||
shouldDisplayMessageWhenNoUpdates: false,
|
shouldDisplayMessageWhenNoUpdates: false,
|
||||||
allowAutoUpdating: true
|
allowAutoUpdating: true
|
||||||
})));
|
})));
|
||||||
ctx.subscriptions.push(helpers.commandRunner(checkForUpdatesCommand, () => installOrUpdateThenTryActivate({
|
ctx.subscriptions.push(commandRunner(checkForUpdatesCommand, () => installOrUpdateThenTryActivate({
|
||||||
isUserInitiated: true,
|
isUserInitiated: true,
|
||||||
shouldDisplayMessageWhenNoUpdates: true,
|
shouldDisplayMessageWhenNoUpdates: true,
|
||||||
allowAutoUpdating: true
|
allowAutoUpdating: true
|
||||||
@@ -430,7 +431,7 @@ async function activateWithInstalledDistribution(
|
|||||||
async function compileAndRunQuery(
|
async function compileAndRunQuery(
|
||||||
quickEval: boolean,
|
quickEval: boolean,
|
||||||
selectedQuery: Uri | undefined,
|
selectedQuery: Uri | undefined,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
if (qs !== undefined) {
|
if (qs !== undefined) {
|
||||||
@@ -491,10 +492,10 @@ async function activateWithInstalledDistribution(
|
|||||||
|
|
||||||
logger.log('Registering top-level command palette commands.');
|
logger.log('Registering top-level command palette commands.');
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunnerWithProgress(
|
commandRunnerWithProgress(
|
||||||
'codeQL.runQuery',
|
'codeQL.runQuery',
|
||||||
async (
|
async (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
uri: Uri | undefined
|
uri: Uri | undefined
|
||||||
) => await compileAndRunQuery(false, uri, progress, token),
|
) => await compileAndRunQuery(false, uri, progress, token),
|
||||||
@@ -505,10 +506,10 @@ async function activateWithInstalledDistribution(
|
|||||||
)
|
)
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunnerWithProgress(
|
commandRunnerWithProgress(
|
||||||
'codeQL.runQueries',
|
'codeQL.runQueries',
|
||||||
async (
|
async (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
_: Uri | undefined,
|
_: Uri | undefined,
|
||||||
multi: Uri[]
|
multi: Uri[]
|
||||||
@@ -533,7 +534,7 @@ async function activateWithInstalledDistribution(
|
|||||||
|
|
||||||
// Use a wrapped progress so that messages appear with the queries remaining in it.
|
// Use a wrapped progress so that messages appear with the queries remaining in it.
|
||||||
let queriesRemaining = queryUris.length;
|
let queriesRemaining = queryUris.length;
|
||||||
function wrappedProgress(update: helpers.ProgressUpdate) {
|
function wrappedProgress(update: ProgressUpdate) {
|
||||||
const message = queriesRemaining > 1
|
const message = queriesRemaining > 1
|
||||||
? `${queriesRemaining} remaining. ${update.message}`
|
? `${queriesRemaining} remaining. ${update.message}`
|
||||||
: update.message;
|
: update.message;
|
||||||
@@ -569,10 +570,10 @@ async function activateWithInstalledDistribution(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunnerWithProgress(
|
commandRunnerWithProgress(
|
||||||
'codeQL.quickEval',
|
'codeQL.quickEval',
|
||||||
async (
|
async (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
uri: Uri | undefined
|
uri: Uri | undefined
|
||||||
) => await compileAndRunQuery(true, uri, progress, token),
|
) => await compileAndRunQuery(true, uri, progress, token),
|
||||||
@@ -582,8 +583,8 @@ async function activateWithInstalledDistribution(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunnerWithProgress('codeQL.quickQuery', async (
|
commandRunnerWithProgress('codeQL.quickQuery', async (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
) =>
|
) =>
|
||||||
displayQuickQuery(ctx, cliServer, databaseUI, progress, token),
|
displayQuickQuery(ctx, cliServer, databaseUI, progress, token),
|
||||||
@@ -594,7 +595,7 @@ async function activateWithInstalledDistribution(
|
|||||||
);
|
);
|
||||||
|
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunner('codeQL.restartQueryServer', async () => {
|
commandRunner('codeQL.restartQueryServer', async () => {
|
||||||
await qs.restartQueryServer();
|
await qs.restartQueryServer();
|
||||||
helpers.showAndLogInformationMessage('CodeQL Query Server restarted.', {
|
helpers.showAndLogInformationMessage('CodeQL Query Server restarted.', {
|
||||||
outputLogger: queryServerLogger,
|
outputLogger: queryServerLogger,
|
||||||
@@ -602,24 +603,24 @@ async function activateWithInstalledDistribution(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunner('codeQL.chooseDatabaseFolder', (
|
commandRunner('codeQL.chooseDatabaseFolder', (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
) =>
|
) =>
|
||||||
databaseUI.handleChooseDatabaseFolder(progress, token)
|
databaseUI.handleChooseDatabaseFolder(progress, token)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunner('codeQL.chooseDatabaseArchive', (
|
commandRunner('codeQL.chooseDatabaseArchive', (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
) =>
|
) =>
|
||||||
databaseUI.handleChooseDatabaseArchive(progress, token)
|
databaseUI.handleChooseDatabaseArchive(progress, token)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunnerWithProgress('codeQL.chooseDatabaseLgtm', (
|
commandRunnerWithProgress('codeQL.chooseDatabaseLgtm', (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
) =>
|
) =>
|
||||||
databaseUI.handleChooseDatabaseLgtm(progress, token),
|
databaseUI.handleChooseDatabaseLgtm(progress, token),
|
||||||
@@ -628,8 +629,8 @@ async function activateWithInstalledDistribution(
|
|||||||
})
|
})
|
||||||
);
|
);
|
||||||
ctx.subscriptions.push(
|
ctx.subscriptions.push(
|
||||||
helpers.commandRunnerWithProgress('codeQL.chooseDatabaseInternet', (
|
commandRunnerWithProgress('codeQL.chooseDatabaseInternet', (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
) =>
|
) =>
|
||||||
databaseUI.handleChooseDatabaseInternet(progress, token),
|
databaseUI.handleChooseDatabaseInternet(progress, token),
|
||||||
@@ -656,8 +657,8 @@ async function activateWithInstalledDistribution(
|
|||||||
|
|
||||||
const astViewer = new AstViewer();
|
const astViewer = new AstViewer();
|
||||||
ctx.subscriptions.push(astViewer);
|
ctx.subscriptions.push(astViewer);
|
||||||
ctx.subscriptions.push(helpers.commandRunnerWithProgress('codeQL.viewAst', async (
|
ctx.subscriptions.push(commandRunnerWithProgress('codeQL.viewAst', async (
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken
|
token: CancellationToken
|
||||||
) => {
|
) => {
|
||||||
const ast = await new TemplatePrintAstProvider(cliServer, qs, dbm, progress, token)
|
const ast = await new TemplatePrintAstProvider(cliServer, qs, dbm, progress, token)
|
||||||
|
|||||||
@@ -3,181 +3,13 @@ import * as glob from 'glob-promise';
|
|||||||
import * as yaml from 'js-yaml';
|
import * as yaml from 'js-yaml';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import {
|
import {
|
||||||
CancellationToken,
|
|
||||||
ExtensionContext,
|
ExtensionContext,
|
||||||
ProgressOptions,
|
|
||||||
window as Window,
|
window as Window,
|
||||||
workspace,
|
workspace
|
||||||
commands,
|
|
||||||
Disposable,
|
|
||||||
ProgressLocation
|
|
||||||
} from 'vscode';
|
} from 'vscode';
|
||||||
import { CodeQLCliServer } from './cli';
|
import { CodeQLCliServer } from './cli';
|
||||||
import { logger } from './logging';
|
import { logger } from './logging';
|
||||||
|
|
||||||
export class UserCancellationException extends Error {
|
|
||||||
/**
|
|
||||||
* @param message The error message
|
|
||||||
* @param silent If silent is true, then this exception will avoid showing a warning message to the user.
|
|
||||||
*/
|
|
||||||
constructor(message?: string, public readonly silent = false) {
|
|
||||||
super(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ProgressUpdate {
|
|
||||||
/**
|
|
||||||
* The current step
|
|
||||||
*/
|
|
||||||
step: number;
|
|
||||||
/**
|
|
||||||
* The maximum step. This *should* be constant for a single job.
|
|
||||||
*/
|
|
||||||
maxStep: number;
|
|
||||||
/**
|
|
||||||
* The current progress message
|
|
||||||
*/
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
export type ProgressCallback = (p: ProgressUpdate) => void;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A task that handles command invocations from `commandRunner`
|
|
||||||
* and includes a progress monitor.
|
|
||||||
*
|
|
||||||
*
|
|
||||||
* Arguments passed to the command handler are passed along,
|
|
||||||
* untouched to this `ProgressTask` instance.
|
|
||||||
*
|
|
||||||
* @param progress a progress handler function. Call this
|
|
||||||
* function with a `ProgressUpdate` instance in order to
|
|
||||||
* denote some progress being achieved on this task.
|
|
||||||
* @param token a cencellation token
|
|
||||||
* @param args arguments passed to this task passed on from
|
|
||||||
* `commands.registerCommand`.
|
|
||||||
*/
|
|
||||||
export type ProgressTask<R> = (
|
|
||||||
progress: ProgressCallback,
|
|
||||||
token: CancellationToken,
|
|
||||||
...args: any[]
|
|
||||||
) => Thenable<R>;
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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`.
|
|
||||||
*/
|
|
||||||
type NoProgressTask = ((...args: any[]) => Promise<any>);
|
|
||||||
|
|
||||||
/**
|
|
||||||
* This mediates between the kind of progress callbacks we want to
|
|
||||||
* write (where we *set* current progress position and give
|
|
||||||
* `maxSteps`) and the kind vscode progress api expects us to write
|
|
||||||
* (which increment progress by a certain amount out of 100%).
|
|
||||||
*
|
|
||||||
* Where possible, the `commandRunner` function below should be used
|
|
||||||
* instead of this function. The commandRunner is meant for wrapping
|
|
||||||
* top-level commands and provides error handling and other support
|
|
||||||
* automatically.
|
|
||||||
*
|
|
||||||
* Only use this function if you need a progress monitor and the
|
|
||||||
* control flow does not always come from a command (eg- during
|
|
||||||
* extension activation, or from an internal language server
|
|
||||||
* request).
|
|
||||||
*/
|
|
||||||
export function withProgress<R>(
|
|
||||||
options: ProgressOptions,
|
|
||||||
task: ProgressTask<R>,
|
|
||||||
...args: any[]
|
|
||||||
): Thenable<R> {
|
|
||||||
let progressAchieved = 0;
|
|
||||||
return Window.withProgress(options,
|
|
||||||
(progress, token) => {
|
|
||||||
return task(p => {
|
|
||||||
const { message, step, maxStep } = p;
|
|
||||||
const increment = 100 * (step - progressAchieved) / maxStep;
|
|
||||||
progressAchieved = step;
|
|
||||||
progress.report({ message, increment });
|
|
||||||
}, token, ...args);
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* 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,
|
|
||||||
): Disposable {
|
|
||||||
return commands.registerCommand(commandId, async (...args: any[]) => {
|
|
||||||
try {
|
|
||||||
return await task(...args);
|
|
||||||
} catch (e) {
|
|
||||||
const errorMessage = `${e.message || e} (${commandId})`;
|
|
||||||
if (e instanceof UserCancellationException) {
|
|
||||||
// User has cancelled this action manually
|
|
||||||
if (e.silent) {
|
|
||||||
logger.log(errorMessage);
|
|
||||||
} else {
|
|
||||||
showAndLogWarningMessage(errorMessage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showAndLogErrorMessage(errorMessage);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
|
||||||
* A generic wrapper for command registration. This wrapper adds uniform error handling,
|
|
||||||
* progress monitoring, and cancellation 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 after the progress callback
|
|
||||||
* and cancellation token.
|
|
||||||
* @param progressOptions Progress options to be sent to the progress monitor.
|
|
||||||
*/
|
|
||||||
export function commandRunnerWithProgress<R>(
|
|
||||||
commandId: string,
|
|
||||||
task: ProgressTask<R>,
|
|
||||||
progressOptions: Partial<ProgressOptions>
|
|
||||||
): Disposable {
|
|
||||||
return commands.registerCommand(commandId, async (...args: any[]) => {
|
|
||||||
const progressOptionsWithDefaults = {
|
|
||||||
location: ProgressLocation.Notification,
|
|
||||||
...progressOptions
|
|
||||||
};
|
|
||||||
try {
|
|
||||||
return await withProgress(progressOptionsWithDefaults, task, ...args);
|
|
||||||
} catch (e) {
|
|
||||||
const errorMessage = `${e.message || e} (${commandId})`;
|
|
||||||
if (e instanceof UserCancellationException) {
|
|
||||||
// User has cancelled this action manually
|
|
||||||
if (e.silent) {
|
|
||||||
logger.log(errorMessage);
|
|
||||||
} else {
|
|
||||||
showAndLogWarningMessage(errorMessage);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
showAndLogErrorMessage(errorMessage);
|
|
||||||
}
|
|
||||||
return undefined;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Show an error message and log it to the console
|
* Show an error message and log it to the console
|
||||||
*
|
*
|
||||||
@@ -532,46 +364,3 @@ export async function isLikelyDatabaseRoot(maybeRoot: string) {
|
|||||||
export function isLikelyDbLanguageFolder(dbPath: string) {
|
export function isLikelyDbLanguageFolder(dbPath: string) {
|
||||||
return !!path.basename(dbPath).startsWith('db-');
|
return !!path.basename(dbPath).startsWith('db-');
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Displays a progress monitor that indicates how much progess has been made
|
|
||||||
* reading from a stream.
|
|
||||||
*
|
|
||||||
* @param readable The stream to read progress from
|
|
||||||
* @param messagePrefix A prefix for displaying the message
|
|
||||||
* @param totalNumBytes Total number of bytes in this stream
|
|
||||||
* @param progress The progress callback used to set messages
|
|
||||||
*/
|
|
||||||
export function reportStreamProgress(
|
|
||||||
readable: NodeJS.ReadableStream,
|
|
||||||
messagePrefix: string,
|
|
||||||
totalNumBytes?: number,
|
|
||||||
progress?: ProgressCallback
|
|
||||||
) {
|
|
||||||
if (progress && totalNumBytes) {
|
|
||||||
let numBytesDownloaded = 0;
|
|
||||||
const bytesToDisplayMB = (numBytes: number): string => `${(numBytes / (1024 * 1024)).toFixed(1)} MB`;
|
|
||||||
const updateProgress = () => {
|
|
||||||
progress({
|
|
||||||
step: numBytesDownloaded,
|
|
||||||
maxStep: totalNumBytes,
|
|
||||||
message: `${messagePrefix} [${bytesToDisplayMB(numBytesDownloaded)} of ${bytesToDisplayMB(totalNumBytes)}]`,
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
// Display the progress straight away rather than waiting for the first chunk.
|
|
||||||
updateProgress();
|
|
||||||
|
|
||||||
readable.on('data', data => {
|
|
||||||
numBytesDownloaded += data.length;
|
|
||||||
updateProgress();
|
|
||||||
});
|
|
||||||
} else if (progress) {
|
|
||||||
progress({
|
|
||||||
step: 1,
|
|
||||||
maxStep: 2,
|
|
||||||
message: `${messagePrefix} (Size unknown)`,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ import {
|
|||||||
RawResultsSortState,
|
RawResultsSortState,
|
||||||
} from './pure/interface-types';
|
} from './pure/interface-types';
|
||||||
import { Logger } from './logging';
|
import { Logger } from './logging';
|
||||||
import { commandRunner } from './helpers';
|
import { commandRunner } from './commandRunner';
|
||||||
import * as messages from './pure/messages';
|
import * as messages from './pure/messages';
|
||||||
import { CompletedQuery, interpretResults } from './query-results';
|
import { CompletedQuery, interpretResults } from './query-results';
|
||||||
import { QueryInfo, tmpDir } from './run-queries';
|
import { QueryInfo, tmpDir } from './run-queries';
|
||||||
|
|||||||
@@ -4,7 +4,15 @@ import { window as Window } from 'vscode';
|
|||||||
import { CompletedQuery } from './query-results';
|
import { CompletedQuery } from './query-results';
|
||||||
import { QueryHistoryConfig } from './config';
|
import { QueryHistoryConfig } from './config';
|
||||||
import { QueryWithResults } from './run-queries';
|
import { QueryWithResults } from './run-queries';
|
||||||
import * as helpers from './helpers';
|
import {
|
||||||
|
showAndLogErrorMessage,
|
||||||
|
showAndLogInformationMessage,
|
||||||
|
showAndLogWarningMessage,
|
||||||
|
showBinaryChoiceDialog
|
||||||
|
} from './helpers';
|
||||||
|
import {
|
||||||
|
commandRunner
|
||||||
|
} from './commandRunner';
|
||||||
import { logger } from './logging';
|
import { logger } from './logging';
|
||||||
import { URLSearchParams } from 'url';
|
import { URLSearchParams } from 'url';
|
||||||
import { QueryServerClient } from './queryserver-client';
|
import { QueryServerClient } from './queryserver-client';
|
||||||
@@ -207,55 +215,55 @@ export class QueryHistoryManager extends DisposableObject {
|
|||||||
|
|
||||||
logger.log('Registering query history panel commands.');
|
logger.log('Registering query history panel commands.');
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.openQuery',
|
'codeQLQueryHistory.openQuery',
|
||||||
this.handleOpenQuery.bind(this)
|
this.handleOpenQuery.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.removeHistoryItem',
|
'codeQLQueryHistory.removeHistoryItem',
|
||||||
this.handleRemoveHistoryItem.bind(this)
|
this.handleRemoveHistoryItem.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.setLabel',
|
'codeQLQueryHistory.setLabel',
|
||||||
this.handleSetLabel.bind(this)
|
this.handleSetLabel.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.compareWith',
|
'codeQLQueryHistory.compareWith',
|
||||||
this.handleCompareWith.bind(this)
|
this.handleCompareWith.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.showQueryLog',
|
'codeQLQueryHistory.showQueryLog',
|
||||||
this.handleShowQueryLog.bind(this)
|
this.handleShowQueryLog.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.showQueryText',
|
'codeQLQueryHistory.showQueryText',
|
||||||
this.handleShowQueryText.bind(this)
|
this.handleShowQueryText.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.viewSarif',
|
'codeQLQueryHistory.viewSarif',
|
||||||
this.handleViewSarif.bind(this)
|
this.handleViewSarif.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.viewDil',
|
'codeQLQueryHistory.viewDil',
|
||||||
this.handleViewDil.bind(this)
|
this.handleViewDil.bind(this)
|
||||||
)
|
)
|
||||||
);
|
);
|
||||||
this.push(
|
this.push(
|
||||||
helpers.commandRunner(
|
commandRunner(
|
||||||
'codeQLQueryHistory.itemClicked',
|
'codeQLQueryHistory.itemClicked',
|
||||||
async (item: CompletedQuery) => {
|
async (item: CompletedQuery) => {
|
||||||
return this.handleItemClicked(item, [item]);
|
return this.handleItemClicked(item, [item]);
|
||||||
@@ -376,7 +384,7 @@ export class QueryHistoryManager extends DisposableObject {
|
|||||||
this.doCompareCallback(from, to);
|
this.doCompareCallback(from, to);
|
||||||
}
|
}
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
helpers.showAndLogErrorMessage(e.message);
|
showAndLogErrorMessage(e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -423,7 +431,7 @@ export class QueryHistoryManager extends DisposableObject {
|
|||||||
if (singleItem.logFileLocation) {
|
if (singleItem.logFileLocation) {
|
||||||
await this.tryOpenExternalFile(singleItem.logFileLocation);
|
await this.tryOpenExternalFile(singleItem.logFileLocation);
|
||||||
} else {
|
} else {
|
||||||
helpers.showAndLogWarningMessage('No log file available');
|
showAndLogWarningMessage('No log file available');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -468,7 +476,7 @@ export class QueryHistoryManager extends DisposableObject {
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const label = singleItem.getLabel();
|
const label = singleItem.getLabel();
|
||||||
helpers.showAndLogInformationMessage(
|
showAndLogInformationMessage(
|
||||||
`Query ${label} has no interpreted results.`
|
`Query ${label} has no interpreted results.`
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -547,7 +555,7 @@ export class QueryHistoryManager extends DisposableObject {
|
|||||||
) ||
|
) ||
|
||||||
e.message.includes('too large to open')
|
e.message.includes('too large to open')
|
||||||
) {
|
) {
|
||||||
const res = await helpers.showBinaryChoiceDialog(
|
const res = await showBinaryChoiceDialog(
|
||||||
`VS Code does not allow extensions to open files >50MB. This file
|
`VS Code does not allow extensions to open files >50MB. This file
|
||||||
exceeds that limit. Do you want to open it outside of VS Code?
|
exceeds that limit. Do you want to open it outside of VS Code?
|
||||||
|
|
||||||
@@ -558,11 +566,11 @@ the file in the file explorer and dragging it into the workspace.`
|
|||||||
try {
|
try {
|
||||||
await vscode.commands.executeCommand('revealFileInOS', uri);
|
await vscode.commands.executeCommand('revealFileInOS', uri);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
helpers.showAndLogErrorMessage(e.message);
|
showAndLogErrorMessage(e.message);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
helpers.showAndLogErrorMessage(`Could not open file ${fileLocation}`);
|
showAndLogErrorMessage(`Could not open file ${fileLocation}`);
|
||||||
logger.log(e.message);
|
logger.log(e.message);
|
||||||
logger.log(e.stack);
|
logger.log(e.stack);
|
||||||
}
|
}
|
||||||
@@ -616,7 +624,7 @@ the file in the file explorer and dragging it into the workspace.`
|
|||||||
|
|
||||||
private assertSingleQuery(multiSelect: CompletedQuery[] = [], message = 'Please select a single query.') {
|
private assertSingleQuery(multiSelect: CompletedQuery[] = [], message = 'Please select a single query.') {
|
||||||
if (multiSelect.length > 1) {
|
if (multiSelect.length > 1) {
|
||||||
helpers.showAndLogErrorMessage(
|
showAndLogErrorMessage(
|
||||||
message
|
message
|
||||||
);
|
);
|
||||||
return false;
|
return false;
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ import {
|
|||||||
getInitialQueryContents,
|
getInitialQueryContents,
|
||||||
getPrimaryDbscheme,
|
getPrimaryDbscheme,
|
||||||
getQlPackForDbscheme,
|
getQlPackForDbscheme,
|
||||||
ProgressCallback,
|
|
||||||
showAndLogErrorMessage,
|
showAndLogErrorMessage,
|
||||||
showBinaryChoiceDialog,
|
showBinaryChoiceDialog,
|
||||||
UserCancellationException
|
|
||||||
} from './helpers';
|
} from './helpers';
|
||||||
|
import {
|
||||||
|
ProgressCallback,
|
||||||
|
UserCancellationException
|
||||||
|
} from './commandRunner';
|
||||||
|
|
||||||
const QUICK_QUERIES_DIR_NAME = 'quick-queries';
|
const QUICK_QUERIES_DIR_NAME = 'quick-queries';
|
||||||
const QUICK_QUERY_QUERY_NAME = 'quick-query.ql';
|
const QUICK_QUERY_QUERY_NAME = 'quick-query.ql';
|
||||||
|
|||||||
@@ -15,7 +15,8 @@ import { ErrorCodes, ResponseError } from 'vscode-languageclient';
|
|||||||
import * as cli from './cli';
|
import * as cli from './cli';
|
||||||
import * as config from './config';
|
import * as config from './config';
|
||||||
import { DatabaseItem, getUpgradesDirectories } from './databases';
|
import { DatabaseItem, getUpgradesDirectories } from './databases';
|
||||||
import * as helpers from './helpers';
|
import { getOnDiskWorkspaceFolders, showAndLogErrorMessage } from './helpers';
|
||||||
|
import { ProgressCallback, UserCancellationException } from './commandRunner';
|
||||||
import { DatabaseInfo, QueryMetadata, ResultsPaths } from './pure/interface-types';
|
import { DatabaseInfo, QueryMetadata, ResultsPaths } from './pure/interface-types';
|
||||||
import { logger } from './logging';
|
import { logger } from './logging';
|
||||||
import * as messages from './pure/messages';
|
import * as messages from './pure/messages';
|
||||||
@@ -79,7 +80,7 @@ export class QueryInfo {
|
|||||||
|
|
||||||
async run(
|
async run(
|
||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
): Promise<messages.EvaluationResult> {
|
): Promise<messages.EvaluationResult> {
|
||||||
let result: messages.EvaluationResult | null = null;
|
let result: messages.EvaluationResult | null = null;
|
||||||
@@ -121,7 +122,7 @@ export class QueryInfo {
|
|||||||
|
|
||||||
async compile(
|
async compile(
|
||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
): Promise<messages.CompilationMessage[]> {
|
): Promise<messages.CompilationMessage[]> {
|
||||||
let compiled: messages.CheckQueryResult | undefined;
|
let compiled: messages.CheckQueryResult | undefined;
|
||||||
@@ -209,7 +210,7 @@ export interface QueryWithResults {
|
|||||||
export async function clearCacheInDatabase(
|
export async function clearCacheInDatabase(
|
||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
dbItem: DatabaseItem,
|
dbItem: DatabaseItem,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
): Promise<messages.ClearCacheResult> {
|
): Promise<messages.ClearCacheResult> {
|
||||||
if (dbItem.contents === undefined) {
|
if (dbItem.contents === undefined) {
|
||||||
@@ -285,10 +286,10 @@ async function checkDbschemeCompatibility(
|
|||||||
cliServer: cli.CodeQLCliServer,
|
cliServer: cli.CodeQLCliServer,
|
||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
query: QueryInfo,
|
query: QueryInfo,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
): Promise<void> {
|
): Promise<void> {
|
||||||
const searchPath = helpers.getOnDiskWorkspaceFolders();
|
const searchPath = getOnDiskWorkspaceFolders();
|
||||||
|
|
||||||
if (query.dbItem.contents !== undefined && query.dbItem.contents.dbSchemeUri !== undefined) {
|
if (query.dbItem.contents !== undefined && query.dbItem.contents.dbSchemeUri !== undefined) {
|
||||||
const { scripts, finalDbscheme } = await cliServer.resolveUpgrades(query.dbItem.contents.dbSchemeUri.fsPath, searchPath);
|
const { scripts, finalDbscheme } = await cliServer.resolveUpgrades(query.dbItem.contents.dbSchemeUri.fsPath, searchPath);
|
||||||
@@ -364,7 +365,7 @@ async function promptUserToSaveChanges(document: TextDocument): Promise<boolean>
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (chosenItem === cancelItem) {
|
if (chosenItem === cancelItem) {
|
||||||
throw new helpers.UserCancellationException('Query run cancelled.', true);
|
throw new UserCancellationException('Query run cancelled.', true);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -454,7 +455,7 @@ export async function compileAndRunQueryAgainstDatabase(
|
|||||||
db: DatabaseItem,
|
db: DatabaseItem,
|
||||||
quickEval: boolean,
|
quickEval: boolean,
|
||||||
selectedQueryUri: Uri | undefined,
|
selectedQueryUri: Uri | undefined,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: CancellationToken,
|
token: CancellationToken,
|
||||||
templates?: messages.TemplateDefinitions,
|
templates?: messages.TemplateDefinitions,
|
||||||
): Promise<QueryWithResults> {
|
): Promise<QueryWithResults> {
|
||||||
@@ -474,7 +475,7 @@ export async function compileAndRunQueryAgainstDatabase(
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the workspace folder paths.
|
// Get the workspace folder paths.
|
||||||
const diskWorkspaceFolders = helpers.getOnDiskWorkspaceFolders();
|
const diskWorkspaceFolders = getOnDiskWorkspaceFolders();
|
||||||
// Figure out the library path for the query.
|
// Figure out the library path for the query.
|
||||||
const packConfig = await cliServer.resolveLibraryPath(diskWorkspaceFolders, queryPath);
|
const packConfig = await cliServer.resolveLibraryPath(diskWorkspaceFolders, queryPath);
|
||||||
|
|
||||||
@@ -533,7 +534,7 @@ export async function compileAndRunQueryAgainstDatabase(
|
|||||||
if (result.resultType !== messages.QueryResultType.SUCCESS) {
|
if (result.resultType !== messages.QueryResultType.SUCCESS) {
|
||||||
const message = result.message || 'Failed to run query';
|
const message = result.message || 'Failed to run query';
|
||||||
logger.log(message);
|
logger.log(message);
|
||||||
helpers.showAndLogErrorMessage(message);
|
showAndLogErrorMessage(message);
|
||||||
}
|
}
|
||||||
return {
|
return {
|
||||||
query,
|
query,
|
||||||
@@ -564,9 +565,9 @@ export async function compileAndRunQueryAgainstDatabase(
|
|||||||
qs.logger.log(formatted);
|
qs.logger.log(formatted);
|
||||||
}
|
}
|
||||||
if (quickEval && formattedMessages.length <= 3) {
|
if (quickEval && formattedMessages.length <= 3) {
|
||||||
helpers.showAndLogErrorMessage('Quick evaluation compilation failed: \n' + formattedMessages.join('\n'));
|
showAndLogErrorMessage('Quick evaluation compilation failed: \n' + formattedMessages.join('\n'));
|
||||||
} else {
|
} else {
|
||||||
helpers.showAndLogErrorMessage((quickEval ? 'Quick evaluation' : 'Query') +
|
showAndLogErrorMessage((quickEval ? 'Quick evaluation' : 'Query') +
|
||||||
' compilation failed. Please make sure there are no errors in the query, the database is up to date,' +
|
' compilation failed. Please make sure there are no errors in the query, the database is up to date,' +
|
||||||
' and the query and database use the same target language. For more details on the error, go to View > Output,' +
|
' and the query and database use the same target language. For more details on the error, go to View > Output,' +
|
||||||
' and choose CodeQL Query Server from the dropdown.');
|
' and choose CodeQL Query Server from the dropdown.');
|
||||||
|
|||||||
@@ -1,6 +1,7 @@
|
|||||||
import * as vscode from 'vscode';
|
import * as vscode from 'vscode';
|
||||||
import { DatabaseItem } from './databases';
|
import { DatabaseItem } from './databases';
|
||||||
import * as helpers from './helpers';
|
import { showAndLogErrorMessage } from './helpers';
|
||||||
|
import { ProgressCallback, UserCancellationException } from './commandRunner';
|
||||||
import { logger } from './logging';
|
import { logger } from './logging';
|
||||||
import * as messages from './pure/messages';
|
import * as messages from './pure/messages';
|
||||||
import * as qsClient from './queryserver-client';
|
import * as qsClient from './queryserver-client';
|
||||||
@@ -24,7 +25,7 @@ async function checkAndConfirmDatabaseUpgrade(
|
|||||||
db: DatabaseItem,
|
db: DatabaseItem,
|
||||||
targetDbScheme: vscode.Uri,
|
targetDbScheme: vscode.Uri,
|
||||||
upgradesDirectories: vscode.Uri[],
|
upgradesDirectories: vscode.Uri[],
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: vscode.CancellationToken,
|
token: vscode.CancellationToken,
|
||||||
): Promise<messages.UpgradeParams | undefined> {
|
): Promise<messages.UpgradeParams | undefined> {
|
||||||
if (db.contents === undefined || db.contents.dbSchemeUri === undefined) {
|
if (db.contents === undefined || db.contents.dbSchemeUri === undefined) {
|
||||||
@@ -75,7 +76,7 @@ async function checkAndConfirmDatabaseUpgrade(
|
|||||||
if (curSha != targetSha) {
|
if (curSha != targetSha) {
|
||||||
// Newlines aren't rendered in notifications: https://github.com/microsoft/vscode/issues/48900
|
// Newlines aren't rendered in notifications: https://github.com/microsoft/vscode/issues/48900
|
||||||
// A modal dialog would be rendered better, but is more intrusive.
|
// A modal dialog would be rendered better, but is more intrusive.
|
||||||
await helpers.showAndLogErrorMessage(`Database cannot be upgraded to the target database scheme.
|
await showAndLogErrorMessage(`Database cannot be upgraded to the target database scheme.
|
||||||
Can upgrade from ${checkedUpgrades.initialSha} (current) to ${curSha}, but cannot reach ${targetSha} (target).`);
|
Can upgrade from ${checkedUpgrades.initialSha} (current) to ${curSha}, but cannot reach ${targetSha} (target).`);
|
||||||
// TODO: give a more informative message if we think the DB is ahead of the target DB scheme
|
// TODO: give a more informative message if we think the DB is ahead of the target DB scheme
|
||||||
return;
|
return;
|
||||||
@@ -114,7 +115,7 @@ async function checkAndConfirmDatabaseUpgrade(
|
|||||||
return params;
|
return params;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
throw new helpers.UserCancellationException('User cancelled the database upgrade.');
|
throw new UserCancellationException('User cancelled the database upgrade.');
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,7 +129,7 @@ export async function upgradeDatabase(
|
|||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
db: DatabaseItem, targetDbScheme: vscode.Uri,
|
db: DatabaseItem, targetDbScheme: vscode.Uri,
|
||||||
upgradesDirectories: vscode.Uri[],
|
upgradesDirectories: vscode.Uri[],
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: vscode.CancellationToken,
|
token: vscode.CancellationToken,
|
||||||
): Promise<messages.RunUpgradeResult | undefined> {
|
): Promise<messages.RunUpgradeResult | undefined> {
|
||||||
const upgradeParams = await checkAndConfirmDatabaseUpgrade(qs, db, targetDbScheme, upgradesDirectories, progress, token);
|
const upgradeParams = await checkAndConfirmDatabaseUpgrade(qs, db, targetDbScheme, upgradesDirectories, progress, token);
|
||||||
@@ -142,7 +143,7 @@ export async function upgradeDatabase(
|
|||||||
compileUpgradeResult = await compileDatabaseUpgrade(qs, upgradeParams, progress, token);
|
compileUpgradeResult = await compileDatabaseUpgrade(qs, upgradeParams, progress, token);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
helpers.showAndLogErrorMessage(`Compilation of database upgrades failed: ${e}`);
|
showAndLogErrorMessage(`Compilation of database upgrades failed: ${e}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -151,7 +152,7 @@ export async function upgradeDatabase(
|
|||||||
|
|
||||||
if (compileUpgradeResult.compiledUpgrades === undefined) {
|
if (compileUpgradeResult.compiledUpgrades === undefined) {
|
||||||
const error = compileUpgradeResult.error || '[no error message available]';
|
const error = compileUpgradeResult.error || '[no error message available]';
|
||||||
helpers.showAndLogErrorMessage(`Compilation of database upgrades failed: ${error}`);
|
(`Compilation of database upgrades failed: ${error}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -168,7 +169,7 @@ export async function upgradeDatabase(
|
|||||||
return await runDatabaseUpgrade(qs, db, compileUpgradeResult.compiledUpgrades, progress, token);
|
return await runDatabaseUpgrade(qs, db, compileUpgradeResult.compiledUpgrades, progress, token);
|
||||||
}
|
}
|
||||||
catch (e) {
|
catch (e) {
|
||||||
helpers.showAndLogErrorMessage(`Database upgrade failed: ${e}`);
|
showAndLogErrorMessage(`Database upgrade failed: ${e}`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
finally {
|
finally {
|
||||||
@@ -179,7 +180,7 @@ export async function upgradeDatabase(
|
|||||||
async function checkDatabaseUpgrade(
|
async function checkDatabaseUpgrade(
|
||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
upgradeParams: messages.UpgradeParams,
|
upgradeParams: messages.UpgradeParams,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: vscode.CancellationToken,
|
token: vscode.CancellationToken,
|
||||||
): Promise<messages.CheckUpgradeResult> {
|
): Promise<messages.CheckUpgradeResult> {
|
||||||
progress({
|
progress({
|
||||||
@@ -194,7 +195,7 @@ async function checkDatabaseUpgrade(
|
|||||||
async function compileDatabaseUpgrade(
|
async function compileDatabaseUpgrade(
|
||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
upgradeParams: messages.UpgradeParams,
|
upgradeParams: messages.UpgradeParams,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: vscode.CancellationToken,
|
token: vscode.CancellationToken,
|
||||||
): Promise<messages.CompileUpgradeResult> {
|
): Promise<messages.CompileUpgradeResult> {
|
||||||
const params: messages.CompileUpgradeParams = {
|
const params: messages.CompileUpgradeParams = {
|
||||||
@@ -216,7 +217,7 @@ async function runDatabaseUpgrade(
|
|||||||
qs: qsClient.QueryServerClient,
|
qs: qsClient.QueryServerClient,
|
||||||
db: DatabaseItem,
|
db: DatabaseItem,
|
||||||
upgrades: messages.CompiledUpgrades,
|
upgrades: messages.CompiledUpgrades,
|
||||||
progress: helpers.ProgressCallback,
|
progress: ProgressCallback,
|
||||||
token: vscode.CancellationToken,
|
token: vscode.CancellationToken,
|
||||||
): Promise<messages.RunUpgradeResult> {
|
): Promise<messages.RunUpgradeResult> {
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { extensions, CancellationToken, Uri, window } from 'vscode';
|
|||||||
import { CodeQLExtensionInterface } from '../../extension';
|
import { CodeQLExtensionInterface } from '../../extension';
|
||||||
import { DatabaseManager } from '../../databases';
|
import { DatabaseManager } from '../../databases';
|
||||||
import { promptImportLgtmDatabase, importArchiveDatabase, promptImportInternetDatabase } from '../../databaseFetcher';
|
import { promptImportLgtmDatabase, importArchiveDatabase, promptImportInternetDatabase } from '../../databaseFetcher';
|
||||||
import { ProgressCallback } from '../../helpers';
|
import { ProgressCallback } from '../../commandRunner';
|
||||||
import { dbLoc, DB_URL, storagePath } from './global.helper';
|
import { dbLoc, DB_URL, storagePath } from './global.helper';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
|||||||
@@ -17,7 +17,7 @@ import {
|
|||||||
import { Logger } from '../../logging';
|
import { Logger } from '../../logging';
|
||||||
import { QueryServerClient } from '../../queryserver-client';
|
import { QueryServerClient } from '../../queryserver-client';
|
||||||
import { registerDatabases } from '../../pure/messages';
|
import { registerDatabases } from '../../pure/messages';
|
||||||
import { ProgressCallback } from '../../helpers';
|
import { ProgressCallback } from '../../commandRunner';
|
||||||
import { CodeQLCliServer } from '../../cli';
|
import { CodeQLCliServer } from '../../cli';
|
||||||
import { encodeArchiveBasePath, encodeSourceArchiveUri } from '../../archive-filesystem-provider';
|
import { encodeArchiveBasePath, encodeSourceArchiveUri } from '../../archive-filesystem-provider';
|
||||||
|
|
||||||
|
|||||||
@@ -7,7 +7,8 @@ import * as path from 'path';
|
|||||||
import * as fs from 'fs-extra';
|
import * as fs from 'fs-extra';
|
||||||
import * as sinon from 'sinon';
|
import * as sinon from 'sinon';
|
||||||
|
|
||||||
import { getInitialQueryContents, InvocationRateLimiter, isLikelyDbLanguageFolder, reportStreamProgress } from '../../helpers';
|
import { getInitialQueryContents, InvocationRateLimiter, isLikelyDbLanguageFolder } from '../../helpers';
|
||||||
|
import { reportStreamProgress } from '../../commandRunner';
|
||||||
|
|
||||||
describe('helpers', () => {
|
describe('helpers', () => {
|
||||||
let sandbox: sinon.SinonSandbox;
|
let sandbox: sinon.SinonSandbox;
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import { TreeDataProvider, window } from 'vscode';
|
import { TreeDataProvider, window } from 'vscode';
|
||||||
import { DisposableObject } from './disposable-object';
|
import { DisposableObject } from './disposable-object';
|
||||||
import { commandRunner } from '../helpers';
|
import { commandRunner } from '../commandRunner';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A VS Code service that interacts with the UI, including handling commands.
|
* A VS Code service that interacts with the UI, including handling commands.
|
||||||
|
|||||||
Reference in New Issue
Block a user