@codingame/monaco-vscode-extensions-service-override
Version:
VSCode public API plugged on the monaco editor - extensions service-override
528 lines (525 loc) • 22.8 kB
JavaScript
import { __decorate, __param } from 'vscode/external/tslib/tslib.es6.js';
import { Event } from 'vscode/vscode/vs/base/common/event';
import { DisposableStore, DisposableMap } from 'vscode/vscode/vs/base/common/lifecycle';
import { isEqual } from 'vscode/vscode/vs/base/common/resources';
import { URI } from 'vscode/vscode/vs/base/common/uri';
import { IConfigurationService } from 'vscode/vscode/vs/platform/configuration/common/configuration.service';
import { ILogService } from 'vscode/vscode/vs/platform/log/common/log.service';
import { ExtHostContext, TabInputKind, TabModelOperationKind, MainContext } from 'vscode/vscode/vs/workbench/api/common/extHost.protocol';
import { EditorResourceAccessor, SideBySideEditor, GroupModelChangeKind } from 'vscode/vscode/vs/workbench/common/editor';
import { DiffEditorInput } from 'vscode/vscode/vs/workbench/common/editor/diffEditorInput';
import { isGroupEditorMoveEvent } from 'vscode/vscode/vs/workbench/common/editor/editorGroupModel';
import { SideBySideEditorInput } from 'vscode/vscode/vs/workbench/common/editor/sideBySideEditorInput';
import { AbstractTextResourceEditorInput } from 'vscode/vscode/vs/workbench/common/editor/textResourceEditorInput';
import { ChatEditorInput } from 'vscode/vscode/vs/workbench/contrib/chat/browser/chatEditorInput';
import { CustomEditorInput } from 'vscode/vscode/vs/workbench/contrib/customEditor/browser/customEditorInput';
import { InteractiveEditorInput } from 'vscode/vscode/vs/workbench/contrib/interactive/browser/interactiveEditorInput';
import { MergeEditorInput } from 'vscode/vscode/vs/workbench/contrib/mergeEditor/browser/mergeEditorInput';
import { MultiDiffEditorInput } from 'vscode/vscode/vs/workbench/contrib/multiDiffEditor/browser/multiDiffEditorInput';
import { NotebookEditorInput } from 'vscode/vscode/vs/workbench/contrib/notebook/common/notebookEditorInput';
import { TerminalEditorInput } from 'vscode/vscode/vs/workbench/contrib/terminal/browser/terminalEditorInput';
import { WebviewInput } from 'vscode/vscode/vs/workbench/contrib/webviewPanel/browser/webviewEditorInput';
import { editorGroupToColumn, columnToEditorGroup } from 'vscode/vscode/vs/workbench/services/editor/common/editorGroupColumn';
import { GroupDirection, preferredSideBySideGroupDirection } from 'vscode/vscode/vs/workbench/services/editor/common/editorGroupsService';
import { IEditorGroupsService } from 'vscode/vscode/vs/workbench/services/editor/common/editorGroupsService.service';
import { SIDE_GROUP } from 'vscode/vscode/vs/workbench/services/editor/common/editorService';
import { IEditorService } from 'vscode/vscode/vs/workbench/services/editor/common/editorService.service';
import { extHostNamedCustomer } from '../../services/extensions/common/extHostCustomers.js';
let MainThreadEditorTabs = class MainThreadEditorTabs {
constructor(extHostContext, _editorGroupsService, _configurationService, _logService, editorService) {
this._editorGroupsService = _editorGroupsService;
this._configurationService = _configurationService;
this._logService = _logService;
this._dispoables = ( new DisposableStore());
this._tabGroupModel = [];
this._groupLookup = ( new Map());
this._tabInfoLookup = ( new Map());
this._multiDiffEditorInputListeners = ( new DisposableMap());
this._proxy = ( extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs));
this._dispoables.add(editorService.onDidEditorsChange((event) => {
try {
this._updateTabsModel(event);
}
catch {
this._logService.error('Failed to update model, rebuilding');
this._createTabsModel();
}
}));
this._dispoables.add(this._multiDiffEditorInputListeners);
this._dispoables.add(this._editorGroupsService.onDidAddGroup(() => this._createTabsModel()));
this._dispoables.add(this._editorGroupsService.onDidRemoveGroup(() => this._createTabsModel()));
this._editorGroupsService.whenReady.then(() => this._createTabsModel());
}
dispose() {
this._groupLookup.clear();
this._tabInfoLookup.clear();
this._dispoables.dispose();
}
_buildTabObject(group, editor, editorIndex) {
const editorId = editor.editorId;
const tab = {
id: this._generateTabId(editor, group.id),
label: editor.getName(),
editorId,
input: this._editorInputToDto(editor),
isPinned: group.isSticky(editorIndex),
isPreview: !group.isPinned(editorIndex),
isActive: group.isActive(editor),
isDirty: editor.isDirty()
};
return tab;
}
_editorInputToDto(editor) {
if (editor instanceof MergeEditorInput) {
return {
kind: TabInputKind.TextMergeInput,
base: editor.base,
input1: editor.input1.uri,
input2: editor.input2.uri,
result: editor.resource
};
}
if (editor instanceof AbstractTextResourceEditorInput) {
return {
kind: TabInputKind.TextInput,
uri: editor.resource
};
}
if (editor instanceof SideBySideEditorInput && !(editor instanceof DiffEditorInput)) {
const primaryResource = editor.primary.resource;
const secondaryResource = editor.secondary.resource;
if (editor.primary instanceof AbstractTextResourceEditorInput
&& editor.secondary instanceof AbstractTextResourceEditorInput
&& isEqual(primaryResource, secondaryResource)
&& primaryResource
&& secondaryResource) {
return {
kind: TabInputKind.TextInput,
uri: primaryResource
};
}
return { kind: TabInputKind.UnknownInput };
}
if (editor instanceof NotebookEditorInput) {
return {
kind: TabInputKind.NotebookInput,
notebookType: editor.viewType,
uri: editor.resource
};
}
if (editor instanceof CustomEditorInput) {
return {
kind: TabInputKind.CustomEditorInput,
viewType: editor.viewType,
uri: editor.resource,
};
}
if (editor instanceof WebviewInput) {
return {
kind: TabInputKind.WebviewEditorInput,
viewType: editor.viewType
};
}
if (editor instanceof TerminalEditorInput) {
return {
kind: TabInputKind.TerminalEditorInput
};
}
if (editor instanceof DiffEditorInput) {
if (editor.modified instanceof AbstractTextResourceEditorInput && editor.original instanceof AbstractTextResourceEditorInput) {
return {
kind: TabInputKind.TextDiffInput,
modified: editor.modified.resource,
original: editor.original.resource
};
}
if (editor.modified instanceof NotebookEditorInput && editor.original instanceof NotebookEditorInput) {
return {
kind: TabInputKind.NotebookDiffInput,
notebookType: editor.original.viewType,
modified: editor.modified.resource,
original: editor.original.resource
};
}
}
if (editor instanceof InteractiveEditorInput) {
return {
kind: TabInputKind.InteractiveEditorInput,
uri: editor.resource,
inputBoxUri: editor.inputResource
};
}
if (editor instanceof ChatEditorInput) {
return {
kind: TabInputKind.ChatEditorInput,
};
}
if (editor instanceof MultiDiffEditorInput) {
const diffEditors = [];
for (const resource of (editor?.resources.get() ?? [])) {
if (resource.originalUri && resource.modifiedUri) {
diffEditors.push({
kind: TabInputKind.TextDiffInput,
original: resource.originalUri,
modified: resource.modifiedUri
});
}
}
return {
kind: TabInputKind.MultiDiffEditorInput,
diffEditors
};
}
return { kind: TabInputKind.UnknownInput };
}
_generateTabId(editor, groupId) {
let resourceString;
const resource = EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.BOTH });
if (resource instanceof URI) {
resourceString = ( resource.toString());
}
else {
resourceString = `${resource?.primary?.toString()}-${resource?.secondary?.toString()}`;
}
return `${groupId}~${editor.editorId}-${editor.typeId}-${resourceString} `;
}
_onDidGroupActivate() {
const activeGroupId = this._editorGroupsService.activeGroup.id;
const activeGroup = this._groupLookup.get(activeGroupId);
if (activeGroup) {
activeGroup.isActive = true;
this._proxy.$acceptTabGroupUpdate(activeGroup);
}
}
_onDidTabLabelChange(groupId, editorInput, editorIndex) {
const tabId = this._generateTabId(editorInput, groupId);
const tabInfo = this._tabInfoLookup.get(tabId);
if (tabInfo) {
tabInfo.tab.label = editorInput.getName();
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: tabInfo.tab,
kind: TabModelOperationKind.TAB_UPDATE
});
}
else {
this._logService.error('Invalid model for label change, rebuilding');
this._createTabsModel();
}
}
_onDidTabOpen(groupId, editorInput, editorIndex) {
const group = this._editorGroupsService.getGroup(groupId);
const groupInModel = this._groupLookup.get(groupId) !== undefined;
if (!group || !groupInModel) {
this._createTabsModel();
return;
}
const tabs = this._groupLookup.get(groupId)?.tabs;
if (!tabs) {
return;
}
const tabObject = this._buildTabObject(group, editorInput, editorIndex);
tabs.splice(editorIndex, 0, tabObject);
const tabId = this._generateTabId(editorInput, groupId);
this._tabInfoLookup.set(tabId, { group, editorInput, tab: tabObject });
if (editorInput instanceof MultiDiffEditorInput) {
this._multiDiffEditorInputListeners.set(editorInput, Event.fromObservableLight(editorInput.resources)(() => {
const tabInfo = this._tabInfoLookup.get(tabId);
if (!tabInfo) {
return;
}
tabInfo.tab = this._buildTabObject(group, editorInput, editorIndex);
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: tabInfo.tab,
kind: TabModelOperationKind.TAB_UPDATE
});
}));
}
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: tabObject,
kind: TabModelOperationKind.TAB_OPEN
});
}
_onDidTabClose(groupId, editorIndex) {
const group = this._editorGroupsService.getGroup(groupId);
const tabs = this._groupLookup.get(groupId)?.tabs;
if (!group || !tabs) {
this._createTabsModel();
return;
}
const removedTab = tabs.splice(editorIndex, 1);
if (removedTab.length === 0) {
return;
}
this._tabInfoLookup.delete(removedTab[0]?.id ?? '');
if (removedTab[0]?.input instanceof MultiDiffEditorInput) {
this._multiDiffEditorInputListeners.deleteAndDispose(removedTab[0]?.input);
}
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: removedTab[0],
kind: TabModelOperationKind.TAB_CLOSE
});
}
_onDidTabActiveChange(groupId, editorIndex) {
const tabs = this._groupLookup.get(groupId)?.tabs;
if (!tabs) {
return;
}
const activeTab = tabs[editorIndex];
activeTab.isActive = true;
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: activeTab,
kind: TabModelOperationKind.TAB_UPDATE
});
}
_onDidTabDirty(groupId, editorIndex, editor) {
const tabId = this._generateTabId(editor, groupId);
const tabInfo = this._tabInfoLookup.get(tabId);
if (!tabInfo) {
this._logService.error('Invalid model for dirty change, rebuilding');
this._createTabsModel();
return;
}
tabInfo.tab.isDirty = editor.isDirty();
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: tabInfo.tab,
kind: TabModelOperationKind.TAB_UPDATE
});
}
_onDidTabPinChange(groupId, editorIndex, editor) {
const tabId = this._generateTabId(editor, groupId);
const tabInfo = this._tabInfoLookup.get(tabId);
const group = tabInfo?.group;
const tab = tabInfo?.tab;
if (!group || !tab) {
this._logService.error('Invalid model for sticky change, rebuilding');
this._createTabsModel();
return;
}
tab.isPinned = group.isSticky(editorIndex);
this._proxy.$acceptTabOperation({
groupId,
index: editorIndex,
tabDto: tab,
kind: TabModelOperationKind.TAB_UPDATE
});
}
_onDidTabPreviewChange(groupId, editorIndex, editor) {
const tabId = this._generateTabId(editor, groupId);
const tabInfo = this._tabInfoLookup.get(tabId);
const group = tabInfo?.group;
const tab = tabInfo?.tab;
if (!group || !tab) {
this._logService.error('Invalid model for sticky change, rebuilding');
this._createTabsModel();
return;
}
tab.isPreview = !group.isPinned(editorIndex);
this._proxy.$acceptTabOperation({
kind: TabModelOperationKind.TAB_UPDATE,
groupId,
tabDto: tab,
index: editorIndex
});
}
_onDidTabMove(groupId, editorIndex, oldEditorIndex, editor) {
const tabs = this._groupLookup.get(groupId)?.tabs;
if (!tabs) {
this._logService.error('Invalid model for move change, rebuilding');
this._createTabsModel();
return;
}
const removedTab = tabs.splice(oldEditorIndex, 1);
if (removedTab.length === 0) {
return;
}
tabs.splice(editorIndex, 0, removedTab[0]);
this._proxy.$acceptTabOperation({
kind: TabModelOperationKind.TAB_MOVE,
groupId,
tabDto: removedTab[0],
index: editorIndex,
oldIndex: oldEditorIndex
});
}
_createTabsModel() {
if (this._editorGroupsService.groups.length === 0) {
return;
}
this._tabGroupModel = [];
this._groupLookup.clear();
this._tabInfoLookup.clear();
let tabs = [];
for (const group of this._editorGroupsService.groups) {
const currentTabGroupModel = {
groupId: group.id,
isActive: group.id === this._editorGroupsService.activeGroup.id,
viewColumn: editorGroupToColumn(this._editorGroupsService, group),
tabs: []
};
group.editors.forEach((editor, editorIndex) => {
const tab = this._buildTabObject(group, editor, editorIndex);
tabs.push(tab);
this._tabInfoLookup.set(this._generateTabId(editor, group.id), {
group,
tab,
editorInput: editor
});
});
currentTabGroupModel.tabs = tabs;
this._tabGroupModel.push(currentTabGroupModel);
this._groupLookup.set(group.id, currentTabGroupModel);
tabs = [];
}
this._proxy.$acceptEditorTabModel(this._tabGroupModel);
}
_updateTabsModel(changeEvent) {
const event = changeEvent.event;
const groupId = changeEvent.groupId;
switch (event.kind) {
case GroupModelChangeKind.GROUP_ACTIVE:
if (groupId === this._editorGroupsService.activeGroup.id) {
this._onDidGroupActivate();
break;
}
else {
return;
}
case GroupModelChangeKind.EDITOR_LABEL:
if (event.editor !== undefined && event.editorIndex !== undefined) {
this._onDidTabLabelChange(groupId, event.editor, event.editorIndex);
break;
}
case GroupModelChangeKind.EDITOR_OPEN:
if (event.editor !== undefined && event.editorIndex !== undefined) {
this._onDidTabOpen(groupId, event.editor, event.editorIndex);
break;
}
case GroupModelChangeKind.EDITOR_CLOSE:
if (event.editorIndex !== undefined) {
this._onDidTabClose(groupId, event.editorIndex);
break;
}
case GroupModelChangeKind.EDITOR_ACTIVE:
if (event.editorIndex !== undefined) {
this._onDidTabActiveChange(groupId, event.editorIndex);
break;
}
case GroupModelChangeKind.EDITOR_DIRTY:
if (event.editorIndex !== undefined && event.editor !== undefined) {
this._onDidTabDirty(groupId, event.editorIndex, event.editor);
break;
}
case GroupModelChangeKind.EDITOR_STICKY:
if (event.editorIndex !== undefined && event.editor !== undefined) {
this._onDidTabPinChange(groupId, event.editorIndex, event.editor);
break;
}
case GroupModelChangeKind.EDITOR_PIN:
if (event.editorIndex !== undefined && event.editor !== undefined) {
this._onDidTabPreviewChange(groupId, event.editorIndex, event.editor);
break;
}
case GroupModelChangeKind.EDITOR_TRANSIENT:
break;
case GroupModelChangeKind.EDITOR_MOVE:
if (isGroupEditorMoveEvent(event) && event.editor && event.editorIndex !== undefined && event.oldEditorIndex !== undefined) {
this._onDidTabMove(groupId, event.editorIndex, event.oldEditorIndex, event.editor);
break;
}
default:
this._createTabsModel();
}
}
$moveTab(tabId, index, viewColumn, preserveFocus) {
const groupId = columnToEditorGroup(this._editorGroupsService, this._configurationService, viewColumn);
const tabInfo = this._tabInfoLookup.get(tabId);
const tab = tabInfo?.tab;
if (!tab) {
throw ( new Error(`Attempted to close tab with id ${tabId} which does not exist`));
}
let targetGroup;
const sourceGroup = this._editorGroupsService.getGroup(tabInfo.group.id);
if (!sourceGroup) {
return;
}
if (this._groupLookup.get(groupId) === undefined) {
let direction = GroupDirection.RIGHT;
if (viewColumn === SIDE_GROUP) {
direction = preferredSideBySideGroupDirection(this._configurationService);
}
targetGroup = this._editorGroupsService.addGroup(this._editorGroupsService.groups[this._editorGroupsService.groups.length - 1], direction);
}
else {
targetGroup = this._editorGroupsService.getGroup(groupId);
}
if (!targetGroup) {
return;
}
if (index < 0 || index > targetGroup.editors.length) {
index = targetGroup.editors.length;
}
const editorInput = tabInfo?.editorInput;
if (!editorInput) {
return;
}
sourceGroup.moveEditor(editorInput, targetGroup, { index, preserveFocus });
return;
}
async $closeTab(tabIds, preserveFocus) {
const groups = ( new Map());
for (const tabId of tabIds) {
const tabInfo = this._tabInfoLookup.get(tabId);
const tab = tabInfo?.tab;
const group = tabInfo?.group;
const editorTab = tabInfo?.editorInput;
if (!group || !tab || !tabInfo || !editorTab) {
continue;
}
const groupEditors = groups.get(group);
if (!groupEditors) {
groups.set(group, [editorTab]);
}
else {
groupEditors.push(editorTab);
}
}
const results = [];
for (const [group, editors] of groups) {
results.push(await group.closeEditors(editors, { preserveFocus }));
}
return results.every(result => result);
}
async $closeGroup(groupIds, preserveFocus) {
const groupCloseResults = [];
for (const groupId of groupIds) {
const group = this._editorGroupsService.getGroup(groupId);
if (group) {
groupCloseResults.push(await group.closeAllEditors());
if (group.count === 0 && this._editorGroupsService.getGroup(group.id)) {
this._editorGroupsService.removeGroup(group);
}
}
}
return groupCloseResults.every(result => result);
}
};
MainThreadEditorTabs = __decorate([
extHostNamedCustomer(MainContext.MainThreadEditorTabs),
( __param(1, IEditorGroupsService)),
( __param(2, IConfigurationService)),
( __param(3, ILogService)),
( __param(4, IEditorService))
], MainThreadEditorTabs);
export { MainThreadEditorTabs };