enable find in the debug console (#225093)

This commit is contained in:
Megan Rogge 2024-08-08 17:21:51 -07:00 committed by GitHub
parent de688270dd
commit 8f88d203d7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
2 changed files with 49 additions and 61 deletions

View file

@ -690,6 +690,8 @@ export class AsyncDataTree<TInput, T, TFilterData = void> implements IDisposable
} }
openFind(): void { openFind(): void {
// Until #212077, set to filter so behavior is consistent with filter widget
this.tree.findMode = TreeFindMode.Filter;
this.tree.openFind(); this.tree.openFind();
} }

View file

@ -56,7 +56,7 @@ import { IStorageService, StorageScope, StorageTarget } from 'vs/platform/storag
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry'; import { editorForeground, resolveColorValue } from 'vs/platform/theme/common/colorRegistry';
import { IThemeService } from 'vs/platform/theme/common/themeService'; import { IThemeService } from 'vs/platform/theme/common/themeService';
import { FilterViewPane, IViewPaneOptions, ViewAction } from 'vs/workbench/browser/parts/views/viewPane'; import { IViewPaneOptions, ViewAction, ViewPane } from 'vs/workbench/browser/parts/views/viewPane';
import { IViewDescriptorService } from 'vs/workbench/common/views'; import { IViewDescriptorService } from 'vs/workbench/common/views';
import { IViewsService } from 'vs/workbench/services/views/common/viewsService'; import { IViewsService } from 'vs/workbench/services/views/common/viewsService';
import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions'; import { getSimpleCodeEditorWidgetOptions, getSimpleEditorOptions } from 'vs/workbench/contrib/codeEditor/browser/simpleEditorOptions';
@ -74,11 +74,11 @@ import { AccessibilitySignal, IAccessibilitySignalService } from 'vs/platform/ac
import { IHoverService } from 'vs/platform/hover/browser/hover'; import { IHoverService } from 'vs/platform/hover/browser/hover';
import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration'; import { AccessibilityVerbositySettingId } from 'vs/workbench/contrib/accessibility/browser/accessibilityConfiguration';
import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands'; import { AccessibilityCommandId } from 'vs/workbench/contrib/accessibility/common/accessibilityCommands';
import { Codicon } from 'vs/base/common/codicons';
const $ = dom.$; const $ = dom.$;
const HISTORY_STORAGE_KEY = 'debug.repl.history'; const HISTORY_STORAGE_KEY = 'debug.repl.history';
const FILTER_HISTORY_STORAGE_KEY = 'debug.repl.filterHistory';
const FILTER_VALUE_STORAGE_KEY = 'debug.repl.filterValue'; const FILTER_VALUE_STORAGE_KEY = 'debug.repl.filterValue';
const DECORATION_KEY = 'replinputdecoration'; const DECORATION_KEY = 'replinputdecoration';
@ -90,7 +90,7 @@ function revealLastElement(tree: WorkbenchAsyncDataTree<any, any, any>) {
const sessionsToIgnore = new Set<IDebugSession>(); const sessionsToIgnore = new Set<IDebugSession>();
const identityProvider = { getId: (element: IReplElement) => element.getId() }; const identityProvider = { getId: (element: IReplElement) => element.getId() };
export class Repl extends FilterViewPane implements IHistoryNavigationWidget { export class Repl extends ViewPane implements IHistoryNavigationWidget {
declare readonly _serviceBrand: undefined; declare readonly _serviceBrand: undefined;
private static readonly REFRESH_DELAY = 50; // delay in ms to refresh the repl for new elements to show private static readonly REFRESH_DELAY = 50; // delay in ms to refresh the repl for new elements to show
@ -119,6 +119,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
private multiSessionRepl: IContextKey<boolean>; private multiSessionRepl: IContextKey<boolean>;
private menu: IMenu; private menu: IMenu;
private replDataSource: IAsyncDataSource<IDebugSession, IReplElement> | undefined; private replDataSource: IAsyncDataSource<IDebugSession, IReplElement> | undefined;
private findIsOpen: boolean = false;
constructor( constructor(
options: IViewPaneOptions, options: IViewPaneOptions,
@ -131,10 +132,10 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
@ICodeEditorService codeEditorService: ICodeEditorService, @ICodeEditorService codeEditorService: ICodeEditorService,
@IViewDescriptorService viewDescriptorService: IViewDescriptorService, @IViewDescriptorService viewDescriptorService: IViewDescriptorService,
@IContextMenuService contextMenuService: IContextMenuService, @IContextMenuService contextMenuService: IContextMenuService,
@IConfigurationService protected override readonly configurationService: IConfigurationService, @IConfigurationService configurationService: IConfigurationService,
@ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService, @ITextResourcePropertiesService private readonly textResourcePropertiesService: ITextResourcePropertiesService,
@IEditorService private readonly editorService: IEditorService, @IEditorService private readonly editorService: IEditorService,
@IKeybindingService protected override readonly keybindingService: IKeybindingService, @IKeybindingService keybindingService: IKeybindingService,
@IOpenerService openerService: IOpenerService, @IOpenerService openerService: IOpenerService,
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@IHoverService hoverService: IHoverService, @IHoverService hoverService: IHoverService,
@ -143,14 +144,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
@ILogService private readonly logService: ILogService, @ILogService private readonly logService: ILogService,
) { ) {
const filterText = storageService.get(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE, ''); const filterText = storageService.get(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE, '');
super({ super(options, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService, hoverService);
...options,
filterOptions: {
placeholder: localize({ key: 'workbench.debug.filter.placeholder', comment: ['Text in the brackets after e.g. is not localizable'] }, "Filter (e.g. text, !exclude, \\escape)"),
text: filterText,
history: JSON.parse(storageService.get(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE, '[]')) as string[],
}
}, keybindingService, contextMenuService, configurationService, contextKeyService, viewDescriptorService, instantiationService, openerService, themeService, telemetryService, hoverService);
this.menu = menuService.createMenu(MenuId.DebugConsoleContext, contextKeyService); this.menu = menuService.createMenu(MenuId.DebugConsoleContext, contextKeyService);
this._register(this.menu); this._register(this.menu);
@ -230,14 +224,6 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
this._register(this.editorService.onDidActiveEditorChange(() => { this._register(this.editorService.onDidActiveEditorChange(() => {
this.setMode(); this.setMode();
})); }));
this._register(this.filterWidget.onDidChangeFilterText(() => {
this.filter.filterQuery = this.filterWidget.getFilterText();
if (this.tree) {
this.tree.refilter();
revealLastElement(this.tree);
}
}));
} }
private async onDidFocusSession(session: IDebugSession | undefined): Promise<void> { private async onDidFocusSession(session: IDebugSession | undefined): Promise<void> {
@ -344,8 +330,8 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
} }
} }
focusFilter(): void { openFind(): void {
this.filterWidget.focus(); this.tree?.openFind();
} }
private setMode(): void { private setMode(): void {
@ -396,7 +382,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
this.tree?.rerender(); this.tree?.rerender();
if (this.bodyContentDimension) { if (this.bodyContentDimension) {
this.layoutBodyContent(this.bodyContentDimension.height, this.bodyContentDimension.width); this.layoutBody(this.bodyContentDimension.height, this.bodyContentDimension.width);
} }
} }
} }
@ -470,7 +456,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
this.replInputLineCount = 1; this.replInputLineCount = 1;
if (shouldRelayout && this.bodyContentDimension) { if (shouldRelayout && this.bodyContentDimension) {
// Trigger a layout to shrink a potential multi line input // Trigger a layout to shrink a potential multi line input
this.layoutBodyContent(this.bodyContentDimension.height, this.bodyContentDimension.width); this.layoutBody(this.bodyContentDimension.height, this.bodyContentDimension.width);
} }
} }
} }
@ -504,7 +490,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
return removeAnsiEscapeCodes(text); return removeAnsiEscapeCodes(text);
} }
protected layoutBodyContent(height: number, width: number): void { protected override layoutBody(height: number, width: number): void {
this.bodyContentDimension = new dom.Dimension(width, height); this.bodyContentDimension = new dom.Dimension(width, height);
const replInputHeight = Math.min(this.replInput.getContentHeight(), height); const replInputHeight = Math.min(this.replInput.getContentHeight(), height);
if (this.tree) { if (this.tree) {
@ -598,9 +584,6 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
}; };
await autoExpandElements(session.getReplElements()); await autoExpandElements(session.getReplElements());
} }
// Repl elements count changed, need to update filter stats on the badge
const { total, filtered } = this.getFilterStats();
this.filterWidget.updateBadge(total === filtered || total === 0 ? undefined : localize('showing filtered repl lines', "Showing {0} of {1}", filtered, total));
}, Repl.REFRESH_DELAY); }, Repl.REFRESH_DELAY);
} }
@ -610,10 +593,10 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
super.render(); super.render();
this._register(registerNavigableContainer({ this._register(registerNavigableContainer({
name: 'repl', name: 'repl',
focusNotifiers: [this, this.filterWidget], focusNotifiers: [this],
focusNextWidget: () => { focusNextWidget: () => {
const element = this.tree?.getHTMLElement(); const element = this.tree?.getHTMLElement();
if (this.filterWidget.hasFocus()) { if (this.findIsOpen) {
this.tree?.domFocus(); this.tree?.domFocus();
} else if (element && dom.isActiveElement(element)) { } else if (element && dom.isActiveElement(element)) {
this.focus(); this.focus();
@ -624,7 +607,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
if (this.replInput.hasTextFocus()) { if (this.replInput.hasTextFocus()) {
this.tree?.domFocus(); this.tree?.domFocus();
} else if (element && dom.isActiveElement(element)) { } else if (element && dom.isActiveElement(element)) {
this.focusFilter(); this.openFind();
} }
} }
})); }));
@ -664,7 +647,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
accessibilityProvider: new ReplAccessibilityProvider(), accessibilityProvider: new ReplAccessibilityProvider(),
identityProvider, identityProvider,
mouseSupport: false, mouseSupport: false,
findWidgetEnabled: false, findWidgetEnabled: true,
keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IReplElement) => e.toString(true) }, keyboardNavigationLabelProvider: { getKeyboardNavigationLabel: (e: IReplElement) => e.toString(true) },
horizontalScrolling: !wordWrap, horizontalScrolling: !wordWrap,
setRowLineHeight: false, setRowLineHeight: false,
@ -689,11 +672,16 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
})); }));
this._register(tree.onContextMenu(e => this.onContextMenu(e))); this._register(tree.onContextMenu(e => this.onContextMenu(e)));
this._register(tree.onDidChangeFindOpenState((open) => this.findIsOpen = open));
let lastSelectedString: string; let lastSelectedString: string;
this._register(tree.onMouseClick(() => { this._register(tree.onMouseClick(() => {
if (this.findIsOpen) {
return;
}
const selection = dom.getWindow(this.treeContainer).getSelection(); const selection = dom.getWindow(this.treeContainer).getSelection();
if (!selection || selection.type !== 'Range' || lastSelectedString === selection.toString()) { if (!selection || selection.type !== 'Range' || lastSelectedString === selection.toString()) {
// only focus the input if the user is not currently selecting. // only focus the input if the user is not currently selecting and find isn't open.
this.replInput.focus(); this.replInput.focus();
} }
lastSelectedString = selection ? selection.toString() : ''; lastSelectedString = selection ? selection.toString() : '';
@ -732,7 +720,7 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
if (lineCount !== this.replInputLineCount) { if (lineCount !== this.replInputLineCount) {
this.replInputLineCount = lineCount; this.replInputLineCount = lineCount;
if (this.bodyContentDimension) { if (this.bodyContentDimension) {
this.layoutBodyContent(this.bodyContentDimension.height, this.bodyContentDimension.width); this.layoutBody(this.bodyContentDimension.height, this.bodyContentDimension.width);
} }
} }
})); }));
@ -815,19 +803,6 @@ export class Repl extends FilterViewPane implements IHistoryNavigationWidget {
} else { } else {
this.storageService.remove(HISTORY_STORAGE_KEY, StorageScope.WORKSPACE); this.storageService.remove(HISTORY_STORAGE_KEY, StorageScope.WORKSPACE);
} }
const filterHistory = this.filterWidget.getHistory();
if (filterHistory.length) {
this.storageService.store(FILTER_HISTORY_STORAGE_KEY, JSON.stringify(filterHistory), StorageScope.WORKSPACE, StorageTarget.MACHINE);
} else {
this.storageService.remove(FILTER_HISTORY_STORAGE_KEY, StorageScope.WORKSPACE);
}
const filterValue = this.filterWidget.getFilterText();
if (filterValue) {
this.storageService.store(FILTER_VALUE_STORAGE_KEY, filterValue, StorageScope.WORKSPACE, StorageTarget.MACHINE);
} else {
this.storageService.remove(FILTER_VALUE_STORAGE_KEY, StorageScope.WORKSPACE);
}
super.saveState(); super.saveState();
} }
@ -913,25 +888,36 @@ class AcceptReplInputAction extends EditorAction {
} }
} }
class FilterReplAction extends EditorAction { class FilterReplAction extends ViewAction<Repl> {
constructor() { constructor() {
super({ super({
id: 'repl.action.filter', viewId: REPL_VIEW_ID,
label: localize('repl.action.filter', "Debug Console: Focus Filter"), id: 'repl.action.find',
alias: 'Debug Console: Focus Filter', title: localize('repl.action.find', "Debug Console: Focus Find"),
precondition: CONTEXT_IN_DEBUG_REPL, precondition: ContextKeyExpr.or(CONTEXT_IN_DEBUG_REPL, ContextKeyExpr.equals('focusedView', 'workbench.panel.repl.view')),
kbOpts: { keybinding: [{
kbExpr: EditorContextKeys.textInputFocus, when: ContextKeyExpr.or(CONTEXT_IN_DEBUG_REPL, ContextKeyExpr.equals('focusedView', 'workbench.panel.repl.view')),
primary: KeyMod.CtrlCmd | KeyCode.KeyF, primary: KeyMod.CtrlCmd | KeyCode.KeyF,
weight: KeybindingWeight.EditorContrib // override the editor's find
} weight: KeybindingWeight.EditorContrib + 10
}],
icon: Codicon.search,
menu: [{
id: MenuId.ViewTitle,
group: 'navigation',
when: ContextKeyExpr.equals('view', REPL_VIEW_ID),
order: 10
}, {
id: MenuId.DebugConsoleContext,
group: 'z_commands',
order: 20
}],
}); });
} }
run(accessor: ServicesAccessor, editor: ICodeEditor): void | Promise<void> { runInView(accessor: ServicesAccessor, view: Repl): void | Promise<void> {
const repl = getReplView(accessor.get(IViewsService)); view.openFind();
repl?.focusFilter();
} }
} }
@ -957,7 +943,7 @@ class ReplCopyAllAction extends EditorAction {
registerEditorAction(AcceptReplInputAction); registerEditorAction(AcceptReplInputAction);
registerEditorAction(ReplCopyAllAction); registerEditorAction(ReplCopyAllAction);
registerEditorAction(FilterReplAction); registerAction2(FilterReplAction);
class SelectReplActionViewItem extends FocusSessionActionViewItem { class SelectReplActionViewItem extends FocusSessionActionViewItem {