diff --git a/src/vs/workbench/contrib/debug/browser/media/repl.css b/src/vs/workbench/contrib/debug/browser/media/repl.css index 2eaa06164d0a529791f87965334522ff95203978..b2a47407653969ecf4496ab30bc1d5590518ad1c 100644 --- a/src/vs/workbench/contrib/debug/browser/media/repl.css +++ b/src/vs/workbench/contrib/debug/browser/media/repl.css @@ -115,6 +115,25 @@ } .panel > .title .monaco-action-bar .action-item.repl-panel-filter-container { - min-width: 200px; + min-width: 300px; margin-right: 10px; } + +.repl-panel-filter-container .repl-panel-filter-controls { + position: absolute; + top: 0px; + bottom: 0; + right: 0px; + display: flex; + align-items: center; +} + +.repl-panel-filter-container .repl-panel-filter-controls > .repl-panel-filter-badge { + margin: 4px; + padding: 0px 8px; + border-radius: 2px; +} + +.repl-panel-filter-container .repl-panel-filter-controls > .repl-panel-filter-badge.hidden { + display: none; +} diff --git a/src/vs/workbench/contrib/debug/browser/repl.ts b/src/vs/workbench/contrib/debug/browser/repl.ts index 06620126115c58f51e00ae4968e86e955bc2d753..fc538869ccbc4cacd52de0faf5d7e39049782070 100644 --- a/src/vs/workbench/contrib/debug/browser/repl.ts +++ b/src/vs/workbench/contrib/debug/browser/repl.ts @@ -251,6 +251,22 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { })); } + private computeFilterStats(): { total: number, filtered: number } { + let filtered = 0; + let total = 0; + if (this.tree) { + total = this.tree.getNode().children.length; + for (const child of this.tree.getNode().children) { + if (child.visible) { + ++filtered; + } + } + } + return { + total, filtered + }; + } + get isReadonly(): boolean { // Do not allow to edit inactive sessions const session = this.tree.getInput(); @@ -574,6 +590,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } lastSelectedString = selection ? selection.toString() : ''; })); + this._register(this.tree.onDidChangeContentHeight(() => this.refreshReplElements(false))); // Make sure to select the session if debugging is already active this.selectSession(); this.styleElement = dom.createStyleSheet(this.container); @@ -665,6 +682,7 @@ export class Repl extends ViewPane implements IHistoryNavigationWidget { } this.refreshScheduler.schedule(noDelay ? 0 : undefined); + this.filterState.filterStats = this.computeFilterStats(); } } diff --git a/src/vs/workbench/contrib/debug/browser/replFilter.ts b/src/vs/workbench/contrib/debug/browser/replFilter.ts index 978564cbfd9608fb82a32edd9c71ec67a0760e6e..0bd4c0c9cd6b5043e8c4839e008e2dfba3112490 100644 --- a/src/vs/workbench/contrib/debug/browser/replFilter.ts +++ b/src/vs/workbench/contrib/debug/browser/replFilter.ts @@ -19,9 +19,11 @@ import { Event, Emitter } from 'vs/base/common/event'; import { StandardKeyboardEvent } from 'vs/base/browser/keyboardEvent'; import { KeyCode } from 'vs/base/common/keyCodes'; import { ContextScopedHistoryInputBox } from 'vs/platform/browser/contextScopedHistoryWidget'; -import { attachInputBoxStyler } from 'vs/platform/theme/common/styler'; +import { attachInputBoxStyler, attachStylerCallback } from 'vs/platform/theme/common/styler'; import { IThemeService } from 'vs/platform/theme/common/themeService'; +import { badgeBackground, badgeForeground, contrastBorder } from 'vs/platform/theme/common/colorRegistry'; import { ReplEvaluationResult, ReplEvaluationInput } from 'vs/workbench/contrib/debug/common/replModel'; +import { localize } from 'vs/nls'; type ParsedQuery = { @@ -84,12 +86,30 @@ export class ReplFilterState { return this._onDidChange.event; } + private readonly _onDidStatsChange: Emitter = new Emitter(); + get onDidStatsChange(): Event { + return this._onDidStatsChange.event; + } + private _filterText = ''; + private _stats = { total: 0, filtered: 0 }; get filterText(): string { return this._filterText; } + get filterStats(): { total: number, filtered: number } { + return this._stats; + } + + set filterStats(stats: { total: number, filtered: number }) { + const { total, filtered } = stats; + if (this._stats.total !== total || this._stats.filtered !== filtered) { + this._stats = { total, filtered }; + this._onDidStatsChange.fire(); + } + } + set filterText(filterText: string) { if (this._filterText !== filterText) { this._filterText = filterText; @@ -102,6 +122,7 @@ export class ReplFilterActionViewItem extends BaseActionViewItem { private delayedFilterUpdate: Delayer; private container!: HTMLElement; + private filterBadge: HTMLElement | null = null; private filterInputBox!: HistoryInputBox; constructor( @@ -123,6 +144,7 @@ export class ReplFilterActionViewItem extends BaseActionViewItem { this.element = DOM.append(this.container, DOM.$('')); this.element.className = this.class; this.createInput(this.element); + this.createBadge(this.element); this.updateClass(); } @@ -179,6 +201,37 @@ export class ReplFilterActionViewItem extends BaseActionViewItem { } } + private createBadge(container: HTMLElement): void { + const controlsContainer = DOM.append(container, DOM.$('.repl-panel-filter-controls')); + const filterBadge = this.filterBadge = DOM.append(controlsContainer, DOM.$('.repl-panel-filter-badge')); + this._register(attachStylerCallback(this.themeService, { badgeBackground, badgeForeground, contrastBorder }, colors => { + const background = colors.badgeBackground ? colors.badgeBackground.toString() : ''; + const foreground = colors.badgeForeground ? colors.badgeForeground.toString() : ''; + const border = colors.contrastBorder ? colors.contrastBorder.toString() : ''; + + filterBadge.style.backgroundColor = background; + + filterBadge.style.borderWidth = border ? '1px' : ''; + filterBadge.style.borderStyle = border ? 'solid' : ''; + filterBadge.style.borderColor = border; + filterBadge.style.color = foreground; + })); + this.updateBadge(); + this._register(this.filters.onDidStatsChange(() => this.updateBadge())); + } + + private updateBadge(): void { + if (this.filterBadge) { + const { total, filtered } = this.filters.filterStats; + const filterBadgeHidden = total === filtered || total === 0; + + this.filterBadge.classList.toggle('hidden', filterBadgeHidden); + this.filterBadge.textContent = localize('showing filtered repl lines', "Showing {0} of {1}", filtered, total); + + this.filterInputBox.inputElement.style.paddingRight = filterBadgeHidden ? '4px' : '150px'; + } + } + protected get class(): string { return 'panel-action-tree-filter'; } diff --git a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts index 5732761d20ac0825d816ead175656830450edcfd..e18243b1ab7ca659e13d9e024f0c63a31a5db04e 100644 --- a/src/vs/workbench/contrib/markers/browser/markersViewActions.ts +++ b/src/vs/workbench/contrib/markers/browser/markersViewActions.ts @@ -392,7 +392,7 @@ export class MarkersFilterActionViewItem extends BaseActionViewItem { private updateBadge(): void { if (this.filterBadge) { const { total, filtered } = this.filterController.getFilterStats(); - this.filterBadge.classList.toggle('hidden', total === filtered || filtered === 0); + this.filterBadge.classList.toggle('hidden', total === filtered || total === 0); this.filterBadge.textContent = localize('showing filtered problems', "Showing {0} of {1}", filtered, total); this.adjustInputBox(); }