Skip to content

Improvements to Query History Labels #176

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
18 changes: 18 additions & 0 deletions extensions/ql-vscode/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@
"type": "boolean",
"default": false,
"description": "Enable debug logging and tuple counting when running CodeQL queries. This information is useful for debugging query performance."
},
"codeQL.queryHistory.format": {
"type": "string",
"default": "[%t] %q on %d - %s",
"description": "Default string for how to label query history items. %t is the time of the query, %q is the query name, %d is the database name, and %s is a status string."
}
}
},
Expand Down Expand Up @@ -178,6 +183,10 @@
{
"command": "codeQLQueryResults.previousPathStep",
"title": "CodeQL: Show Previous Step on Path"
},
{
"command": "codeQLQueryHistory.setLabel",
"title": "Set Label"
}
],
"menus": {
Expand Down Expand Up @@ -213,6 +222,11 @@
"command": "codeQLQueryHistory.removeHistoryItem",
"group": "9_qlCommands",
"when": "view == codeQLQueryHistory"
},
{
"command": "codeQLQueryHistory.setLabel",
"group": "9_qlCommands",
"when": "view == codeQLQueryHistory"
}
],
"explorer/context": [
Expand Down Expand Up @@ -259,6 +273,10 @@
{
"command": "codeQLQueryHistory.itemClicked",
"when": "false"
},
{
"command": "codeQLQueryHistory.setLabel",
"when": "false"
}
],
"editor/context": [
Expand Down
24 changes: 24 additions & 0 deletions extensions/ql-vscode/src/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,8 @@ const DISTRIBUTION_SETTING = new Setting('cli', ROOT_SETTING);
const CUSTOM_CODEQL_PATH_SETTING = new Setting('executablePath', DISTRIBUTION_SETTING);
const INCLUDE_PRERELEASE_SETTING = new Setting('includePrerelease', DISTRIBUTION_SETTING);
const PERSONAL_ACCESS_TOKEN_SETTING = new Setting('personalAccessToken', DISTRIBUTION_SETTING);
const QUERY_HISTORY_SETTING = new Setting('queryHistory', ROOT_SETTING);
const QUERY_HISTORY_FORMAT_SETTING = new Setting('format', QUERY_HISTORY_SETTING);

/** When these settings change, the distribution should be updated. */
const DISTRIBUTION_CHANGE_SETTINGS = [CUSTOM_CODEQL_PATH_SETTING, INCLUDE_PRERELEASE_SETTING, PERSONAL_ACCESS_TOKEN_SETTING];
Expand Down Expand Up @@ -70,6 +72,14 @@ export interface QueryServerConfig {
onDidChangeQueryServerConfiguration?: Event<void>;
}

/** When these settings change, the query history should be refreshed. */
const QUERY_HISTORY_SETTINGS = [QUERY_HISTORY_FORMAT_SETTING];

export interface QueryHistoryConfig {
format: string,
onDidChangeQueryHistoryConfiguration: Event<void>;
}

abstract class ConfigListener extends DisposableObject {
protected readonly _onDidChangeConfiguration = this.push(new EventEmitter<void>());

Expand Down Expand Up @@ -176,3 +186,17 @@ export class QueryServerConfigListener extends ConfigListener implements QuerySe
this.handleDidChangeConfigurationForRelevantSettings(QUERY_SERVER_RESTARTING_SETTINGS, e);
}
}

export class QueryHistoryConfigListener extends ConfigListener implements QueryHistoryConfig {
protected handleDidChangeConfiguration(e: ConfigurationChangeEvent): void {
this.handleDidChangeConfigurationForRelevantSettings(QUERY_HISTORY_SETTINGS, e);
}

public get onDidChangeQueryHistoryConfiguration(): Event<void> {
return this._onDidChangeConfiguration.event;
}

public get format(): string {
return QUERY_HISTORY_FORMAT_SETTING.getValue<string>();
}
}
15 changes: 10 additions & 5 deletions extensions/ql-vscode/src/extension.ts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { commands, Disposable, ExtensionContext, extensions, ProgressLocation, ProgressOptions, window as Window, Uri } from 'vscode';
import { ErrorCodes, LanguageClient, ResponseError } from 'vscode-languageclient';
import * as archiveFilesystemProvider from './archive-filesystem-provider';
import { DistributionConfigListener, QueryServerConfigListener } from './config';
import { DistributionConfigListener, QueryServerConfigListener, QueryHistoryConfigListener } from './config';
import { DatabaseManager } from './databases';
import { DatabaseUI } from './databases-ui';
import { DistributionUpdateCheckResultKind, DistributionManager, FindDistributionResult, FindDistributionResultKind, GithubApiError,
Expand All @@ -11,7 +11,7 @@ import { spawnIdeServer } from './ide-server';
import { InterfaceManager, WebviewReveal } from './interface';
import { ideServerLogger, logger, queryServerLogger } from './logging';
import { compileAndRunQueryAgainstDatabase, EvaluationInfo, tmpDirDisposal, UserCancellationException } from './queries';
import { QueryHistoryItem, QueryHistoryManager } from './query-history';
import { QueryHistoryManager } from './query-history';
import * as qsClient from './queryserver-client';
import { CodeQLCliServer } from './cli';
import { assertNever } from './helpers-pure';
Expand Down Expand Up @@ -78,7 +78,7 @@ export async function activate(ctx: ExtensionContext): Promise<void> {
const distributionManager = new DistributionManager(ctx, distributionConfigListener, DEFAULT_DISTRIBUTION_VERSION_CONSTRAINT);

const shouldUpdateOnNextActivationKey = "shouldUpdateOnNextActivation";

registerErrorStubs(ctx, [checkForUpdatesCommand], command => () => {
helpers.showAndLogErrorMessage(`Can't execute ${command}: waiting to finish loading CodeQL CLI.`);
});
Expand Down Expand Up @@ -244,7 +244,12 @@ async function activateWithInstalledDistribution(ctx: ExtensionContext, distribu
const databaseUI = new DatabaseUI(ctx, cliServer, dbm, qs);
ctx.subscriptions.push(databaseUI);

const qhm = new QueryHistoryManager(ctx, async item => showResultsForInfo(item.info, WebviewReveal.Forced));
const queryHistoryConfigurationListener = new QueryHistoryConfigListener();
const qhm = new QueryHistoryManager(
ctx,
queryHistoryConfigurationListener,
async item => showResultsForInfo(item.info, WebviewReveal.Forced)
);
const intm = new InterfaceManager(ctx, dbm, cliServer, queryServerLogger);
ctx.subscriptions.push(intm);
archiveFilesystemProvider.activate(ctx);
Expand All @@ -262,7 +267,7 @@ async function activateWithInstalledDistribution(ctx: ExtensionContext, distribu
}
const info = await compileAndRunQueryAgainstDatabase(cliServer, qs, dbItem, quickEval, selectedQuery);
await showResultsForInfo(info, WebviewReveal.NotForced);
qhm.push(new QueryHistoryItem(info));
qhm.push(info);
}
catch (e) {
if (e instanceof UserCancellationException) {
Expand Down
69 changes: 62 additions & 7 deletions extensions/ql-vscode/src/query-history.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@ import { ExtensionContext, window as Window } from 'vscode';
import { EvaluationInfo } from './queries';
import * as helpers from './helpers';
import * as messages from './messages';
import { QueryHistoryConfig } from './config';
/**
* query-history.ts
* ------------
Expand All @@ -21,7 +22,11 @@ export class QueryHistoryItem {
databaseName: string;
info: EvaluationInfo;

constructor(info: EvaluationInfo) {
constructor(
info: EvaluationInfo,
public config: QueryHistoryConfig,
public label?: string, // user-settable label
) {
this.queryName = helpers.getQueryName(info);
this.databaseName = info.database.name;
this.info = info;
Expand All @@ -44,9 +49,29 @@ export class QueryHistoryItem {
}
}

interpolate(template: string): string {
const { databaseName, queryName, time, statusString } = this;
const replacements: { [k: string]: string } = {
t: time,
q: queryName,
d: databaseName,
s: statusString,
'%': '%',
};
return template.replace(/%(.)/g, (match, key) => {
const replacement = replacements[key];
return replacement !== undefined ? replacement : match;
});
}

getLabel(): string {
if (this.label !== undefined)
return this.label;
return this.config.format;
}

toString(): string {
const { databaseName, queryName, time } = this;
return `[${time}] ${queryName} on ${databaseName} - ${this.statusString}`;
return this.interpolate(this.getLabel());
}
}

Expand Down Expand Up @@ -109,7 +134,7 @@ class HistoryTreeDataProvider implements vscode.TreeDataProvider<QueryHistoryIte
push(item: QueryHistoryItem): void {
this.current = item;
this.history.push(item);
this._onDidChangeTreeData.fire();
this.refresh();
}

setCurrentItem(item: QueryHistoryItem) {
Expand All @@ -127,9 +152,13 @@ class HistoryTreeDataProvider implements vscode.TreeDataProvider<QueryHistoryIte
// are any available.
this.current = this.history[Math.min(index, this.history.length - 1)];
}
this._onDidChangeTreeData.fire();
this.refresh();
}
}

refresh() {
this._onDidChangeTreeData.fire();
}
}

/**
Expand Down Expand Up @@ -166,6 +195,23 @@ export class QueryHistoryManager {
}
}

async handleSetLabel(queryHistoryItem: QueryHistoryItem) {
const response = await vscode.window.showInputBox({
prompt: 'Label:',
placeHolder: '(use default)',
value: queryHistoryItem.getLabel(),
});
// undefined response means the user cancelled the dialog; don't change anything
if (response !== undefined) {
if (response === '')
// Interpret empty string response as "go back to using default"
queryHistoryItem.label = undefined;
else
queryHistoryItem.label = response;
this.treeDataProvider.refresh();
}
}

async handleItemClicked(queryHistoryItem: QueryHistoryItem) {
this.treeDataProvider.setCurrentItem(queryHistoryItem);

Expand All @@ -185,7 +231,11 @@ export class QueryHistoryManager {
}
}

constructor(ctx: ExtensionContext, selectedCallback?: (item: QueryHistoryItem) => Promise<void>) {
constructor(
ctx: ExtensionContext,
private queryHistoryConfigListener: QueryHistoryConfig,
selectedCallback?: (item: QueryHistoryItem) => Promise<void>
) {
this.ctx = ctx;
this.selectedCallback = selectedCallback;
const treeDataProvider = this.treeDataProvider = new HistoryTreeDataProvider(ctx);
Expand All @@ -199,12 +249,17 @@ export class QueryHistoryManager {
});
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.openQuery', this.handleOpenQuery));
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.removeHistoryItem', this.handleRemoveHistoryItem.bind(this)));
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.setLabel', this.handleSetLabel.bind(this)));
ctx.subscriptions.push(vscode.commands.registerCommand('codeQLQueryHistory.itemClicked', async (item) => {
return this.handleItemClicked(item);
}));
queryHistoryConfigListener.onDidChangeQueryHistoryConfiguration(() => {
this.treeDataProvider.refresh();
});
}

push(item: QueryHistoryItem) {
push(evaluationInfo: EvaluationInfo) {
const item = new QueryHistoryItem(evaluationInfo, this.queryHistoryConfigListener);
this.treeDataProvider.push(item);
this.treeView.reveal(item, { select: true });
}
Expand Down