Skip to content

Commit 9385f11

Browse files
committed
1 parent adbcbfa commit 9385f11

File tree

3 files changed

+90
-103
lines changed

3 files changed

+90
-103
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>,
@@ -871,7 +865,6 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
871865
// The container changed, reattach
872866
this._container = container;
873867
this._container.appendChild(this._wrapperElement);
874-
this._onDidAttachToElement.fire(this._container);
875868
this.xterm?.refresh();
876869

877870
setTimeout(() => this._initDragAndDrop(container));
@@ -1832,17 +1825,16 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
18321825
}
18331826

18341827
this._resize();
1835-
this._onDidLayout.fire(dimension);
18361828

18371829
// Signal the container is ready
18381830
this._containerReadyBarrier.open();
18391831

18401832
// Layout all contributions
18411833
for (const contribution of this._contributions.values()) {
18421834
if (!this.xterm) {
1843-
this._xtermReadyPromise.then(xterm => contribution.layout?.(xterm));
1835+
this._xtermReadyPromise.then(xterm => contribution.layout?.(xterm, dimension));
18441836
} else {
1845-
contribution.layout?.(this.xterm);
1837+
contribution.layout?.(this.xterm, dimension);
18461838
}
18471839
}
18481840
}
@@ -2279,28 +2271,11 @@ export class TerminalInstance extends Disposable implements ITerminalInstance {
22792271
}
22802272

22812273
forceScrollbarVisibility(): void {
2282-
this._container?.classList.add('force-scrollbar');
2274+
this._wrapperElement.classList.add('force-scrollbar');
22832275
}
22842276

22852277
resetScrollbarVisibility(): void {
2286-
this._container?.classList.remove('force-scrollbar');
2287-
}
2288-
2289-
registerChildElement(child: ITerminalChildElement): IDisposable {
2290-
const store = new DisposableStore();
2291-
if (this._container) {
2292-
this._container.appendChild(child.element);
2293-
} else {
2294-
store.add(this._onDidAttachToElementEvent(container => container.appendChild(child.element)));
2295-
}
2296-
if (this._lastLayoutDimensions) {
2297-
child.layout?.(this._lastLayoutDimensions);
2298-
}
2299-
store.add(this._onDidLayoutEvent(e => child.layout?.(e)));
2300-
if (child.xtermReady) {
2301-
this._xtermReadyPromise.then(xterm => child.xtermReady!(xterm));
2302-
}
2303-
return store;
2278+
this._wrapperElement.classList.remove('force-scrollbar');
23042279
}
23052280
}
23062281

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

Lines changed: 80 additions & 55 deletions
Original file line numberDiff line numberDiff line change
@@ -3,65 +3,90 @@
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+
private _focusState: boolean = false;
34+
35+
get findWidget(): TerminalFindWidget { return this._findWidget.value; }
4936

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();
37+
constructor(
38+
private readonly _instance: ITerminalInstance,
39+
processManager: ITerminalProcessManager,
40+
widgetManager: TerminalWidgetManager,
41+
@IInstantiationService readonly _instantiationService: IInstantiationService,
42+
@ITerminalService readonly _terminalService: ITerminalService
43+
) {
44+
super();
45+
46+
this._findWidget = new Lazy(() => {
47+
const findWidget = this._instantiationService.createInstance(TerminalFindWidget, _instance);
48+
49+
// Track focus and set state so we can force the scroll bar to be visible
50+
findWidget.focusTracker.onDidFocus(() => {
51+
this._focusState = true;
52+
_instance.forceScrollbarVisibility();
53+
_terminalService.setActiveInstance(_instance);
54+
});
55+
findWidget.focusTracker.onDidBlur(() => {
56+
this._focusState = false;
57+
_instance.resetScrollbarVisibility();
58+
});
59+
60+
_instance.domElement.appendChild(findWidget.getDomNode());
61+
if (this._lastLayoutDimensions) {
62+
findWidget.layout(this._lastLayoutDimensions.width);
5763
}
64+
65+
return findWidget;
5866
});
67+
}
68+
69+
layout(xterm: IXtermTerminal & { raw: RawXtermTerminal }, dimension: IDimension): void {
70+
this._lastLayoutDimensions = dimension;
71+
this._findWidget.rawValue?.layout(dimension.width);
72+
}
73+
74+
xtermReady(xterm: IXtermTerminal & { raw: RawXtermTerminal }): void {
75+
this._register(xterm.onDidChangeFindResults(() => this._findWidget.rawValue?.updateResultCount()));
76+
}
77+
78+
override dispose() {
79+
super.dispose();
5980

60-
findWidgets.set(instance, widget);
61-
result = widget;
81+
const focusTerminal = this._focusState;
82+
this._findWidget.rawValue?.dispose();
83+
if (focusTerminal) {
84+
this._instance.focus();
85+
}
6286
}
63-
return result;
87+
6488
}
89+
registerTerminalContribution(TerminalFindContribution.ID, TerminalFindContribution);
6590

6691
registerActiveInstanceAction({
6792
id: TerminalCommandId.FindFocus,
@@ -72,8 +97,8 @@ registerActiveInstanceAction({
7297
weight: KeybindingWeight.WorkbenchContrib
7398
},
7499
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
75-
run: (activeInstance, c, accessor) => {
76-
getFindWidget(activeInstance, accessor)?.reveal();
100+
run: (activeInstance) => {
101+
TerminalFindContribution.get(activeInstance)?.findWidget?.reveal();
77102
}
78103
});
79104

@@ -87,8 +112,8 @@ registerActiveInstanceAction({
87112
weight: KeybindingWeight.WorkbenchContrib
88113
},
89114
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
90-
run: (activeInstance, c, accessor) => {
91-
getFindWidget(activeInstance, accessor)?.hide();
115+
run: (activeInstance) => {
116+
TerminalFindContribution.get(activeInstance)?.findWidget?.hide();
92117
}
93118
});
94119

@@ -102,8 +127,8 @@ registerActiveInstanceAction({
102127
weight: KeybindingWeight.WorkbenchContrib
103128
},
104129
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
105-
run: (activeInstance, c, accessor) => {
106-
const state = getFindWidget(activeInstance, accessor)?.state;
130+
run: (activeInstance) => {
131+
const state = TerminalFindContribution.get(activeInstance)?.findWidget?.state;
107132
if (state) {
108133
state.change({ matchCase: !state.isRegex }, false);
109134
}
@@ -120,8 +145,8 @@ registerActiveInstanceAction({
120145
weight: KeybindingWeight.WorkbenchContrib
121146
},
122147
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
123-
run: (activeInstance, c, accessor) => {
124-
const state = getFindWidget(activeInstance, accessor)?.state;
148+
run: (activeInstance) => {
149+
const state = TerminalFindContribution.get(activeInstance)?.findWidget?.state;
125150
if (state) {
126151
state.change({ matchCase: !state.wholeWord }, false);
127152
}
@@ -138,8 +163,8 @@ registerActiveInstanceAction({
138163
weight: KeybindingWeight.WorkbenchContrib
139164
},
140165
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
141-
run: (activeInstance, c, accessor) => {
142-
const state = getFindWidget(activeInstance, accessor)?.state;
166+
run: (activeInstance) => {
167+
const state = TerminalFindContribution.get(activeInstance)?.findWidget?.state;
143168
if (state) {
144169
state.change({ matchCase: !state.matchCase }, false);
145170
}
@@ -163,8 +188,8 @@ registerActiveInstanceAction({
163188
}
164189
],
165190
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
166-
run: (activeInstance, c, accessor) => {
167-
const widget = getFindWidget(activeInstance, accessor);
191+
run: (activeInstance) => {
192+
const widget = TerminalFindContribution.get(activeInstance)?.findWidget;
168193
if (widget) {
169194
widget.show();
170195
widget.find(false);
@@ -189,8 +214,8 @@ registerActiveInstanceAction({
189214
}
190215
],
191216
precondition: ContextKeyExpr.or(TerminalContextKeys.processSupported, TerminalContextKeys.terminalHasBeenCreated),
192-
run: (activeInstance, c, accessor) => {
193-
const widget = getFindWidget(activeInstance, accessor);
217+
run: (activeInstance) => {
218+
const widget = TerminalFindContribution.get(activeInstance)?.findWidget;
194219
if (widget) {
195220
widget.show();
196221
widget.find(true);

0 commit comments

Comments
 (0)