Skip to content

Commit 98e6e2d

Browse files
committed
refactor: stream results into process picker to avoid long delays on windows
1 parent 6d59b34 commit 98e6e2d

File tree

1 file changed

+43
-25
lines changed

1 file changed

+43
-25
lines changed

src/ui/processPicker.ts

Lines changed: 43 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -91,13 +91,7 @@ export async function resolveProcessId(config: ResolvingNodeAttachConfiguration,
9191
*/
9292
export async function pickProcess(): Promise<string | null> {
9393
try {
94-
const items = await listProcesses();
95-
const options: vscode.QuickPickOptions = {
96-
placeHolder: localize('pickNodeProcess', 'Pick the node.js process to attach to'),
97-
matchOnDescription: true,
98-
matchOnDetail: true,
99-
};
100-
const item = await vscode.window.showQuickPick(items, options);
94+
const item = await listProcesses();
10195
return item ? item.pidAndPort : null;
10296
} catch (err) {
10397
await vscode.window.showErrorMessage(
@@ -116,25 +110,41 @@ const decodePidAndPort = (encoded: string) => {
116110
return { pid: Number(pid), port: port ? Number(port) : undefined };
117111
};
118112

119-
async function listProcesses(): Promise<IProcessItem[]> {
113+
async function listProcesses(): Promise<IProcessItem> {
120114
const nodeProcessPattern = /^(?:node|iojs)$/i;
121115
let seq = 0; // default sort key
122116

123-
const items = await processTree.lookup<IProcessItem[]>((leaf, acc) => {
124-
if (process.platform === 'win32' && leaf.command.indexOf('\\??\\') === 0) {
125-
// remove leading device specifier
126-
leaf.command = leaf.command.replace('\\??\\', '');
127-
}
117+
const quickPick = await vscode.window.createQuickPick<IProcessItem>();
118+
quickPick.placeholder = localize('pickNodeProcess', 'Pick the node.js process to attach to');
119+
quickPick.matchOnDescription = true;
120+
quickPick.matchOnDetail = true;
121+
quickPick.busy = true;
122+
quickPick.show();
123+
124+
let hasPicked = false;
125+
const itemPromise = new Promise<IProcessItem>(resolve => {
126+
quickPick.onDidAccept(() => resolve(quickPick.selectedItems[0]));
127+
quickPick.onDidHide(() => resolve(undefined));
128+
});
129+
130+
processTree
131+
.lookup<IProcessItem[]>((leaf, acc) => {
132+
if (hasPicked) {
133+
return acc;
134+
}
128135

129-
const executableName = basename(leaf.command, '.exe');
130-
const { port } = analyseArguments(leaf.args);
131-
if (!port && !nodeProcessPattern.test(executableName)) {
132-
return acc;
133-
}
136+
if (process.platform === 'win32' && leaf.command.indexOf('\\??\\') === 0) {
137+
// remove leading device specifier
138+
leaf.command = leaf.command.replace('\\??\\', '');
139+
}
134140

135-
return [
136-
...acc,
137-
{
141+
const executableName = basename(leaf.command, '.exe');
142+
const { port } = analyseArguments(leaf.args);
143+
if (!port && !nodeProcessPattern.test(executableName)) {
144+
return acc;
145+
}
146+
147+
const newItem = {
138148
label: executableName,
139149
description: leaf.args,
140150
pidAndPort: encodePidAndPort(leaf.pid, port),
@@ -148,11 +158,19 @@ async function listProcesses(): Promise<IProcessItem[]> {
148158
'SIGUSR1',
149159
)
150160
: localize('process.id.signal', 'process id: {0} ({1})', leaf.pid, 'SIGUSR1'),
151-
},
152-
];
153-
}, []);
161+
};
162+
163+
const index = acc.findIndex(item => item.sortKey < newItem.sortKey);
164+
acc.splice(index === -1 ? acc.length : index, 0, newItem);
165+
quickPick.items = acc;
166+
return acc;
167+
}, [])
168+
.then(() => (quickPick.busy = false));
154169

155-
return items.sort((a, b) => b.sortKey - a.sortKey); // sort items by process id, newest first
170+
const item = await itemPromise;
171+
hasPicked = true;
172+
quickPick.dispose();
173+
return item;
156174
}
157175

158176
function putPidInDebugMode(pid: number): void {

0 commit comments

Comments
 (0)