Merge vscode source through 1.62 release (#19981)

* Build breaks 1

* Build breaks

* Build breaks

* Build breaks

* More build breaks

* Build breaks (#2512)

* Runtime breaks

* Build breaks

* Fix dialog location break

* Update typescript

* Fix ASAR break issue

* Unit test breaks

* Update distro

* Fix breaks in ADO builds (#2513)

* Bump to node 16

* Fix hygiene errors

* Bump distro

* Remove reference to node type

* Delete vscode specific extension

* Bump to node 16 in CI yaml

* Skip integration tests in CI builds (while fixing)

* yarn.lock update

* Bump moment dependency in remote yarn

* Fix drop-down chevron style

* Bump to node 16

* Remove playwrite from ci.yaml

* Skip building build scripts in hygine check
This commit is contained in:
Karl Burtram
2022-07-11 14:09:32 -07:00
committed by GitHub
parent fa0fcef303
commit 26455e9113
1876 changed files with 72050 additions and 37997 deletions

View File

@@ -17,6 +17,7 @@ import { INotificationService } from 'vs/platform/notification/common/notificati
import { fromNow } from 'vs/base/common/date';
import { ActivationKind, IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import type { AuthenticationGetSessionOptions } from 'vscode';
interface TrustedExtensionsQuickPickItem {
label: string;
@@ -204,91 +205,67 @@ export class MainThreadAuthentication extends Disposable implements MainThreadAu
}
private async selectSession(providerId: string, extensionId: string, extensionName: string, scopes: string[], potentialSessions: readonly modes.AuthenticationSession[], clearSessionPreference: boolean, silent: boolean): Promise<modes.AuthenticationSession | undefined> {
if (!potentialSessions.length) {
throw new Error('No potential sessions found');
}
if (clearSessionPreference) {
this.storageService.remove(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
} else {
const existingSessionPreference = this.storageService.get(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
if (existingSessionPreference) {
const matchingSession = potentialSessions.find(session => session.id === existingSessionPreference);
if (matchingSession) {
const allowed = this.authenticationService.isAccessAllowed(providerId, matchingSession.account.label, extensionId);
if (!allowed) {
if (!silent) {
const didAcceptPrompt = await this.authenticationService.showGetSessionPrompt(providerId, matchingSession.account.label, extensionId, extensionName);
if (!didAcceptPrompt) {
throw new Error('User did not consent to login.');
}
} else {
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, potentialSessions);
return undefined;
}
}
return matchingSession;
}
}
}
if (silent) {
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, potentialSessions);
return undefined;
}
return this.authenticationService.selectSession(providerId, extensionId, extensionName, scopes, potentialSessions);
}
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: { createIfNone: boolean, forceNewSession: boolean | { detail: string }, clearSessionPreference: boolean }): Promise<modes.AuthenticationSession | undefined> {
private async doGetSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<modes.AuthenticationSession | undefined> {
const sessions = await this.authenticationService.getSessions(providerId, scopes, true);
let silent = !options.createIfNone;
// Error cases
if (options.forceNewSession && !sessions.length) {
throw new Error('No existing sessions found.');
}
if (options.forceNewSession && options.createIfNone) {
throw new Error('Invalid combination of options. Please remove one of the following: forceNewSession, createIfNone');
}
if (options.forceNewSession && options.silent) {
throw new Error('Invalid combination of options. Please remove one of the following: forceNewSession, silent');
}
if (options.createIfNone && options.silent) {
throw new Error('Invalid combination of options. Please remove one of the following: createIfNone, silent');
}
let session: modes.AuthenticationSession | undefined;
// Ignore existing sessions if we are forceRecreating
// Check if the sessions we have are valid
if (!options.forceNewSession && sessions.length) {
if (!this.authenticationService.supportsMultipleAccounts(providerId)) {
session = sessions[0];
const allowed = this.authenticationService.isAccessAllowed(providerId, session.account.label, extensionId);
if (!allowed) {
if (!silent) {
const didAcceptPrompt = await this.authenticationService.showGetSessionPrompt(providerId, session.account.label, extensionId, extensionName);
if (!didAcceptPrompt) {
throw new Error('User did not consent to login.');
if (this.authenticationService.supportsMultipleAccounts(providerId)) {
if (options.clearSessionPreference) {
this.storageService.remove(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
} else {
const existingSessionPreference = this.storageService.get(`${extensionName}-${providerId}`, StorageScope.GLOBAL);
if (existingSessionPreference) {
const matchingSession = sessions.find(session => session.id === existingSessionPreference);
if (matchingSession && this.authenticationService.isAccessAllowed(providerId, matchingSession.account.label, extensionId)) {
return matchingSession;
}
} else if (allowed !== false) {
this.authenticationService.requestSessionAccess(providerId, extensionId, extensionName, scopes, [session]);
return undefined;
} else {
return undefined;
}
}
} else {
return this.selectSession(providerId, extensionId, extensionName, scopes, sessions, !!options.clearSessionPreference, silent);
}
} else {
// If we are forceRecreating, we need to show the prompt.
if (options.forceNewSession || !silent) {
const providerName = this.authenticationService.getLabel(providerId);
const detail = (typeof options.forceNewSession === 'object') ? options.forceNewSession!.detail : undefined;
const isAllowed = await this.loginPrompt(providerName, extensionName, !!options.forceNewSession, detail);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
session = await this.authenticationService.createSession(providerId, scopes, true);
await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
} else {
await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);
} else if (this.authenticationService.isAccessAllowed(providerId, sessions[0].account.label, extensionId)) {
return sessions[0];
}
}
// We may need to prompt because we don't have a valid session
// modal flows
if (options.createIfNone || options.forceNewSession) {
const providerName = this.authenticationService.getLabel(providerId);
const detail = (typeof options.forceNewSession === 'object') ? options.forceNewSession!.detail : undefined;
const isAllowed = await this.loginPrompt(providerName, extensionName, !!options.forceNewSession, detail);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
const session = await this.authenticationService.createSession(providerId, scopes, true);
await this.setTrustedExtensionAndAccountPreference(providerId, session.account.label, extensionId, extensionName, session.id);
return session;
}
// passive flows
if (!options.silent) {
await this.authenticationService.requestNewSession(providerId, scopes, extensionId, extensionName);
}
return undefined;
}
async $getSession(providerId: string, scopes: string[], extensionId: string, extensionName: string, options: AuthenticationGetSessionOptions): Promise<modes.AuthenticationSession | undefined> {
const session = await this.doGetSession(providerId, scopes, extensionId, extensionName, options);
if (session) {
type AuthProviderUsageClassification = {
extensionId: { classification: 'SystemMetaData', purpose: 'FeatureInsight' };

View File

@@ -9,6 +9,7 @@ import { ExtHostContext, MainThreadCommandsShape, ExtHostCommandsShape, MainCont
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { revive } from 'vs/base/common/marshalling';
import { IExtensionService } from 'vs/workbench/services/extensions/common/extensions';
import { SerializableObjectWithBuffers } from 'vs/workbench/services/extensions/common/proxyIdentifier';
@extHostNamedCustomer(MainContext.MainThreadCommands)
export class MainThreadCommands implements MainThreadCommandsShape {
@@ -72,7 +73,10 @@ export class MainThreadCommands implements MainThreadCommandsShape {
}
}
async $executeCommand<T>(id: string, args: any[], retry: boolean): Promise<T | undefined> {
async $executeCommand<T>(id: string, args: any[] | SerializableObjectWithBuffers<any[]>, retry: boolean): Promise<T | undefined> {
if (args instanceof SerializableObjectWithBuffers) {
args = args.value;
}
for (let i = 0; i < args.length; i++) {
args[i] = revive(args[i]);
}

View File

@@ -290,6 +290,10 @@ export class MainThreadCommentController {
}
}
updateCommentingRanges() {
this._commentService.updateCommentingRanges(this._uniqueId);
}
private getKnownThread(commentThreadHandle: number): MainThreadCommentThread {
const thread = this._threads.get(commentThreadHandle);
if (!thread) {
@@ -412,12 +416,15 @@ export class MainThreadComments extends Disposable implements MainThreadComments
$unregisterCommentController(handle: number): void {
const providerId = this._handlers.get(handle);
if (typeof providerId !== 'string') {
throw new Error('unknown handler');
}
this._commentService.unregisterCommentController(providerId);
this._handlers.delete(handle);
this._commentControllers.delete(handle);
if (typeof providerId !== 'string') {
return;
// throw new Error('unknown handler');
} else {
this._commentService.unregisterCommentController(providerId);
}
}
$updateCommentControllerFeatures(handle: number, features: CommentProviderFeatures): void {
@@ -470,6 +477,16 @@ export class MainThreadComments extends Disposable implements MainThreadComments
return provider.deleteCommentThread(commentThreadHandle);
}
$updateCommentingRanges(handle: number) {
let provider = this._commentControllers.get(handle);
if (!provider) {
return;
}
provider.updateCommentingRanges();
}
private registerView(commentsViewAlreadyRegistered: boolean) {
if (!commentsViewAlreadyRegistered) {
const VIEW_CONTAINER: ViewContainer = Registry.as<IViewContainersRegistry>(ViewExtensions.ViewContainersRegistry).registerViewContainer({

View File

@@ -7,7 +7,7 @@ import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MainContext, MainThreadConsoleShape, IExtHostContext } from 'vs/workbench/api/common/extHost.protocol';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IRemoteConsoleLog, log } from 'vs/base/common/console';
import { logRemoteEntry } from 'vs/workbench/services/extensions/common/remoteConsoleUtil';
import { logRemoteEntry, logRemoteEntryIfError } from 'vs/workbench/services/extensions/common/remoteConsoleUtil';
import { parseExtensionDevOptions } from 'vs/workbench/services/extensions/common/extensionDevOptions';
import { ILogService } from 'vs/platform/log/common/log';
@@ -30,14 +30,13 @@ export class MainThreadConsole implements MainThreadConsoleShape {
}
$logExtensionHostMessage(entry: IRemoteConsoleLog): void {
// Send to local console unless we run tests from cli
if (!this._isExtensionDevTestFromCli) {
log(entry, 'Extension Host');
}
// Log on main side if running tests from cli
if (this._isExtensionDevTestFromCli) {
// If running tests from cli, log to the log service everything
logRemoteEntry(this._logService, entry);
} else {
// Log to the log service only errors and log everything to local console
logRemoteEntryIfError(this._logService, entry, 'Extension Host');
log(entry, 'Extension Host');
}
}
}

View File

@@ -646,7 +646,7 @@ class MainThreadCustomEditorModel extends ResourceWorkingCopy implements ICustom
backupId: '',
extension: primaryEditor.extension ? {
id: primaryEditor.extension.id.value,
location: primaryEditor.extension.location,
location: primaryEditor.extension.location!,
} : undefined,
webview: {
id: primaryEditor.id,

View File

@@ -219,7 +219,7 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
return undefined;
}
public $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, options: IStartDebuggingOptions): Promise<boolean> {
public async $startDebugging(folder: UriComponents | undefined, nameOrConfig: string | IDebugConfiguration, options: IStartDebuggingOptions): Promise<boolean> {
const folderUri = folder ? uri.revive(folder) : undefined;
const launch = this.debugService.getConfigurationManager().getLaunch(folderUri);
const parentSession = this.getSession(options.parentSessionID);
@@ -232,11 +232,12 @@ export class MainThreadDebugService implements MainThreadDebugServiceShape, IDeb
debugUI: options.debugUI,
compoundRoot: parentSession?.compoundRoot
};
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions).then(success => {
return success;
}, err => {
return Promise.reject(new Error(err && err.message ? err.message : 'cannot start debugging'));
});
try {
const saveBeforeStart = typeof options.suppressSaveBeforeStart === 'boolean' ? !options.suppressSaveBeforeStart : undefined;
return this.debugService.startDebugging(launch, nameOrConfig, debugOptions, saveBeforeStart);
} catch (err) {
throw new Error(err && err.message ? err.message : 'cannot start debugging');
}
}
public $setDebugSessionName(sessionId: DebugSessionUUID, name: string): void {

View File

@@ -8,7 +8,7 @@ import { Emitter } from 'vs/base/common/event';
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
import { ExtHostContext, MainContext, IExtHostContext, MainThreadDecorationsShape, ExtHostDecorationsShape, DecorationData, DecorationRequest } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/browser/decorations';
import { IDecorationsService, IDecorationData } from 'vs/workbench/services/decorations/common/decorations';
import { CancellationToken } from 'vs/base/common/cancellation';
class DecorationRequestsQueue {

View File

@@ -29,8 +29,9 @@ export class BoundModelReferenceCollection {
constructor(
private readonly _extUri: IExtUri,
private readonly _maxAge: number = 1000 * 60 * 3,
private readonly _maxLength: number = 1024 * 1024 * 80,
private readonly _maxAge: number = 1000 * 60 * 3, // auto-dispse by age
private readonly _maxLength: number = 1024 * 1024 * 80, // auto-dispose by total length
private readonly _maxSize: number = 50 // auto-dispose by number of references
) {
//
}
@@ -69,9 +70,15 @@ export class BoundModelReferenceCollection {
}
private _cleanup(): void {
// clean-up wrt total length
while (this._length > this._maxLength) {
this._data[0].dispose();
}
// clean-up wrt number of documents
const extraSize = Math.ceil(this._maxSize * 1.2);
if (this._data.length >= extraSize) {
dispose(this._data.slice(0, extraSize - this._maxSize));
}
}
}
@@ -191,7 +198,7 @@ export class MainThreadDocuments extends Disposable implements MainThreadDocumen
if (!this._modelIsSynced.has(model.uri)) {
return;
}
this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageIdentifier().language);
this._proxy.$acceptModelModeChanged(model.uri, model.getLanguageId());
}
private _onModelRemoved(modelUrl: URI): void {

View File

@@ -24,7 +24,6 @@ import { IEditorPane } from 'vs/workbench/common/editor';
import { EditorGroupColumn, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IPanelService } from 'vs/workbench/services/panel/common/panelService';
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
import { IWorkbenchEnvironmentService } from 'vs/workbench/services/environment/common/environmentService';
import { IWorkingCopyFileService } from 'vs/workbench/services/workingCopy/common/workingCopyFileService';
@@ -35,7 +34,8 @@ import { diffSets, diffMaps } from 'vs/base/common/collections';
import { INotebookService } from 'sql/workbench/services/notebook/browser/notebookService';
import { Schemas } from 'vs/base/common/network';
import { CELL_URI_PATH_PREFIX } from 'sql/workbench/common/constants';
import { IPaneCompositePartService } from 'vs/workbench/services/panecomposite/browser/panecomposite';
import { ViewContainerLocation } from 'vs/workbench/common/views';
class TextEditorSnapshot {
@@ -125,7 +125,7 @@ class MainThreadDocumentAndEditorStateComputer {
@IModelService private readonly _modelService: IModelService,
@ICodeEditorService private readonly _codeEditorService: ICodeEditorService,
@IEditorService private readonly _editorService: IEditorService,
@IPanelService private readonly _panelService: IPanelService
@IPaneCompositePartService private readonly _paneCompositeService: IPaneCompositePartService,
) {
this._modelService.onModelAdded(this._updateStateOnModelAdd, this, this._toDispose);
this._modelService.onModelRemoved(_ => this._updateState(), this, this._toDispose);
@@ -135,8 +135,8 @@ class MainThreadDocumentAndEditorStateComputer {
this._codeEditorService.onCodeEditorRemove(this._onDidRemoveEditor, this, this._toDispose);
this._codeEditorService.listCodeEditors().forEach(this._onDidAddEditor, this);
this._panelService.onDidPanelOpen(_ => this._activeEditorOrder = ActiveEditorOrder.Panel, undefined, this._toDispose);
this._panelService.onDidPanelClose(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
Event.filter(this._paneCompositeService.onDidPaneCompositeOpen, event => event.viewContainerLocation === ViewContainerLocation.Panel)(_ => this._activeEditorOrder = ActiveEditorOrder.Panel, undefined, this._toDispose);
Event.filter(this._paneCompositeService.onDidPaneCompositeClose, event => event.viewContainerLocation === ViewContainerLocation.Panel)(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
this._editorService.onDidVisibleEditorsChange(_ => this._activeEditorOrder = ActiveEditorOrder.Editor, undefined, this._toDispose);
this._updateState();
@@ -255,12 +255,15 @@ class MainThreadDocumentAndEditorStateComputer {
}
private _getActiveEditorFromPanel(): IEditor | undefined {
const panel = this._panelService.getActivePanel();
if (panel instanceof BaseTextEditor && isCodeEditor(panel.getControl())) {
return panel.getControl();
} else {
return undefined;
const panel = this._paneCompositeService.getActivePaneComposite(ViewContainerLocation.Panel);
if (panel instanceof BaseTextEditor) {
const control = panel.getControl();
if (isCodeEditor(control)) {
return control;
}
}
return undefined;
}
private _getActiveEditorFromEditorPart(): IEditor | undefined {
@@ -300,7 +303,7 @@ export class MainThreadDocumentsAndEditors {
@ITextModelService textModelResolverService: ITextModelService,
@IEditorGroupsService private readonly _editorGroupService: IEditorGroupsService,
@IBulkEditService bulkEditService: IBulkEditService,
@IPanelService panelService: IPanelService,
@IPaneCompositePartService paneCompositeService: IPaneCompositePartService,
@IWorkbenchEnvironmentService environmentService: IWorkbenchEnvironmentService,
@IWorkingCopyFileService workingCopyFileService: IWorkingCopyFileService,
@IUriIdentityService uriIdentityService: IUriIdentityService,
@@ -317,7 +320,7 @@ export class MainThreadDocumentsAndEditors {
extHostContext.set(MainContext.MainThreadTextEditors, mainThreadTextEditors);
// It is expected that the ctor of the state computer calls our `_onDelta`.
this._toDispose.add(new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, panelService));
this._toDispose.add(new MainThreadDocumentAndEditorStateComputer(delta => this._onDelta(delta), _modelService, codeEditorService, this._editorService, paneCompositeService));
this._toDispose.add(this._onTextEditorAdd);
this._toDispose.add(this._onTextEditorRemove);
@@ -403,7 +406,7 @@ export class MainThreadDocumentsAndEditors {
versionId: model.getVersionId(),
lines: model.getLinesContent(),
EOL: model.getEOL(),
modeId: model.getLanguageIdentifier().language,
languageId: model.getLanguageId(),
isDirty: this._textFileService.isDirty(model.uri),
notebookUri: notebookUri
};

View File

@@ -349,7 +349,7 @@ export class MainThreadTextEditor {
}
private _setIndentConfiguration(newConfiguration: ITextEditorConfigurationUpdate): void {
const creationOpts = this._modelService.getCreationOptions(this._model.getLanguageIdentifier().language, this._model.uri, this._model.isForSimpleWidget);
const creationOpts = this._modelService.getCreationOptions(this._model.getLanguageId(), this._model.uri, this._model.isForSimpleWidget);
if (newConfiguration.tabSize === 'auto' || newConfiguration.insertSpaces === 'auto') {
// one of the options was set to 'auto' => detect indentation

View File

@@ -3,27 +3,26 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { URI } from 'vs/base/common/uri';
import { ExtHostContext, IExtHostEditorTabsShape, IExtHostContext, MainContext, IEditorTabDto } from 'vs/workbench/api/common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { EditorResourceAccessor, Verbosity } from 'vs/workbench/common/editor';
import { GroupChangeKind, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { EditorResourceAccessor, IUntypedEditorInput, SideBySideEditor } from 'vs/workbench/common/editor';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { SideBySideEditorInput } from 'vs/workbench/common/editor/sideBySideEditorInput';
import { columnToEditorGroup, EditorGroupColumn, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { GroupChangeKind, GroupDirection, IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorsChangeEvent, IEditorService } from 'vs/workbench/services/editor/common/editorService';
export interface ITabInfo {
name: string;
resource: URI;
}
@extHostNamedCustomer(MainContext.MainThreadEditorTabs)
export class MainThreadEditorTabs {
private static _GroupEventFilter = new Set([GroupChangeKind.EDITOR_CLOSE, GroupChangeKind.EDITOR_OPEN]);
private readonly _dispoables = new DisposableStore();
private readonly _groups = new Map<IEditorGroup, IDisposable>();
private readonly _proxy: IExtHostEditorTabsShape;
private readonly _tabModel: Map<number, IEditorTabDto[]> = new Map<number, IEditorTabDto[]>();
private _currentlyActiveTab: { groupId: number, tab: IEditorTabDto } | undefined = undefined;
constructor(
extHostContext: IExtHostContext,
@@ -33,51 +32,255 @@ export class MainThreadEditorTabs {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostEditorTabs);
this._editorGroupsService.whenReady.then(() => this._editorGroupsService.groups.forEach(this._subscribeToGroup, this));
this._dispoables.add(_editorGroupsService.onDidAddGroup(this._subscribeToGroup, this));
this._dispoables.add(_editorGroupsService.onDidRemoveGroup(e => {
const subscription = this._groups.get(e);
if (subscription) {
subscription.dispose();
this._groups.delete(e);
this._pushEditorTabs();
}
}));
this._dispoables.add(editorService.onDidActiveEditorChange(this._pushEditorTabs, this));
this._pushEditorTabs();
// Queue all events that arrive on the same event loop and then send them as a batch
this._dispoables.add(editorService.onDidEditorsChange((events) => this._updateTabsModel(events)));
this._editorGroupsService.whenReady.then(() => this._createTabsModel());
}
dispose(): void {
dispose(this._groups.values());
this._dispoables.dispose();
}
private _subscribeToGroup(group: IEditorGroup) {
this._groups.get(group)?.dispose();
const listener = group.onDidGroupChange(e => {
if (MainThreadEditorTabs._GroupEventFilter.has(e.kind)) {
this._pushEditorTabs();
}
});
this._groups.set(group, listener);
/**
* Creates a tab object with the correct properties
* @param editor The editor input represented by the tab
* @param group The group the tab is in
* @returns A tab object
*/
private _buildTabObject(editor: EditorInput, group: IEditorGroup): IEditorTabDto {
// Even though the id isn't a diff / sideBySide on the main side we need to let the ext host know what type of editor it is
const editorId = editor instanceof DiffEditorInput ? 'diff' : editor instanceof SideBySideEditorInput ? 'sideBySide' : editor.editorId;
const tab: IEditorTabDto = {
viewColumn: editorGroupToColumn(this._editorGroupsService, group),
label: editor.getName(),
resource: editor instanceof SideBySideEditorInput ? EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.PRIMARY }) : EditorResourceAccessor.getCanonicalUri(editor),
editorId,
additionalResourcesAndViewIds: [],
isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor)
};
tab.additionalResourcesAndViewIds.push({ resource: tab.resource, viewId: tab.editorId });
if (editor instanceof SideBySideEditorInput) {
tab.additionalResourcesAndViewIds.push({ resource: EditorResourceAccessor.getCanonicalUri(editor, { supportSideBySide: SideBySideEditor.SECONDARY }), viewId: editor.primary.editorId ?? editor.editorId });
}
return tab;
}
private _pushEditorTabs(): void {
const tabs: IEditorTabDto[] = [];
private _tabToUntypedEditorInput(tab: IEditorTabDto): IUntypedEditorInput {
if (tab.editorId !== 'diff' && tab.editorId !== 'sideBySide') {
return { resource: URI.revive(tab.resource), options: { override: tab.editorId } };
} else if (tab.editorId === 'sideBySide') {
return {
primary: { resource: URI.revive(tab.resource), options: { override: tab.editorId } },
secondary: { resource: URI.revive(tab.additionalResourcesAndViewIds[1].resource), options: { override: tab.additionalResourcesAndViewIds[1].viewId } }
};
} else {
return {
modified: { resource: URI.revive(tab.resource), options: { override: tab.editorId } },
original: { resource: URI.revive(tab.additionalResourcesAndViewIds[1].resource), options: { override: tab.additionalResourcesAndViewIds[1].viewId } }
};
}
}
/**
* Builds the model from scratch based on the current state of the editor service.
*/
private _createTabsModel(): void {
this._tabModel.clear();
let tabs: IEditorTabDto[] = [];
for (const group of this._editorGroupsService.groups) {
for (const editor of group.editors) {
if (editor.isDisposed() || !editor.resource) {
if (editor.isDisposed()) {
continue;
}
tabs.push({
group: group.id,
name: editor.getTitle(Verbosity.SHORT) ?? '',
resource: EditorResourceAccessor.getOriginalUri(editor) ?? editor.resource,
isActive: (this._editorGroupsService.activeGroup === group) && group.isActive(editor)
});
const tab = this._buildTabObject(editor, group);
if (tab.isActive) {
this._currentlyActiveTab = { groupId: group.id, tab };
}
tabs.push(tab);
}
this._tabModel.set(group.id, tabs);
}
this._proxy.$acceptEditorTabs(tabs);
}
private _onDidTabOpen(event: IEditorsChangeEvent): void {
if (event.kind !== GroupChangeKind.EDITOR_OPEN || !event.editor || event.editorIndex === undefined) {
return;
}
if (!this._tabModel.has(event.groupId)) {
this._tabModel.set(event.groupId, []);
}
const editor = event.editor;
const tab = this._buildTabObject(editor, this._editorGroupsService.getGroup(event.groupId) ?? this._editorGroupsService.activeGroup);
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 0, tab);
// Update the currently active tab which may or may not be the opened one
if (tab.isActive) {
if (this._currentlyActiveTab) {
this._currentlyActiveTab.tab.isActive = (this._editorGroupsService.activeGroup.id === this._currentlyActiveTab.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(this._currentlyActiveTab.tab));
}
this._currentlyActiveTab = { groupId: event.groupId, tab };
}
}
private _onDidTabClose(event: IEditorsChangeEvent): void {
if (event.kind !== GroupChangeKind.EDITOR_CLOSE || event.editorIndex === undefined) {
return;
}
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 1);
this._findAndUpdateActiveTab();
// Remove any empty groups
if (this._tabModel.get(event.groupId)?.length === 0) {
this._tabModel.delete(event.groupId);
}
}
private _onDidTabMove(event: IEditorsChangeEvent): void {
if (event.kind !== GroupChangeKind.EDITOR_MOVE || event.editorIndex === undefined || event.oldEditorIndex === undefined) {
return;
}
const movedTab = this._tabModel.get(event.groupId)?.splice(event.oldEditorIndex, 1);
if (movedTab === undefined) {
return;
}
this._tabModel.get(event.groupId)?.splice(event.editorIndex, 0, movedTab[0]);
movedTab[0].isActive = (this._editorGroupsService.activeGroup.id === event.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(movedTab[0]));
// Update the currently active tab
if (movedTab[0].isActive) {
if (this._currentlyActiveTab) {
this._currentlyActiveTab.tab.isActive = (this._editorGroupsService.activeGroup.id === this._currentlyActiveTab.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(this._currentlyActiveTab.tab));
}
this._currentlyActiveTab = { groupId: event.groupId, tab: movedTab[0] };
}
}
private _onDidGroupActivate(event: IEditorsChangeEvent): void {
if (event.kind !== GroupChangeKind.GROUP_INDEX && event.kind !== GroupChangeKind.EDITOR_ACTIVE) {
return;
}
this._findAndUpdateActiveTab();
}
/**
* Updates the currently active tab so that `this._currentlyActiveTab` is up to date.
*/
private _findAndUpdateActiveTab() {
// Go to the active group and update the active tab
const activeGroupId = this._editorGroupsService.activeGroup.id;
this._tabModel.get(activeGroupId)?.forEach(t => {
if (t.resource) {
t.isActive = this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(t));
}
if (t.isActive) {
if (this._currentlyActiveTab) {
this._currentlyActiveTab.tab.isActive = (this._editorGroupsService.activeGroup.id === this._currentlyActiveTab.groupId) && this._editorGroupsService.activeGroup.isActive(this._tabToUntypedEditorInput(this._currentlyActiveTab.tab));
}
this._currentlyActiveTab = { groupId: activeGroupId, tab: t };
return;
}
}, this);
}
// TODOD @lramos15 Remove this after done finishing the tab model code
// private _eventArrayToString(events: IEditorsChangeEvent[]): void {
// let eventString = '[';
// events.forEach(event => {
// switch (event.kind) {
// case GroupChangeKind.GROUP_INDEX: eventString += 'GROUP_INDEX, '; break;
// case GroupChangeKind.EDITOR_ACTIVE: eventString += 'EDITOR_ACTIVE, '; break;
// case GroupChangeKind.EDITOR_PIN: eventString += 'EDITOR_PIN, '; break;
// case GroupChangeKind.EDITOR_OPEN: eventString += 'EDITOR_OPEN, '; break;
// case GroupChangeKind.EDITOR_CLOSE: eventString += 'EDITOR_CLOSE, '; break;
// case GroupChangeKind.EDITOR_MOVE: eventString += 'EDITOR_MOVE, '; break;
// case GroupChangeKind.EDITOR_LABEL: eventString += 'EDITOR_LABEL, '; break;
// case GroupChangeKind.GROUP_ACTIVE: eventString += 'GROUP_ACTIVE, '; break;
// case GroupChangeKind.GROUP_LOCKED: eventString += 'GROUP_LOCKED, '; break;
// default: eventString += 'UNKNOWN, '; break;
// }
// });
// eventString += ']';
// console.log(eventString);
// }
/**
* The main handler for the tab events
* @param events The list of events to process
*/
private _updateTabsModel(events: IEditorsChangeEvent[]): void {
events.forEach(event => {
// Call the correct function for the change type
switch (event.kind) {
case GroupChangeKind.EDITOR_OPEN:
this._onDidTabOpen(event);
break;
case GroupChangeKind.EDITOR_CLOSE:
this._onDidTabClose(event);
break;
case GroupChangeKind.EDITOR_ACTIVE:
case GroupChangeKind.GROUP_ACTIVE:
if (this._editorGroupsService.activeGroup.id !== event.groupId) {
return;
}
this._onDidGroupActivate(event);
break;
case GroupChangeKind.GROUP_INDEX:
this._createTabsModel();
// Here we stop the loop as no need to process other events
break;
case GroupChangeKind.EDITOR_MOVE:
this._onDidTabMove(event);
break;
default:
break;
}
});
// Flatten the map into a singular array to send the ext host
let allTabs: IEditorTabDto[] = [];
this._tabModel.forEach((tabs) => allTabs = allTabs.concat(tabs));
this._proxy.$acceptEditorTabs(allTabs);
}
//#region Messages received from Ext Host
$moveTab(tab: IEditorTabDto, index: number, viewColumn: EditorGroupColumn): void {
const groupId = columnToEditorGroup(this._editorGroupsService, viewColumn);
let targetGroup: IEditorGroup | undefined;
const sourceGroup = this._editorGroupsService.getGroup(columnToEditorGroup(this._editorGroupsService, tab.viewColumn));
if (!sourceGroup) {
return;
}
// If group index is out of bounds then we make a new one that's to the right of the last group
if (this._tabModel.get(groupId) === undefined) {
targetGroup = this._editorGroupsService.addGroup(this._editorGroupsService.groups[this._editorGroupsService.groups.length - 1], GroupDirection.RIGHT, undefined);
} else {
targetGroup = this._editorGroupsService.getGroup(groupId);
}
if (!targetGroup) {
return;
}
// Similar logic to if index is out of bounds we place it at the end
if (index < 0 || index > targetGroup.editors.length) {
index = targetGroup.editors.length;
}
// Find the correct EditorInput using the tab info
const editorInput = sourceGroup.editors.find(editor => editor.matches(this._tabToUntypedEditorInput(tab)));
if (!editorInput) {
return;
}
// Move the editor to the target group
sourceGroup.moveEditor(editorInput, targetGroup, { index, preserveFocus: true });
}
async $closeTab(tab: IEditorTabDto): Promise<void> {
const group = this._editorGroupsService.getGroup(columnToEditorGroup(this._editorGroupsService, tab.viewColumn));
if (!group) {
return;
}
const editor = group.editors.find(editor => editor.matches(this._tabToUntypedEditorInput(tab)));
if (!editor) {
return;
}
return group.closeEditor(editor);
}
//#endregion
}

View File

@@ -6,7 +6,7 @@
import { Emitter, Event } from 'vs/base/common/event';
import { IDisposable, dispose, toDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { URI, UriComponents } from 'vs/base/common/uri';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission } from 'vs/platform/files/common/files';
import { FileWriteOptions, FileSystemProviderCapabilities, IFileChange, IFileService, IStat, IWatchOptions, FileType, FileOverwriteOptions, FileDeleteOptions, FileOpenOptions, IFileStat, FileOperationError, FileOperationResult, FileSystemProviderErrorCode, IFileSystemProviderWithOpenReadWriteCloseCapability, IFileSystemProviderWithFileReadWriteCapability, IFileSystemProviderWithFileFolderCopyCapability, FilePermission, toFileSystemProviderErrorCode } from 'vs/platform/files/common/files';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ExtHostContext, ExtHostFileSystemShape, IExtHostContext, IFileChangeDto, MainContext, MainThreadFileSystemShape } from '../common/extHost.protocol';
import { VSBuffer } from 'vs/base/common/buffer';
@@ -65,7 +65,7 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
ctime: stat.ctime,
mtime: stat.mtime,
size: stat.size,
permissions: MainThreadFileSystem._asFilePermission(stat),
permissions: stat.readonly ? FilePermission.Readonly : undefined,
type: MainThreadFileSystem._asFileType(stat)
};
}).catch(MainThreadFileSystem._handleError);
@@ -96,13 +96,6 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
return res;
}
private static _asFilePermission(stat: IFileStat): FilePermission | undefined {
if (stat.readonly) {
return FilePermission.Readonly;
}
return undefined;
}
$readFile(uri: UriComponents): Promise<VSBuffer> {
return this._fileService.readFile(URI.revive(uri)).then(file => file.value).catch(MainThreadFileSystem._handleError);
}
@@ -147,6 +140,11 @@ export class MainThreadFileSystem implements MainThreadFileSystemShape {
err.name = FileSystemProviderErrorCode.FileExists;
break;
}
} else if (err instanceof Error) {
const code = toFileSystemProviderErrorCode(err);
if (code !== FileSystemProviderErrorCode.Unknown) {
err.name = code;
}
}
throw err;

View File

@@ -89,7 +89,7 @@ export class MainThreadFileSystemEventService {
delay: Math.min(timeout / 2, 3000)
}, () => {
// race extension host event delivery against timeout AND user-cancel
const onWillEvent = proxy.$onWillRunFileOperation(operation, files, timeout, token);
const onWillEvent = proxy.$onWillRunFileOperation(operation, files, timeout, cts.token);
return raceCancellation(onWillEvent, cts.token);
}, () => {
// user-cancel
@@ -100,8 +100,8 @@ export class MainThreadFileSystemEventService {
clearTimeout(timer);
});
if (!data) {
// cancelled or no reply
if (!data || data.edit.edits.length === 0) {
// cancelled, no reply, or no edits
return;
}

View File

@@ -43,12 +43,8 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
const langWordPairs = LanguageConfigurationRegistry.getWordDefinitions();
let wordDefinitionDtos: ILanguageWordDefinitionDto[] = [];
for (const [languageId, wordDefinition] of langWordPairs) {
const language = this._modeService.getLanguageIdentifier(languageId);
if (!language) {
continue;
}
wordDefinitionDtos.push({
languageId: language.language,
languageId: languageId,
regexSource: wordDefinition.source,
regexFlags: wordDefinition.flags
});
@@ -56,9 +52,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
this._proxy.$setWordDefinitions(wordDefinitionDtos);
};
LanguageConfigurationRegistry.onDidChange((e) => {
const wordDefinition = LanguageConfigurationRegistry.getWordDefinition(e.languageIdentifier.id);
const wordDefinition = LanguageConfigurationRegistry.getWordDefinition(e.languageId);
this._proxy.$setWordDefinitions([{
languageId: e.languageIdentifier.language,
languageId: e.languageId,
regexSource: wordDefinition.source,
regexFlags: wordDefinition.flags
}]);
@@ -567,10 +563,10 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
this._registrations.set(handle, modes.InlayHintsProviderRegistry.register(selector, provider));
}
$emitInlayHintsEvent(eventHandle: number, event?: any): void {
$emitInlayHintsEvent(eventHandle: number): void {
const obj = this._registrations.get(eventHandle);
if (obj instanceof Emitter) {
obj.fire(event);
obj.fire(undefined);
}
}
@@ -776,9 +772,9 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
};
}
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (languageIdentifier) {
this._registrations.set(handle, LanguageConfigurationRegistry.register(languageIdentifier, configuration, 100));
const validLanguageId = this._modeService.validateLanguageId(languageId);
if (validLanguageId) {
this._registrations.set(handle, LanguageConfigurationRegistry.register(validLanguageId, configuration, 100));
}
}

View File

@@ -6,38 +6,51 @@
import { URI, UriComponents } from 'vs/base/common/uri';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IModelService } from 'vs/editor/common/services/modelService';
import { MainThreadLanguagesShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { MainThreadLanguagesShape, MainContext, IExtHostContext, ExtHostContext, ExtHostLanguagesShape } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IPosition } from 'vs/editor/common/core/position';
import { IRange, Range } from 'vs/editor/common/core/range';
import { StandardTokenType } from 'vs/editor/common/modes';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { ILanguageStatus, ILanguageStatusService } from 'vs/workbench/services/languageStatus/common/languageStatusService';
import { IDisposable } from 'vs/base/common/lifecycle';
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
@extHostNamedCustomer(MainContext.MainThreadLanguages)
export class MainThreadLanguages implements MainThreadLanguagesShape {
private readonly _disposables = new DisposableStore();
private readonly _proxy: ExtHostLanguagesShape;
private readonly _status = new Map<number, IDisposable>();
constructor(
_extHostContext: IExtHostContext,
@IModeService private readonly _modeService: IModeService,
@IModelService private readonly _modelService: IModelService,
@ITextModelService private _resolverService: ITextModelService,
@ILanguageStatusService private readonly _languageStatusService: ILanguageStatusService,
) { }
) {
this._proxy = _extHostContext.getProxy(ExtHostContext.ExtHostLanguages);
dispose(): void {
// nothing
this._proxy.$acceptLanguageIds(_modeService.getRegisteredModes());
this._disposables.add(_modeService.onLanguagesMaybeChanged(e => {
this._proxy.$acceptLanguageIds(_modeService.getRegisteredModes());
}));
}
$getLanguages(): Promise<string[]> {
return Promise.resolve(this._modeService.getRegisteredModes());
dispose(): void {
this._disposables.dispose();
for (const status of this._status.values()) {
status.dispose();
}
this._status.clear();
}
async $changeLanguage(resource: UriComponents, languageId: string): Promise<void> {
const languageIdentifier = this._modeService.getLanguageIdentifier(languageId);
if (!languageIdentifier || languageIdentifier.language !== languageId) {
const validLanguageId = this._modeService.validateLanguageId(languageId);
if (!validLanguageId || validLanguageId !== languageId) {
return Promise.reject(new Error(`Unknown language id: ${languageId}`));
}
@@ -67,8 +80,6 @@ export class MainThreadLanguages implements MainThreadLanguagesShape {
// --- language status
private readonly _status = new Map<number, IDisposable>();
$setLanguageStatus(handle: number, status: ILanguageStatus): void {
this._status.get(handle)?.dispose();
this._status.set(handle, this._languageStatusService.addStatus(status));

View File

@@ -12,12 +12,10 @@ import { INotebookDecorationRenderOptions } from 'vs/workbench/contrib/notebook/
import { ICellRange } from 'vs/workbench/contrib/notebook/common/notebookRange';
import { ILogService } from 'vs/platform/log/common/log';
import { URI, UriComponents } from 'vs/base/common/uri';
import { EditorActivation, EditorResolution } from 'vs/platform/editor/common/editor';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/common/notebookEditorInput';
import { EditorActivation } from 'vs/platform/editor/common/editor';
import { IEditorService } from 'vs/workbench/services/editor/common/editorService';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { columnToEditorGroup, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { equals } from 'vs/base/common/objects';
import { NotebookDto } from 'vs/workbench/api/browser/mainThreadNotebookDto';
@@ -45,7 +43,6 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
constructor(
extHostContext: IExtHostContext,
notebooksAndEditors: MainThreadNotebooksAndEditors,
@IInstantiationService private readonly _instantiationService: IInstantiationService,
@IEditorService private readonly _editorService: IEditorService,
@ILogService private readonly _logService: ILogService,
@INotebookEditorService private readonly _notebookEditorService: INotebookEditorService,
@@ -131,11 +128,10 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
// preserve pre 1.38 behaviour to not make group active when preserveFocus: true
// but make sure to restore the editor to fix https://github.com/microsoft/vscode/issues/79633
activation: options.preserveFocus ? EditorActivation.RESTORE : undefined,
override: EditorResolution.DISABLED
override: viewType
};
const input = NotebookEditorInput.create(this._instantiationService, URI.revive(resource), viewType);
const editorPane = await this._editorService.openEditor(input, editorOptions, options.position);
const editorPane = await this._editorService.openEditor({ resource: URI.revive(resource), options: editorOptions }, columnToEditorGroup(this._editorGroupService, options.position));
const notebookEditor = getNotebookEditorFromEditorPane(editorPane);
if (notebookEditor) {
@@ -154,12 +150,13 @@ export class MainThreadNotebookEditors implements MainThreadNotebookEditorsShape
if (!notebookEditor.hasModel()) {
return;
}
const viewModel = notebookEditor.viewModel;
const cell = viewModel.cellAt(range.start);
if (!cell) {
if (range.start >= notebookEditor.getLength()) {
return;
}
const cell = notebookEditor.cellAt(range.start);
switch (revealType) {
case NotebookEditorRevealType.Default:
return notebookEditor.revealCellRangeInView(range);

View File

@@ -33,6 +33,7 @@ abstract class MainThreadKernel implements INotebookKernel {
label: string;
description?: string;
detail?: string;
kind?: string;
supportedLanguages: string[];
implementsExecutionOrder: boolean;
localResourceRoot: URI;
@@ -54,6 +55,7 @@ abstract class MainThreadKernel implements INotebookKernel {
this.label = data.label;
this.description = data.description;
this.detail = data.detail;
this.kind = data.kind;
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : _modeService.getRegisteredModes();
this.implementsExecutionOrder = data.supportsExecutionOrder ?? false;
this.localResourceRoot = URI.revive(data.extensionLocation);
@@ -76,6 +78,10 @@ abstract class MainThreadKernel implements INotebookKernel {
this.detail = data.detail;
event.detail = true;
}
if (data.kind !== undefined) {
this.kind = data.kind;
event.kind = true;
}
if (data.supportedLanguages !== undefined) {
this.supportedLanguages = isNonEmptyArray(data.supportedLanguages) ? data.supportedLanguages : this._modeService.getRegisteredModes();
event.supportedLanguages = true;

View File

@@ -40,7 +40,7 @@ export class MainThreadProgress implements MainThreadProgressShape {
this._progress.clear();
}
$startProgress(handle: number, options: IProgressOptions, extension?: IExtensionDescription): void {
async $startProgress(handle: number, options: IProgressOptions, extension?: IExtensionDescription): Promise<void> {
const task = this._createTask(handle);
if (options.location === ProgressLocation.Notification && extension && !extension.isUnderDevelopment) {

View File

@@ -120,6 +120,7 @@ class MainThreadSCMProvider implements ISCMProvider {
get commitTemplate(): string { return this.features.commitTemplate || ''; }
get acceptInputCommand(): Command | undefined { return this.features.acceptInputCommand; }
get actionButton(): Command | undefined { return this.features.actionButton ?? undefined; }
get statusBarCommands(): Command[] | undefined { return this.features.statusBarCommands; }
get count(): number | undefined { return this.features.count; }

View File

@@ -9,7 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IFileMatch, IFileQuery, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchProgressItem, ISearchResultProvider, ISearchService, ITextQuery, QueryType, SearchProviderType } from 'vs/workbench/services/search/common/search';
import { IFileMatch, IFileQuery, IRawFileMatch2, ISearchComplete, ISearchCompleteStats, ISearchConfiguration, ISearchProgressItem, ISearchResultProvider, ISearchService, ITextQuery, QueryType, SearchProviderType } from 'vs/workbench/services/search/common/search';
import { ExtHostContext, ExtHostSearchShape, IExtHostContext, MainContext, MainThreadSearchShape } from '../common/extHost.protocol';
@extHostNamedCustomer(MainContext.MainThreadSearch)
@@ -26,8 +26,8 @@ export class MainThreadSearch implements MainThreadSearchShape {
) {
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostSearch);
const forceEHSearch = _configurationService.getValue('search.experimental.forceExtensionHostSearch');
if (forceEHSearch) {
const searchConfig = _configurationService.getValue<ISearchConfiguration>().search;
if (!searchConfig.forceSearchProcess) {
this._proxy.$enableExtensionHostSearch();
}
}

View File

@@ -3,7 +3,7 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry } from 'vs/workbench/services/statusbar/common/statusbar';
import { IStatusbarService, StatusbarAlignment as MainThreadStatusBarAlignment, IStatusbarEntryAccessor, IStatusbarEntry, StatusbarAlignment } from 'vs/workbench/services/statusbar/browser/statusbar';
import { MainThreadStatusBarShape, MainContext, IExtHostContext } from '../common/extHost.protocol';
import { ThemeColor } from 'vs/platform/theme/common/themeService';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
@@ -28,7 +28,7 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
this.entries.clear();
}
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignment: MainThreadStatusBarAlignment, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
$setEntry(entryId: number, id: string, name: string, text: string, tooltip: IMarkdownString | string | undefined, command: Command | undefined, color: string | ThemeColor | undefined, backgroundColor: string | ThemeColor | undefined, alignLeft: boolean, priority: number | undefined, accessibilityInformation: IAccessibilityInformation): void {
// if there are icons in the text use the tooltip for the aria label
let ariaLabel: string;
let role: string | undefined = undefined;
@@ -48,6 +48,8 @@ export class MainThreadStatusBar implements MainThreadStatusBarShape {
priority = 0;
}
const alignment = alignLeft ? StatusbarAlignment.LEFT : StatusbarAlignment.RIGHT;
// Reset existing entry if alignment or priority changed
let existingEntry = this.entries.get(entryId);
if (existingEntry && (existingEntry.alignment !== alignment || existingEntry.priority !== priority)) {

View File

@@ -8,6 +8,7 @@ import { MainThreadStorageShape, MainContext, IExtHostContext, ExtHostStorageSha
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { IDisposable } from 'vs/base/common/lifecycle';
import { IExtensionIdWithVersion, IExtensionsStorageSyncService } from 'vs/platform/userDataSync/common/extensionsStorageSync';
import { ILogService } from 'vs/platform/log/common/log';
@extHostNamedCustomer(MainContext.MainThreadStorage)
export class MainThreadStorage implements MainThreadStorageShape {
@@ -22,6 +23,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
extHostContext: IExtHostContext,
@IStorageService storageService: IStorageService,
@IExtensionsStorageSyncService extensionsStorageSyncService: IExtensionsStorageSyncService,
@ILogService private readonly _logService: ILogService
) {
this._storageService = storageService;
this._extensionsStorageSyncService = extensionsStorageSyncService;
@@ -30,11 +32,7 @@ export class MainThreadStorage implements MainThreadStorageShape {
this._storageListener = this._storageService.onDidChangeValue(e => {
const shared = e.scope === StorageScope.GLOBAL;
if (shared && this._sharedStorageKeysToWatch.has(e.key)) {
try {
this._proxy.$acceptValue(shared, e.key, this._getValue(shared, e.key));
} catch (error) {
// ignore parsing errors that can happen
}
this._proxy.$acceptValue(shared, e.key, this._getValue(shared, e.key));
}
});
}
@@ -43,35 +41,30 @@ export class MainThreadStorage implements MainThreadStorageShape {
this._storageListener.dispose();
}
$getValue<T>(shared: boolean, key: string): Promise<T | undefined> {
async $getValue<T>(shared: boolean, key: string): Promise<T | undefined> {
if (shared) {
this._sharedStorageKeysToWatch.set(key, true);
}
try {
return Promise.resolve(this._getValue<T>(shared, key));
} catch (error) {
return Promise.reject(error);
}
return this._getValue<T>(shared, key);
}
private _getValue<T>(shared: boolean, key: string): T | undefined {
const jsonValue = this._storageService.get(key, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE);
if (!jsonValue) {
return undefined;
if (jsonValue) {
try {
return JSON.parse(jsonValue);
} catch (error) {
// Do not fail this call but log it for diagnostics
// https://github.com/microsoft/vscode/issues/132777
this._logService.error(`[mainThreadStorage] unexpected error parsing storage contents (key: ${key}, shared: ${shared}): ${error}`);
}
}
return JSON.parse(jsonValue);
return undefined;
}
$setValue(shared: boolean, key: string, value: object): Promise<void> {
let jsonValue: string;
try {
jsonValue = JSON.stringify(value);
// Extension state is synced separately through extensions
this._storageService.store(key, jsonValue, shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE);
} catch (err) {
return Promise.reject(err);
}
return Promise.resolve(undefined);
async $setValue(shared: boolean, key: string, value: object): Promise<void> {
this._storageService.store(key, JSON.stringify(value), shared ? StorageScope.GLOBAL : StorageScope.WORKSPACE, StorageTarget.MACHINE /* Extension state is synced separately through extensions */);
}
$registerExtensionStorageKeysToSync(extension: IExtensionIdWithVersion, keys: string[]): void {

View File

@@ -3,13 +3,15 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { ITelemetryService, TelemetryLevel, TELEMETRY_OLD_SETTING_ID, TELEMETRY_SETTING_ID } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadTelemetryShape, MainContext, IExtHostContext, ExtHostTelemetryShape, ExtHostContext } from '../common/extHost.protocol';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { ClassifiedEvent, StrictPropertyCheck, GDPRClassification } from 'vs/platform/telemetry/common/gdprTypings';
import { Disposable } from 'vs/base/common/lifecycle';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IProductService } from 'vs/platform/product/common/productService';
import { getTelemetryLevel, supportsTelemetry } from 'vs/platform/telemetry/common/telemetryUtils';
@extHostNamedCustomer(MainContext.MainThreadTelemetry)
export class MainThreadTelemetry extends Disposable implements MainThreadTelemetryShape {
@@ -17,20 +19,29 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet
private static readonly _name = 'pluginHostTelemetry';
private _oldTelemetryEnabledValue: boolean | undefined;
constructor(
extHostContext: IExtHostContext,
@ITelemetryService private readonly _telemetryService: ITelemetryService,
@IConfigurationService private readonly _configurationService: IConfigurationService,
@IEnvironmentService private readonly _environmenService: IEnvironmentService,
@IProductService private readonly _productService: IProductService
) {
super();
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostTelemetry);
if (!this._environmenService.disableTelemetry) {
if (supportsTelemetry(this._productService, this._environmenService)) {
this._register(this._configurationService.onDidChangeConfiguration(e => {
if (e.affectedKeys.includes('telemetry.enableTelemetry')) {
this._proxy.$onDidChangeTelemetryEnabled(this.telemetryEnabled);
if (e.affectsConfiguration(TELEMETRY_SETTING_ID) || e.affectsConfiguration(TELEMETRY_OLD_SETTING_ID)) {
const telemetryEnabled = this.telemetryEnabled;
// Since changing telemetryLevel from "off" => "error" doesn't change the isEnabled state
// We shouldn't fire a change event
if (telemetryEnabled !== this._oldTelemetryEnabledValue) {
this._oldTelemetryEnabledValue = telemetryEnabled;
this._proxy.$onDidChangeTelemetryEnabled(this.telemetryEnabled);
}
}
}));
}
@@ -39,11 +50,11 @@ export class MainThreadTelemetry extends Disposable implements MainThreadTelemet
}
private get telemetryEnabled(): boolean {
if (this._environmenService.disableTelemetry) {
if (!supportsTelemetry(this._productService, this._environmenService)) {
return false;
}
return !!this._configurationService.getValue('telemetry.enableTelemetry');
return getTelemetryLevel(this._configurationService) === TelemetryLevel.USAGE;
}
$publicLog(eventName: string, data: any = Object.create(null)): void {

View File

@@ -10,7 +10,7 @@ import { URI } from 'vs/base/common/uri';
import { StopWatch } from 'vs/base/common/stopwatch';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { ILogService } from 'vs/platform/log/common/log';
import { IShellLaunchConfig, IShellLaunchConfigDto, ITerminalDimensions, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal';
import { IProcessProperty, IShellLaunchConfig, IShellLaunchConfigDto, ProcessPropertyType, TerminalLocation, TitleEventSource } from 'vs/platform/terminal/common/terminal';
import { TerminalDataBufferer } from 'vs/platform/terminal/common/terminalDataBuffering';
import { ITerminalEditorService, ITerminalExternalLinkProvider, ITerminalGroupService, ITerminalInstance, ITerminalInstanceService, ITerminalLink, ITerminalService } from 'vs/workbench/contrib/terminal/browser/terminal';
import { TerminalProcessExtHostProxy } from 'vs/workbench/contrib/terminal/browser/terminalProcessExtHostProxy';
@@ -21,6 +21,7 @@ import { IRemoteAgentService } from 'vs/workbench/services/remote/common/remoteA
import { withNullAsUndefined } from 'vs/base/common/types';
import { OperatingSystem, OS } from 'vs/base/common/platform';
import { TerminalEditorLocationOptions } from 'vscode';
import { Promises } from 'vs/base/common/async';
@extHostNamedCustomer(MainContext.MainThreadTerminalService)
export class MainThreadTerminalService implements MainThreadTerminalServiceShape {
@@ -140,16 +141,20 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
isExtensionOwnedTerminal: launchConfig.isExtensionOwnedTerminal,
useShellEnvironment: launchConfig.useShellEnvironment,
};
this._extHostTerminals.set(extHostTerminalId, new Promise(async r => {
// eslint-disable-next-line no-async-promise-executor
const terminal = Promises.withAsyncBody<ITerminalInstance>(async r => {
const terminal = await this._terminalService.createTerminal({
config: shellLaunchConfig,
location: await this._deserializeParentTerminal(launchConfig.location)
});
r(terminal);
}));
});
this._extHostTerminals.set(extHostTerminalId, terminal);
await terminal;
}
private async _deserializeParentTerminal(location?: TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean }): Promise<TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ITerminalInstance } | { splitActiveTerminal: boolean } | undefined> {
private async _deserializeParentTerminal(location?: TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ExtHostTerminalIdentifier } | { splitActiveTerminal: boolean, location?: TerminalLocation }): Promise<TerminalLocation | TerminalEditorLocationOptions | { parentTerminal: ITerminalInstance } | { splitActiveTerminal: boolean } | undefined> {
if (typeof location === 'object' && 'parentTerminal' in location) {
const parentTerminal = await this._extHostTerminals.get(location.parentTerminal.toString());
return parentTerminal ? { parentTerminal } : undefined;
@@ -186,6 +191,10 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
await instance?.sendText(text, addNewLine);
}
public $sendProcessExit(terminalId: number, exitCode: number | undefined): void {
this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode);
}
public $startSendingDataEvents(): void {
if (!this._dataEventTracker) {
this._dataEventTracker = this._instantiationService.createInstance(TerminalDataEventTracker, (id, data) => {
@@ -298,18 +307,6 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
proxy.onRequestLatency(() => this._onRequestLatency(proxy.instanceId));
}
public $sendProcessTitle(terminalId: number, title: string): void {
// Since title events can only come from vscode.Pseudoterminals right now, these are routed
// directly to the instance as API source events such that they will replace the initial
// `name` property provided for the Pseudoterminal. If we support showing both Api and
// Process titles at the same time we may want to pass this through as a Process source
// event.
const instance = this._terminalService.getInstanceFromId(terminalId);
if (instance) {
instance.setTitle(title, TitleEventSource.Api);
}
}
public $sendProcessData(terminalId: number, data: string): void {
this._terminalProcessProxies.get(terminalId)?.emitData(data);
}
@@ -318,24 +315,14 @@ export class MainThreadTerminalService implements MainThreadTerminalServiceShape
this._terminalProcessProxies.get(terminalId)?.emitReady(pid, cwd);
}
public $sendProcessExit(terminalId: number, exitCode: number | undefined): void {
this._terminalProcessProxies.get(terminalId)?.emitExit(exitCode);
}
public $sendOverrideDimensions(terminalId: number, dimensions: ITerminalDimensions | undefined): void {
this._terminalProcessProxies.get(terminalId)?.emitOverrideDimensions(dimensions);
}
public $sendProcessInitialCwd(terminalId: number, initialCwd: string): void {
this._terminalProcessProxies.get(terminalId)?.emitInitialCwd(initialCwd);
}
public $sendProcessCwd(terminalId: number, cwd: string): void {
this._terminalProcessProxies.get(terminalId)?.emitCwd(cwd);
}
public $sendResolvedLaunchConfig(terminalId: number, shellLaunchConfig: IShellLaunchConfig): void {
this._getTerminalProcess(terminalId)?.emitResolvedShellLaunchConfig(shellLaunchConfig);
public $sendProcessProperty(terminalId: number, property: IProcessProperty<any>): void {
if (property.type === ProcessPropertyType.Title) {
const instance = this._terminalService.getInstanceFromId(terminalId);
if (instance) {
instance.refreshTabLabels(property.value, TitleEventSource.Api);
}
}
this._terminalProcessProxies.get(terminalId)?.emitProcessProperty(property);
}
private async _onRequestLatency(terminalId: number): Promise<void> {

View File

@@ -11,7 +11,7 @@ import { URI } from 'vs/base/common/uri';
import { Range } from 'vs/editor/common/core/range';
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
import { MutableObservableValue } from 'vs/workbench/contrib/testing/common/observableValue';
import { ExtensionRunTestsRequest, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, TestDiffOpType, TestResultState, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { ExtensionRunTestsRequest, ITestItem, ITestMessage, ITestRunProfile, ITestRunTask, ResolvedTestRunRequest, SerializedTestMessage, TestDiffOpType, TestResultState, TestsDiff } from 'vs/workbench/contrib/testing/common/testCollection';
import { ITestProfileService } from 'vs/workbench/contrib/testing/common/testProfileService';
import { TestCoverage } from 'vs/workbench/contrib/testing/common/testCoverage';
import { LiveTestResult } from 'vs/workbench/contrib/testing/common/testResult';
@@ -176,7 +176,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
/**
* @inheritdoc
*/
public $appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: ITestMessage[]): void {
public $appendTestMessagesInRun(runId: string, taskId: string, testId: string, messages: SerializedTestMessage[]): void {
const r = this.resultService.getResult(runId);
if (r && r instanceof LiveTestResult) {
for (const message of messages) {
@@ -185,7 +185,7 @@ export class MainThreadTesting extends Disposable implements MainThreadTestingSh
message.location.range = Range.lift(message.location.range);
}
r.appendMessage(testId, taskId, message);
r.appendMessage(testId, taskId, message as ITestMessage);
}
}
}

View File

@@ -177,6 +177,7 @@ export class MainThreadTunnelService extends Disposable implements MainThreadTun
localAddress: typeof tunnel.localAddress === 'string' ? tunnel.localAddress : makeAddress(tunnel.localAddress.host, tunnel.localAddress.port),
tunnelLocalPort: typeof tunnel.localAddress !== 'string' ? tunnel.localAddress.port : undefined,
public: tunnel.public,
privacy: tunnel.privacy,
protocol: tunnel.protocol ?? TunnelProtocol.Http,
dispose: async (silent?: boolean) => {
this.logService.trace(`ForwardedPorts: (MainThreadTunnelService) Closing tunnel from tunnel provider: ${tunnel?.remoteAddress.host}:${tunnel?.remoteAddress.port}`);

View File

@@ -9,7 +9,7 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { MainThreadWebviews, reviveWebviewContentOptions, reviveWebviewExtension } from 'vs/workbench/api/browser/mainThreadWebviews';
import * as extHostProtocol from 'vs/workbench/api/common/extHost.protocol';
import { IEditorInput } from 'vs/workbench/common/editor';
import { EditorInput } from 'vs/workbench/common/editor/editorInput';
import { EditorGroupColumn, columnToEditorGroup, editorGroupToColumn } from 'vs/workbench/services/editor/common/editorGroupColumn';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { WebviewOptions } from 'vs/workbench/contrib/webview/browser/webview';
@@ -263,14 +263,14 @@ export class MainThreadWebviewPanels extends Disposable implements extHostProtoc
this._revivers.delete(viewType);
}
private updateWebviewViewStates(activeEditorInput: IEditorInput | undefined) {
private updateWebviewViewStates(activeEditorInput: EditorInput | undefined) {
if (!this._webviewInputs.size) {
return;
}
const viewStates: extHostProtocol.WebviewPanelViewStateData = {};
const updateViewStatesForInput = (group: IEditorGroup, topLevelInput: IEditorInput, editorInput: IEditorInput) => {
const updateViewStatesForInput = (group: IEditorGroup, topLevelInput: EditorInput, editorInput: EditorInput) => {
if (!(editorInput instanceof WebviewInput)) {
return;
}

View File

@@ -129,6 +129,7 @@ export function reviveWebviewExtension(extensionData: extHostProtocol.WebviewExt
export function reviveWebviewContentOptions(webviewOptions: extHostProtocol.IWebviewOptions): WebviewContentOptions {
return {
allowScripts: webviewOptions.enableScripts,
allowForms: webviewOptions.enableForms,
enableCommandUris: webviewOptions.enableCommandUris,
localResourceRoots: Array.isArray(webviewOptions.localResourceRoots) ? webviewOptions.localResourceRoots.map(r => URI.revive(r)) : undefined,
portMapping: webviewOptions.portMapping,

View File

@@ -54,7 +54,7 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
const workspace = this._contextService.getWorkspace();
// The workspace file is provided be a unknown file system provider. It might come
// from the extension host. So initialize now knowing that `rootPath` is undefined.
if (workspace.configuration && !isNative && !fileService.canHandleResource(workspace.configuration)) {
if (workspace.configuration && !isNative && !fileService.hasProvider(workspace.configuration)) {
this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace), this.isWorkspaceTrusted());
} else {
this._contextService.getCompleteWorkspace().then(workspace => this._proxy.$initializeWorkspace(this.getWorkspaceData(workspace), this.isWorkspaceTrusted()));
@@ -129,7 +129,8 @@ export class MainThreadWorkspace implements MainThreadWorkspaceShape {
isUntitled: workspace.configuration ? isUntitledWorkspace(workspace.configuration, this._environmentService) : false,
folders: workspace.folders,
id: workspace.id,
name: this._labelService.getWorkspaceLabel(workspace)
name: this._labelService.getWorkspaceLabel(workspace),
transient: workspace.transient
};
}

View File

@@ -15,11 +15,11 @@ import { SyncDescriptor } from 'vs/platform/instantiation/common/descriptors';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { Registry } from 'vs/platform/registry/common/platform';
import { ThemeIcon } from 'vs/platform/theme/common/themeService';
import { Extensions as ViewletExtensions, PaneCompositeRegistry } from 'vs/workbench/browser/panecomposite';
import { CustomTreeView, TreeViewPane } from 'vs/workbench/browser/parts/views/treeView';
import { ViewPaneContainer } from 'vs/workbench/browser/parts/views/viewPaneContainer';
import { Extensions as ViewletExtensions, ViewletRegistry } from 'vs/workbench/browser/viewlet';
import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchContributionsRegistry } from 'vs/workbench/common/contributions';
import { Extensions as ViewContainerExtensions, ITreeViewDescriptor, IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { Extensions as ViewContainerExtensions, ICustomTreeViewDescriptor, ICustomViewDescriptor, IViewContainersRegistry, IViewDescriptor, IViewsRegistry, ViewContainer, ViewContainerLocation } from 'vs/workbench/common/views';
import { VIEWLET_ID as DEBUG } from 'vs/workbench/contrib/debug/common/debug';
import { VIEWLET_ID as EXPLORER } from 'vs/workbench/contrib/files/common/files';
import { VIEWLET_ID as REMOTE } from 'vs/workbench/contrib/remote/browser/remoteExplorer';
@@ -234,18 +234,6 @@ const viewsContribution: IJSONSchema = {
}
};
export interface ICustomTreeViewDescriptor extends ITreeViewDescriptor {
readonly extensionId: ExtensionIdentifier;
readonly originalContainerId: string;
}
export interface ICustomWebviewViewDescriptor extends IViewDescriptor {
readonly extensionId: ExtensionIdentifier;
readonly originalContainerId: string;
}
export type ICustomViewDescriptor = ICustomTreeViewDescriptor | ICustomWebviewViewDescriptor;
type ViewContainerExtensionPointType = { [loc: string]: IUserFriendlyViewsContainerDescriptor[] };
const viewsContainersExtensionPoint: IExtensionPoint<ViewContainerExtensionPointType> = ExtensionsRegistry.registerExtensionPoint<ViewContainerExtensionPointType>({
extensionPoint: 'viewsContainers',
@@ -398,7 +386,7 @@ class ViewsExtensionHandler implements IWorkbenchContribution {
private deregisterCustomViewContainer(viewContainer: ViewContainer): void {
this.viewContainersRegistry.deregisterViewContainer(viewContainer);
Registry.as<ViewletRegistry>(ViewletExtensions.Viewlets).deregisterViewlet(viewContainer.id);
Registry.as<PaneCompositeRegistry>(ViewletExtensions.Viewlets).deregisterPaneComposite(viewContainer.id);
}
private handleAndRegisterCustomViews() {