Merge from vscode fcf3346a8e9f5ee1e00674461d9e2c2292a14ee3 (#12295)

* Merge from vscode fcf3346a8e9f5ee1e00674461d9e2c2292a14ee3

* Fix test build break

* Update distro

* Fix build errors

* Update distro

* Update REH build file

* Update build task names for REL

* Fix product build yaml

* Fix product REH task name

* Fix type in task name

* Update linux build step

* Update windows build tasks

* Turn off server publish

* Disable REH

* Fix typo

* Bump distro

* Update vscode tests

* Bump distro

* Fix type in disto

* Bump distro

* Turn off docker build

* Remove docker step from release

Co-authored-by: ADS Merger <andresse@microsoft.com>
Co-authored-by: Karl Burtram <karlb@microsoft.com>
This commit is contained in:
Christopher Suh
2020-10-03 14:42:05 -04:00
committed by GitHub
parent 58d02b76db
commit 6ff1e3866b
687 changed files with 10507 additions and 9104 deletions

View File

@@ -67,7 +67,6 @@ import { ILogService } from 'vs/platform/log/common/log';
import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransformerService';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
import { find } from 'vs/base/common/arrays';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
@@ -80,6 +79,8 @@ import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileS
import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView';
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
import { ExtHostWebviewPanels } from 'vs/workbench/api/common/extHostWebviewPanels';
import { ExtHostBulkEdits } from 'vs/workbench/api/common/extHostBulkEdits';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
export interface IExtensionApiFactory {
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
@@ -92,6 +93,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// services
const initData = accessor.get(IExtHostInitDataService);
const extHostFileSystemInfo = accessor.get(IExtHostFileSystemInfo);
const extHostConsumerFileSystem = accessor.get(IExtHostConsumerFileSystem);
const extensionService = accessor.get(IExtHostExtensionService);
const extHostWorkspace = accessor.get(IExtHostWorkspace);
@@ -106,6 +108,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostWindow = accessor.get(IExtHostWindow);
// register addressable instances
rpcProtocol.set(ExtHostContext.ExtHostFileSystemInfo, extHostFileSystemInfo);
rpcProtocol.set(ExtHostContext.ExtHostLogService, <ExtHostLogServiceShape><any>extHostLogService);
rpcProtocol.set(ExtHostContext.ExtHostWorkspace, extHostWorkspace);
rpcProtocol.set(ExtHostContext.ExtHostConfiguration, extHostConfiguration);
@@ -128,14 +131,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
const extHostUrls = rpcProtocol.set(ExtHostContext.ExtHostUrls, new ExtHostUrls(rpcProtocol));
const extHostDocuments = rpcProtocol.set(ExtHostContext.ExtHostDocuments, new ExtHostDocuments(rpcProtocol, extHostDocumentsAndEditors));
const extHostDocumentContentProviders = rpcProtocol.set(ExtHostContext.ExtHostDocumentContentProviders, new ExtHostDocumentContentProvider(rpcProtocol, extHostDocumentsAndEditors, extHostLogService));
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadTextEditors)));
const extHostDocumentSaveParticipant = rpcProtocol.set(ExtHostContext.ExtHostDocumentSaveParticipant, new ExtHostDocumentSaveParticipant(extHostLogService, extHostDocuments, rpcProtocol.getProxy(MainContext.MainThreadBulkEdits)));
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService, extensionStoragePaths));
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors, extHostNotebook));
const extHostEditors = rpcProtocol.set(ExtHostContext.ExtHostEditors, new ExtHostEditors(rpcProtocol, extHostDocumentsAndEditors));
const extHostTreeViews = rpcProtocol.set(ExtHostContext.ExtHostTreeViews, new ExtHostTreeViews(rpcProtocol.getProxy(MainContext.MainThreadTreeViews), extHostCommands, extHostLogService));
const extHostEditorInsets = rpcProtocol.set(ExtHostContext.ExtHostEditorInsets, new ExtHostEditorInsets(rpcProtocol.getProxy(MainContext.MainThreadEditorInsets), extHostEditors, initData.environment));
const extHostDiagnostics = rpcProtocol.set(ExtHostContext.ExtHostDiagnostics, new ExtHostDiagnostics(rpcProtocol, extHostLogService));
const extHostLanguageFeatures = rpcProtocol.set(ExtHostContext.ExtHostLanguageFeatures, new ExtHostLanguageFeatures(rpcProtocol, uriTransformer, extHostDocuments, extHostCommands, extHostDiagnostics, extHostLogService, extHostApiDeprecation));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures));
const extHostFileSystem = rpcProtocol.set(ExtHostContext.ExtHostFileSystem, new ExtHostFileSystem(rpcProtocol, extHostLanguageFeatures, extHostFileSystemInfo));
const extHostFileSystemEvent = rpcProtocol.set(ExtHostContext.ExtHostFileSystemEventService, new ExtHostFileSystemEventService(rpcProtocol, extHostLogService, extHostDocumentsAndEditors));
const extHostQuickOpen = rpcProtocol.set(ExtHostContext.ExtHostQuickOpen, new ExtHostQuickOpen(rpcProtocol, extHostWorkspace, extHostCommands));
const extHostSCM = rpcProtocol.set(ExtHostContext.ExtHostSCM, new ExtHostSCM(rpcProtocol, extHostCommands, extHostLogService));
@@ -153,10 +156,11 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
// Check that no named customers are missing
// {{SQL CARBON EDIT}} filter out the services we don't expose
const filtered: ProxyIdentifier<any>[] = [ExtHostContext.ExtHostDebugService, ExtHostContext.ExtHostTask];
const expected: ProxyIdentifier<any>[] = values(ExtHostContext).filter(v => !find(filtered, x => x === v));
const expected: ProxyIdentifier<any>[] = values(ExtHostContext).filter(v => !filtered.find(x => x === v));
rpcProtocol.assertRegistered(expected);
// Other instances
const extHostBulkEdits = new ExtHostBulkEdits(rpcProtocol, extHostDocumentsAndEditors, extHostNotebook);
const extHostClipboard = new ExtHostClipboard(rpcProtocol);
const extHostMessageService = new ExtHostMessageService(rpcProtocol, extHostLogService);
const extHostDialogs = new ExtHostDialogs(rpcProtocol);
@@ -694,7 +698,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
return extHostWorkspace.saveAll(includeUntitled);
},
applyEdit(edit: vscode.WorkspaceEdit): Thenable<boolean> {
return extHostEditors.applyWorkspaceEdit(edit);
return extHostBulkEdits.applyWorkspaceEdit(edit);
},
createFileSystemWatcher: (pattern, ignoreCreate, ignoreChange, ignoreDelete): vscode.FileSystemWatcher => {
return extHostFileSystemEvent.createFileSystemWatcher(typeConverters.GlobPattern.from(pattern), ignoreCreate, ignoreChange, ignoreDelete);
@@ -991,6 +995,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeActiveNotebookEditor(listener, thisArgs, disposables);
},
onDidChangeNotebookDocumentMetadata(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookDocumentMetadata(listener, thisArgs, disposables);
},
onDidChangeNotebookCells(listener, thisArgs?, disposables?) {
checkProposedApiEnabled(extension);
return extHostNotebook.onDidChangeNotebookCells(listener, thisArgs, disposables);

View File

@@ -19,7 +19,8 @@ import { IExtHostStorage, ExtHostStorage } from 'vs/workbench/api/common/extHost
import { IExtHostTunnelService, ExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
import { IExtHostApiDeprecationService, ExtHostApiDeprecationService, } from 'vs/workbench/api/common/extHostApiDeprecationService';
import { IExtHostWindow, ExtHostWindow } from 'vs/workbench/api/common/extHostWindow';
import { ExtHostConsumerFileSystem, IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostConsumerFileSystem, ExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
import { IExtHostFileSystemInfo, ExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
registerSingleton(IExtensionStoragePaths, ExtensionStoragePaths);
registerSingleton(IExtHostApiDeprecationService, ExtHostApiDeprecationService);
@@ -29,6 +30,7 @@ registerSingleton(IExtHostConsumerFileSystem, ExtHostConsumerFileSystem);
// registerSingleton(IExtHostDebugService, WorkerExtHostDebugService);
registerSingleton(IExtHostDecorations, ExtHostDecorations);
registerSingleton(IExtHostDocumentsAndEditors, ExtHostDocumentsAndEditors);
registerSingleton(IExtHostFileSystemInfo, ExtHostFileSystemInfo);
registerSingleton(IExtHostOutputService, ExtHostOutputService);
registerSingleton(IExtHostSearch, ExtHostSearch);
registerSingleton(IExtHostStorage, ExtHostStorage);

View File

@@ -51,7 +51,7 @@ import { TunnelDto } from 'vs/workbench/api/common/extHostTunnelService';
import { TunnelOptions } from 'vs/platform/remote/common/tunnel';
import { Timeline, TimelineChangeEvent, TimelineOptions, TimelineProviderDescriptor, InternalTimelineOptions } from 'vs/workbench/contrib/timeline/common/timeline';
import { revive } from 'vs/base/common/marshalling';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEventDto, NotebookDataDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2, TransientMetadata, INotebookCellStatusBarEntry, ICellRange } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
@@ -267,6 +267,10 @@ export interface ITextDocumentShowOptions {
selection?: IRange;
}
export interface MainThreadBulkEditsShape extends IDisposable {
$tryApplyWorkspaceEdit(workspaceEditDto: IWorkspaceEditDto): Promise<boolean>;
}
export interface MainThreadTextEditorsShape extends IDisposable {
$tryShowTextDocument(resource: UriComponents, options: ITextDocumentShowOptions): Promise<string | undefined>;
$registerTextEditorDecorationType(key: string, options: editorCommon.IDecorationRenderOptions): void;
@@ -279,7 +283,6 @@ export interface MainThreadTextEditorsShape extends IDisposable {
$tryRevealRange(id: string, range: IRange, revealType: TextEditorRevealType): Promise<void>;
$trySetSelections(id: string, selections: ISelection[]): Promise<void>;
$tryApplyEdits(id: string, modelVersionId: number, edits: ISingleEditOperation[], opts: IApplyEditsOptions): Promise<boolean>;
$tryApplyWorkspaceEdit(workspaceEditDto: IWorkspaceEditDto): Promise<boolean>;
$tryInsertSnippet(id: string, template: string, selections: readonly IRange[], opts: IUndoStopOptions): Promise<boolean>;
$getDiffInformation(id: string): Promise<editorCommon.ILineChange[]>;
}
@@ -644,6 +647,9 @@ export interface MainThreadWebviewViewsShape extends IDisposable {
$unregisterWebviewViewProvider(viewType: string): void;
$setWebviewViewTitle(handle: WebviewHandle, value: string | undefined): void;
$setWebviewViewDescription(handle: WebviewHandle, value: string | undefined): void;
$show(handle: WebviewHandle, preserveFocus: boolean): void;
}
export interface WebviewPanelViewStateData {
@@ -684,7 +690,7 @@ export interface ExtHostCustomEditorsShape {
}
export interface ExtHostWebviewViewsShape {
$resolveWebviewView(webviewHandle: WebviewHandle, viewType: string, state: any, cancellation: CancellationToken): Promise<void>;
$resolveWebviewView(webviewHandle: WebviewHandle, viewType: string, title: string | undefined, state: any, cancellation: CancellationToken): Promise<void>;
$onDidChangeWebviewViewVisibility(webviewHandle: WebviewHandle, visible: boolean): void;
@@ -734,20 +740,17 @@ export type INotebookCellStatusBarEntryDto = Dto<INotebookCellStatusBarEntry>;
export interface MainThreadNotebookShape extends IDisposable {
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, options: { transientOutputs: boolean; transientMetadata: TransientMetadata }): Promise<void>;
$onNotebookChange(viewType: string, resource: UriComponents): Promise<void>;
$unregisterNotebookProvider(viewType: string): Promise<void>;
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
$onNotebookKernelChange(handle: number, uri: UriComponents | undefined): void;
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[]): Promise<boolean>;
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void>;
$updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata | undefined): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void>;
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
$setStatusBarEntry(id: number, statusBarEntry: INotebookCellStatusBarEntryDto): Promise<void>;
$tryRevealRange(id: string, range: ICellRange, revealType: NotebookEditorRevealType): Promise<void>;
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
$onUndoableContentChange(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
$onContentChange(resource: UriComponents, viewType: string): void;
}
@@ -1037,6 +1040,10 @@ export interface ExtHostWorkspaceShape {
$handleTextSearchResult(result: search.IRawFileMatch2, requestId: number): void;
}
export interface ExtHostFileSystemInfoShape {
$acceptProviderInfos(scheme: string, capabilities: number | null): void;
}
export interface ExtHostFileSystemShape {
$stat(handle: number, resource: UriComponents): Promise<files.IStat>;
$readdir(handle: number, resource: UriComponents): Promise<[string, files.FileType][]>;
@@ -1277,7 +1284,7 @@ export interface IWorkspaceCellEditDto {
_type: WorkspaceEditType.Cell;
resource: UriComponents;
edit: ICellEditOperation;
modelVersionId?: number;
notebookVersionId?: number;
metadata?: IWorkspaceEditEntryMetadataDto;
}
@@ -1643,16 +1650,15 @@ export interface INotebookVisibleRangesEvent {
export interface INotebookEditorPropertiesChangeData {
visibleRanges: INotebookVisibleRangesEvent | null;
selections: INotebookSelectionChangeEvent | null;
}
export interface INotebookDocumentPropertiesChangeData {
metadata: NotebookDocumentMetadata | null;
selections: INotebookSelectionChangeEvent | null;
}
export interface INotebookModelAddedData {
uri: UriComponents;
handle: number;
versionId: number;
cells: IMainCellDto[],
viewType: string;
@@ -1677,7 +1683,7 @@ export interface INotebookDocumentsAndEditorsDelta {
}
export interface ExtHostNotebookShape {
$resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto | undefined>;
$resolveNotebookData(viewType: string, uri: UriComponents, backupId?: string): Promise<NotebookDataDto>;
$resolveNotebookEditor(viewType: string, uri: UriComponents, editorId: string): Promise<void>;
$provideNotebookKernels(handle: number, uri: UriComponents, token: CancellationToken): Promise<INotebookKernelInfoDto2[]>;
$resolveNotebookKernel(handle: number, editorId: string, uri: UriComponents, kernelId: string, token: CancellationToken): Promise<void>;
@@ -1690,7 +1696,7 @@ export interface ExtHostNotebookShape {
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }): void;
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent, isDirty: boolean): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEventDto, isDirty: boolean): void;
$acceptModelSaved(uriComponents: UriComponents): void;
$acceptEditorPropertiesChanged(id: string, data: INotebookEditorPropertiesChangeData): void;
$acceptDocumentPropertiesChanged(uriComponents: UriComponents, data: INotebookDocumentPropertiesChangeData): void;
@@ -1727,6 +1733,7 @@ export interface ExtHostTimelineShape {
export const MainContext = {
MainThreadAuthentication: createMainId<MainThreadAuthenticationShape>('MainThreadAuthentication'),
MainThreadBulkEdits: createMainId<MainThreadBulkEditsShape>('MainThreadBulkEdits'),
MainThreadClipboard: createMainId<MainThreadClipboardShape>('MainThreadClipboard'),
MainThreadCommands: createMainId<MainThreadCommandsShape>('MainThreadCommands'),
MainThreadComments: createMainId<MainThreadCommentsShape>('MainThreadComments'),
@@ -1787,6 +1794,7 @@ export const ExtHostContext = {
ExtHostEditors: createExtId<ExtHostEditorsShape>('ExtHostEditors'),
ExtHostTreeViews: createExtId<ExtHostTreeViewsShape>('ExtHostTreeViews'),
ExtHostFileSystem: createExtId<ExtHostFileSystemShape>('ExtHostFileSystem'),
ExtHostFileSystemInfo: createExtId<ExtHostFileSystemInfoShape>('ExtHostFileSystemInfo'),
ExtHostFileSystemEventService: createExtId<ExtHostFileSystemEventServiceShape>('ExtHostFileSystemEventService'),
ExtHostLanguageFeatures: createExtId<ExtHostLanguageFeaturesShape>('ExtHostLanguageFeatures'),
ExtHostQuickOpen: createExtId<ExtHostQuickOpenShape>('ExtHostQuickOpen'),

View File

@@ -228,10 +228,15 @@ const newCommands: ApiCommand[] = [
}
return typeConverters.WorkspaceEdit.to(value);
})
),
// --- links
new ApiCommand(
'vscode.executeLinkProvider', '_executeLinkProvider', 'Execute document link provider.',
[ApiCommandArgument.Uri, new ApiCommandArgument('linkResolveCount', '(optional) Number of links that should be resolved, only when links are unresolved.', v => typeof v === 'number' || typeof v === 'undefined', v => v)],
new ApiCommandResult<modes.ILink[], vscode.DocumentLink[]>('A promise that resolves to an array of DocumentLink-instances.', value => value.map(typeConverters.DocumentLink.to))
)
];
//#endregion
@@ -289,13 +294,6 @@ export class ExtHostApiCommands {
returns: 'A promise that resolves to an array of CodeLens-instances.'
});
this._register('vscode.executeLinkProvider', this._executeDocumentLinkProvider, {
description: 'Execute document link provider.',
args: [
{ name: 'uri', description: 'Uri of a text document', constraint: URI }
],
returns: 'A promise that resolves to an array of DocumentLink-instances.'
});
this._register('vscode.executeDocumentColorProvider', this._executeDocumentColorProvider, {
description: 'Execute document color provider.',
args: [
@@ -478,12 +476,6 @@ export class ExtHostApiCommands {
typeConverters.Range.to(item.range),
item.command ? this._commands.converter.fromInternal(item.command) : undefined);
}));
}
private _executeDocumentLinkProvider(resource: URI): Promise<vscode.DocumentLink[] | undefined> {
return this._commands.executeCommand<modes.ILink[]>('_executeLinkProvider', resource)
.then(tryMapWith(typeConverters.DocumentLink.to));
}
}

View File

@@ -0,0 +1,29 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { MainContext, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { WorkspaceEdit } from 'vs/workbench/api/common/extHostTypeConverters';
import type * as vscode from 'vscode';
export class ExtHostBulkEdits {
private readonly _proxy: MainThreadBulkEditsShape;
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
private readonly _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _extHostNotebooks: ExtHostNotebookController,
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadBulkEdits);
}
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): Promise<boolean> {
const dto = WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors, this._extHostNotebooks);
return this._proxy.$tryApplyWorkspaceEdit(dto);
}
}

View File

@@ -6,7 +6,7 @@
import { Event } from 'vs/base/common/event';
import { URI, UriComponents } from 'vs/base/common/uri';
import { illegalState } from 'vs/base/common/errors';
import { ExtHostDocumentSaveParticipantShape, MainThreadTextEditorsShape, IWorkspaceEditDto, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentSaveParticipantShape, IWorkspaceEditDto, WorkspaceEditType, MainThreadBulkEditsShape } from 'vs/workbench/api/common/extHost.protocol';
import { TextEdit } from 'vs/workbench/api/common/extHostTypes';
import { Range, TextDocumentSaveReason, EndOfLine } from 'vs/workbench/api/common/extHostTypeConverters';
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
@@ -26,7 +26,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
constructor(
private readonly _logService: ILogService,
private readonly _documents: ExtHostDocuments,
private readonly _mainThreadEditors: MainThreadTextEditorsShape,
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _thresholds: { timeout: number; errors: number; } = { timeout: 1500, errors: 3 }
) {
//
@@ -165,7 +165,7 @@ export class ExtHostDocumentSaveParticipant implements ExtHostDocumentSavePartic
}
if (version === document.version) {
return this._mainThreadEditors.$tryApplyWorkspaceEdit(dto);
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit(dto);
}
return Promise.reject(new Error('concurrent_edits'));

View File

@@ -747,7 +747,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
protected abstract _beforeAlmostReadyToRunExtensions(): Promise<void>;
protected abstract _getEntryPoint(extensionDescription: IExtensionDescription): string | undefined;
protected abstract _loadCommonJSModule<T>(module: URI, activationTimesBuilder: ExtensionActivationTimesBuilder): Promise<T>;
public abstract async $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
public abstract $setRemoteEnvironment(env: { [key: string]: string | null }): Promise<void>;
}

View File

@@ -7,15 +7,15 @@ import { URI, UriComponents } from 'vs/base/common/uri';
import { MainContext, IMainContext, ExtHostFileSystemShape, MainThreadFileSystemShape, IFileChangeDto } from './extHost.protocol';
import type * as vscode from 'vscode';
import * as files from 'vs/platform/files/common/files';
import { IDisposable, toDisposable, dispose } from 'vs/base/common/lifecycle';
import { IDisposable, toDisposable } from 'vs/base/common/lifecycle';
import { FileChangeType } from 'vs/workbench/api/common/extHostTypes';
import * as typeConverter from 'vs/workbench/api/common/extHostTypeConverters';
import { ExtHostLanguageFeatures } from 'vs/workbench/api/common/extHostLanguageFeatures';
import { Schemas } from 'vs/base/common/network';
import { State, StateMachine, LinkComputer, Edge } from 'vs/editor/common/modes/linkComputer';
import { commonPrefixLength } from 'vs/base/common/strings';
import { CharCode } from 'vs/base/common/charCode';
import { VSBuffer } from 'vs/base/common/buffer';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
class FsLinkProvider {
@@ -113,21 +113,18 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
private readonly _proxy: MainThreadFileSystemShape;
private readonly _linkProvider = new FsLinkProvider();
private readonly _fsProvider = new Map<number, vscode.FileSystemProvider>();
private readonly _usedSchemes = new Set<string>();
private readonly _registeredSchemes = new Set<string>();
private readonly _watches = new Map<number, IDisposable>();
private _linkProviderRegistration?: IDisposable;
private _handlePool: number = 0;
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures) {
constructor(mainContext: IMainContext, private _extHostLanguageFeatures: ExtHostLanguageFeatures, private _extHostFileSystemInfo: IExtHostFileSystemInfo) {
this._proxy = mainContext.getProxy(MainContext.MainThreadFileSystem);
// register used schemes
Object.keys(Schemas).forEach(scheme => this._usedSchemes.add(scheme));
}
dispose(): void {
dispose(this._linkProviderRegistration);
this._linkProviderRegistration?.dispose();
}
private _registerLinkProviderIfNotYetRegistered(): void {
@@ -138,7 +135,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
registerFileSystemProvider(scheme: string, provider: vscode.FileSystemProvider, options: { isCaseSensitive?: boolean, isReadonly?: boolean } = {}) {
if (this._usedSchemes.has(scheme)) {
if (this._registeredSchemes.has(scheme) || !this._extHostFileSystemInfo.isFreeScheme(scheme)) {
throw new Error(`a provider for the scheme '${scheme}' is already registered`);
}
@@ -147,7 +144,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
const handle = this._handlePool++;
this._linkProvider.add(scheme);
this._usedSchemes.add(scheme);
this._registeredSchemes.add(scheme);
this._fsProvider.set(handle, provider);
let capabilities = files.FileSystemProviderCapabilities.FileReadWrite;
@@ -198,7 +195,7 @@ export class ExtHostFileSystem implements ExtHostFileSystemShape {
return toDisposable(() => {
subscription.dispose();
this._linkProvider.delete(scheme);
this._usedSchemes.delete(scheme);
this._registeredSchemes.delete(scheme);
this._fsProvider.delete(handle);
this._proxy.$unregisterProvider(handle);
});

View File

@@ -10,6 +10,7 @@ import { FileSystemError } from 'vs/workbench/api/common/extHostTypes';
import { VSBuffer } from 'vs/base/common/buffer';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { IExtHostFileSystemInfo } from 'vs/workbench/api/common/extHostFileSystemInfo';
export class ExtHostConsumerFileSystem implements vscode.FileSystem {
@@ -17,7 +18,10 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem {
private readonly _proxy: MainThreadFileSystemShape;
constructor(@IExtHostRpcService extHostRpc: IExtHostRpcService) {
constructor(
@IExtHostRpcService extHostRpc: IExtHostRpcService,
@IExtHostFileSystemInfo private readonly _fileSystemInfo: IExtHostFileSystemInfo,
) {
this._proxy = extHostRpc.getProxy(MainContext.MainThreadFileSystem);
}
@@ -45,6 +49,14 @@ export class ExtHostConsumerFileSystem implements vscode.FileSystem {
copy(source: vscode.Uri, destination: vscode.Uri, options?: { overwrite?: boolean; }): Promise<void> {
return this._proxy.$copy(source, destination, { ...{ overwrite: false }, ...options }).catch(ExtHostConsumerFileSystem._handleError);
}
isWritableFileSystem(scheme: string): boolean | undefined {
const capabilities = this._fileSystemInfo.getCapabilities(scheme);
if (typeof capabilities === 'number') {
return !(capabilities & files.FileSystemProviderCapabilities.Readonly);
}
return undefined;
}
private static _handleError(err: any): never {
// generic error
if (!(err instanceof Error)) {

View File

@@ -8,7 +8,7 @@ import { IRelativePattern, parse } from 'vs/base/common/glob';
import { URI } from 'vs/base/common/uri';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import type * as vscode from 'vscode';
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, MainThreadTextEditorsShape, SourceTargetPair, IWorkspaceEditDto } from './extHost.protocol';
import { ExtHostFileSystemEventServiceShape, FileSystemEvents, IMainContext, MainContext, SourceTargetPair, IWorkspaceEditDto, MainThreadBulkEditsShape } from './extHost.protocol';
import * as typeConverter from './extHostTypeConverters';
import { Disposable, WorkspaceEdit } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
@@ -123,7 +123,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
mainContext: IMainContext,
private readonly _logService: ILogService,
private readonly _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _mainThreadTextEditors: MainThreadTextEditorsShape = mainContext.getProxy(MainContext.MainThreadTextEditors)
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape = mainContext.getProxy(MainContext.MainThreadBulkEdits)
) {
//
}
@@ -222,7 +222,7 @@ export class ExtHostFileSystemEventService implements ExtHostFileSystemEventServ
let { edits } = typeConverter.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors);
dto.edits = dto.edits.concat(edits);
}
return this._mainThreadTextEditors.$tryApplyWorkspaceEdit(dto);
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit(dto);
}
}
}

View File

@@ -0,0 +1,35 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Schemas } from 'vs/base/common/network';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { ExtHostFileSystemInfoShape } from 'vs/workbench/api/common/extHost.protocol';
export class ExtHostFileSystemInfo implements ExtHostFileSystemInfoShape {
declare readonly _serviceBrand: undefined;
private readonly _systemSchemes = new Set(Object.keys(Schemas));
private readonly _providerInfo = new Map<string, number>();
$acceptProviderInfos(scheme: string, capabilities: number | null): void {
if (capabilities === null) {
this._providerInfo.delete(scheme);
} else {
this._providerInfo.set(scheme, capabilities);
}
}
isFreeScheme(scheme: string): boolean {
return !this._providerInfo.has(scheme) && !this._systemSchemes.has(scheme);
}
getCapabilities(scheme: string): number | undefined {
return this._providerInfo.get(scheme);
}
}
export interface IExtHostFileSystemInfo extends ExtHostFileSystemInfo { }
export const IExtHostFileSystemInfo = createDecorator<IExtHostFileSystemInfo>('IExtHostFileSystemInfo');

View File

@@ -25,7 +25,7 @@ import { ILogService } from 'vs/platform/log/common/log';
import { CancellationToken } from 'vs/base/common/cancellation';
import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { IURITransformer } from 'vs/base/common/uriIpc';
import { DisposableStore, dispose } from 'vs/base/common/lifecycle';
import { DisposableStore } from 'vs/base/common/lifecycle';
import { VSBuffer } from 'vs/base/common/buffer';
import { encodeSemanticTokensDto } from 'vs/workbench/api/common/shared/semanticTokensDto';
import { IdGenerator } from 'vs/base/common/idGenerator';
@@ -177,7 +177,7 @@ class CodeLensAdapter {
}
releaseCodeLenses(cachedId: number): void {
dispose(this._disposables.get(cachedId));
this._disposables.get(cachedId)?.dispose();
this._disposables.delete(cachedId);
this._cache.delete(cachedId);
}
@@ -455,7 +455,7 @@ class CodeActionAdapter {
}
public releaseCodeActions(cachedId: number): void {
dispose(this._disposables.get(cachedId));
this._disposables.get(cachedId)?.dispose();
this._disposables.delete(cachedId);
this._cache.delete(cachedId);
}
@@ -938,7 +938,7 @@ class SuggestAdapter {
}
releaseCompletionItems(id: number): any {
dispose(this._disposables.get(id));
this._disposables.get(id)?.dispose();
this._disposables.delete(id);
this._cache.delete(id);
}

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,527 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { Emitter, Event } from 'vs/base/common/event';
import { hash } from 'vs/base/common/hash';
import { Disposable, DisposableStore, dispose, IDisposable } from 'vs/base/common/lifecycle';
import { Schemas } from 'vs/base/common/network';
import { joinPath } from 'vs/base/common/resources';
import { ISplice } from 'vs/base/common/sequence';
import { URI } from 'vs/base/common/uri';
import * as UUID from 'vs/base/common/uuid';
import { CellKind, INotebookDocumentPropertiesChangeData, IWorkspaceCellEditDto, MainThreadBulkEditsShape, MainThreadNotebookShape, NotebookCellOutputsSplice, WorkspaceEditType } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentsAndEditors, IExtHostModelAddedData } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { CellEditType, CellOutputKind, diff, IMainCellDto, IProcessedOutput, NotebookCellMetadata, NotebookCellsChangedEventDto, NotebookCellsChangeType, NotebookCellsSplice2, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { Cache } from './cache';
interface IObservable<T> {
proxy: T;
onDidChange: Event<void>;
}
function getObservable<T extends Object>(obj: T): IObservable<T> {
const onDidChange = new Emitter<void>();
const proxy = new Proxy(obj, {
set(target: T, p: PropertyKey, value: any, _receiver: any): boolean {
target[p as keyof T] = value;
onDidChange.fire();
return true;
}
});
return {
proxy,
onDidChange: onDidChange.event
};
}
class RawContentChangeEvent {
constructor(readonly start: number, readonly deletedCount: number, readonly deletedItems: ExtHostCell[], readonly items: ExtHostCell[]) { }
static asApiEvent(event: RawContentChangeEvent): vscode.NotebookCellsChangeData {
return Object.freeze({
start: event.start,
deletedCount: event.deletedCount,
deletedItems: event.deletedItems.map(data => data.cell),
items: event.items.map(data => data.cell)
});
}
}
export class ExtHostCell extends Disposable {
static asModelAddData(notebook: vscode.NotebookDocument, cell: IMainCellDto): IExtHostModelAddedData {
return {
EOL: cell.eol,
lines: cell.source,
modeId: cell.language,
uri: cell.uri,
isDirty: false,
versionId: 1,
notebook
};
}
private _onDidDispose = new Emitter<void>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
private _onDidChangeOutputs = new Emitter<ISplice<IProcessedOutput>[]>();
readonly onDidChangeOutputs: Event<ISplice<IProcessedOutput>[]> = this._onDidChangeOutputs.event;
private _outputs: any[];
private _outputMapping = new WeakMap<vscode.CellOutput, string | undefined /* output ID */>();
private _metadata: vscode.NotebookCellMetadata;
private _metadataChangeListener: IDisposable;
readonly handle: number;
readonly uri: URI;
readonly cellKind: CellKind;
private _cell: vscode.NotebookCell | undefined;
constructor(
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _notebook: ExtHostNotebookDocument,
private readonly _extHostDocument: ExtHostDocumentsAndEditors,
private readonly _cellData: IMainCellDto,
) {
super();
this.handle = _cellData.handle;
this.uri = URI.revive(_cellData.uri);
this.cellKind = _cellData.cellKind;
this._outputs = _cellData.outputs;
for (const output of this._outputs) {
this._outputMapping.set(output, output.outputId);
delete output.outputId;
}
const observableMetadata = getObservable(_cellData.metadata ?? {});
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
}
get cell(): vscode.NotebookCell {
if (!this._cell) {
const that = this;
const document = this._extHostDocument.getDocument(this.uri)!.document;
this._cell = Object.freeze({
get index() { return that._notebook.getCellIndex(that); },
notebook: that._notebook.notebookDocument,
uri: that.uri,
cellKind: this._cellData.cellKind,
document,
get language() { return document.languageId; },
get outputs() { return that._outputs; },
set outputs(value) { that._updateOutputs(value); },
get metadata() { return that._metadata; },
set metadata(value) {
that.setMetadata(value);
that._updateMetadata();
},
});
}
return this._cell;
}
dispose() {
super.dispose();
this._onDidDispose.fire();
}
setOutputs(newOutputs: vscode.CellOutput[]): void {
this._outputs = newOutputs;
}
private _updateOutputs(newOutputs: vscode.CellOutput[]) {
const rawDiffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
return this._outputMapping.has(a);
});
const transformedDiffs: ISplice<IProcessedOutput>[] = rawDiffs.map(diff => {
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
this._outputMapping.delete(this._outputs[i]);
}
return {
deleteCount: diff.deleteCount,
start: diff.start,
toInsert: diff.toInsert.map((output): IProcessedOutput => {
if (output.outputKind === CellOutputKind.Rich) {
const uuid = UUID.generateUuid();
this._outputMapping.set(output, uuid);
return { ...output, outputId: uuid };
}
this._outputMapping.set(output, undefined);
return output;
})
};
});
this._outputs = newOutputs;
this._onDidChangeOutputs.fire(transformedDiffs);
}
setMetadata(newMetadata: vscode.NotebookCellMetadata): void {
// Don't apply metadata defaults here, 'undefined' means 'inherit from document metadata'
this._metadataChangeListener.dispose();
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._updateMetadata();
}));
}
private _updateMetadata(): Promise<boolean> {
const index = this._notebook.notebookDocument.cells.indexOf(this.cell);
const edit: IWorkspaceCellEditDto = {
_type: WorkspaceEditType.Cell,
metadata: undefined,
resource: this._notebook.uri,
notebookVersionId: this._notebook.notebookDocument.version,
edit: { editType: CellEditType.Metadata, index, metadata: this._metadata }
};
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit({ edits: [edit] });
}
}
export interface INotebookEventEmitter {
emitModelChange(events: vscode.NotebookCellsChangeEvent): void;
emitDocumentMetadataChange(event: vscode.NotebookDocumentMetadataChangeEvent): void;
emitCellOutputsChange(event: vscode.NotebookCellOutputsChangeEvent): void;
emitCellLanguageChange(event: vscode.NotebookCellLanguageChangeEvent): void;
emitCellMetadataChange(event: vscode.NotebookCellMetadataChangeEvent): void;
}
function hashPath(resource: URI): string {
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
return hash(str) + '';
}
export class ExtHostNotebookDocument extends Disposable {
private static _handlePool: number = 0;
readonly handle = ExtHostNotebookDocument._handlePool++;
private _cells: ExtHostCell[] = [];
private _cellDisposableMapping = new Map<number, DisposableStore>();
private _notebook: vscode.NotebookDocument | undefined;
private _metadata: Required<vscode.NotebookDocumentMetadata>;
private _metadataChangeListener: IDisposable;
private _versionId = 0;
private _isDirty: boolean = false;
private _backupCounter = 1;
private _backup?: vscode.NotebookDocumentBackup;
private _disposed = false;
private _languages: string[] = [];
private readonly _edits = new Cache<vscode.NotebookDocumentEditEvent>('notebook documents');
constructor(
private readonly _proxy: MainThreadNotebookShape,
private readonly _documentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _mainThreadBulkEdits: MainThreadBulkEditsShape,
private readonly _emitter: INotebookEventEmitter,
private readonly _viewType: string,
metadata: Required<vscode.NotebookDocumentMetadata>,
public readonly uri: URI,
private readonly _storagePath: URI | undefined
) {
super();
const observableMetadata = getObservable(metadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
}
dispose() {
this._disposed = true;
super.dispose();
dispose(this._cellDisposableMapping.values());
}
private _updateMetadata(newMetadata: Required<vscode.NotebookDocumentMetadata>) {
this._metadataChangeListener.dispose();
newMetadata = {
...notebookDocumentMetadataDefaults,
...newMetadata
};
if (this._metadataChangeListener) {
this._metadataChangeListener.dispose();
}
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
this._tryUpdateMetadata();
}
private _tryUpdateMetadata() {
const edit: IWorkspaceCellEditDto = {
_type: WorkspaceEditType.Cell,
metadata: undefined,
edit: { editType: CellEditType.DocumentMetadata, metadata: this._metadata },
resource: this.uri,
notebookVersionId: this.notebookDocument.version,
};
return this._mainThreadBulkEdits.$tryApplyWorkspaceEdit({ edits: [edit] });
}
get notebookDocument(): vscode.NotebookDocument {
if (!this._notebook) {
const that = this;
this._notebook = Object.freeze({
get uri() { return that.uri; },
get version() { return that._versionId; },
get fileName() { return that.uri.fsPath; },
get viewType() { return that._viewType; },
get isDirty() { return that._isDirty; },
get isUntitled() { return that.uri.scheme === Schemas.untitled; },
get cells(): ReadonlyArray<vscode.NotebookCell> { return that._cells.map(cell => cell.cell); },
get languages() { return that._languages; },
set languages(value: string[]) { that._trySetLanguages(value); },
get metadata() { return that._metadata; },
set metadata(value: Required<vscode.NotebookDocumentMetadata>) { that._updateMetadata(value); },
});
}
return this._notebook;
}
private _trySetLanguages(newLanguages: string[]) {
this._languages = newLanguages;
this._proxy.$updateNotebookLanguages(this._viewType, this.uri, this._languages);
}
getNewBackupUri(): URI {
if (!this._storagePath) {
throw new Error('Backup requires a valid storage path');
}
const fileName = hashPath(this.uri) + (this._backupCounter++);
return joinPath(this._storagePath, fileName);
}
updateBackup(backup: vscode.NotebookDocumentBackup): void {
this._backup?.delete();
this._backup = backup;
}
disposeBackup(): void {
this._backup?.delete();
this._backup = undefined;
}
acceptDocumentPropertiesChanged(data: INotebookDocumentPropertiesChangeData) {
const newMetadata = {
...notebookDocumentMetadataDefaults,
...data.metadata
};
if (this._metadataChangeListener) {
this._metadataChangeListener.dispose();
}
const observableMetadata = getObservable(newMetadata);
this._metadata = observableMetadata.proxy;
this._metadataChangeListener = this._register(observableMetadata.onDidChange(() => {
this._tryUpdateMetadata();
}));
this._emitter.emitDocumentMetadataChange({ document: this.notebookDocument });
}
acceptModelChanged(event: NotebookCellsChangedEventDto, isDirty: boolean): void {
this._versionId = event.versionId;
this._isDirty = isDirty;
event.rawEvents.forEach(e => {
if (e.kind === NotebookCellsChangeType.Initialize) {
this._spliceNotebookCells(e.changes, true);
} if (e.kind === NotebookCellsChangeType.ModelChange) {
this._spliceNotebookCells(e.changes, false);
} else if (e.kind === NotebookCellsChangeType.Move) {
this._moveCell(e.index, e.newIdx);
} else if (e.kind === NotebookCellsChangeType.Output) {
this._setCellOutputs(e.index, e.outputs);
} else if (e.kind === NotebookCellsChangeType.ChangeLanguage) {
this._changeCellLanguage(e.index, e.language);
} else if (e.kind === NotebookCellsChangeType.ChangeCellMetadata) {
this._changeCellMetadata(e.index, e.metadata);
}
});
}
private _spliceNotebookCells(splices: NotebookCellsSplice2[], initialization: boolean): void {
if (this._disposed) {
return;
}
const contentChangeEvents: RawContentChangeEvent[] = [];
const addedCellDocuments: IExtHostModelAddedData[] = [];
const removedCellDocuments: URI[] = [];
splices.reverse().forEach(splice => {
const cellDtos = splice[2];
const newCells = cellDtos.map(cell => {
const extCell = new ExtHostCell(this._mainThreadBulkEdits, this, this._documentsAndEditors, cell);
if (!initialization) {
addedCellDocuments.push(ExtHostCell.asModelAddData(this.notebookDocument, cell));
}
if (!this._cellDisposableMapping.has(extCell.handle)) {
const store = new DisposableStore();
store.add(extCell);
this._cellDisposableMapping.set(extCell.handle, store);
}
const store = this._cellDisposableMapping.get(extCell.handle)!;
store.add(extCell.onDidChangeOutputs((diffs) => {
this.eventuallyUpdateCellOutputs(extCell, diffs);
}));
return extCell;
});
for (let j = splice[0]; j < splice[0] + splice[1]; j++) {
this._cellDisposableMapping.get(this._cells[j].handle)?.dispose();
this._cellDisposableMapping.delete(this._cells[j].handle);
}
const deletedItems = this._cells.splice(splice[0], splice[1], ...newCells);
for (let cell of deletedItems) {
removedCellDocuments.push(cell.uri);
}
contentChangeEvents.push(new RawContentChangeEvent(splice[0], splice[1], deletedItems, newCells));
});
this._documentsAndEditors.acceptDocumentsAndEditorsDelta({
addedDocuments: addedCellDocuments,
removedDocuments: removedCellDocuments
});
if (!initialization) {
this._emitter.emitModelChange({
document: this.notebookDocument,
changes: contentChangeEvents.map(RawContentChangeEvent.asApiEvent)
});
}
}
private _moveCell(index: number, newIdx: number): void {
const cells = this._cells.splice(index, 1);
this._cells.splice(newIdx, 0, ...cells);
const changes: vscode.NotebookCellsChangeData[] = [{
start: index,
deletedCount: 1,
deletedItems: cells.map(data => data.cell),
items: []
}, {
start: newIdx,
deletedCount: 0,
deletedItems: [],
items: cells.map(data => data.cell)
}];
this._emitter.emitModelChange({
document: this.notebookDocument,
changes
});
}
private _setCellOutputs(index: number, outputs: IProcessedOutput[]): void {
const cell = this._cells[index];
cell.setOutputs(outputs);
this._emitter.emitCellOutputsChange({ document: this.notebookDocument, cells: [cell.cell] });
}
private _changeCellLanguage(index: number, language: string): void {
const cell = this._cells[index];
const event: vscode.NotebookCellLanguageChangeEvent = { document: this.notebookDocument, cell: cell.cell, language };
this._emitter.emitCellLanguageChange(event);
}
private _changeCellMetadata(index: number, newMetadata: NotebookCellMetadata | undefined): void {
const cell = this._cells[index];
cell.setMetadata(newMetadata || {});
const event: vscode.NotebookCellMetadataChangeEvent = { document: this.notebookDocument, cell: cell.cell };
this._emitter.emitCellMetadataChange(event);
}
async eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<IProcessedOutput>[]) {
const outputDtos: NotebookCellOutputsSplice[] = diffs.map(diff => {
const outputs = diff.toInsert;
return [diff.start, diff.deleteCount, outputs];
});
if (!outputDtos.length) {
return;
}
await this._proxy.$spliceNotebookCellOutputs(this._viewType, this.uri, cell.handle, outputDtos);
this._emitter.emitCellOutputsChange({
document: this.notebookDocument,
cells: [cell.cell]
});
}
getCell(cellHandle: number): ExtHostCell | undefined {
return this._cells.find(cell => cell.handle === cellHandle);
}
getCellIndex(cell: ExtHostCell): number {
return this._cells.indexOf(cell);
}
addEdit(item: vscode.NotebookDocumentEditEvent): number {
return this._edits.add([item]);
}
async undo(editId: number, isDirty: boolean): Promise<void> {
await this.getEdit(editId).undo();
// if (!isDirty) {
// this.disposeBackup();
// }
}
async redo(editId: number, isDirty: boolean): Promise<void> {
await this.getEdit(editId).redo();
// if (!isDirty) {
// this.disposeBackup();
// }
}
private getEdit(editId: number): vscode.NotebookDocumentEditEvent {
const edit = this._edits.get(editId, 0);
if (!edit) {
throw new Error('No edit found');
}
return edit;
}
disposeEdits(editIds: number[]): void {
for (const id of editIds) {
this._edits.delete(id);
}
}
}

View File

@@ -0,0 +1,230 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { readonly } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable } from 'vs/base/common/lifecycle';
import { MainThreadNotebookShape } from 'vs/workbench/api/common/extHost.protocol';
import * as extHostTypes from 'vs/workbench/api/common/extHostTypes';
import { addIdToOutput, CellEditType, ICellEditOperation, ICellReplaceEdit, INotebookEditData, notebookDocumentMetadataDefaults } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { ExtHostNotebookDocument } from './extHostNotebookDocument';
class NotebookEditorCellEditBuilder implements vscode.NotebookEditorEdit {
private readonly _documentVersionId: number;
private _finalized: boolean = false;
private _collectedEdits: ICellEditOperation[] = [];
constructor(documentVersionId: number) {
this._documentVersionId = documentVersionId;
}
finalize(): INotebookEditData {
this._finalized = true;
return {
documentVersionId: this._documentVersionId,
cellEdits: this._collectedEdits
};
}
private _throwIfFinalized() {
if (this._finalized) {
throw new Error('Edit is only valid while callback runs');
}
}
replaceMetadata(value: vscode.NotebookDocumentMetadata): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.DocumentMetadata,
metadata: { ...notebookDocumentMetadataDefaults, ...value }
});
}
replaceCellMetadata(index: number, metadata: vscode.NotebookCellMetadata): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Metadata,
index,
metadata
});
}
replaceCellOutput(index: number, outputs: vscode.CellOutput[]): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Output,
index,
outputs: outputs.map(output => addIdToOutput(output))
});
}
replaceCells(from: number, to: number, cells: vscode.NotebookCellData[]): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Replace,
index: from,
count: to - from,
cells: cells.map(data => {
return {
...data,
outputs: data.outputs.map(output => addIdToOutput(output)),
};
})
});
}
}
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
//TODO@rebornix noop setter?
selection?: vscode.NotebookCell;
private _visibleRanges: vscode.NotebookCellRange[] = [];
private _viewColumn?: vscode.ViewColumn;
private _active: boolean = false;
private _visible: boolean = false;
private _kernel?: vscode.NotebookKernel;
private _onDidDispose = new Emitter<void>();
private _onDidReceiveMessage = new Emitter<any>();
readonly onDidDispose: Event<void> = this._onDidDispose.event;
readonly onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
constructor(
readonly id: string,
private readonly _viewType: string,
private readonly _proxy: MainThreadNotebookShape,
private readonly _webComm: vscode.NotebookCommunication,
readonly notebookData: ExtHostNotebookDocument,
) {
super();
this._register(this._webComm.onDidReceiveMessage(e => {
this._onDidReceiveMessage.fire(e);
}));
}
get viewColumn(): vscode.ViewColumn | undefined {
return this._viewColumn;
}
set viewColumn(_value) {
throw readonly('viewColumn');
}
get kernel() {
return this._kernel;
}
set kernel(_kernel: vscode.NotebookKernel | undefined) {
throw readonly('kernel');
}
_acceptKernel(kernel?: vscode.NotebookKernel) {
this._kernel = kernel;
}
get visible(): boolean {
return this._visible;
}
set visible(_state: boolean) {
throw readonly('visible');
}
_acceptVisibility(value: boolean) {
this._visible = value;
}
get visibleRanges() {
return this._visibleRanges;
}
set visibleRanges(_range: vscode.NotebookCellRange[]) {
throw readonly('visibleRanges');
}
_acceptVisibleRanges(value: vscode.NotebookCellRange[]): void {
this._visibleRanges = value;
}
get active(): boolean {
return this._active;
}
set active(_state: boolean) {
throw readonly('active');
}
_acceptActive(value: boolean) {
this._active = value;
}
get document(): vscode.NotebookDocument {
return this.notebookData.notebookDocument;
}
edit(callback: (editBuilder: NotebookEditorCellEditBuilder) => void): Thenable<boolean> {
const edit = new NotebookEditorCellEditBuilder(this.document.version);
callback(edit);
return this._applyEdit(edit.finalize());
}
private _applyEdit(editData: INotebookEditData): Promise<boolean> {
// return when there is nothing to do
if (editData.cellEdits.length === 0) {
return Promise.resolve(true);
}
const compressedEdits: ICellEditOperation[] = [];
let compressedEditsIndex = -1;
for (let i = 0; i < editData.cellEdits.length; i++) {
if (compressedEditsIndex < 0) {
compressedEdits.push(editData.cellEdits[i]);
compressedEditsIndex++;
continue;
}
const prevIndex = compressedEditsIndex;
const prev = compressedEdits[prevIndex];
if (prev.editType === CellEditType.Replace && editData.cellEdits[i].editType === CellEditType.Replace) {
const edit = editData.cellEdits[i];
if ((edit.editType !== CellEditType.DocumentMetadata && edit.editType !== CellEditType.Unknown) && prev.index === edit.index) {
prev.cells.push(...(editData.cellEdits[i] as ICellReplaceEdit).cells);
prev.count += (editData.cellEdits[i] as ICellReplaceEdit).count;
continue;
}
}
compressedEdits.push(editData.cellEdits[i]);
compressedEditsIndex++;
}
return this._proxy.$tryApplyEdits(this._viewType, this.document.uri, editData.documentVersionId, compressedEdits);
}
revealRange(range: vscode.NotebookCellRange, revealType?: extHostTypes.NotebookEditorRevealType) {
this._proxy.$tryRevealRange(this.id, range, revealType || extHostTypes.NotebookEditorRevealType.Default);
}
async postMessage(message: any): Promise<boolean> {
return this._webComm.postMessage(message);
}
asWebviewUri(localResource: vscode.Uri): vscode.Uri {
return this._webComm.asWebviewUri(localResource);
}
dispose() {
this._onDidDispose.fire();
super.dispose();
}
}

View File

@@ -456,7 +456,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
});
}
public abstract async executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution>;
public abstract executeTask(extension: IExtensionDescription, task: vscode.Task): Promise<vscode.TaskExecution>;
public get taskExecutions(): vscode.TaskExecution[] {
const result: vscode.TaskExecution[] = [];
@@ -561,7 +561,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
});
}
protected abstract async resolveTaskInternal(resolvedTaskDTO: tasks.TaskDTO): Promise<tasks.TaskDTO | undefined>;
protected abstract resolveTaskInternal(resolvedTaskDTO: tasks.TaskDTO): Promise<tasks.TaskDTO | undefined>;
public async $resolveTask(handle: number, taskDTO: tasks.TaskDTO): Promise<tasks.TaskDTO | undefined> {
const handler = this._handlers.get(handle);
@@ -601,7 +601,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
return await this.resolveTaskInternal(resolvedTaskDTO);
}
public abstract async $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }>;
public abstract $resolveVariables(uriComponents: UriComponents, toResolve: { process?: { name: string; cwd?: string; path?: string }, variables: string[] }): Promise<{ process?: string, variables: { [key: string]: string; } }>;
public abstract $getDefaultShellAndArgs(): Promise<{ shell: string, args: string[] | string | undefined }>;

View File

@@ -120,7 +120,7 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
) {
super(proxy, id);
this._creationOptions = Object.freeze(this._creationOptions);
this._pidPromise = new Promise<number>(c => this._pidPromiseComplete = c);
this._pidPromise = new Promise<number | undefined>(c => this._pidPromiseComplete = c);
}
public async create(
@@ -316,7 +316,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
protected _terminalProcesses: { [id: number]: ITerminalChildProcess } = {};
protected _terminalProcessDisposables: { [id: number]: IDisposable } = {};
protected _extensionTerminalAwaitingStart: { [id: number]: { initialDimensions: ITerminalDimensionsDto | undefined } | undefined } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal> } = {};
protected _getTerminalPromises: { [id: number]: Promise<ExtHostTerminal | undefined> } = {};
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
private readonly _bufferer: TerminalDataBufferer;
@@ -670,7 +670,7 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
return this._getTerminalPromises[id];
}
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal> {
private _createGetTerminalPromise(id: number, retries: number = 5): Promise<ExtHostTerminal | undefined> {
return new Promise(c => {
if (retries === 0) {
c(undefined);

View File

@@ -7,7 +7,6 @@ import { Emitter, Event } from 'vs/base/common/event';
import * as arrays from 'vs/base/common/arrays';
import { ExtHostEditorsShape, IEditorPropertiesChangeData, IMainContext, ITextDocumentShowOptions, ITextEditorPositionData, MainContext, MainThreadTextEditorsShape } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
import { ExtHostTextEditor, TextEditorDecorationType } from 'vs/workbench/api/common/extHostTextEditor';
import * as TypeConverters from 'vs/workbench/api/common/extHostTypeConverters';
import { TextEditorSelectionChangeKind } from 'vs/workbench/api/common/extHostTypes';
@@ -34,7 +33,6 @@ export class ExtHostEditors implements ExtHostEditorsShape {
constructor(
mainContext: IMainContext,
private readonly _extHostDocumentsAndEditors: ExtHostDocumentsAndEditors,
private readonly _extHostNotebooks: ExtHostNotebookController,
) {
this._proxy = mainContext.getProxy(MainContext.MainThreadTextEditors);
@@ -92,11 +90,6 @@ export class ExtHostEditors implements ExtHostEditorsShape {
return new TextEditorDecorationType(this._proxy, options);
}
applyWorkspaceEdit(edit: vscode.WorkspaceEdit): Promise<boolean> {
const dto = TypeConverters.WorkspaceEdit.from(edit, this._extHostDocumentsAndEditors, this._extHostNotebooks);
return this._proxy.$tryApplyWorkspaceEdit(dto);
}
// --- called from main thread
$acceptEditorPropertiesChanged(id: string, data: IEditorPropertiesChangeData): void {

View File

@@ -537,10 +537,11 @@ export namespace WorkspaceEdit {
} else if (entry._type === types.FileEditType.Cell) {
result.edits.push(<extHostProtocol.IWorkspaceCellEditDto>{
_type: extHostProtocol.WorkspaceEditType.Cell,
metadata: entry.metadata,
resource: entry.uri,
edit: entry.edit,
metadata: entry.metadata,
modelVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version
notebookMetadata: entry.notebookMetadata,
notebookVersionId: notebooks?.lookupNotebookDocument(entry.uri)?.notebookDocument.version
});
}
}

View File

@@ -19,7 +19,7 @@ import { addIdToOutput, CellEditType, ICellEditOperation } from 'vs/workbench/co
import type * as vscode from 'vscode';
function es5ClassCompat(target: Function): any {
///@ts-expect-error
// @ts-ignore - {{SQL CARBON EDIT}}
function _() { return Reflect.construct(target, arguments, this.constructor); }
Object.defineProperty(_, 'name', Object.getOwnPropertyDescriptor(target, 'name')!);
Object.setPrototypeOf(_, target);
@@ -601,7 +601,8 @@ export interface IFileTextEdit {
export interface IFileCellEdit {
_type: FileEditType.Cell;
uri: URI;
edit: ICellEditOperation;
edit?: ICellEditOperation;
notebookMetadata?: vscode.NotebookDocumentMetadata;
metadata?: vscode.WorkspaceEditEntryMetadata;
}
@@ -629,17 +630,21 @@ export class WorkspaceEdit implements vscode.WorkspaceEdit {
this._edits.push({ _type: FileEditType.File, from: uri, to: undefined, options, metadata });
}
// --- cell
// --- notebook
replaceCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
replaceNotebookMetadata(uri: URI, value: vscode.NotebookDocumentMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, notebookMetadata: value });
}
replaceNotebookCells(uri: URI, start: number, end: number, cells: vscode.NotebookCellData[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Replace, index: start, count: end - start, cells: cells.map(cell => ({ ...cell, outputs: cell.outputs.map(output => addIdToOutput(output)) })) } });
}
replaceCellOutput(uri: URI, index: number, outputs: vscode.CellOutput[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
replaceNotebookCellOutput(uri: URI, index: number, outputs: vscode.CellOutput[], metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Output, index, outputs: outputs.map(output => addIdToOutput(output)) } });
}
replaceCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
replaceNotebookCellMetadata(uri: URI, index: number, cellMetadata: vscode.NotebookCellMetadata, metadata?: vscode.WorkspaceEditEntryMetadata): void {
this._edits.push({ _type: FileEditType.Cell, metadata, uri, edit: { editType: CellEditType.Metadata, index, metadata: cellMetadata } });
}

View File

@@ -23,17 +23,20 @@ class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
#isDisposed = false;
#isVisible: boolean;
#title: string | undefined;
#description: string | undefined;
constructor(
handle: extHostProtocol.WebviewHandle,
proxy: extHostProtocol.MainThreadWebviewViewsShape,
viewType: string,
title: string | undefined,
webview: ExtHostWebview,
isVisible: boolean,
) {
super();
this.#viewType = viewType;
this.#title = title;
this.#handle = handle;
this.#proxy = proxy;
this.#webview = webview;
@@ -70,6 +73,19 @@ class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
}
}
public get description(): string | undefined {
this.assertNotDisposed();
return this.#description;
}
public set description(value: string | undefined) {
this.assertNotDisposed();
if (this.#description !== value) {
this.#description = value;
this.#proxy.$setWebviewViewDescription(this.#handle, value);
}
}
public get visible(): boolean { return this.#isVisible; }
public get webview(): vscode.Webview { return this.#webview; }
@@ -85,6 +101,11 @@ class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
this.#onDidChangeVisibility.fire();
}
public show(preserveFocus?: boolean): void {
this.assertNotDisposed();
this.#proxy.$show(this.#handle, !!preserveFocus);
}
private assertNotDisposed() {
if (this.#isDisposed) {
throw new Error('Webview is disposed');
@@ -134,6 +155,7 @@ export class ExtHostWebviewViews implements extHostProtocol.ExtHostWebviewViewsS
async $resolveWebviewView(
webviewHandle: string,
viewType: string,
title: string | undefined,
state: any,
cancellation: CancellationToken,
): Promise<void> {
@@ -145,7 +167,7 @@ export class ExtHostWebviewViews implements extHostProtocol.ExtHostWebviewViewsS
const { provider, extension } = entry;
const webview = this._extHostWebview.createNewWebview(webviewHandle, { /* todo */ }, extension);
const revivedView = new ExtHostWebviewView(webviewHandle, this._proxy, viewType, webview, true);
const revivedView = new ExtHostWebviewView(webviewHandle, this._proxy, viewType, title, webview, true);
this._webviewViews.set(webviewHandle, revivedView);

View File

@@ -405,7 +405,7 @@ namespace schema {
};
export const submenusContribution: IJSONSchema = {
description: localize('vscode.extension.contributes.submenus', "(Proposed API) Contributes submenu items to the editor"),
description: localize('vscode.extension.contributes.submenus', "Contributes submenu items to the editor"),
type: 'array',
items: submenu
};
@@ -622,11 +622,6 @@ submenusExtensionPoint.setHandler(extensions => {
return;
}
if (!extension.description.enableProposedApi) {
collector.error(localize('submenu.proposedAPI.invalid', "Submenus are proposed API and are only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value));
return;
}
let absoluteIcon: { dark: URI; light?: URI; } | ThemeIcon | undefined;
if (entry.value.icon) {
if (typeof entry.value.icon === 'string') {
@@ -675,7 +670,6 @@ menusExtensionPoint.setHandler(extensions => {
}
let menu = _apiMenusByKey.get(entry.key);
let isSubmenu = false;
if (!menu) {
const submenu = _submenus.get(entry.key);
@@ -686,7 +680,6 @@ menusExtensionPoint.setHandler(extensions => {
id: submenu.id,
description: ''
};
isSubmenu = true;
}
}
@@ -700,11 +693,6 @@ menusExtensionPoint.setHandler(extensions => {
return;
}
if (isSubmenu && !extension.description.enableProposedApi) {
collector.error(localize('proposedAPI.invalid.submenu', "{0} is a submenu identifier and is only available when running out of dev or with the following command line switch: --enable-proposed-api {1}", entry.key, extension.description.identifier.value));
return;
}
for (const menuItem of entry.value) {
let item: IMenuItem | ISubmenuItem;
@@ -725,13 +713,8 @@ menusExtensionPoint.setHandler(extensions => {
item = { command, alt, group: undefined, order: undefined, when: undefined };
} else {
if (!extension.description.enableProposedApi) {
collector.error(localize('proposedAPI.invalid.submenureference', "Menu item references a submenu which is only available when running out of dev or with the following command line switch: --enable-proposed-api {0}", extension.description.identifier.value));
continue;
}
if (menu.supportsSubmenus === false) {
collector.error(localize('proposedAPI.unsupported.submenureference', "Menu item references a submenu for a menu which doesn't have submenu support."));
collector.error(localize('unsupported.submenureference', "Menu item references a submenu for a menu which doesn't have submenu support."));
continue;
}