Skip to content

Commit 1a6ca93

Browse files
authored
Merge pull request microsoft#183090 from jeanp413/fix-183087
Fix cannot hide terminal find widget when pressing `esc`
2 parents 6fb9b05 + 3c7233e commit 1a6ca93

File tree

3 files changed

+85
-112
lines changed

3 files changed

+85
-112
lines changed

src/vs/workbench/contrib/terminal/browser/terminal.ts

Lines changed: 3 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
* Copyright (c) Microsoft Corporation. All rights reserved.
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
5-
import { Dimension } from 'vs/base/browser/dom';
5+
import { IDimension } from 'vs/base/browser/dom';
66
import { Orientation } from 'vs/base/browser/ui/splitview/splitview';
77
import { Color } from 'vs/base/common/color';
88
import { Event } from 'vs/base/common/event';
@@ -37,7 +37,7 @@ export const ITerminalInstanceService = createDecorator<ITerminalInstanceService
3737
* been initialized.
3838
*/
3939
export interface ITerminalContribution extends IDisposable {
40-
layout?(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void;
40+
layout?(xterm: IXtermTerminal & { raw: RawXtermTerminal }, dimension: IDimension): void;
4141
xtermReady?(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void;
4242
}
4343

@@ -434,7 +434,7 @@ export interface ITerminalInstance {
434434
readonly maxRows: number;
435435
readonly fixedCols?: number;
436436
readonly fixedRows?: number;
437-
readonly container?: HTMLElement;
437+
readonly domElement: HTMLElement;
438438
readonly icon?: TerminalIcon;
439439
readonly color?: string;
440440
readonly reconnectionProperties?: IReconnectionProperties;
@@ -936,25 +936,12 @@ export interface ITerminalInstance {
936936
*/
937937
resetScrollbarVisibility(): void;
938938

939-
/**
940-
* Register a child element to the terminal instance's container.
941-
*/
942-
registerChildElement(element: ITerminalChildElement): IDisposable;
943-
944939
/**
945940
* Gets a terminal contribution by its ID.
946941
*/
947942
getContribution<T extends ITerminalContribution>(id: string): T | null;
948943
}
949944

950-
// NOTE: This interface is very similar to the widget manager internal to TerminalInstance, in the
951-
// future these should probably be consolidated.
952-
export interface ITerminalChildElement {
953-
element: HTMLElement;
954-
layout?(dimension: Dimension): void;
955-
xtermReady?(xterm: IXtermTerminal): void;
956-
}
957-
958945
export const enum XtermTerminalConstants {
959946
SearchHighlightLimit = 1000
960947
}

src/vs/workbench/contrib/terminal/browser/terminalInstance.ts

Lines changed: 7 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ import { ErrorNoTelemetry, onUnexpectedError } from 'vs/base/common/errors';
1717
import { Emitter, Event } from 'vs/base/common/event';
1818
import { KeyCode } from 'vs/base/common/keyCodes';
1919
import { ISeparator, template } from 'vs/base/common/labels';
20-
import { Disposable, DisposableStore, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
20+
import { Disposable, dispose, IDisposable, toDisposable } from 'vs/base/common/lifecycle';
2121
import { Schemas } from 'vs/base/common/network';
2222
import * as path from 'vs/base/common/path';
2323
import { isMacintosh, isWindows, OperatingSystem, OS } from 'vs/base/common/platform';
@@ -53,7 +53,7 @@ import { IWorkspaceContextService, IWorkspaceFolder } from 'vs/platform/workspac
5353
import { IWorkspaceTrustRequestService } from 'vs/platform/workspace/common/workspaceTrust';
5454
import { IViewDescriptorService, IViewsService, ViewContainerLocation } from 'vs/workbench/common/views';
5555
import { TaskSettingId } from 'vs/workbench/contrib/tasks/common/tasks';
56-
import { IRequestAddInstanceToGroupEvent, ITerminalChildElement, ITerminalContribution, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
56+
import { IRequestAddInstanceToGroupEvent, ITerminalContribution, ITerminalInstance, TerminalDataTransfers } from 'vs/workbench/contrib/terminal/browser/terminal';
5757
import { TerminalLaunchHelpAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
5858
import { TerminalConfigHelper } from 'vs/workbench/contrib/terminal/browser/terminalConfigHelper';
5959
import { TerminalEditorInput } from 'vs/workbench/contrib/terminal/browser/terminalEditorInput';
@@ -163,8 +163,8 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
163163
private _title: string = '';
164164
private _titleSource: TitleEventSource = TitleEventSource.Process;
165165
private _container: HTMLElement | undefined;
166-
get container(): HTMLElement | undefined { return this._container; }
167166
private _wrapperElement: (HTMLElement & { xterm?: XTermTerminal });
167+
get domElement(): HTMLElement { return this._wrapperElement; }
168168
private _horizontalScrollbar: DomScrollableElement | undefined;
169169
private _terminalFocusContextKey: IContextKey<boolean>;
170170
private _terminalHasFixedWidth: IContextKey<boolean>;
@@ -335,12 +335,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
335335
private readonly _onDidChangeHasChildProcesses = this._register(new Emitter<boolean>());
336336
readonly onDidChangeHasChildProcesses = this._onDidChangeHasChildProcesses.event;
337337

338-
// Internal events
339-
private readonly _onDidAttachToElement = new Emitter<HTMLElement>();
340-
private readonly _onDidAttachToElementEvent = this._onDidAttachToElement.event;
341-
private readonly _onDidLayout = new Emitter<dom.Dimension>();
342-
private readonly _onDidLayoutEvent = this._onDidLayout.event;
343-
344338
constructor(
345339
private readonly _terminalShellTypeContextKey: IContextKey<string>,
346340
private readonly _terminalInRunCommandPicker: IContextKey<boolean>,
@@ -876,7 +870,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
876870
// The container changed, reattach
877871
this._container = container;
878872
this._container.appendChild(this._wrapperElement);
879-
this._onDidAttachToElement.fire(this._container);
880873
this.xterm?.refresh();
881874

882875
setTimeout(() => this._initDragAndDrop(container));
@@ -1837,17 +1830,16 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
18371830
}
18381831

18391832
this._resize();
1840-
this._onDidLayout.fire(dimension);
18411833

18421834
// Signal the container is ready
18431835
this._containerReadyBarrier.open();
18441836

18451837
// Layout all contributions
18461838
for (const contribution of this._contributions.values()) {
18471839
if (!this.xterm) {
1848-
this._xtermReadyPromise.then(xterm => contribution.layout?.(xterm));
1840+
this._xtermReadyPromise.then(xterm => contribution.layout?.(xterm, dimension));
18491841
} else {
1850-
contribution.layout?.(this.xterm);
1842+
contribution.layout?.(this.xterm, dimension);
18511843
}
18521844
}
18531845
}
@@ -2284,28 +2276,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
22842276
}
22852277

22862278
forceScrollbarVisibility(): void {
2287-
this._container?.classList.add('force-scrollbar');
2279+
this._wrapperElement.classList.add('force-scrollbar');
22882280
}
22892281

22902282
resetScrollbarVisibility(): void {
2291-
this._container?.classList.remove('force-scrollbar');
2292-
}
2293-
2294-
registerChildElement(child: ITerminalChildElement): IDisposable {
2295-
const store = new DisposableStore();
2296-
if (this._container) {
2297-
this._container.appendChild(child.element);
2298-
} else {
2299-
store.add(this._onDidAttachToElementEvent(container => container.appendChild(child.element)));
2300-
}
2301-
if (this._lastLayoutDimensions) {
2302-
child.layout?.(this._lastLayoutDimensions);
2303-
}
2304-
store.add(this._onDidLayoutEvent(e => child.layout?.(e)));
2305-
if (child.xtermReady) {
2306-
this._xtermReadyPromise.then(xterm => child.xtermReady!(xterm));
2307-
}
2308-
return store;
2283+
this._wrapperElement.classList.remove('force-scrollbar');
23092284
}
23102285
}
23112286

src/vs/workbench/contrib/terminalContrib/find/browser/terminal.find.contribution.ts

Lines changed: 75 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,82 @@
33
* Licensed under the MIT License. See License.txt in the project root for license information.
44
*--------------------------------------------------------------------------------------------*/
55

6+
import { IDimension } from 'vs/base/browser/dom';
67
import { KeyCode, KeyMod } from 'vs/base/common/keyCodes';
8+
import { Lazy } from 'vs/base/common/lazy';
9+
import { Disposable } from 'vs/base/common/lifecycle';
710
import { localize } from 'vs/nls';
811
import { ContextKeyExpr } from 'vs/platform/contextkey/common/contextkey';
9-
import { IInstantiationService, ServicesAccessor } from 'vs/platform/instantiation/common/instantiation';
12+
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
1013
import { KeybindingWeight } from 'vs/platform/keybinding/common/keybindingsRegistry';
1114
import { findInFilesCommand } from 'vs/workbench/contrib/search/browser/searchActionsFind';
12-
import { ITerminalInstance, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
15+
import { ITerminalContribution, ITerminalInstance, ITerminalService, IXtermTerminal } from 'vs/workbench/contrib/terminal/browser/terminal';
1316
import { registerActiveInstanceAction } from 'vs/workbench/contrib/terminal/browser/terminalActions';
14-
import { TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
17+
import { registerTerminalContribution } from 'vs/workbench/contrib/terminal/browser/terminalExtensions';
18+
import { TerminalWidgetManager } from 'vs/workbench/contrib/terminal/browser/widgets/widgetManager';
19+
import { ITerminalProcessManager, TerminalCommandId } from 'vs/workbench/contrib/terminal/common/terminal';
1520
import { TerminalContextKeys } from 'vs/workbench/contrib/terminal/common/terminalContextKey';
1621
import { TerminalFindWidget } from 'vs/workbench/contrib/terminalContrib/find/browser/terminalFindWidget';
22+
import { Terminal as RawXtermTerminal } from 'xterm';
1723

18-
const findWidgets: Map<ITerminalInstance, TerminalFindWidget> = new Map();
24+
class TerminalFindContribution extends Disposable implements ITerminalContribution {
25+
static readonly ID = 'terminal.find';
1926

20-
function getFindWidget(instance: ITerminalInstance | undefined, accessor: ServicesAccessor): TerminalFindWidget | undefined {
21-
if (instance === undefined) {
22-
return undefined;
27+
static get(instance: ITerminalInstance): TerminalFindContribution | null {
28+
return instance.getContribution<TerminalFindContribution>(TerminalFindContribution.ID);
2329
}
24-
let result = findWidgets.get(instance);
25-
if (!result) {
26-
const terminalService = accessor.get(ITerminalService);
27-
const widget = accessor.get(IInstantiationService).createInstance(TerminalFindWidget, instance);
28-
29-
// Track focus and set state so we can force the scroll bar to be visible
30-
let focusState = false;
31-
widget.focusTracker.onDidFocus(() => {
32-
focusState = true;
33-
instance.forceScrollbarVisibility();
34-
terminalService.setActiveInstance(instance);
35-
});
36-
widget.focusTracker.onDidBlur(() => {
37-
focusState = false;
38-
instance.resetScrollbarVisibility();
39-
});
4030

41-
// Attach the find widget and listen for layout
42-
instance.registerChildElement({
43-
element: widget.getDomNode(),
44-
layout: dimension => widget.layout(dimension.width),
45-
xtermReady: xterm => {
46-
xterm.onDidChangeFindResults(() => widget.updateResultCount());
47-
}
48-
});
31+
private _findWidget: Lazy<TerminalFindWidget>;
32+
private _lastLayoutDimensions: IDimension | undefined;
33+
34+
get findWidget(): TerminalFindWidget { return this._findWidget.value; }
4935

50-
// Cache the widget while the instance exists, dispose it when the terminal is disposed
51-
instance.onDisposed(e => {
52-
const focusTerminal = focusState;
53-
widget?.dispose();
54-
findWidgets.delete(e);
55-
if (focusTerminal) {
56-
instance.focus();
36+
constructor(
37+
private readonly _instance: ITerminalInstance,
38+
processManager: ITerminalProcessManager,
39+
widgetManager: TerminalWidgetManager,
40+
@IInstantiationService instantiationService: IInstantiationService,
41+
@ITerminalService terminalService: ITerminalService
42+
) {
43+
super();
44+
45+
this._findWidget = new Lazy(() => {
46+
const findWidget = instantiationService.createInstance(TerminalFindWidget, this._instance);
47+
48+
// Track focus and set state so we can force the scroll bar to be visible
49+
findWidget.focusTracker.onDidFocus(() => {
50+
this._instance.forceScrollbarVisibility();
51+
terminalService.setActiveInstance(this._instance);
52+
});
53+
findWidget.focusTracker.onDidBlur(() => {
54+
this._instance.resetScrollbarVisibility();
55+
});
56+
57+
this._instance.domElement.appendChild(findWidget.getDomNode());
58+
if (this._lastLayoutDimensions) {
59+
findWidget.layout(this._lastLayoutDimensions.width);
5760
}
61+
62+
return findWidget;
5863
});
64+
}
65+
66+
layout(xterm: IXtermTerminal & { raw: RawXtermTerminal }, dimension: IDimension): void {
67+
this._lastLayoutDimensions = dimension;
68+
this._findWidget.rawValue?.layout(dimension.width);
69+
}
70+
71+
xtermReady(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void {
72+
this._register(xterm.onDidChangeFindResults(() => this._findWidget.rawValue?.updateResultCount()));
73+
}
5974

60-
findWidgets.set(instance, widget);
61-
result = widget;
75+
override dispose() {
76+
super.dispose();
77+
this._findWidget.rawValue?.dispose();
6278
}
63-
return result;
79+
6480
}
81+
registerTerminalContribution(TerminalFindContribution.ID, TerminalFindContribution);
6582

6683
registerActiveInstanceAction({
6784
id: TerminalCommandId.FindFocus,
@@ -72,8 +89,8 @@ registerActiveInstanceAction({
7289
weight: KeybindingWeight.WorkbenchContrib
7390
},
7491
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
75-
run: (activeInstance, c, accessor) => {
76-
getFindWidget(activeInstance, accessor)?.reveal();
92+
run: (activeInstance) => {
93+
TerminalFindContribution.get(activeInstance)?.findWidget.reveal();
7794
}
7895
});
7996

@@ -87,8 +104,8 @@ registerActiveInstanceAction({
87104
weight: KeybindingWeight.WorkbenchContrib
88105
},
89106
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
90-
run: (activeInstance, c, accessor) => {
91-
getFindWidget(activeInstance, accessor)?.hide();
107+
run: (activeInstance) => {
108+
TerminalFindContribution.get(activeInstance)?.findWidget.hide();
92109
}
93110
});
94111

@@ -102,11 +119,9 @@ registerActiveInstanceAction({
102119
weight: KeybindingWeight.WorkbenchContrib
103120
},
104121
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
105-
run: (activeInstance, c, accessor) => {
106-
const state = getFindWidget(activeInstance, accessor)?.state;
107-
if (state) {
108-
state.change({ matchCase: !state.isRegex }, false);
109-
}
122+
run: (activeInstance) => {
123+
const state = TerminalFindContribution.get(activeInstance)?.findWidget.state;
124+
state?.change({ matchCase: !state.isRegex }, false);
110125
}
111126
});
112127

@@ -120,11 +135,9 @@ registerActiveInstanceAction({
120135
weight: KeybindingWeight.WorkbenchContrib
121136
},
122137
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
123-
run: (activeInstance, c, accessor) => {
124-
const state = getFindWidget(activeInstance, accessor)?.state;
125-
if (state) {
126-
state.change({ matchCase: !state.wholeWord }, false);
127-
}
138+
run: (activeInstance) => {
139+
const state = TerminalFindContribution.get(activeInstance)?.findWidget.state;
140+
state?.change({ matchCase: !state.wholeWord }, false);
128141
}
129142
});
130143

@@ -138,11 +151,9 @@ registerActiveInstanceAction({
138151
weight: KeybindingWeight.WorkbenchContrib
139152
},
140153
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
141-
run: (activeInstance, c, accessor) => {
142-
const state = getFindWidget(activeInstance, accessor)?.state;
143-
if (state) {
144-
state.change({ matchCase: !state.matchCase }, false);
145-
}
154+
run: (activeInstance) => {
155+
const state = TerminalFindContribution.get(activeInstance)?.findWidget.state;
156+
state?.change({ matchCase: !state.matchCase }, false);
146157
}
147158
});
148159

@@ -163,8 +174,8 @@ registerActiveInstanceAction({
163174
}
164175
],
165176
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
166-
run: (activeInstance, c, accessor) => {
167-
const widget = getFindWidget(activeInstance, accessor);
177+
run: (activeInstance) => {
178+
const widget = TerminalFindContribution.get(activeInstance)?.findWidget;
168179
if (widget) {
169180
widget.show();
170181
widget.find(false);
@@ -189,8 +200,8 @@ registerActiveInstanceAction({
189200
}
190201
],
191202
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
192-
run: (activeInstance, c, accessor) => {
193-
const widget = getFindWidget(activeInstance, accessor);
203+
run: (activeInstance) => {
204+
const widget = TerminalFindContribution.get(activeInstance)?.findWidget;
194205
if (widget) {
195206
widget.show();
196207
widget.find(true);

0 commit comments

Comments
 (0)