Skip to content

Commit 2219a2c

Browse files
authored
Quick Access For Loaded Scripts (microsoft#152680)
* add quick access for loaded scripts
1 parent 26aa72b commit 2219a2c

File tree

3 files changed

+125
-1
lines changed

3 files changed

+125
-1
lines changed

src/vs/workbench/contrib/debug/browser/debug.contribution.ts

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -20,7 +20,7 @@ import {
2020
} from 'vs/workbench/contrib/debug/common/debug';
2121
import { DebugToolBar } from 'vs/workbench/contrib/debug/browser/debugToolBar';
2222
import { DebugService } from 'vs/workbench/contrib/debug/browser/debugService';
23-
import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, DEBUG_QUICK_ACCESS_PREFIX, STEP_INTO_TARGET_ID, STEP_INTO_TARGET_LABEL } from 'vs/workbench/contrib/debug/browser/debugCommands';
23+
import { ADD_CONFIGURATION_ID, TOGGLE_INLINE_BREAKPOINT_ID, COPY_STACK_TRACE_ID, RESTART_SESSION_ID, TERMINATE_THREAD_ID, STEP_OVER_ID, STEP_INTO_ID, STEP_OUT_ID, PAUSE_ID, DISCONNECT_ID, STOP_ID, RESTART_FRAME_ID, CONTINUE_ID, FOCUS_REPL_ID, JUMP_TO_CURSOR_ID, RESTART_LABEL, STEP_INTO_LABEL, STEP_OVER_LABEL, STEP_OUT_LABEL, PAUSE_LABEL, DISCONNECT_LABEL, STOP_LABEL, CONTINUE_LABEL, DEBUG_START_LABEL, DEBUG_START_COMMAND_ID, DEBUG_RUN_LABEL, DEBUG_RUN_COMMAND_ID, EDIT_EXPRESSION_COMMAND_ID, REMOVE_EXPRESSION_COMMAND_ID, SELECT_AND_START_ID, SELECT_AND_START_LABEL, SET_EXPRESSION_COMMAND_ID, DISCONNECT_AND_SUSPEND_ID, DISCONNECT_AND_SUSPEND_LABEL, NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL, PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL, SHOW_LOADED_SCRIPTS_LABEL, SHOW_LOADED_SCRIPTS_ID, DEBUG_QUICK_ACCESS_PREFIX, DEBUG_CONSOLE_QUICK_ACCESS_PREFIX, SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL, STEP_INTO_TARGET_LABEL, STEP_INTO_TARGET_ID } from 'vs/workbench/contrib/debug/browser/debugCommands';
2424
import { StatusBarColorProvider } from 'vs/workbench/contrib/debug/browser/statusbarColorProvider';
2525
import { IViewsRegistry, Extensions as ViewExtensions, IViewContainersRegistry, ViewContainerLocation, ViewContainer } from 'vs/workbench/common/views';
2626
import { isMacintosh, isWeb } from 'vs/base/common/platform';
@@ -133,6 +133,7 @@ registerDebugCommandPaletteItem(DEBUG_RUN_COMMAND_ID, DEBUG_RUN_LABEL, ContextKe
133133
registerDebugCommandPaletteItem(SELECT_AND_START_ID, SELECT_AND_START_LABEL, ContextKeyExpr.and(CONTEXT_DEBUGGERS_AVAILABLE, CONTEXT_DEBUG_STATE.notEqualsTo(getStateLabel(State.Initializing))));
134134
registerDebugCommandPaletteItem(NEXT_DEBUG_CONSOLE_ID, NEXT_DEBUG_CONSOLE_LABEL);
135135
registerDebugCommandPaletteItem(PREV_DEBUG_CONSOLE_ID, PREV_DEBUG_CONSOLE_LABEL);
136+
registerDebugCommandPaletteItem(SHOW_LOADED_SCRIPTS_ID, SHOW_LOADED_SCRIPTS_LABEL, CONTEXT_IN_DEBUG_MODE);
136137
registerDebugCommandPaletteItem(SELECT_DEBUG_CONSOLE_ID, SELECT_DEBUG_CONSOLE_LABEL);
137138

138139

src/vs/workbench/contrib/debug/browser/debugCommands.ts

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ import { deepClone } from 'vs/base/common/objects';
3131
import { isWeb, isWindows } from 'vs/base/common/platform';
3232
import { saveAllBeforeDebugStart } from 'vs/workbench/contrib/debug/common/debugUtils';
3333
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
34+
import { showLoadedScriptMenu } from 'vs/workbench/contrib/debug/common/loadedScriptsPicker';
3435

3536
export const ADD_CONFIGURATION_ID = 'debug.addConfiguration';
3637
export const TOGGLE_INLINE_BREAKPOINT_ID = 'editor.debug.action.toggleInlineBreakpoint';
@@ -62,6 +63,7 @@ export const SET_EXPRESSION_COMMAND_ID = 'debug.setWatchExpression';
6263
export const REMOVE_EXPRESSION_COMMAND_ID = 'debug.removeWatchExpression';
6364
export const NEXT_DEBUG_CONSOLE_ID = 'workbench.action.debug.nextConsole';
6465
export const PREV_DEBUG_CONSOLE_ID = 'workbench.action.debug.prevConsole';
66+
export const SHOW_LOADED_SCRIPTS_ID = 'workbench.action.debug.showLoadedScripts';
6567

6668
export const RESTART_LABEL = nls.localize('restartDebug', "Restart");
6769
export const STEP_OVER_LABEL = nls.localize('stepOverDebug', "Step Over");
@@ -80,6 +82,8 @@ export const DEBUG_START_LABEL = nls.localize('startDebug', "Start Debugging");
8082
export const DEBUG_RUN_LABEL = nls.localize('startWithoutDebugging', "Start Without Debugging");
8183
export const NEXT_DEBUG_CONSOLE_LABEL = nls.localize('nextDebugConsole', "Focus Next Debug Console");
8284
export const PREV_DEBUG_CONSOLE_LABEL = nls.localize('prevDebugConsole', "Focus Previous Debug Console");
85+
export const SHOW_LOADED_SCRIPTS_LABEL = nls.localize('showLoadedScripts', "Show Loaded Scripts");
86+
8387
export const SELECT_DEBUG_CONSOLE_LABEL = nls.localize('selectDebugConsole', "Select Debug Console");
8488

8589
export const DEBUG_QUICK_ACCESS_PREFIX = 'debug ';
@@ -511,6 +515,15 @@ KeybindingsRegistry.registerCommandAndKeybindingRule({
511515
}
512516
});
513517

518+
CommandsRegistry.registerCommand({
519+
id: SHOW_LOADED_SCRIPTS_ID,
520+
handler: async (accessor) => {
521+
522+
await showLoadedScriptMenu(accessor);
523+
524+
}
525+
});
526+
514527
CommandsRegistry.registerCommand({
515528
id: FOCUS_REPL_ID,
516529
handler: async (accessor) => {
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
/*---------------------------------------------------------------------------------------------
2+
* Copyright (c) Microsoft Corporation. All rights reserved.
3+
* Licensed under the MIT License. See License.txt in the project root for license information.
4+
*--------------------------------------------------------------------------------------------*/
5+
import * as nls from 'vs/nls';
6+
import { matchesFuzzy } from 'vs/base/common/filters';
7+
import { Source } from 'vs/workbench/contrib/debug/common/debugSource';
8+
import { IQuickInputService, IQuickPickItem, IQuickPickSeparator } from 'vs/platform/quickinput/common/quickInput';
9+
import { IDebugService, IDebugSession } from 'vs/workbench/contrib/debug/common/debug';
10+
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
11+
import { getIconClasses } from 'vs/editor/common/services/getIconClasses';
12+
import { IModelService } from 'vs/editor/common/services/model';
13+
import { ILanguageService } from 'vs/editor/common/languages/language';
14+
import { DisposableStore } from 'vs/base/common/lifecycle';
15+
16+
import { dirname } from 'vs/base/common/resources';
17+
import { ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
18+
import { ILabelService } from 'vs/platform/label/common/label';
19+
20+
21+
interface IPickerLoadedScriptItem extends IQuickPickItem {
22+
accept(): void;
23+
}
24+
25+
26+
/**
27+
* This function takes a regular quickpick and makes one for loaded scripts that has persistent headers
28+
* e.g. when some picks are filtered out, the ones that are visible still have its header.
29+
*/
30+
export async function showLoadedScriptMenu(accessor: ServicesAccessor) {
31+
const quickInputService = accessor.get(IQuickInputService);
32+
const debugService = accessor.get(IDebugService);
33+
const editorService = accessor.get(IEditorService);
34+
const sessions = debugService.getModel().getSessions(false);
35+
const modelService = accessor.get(IModelService);
36+
const languageService = accessor.get(ILanguageService);
37+
const labelService = accessor.get(ILabelService);
38+
39+
const localDisposableStore = new DisposableStore();
40+
const quickPick = quickInputService.createQuickPick<IPickerLoadedScriptItem>();
41+
localDisposableStore.add(quickPick);
42+
quickPick.matchOnLabel = quickPick.matchOnDescription = quickPick.matchOnDetail = quickPick.sortByLabel = false;
43+
quickPick.placeholder = nls.localize('moveFocusedView.selectView', "Search loaded scripts by name");
44+
quickPick.items = await _getPicks(quickPick.value, sessions, editorService, modelService, languageService, labelService);
45+
46+
localDisposableStore.add(quickPick.onDidChangeValue(async () => {
47+
quickPick.items = await _getPicks(quickPick.value, sessions, editorService, modelService, languageService, labelService);
48+
}));
49+
localDisposableStore.add(quickPick.onDidAccept(() => {
50+
const selectedItem = quickPick.selectedItems[0];
51+
selectedItem.accept();
52+
quickPick.hide();
53+
localDisposableStore.dispose();
54+
}));
55+
quickPick.show();
56+
}
57+
58+
async function _getPicksFromSession(session: IDebugSession, filter: string, editorService: IEditorService, modelService: IModelService, languageService: ILanguageService, labelService: ILabelService): Promise<Array<IPickerLoadedScriptItem | IQuickPickSeparator>> {
59+
const items: Array<IPickerLoadedScriptItem | IQuickPickSeparator> = [];
60+
items.push({ type: 'separator', label: session.name });
61+
const sources = await session.getLoadedSources();
62+
63+
sources.forEach((element: Source) => {
64+
const pick = _createPick(element, filter, editorService, modelService, languageService, labelService);
65+
if (pick) {
66+
items.push(pick);
67+
}
68+
69+
});
70+
return items;
71+
}
72+
async function _getPicks(filter: string, sessions: IDebugSession[], editorService: IEditorService, modelService: IModelService, languageService: ILanguageService, labelService: ILabelService): Promise<Array<IPickerLoadedScriptItem | IQuickPickSeparator>> {
73+
const loadedScriptPicks: Array<IPickerLoadedScriptItem | IQuickPickSeparator> = [];
74+
75+
76+
const picks = await Promise.all(
77+
sessions.map((session) => _getPicksFromSession(session, filter, editorService, modelService, languageService, labelService))
78+
);
79+
80+
for (const row of picks) {
81+
for (const elem of row) {
82+
loadedScriptPicks.push(elem);
83+
}
84+
}
85+
return loadedScriptPicks;
86+
}
87+
88+
function _createPick(source: Source, filter: string, editorService: IEditorService, modelService: IModelService, languageService: ILanguageService, labelService: ILabelService): IPickerLoadedScriptItem | undefined {
89+
90+
const label = labelService.getUriBasenameLabel(source.uri);
91+
const desc = labelService.getUriLabel(dirname(source.uri));
92+
93+
// manually filter so that headers don't get filtered out
94+
const labelHighlights = matchesFuzzy(filter, label, true);
95+
const descHighlights = matchesFuzzy(filter, desc, true);
96+
if (labelHighlights || descHighlights) {
97+
return {
98+
label,
99+
description: desc === '.' ? undefined : desc,
100+
highlights: { label: labelHighlights ?? undefined, description: descHighlights ?? undefined },
101+
iconClasses: getIconClasses(modelService, languageService, source.uri),
102+
accept: () => {
103+
if (source.available) {
104+
source.openInEditor(editorService, { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 });
105+
}
106+
}
107+
};
108+
}
109+
return undefined;
110+
}

0 commit comments

Comments
 (0)