Path: blob/main/src/vs/sessions/contrib/browserView/browser/sessionBrowserView.ts
13401 views
/*---------------------------------------------------------------------------------------------1* Copyright (c) Microsoft Corporation. All rights reserved.2* Licensed under the MIT License. See License.txt in the project root for license information.3*--------------------------------------------------------------------------------------------*/45import { Disposable, DisposableMap, DisposableStore } from '../../../../base/common/lifecycle.js';6import { IWorkbenchContribution } from '../../../../workbench/common/contributions.js';7import { IBrowserViewWorkbenchService } from '../../../../workbench/contrib/browserView/common/browserView.js';8import { BrowserEditorInput } from '../../../../workbench/contrib/browserView/common/browserEditorInput.js';9import { IEditorService } from '../../../../workbench/services/editor/common/editorService.js';10import { IEditorGroupsService } from '../../../../workbench/services/editor/common/editorGroupsService.js';11import { ISessionsManagementService } from '../../../services/sessions/common/sessionsManagement.js';12import { ISession } from '../../../services/sessions/common/session.js';13import { runOnChange } from '../../../../base/common/observable.js';1415export class SessionBrowserViewController extends Disposable implements IWorkbenchContribution {1617static readonly ID = 'workbench.contrib.sessionBrowserViewController';1819/**20* Tracks browser view inputs with their owning session. The21* DisposableMap cleans up lifecycle listeners on deletion/disposal.22*/23private readonly _trackedInputs = this._register(new DisposableMap<string, { session: ISession; dispose: () => void }>());2425constructor(26@ISessionsManagementService private readonly _sessionManagementService: ISessionsManagementService,27@IBrowserViewWorkbenchService private readonly _browserViewService: IBrowserViewWorkbenchService,28@IEditorService private readonly _editorService: IEditorService,29@IEditorGroupsService private readonly _editorGroupsService: IEditorGroupsService,30) {31super();3233// Catch editors opened via normal user/tool actions.34this._register(this._editorService.onWillOpenEditor(e => {35if (e.editor instanceof BrowserEditorInput) {36this._attachLifecycle(e.editor);37}38}));3940// Catch editors restored from a working set swap — onWillOpenEditor41// does not fire for deserialized editors, but onDidAddGroup fires42// after the group (with its editors) has been created.43this._register(this._editorGroupsService.onDidAddGroup(group => {44for (const editor of group.editors) {45if (editor instanceof BrowserEditorInput) {46this._attachLifecycle(editor);47}48}49}));5051// Force-destroy browser views when sessions are removed.52this._register(this._sessionManagementService.onDidChangeSessions(e => {53if (e.removed.length === 0 || this._trackedInputs.size === 0) {54return;55}5657const removedSessionIds = new Set(e.removed.map(s => s.resource.toString()));58const known = this._browserViewService.getKnownBrowserViews();59for (const [id, { session }] of this._trackedInputs) {60if (removedSessionIds.has(session.resource.toString())) {61const existingInput = known.get(id);62if (existingInput instanceof BrowserEditorInput) {63existingInput.dispose(true);64}65}66}67}));68}6970private _attachLifecycle(input: BrowserEditorInput): void {71if (this._trackedInputs.has(input.id)) {72return;73}7475const session = this._sessionManagementService.activeSession.read(undefined);76if (!session) {77return; // no session, no lifecycle management needed78}7980const store = new DisposableStore();81this._trackedInputs.set(input.id, { session, dispose: () => store.dispose() });8283// When the owning session is archived, force-dispose the browser view.84store.add(runOnChange(session.isArchived, (isArchived) => {85if (isArchived) {86input.dispose(true);87}88}));8990store.add(input.onBeforeDispose(e => {91const activeSession = this._sessionManagementService.activeSession.read(undefined);9293// If the input is being disposed, but we are not currently in the owning session,94// assume a session swap is happening and do not actually dispose the browser yet.95if (session.sessionId !== activeSession?.sessionId) {96e.veto();97}98}));99100store.add(input.onWillDispose(() => {101store.dispose();102this._trackedInputs.deleteAndDispose(input.id);103}));104}105}106107108