Skip to content

Commit 0cf7341

Browse files
Make types for selection commands more precise
1 parent b0940e6 commit 0cf7341

File tree

4 files changed

+104
-66
lines changed

4 files changed

+104
-66
lines changed

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

Lines changed: 73 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -13,18 +13,53 @@ import type {
1313
} from "../variant-analysis/shared/variant-analysis";
1414

1515
// A command function matching the signature that VS Code calls when
16-
// a command on a selection is invoked.
17-
export type SelectionCommandFunction<Item> = (
16+
// a command is invoked from the title bar of a TreeView with
17+
// canSelectMany set to true.
18+
//
19+
// It is possible to get any combination of singleItem and multiSelect
20+
// to be undefined. This is because it is possible to click a title bar
21+
// option without interacting with any individual items first, or even
22+
// when there are no items present at all.
23+
// If both singleItem and multiSelect are defined, then singleItem will
24+
// be contained within multiSelect.
25+
export type TreeViewTitleMultiSelectionCommandFunction<Item> = (
26+
singleItem: Item | undefined,
27+
multiSelect: Item[] | undefined,
28+
) => Promise<void>;
29+
30+
// A command function matching the signature that VS Code calls when
31+
// a command is invoked from a context menu on a TreeView with
32+
// canSelectMany set to true.
33+
//
34+
// singleItem will always be defined and corresponds to the item that
35+
// was hovered or right-clicked. If precisely one item was selected then
36+
// multiSelect will be undefined. If more than one item is selected then
37+
// multiSelect will contain all selected items, including singleItem.
38+
export type TreeViewContextMultiSelectionCommandFunction<Item> = (
1839
singleItem: Item,
19-
multiSelect: Item[],
40+
multiSelect: Item[] | undefined,
2041
) => Promise<void>;
2142

2243
// A command function matching the signature that VS Code calls when
23-
// a command on a selection is invoked when canSelectMany is false.
24-
export type SingleSelectionCommandFunction<Item> = (
44+
// a command is invoked from a context menu on a TreeView with
45+
// canSelectMany set to false.
46+
//
47+
// It is guaranteed that precisely one item will be selected.
48+
export type TreeViewContextSingleSelectionCommandFunction<Item> = (
2549
singleItem: Item,
2650
) => Promise<void>;
2751

52+
// A command function matching the signature that VS Code calls when
53+
// a command is invoked from a context menu on the file explorer.
54+
//
55+
// singleItem corresponds to the item that was right-clicked.
56+
// multiSelect will always been defined and non-empty and contains
57+
// all selected items, including singleItem.
58+
export type ExplorerSelectionCommandFunction<Item> = (
59+
singleItem: Item,
60+
multiSelect: Item[],
61+
) => Promise<void>;
62+
2863
/**
2964
* Contains type definitions for all commands used by the extension.
3065
*
@@ -93,7 +128,7 @@ export type LocalQueryCommands = {
93128
"codeQL.runQueryOnMultipleDatabasesContextEditor": (
94129
uri?: Uri,
95130
) => Promise<void>;
96-
"codeQL.runQueries": SelectionCommandFunction<Uri>;
131+
"codeQL.runQueries": ExplorerSelectionCommandFunction<Uri>;
97132
"codeQL.quickEval": (uri: Uri) => Promise<void>;
98133
"codeQL.quickEvalContextEditor": (uri: Uri) => Promise<void>;
99134
"codeQL.codeLensQuickEval": (uri: Uri, range: Range) => Promise<void>;
@@ -117,28 +152,28 @@ export type QueryHistoryCommands = {
117152
"codeQLQueryHistory.sortByCount": () => Promise<void>;
118153

119154
// Commands in the context menu or in the hover menu
120-
"codeQLQueryHistory.openQueryTitleMenu": SelectionCommandFunction<QueryHistoryInfo>;
121-
"codeQLQueryHistory.openQueryContextMenu": SelectionCommandFunction<QueryHistoryInfo>;
122-
"codeQLQueryHistory.removeHistoryItemTitleMenu": SelectionCommandFunction<QueryHistoryInfo>;
123-
"codeQLQueryHistory.removeHistoryItemContextMenu": SelectionCommandFunction<QueryHistoryInfo>;
124-
"codeQLQueryHistory.removeHistoryItemContextInline": SelectionCommandFunction<QueryHistoryInfo>;
125-
"codeQLQueryHistory.renameItem": SelectionCommandFunction<QueryHistoryInfo>;
126-
"codeQLQueryHistory.compareWith": SelectionCommandFunction<QueryHistoryInfo>;
127-
"codeQLQueryHistory.showEvalLog": SelectionCommandFunction<QueryHistoryInfo>;
128-
"codeQLQueryHistory.showEvalLogSummary": SelectionCommandFunction<QueryHistoryInfo>;
129-
"codeQLQueryHistory.showEvalLogViewer": SelectionCommandFunction<QueryHistoryInfo>;
130-
"codeQLQueryHistory.showQueryLog": SelectionCommandFunction<QueryHistoryInfo>;
131-
"codeQLQueryHistory.showQueryText": SelectionCommandFunction<QueryHistoryInfo>;
132-
"codeQLQueryHistory.openQueryDirectory": SelectionCommandFunction<QueryHistoryInfo>;
133-
"codeQLQueryHistory.cancel": SelectionCommandFunction<QueryHistoryInfo>;
134-
"codeQLQueryHistory.exportResults": SelectionCommandFunction<QueryHistoryInfo>;
135-
"codeQLQueryHistory.viewCsvResults": SelectionCommandFunction<QueryHistoryInfo>;
136-
"codeQLQueryHistory.viewCsvAlerts": SelectionCommandFunction<QueryHistoryInfo>;
137-
"codeQLQueryHistory.viewSarifAlerts": SelectionCommandFunction<QueryHistoryInfo>;
138-
"codeQLQueryHistory.viewDil": SelectionCommandFunction<QueryHistoryInfo>;
139-
"codeQLQueryHistory.itemClicked": SelectionCommandFunction<QueryHistoryInfo>;
140-
"codeQLQueryHistory.openOnGithub": SelectionCommandFunction<QueryHistoryInfo>;
141-
"codeQLQueryHistory.copyRepoList": SelectionCommandFunction<QueryHistoryInfo>;
155+
"codeQLQueryHistory.openQueryTitleMenu": TreeViewTitleMultiSelectionCommandFunction<QueryHistoryInfo>;
156+
"codeQLQueryHistory.openQueryContextMenu": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
157+
"codeQLQueryHistory.removeHistoryItemTitleMenu": TreeViewTitleMultiSelectionCommandFunction<QueryHistoryInfo>;
158+
"codeQLQueryHistory.removeHistoryItemContextMenu": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
159+
"codeQLQueryHistory.removeHistoryItemContextInline": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
160+
"codeQLQueryHistory.renameItem": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
161+
"codeQLQueryHistory.compareWith": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
162+
"codeQLQueryHistory.showEvalLog": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
163+
"codeQLQueryHistory.showEvalLogSummary": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
164+
"codeQLQueryHistory.showEvalLogViewer": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
165+
"codeQLQueryHistory.showQueryLog": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
166+
"codeQLQueryHistory.showQueryText": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
167+
"codeQLQueryHistory.openQueryDirectory": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
168+
"codeQLQueryHistory.cancel": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
169+
"codeQLQueryHistory.exportResults": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
170+
"codeQLQueryHistory.viewCsvResults": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
171+
"codeQLQueryHistory.viewCsvAlerts": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
172+
"codeQLQueryHistory.viewSarifAlerts": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
173+
"codeQLQueryHistory.viewDil": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
174+
"codeQLQueryHistory.itemClicked": TreeViewTitleMultiSelectionCommandFunction<QueryHistoryInfo>;
175+
"codeQLQueryHistory.openOnGithub": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
176+
"codeQLQueryHistory.copyRepoList": TreeViewContextMultiSelectionCommandFunction<QueryHistoryInfo>;
142177

143178
// Commands in the command palette
144179
"codeQL.exportSelectedVariantAnalysisResults": () => Promise<void>;
@@ -171,11 +206,11 @@ export type LocalDatabasesCommands = {
171206
) => Promise<void>;
172207

173208
// Database panel selection commands
174-
"codeQLDatabases.removeDatabase": SelectionCommandFunction<DatabaseItem>;
175-
"codeQLDatabases.upgradeDatabase": SelectionCommandFunction<DatabaseItem>;
176-
"codeQLDatabases.renameDatabase": SelectionCommandFunction<DatabaseItem>;
177-
"codeQLDatabases.openDatabaseFolder": SelectionCommandFunction<DatabaseItem>;
178-
"codeQLDatabases.addDatabaseSource": SelectionCommandFunction<DatabaseItem>;
209+
"codeQLDatabases.removeDatabase": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
210+
"codeQLDatabases.upgradeDatabase": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
211+
"codeQLDatabases.renameDatabase": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
212+
"codeQLDatabases.openDatabaseFolder": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
213+
"codeQLDatabases.addDatabaseSource": TreeViewContextMultiSelectionCommandFunction<DatabaseItem>;
179214

180215
// Codespace template commands
181216
"codeQL.setDefaultTourDatabase": () => Promise<void>;
@@ -220,11 +255,11 @@ export type DatabasePanelCommands = {
220255
"codeQLVariantAnalysisRepositories.addNewList": () => Promise<void>;
221256
"codeQLVariantAnalysisRepositories.setupControllerRepository": () => Promise<void>;
222257

223-
"codeQLVariantAnalysisRepositories.setSelectedItem": SingleSelectionCommandFunction<DbTreeViewItem>;
224-
"codeQLVariantAnalysisRepositories.setSelectedItemContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
225-
"codeQLVariantAnalysisRepositories.openOnGitHubContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
226-
"codeQLVariantAnalysisRepositories.renameItemContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
227-
"codeQLVariantAnalysisRepositories.removeItemContextMenu": SingleSelectionCommandFunction<DbTreeViewItem>;
258+
"codeQLVariantAnalysisRepositories.setSelectedItem": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
259+
"codeQLVariantAnalysisRepositories.setSelectedItemContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
260+
"codeQLVariantAnalysisRepositories.openOnGitHubContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
261+
"codeQLVariantAnalysisRepositories.renameItemContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
262+
"codeQLVariantAnalysisRepositories.removeItemContextMenu": TreeViewContextSingleSelectionCommandFunction<DbTreeViewItem>;
228263
};
229264

230265
export type AstCfgCommands = {

extensions/ql-vscode/src/local-queries.ts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ export class LocalQueries extends DisposableObject {
265265
);
266266
}
267267

268-
private async runQueries(_: Uri | undefined, multi: Uri[]): Promise<void> {
268+
private async runQueries(_: unknown, multi: Uri[]): Promise<void> {
269269
await withProgress(
270270
async (progress, token) => {
271271
const maxQueryCount = MAX_QUERIES.getValue() as number;

extensions/ql-vscode/src/query-history/query-history-manager.ts

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -402,8 +402,8 @@ export class QueryHistoryManager extends DisposableObject {
402402
}
403403

404404
async handleOpenQuery(
405-
singleItem: QueryHistoryInfo,
406-
multiSelect: QueryHistoryInfo[],
405+
singleItem: QueryHistoryInfo | undefined,
406+
multiSelect: QueryHistoryInfo[] | undefined,
407407
): Promise<void> {
408408
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
409409
singleItem,
@@ -465,8 +465,8 @@ export class QueryHistoryManager extends DisposableObject {
465465
}
466466

467467
async handleRemoveHistoryItem(
468-
singleItem: QueryHistoryInfo,
469-
multiSelect: QueryHistoryInfo[] = [],
468+
singleItem: QueryHistoryInfo | undefined,
469+
multiSelect: QueryHistoryInfo[] | undefined,
470470
) {
471471
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
472472
singleItem,
@@ -566,14 +566,14 @@ export class QueryHistoryManager extends DisposableObject {
566566

567567
async handleRenameItem(
568568
singleItem: QueryHistoryInfo,
569-
multiSelect: QueryHistoryInfo[],
569+
multiSelect: QueryHistoryInfo[] | undefined,
570570
): Promise<void> {
571571
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
572572
singleItem,
573573
multiSelect,
574574
);
575575

576-
if (!this.assertSingleQuery(finalMultiSelect)) {
576+
if (!this.assertSingleQuery(finalMultiSelect) || !finalSingleItem) {
577577
return;
578578
}
579579

@@ -595,7 +595,7 @@ export class QueryHistoryManager extends DisposableObject {
595595

596596
async handleCompareWith(
597597
singleItem: QueryHistoryInfo,
598-
multiSelect: QueryHistoryInfo[],
598+
multiSelect: QueryHistoryInfo[] | undefined,
599599
) {
600600
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
601601
singleItem,
@@ -633,8 +633,8 @@ export class QueryHistoryManager extends DisposableObject {
633633
}
634634

635635
async handleItemClicked(
636-
singleItem: QueryHistoryInfo,
637-
multiSelect: QueryHistoryInfo[] = [],
636+
singleItem: QueryHistoryInfo | undefined,
637+
multiSelect: QueryHistoryInfo[] | undefined,
638638
) {
639639
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
640640
singleItem,
@@ -668,7 +668,7 @@ export class QueryHistoryManager extends DisposableObject {
668668

669669
async handleShowQueryLog(
670670
singleItem: QueryHistoryInfo,
671-
multiSelect: QueryHistoryInfo[],
671+
multiSelect: QueryHistoryInfo[] | undefined,
672672
) {
673673
// Local queries only
674674
if (!this.assertSingleQuery(multiSelect) || singleItem?.t !== "local") {
@@ -709,7 +709,7 @@ export class QueryHistoryManager extends DisposableObject {
709709

710710
async handleOpenQueryDirectory(
711711
singleItem: QueryHistoryInfo,
712-
multiSelect: QueryHistoryInfo[],
712+
multiSelect: QueryHistoryInfo[] | undefined,
713713
) {
714714
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
715715
singleItem,
@@ -783,7 +783,7 @@ export class QueryHistoryManager extends DisposableObject {
783783

784784
async handleShowEvalLog(
785785
singleItem: QueryHistoryInfo,
786-
multiSelect: QueryHistoryInfo[],
786+
multiSelect: QueryHistoryInfo[] | undefined,
787787
) {
788788
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
789789
singleItem,
@@ -811,7 +811,7 @@ export class QueryHistoryManager extends DisposableObject {
811811

812812
async handleShowEvalLogSummary(
813813
singleItem: QueryHistoryInfo,
814-
multiSelect: QueryHistoryInfo[],
814+
multiSelect: QueryHistoryInfo[] | undefined,
815815
) {
816816
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
817817
singleItem,
@@ -849,7 +849,7 @@ export class QueryHistoryManager extends DisposableObject {
849849

850850
async handleShowEvalLogViewer(
851851
singleItem: QueryHistoryInfo,
852-
multiSelect: QueryHistoryInfo[],
852+
multiSelect: QueryHistoryInfo[] | undefined,
853853
) {
854854
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
855855
singleItem,
@@ -889,7 +889,7 @@ export class QueryHistoryManager extends DisposableObject {
889889

890890
async handleCancel(
891891
singleItem: QueryHistoryInfo,
892-
multiSelect: QueryHistoryInfo[],
892+
multiSelect: QueryHistoryInfo[] | undefined,
893893
) {
894894
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
895895
singleItem,
@@ -954,7 +954,7 @@ export class QueryHistoryManager extends DisposableObject {
954954

955955
async handleViewSarifAlerts(
956956
singleItem: QueryHistoryInfo,
957-
multiSelect: QueryHistoryInfo[],
957+
multiSelect: QueryHistoryInfo[] | undefined,
958958
) {
959959
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
960960
singleItem,
@@ -988,7 +988,7 @@ export class QueryHistoryManager extends DisposableObject {
988988

989989
async handleViewCsvResults(
990990
singleItem: QueryHistoryInfo,
991-
multiSelect: QueryHistoryInfo[],
991+
multiSelect: QueryHistoryInfo[] | undefined,
992992
) {
993993
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
994994
singleItem,
@@ -1016,7 +1016,7 @@ export class QueryHistoryManager extends DisposableObject {
10161016

10171017
async handleViewCsvAlerts(
10181018
singleItem: QueryHistoryInfo,
1019-
multiSelect: QueryHistoryInfo[],
1019+
multiSelect: QueryHistoryInfo[] | undefined,
10201020
) {
10211021
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
10221022
singleItem,
@@ -1044,7 +1044,7 @@ export class QueryHistoryManager extends DisposableObject {
10441044

10451045
async handleViewDil(
10461046
singleItem: QueryHistoryInfo,
1047-
multiSelect: QueryHistoryInfo[],
1047+
multiSelect: QueryHistoryInfo[] | undefined,
10481048
) {
10491049
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
10501050
singleItem,
@@ -1071,7 +1071,7 @@ export class QueryHistoryManager extends DisposableObject {
10711071

10721072
async handleOpenOnGithub(
10731073
singleItem: QueryHistoryInfo,
1074-
multiSelect: QueryHistoryInfo[],
1074+
multiSelect: QueryHistoryInfo[] | undefined,
10751075
) {
10761076
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
10771077
singleItem,
@@ -1096,7 +1096,7 @@ export class QueryHistoryManager extends DisposableObject {
10961096

10971097
async handleCopyRepoList(
10981098
singleItem: QueryHistoryInfo,
1099-
multiSelect: QueryHistoryInfo[],
1099+
multiSelect: QueryHistoryInfo[] | undefined,
11001100
) {
11011101
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
11021102
singleItem,
@@ -1120,7 +1120,7 @@ export class QueryHistoryManager extends DisposableObject {
11201120

11211121
async handleExportResults(
11221122
singleItem: QueryHistoryInfo,
1123-
multiSelect: QueryHistoryInfo[],
1123+
multiSelect: QueryHistoryInfo[] | undefined,
11241124
): Promise<void> {
11251125
const { finalSingleItem, finalMultiSelect } = this.determineSelection(
11261126
singleItem,
@@ -1295,10 +1295,10 @@ export class QueryHistoryManager extends DisposableObject {
12951295
* @param multiSelect a multi-select or undefined if no items are selected
12961296
*/
12971297
private determineSelection(
1298-
singleItem: QueryHistoryInfo,
1299-
multiSelect: QueryHistoryInfo[],
1298+
singleItem: QueryHistoryInfo | undefined,
1299+
multiSelect: QueryHistoryInfo[] | undefined,
13001300
): {
1301-
finalSingleItem: QueryHistoryInfo;
1301+
finalSingleItem: QueryHistoryInfo | undefined;
13021302
finalMultiSelect: QueryHistoryInfo[];
13031303
} {
13041304
if (!singleItem && !multiSelect?.[0]) {
@@ -1325,7 +1325,7 @@ export class QueryHistoryManager extends DisposableObject {
13251325
}
13261326
return {
13271327
finalSingleItem: singleItem,
1328-
finalMultiSelect: multiSelect,
1328+
finalMultiSelect: multiSelect || [],
13291329
};
13301330
}
13311331

extensions/ql-vscode/test/vscode-tests/no-workspace/query-history/variant-analysis-history.test.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -132,7 +132,10 @@ describe("Variant Analyses and QueryHistoryManager", () => {
132132
await qhm.readQueryHistory();
133133

134134
// Remove the first variant analysis
135-
await qhm.handleRemoveHistoryItem(qhm.treeDataProvider.allHistory[0]);
135+
await qhm.handleRemoveHistoryItem(
136+
qhm.treeDataProvider.allHistory[0],
137+
undefined,
138+
);
136139

137140
// Add it back to the history
138141
qhm.addQuery(rawQueryHistory[0]);

0 commit comments

Comments
 (0)