Skip to content

Commit 486f915

Browse files
authored
Add command to manage breakpoint exception types in command palette (#1566)
1 parent 97be390 commit 486f915

File tree

3 files changed

+130
-0
lines changed

3 files changed

+130
-0
lines changed

package.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,10 @@
9999
"command": "java.debug.pauseOthers",
100100
"title": "Pause Others"
101101
},
102+
{
103+
"command": "java.debug.breakpoints.exceptionTypes",
104+
"title": "Manage Java Breakpoint Exception Types"
105+
},
102106
{
103107
"command": "java.debug.variables.showHex",
104108
"title": "Show as Hex"

src/breakpointCommands.ts

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
import * as vscode from "vscode";
2+
3+
export function registerBreakpointCommands(context: vscode.ExtensionContext): void {
4+
context.subscriptions.push(vscode.commands.registerCommand('java.debug.breakpoints.exceptionTypes', exceptionTypes));
5+
}
6+
7+
async function exceptionTypes() {
8+
const config = vscode.workspace.getConfiguration('java.debug.settings.exceptionBreakpoint');
9+
let currentTypes = config.get<string[]>('exceptionTypes', []);
10+
const addExceptionTypeItem: vscode.QuickPickItem = {
11+
label: '$(add) Add Exception Types...',
12+
alwaysShow: true,
13+
};
14+
const removeExceptionTypeItem: any = (type: string): any => ({
15+
label: type,
16+
buttons: [{
17+
iconPath: new vscode.ThemeIcon('close'),
18+
tooltip: 'Remove this Exception Type'
19+
}]
20+
});
21+
22+
// Step 1: Show Breakpoint Exception Types
23+
const pickStep = async (state: any) => {
24+
return new Promise<any>((resolve) => {
25+
const items: vscode.QuickPickItem[] = [
26+
addExceptionTypeItem,
27+
...currentTypes.map(type => removeExceptionTypeItem(type))
28+
];
29+
const quickPick = vscode.window.createQuickPick();
30+
quickPick.items = items;
31+
quickPick.title = 'Breakpoint Exception Types';
32+
quickPick.canSelectMany = false;
33+
quickPick.matchOnDescription = false;
34+
quickPick.matchOnDetail = false;
35+
36+
quickPick.onDidAccept(() => {
37+
const selected = quickPick.selectedItems[0];
38+
if (selected.label.includes('Add Exception Types')) {
39+
quickPick.hide();
40+
// go to next step
41+
resolve(state);
42+
}
43+
});
44+
45+
quickPick.onDidTriggerItemButton(async (e) => {
46+
const typeToRemove = e.item.label;
47+
currentTypes = currentTypes.filter(type => type !== typeToRemove);
48+
await config.update('exceptionTypes', currentTypes, vscode.ConfigurationTarget.Global);
49+
quickPick.items = [
50+
addExceptionTypeItem,
51+
...currentTypes.map(type => removeExceptionTypeItem(type))
52+
];
53+
});
54+
quickPick.onDidHide(() => {
55+
quickPick.dispose();
56+
});
57+
quickPick.show();
58+
});
59+
};
60+
61+
// Step 2: Add Exception Type(s)
62+
const inputStep = async (state: any) => {
63+
return new Promise<any>((resolve, reject) => {
64+
const input = vscode.window.createInputBox();
65+
input.title = 'Add Breakpoint Exception Type(s)';
66+
input.placeholder = 'Enter exception type(s) (comma or space separated). "java.lang.NullPointerException" e.g.';
67+
input.prompt = 'Input exception types';
68+
input.buttons = [vscode.QuickInputButtons.Back];
69+
input.onDidAccept(async () => {
70+
const exceptionType = input.value;
71+
if (exceptionType) {
72+
const types = exceptionType.split(/[,\s]+/).map(type => type.trim()).filter(type => type.length > 0);
73+
let updated = false;
74+
for (const type of types) {
75+
if (!currentTypes.includes(type)) {
76+
currentTypes.push(type);
77+
updated = true;
78+
}
79+
}
80+
if (updated) {
81+
await config.update('exceptionTypes', currentTypes, vscode.ConfigurationTarget.Global);
82+
}
83+
}
84+
input.hide();
85+
// go back to pick step
86+
resolve(state);
87+
});
88+
input.onDidTriggerButton((btn) => {
89+
if (btn === vscode.QuickInputButtons.Back) {
90+
input.hide();
91+
reject({ stepBack: true });
92+
}
93+
});
94+
input.onDidHide(() => {
95+
input.dispose();
96+
});
97+
input.show();
98+
});
99+
};
100+
101+
while (true) {
102+
await multiStepInput([pickStep, inputStep], {});
103+
}
104+
}
105+
106+
async function multiStepInput<T>(steps: ((input: T) => Promise<T>)[], initial: T): Promise<T> {
107+
let state = initial;
108+
let currentStep = 0;
109+
while (currentStep < steps.length) {
110+
try {
111+
state = await steps[currentStep](state);
112+
currentStep++;
113+
} catch (err) {
114+
if (err?.stepBack) {
115+
if (currentStep > 0) {
116+
currentStep--;
117+
}
118+
} else {
119+
throw err;
120+
}
121+
}
122+
}
123+
return state;
124+
}

src/extension.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ import { progressProvider } from "./progressImpl";
2626
import { JavaTerminalLinkProvder } from "./terminalLinkProvider";
2727
import { initializeThreadOperations } from "./threadOperations";
2828
import * as utility from "./utility";
29+
import { registerBreakpointCommands } from "./breakpointCommands";
2930
import { registerVariableMenuCommands } from "./variableMenu";
3031
import { promisify } from "util";
3132

@@ -45,6 +46,7 @@ export async function activate(context: vscode.ExtensionContext): Promise<any> {
4546

4647
function initializeExtension(_operationId: string, context: vscode.ExtensionContext): any {
4748
registerDebugEventListener(context);
49+
registerBreakpointCommands(context);
4850
registerVariableMenuCommands(context);
4951
context.subscriptions.push(vscode.window.registerTerminalLinkProvider(new JavaTerminalLinkProvder()));
5052
context.subscriptions.push(vscode.debug.registerDebugConfigurationProvider("java", new JavaDebugConfigurationProvider()));

0 commit comments

Comments
 (0)