Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
microsoft
GitHub Repository: microsoft/vscode
Path: blob/main/src/vs/sessions/contrib/browserView/browser/sessionBrowserView.ts
13401 views
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
6
import { Disposable, DisposableMap, DisposableStore } from '../../../../base/common/lifecycle.js';
7
import { IWorkbenchContribution } from '../../../../workbench/common/contributions.js';
8
import { IBrowserViewWorkbenchService } from '../../../../workbench/contrib/browserView/common/browserView.js';
9
import { BrowserEditorInput } from '../../../../workbench/contrib/browserView/common/browserEditorInput.js';
10
import { IEditorService } from '../../../../workbench/services/editor/common/editorService.js';
11
import { IEditorGroupsService } from '../../../../workbench/services/editor/common/editorGroupsService.js';
12
import { ISessionsManagementService } from '../../../services/sessions/common/sessionsManagement.js';
13
import { ISession } from '../../../services/sessions/common/session.js';
14
import { runOnChange } from '../../../../base/common/observable.js';
15
16
export class SessionBrowserViewController extends Disposable implements IWorkbenchContribution {
17
18
static readonly ID = 'workbench.contrib.sessionBrowserViewController';
19
20
/**
21
* Tracks browser view inputs with their owning session. The
22
* DisposableMap cleans up lifecycle listeners on deletion/disposal.
23
*/
24
private readonly _trackedInputs = this._register(new DisposableMap<string, { session: ISession; dispose: () => void }>());
25
26
constructor(
27
@ISessionsManagementService private readonly _sessionManagementService: ISessionsManagementService,
28
@IBrowserViewWorkbenchService private readonly _browserViewService: IBrowserViewWorkbenchService,
29
@IEditorService private readonly _editorService: IEditorService,
30
@IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService,
31
) {
32
super();
33
34
// Catch editors opened via normal user/tool actions.
35
this._register(this._editorService.onWillOpenEditor(e => {
36
if (e.editor instanceof BrowserEditorInput) {
37
this._attachLifecycle(e.editor);
38
}
39
}));
40
41
// Catch editors restored from a working set swap — onWillOpenEditor
42
// does not fire for deserialized editors, but onDidAddGroup fires
43
// after the group (with its editors) has been created.
44
this._register(this._editorGroupsService.onDidAddGroup(group => {
45
for (const editor of group.editors) {
46
if (editor instanceof BrowserEditorInput) {
47
this._attachLifecycle(editor);
48
}
49
}
50
}));
51
52
// Force-destroy browser views when sessions are removed.
53
this._register(this._sessionManagementService.onDidChangeSessions(e => {
54
if (e.removed.length === 0 || this._trackedInputs.size === 0) {
55
return;
56
}
57
58
const removedSessionIds = new Set(e.removed.map(s => s.resource.toString()));
59
const known = this._browserViewService.getKnownBrowserViews();
60
for (const [id, { session }] of this._trackedInputs) {
61
if (removedSessionIds.has(session.resource.toString())) {
62
const existingInput = known.get(id);
63
if (existingInput instanceof BrowserEditorInput) {
64
existingInput.dispose(true);
65
}
66
}
67
}
68
}));
69
}
70
71
private _attachLifecycle(input: BrowserEditorInput): void {
72
if (this._trackedInputs.has(input.id)) {
73
return;
74
}
75
76
const session = this._sessionManagementService.activeSession.read(undefined);
77
if (!session) {
78
return; // no session, no lifecycle management needed
79
}
80
81
const store = new DisposableStore();
82
this._trackedInputs.set(input.id, { session, dispose: () => store.dispose() });
83
84
// When the owning session is archived, force-dispose the browser view.
85
store.add(runOnChange(session.isArchived, (isArchived) => {
86
if (isArchived) {
87
input.dispose(true);
88
}
89
}));
90
91
store.add(input.onBeforeDispose(e => {
92
const activeSession = this._sessionManagementService.activeSession.read(undefined);
93
94
// If the input is being disposed, but we are not currently in the owning session,
95
// assume a session swap is happening and do not actually dispose the browser yet.
96
if (session.sessionId !== activeSession?.sessionId) {
97
e.veto();
98
}
99
}));
100
101
store.add(input.onWillDispose(() => {
102
store.dispose();
103
this._trackedInputs.deleteAndDispose(input.id);
104
}));
105
}
106
}
107
108