mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-13 03:28:33 -05:00
Merge from vscode ad407028575a77ea387eb7cc219b323dc017b686
This commit is contained in:
committed by
Anthony Dresser
parent
404260b8a0
commit
4ad73d381c
@@ -77,6 +77,9 @@ import { ExtHostTimeline } from 'vs/workbench/api/common/extHostTimeline';
|
||||
import { ExtHostNotebookConcatDocument } from 'vs/workbench/api/common/extHostNotebookConcatDocument';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { IExtHostConsumerFileSystem } from 'vs/workbench/api/common/extHostFileSystemConsumer';
|
||||
import { ExtHostWebviewViews } from 'vs/workbench/api/common/extHostWebviewView';
|
||||
import { ExtHostCustomEditors } from 'vs/workbench/api/common/extHostCustomEditors';
|
||||
import { ExtHostWebviewSerializer } from 'vs/workbench/api/common/extHostWebviewSerializer';
|
||||
|
||||
export interface IExtensionApiFactory {
|
||||
(extension: IExtensionDescription, registry: ExtensionDescriptionRegistry, configProvider: ExtHostConfigProvider): typeof vscode;
|
||||
@@ -138,11 +141,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, initData.uiKind === UIKind.Web ? new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment) : new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extensionStoragePaths));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostCommands, extHostDocumentsAndEditors, initData.environment, extHostLogService, extensionStoragePaths));
|
||||
const extHostTheming = rpcProtocol.set(ExtHostContext.ExtHostTheming, new ExtHostTheming(rpcProtocol));
|
||||
const extHostAuthentication = rpcProtocol.set(ExtHostContext.ExtHostAuthentication, new ExtHostAuthentication(rpcProtocol));
|
||||
const extHostTimeline = rpcProtocol.set(ExtHostContext.ExtHostTimeline, new ExtHostTimeline(rpcProtocol, extHostCommands));
|
||||
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation, extHostDocuments, extensionStoragePaths));
|
||||
const extHostWebviews = rpcProtocol.set(ExtHostContext.ExtHostWebviews, new ExtHostWebviews(rpcProtocol, initData.environment, extHostWorkspace, extHostLogService, extHostApiDeprecation));
|
||||
const extHostWebviewSerializers = rpcProtocol.set(ExtHostContext.ExtHostWebviewSerializer, new ExtHostWebviewSerializer(rpcProtocol, extHostWebviews));
|
||||
const extHostCustomEditors = rpcProtocol.set(ExtHostContext.ExtHostCustomEditors, new ExtHostCustomEditors(rpcProtocol, extHostDocuments, extensionStoragePaths, extHostWebviews));
|
||||
const extHostWebviewViews = rpcProtocol.set(ExtHostContext.ExtHostWebviewViews, new ExtHostWebviewViews(rpcProtocol, extHostWebviews));
|
||||
|
||||
// Check that no named customers are missing
|
||||
// {{SQL CARBON EDIT}} filter out the services we don't expose
|
||||
@@ -582,12 +588,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
}
|
||||
return extHostTerminalService.createTerminal(nameOrOptions, shellPath, shellArgs);
|
||||
},
|
||||
registerTerminalLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTerminalService.registerLinkHandler(handler);
|
||||
},
|
||||
registerTerminalLinkProvider(handler: vscode.TerminalLinkProvider): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTerminalService.registerLinkProvider(handler);
|
||||
},
|
||||
registerTreeDataProvider(viewId: string, treeDataProvider: vscode.TreeDataProvider<any>): vscode.Disposable {
|
||||
@@ -597,10 +598,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
return extHostTreeViews.createTreeView(viewId, options, extension);
|
||||
},
|
||||
registerWebviewPanelSerializer: (viewType: string, serializer: vscode.WebviewPanelSerializer) => {
|
||||
return extHostWebviews.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
return extHostWebviewSerializers.registerWebviewPanelSerializer(extension, viewType, serializer);
|
||||
},
|
||||
registerCustomEditorProvider: (viewType: string, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider, options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean } = {}) => {
|
||||
return extHostWebviews.registerCustomEditorProvider(extension, viewType, provider, options);
|
||||
return extHostCustomEditors.registerCustomEditorProvider(extension, viewType, provider, options);
|
||||
},
|
||||
registerDecorationProvider(provider: vscode.DecorationProvider) {
|
||||
checkProposedApiEnabled(extension);
|
||||
@@ -620,6 +621,14 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
},
|
||||
onDidChangeActiveColorTheme(listener, thisArg?, disposables?) {
|
||||
return extHostTheming.onDidChangeActiveColorTheme(listener, thisArg, disposables);
|
||||
},
|
||||
registerWebviewViewProvider(viewId: string, provider: vscode.WebviewViewProvider, options?: {
|
||||
webviewOptions?: {
|
||||
retainContextWhenHidden?: boolean
|
||||
}
|
||||
}) {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostWebviewViews.registerWebviewViewProvider(extension, viewId, provider, options?.webviewOptions);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -880,7 +889,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
|
||||
return undefined!;
|
||||
},
|
||||
stopDebugging(session: vscode.DebugSession | undefined) {
|
||||
stopDebugging(session?: vscode.DebugSession) {
|
||||
extHostLogService.warn('Debug API is disabled in Azure Data Studio');
|
||||
return undefined!;
|
||||
},
|
||||
@@ -975,10 +984,6 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookKernelProvider(extension, selector, provider);
|
||||
},
|
||||
registerNotebookOutputRenderer: (type: string, outputFilter: vscode.NotebookOutputSelector, renderer: vscode.NotebookOutputRenderer) => {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer);
|
||||
},
|
||||
get activeNotebookEditor(): vscode.NotebookEditor | undefined {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostNotebook.activeNotebookEditor;
|
||||
@@ -1047,6 +1052,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
ConfigurationTarget: extHostTypes.ConfigurationTarget,
|
||||
DebugAdapterExecutable: extHostTypes.DebugAdapterExecutable,
|
||||
DebugAdapterServer: extHostTypes.DebugAdapterServer,
|
||||
DebugAdapterNamedPipeServer: extHostTypes.DebugAdapterNamedPipeServer,
|
||||
DebugAdapterInlineImplementation: extHostTypes.DebugAdapterInlineImplementation,
|
||||
DecorationRangeBehavior: extHostTypes.DecorationRangeBehavior,
|
||||
Diagnostic: extHostTypes.Diagnostic,
|
||||
@@ -1064,8 +1070,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
EventEmitter: Emitter,
|
||||
ExtensionKind: extHostTypes.ExtensionKind,
|
||||
ExtensionMode: extHostTypes.ExtensionMode,
|
||||
ExtensionRuntime: extHostTypes.ExtensionRuntime,
|
||||
CustomExecution: extHostTypes.CustomExecution,
|
||||
CustomExecution2: extHostTypes.CustomExecution,
|
||||
FileChangeType: extHostTypes.FileChangeType,
|
||||
FileSystemError: extHostTypes.FileSystemError,
|
||||
FileType: files.FileType,
|
||||
|
||||
@@ -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 { INotebookMimeTypeSelector, IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, IOutputRenderRequest, IOutputRenderResponse, INotebookDocumentFilter, INotebookKernelInfoDto2 } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IProcessedOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent, NotebookDataDto, INotebookKernelInfoDto, IMainCellDto, INotebookDocumentFilter, INotebookKernelInfoDto2 } 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';
|
||||
@@ -452,8 +452,6 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
|
||||
$show(terminalId: number, preserveFocus: boolean): void;
|
||||
$startSendingDataEvents(): void;
|
||||
$stopSendingDataEvents(): void;
|
||||
$startHandlingLinks(): void;
|
||||
$stopHandlingLinks(): void;
|
||||
$startLinkProvider(): void;
|
||||
$stopLinkProvider(): void;
|
||||
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
|
||||
@@ -635,6 +633,11 @@ export interface MainThreadWebviewsShape extends IDisposable {
|
||||
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
|
||||
$onContentChange(resource: UriComponents, viewType: string): void;
|
||||
|
||||
$registerWebviewViewProvider(viewType: string, options?: { retainContextWhenHidden?: boolean }): void;
|
||||
$unregisterWebviewViewProvider(viewType: string): void;
|
||||
|
||||
$setWebviewViewTitle(handle: WebviewPanelHandle, value: string | undefined): void;
|
||||
}
|
||||
|
||||
export interface WebviewPanelViewStateData {
|
||||
@@ -650,9 +653,13 @@ export interface ExtHostWebviewsShape {
|
||||
$onMissingCsp(handle: WebviewPanelHandle, extensionId: string): void;
|
||||
$onDidChangeWebviewPanelViewStates(newState: WebviewPanelViewStateData): void;
|
||||
$onDidDisposeWebviewPanel(handle: WebviewPanelHandle): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostWebviewSerializerShape {
|
||||
$deserializeWebviewPanel(newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, state: any, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostCustomEditorsShape {
|
||||
$resolveWebviewEditor(resource: UriComponents, newWebviewHandle: WebviewPanelHandle, viewType: string, title: string, position: EditorViewColumn, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, cancellation: CancellationToken): Promise<void>;
|
||||
$createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken): Promise<{ editable: boolean }>;
|
||||
$disposeCustomDocument(resource: UriComponents, viewType: string): Promise<void>;
|
||||
@@ -670,6 +677,14 @@ export interface ExtHostWebviewsShape {
|
||||
$onMoveCustomEditor(handle: WebviewPanelHandle, newResource: UriComponents, viewType: string): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostWebviewViewsShape {
|
||||
$resolveWebviewView(webviewHandle: WebviewPanelHandle, viewType: string, state: any, cancellation: CancellationToken): Promise<void>;
|
||||
|
||||
$onDidChangeWebviewViewVisibility(webviewHandle: WebviewPanelHandle, visible: boolean): void;
|
||||
|
||||
$disposeWebviewView(webviewHandle: WebviewPanelHandle): void;
|
||||
}
|
||||
|
||||
export enum CellKind {
|
||||
Markdown = 1,
|
||||
Code = 2
|
||||
@@ -707,8 +722,6 @@ export interface MainThreadNotebookShape extends IDisposable {
|
||||
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string, supportBackup: boolean, kernelInfoDto: INotebookKernelInfoDto | undefined): Promise<void>;
|
||||
$onNotebookChange(viewType: string, resource: UriComponents): Promise<void>;
|
||||
$unregisterNotebookProvider(viewType: string): Promise<void>;
|
||||
$registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, preloads: UriComponents[]): Promise<void>;
|
||||
$unregisterNotebookRenderer(id: string): Promise<void>;
|
||||
$registerNotebookKernel(extension: NotebookExtensionDescription, id: string, label: string, selectors: (string | IRelativePattern)[], preloads: UriComponents[]): Promise<void>;
|
||||
$registerNotebookKernelProvider(extension: NotebookExtensionDescription, handle: number, documentFilter: INotebookDocumentFilter): Promise<void>;
|
||||
$unregisterNotebookKernelProvider(handle: number): Promise<void>;
|
||||
@@ -718,7 +731,7 @@ export interface MainThreadNotebookShape extends IDisposable {
|
||||
$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[], renderers: number[]): Promise<void>;
|
||||
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[]): Promise<void>;
|
||||
$postMessage(editorId: string, forRendererId: string | undefined, value: any): Promise<boolean>;
|
||||
|
||||
$onDidEdit(resource: UriComponents, viewType: string, editId: number, label: string | undefined): void;
|
||||
@@ -822,7 +835,8 @@ export type SCMRawResource = [
|
||||
UriComponents[] /*icons: light, dark*/,
|
||||
string /*tooltip*/,
|
||||
boolean /*strike through*/,
|
||||
boolean /*faded*/
|
||||
boolean /*faded*/,
|
||||
string /*context value*/
|
||||
];
|
||||
|
||||
export type SCMRawResourceSplice = [
|
||||
@@ -841,7 +855,7 @@ export interface MainThreadSCMShape extends IDisposable {
|
||||
$updateSourceControl(handle: number, features: SCMProviderFeatures): void;
|
||||
$unregisterSourceControl(handle: number): void;
|
||||
|
||||
$registerGroup(sourceControlHandle: number, handle: number, id: string, label: string): void;
|
||||
$registerGroups(sourceControlHandle: number, groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][], splices: SCMRawResourceSplices[]): void;
|
||||
$updateGroup(sourceControlHandle: number, handle: number, features: SCMGroupFeatures): void;
|
||||
$updateGroupLabel(sourceControlHandle: number, handle: number, label: string): void;
|
||||
$unregisterGroup(sourceControlHandle: number, handle: number): void;
|
||||
@@ -884,6 +898,7 @@ export interface MainThreadDebugServiceShape extends IDisposable {
|
||||
$stopDebugging(sessionId: DebugSessionUUID | undefined): Promise<void>;
|
||||
$setDebugSessionName(id: DebugSessionUUID, name: string): void;
|
||||
$customDebugAdapterRequest(id: DebugSessionUUID, command: string, args: any): Promise<any>;
|
||||
$getDebugProtocolBreakpoint(id: DebugSessionUUID, breakpoinId: string): Promise<DebugProtocol.Breakpoint | undefined>;
|
||||
$appendDebugConsole(value: string): void;
|
||||
$startBreakpointEvents(): void;
|
||||
$registerBreakpoints(breakpoints: Array<ISourceMultiBreakpointDto | IFunctionBreakpointDto | IDataBreakpointDto>): Promise<void>;
|
||||
@@ -1338,7 +1353,7 @@ export interface ExtHostLanguageFeaturesShape {
|
||||
$provideHover(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.Hover | undefined>;
|
||||
$provideEvaluatableExpression(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.EvaluatableExpression | undefined>;
|
||||
$provideDocumentHighlights(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<modes.DocumentHighlight[] | undefined>;
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IRange[] | undefined>;
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: IRegExpDto; } | undefined>;
|
||||
$provideReferences(handle: number, resource: UriComponents, position: IPosition, context: modes.ReferenceContext, token: CancellationToken): Promise<ILocationDto[] | undefined>;
|
||||
$provideCodeActions(handle: number, resource: UriComponents, rangeOrSelection: IRange | ISelection, context: modes.CodeActionContext, token: CancellationToken): Promise<ICodeActionListDto | undefined>;
|
||||
$releaseCodeActions(handle: number, cacheId: number): void;
|
||||
@@ -1438,7 +1453,6 @@ export interface ExtHostTerminalServiceShape {
|
||||
$acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
|
||||
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
|
||||
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
|
||||
$handleLink(id: number, link: string): Promise<boolean>;
|
||||
$provideLinks(id: number, line: string): Promise<ITerminalLinkDto[]>;
|
||||
$activateLink(id: number, linkId: number): void;
|
||||
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
|
||||
@@ -1455,7 +1469,7 @@ export interface ExtHostSCMShape {
|
||||
export interface ExtHostTaskShape {
|
||||
$provideTasks(handle: number, validTypes: { [key: string]: boolean; }): Thenable<tasks.TaskSetDTO>;
|
||||
$resolveTask(handle: number, taskDTO: tasks.TaskDTO): Thenable<tasks.TaskDTO | undefined>;
|
||||
$onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number): void;
|
||||
$onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number, resolvedDefinition: tasks.TaskDefinitionDTO): void;
|
||||
$onDidStartTaskProcess(value: tasks.TaskProcessStartedDTO): void;
|
||||
$onDidEndTaskProcess(value: tasks.TaskProcessEndedDTO): void;
|
||||
$OnDidEndTask(execution: tasks.TaskExecutionDTO): void;
|
||||
@@ -1633,13 +1647,11 @@ export interface ExtHostNotebookShape {
|
||||
$backup(viewType: string, uri: UriComponents, cancellation: CancellationToken): Promise<string | undefined>;
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
|
||||
$acceptNotebookActiveKernelChange(event: { uri: UriComponents, providerHandle: number | undefined, kernelId: string | undefined }): void;
|
||||
$renderOutputs(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<UriComponents>): Promise<IOutputRenderResponse<UriComponents> | undefined>;
|
||||
$renderOutputs2<T>(uriComponents: UriComponents, id: string, request: IOutputRenderRequest<T>): Promise<IOutputRenderResponse<T> | undefined>;
|
||||
$onDidReceiveMessage(editorId: string, rendererId: string | undefined, message: unknown): void;
|
||||
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
|
||||
$acceptModelSaved(uriComponents: UriComponents): void;
|
||||
$acceptEditorPropertiesChanged(uriComponents: UriComponents, data: INotebookEditorPropertiesChangeData): void;
|
||||
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): Promise<void>;
|
||||
$acceptDocumentAndEditorsDelta(delta: INotebookDocumentsAndEditorsDelta): void;
|
||||
$undoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
|
||||
$redoNotebook(viewType: string, uri: UriComponents, editId: number, isDirty: boolean): Promise<void>;
|
||||
|
||||
@@ -1741,6 +1753,9 @@ export const ExtHostContext = {
|
||||
ExtHostWorkspace: createExtId<ExtHostWorkspaceShape>('ExtHostWorkspace'),
|
||||
ExtHostWindow: createExtId<ExtHostWindowShape>('ExtHostWindow'),
|
||||
ExtHostWebviews: createExtId<ExtHostWebviewsShape>('ExtHostWebviews'),
|
||||
ExtHostWebviewSerializer: createExtId<ExtHostWebviewSerializerShape>('ExtHostWebviewSerializer'),
|
||||
ExtHostCustomEditors: createExtId<ExtHostCustomEditorsShape>('ExtHostCustomEditors'),
|
||||
ExtHostWebviewViews: createExtId<ExtHostWebviewViewsShape>('ExtHostWebviewViews'),
|
||||
ExtHostEditorInsets: createExtId<ExtHostEditorInsetsShape>('ExtHostEditorInsets'),
|
||||
ExtHostProgress: createMainId<ExtHostProgressShape>('ExtHostProgress'),
|
||||
ExtHostComments: createMainId<ExtHostCommentsShape>('ExtHostComments'),
|
||||
|
||||
385
src/vs/workbench/api/common/extHostCustomEditors.ts
Normal file
385
src/vs/workbench/api/common/extHostCustomEditors.ts
Normal file
@@ -0,0 +1,385 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import { ExtHostWebviews, toExtensionData } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import type * as vscode from 'vscode';
|
||||
import { Cache } from './cache';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import * as extHostTypes from './extHostTypes';
|
||||
|
||||
|
||||
class CustomDocumentStoreEntry {
|
||||
|
||||
private _backupCounter = 1;
|
||||
|
||||
constructor(
|
||||
public readonly document: vscode.CustomDocument,
|
||||
private readonly _storagePath: URI | undefined,
|
||||
) { }
|
||||
|
||||
private readonly _edits = new Cache<vscode.CustomDocumentEditEvent>('custom documents');
|
||||
|
||||
private _backup?: vscode.CustomDocumentBackup;
|
||||
|
||||
addEdit(item: vscode.CustomDocumentEditEvent): 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();
|
||||
}
|
||||
}
|
||||
|
||||
disposeEdits(editIds: number[]): void {
|
||||
for (const id of editIds) {
|
||||
this._edits.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
getNewBackupUri(): URI {
|
||||
if (!this._storagePath) {
|
||||
throw new Error('Backup requires a valid storage path');
|
||||
}
|
||||
const fileName = hashPath(this.document.uri) + (this._backupCounter++);
|
||||
return joinPath(this._storagePath, fileName);
|
||||
}
|
||||
|
||||
updateBackup(backup: vscode.CustomDocumentBackup): void {
|
||||
this._backup?.delete();
|
||||
this._backup = backup;
|
||||
}
|
||||
|
||||
disposeBackup(): void {
|
||||
this._backup?.delete();
|
||||
this._backup = undefined;
|
||||
}
|
||||
|
||||
private getEdit(editId: number): vscode.CustomDocumentEditEvent {
|
||||
const edit = this._edits.get(editId, 0);
|
||||
if (!edit) {
|
||||
throw new Error('No edit found');
|
||||
}
|
||||
return edit;
|
||||
}
|
||||
}
|
||||
|
||||
class CustomDocumentStore {
|
||||
private readonly _documents = new Map<string, CustomDocumentStoreEntry>();
|
||||
|
||||
public get(viewType: string, resource: vscode.Uri): CustomDocumentStoreEntry | undefined {
|
||||
return this._documents.get(this.key(viewType, resource));
|
||||
}
|
||||
|
||||
public add(viewType: string, document: vscode.CustomDocument, storagePath: URI | undefined): CustomDocumentStoreEntry {
|
||||
const key = this.key(viewType, document.uri);
|
||||
if (this._documents.has(key)) {
|
||||
throw new Error(`Document already exists for viewType:${viewType} resource:${document.uri}`);
|
||||
}
|
||||
const entry = new CustomDocumentStoreEntry(document, storagePath);
|
||||
this._documents.set(key, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public delete(viewType: string, document: vscode.CustomDocument) {
|
||||
const key = this.key(viewType, document.uri);
|
||||
this._documents.delete(key);
|
||||
}
|
||||
|
||||
private key(viewType: string, resource: vscode.Uri): string {
|
||||
return `${viewType}@@@${resource}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const enum WebviewEditorType {
|
||||
Text,
|
||||
Custom
|
||||
}
|
||||
|
||||
type ProviderEntry = {
|
||||
readonly extension: IExtensionDescription;
|
||||
readonly type: WebviewEditorType.Text;
|
||||
readonly provider: vscode.CustomTextEditorProvider;
|
||||
} | {
|
||||
readonly extension: IExtensionDescription;
|
||||
readonly type: WebviewEditorType.Custom;
|
||||
readonly provider: vscode.CustomReadonlyEditorProvider;
|
||||
};
|
||||
|
||||
class EditorProviderStore {
|
||||
private readonly _providers = new Map<string, ProviderEntry>();
|
||||
|
||||
public addTextProvider(viewType: string, extension: IExtensionDescription, provider: vscode.CustomTextEditorProvider): vscode.Disposable {
|
||||
return this.add(WebviewEditorType.Text, viewType, extension, provider);
|
||||
}
|
||||
|
||||
public addCustomProvider(viewType: string, extension: IExtensionDescription, provider: vscode.CustomReadonlyEditorProvider): vscode.Disposable {
|
||||
return this.add(WebviewEditorType.Custom, viewType, extension, provider);
|
||||
}
|
||||
|
||||
public get(viewType: string): ProviderEntry | undefined {
|
||||
return this._providers.get(viewType);
|
||||
}
|
||||
|
||||
private add(type: WebviewEditorType, viewType: string, extension: IExtensionDescription, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider): vscode.Disposable {
|
||||
if (this._providers.has(viewType)) {
|
||||
throw new Error(`Provider for viewType:${viewType} already registered`);
|
||||
}
|
||||
this._providers.set(viewType, { type, extension, provider } as ProviderEntry);
|
||||
return new extHostTypes.Disposable(() => this._providers.delete(viewType));
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostCustomEditors implements extHostProtocol.ExtHostCustomEditorsShape {
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
private readonly _editorProviders = new EditorProviderStore();
|
||||
|
||||
private readonly _documents = new CustomDocumentStore();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
private readonly _extHostDocuments: ExtHostDocuments,
|
||||
private readonly _extensionStoragePaths: IExtensionStoragePaths | undefined,
|
||||
private readonly _extHostWebview: ExtHostWebviews,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
public registerCustomEditorProvider(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
provider: vscode.CustomReadonlyEditorProvider | vscode.CustomTextEditorProvider,
|
||||
options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean },
|
||||
): vscode.Disposable {
|
||||
const disposables = new DisposableStore();
|
||||
if ('resolveCustomTextEditor' in provider) {
|
||||
disposables.add(this._editorProviders.addTextProvider(viewType, extension, provider));
|
||||
this._proxy.$registerTextEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, {
|
||||
supportsMove: !!provider.moveCustomTextEditor,
|
||||
});
|
||||
} else {
|
||||
disposables.add(this._editorProviders.addCustomProvider(viewType, extension, provider));
|
||||
|
||||
if (this.supportEditing(provider)) {
|
||||
disposables.add(provider.onDidChangeCustomDocument(e => {
|
||||
const entry = this.getCustomDocumentEntry(viewType, e.document.uri);
|
||||
if (isEditEvent(e)) {
|
||||
const editId = entry.addEdit(e);
|
||||
this._proxy.$onDidEdit(e.document.uri, viewType, editId, e.label);
|
||||
} else {
|
||||
this._proxy.$onContentChange((e as vscode.CustomDocumentContentChangeEvent).document.uri, viewType); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this._proxy.$registerCustomEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, !!options.supportsMultipleEditorsPerDocument);
|
||||
}
|
||||
|
||||
return extHostTypes.Disposable.from(
|
||||
disposables,
|
||||
new extHostTypes.Disposable(() => {
|
||||
this._proxy.$unregisterEditorProvider(viewType);
|
||||
}));
|
||||
}
|
||||
|
||||
|
||||
async $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken) {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
if (entry.type !== WebviewEditorType.Custom) {
|
||||
throw new Error(`Invalid provide type for '${viewType}'`);
|
||||
}
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const document = await entry.provider.openCustomDocument(revivedResource, { backupId }, cancellation);
|
||||
|
||||
let storageRoot: URI | undefined;
|
||||
if (this.supportEditing(entry.provider) && this._extensionStoragePaths) {
|
||||
storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension);
|
||||
}
|
||||
this._documents.add(viewType, document, storageRoot);
|
||||
|
||||
return { editable: this.supportEditing(entry.provider) };
|
||||
}
|
||||
|
||||
async $disposeCustomDocument(resource: UriComponents, viewType: string): Promise<void> {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
if (entry.type !== WebviewEditorType.Custom) {
|
||||
throw new Error(`Invalid provider type for '${viewType}'`);
|
||||
}
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const { document } = this.getCustomDocumentEntry(viewType, revivedResource);
|
||||
this._documents.delete(viewType, document);
|
||||
document.dispose();
|
||||
}
|
||||
|
||||
async $resolveWebviewEditor(
|
||||
resource: UriComponents,
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions,
|
||||
cancellation: CancellationToken,
|
||||
): Promise<void> {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
const webview = this._extHostWebview.createNewWebview(handle, options, entry.extension);
|
||||
const panel = this._extHostWebview.createNewWebviewPanel(handle, viewType, title, position, options, webview);
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
|
||||
switch (entry.type) {
|
||||
case WebviewEditorType.Custom:
|
||||
{
|
||||
const { document } = this.getCustomDocumentEntry(viewType, revivedResource);
|
||||
return entry.provider.resolveCustomEditor(document, panel, cancellation);
|
||||
}
|
||||
case WebviewEditorType.Text:
|
||||
{
|
||||
const document = this._extHostDocuments.getDocument(revivedResource);
|
||||
return entry.provider.resolveCustomTextEditor(document, panel, cancellation);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new Error('Unknown webview provider type');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void {
|
||||
const document = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
document.disposeEdits(editIds);
|
||||
}
|
||||
|
||||
async $onMoveCustomEditor(handle: string, newResourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
if (!(entry.provider as vscode.CustomTextEditorProvider).moveCustomTextEditor) {
|
||||
throw new Error(`Provider does not implement move '${viewType}'`);
|
||||
}
|
||||
|
||||
const webview = this._extHostWebview.getWebviewPanel(handle);
|
||||
if (!webview) {
|
||||
throw new Error(`No webview found`);
|
||||
}
|
||||
|
||||
const resource = URI.revive(newResourceComponents);
|
||||
const document = this._extHostDocuments.getDocument(resource);
|
||||
await (entry.provider as vscode.CustomTextEditorProvider).moveCustomTextEditor!(document, webview, CancellationToken.None);
|
||||
}
|
||||
|
||||
async $undo(resourceComponents: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
return entry.undo(editId, isDirty);
|
||||
}
|
||||
|
||||
async $redo(resourceComponents: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
return entry.redo(editId, isDirty);
|
||||
}
|
||||
|
||||
async $revert(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
await provider.revertCustomDocument(entry.document, cancellation);
|
||||
entry.disposeBackup();
|
||||
}
|
||||
|
||||
async $onSave(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
await provider.saveCustomDocument(entry.document, cancellation);
|
||||
entry.disposeBackup();
|
||||
}
|
||||
|
||||
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
return provider.saveCustomDocumentAs(entry.document, URI.revive(targetResource), cancellation);
|
||||
}
|
||||
|
||||
async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<string> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
|
||||
const backup = await provider.backupCustomDocument(entry.document, {
|
||||
destination: entry.getNewBackupUri(),
|
||||
}, cancellation);
|
||||
entry.updateBackup(backup);
|
||||
return backup.id;
|
||||
}
|
||||
|
||||
|
||||
private getCustomDocumentEntry(viewType: string, resource: UriComponents): CustomDocumentStoreEntry {
|
||||
const entry = this._documents.get(viewType, URI.revive(resource));
|
||||
if (!entry) {
|
||||
throw new Error('No custom document found');
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
private getCustomEditorProvider(viewType: string): vscode.CustomEditorProvider {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
const provider = entry?.provider;
|
||||
if (!provider || !this.supportEditing(provider)) {
|
||||
throw new Error('Custom document is not editable');
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
private supportEditing(
|
||||
provider: vscode.CustomTextEditorProvider | vscode.CustomEditorProvider | vscode.CustomReadonlyEditorProvider
|
||||
): provider is vscode.CustomEditorProvider {
|
||||
return !!(provider as vscode.CustomEditorProvider).onDidChangeCustomDocument;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
function isEditEvent(e: vscode.CustomDocumentContentChangeEvent | vscode.CustomDocumentEditEvent): e is vscode.CustomDocumentEditEvent {
|
||||
return typeof (e as vscode.CustomDocumentEditEvent).undo === 'function'
|
||||
&& typeof (e as vscode.CustomDocumentEditEvent).redo === 'function';
|
||||
}
|
||||
|
||||
function hashPath(resource: URI): string {
|
||||
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
|
||||
return hash(str) + '';
|
||||
}
|
||||
@@ -11,12 +11,12 @@ import {
|
||||
MainContext, MainThreadDebugServiceShape, ExtHostDebugServiceShape, DebugSessionUUID,
|
||||
IBreakpointsDeltaDto, ISourceMultiBreakpointDto, IFunctionBreakpointDto, IDebugSessionDto
|
||||
} from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable, DataBreakpoint, DebugConsoleMode, DebugAdapterInlineImplementation } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { Disposable, Position, Location, SourceBreakpoint, FunctionBreakpoint, DebugAdapterServer, DebugAdapterExecutable, DataBreakpoint, DebugConsoleMode, DebugAdapterInlineImplementation, DebugAdapterNamedPipeServer } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { AbstractDebugAdapter } from 'vs/workbench/contrib/debug/common/abstractDebugAdapter';
|
||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { IExtHostExtensionService } from 'vs/workbench/api/common/extHostExtensionService';
|
||||
import { ExtHostDocumentsAndEditors, IExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor, IDebugAdapterImpl } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IDebuggerContribution, IConfig, IDebugAdapter, IDebugAdapterServer, IDebugAdapterExecutable, IAdapterDescriptor, IDebugAdapterImpl, IDebugAdapterNamedPipeServer } from 'vs/workbench/contrib/debug/common/debug';
|
||||
import { IWorkspaceFolder } from 'vs/platform/workspace/common/workspace';
|
||||
import { AbstractVariableResolverService } from 'vs/workbench/services/configurationResolver/common/variableResolver';
|
||||
import { ExtHostConfigProvider, IExtHostConfiguration } from '../common/extHostConfiguration';
|
||||
@@ -51,7 +51,7 @@ export interface IExtHostDebugService extends ExtHostDebugServiceShape {
|
||||
addBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void>;
|
||||
removeBreakpoints(breakpoints0: vscode.Breakpoint[]): Promise<void>;
|
||||
startDebugging(folder: vscode.WorkspaceFolder | undefined, nameOrConfig: string | vscode.DebugConfiguration, options: vscode.DebugSessionOptions): Promise<boolean>;
|
||||
stopDebugging(session: vscode.DebugSession | undefined): Promise<void>;
|
||||
stopDebugging(session?: vscode.DebugSession): Promise<void>;
|
||||
registerDebugConfigurationProvider(type: string, provider: vscode.DebugConfigurationProvider, trigger: vscode.DebugConfigurationProviderTriggerKind): vscode.Disposable;
|
||||
registerDebugAdapterDescriptorFactory(extension: IExtensionDescription, type: string, factory: vscode.DebugAdapterDescriptorFactory): vscode.Disposable;
|
||||
registerDebugAdapterTrackerFactory(type: string, factory: vscode.DebugAdapterTrackerFactory): vscode.Disposable;
|
||||
@@ -302,7 +302,7 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
|
||||
});
|
||||
}
|
||||
|
||||
public stopDebugging(session: vscode.DebugSession | undefined): Promise<void> {
|
||||
public stopDebugging(session?: vscode.DebugSession): Promise<void> {
|
||||
return this._debugServiceProxy.$stopDebugging(session ? session.id : undefined);
|
||||
}
|
||||
|
||||
@@ -737,6 +737,11 @@ export abstract class ExtHostDebugServiceBase implements IExtHostDebugService, E
|
||||
port: x.port,
|
||||
host: x.host
|
||||
};
|
||||
} else if (x instanceof DebugAdapterNamedPipeServer) {
|
||||
return <IDebugAdapterNamedPipeServer>{
|
||||
type: 'pipeServer',
|
||||
path: x.path
|
||||
};
|
||||
} else if (x instanceof DebugAdapterInlineImplementation) {
|
||||
return <IDebugAdapterImpl>{
|
||||
type: 'implementation',
|
||||
@@ -957,6 +962,10 @@ export class ExtHostDebugSession implements vscode.DebugSession {
|
||||
public customRequest(command: string, args: any): Promise<any> {
|
||||
return this._debugServiceProxy.$customDebugAdapterRequest(this._id, command, args);
|
||||
}
|
||||
|
||||
public getDebugProtocolBreakpoint(breakpoint: vscode.Breakpoint): Promise<vscode.DebugProtocolBreakpoint | undefined> {
|
||||
return this._debugServiceProxy.$getDebugProtocolBreakpoint(this._id, breakpoint.id);
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostDebugConsole implements vscode.DebugConsole {
|
||||
|
||||
@@ -29,19 +29,17 @@ export function getWordDefinitionFor(modeId: string): RegExp | undefined {
|
||||
|
||||
export class ExtHostDocumentData extends MirrorTextModel {
|
||||
|
||||
private _proxy: MainThreadDocumentsShape;
|
||||
private _languageId: string;
|
||||
private _isDirty: boolean;
|
||||
private _document?: vscode.TextDocument;
|
||||
private _isDisposed: boolean = false;
|
||||
|
||||
constructor(proxy: MainThreadDocumentsShape, uri: URI, lines: string[], eol: string,
|
||||
languageId: string, versionId: number, isDirty: boolean
|
||||
constructor(
|
||||
private readonly _proxy: MainThreadDocumentsShape,
|
||||
uri: URI, lines: string[], eol: string, versionId: number,
|
||||
private _languageId: string,
|
||||
private _isDirty: boolean,
|
||||
private readonly _notebook?: vscode.NotebookDocument | undefined
|
||||
) {
|
||||
super(uri, lines, eol, versionId);
|
||||
this._proxy = proxy;
|
||||
this._languageId = languageId;
|
||||
this._isDirty = isDirty;
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
@@ -59,25 +57,26 @@ export class ExtHostDocumentData extends MirrorTextModel {
|
||||
|
||||
get document(): vscode.TextDocument {
|
||||
if (!this._document) {
|
||||
const data = this;
|
||||
const that = this;
|
||||
this._document = {
|
||||
get uri() { return data._uri; },
|
||||
get fileName() { return data._uri.fsPath; },
|
||||
get isUntitled() { return data._uri.scheme === Schemas.untitled; },
|
||||
get languageId() { return data._languageId; },
|
||||
get version() { return data._versionId; },
|
||||
get isClosed() { return data._isDisposed; },
|
||||
get isDirty() { return data._isDirty; },
|
||||
save() { return data._save(); },
|
||||
getText(range?) { return range ? data._getTextInRange(range) : data.getText(); },
|
||||
get eol() { return data._eol === '\n' ? EndOfLine.LF : EndOfLine.CRLF; },
|
||||
get lineCount() { return data._lines.length; },
|
||||
lineAt(lineOrPos: number | vscode.Position) { return data._lineAt(lineOrPos); },
|
||||
offsetAt(pos) { return data._offsetAt(pos); },
|
||||
positionAt(offset) { return data._positionAt(offset); },
|
||||
validateRange(ran) { return data._validateRange(ran); },
|
||||
validatePosition(pos) { return data._validatePosition(pos); },
|
||||
getWordRangeAtPosition(pos, regexp?) { return data._getWordRangeAtPosition(pos, regexp); }
|
||||
get uri() { return that._uri; },
|
||||
get fileName() { return that._uri.fsPath; },
|
||||
get isUntitled() { return that._uri.scheme === Schemas.untitled; },
|
||||
get languageId() { return that._languageId; },
|
||||
get version() { return that._versionId; },
|
||||
get isClosed() { return that._isDisposed; },
|
||||
get isDirty() { return that._isDirty; },
|
||||
get notebook() { return that._notebook; },
|
||||
save() { return that._save(); },
|
||||
getText(range?) { return range ? that._getTextInRange(range) : that.getText(); },
|
||||
get eol() { return that._eol === '\n' ? EndOfLine.LF : EndOfLine.CRLF; },
|
||||
get lineCount() { return that._lines.length; },
|
||||
lineAt(lineOrPos: number | vscode.Position) { return that._lineAt(lineOrPos); },
|
||||
offsetAt(pos) { return that._offsetAt(pos); },
|
||||
positionAt(offset) { return that._positionAt(offset); },
|
||||
validateRange(ran) { return that._validateRange(ran); },
|
||||
validatePosition(pos) { return that._validatePosition(pos); },
|
||||
getWordRangeAtPosition(pos, regexp?) { return that._getWordRangeAtPosition(pos, regexp); },
|
||||
};
|
||||
}
|
||||
return Object.freeze(this._document);
|
||||
|
||||
@@ -53,7 +53,7 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
}
|
||||
|
||||
public getAllDocumentData(): ExtHostDocumentData[] {
|
||||
return this._documentsAndEditors.allDocuments();
|
||||
return [...this._documentsAndEditors.allDocuments()];
|
||||
}
|
||||
|
||||
public getDocumentData(resource: vscode.Uri): ExtHostDocumentData | undefined {
|
||||
@@ -69,8 +69,8 @@ export class ExtHostDocuments implements ExtHostDocumentsShape {
|
||||
|
||||
public getDocument(resource: vscode.Uri): vscode.TextDocument {
|
||||
const data = this.getDocumentData(resource);
|
||||
if (!data || !data.document) {
|
||||
throw new Error('Unable to retrieve document from URI');
|
||||
if (!data?.document) {
|
||||
throw new Error(`Unable to retrieve document from URI '${resource}'`);
|
||||
}
|
||||
return data.document;
|
||||
}
|
||||
|
||||
@@ -4,17 +4,39 @@
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as assert from 'vs/base/common/assert';
|
||||
import * as vscode from 'vscode';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { dispose } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentsAndEditorsShape, IDocumentsAndEditorsDelta, IModelAddedData, MainContext } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { ExtHostDocumentData } from 'vs/workbench/api/common/extHostDocumentData';
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { ExtHostTextEditor } from 'vs/workbench/api/common/extHostTextEditor';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { ResourceMap } from 'vs/base/common/map';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { Iterable } from 'vs/base/common/iterator';
|
||||
|
||||
class Reference<T> {
|
||||
private _count = 0;
|
||||
constructor(readonly value: T) { }
|
||||
ref() {
|
||||
this._count++;
|
||||
}
|
||||
unref() {
|
||||
return --this._count === 0;
|
||||
}
|
||||
}
|
||||
|
||||
export interface IExtHostModelAddedData extends IModelAddedData {
|
||||
notebook?: vscode.NotebookDocument;
|
||||
}
|
||||
|
||||
export interface IExtHostDocumentsAndEditorsDelta extends IDocumentsAndEditorsDelta {
|
||||
addedDocuments?: IExtHostModelAddedData[];
|
||||
}
|
||||
|
||||
export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsShape {
|
||||
|
||||
@@ -23,7 +45,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
private _activeEditorId: string | null = null;
|
||||
|
||||
private readonly _editors = new Map<string, ExtHostTextEditor>();
|
||||
private readonly _documents = new ResourceMap<ExtHostDocumentData>();
|
||||
private readonly _documents = new ResourceMap<Reference<ExtHostDocumentData>>();
|
||||
|
||||
private readonly _onDidAddDocuments = new Emitter<ExtHostDocumentData[]>();
|
||||
private readonly _onDidRemoveDocuments = new Emitter<ExtHostDocumentData[]>();
|
||||
@@ -41,6 +63,10 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
) { }
|
||||
|
||||
$acceptDocumentsAndEditorsDelta(delta: IDocumentsAndEditorsDelta): void {
|
||||
this.acceptDocumentsAndEditorsDelta(delta);
|
||||
}
|
||||
|
||||
acceptDocumentsAndEditorsDelta(delta: IExtHostDocumentsAndEditorsDelta): void {
|
||||
|
||||
const removedDocuments: ExtHostDocumentData[] = [];
|
||||
const addedDocuments: ExtHostDocumentData[] = [];
|
||||
@@ -50,9 +76,9 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
for (const uriComponent of delta.removedDocuments) {
|
||||
const uri = URI.revive(uriComponent);
|
||||
const data = this._documents.get(uri);
|
||||
this._documents.delete(uri);
|
||||
if (data) {
|
||||
removedDocuments.push(data);
|
||||
if (data?.unref()) {
|
||||
this._documents.delete(uri);
|
||||
removedDocuments.push(data.value);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -60,19 +86,31 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
if (delta.addedDocuments) {
|
||||
for (const data of delta.addedDocuments) {
|
||||
const resource = URI.revive(data.uri);
|
||||
assert.ok(!this._documents.has(resource), `document '${resource} already exists!'`);
|
||||
let ref = this._documents.get(resource);
|
||||
|
||||
const documentData = new ExtHostDocumentData(
|
||||
this._extHostRpc.getProxy(MainContext.MainThreadDocuments),
|
||||
resource,
|
||||
data.lines,
|
||||
data.EOL,
|
||||
data.modeId,
|
||||
data.versionId,
|
||||
data.isDirty
|
||||
);
|
||||
this._documents.set(resource, documentData);
|
||||
addedDocuments.push(documentData);
|
||||
// double check -> only notebook cell documents should be
|
||||
// referenced/opened more than once...
|
||||
if (ref) {
|
||||
if (resource.scheme !== Schemas.vscodeNotebookCell) {
|
||||
throw new Error(`document '${resource} already exists!'`);
|
||||
}
|
||||
}
|
||||
if (!ref) {
|
||||
ref = new Reference(new ExtHostDocumentData(
|
||||
this._extHostRpc.getProxy(MainContext.MainThreadDocuments),
|
||||
resource,
|
||||
data.lines,
|
||||
data.EOL,
|
||||
data.versionId,
|
||||
data.modeId,
|
||||
data.isDirty,
|
||||
data.notebook
|
||||
));
|
||||
this._documents.set(resource, ref);
|
||||
addedDocuments.push(ref.value);
|
||||
}
|
||||
|
||||
ref.ref();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -92,7 +130,7 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
assert.ok(this._documents.has(resource), `document '${resource}' does not exist`);
|
||||
assert.ok(!this._editors.has(data.id), `editor '${data.id}' already exists!`);
|
||||
|
||||
const documentData = this._documents.get(resource)!;
|
||||
const documentData = this._documents.get(resource)!.value;
|
||||
const editor = new ExtHostTextEditor(
|
||||
data.id,
|
||||
this._extHostRpc.getProxy(MainContext.MainThreadTextEditors),
|
||||
@@ -132,11 +170,11 @@ export class ExtHostDocumentsAndEditors implements ExtHostDocumentsAndEditorsSha
|
||||
}
|
||||
|
||||
getDocument(uri: URI): ExtHostDocumentData | undefined {
|
||||
return this._documents.get(uri);
|
||||
return this._documents.get(uri)?.value;
|
||||
}
|
||||
|
||||
allDocuments(): ExtHostDocumentData[] {
|
||||
return [...this._documents.values()];
|
||||
allDocuments(): Iterable<ExtHostDocumentData> {
|
||||
return Iterable.map(this._documents.values(), ref => ref.value);
|
||||
}
|
||||
|
||||
getEditor(id: string): ExtHostTextEditor | undefined {
|
||||
|
||||
@@ -25,7 +25,7 @@ import { ExtensionIdentifier, IExtensionDescription } from 'vs/platform/extensio
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { ExtensionMemento } from 'vs/workbench/api/common/extHostMemento';
|
||||
import { RemoteAuthorityResolverError, ExtensionMode } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { RemoteAuthorityResolverError, ExtensionMode, ExtensionRuntime } from 'vs/workbench/api/common/extHostTypes';
|
||||
import { ResolvedAuthority, ResolvedOptions, RemoteAuthorityResolverErrorCode, IRemoteConnectionData } from 'vs/platform/remote/common/remoteAuthorityResolver';
|
||||
import { IInstantiationService, createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
@@ -71,6 +71,7 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
|
||||
readonly _serviceBrand: undefined;
|
||||
|
||||
abstract readonly extensionRuntime: ExtensionRuntime;
|
||||
|
||||
private readonly _onDidChangeRemoteConnectionData = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeRemoteConnectionData = this._onDidChangeRemoteConnectionData.event;
|
||||
@@ -395,19 +396,14 @@ export abstract class AbstractExtHostExtensionService extends Disposable impleme
|
||||
get storagePath() { return that._storagePath.workspaceValue(extensionDescription)?.fsPath; },
|
||||
get globalStoragePath() { return that._storagePath.globalValue(extensionDescription).fsPath; },
|
||||
get logPath() { return path.join(that._initData.logsLocation.fsPath, extensionDescription.identifier.value); },
|
||||
get logUri() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return URI.joinPath(that._initData.logsLocation, extensionDescription.identifier.value);
|
||||
},
|
||||
get storageUri() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that._storagePath.workspaceValue(extensionDescription);
|
||||
},
|
||||
get globalStorageUri() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that._storagePath.globalValue(extensionDescription);
|
||||
},
|
||||
get logUri() { return URI.joinPath(that._initData.logsLocation, extensionDescription.identifier.value); },
|
||||
get storageUri() { return that._storagePath.workspaceValue(extensionDescription); },
|
||||
get globalStorageUri() { return that._storagePath.globalValue(extensionDescription); },
|
||||
get extensionMode() { return extensionMode; },
|
||||
get extensionRuntime() {
|
||||
checkProposedApiEnabled(extensionDescription);
|
||||
return that.extensionRuntime;
|
||||
},
|
||||
get environmentVariableCollection() { return that._extHostTerminalService.getEnvironmentVariableCollection(extensionDescription); }
|
||||
});
|
||||
});
|
||||
|
||||
@@ -324,14 +324,17 @@ class OnTypeRenameAdapter {
|
||||
private readonly _provider: vscode.OnTypeRenameProvider
|
||||
) { }
|
||||
|
||||
provideOnTypeRenameRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<IRange[] | undefined> {
|
||||
provideOnTypeRenameRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: RegExp; } | undefined> {
|
||||
|
||||
const doc = this._documents.getDocument(resource);
|
||||
const pos = typeConvert.Position.to(position);
|
||||
|
||||
return asPromise(() => this._provider.provideOnTypeRenameRanges(doc, pos, token)).then(value => {
|
||||
if (Array.isArray(value)) {
|
||||
return coalesce(value.map(typeConvert.Range.from));
|
||||
if (value && Array.isArray(value.ranges)) {
|
||||
return {
|
||||
ranges: coalesce(value.ranges.map(typeConvert.Range.from)),
|
||||
wordPattern: value.wordPattern
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
@@ -1549,15 +1552,24 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
||||
|
||||
// --- on type rename
|
||||
|
||||
registerOnTypeRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider, stopPattern?: RegExp): vscode.Disposable {
|
||||
registerOnTypeRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider, wordPattern?: RegExp): vscode.Disposable {
|
||||
const handle = this._addNewAdapter(new OnTypeRenameAdapter(this._documents, provider), extension);
|
||||
const serializedStopPattern = stopPattern ? ExtHostLanguageFeatures._serializeRegExp(stopPattern) : undefined;
|
||||
this._proxy.$registerOnTypeRenameProvider(handle, this._transformDocumentSelector(selector), serializedStopPattern);
|
||||
const serializedWordPattern = wordPattern ? ExtHostLanguageFeatures._serializeRegExp(wordPattern) : undefined;
|
||||
this._proxy.$registerOnTypeRenameProvider(handle, this._transformDocumentSelector(selector), serializedWordPattern);
|
||||
return this._createDisposable(handle);
|
||||
}
|
||||
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<IRange[] | undefined> {
|
||||
return this._withAdapter(handle, OnTypeRenameAdapter, adapter => adapter.provideOnTypeRenameRanges(URI.revive(resource), position, token), undefined);
|
||||
$provideOnTypeRenameRanges(handle: number, resource: UriComponents, position: IPosition, token: CancellationToken): Promise<{ ranges: IRange[]; wordPattern?: extHostProtocol.IRegExpDto; } | undefined> {
|
||||
return this._withAdapter(handle, OnTypeRenameAdapter, async adapter => {
|
||||
const res = await adapter.provideOnTypeRenameRanges(URI.revive(resource), position, token);
|
||||
if (res) {
|
||||
return {
|
||||
ranges: res.ranges,
|
||||
wordPattern: res.wordPattern ? ExtHostLanguageFeatures._serializeRegExp(res.wordPattern) : undefined
|
||||
};
|
||||
}
|
||||
return undefined;
|
||||
}, undefined);
|
||||
}
|
||||
|
||||
// --- references
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -6,7 +6,7 @@
|
||||
import * as types from 'vs/workbench/api/common/extHostTypes';
|
||||
import * as vscode from 'vscode';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { ExtHostNotebookController, ExtHostCell } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { PrefixSumComputer } from 'vs/editor/common/viewModel/prefixSumComputer';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
@@ -21,7 +21,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
|
||||
private _disposables = new DisposableStore();
|
||||
private _isClosed = false;
|
||||
|
||||
private _cells!: ExtHostCell[];
|
||||
private _cells!: vscode.NotebookCell[];
|
||||
private _cellUris!: ResourceMap<number>;
|
||||
private _cellLengths!: PrefixSumComputer;
|
||||
private _cellLines!: PrefixSumComputer;
|
||||
@@ -78,7 +78,7 @@ export class ExtHostNotebookConcatDocument implements vscode.NotebookConcatTextD
|
||||
for (const cell of this._notebook.cells) {
|
||||
if (cell.cellKind === CellKind.Code && (!this._selector || score(this._selector, cell.uri, cell.language, true))) {
|
||||
this._cellUris.set(cell.uri, this._cells.length);
|
||||
this._cells.push(<ExtHostCell>cell);
|
||||
this._cells.push(cell);
|
||||
cellLengths.push(cell.document.getText().length + 1);
|
||||
cellLineCounts.push(cell.document.lineCount);
|
||||
}
|
||||
|
||||
@@ -6,10 +6,10 @@
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Event, Emitter } from 'vs/base/common/event';
|
||||
import { debounce } from 'vs/base/common/decorators';
|
||||
import { DisposableStore, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { DisposableStore, IDisposable, MutableDisposable } from 'vs/base/common/lifecycle';
|
||||
import { asPromise } from 'vs/base/common/async';
|
||||
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
|
||||
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto, MainThreadTelemetryShape } from './extHost.protocol';
|
||||
import { MainContext, MainThreadSCMShape, SCMRawResource, SCMRawResourceSplice, SCMRawResourceSplices, IMainContext, ExtHostSCMShape, ICommandDto, MainThreadTelemetryShape, SCMGroupFeatures } from './extHost.protocol';
|
||||
import { sortedDiff, equals } from 'vs/base/common/arrays';
|
||||
import { comparePaths } from 'vs/base/common/comparers';
|
||||
import type * as vscode from 'vscode';
|
||||
@@ -228,6 +228,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
|
||||
private readonly _onDidUpdateResourceStates = new Emitter<void>();
|
||||
readonly onDidUpdateResourceStates = this._onDidUpdateResourceStates.event;
|
||||
|
||||
private _disposed = false;
|
||||
get disposed(): boolean { return this._disposed; }
|
||||
private readonly _onDidDispose = new Emitter<void>();
|
||||
readonly onDidDispose = this._onDidDispose.event;
|
||||
|
||||
@@ -246,7 +249,13 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
get hideWhenEmpty(): boolean | undefined { return this._hideWhenEmpty; }
|
||||
set hideWhenEmpty(hideWhenEmpty: boolean | undefined) {
|
||||
this._hideWhenEmpty = hideWhenEmpty;
|
||||
this._proxy.$updateGroup(this._sourceControlHandle, this.handle, { hideWhenEmpty });
|
||||
this._proxy.$updateGroup(this._sourceControlHandle, this.handle, this.features);
|
||||
}
|
||||
|
||||
get features(): SCMGroupFeatures {
|
||||
return {
|
||||
hideWhenEmpty: this.hideWhenEmpty
|
||||
};
|
||||
}
|
||||
|
||||
get resourceStates(): vscode.SourceControlResourceState[] { return [...this._resourceStates]; }
|
||||
@@ -263,9 +272,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
private _sourceControlHandle: number,
|
||||
private _id: string,
|
||||
private _label: string,
|
||||
) {
|
||||
this._proxy.$registerGroup(_sourceControlHandle, this.handle, _id, _label);
|
||||
}
|
||||
) { }
|
||||
|
||||
getResourceState(handle: number): vscode.SourceControlResourceState | undefined {
|
||||
return this._resourceStatesMap.get(handle);
|
||||
@@ -311,8 +318,9 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
const tooltip = (r.decorations && r.decorations.tooltip) || '';
|
||||
const strikeThrough = r.decorations && !!r.decorations.strikeThrough;
|
||||
const faded = r.decorations && !!r.decorations.faded;
|
||||
const contextValue = r.contextValue || '';
|
||||
|
||||
const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded] as SCMRawResource;
|
||||
const rawResource = [handle, sourceUri, icons, tooltip, strikeThrough, faded, contextValue] as SCMRawResource;
|
||||
|
||||
return { rawResource, handle };
|
||||
});
|
||||
@@ -340,7 +348,7 @@ class ExtHostSourceControlResourceGroup implements vscode.SourceControlResourceG
|
||||
}
|
||||
|
||||
dispose(): void {
|
||||
this._proxy.$unregisterGroup(this._sourceControlHandle, this.handle);
|
||||
this._disposed = true;
|
||||
this._onDidDispose.fire();
|
||||
}
|
||||
}
|
||||
@@ -465,26 +473,51 @@ class ExtHostSourceControl implements vscode.SourceControl {
|
||||
this._proxy.$registerSourceControl(this.handle, _id, _label, _rootUri);
|
||||
}
|
||||
|
||||
private createdResourceGroups = new Map<ExtHostSourceControlResourceGroup, IDisposable>();
|
||||
private updatedResourceGroups = new Set<ExtHostSourceControlResourceGroup>();
|
||||
|
||||
createResourceGroup(id: string, label: string): ExtHostSourceControlResourceGroup {
|
||||
const group = new ExtHostSourceControlResourceGroup(this._proxy, this._commands, this.handle, id, label);
|
||||
|
||||
const updateListener = group.onDidUpdateResourceStates(() => {
|
||||
this.updatedResourceGroups.add(group);
|
||||
this.eventuallyUpdateResourceStates();
|
||||
});
|
||||
|
||||
Event.once(group.onDidDispose)(() => {
|
||||
this.updatedResourceGroups.delete(group);
|
||||
updateListener.dispose();
|
||||
this._groups.delete(group.handle);
|
||||
});
|
||||
|
||||
this._groups.set(group.handle, group);
|
||||
const disposable = Event.once(group.onDidDispose)(() => this.createdResourceGroups.delete(group));
|
||||
this.createdResourceGroups.set(group, disposable);
|
||||
this.eventuallyAddResourceGroups();
|
||||
return group;
|
||||
}
|
||||
|
||||
@debounce(100)
|
||||
eventuallyAddResourceGroups(): void {
|
||||
const groups: [number /*handle*/, string /*id*/, string /*label*/, SCMGroupFeatures][] = [];
|
||||
const splices: SCMRawResourceSplices[] = [];
|
||||
|
||||
for (const [group, disposable] of this.createdResourceGroups) {
|
||||
disposable.dispose();
|
||||
|
||||
const updateListener = group.onDidUpdateResourceStates(() => {
|
||||
this.updatedResourceGroups.add(group);
|
||||
this.eventuallyUpdateResourceStates();
|
||||
});
|
||||
|
||||
Event.once(group.onDidDispose)(() => {
|
||||
this.updatedResourceGroups.delete(group);
|
||||
updateListener.dispose();
|
||||
this._groups.delete(group.handle);
|
||||
this._proxy.$unregisterGroup(this.handle, group.handle);
|
||||
});
|
||||
|
||||
groups.push([group.handle, group.id, group.label, group.features]);
|
||||
|
||||
const snapshot = group._takeResourceStateSnapshot();
|
||||
|
||||
if (snapshot.length > 0) {
|
||||
splices.push([group.handle, snapshot]);
|
||||
}
|
||||
|
||||
this._groups.set(group.handle, group);
|
||||
}
|
||||
|
||||
this._proxy.$registerGroups(this.handle, groups, splices);
|
||||
}
|
||||
|
||||
@debounce(100)
|
||||
eventuallyUpdateResourceStates(): void {
|
||||
const splices: SCMRawResourceSplices[] = [];
|
||||
|
||||
@@ -192,12 +192,16 @@ export namespace CustomExecutionDTO {
|
||||
|
||||
|
||||
export namespace TaskHandleDTO {
|
||||
export function from(value: types.Task): tasks.TaskHandleDTO {
|
||||
export function from(value: types.Task, workspaceService?: IExtHostWorkspace): tasks.TaskHandleDTO {
|
||||
let folder: UriComponents | string;
|
||||
if (value.scope !== undefined && typeof value.scope !== 'number') {
|
||||
folder = value.scope.uri;
|
||||
} else if (value.scope !== undefined && typeof value.scope === 'number') {
|
||||
folder = USER_TASKS_GROUP_KEY;
|
||||
if ((value.scope === types.TaskScope.Workspace) && workspaceService && workspaceService.workspaceFile) {
|
||||
folder = workspaceService.workspaceFile;
|
||||
} else {
|
||||
folder = USER_TASKS_GROUP_KEY;
|
||||
}
|
||||
}
|
||||
return {
|
||||
id: value._id!,
|
||||
@@ -471,11 +475,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
|
||||
return this._onDidExecuteTask.event;
|
||||
}
|
||||
|
||||
protected async resolveDefinition(uri: number | UriComponents | undefined, definition: vscode.TaskDefinition | undefined): Promise<vscode.TaskDefinition | undefined> {
|
||||
return definition;
|
||||
}
|
||||
|
||||
public async $onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number): Promise<void> {
|
||||
public async $onDidStartTask(execution: tasks.TaskExecutionDTO, terminalId: number, resolvedDefinition: tasks.TaskDefinitionDTO): Promise<void> {
|
||||
const customExecution: types.CustomExecution | undefined = this._providedCustomExecutions2.get(execution.id);
|
||||
if (customExecution) {
|
||||
if (this._activeCustomExecutions2.get(execution.id) !== undefined) {
|
||||
@@ -484,7 +484,7 @@ export abstract class ExtHostTaskBase implements ExtHostTaskShape, IExtHostTask
|
||||
|
||||
// Clone the custom execution to keep the original untouched. This is important for multiple runs of the same task.
|
||||
this._activeCustomExecutions2.set(execution.id, customExecution);
|
||||
this._terminalService.attachPtyToTerminal(terminalId, await customExecution.callback(await this.resolveDefinition(execution.task?.source.scope, execution.task?.definition)));
|
||||
this._terminalService.attachPtyToTerminal(terminalId, await customExecution.callback(resolvedDefinition));
|
||||
}
|
||||
this._lastStartedTask = execution.id;
|
||||
|
||||
|
||||
@@ -41,7 +41,6 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
|
||||
attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
|
||||
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
|
||||
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
|
||||
registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable;
|
||||
registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable;
|
||||
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
|
||||
}
|
||||
@@ -176,6 +175,9 @@ export class ExtHostTerminal extends BaseExtHostTerminal implements vscode.Termi
|
||||
// Nothing changed
|
||||
return false;
|
||||
}
|
||||
if (cols === 0 || rows === 0) {
|
||||
return false;
|
||||
}
|
||||
this._cols = cols;
|
||||
this._rows = rows;
|
||||
return true;
|
||||
@@ -318,7 +320,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
protected _environmentVariableCollections: Map<string, EnvironmentVariableCollection> = new Map();
|
||||
|
||||
private readonly _bufferer: TerminalDataBufferer;
|
||||
private readonly _linkHandlers: Set<vscode.TerminalLinkHandler> = new Set();
|
||||
private readonly _linkProviders: Set<vscode.TerminalLinkProvider> = new Set();
|
||||
private readonly _terminalLinkCache: Map<number, Map<number, ICachedLinkEntry>> = new Map();
|
||||
private readonly _terminalLinkCancellationSource: Map<number, CancellationTokenSource> = new Map();
|
||||
@@ -559,19 +560,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
return id;
|
||||
}
|
||||
|
||||
public registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable {
|
||||
this._linkHandlers.add(handler);
|
||||
if (this._linkHandlers.size === 1 && this._linkProviders.size === 0) {
|
||||
this._proxy.$startHandlingLinks();
|
||||
}
|
||||
return new VSCodeDisposable(() => {
|
||||
this._linkHandlers.delete(handler);
|
||||
if (this._linkHandlers.size === 0 && this._linkProviders.size === 0) {
|
||||
this._proxy.$stopHandlingLinks();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public registerLinkProvider(provider: vscode.TerminalLinkProvider): vscode.Disposable {
|
||||
this._linkProviders.add(provider);
|
||||
if (this._linkProviders.size === 1) {
|
||||
@@ -585,25 +573,6 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
|
||||
});
|
||||
}
|
||||
|
||||
public async $handleLink(id: number, link: string): Promise<boolean> {
|
||||
const terminal = this._getTerminalById(id);
|
||||
if (!terminal) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Call each handler synchronously so multiple handlers aren't triggered at once
|
||||
const it = this._linkHandlers.values();
|
||||
let next = it.next();
|
||||
while (!next.done) {
|
||||
const handled = await next.value.handleLink(terminal, link);
|
||||
if (handled) {
|
||||
return true;
|
||||
}
|
||||
next = it.next();
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public async $provideLinks(terminalId: number, line: string): Promise<ITerminalLinkDto[]> {
|
||||
const terminal = this._getTerminalById(terminalId);
|
||||
if (!terminal) {
|
||||
|
||||
@@ -131,8 +131,9 @@ export namespace DiagnosticTag {
|
||||
return types.DiagnosticTag.Unnecessary;
|
||||
case MarkerTag.Deprecated:
|
||||
return types.DiagnosticTag.Deprecated;
|
||||
default:
|
||||
return undefined;
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -210,8 +211,9 @@ export namespace DiagnosticSeverity {
|
||||
return types.DiagnosticSeverity.Error;
|
||||
case MarkerSeverity.Hint:
|
||||
return types.DiagnosticSeverity.Hint;
|
||||
default:
|
||||
return types.DiagnosticSeverity.Error;
|
||||
}
|
||||
return types.DiagnosticSeverity.Error;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1253,9 +1255,9 @@ export namespace LogLevel {
|
||||
return _MainLogLevel.Critical;
|
||||
case types.LogLevel.Off:
|
||||
return _MainLogLevel.Off;
|
||||
default:
|
||||
return _MainLogLevel.Info;
|
||||
}
|
||||
|
||||
return _MainLogLevel.Info;
|
||||
}
|
||||
|
||||
export function to(mainLevel: _MainLogLevel): types.LogLevel {
|
||||
@@ -1274,8 +1276,8 @@ export namespace LogLevel {
|
||||
return types.LogLevel.Critical;
|
||||
case _MainLogLevel.Off:
|
||||
return types.LogLevel.Off;
|
||||
default:
|
||||
return types.LogLevel.Info;
|
||||
}
|
||||
|
||||
return types.LogLevel.Info;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -885,6 +885,12 @@ export class Diagnostic {
|
||||
tags?: DiagnosticTag[];
|
||||
|
||||
constructor(range: Range, message: string, severity: DiagnosticSeverity = DiagnosticSeverity.Error) {
|
||||
if (!Range.isRange(range)) {
|
||||
throw new TypeError('range must be set');
|
||||
}
|
||||
if (!message) {
|
||||
throw new TypeError('message must be set');
|
||||
}
|
||||
this.range = range;
|
||||
this.message = message;
|
||||
this.severity = severity;
|
||||
@@ -1825,20 +1831,20 @@ export enum TaskScope {
|
||||
Workspace = 2
|
||||
}
|
||||
|
||||
export class CustomExecution implements vscode.CustomExecution2 {
|
||||
private _callback: (resolvedDefintion?: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>;
|
||||
constructor(callback: (resolvedDefintion?: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
|
||||
export class CustomExecution implements vscode.CustomExecution {
|
||||
private _callback: (resolvedDefintion: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>;
|
||||
constructor(callback: (resolvedDefintion: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
|
||||
this._callback = callback;
|
||||
}
|
||||
public computeId(): string {
|
||||
return 'customExecution' + generateUuid();
|
||||
}
|
||||
|
||||
public set callback(value: (resolvedDefintion?: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
|
||||
public set callback(value: (resolvedDefintion: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
|
||||
this._callback = value;
|
||||
}
|
||||
|
||||
public get callback(): ((resolvedDefintion?: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
|
||||
public get callback(): ((resolvedDefintion: vscode.TaskDefinition) => Thenable<vscode.Pseudoterminal>) {
|
||||
return this._callback;
|
||||
}
|
||||
}
|
||||
@@ -2288,6 +2294,12 @@ export class DebugAdapterServer implements vscode.DebugAdapterServer {
|
||||
}
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class DebugAdapterNamedPipeServer implements vscode.DebugAdapterNamedPipeServer {
|
||||
constructor(public readonly path: string) {
|
||||
}
|
||||
}
|
||||
|
||||
@es5ClassCompat
|
||||
export class DebugAdapterInlineImplementation implements vscode.DebugAdapterInlineImplementation {
|
||||
readonly implementation: vscode.DebugAdapter;
|
||||
@@ -2777,6 +2789,17 @@ export enum ExtensionMode {
|
||||
Test = 3,
|
||||
}
|
||||
|
||||
export enum ExtensionRuntime {
|
||||
/**
|
||||
* The extension is running in a NodeJS extension host. Runtime access to NodeJS APIs is available.
|
||||
*/
|
||||
Node = 1,
|
||||
/**
|
||||
* The extension is running in a Webworker extension host. Runtime access is limited to Webworker APIs.
|
||||
*/
|
||||
Webworker = 2
|
||||
}
|
||||
|
||||
//#endregion ExtensionContext
|
||||
|
||||
export enum StandardTokenType {
|
||||
|
||||
@@ -3,30 +3,19 @@
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { hash } from 'vs/base/common/hash';
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { Schemas } from 'vs/base/common/network';
|
||||
import { joinPath } from 'vs/base/common/resources';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { generateUuid } from 'vs/base/common/uuid';
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
import { ExtHostDocuments } from 'vs/workbench/api/common/extHostDocuments';
|
||||
import { IExtensionStoragePaths } from 'vs/workbench/api/common/extHostStoragePaths';
|
||||
import * as typeConverters from 'vs/workbench/api/common/extHostTypeConverters';
|
||||
import { IExtHostWorkspace } from 'vs/workbench/api/common/extHostWorkspace';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import { asWebviewUri, WebviewInitData } from 'vs/workbench/api/common/shared/webview';
|
||||
import type * as vscode from 'vscode';
|
||||
import { Cache } from './cache';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import * as extHostTypes from './extHostTypes';
|
||||
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
export class ExtHostWebview implements vscode.Webview {
|
||||
|
||||
@@ -64,7 +53,13 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
/* internal */ readonly _onMessageEmitter = new Emitter<any>();
|
||||
public readonly onDidReceiveMessage: Event<any> = this._onMessageEmitter.event;
|
||||
|
||||
readonly #onDidDisposeEmitter = new Emitter<void>();
|
||||
/* internal */ readonly _onDidDispose: Event<void> = this.#onDidDisposeEmitter.event;
|
||||
|
||||
public dispose() {
|
||||
this.#onDidDisposeEmitter.fire();
|
||||
|
||||
this.#onDidDisposeEmitter.dispose();
|
||||
this._onMessageEmitter.dispose();
|
||||
}
|
||||
|
||||
@@ -119,7 +114,10 @@ export class ExtHostWebview implements vscode.Webview {
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPanel {
|
||||
type IconPath = URI | { light: URI, dark: URI };
|
||||
|
||||
|
||||
class ExtHostWebviewPanel extends Disposable implements vscode.WebviewPanel {
|
||||
|
||||
readonly #handle: extHostProtocol.WebviewPanelHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
@@ -167,6 +165,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
|
||||
|
||||
this.#isDisposed = true;
|
||||
this.#onDidDispose.fire();
|
||||
|
||||
this.#proxy.$disposeWebview(this.#handle);
|
||||
this.#webview.dispose();
|
||||
|
||||
@@ -267,137 +266,6 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
|
||||
}
|
||||
}
|
||||
|
||||
class CustomDocumentStoreEntry {
|
||||
|
||||
private _backupCounter = 1;
|
||||
|
||||
constructor(
|
||||
public readonly document: vscode.CustomDocument,
|
||||
private readonly _storagePath: URI | undefined,
|
||||
) { }
|
||||
|
||||
private readonly _edits = new Cache<vscode.CustomDocumentEditEvent>('custom documents');
|
||||
|
||||
private _backup?: vscode.CustomDocumentBackup;
|
||||
|
||||
addEdit(item: vscode.CustomDocumentEditEvent): 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();
|
||||
}
|
||||
}
|
||||
|
||||
disposeEdits(editIds: number[]): void {
|
||||
for (const id of editIds) {
|
||||
this._edits.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
getNewBackupUri(): URI {
|
||||
if (!this._storagePath) {
|
||||
throw new Error('Backup requires a valid storage path');
|
||||
}
|
||||
const fileName = hashPath(this.document.uri) + (this._backupCounter++);
|
||||
return joinPath(this._storagePath, fileName);
|
||||
}
|
||||
|
||||
updateBackup(backup: vscode.CustomDocumentBackup): void {
|
||||
this._backup?.delete();
|
||||
this._backup = backup;
|
||||
}
|
||||
|
||||
disposeBackup(): void {
|
||||
this._backup?.delete();
|
||||
this._backup = undefined;
|
||||
}
|
||||
|
||||
private getEdit(editId: number): vscode.CustomDocumentEditEvent {
|
||||
const edit = this._edits.get(editId, 0);
|
||||
if (!edit) {
|
||||
throw new Error('No edit found');
|
||||
}
|
||||
return edit;
|
||||
}
|
||||
}
|
||||
|
||||
class CustomDocumentStore {
|
||||
private readonly _documents = new Map<string, CustomDocumentStoreEntry>();
|
||||
|
||||
public get(viewType: string, resource: vscode.Uri): CustomDocumentStoreEntry | undefined {
|
||||
return this._documents.get(this.key(viewType, resource));
|
||||
}
|
||||
|
||||
public add(viewType: string, document: vscode.CustomDocument, storagePath: URI | undefined): CustomDocumentStoreEntry {
|
||||
const key = this.key(viewType, document.uri);
|
||||
if (this._documents.has(key)) {
|
||||
throw new Error(`Document already exists for viewType:${viewType} resource:${document.uri}`);
|
||||
}
|
||||
const entry = new CustomDocumentStoreEntry(document, storagePath);
|
||||
this._documents.set(key, entry);
|
||||
return entry;
|
||||
}
|
||||
|
||||
public delete(viewType: string, document: vscode.CustomDocument) {
|
||||
const key = this.key(viewType, document.uri);
|
||||
this._documents.delete(key);
|
||||
}
|
||||
|
||||
private key(viewType: string, resource: vscode.Uri): string {
|
||||
return `${viewType}@@@${resource}`;
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
const enum WebviewEditorType {
|
||||
Text,
|
||||
Custom
|
||||
}
|
||||
|
||||
type ProviderEntry = {
|
||||
readonly extension: IExtensionDescription;
|
||||
readonly type: WebviewEditorType.Text;
|
||||
readonly provider: vscode.CustomTextEditorProvider;
|
||||
} | {
|
||||
readonly extension: IExtensionDescription;
|
||||
readonly type: WebviewEditorType.Custom;
|
||||
readonly provider: vscode.CustomReadonlyEditorProvider;
|
||||
};
|
||||
|
||||
class EditorProviderStore {
|
||||
private readonly _providers = new Map<string, ProviderEntry>();
|
||||
|
||||
public addTextProvider(viewType: string, extension: IExtensionDescription, provider: vscode.CustomTextEditorProvider): vscode.Disposable {
|
||||
return this.add(WebviewEditorType.Text, viewType, extension, provider);
|
||||
}
|
||||
|
||||
public addCustomProvider(viewType: string, extension: IExtensionDescription, provider: vscode.CustomReadonlyEditorProvider): vscode.Disposable {
|
||||
return this.add(WebviewEditorType.Custom, viewType, extension, provider);
|
||||
}
|
||||
|
||||
public get(viewType: string): ProviderEntry | undefined {
|
||||
return this._providers.get(viewType);
|
||||
}
|
||||
|
||||
private add(type: WebviewEditorType, viewType: string, extension: IExtensionDescription, provider: vscode.CustomTextEditorProvider | vscode.CustomReadonlyEditorProvider): vscode.Disposable {
|
||||
if (this._providers.has(viewType)) {
|
||||
throw new Error(`Provider for viewType:${viewType} already registered`);
|
||||
}
|
||||
this._providers.set(viewType, { type, extension, provider } as ProviderEntry);
|
||||
return new extHostTypes.Disposable(() => this._providers.delete(viewType));
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
|
||||
private static newHandle(): extHostProtocol.WebviewPanelHandle {
|
||||
@@ -405,16 +273,10 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
}
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
private readonly _webviewPanels = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebviewEditor>();
|
||||
|
||||
private readonly _serializers = new Map<string, {
|
||||
readonly serializer: vscode.WebviewPanelSerializer;
|
||||
readonly extension: IExtensionDescription;
|
||||
}>();
|
||||
private readonly _webviews = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebview>();
|
||||
private readonly _webviewPanels = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebviewPanel>();
|
||||
|
||||
private readonly _editorProviders = new EditorProviderStore();
|
||||
|
||||
private readonly _documents = new CustomDocumentStore();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
@@ -422,8 +284,6 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
private readonly workspace: IExtHostWorkspace | undefined,
|
||||
private readonly _logService: ILogService,
|
||||
private readonly _deprecationService: IExtHostApiDeprecationService,
|
||||
private readonly _extHostDocuments: ExtHostDocuments,
|
||||
private readonly _extensionStoragePaths?: IExtensionStoragePaths,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
@@ -444,74 +304,19 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
const handle = ExtHostWebviews.newHandle();
|
||||
this._proxy.$createWebviewPanel(toExtensionData(extension), handle, viewType, title, webviewShowOptions, convertWebviewOptions(extension, this.workspace, options));
|
||||
|
||||
const webview = new ExtHostWebview(handle, this._proxy, options, this.initData, this.workspace, extension, this._deprecationService);
|
||||
const panel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, viewColumn, options, webview);
|
||||
this._webviewPanels.set(handle, panel);
|
||||
const webview = this.createNewWebview(handle, options, extension);
|
||||
const panel = this.createNewWebviewPanel(handle, viewType, title, viewColumn, options, webview);
|
||||
|
||||
return panel;
|
||||
}
|
||||
|
||||
public registerWebviewPanelSerializer(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
serializer: vscode.WebviewPanelSerializer
|
||||
): vscode.Disposable {
|
||||
if (this._serializers.has(viewType)) {
|
||||
throw new Error(`Serializer for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._serializers.set(viewType, { serializer, extension });
|
||||
this._proxy.$registerSerializer(viewType);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._serializers.delete(viewType);
|
||||
this._proxy.$unregisterSerializer(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
public registerCustomEditorProvider(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
provider: vscode.CustomReadonlyEditorProvider | vscode.CustomTextEditorProvider,
|
||||
options: { webviewOptions?: vscode.WebviewPanelOptions, supportsMultipleEditorsPerDocument?: boolean },
|
||||
): vscode.Disposable {
|
||||
const disposables = new DisposableStore();
|
||||
if ('resolveCustomTextEditor' in provider) {
|
||||
disposables.add(this._editorProviders.addTextProvider(viewType, extension, provider));
|
||||
this._proxy.$registerTextEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, {
|
||||
supportsMove: !!provider.moveCustomTextEditor,
|
||||
});
|
||||
} else {
|
||||
disposables.add(this._editorProviders.addCustomProvider(viewType, extension, provider));
|
||||
|
||||
if (this.supportEditing(provider)) {
|
||||
disposables.add(provider.onDidChangeCustomDocument(e => {
|
||||
const entry = this.getCustomDocumentEntry(viewType, e.document.uri);
|
||||
if (isEditEvent(e)) {
|
||||
const editId = entry.addEdit(e);
|
||||
this._proxy.$onDidEdit(e.document.uri, viewType, editId, e.label);
|
||||
} else {
|
||||
this._proxy.$onContentChange((<any>e).document.uri, viewType); // {{SQL CARBON EDIT}} strict-null-checks
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
this._proxy.$registerCustomEditorProvider(toExtensionData(extension), viewType, options.webviewOptions || {}, !!options.supportsMultipleEditorsPerDocument);
|
||||
}
|
||||
|
||||
return extHostTypes.Disposable.from(
|
||||
disposables,
|
||||
new extHostTypes.Disposable(() => {
|
||||
this._proxy.$unregisterEditorProvider(viewType);
|
||||
}));
|
||||
}
|
||||
|
||||
public $onMessage(
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
message: any
|
||||
): void {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (panel) {
|
||||
panel.webview._onMessageEmitter.fire(message);
|
||||
const webview = this.getWebview(handle);
|
||||
if (webview) {
|
||||
webview._onMessageEmitter.fire(message);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -557,203 +362,37 @@ export class ExtHostWebviews implements extHostProtocol.ExtHostWebviewsShape {
|
||||
|
||||
async $onDidDisposeWebviewPanel(handle: extHostProtocol.WebviewPanelHandle): Promise<void> {
|
||||
const panel = this.getWebviewPanel(handle);
|
||||
if (panel) {
|
||||
panel.dispose();
|
||||
this._webviewPanels.delete(handle);
|
||||
}
|
||||
panel?.dispose();
|
||||
|
||||
this._webviewPanels.delete(handle);
|
||||
this._webviews.delete(handle);
|
||||
}
|
||||
|
||||
async $deserializeWebviewPanel(
|
||||
webviewHandle: extHostProtocol.WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
state: any,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||
): Promise<void> {
|
||||
const entry = this._serializers.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No serializer found for '${viewType}'`);
|
||||
}
|
||||
const { serializer, extension } = entry;
|
||||
|
||||
const webview = new ExtHostWebview(webviewHandle, this._proxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService);
|
||||
const revivedPanel = new ExtHostWebviewEditor(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, revivedPanel);
|
||||
await serializer.deserializeWebviewPanel(revivedPanel, state);
|
||||
public createNewWebviewPanel(webviewHandle: string, viewType: string, title: string, position: number, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, webview: ExtHostWebview) {
|
||||
const panel = new ExtHostWebviewPanel(webviewHandle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(webviewHandle, panel);
|
||||
return panel;
|
||||
}
|
||||
|
||||
async $createCustomDocument(resource: UriComponents, viewType: string, backupId: string | undefined, cancellation: CancellationToken) {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
public createNewWebview(handle: string, options: modes.IWebviewOptions & modes.IWebviewPanelOptions, extension: IExtensionDescription): ExtHostWebview {
|
||||
const webview = new ExtHostWebview(handle, this._proxy, reviveOptions(options), this.initData, this.workspace, extension, this._deprecationService);
|
||||
this._webviews.set(handle, webview);
|
||||
|
||||
if (entry.type !== WebviewEditorType.Custom) {
|
||||
throw new Error(`Invalid provide type for '${viewType}'`);
|
||||
}
|
||||
webview._onDidDispose(() => { this._webviews.delete(handle); });
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const document = await entry.provider.openCustomDocument(revivedResource, { backupId }, cancellation);
|
||||
|
||||
let storageRoot: URI | undefined;
|
||||
if (this.supportEditing(entry.provider) && this._extensionStoragePaths) {
|
||||
storageRoot = this._extensionStoragePaths.workspaceValue(entry.extension) ?? this._extensionStoragePaths.globalValue(entry.extension);
|
||||
}
|
||||
this._documents.add(viewType, document, storageRoot);
|
||||
|
||||
return { editable: this.supportEditing(entry.provider) };
|
||||
return webview;
|
||||
}
|
||||
|
||||
async $disposeCustomDocument(resource: UriComponents, viewType: string): Promise<void> {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
if (entry.type !== WebviewEditorType.Custom) {
|
||||
throw new Error(`Invalid provider type for '${viewType}'`);
|
||||
}
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
const { document } = this.getCustomDocumentEntry(viewType, revivedResource);
|
||||
this._documents.delete(viewType, document);
|
||||
document.dispose();
|
||||
private getWebview(handle: extHostProtocol.WebviewPanelHandle): ExtHostWebview | undefined {
|
||||
return this._webviews.get(handle);
|
||||
}
|
||||
|
||||
async $resolveWebviewEditor(
|
||||
resource: UriComponents,
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions,
|
||||
cancellation: CancellationToken,
|
||||
): Promise<void> {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
const webview = new ExtHostWebview(handle, this._proxy, reviveOptions(options), this.initData, this.workspace, entry.extension, this._deprecationService);
|
||||
const revivedPanel = new ExtHostWebviewEditor(handle, this._proxy, viewType, title, typeof position === 'number' && position >= 0 ? typeConverters.ViewColumn.to(position) : undefined, options, webview);
|
||||
this._webviewPanels.set(handle, revivedPanel);
|
||||
|
||||
const revivedResource = URI.revive(resource);
|
||||
|
||||
switch (entry.type) {
|
||||
case WebviewEditorType.Custom:
|
||||
{
|
||||
const { document } = this.getCustomDocumentEntry(viewType, revivedResource);
|
||||
return entry.provider.resolveCustomEditor(document, revivedPanel, cancellation);
|
||||
}
|
||||
case WebviewEditorType.Text:
|
||||
{
|
||||
const document = this._extHostDocuments.getDocument(revivedResource);
|
||||
return entry.provider.resolveCustomTextEditor(document, revivedPanel, cancellation);
|
||||
}
|
||||
default:
|
||||
{
|
||||
throw new Error('Unknown webview provider type');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$disposeEdits(resourceComponents: UriComponents, viewType: string, editIds: number[]): void {
|
||||
const document = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
document.disposeEdits(editIds);
|
||||
}
|
||||
|
||||
async $onMoveCustomEditor(handle: string, newResourceComponents: UriComponents, viewType: string): Promise<void> {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
if (!(entry.provider as vscode.CustomTextEditorProvider).moveCustomTextEditor) {
|
||||
throw new Error(`Provider does not implement move '${viewType}'`);
|
||||
}
|
||||
|
||||
const webview = this.getWebviewPanel(handle);
|
||||
if (!webview) {
|
||||
throw new Error(`No webview found`);
|
||||
}
|
||||
|
||||
const resource = URI.revive(newResourceComponents);
|
||||
const document = this._extHostDocuments.getDocument(resource);
|
||||
await (entry.provider as vscode.CustomTextEditorProvider).moveCustomTextEditor!(document, webview, CancellationToken.None);
|
||||
}
|
||||
|
||||
async $undo(resourceComponents: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
return entry.undo(editId, isDirty);
|
||||
}
|
||||
|
||||
async $redo(resourceComponents: UriComponents, viewType: string, editId: number, isDirty: boolean): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
return entry.redo(editId, isDirty);
|
||||
}
|
||||
|
||||
async $revert(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
await provider.revertCustomDocument(entry.document, cancellation);
|
||||
entry.disposeBackup();
|
||||
}
|
||||
|
||||
async $onSave(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
await provider.saveCustomDocument(entry.document, cancellation);
|
||||
entry.disposeBackup();
|
||||
}
|
||||
|
||||
async $onSaveAs(resourceComponents: UriComponents, viewType: string, targetResource: UriComponents, cancellation: CancellationToken): Promise<void> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
return provider.saveCustomDocumentAs(entry.document, URI.revive(targetResource), cancellation);
|
||||
}
|
||||
|
||||
async $backup(resourceComponents: UriComponents, viewType: string, cancellation: CancellationToken): Promise<string> {
|
||||
const entry = this.getCustomDocumentEntry(viewType, resourceComponents);
|
||||
const provider = this.getCustomEditorProvider(viewType);
|
||||
|
||||
const backup = await provider.backupCustomDocument(entry.document, {
|
||||
destination: entry.getNewBackupUri(),
|
||||
}, cancellation);
|
||||
entry.updateBackup(backup);
|
||||
return backup.id;
|
||||
}
|
||||
|
||||
private getWebviewPanel(handle: extHostProtocol.WebviewPanelHandle): ExtHostWebviewEditor | undefined {
|
||||
public getWebviewPanel(handle: extHostProtocol.WebviewPanelHandle): ExtHostWebviewPanel | undefined {
|
||||
return this._webviewPanels.get(handle);
|
||||
}
|
||||
|
||||
private getCustomDocumentEntry(viewType: string, resource: UriComponents): CustomDocumentStoreEntry {
|
||||
const entry = this._documents.get(viewType, URI.revive(resource));
|
||||
if (!entry) {
|
||||
throw new Error('No custom document found');
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
|
||||
private getCustomEditorProvider(viewType: string): vscode.CustomEditorProvider {
|
||||
const entry = this._editorProviders.get(viewType);
|
||||
const provider = entry?.provider;
|
||||
if (!provider || !this.supportEditing(provider)) {
|
||||
throw new Error('Custom document is not editable');
|
||||
}
|
||||
return provider;
|
||||
}
|
||||
|
||||
private supportEditing(
|
||||
provider: vscode.CustomTextEditorProvider | vscode.CustomEditorProvider | vscode.CustomReadonlyEditorProvider
|
||||
): provider is vscode.CustomEditorProvider {
|
||||
return !!(provider as vscode.CustomEditorProvider).onDidChangeCustomDocument;
|
||||
}
|
||||
}
|
||||
|
||||
function toExtensionData(extension: IExtensionDescription): extHostProtocol.WebviewExtensionDescription {
|
||||
export function toExtensionData(extension: IExtensionDescription): extHostProtocol.WebviewExtensionDescription {
|
||||
return { id: extension.identifier, location: extension.extensionLocation };
|
||||
}
|
||||
|
||||
@@ -786,13 +425,3 @@ function getDefaultLocalResourceRoots(
|
||||
extension.extensionLocation,
|
||||
];
|
||||
}
|
||||
|
||||
function isEditEvent(e: vscode.CustomDocumentContentChangeEvent | vscode.CustomDocumentEditEvent): e is vscode.CustomDocumentEditEvent {
|
||||
return typeof (e as vscode.CustomDocumentEditEvent).undo === 'function'
|
||||
&& typeof (e as vscode.CustomDocumentEditEvent).redo === 'function';
|
||||
}
|
||||
|
||||
function hashPath(resource: URI): string {
|
||||
const str = resource.scheme === Schemas.file || resource.scheme === Schemas.untitled ? resource.fsPath : resource.toString();
|
||||
return hash(str) + '';
|
||||
}
|
||||
|
||||
66
src/vs/workbench/api/common/extHostWebviewSerializer.ts
Normal file
66
src/vs/workbench/api/common/extHostWebviewSerializer.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as modes from 'vs/editor/common/modes';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import { EditorViewColumn } from 'vs/workbench/api/common/shared/editor';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import * as extHostTypes from './extHostTypes';
|
||||
|
||||
export class ExtHostWebviewSerializer implements extHostProtocol.ExtHostWebviewSerializerShape {
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
private readonly _serializers = new Map<string, {
|
||||
readonly serializer: vscode.WebviewPanelSerializer;
|
||||
readonly extension: IExtensionDescription;
|
||||
}>();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
private readonly _webviewService: ExtHostWebviews,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
public registerWebviewPanelSerializer(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
serializer: vscode.WebviewPanelSerializer
|
||||
): vscode.Disposable {
|
||||
if (this._serializers.has(viewType)) {
|
||||
throw new Error(`Serializer for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._serializers.set(viewType, { serializer, extension });
|
||||
this._proxy.$registerSerializer(viewType);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._serializers.delete(viewType);
|
||||
this._proxy.$unregisterSerializer(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
async $deserializeWebviewPanel(
|
||||
webviewHandle: extHostProtocol.WebviewPanelHandle,
|
||||
viewType: string,
|
||||
title: string,
|
||||
state: any,
|
||||
position: EditorViewColumn,
|
||||
options: modes.IWebviewOptions & modes.IWebviewPanelOptions
|
||||
): Promise<void> {
|
||||
const entry = this._serializers.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No serializer found for '${viewType}'`);
|
||||
}
|
||||
const { serializer, extension } = entry;
|
||||
|
||||
const webview = this._webviewService.createNewWebview(webviewHandle, options, extension);
|
||||
const revivedPanel = this._webviewService.createNewWebviewPanel(webviewHandle, viewType, title, position, options, webview);
|
||||
await serializer.deserializeWebviewPanel(revivedPanel, state);
|
||||
}
|
||||
}
|
||||
176
src/vs/workbench/api/common/extHostWebviewView.ts
Normal file
176
src/vs/workbench/api/common/extHostWebviewView.ts
Normal file
@@ -0,0 +1,176 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
import { Emitter } from 'vs/base/common/event';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { ExtHostWebview, ExtHostWebviews } from 'vs/workbench/api/common/extHostWebview';
|
||||
import type * as vscode from 'vscode';
|
||||
import * as extHostProtocol from './extHost.protocol';
|
||||
import * as extHostTypes from './extHostTypes';
|
||||
|
||||
class ExtHostWebviewView extends Disposable implements vscode.WebviewView {
|
||||
|
||||
readonly #handle: extHostProtocol.WebviewPanelHandle;
|
||||
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
readonly #viewType: string;
|
||||
readonly #webview: ExtHostWebview;
|
||||
|
||||
#isDisposed = false;
|
||||
#isVisible: boolean;
|
||||
#title: string | undefined;
|
||||
|
||||
constructor(
|
||||
handle: extHostProtocol.WebviewPanelHandle,
|
||||
proxy: extHostProtocol.MainThreadWebviewsShape,
|
||||
viewType: string,
|
||||
webview: ExtHostWebview,
|
||||
isVisible: boolean,
|
||||
) {
|
||||
super();
|
||||
|
||||
this.#viewType = viewType;
|
||||
this.#handle = handle;
|
||||
this.#proxy = proxy;
|
||||
this.#webview = webview;
|
||||
this.#isVisible = isVisible;
|
||||
}
|
||||
|
||||
public dispose() {
|
||||
if (this.#isDisposed) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#isDisposed = true;
|
||||
this.#onDidDispose.fire();
|
||||
|
||||
super.dispose();
|
||||
}
|
||||
|
||||
readonly #onDidChangeVisibility = this._register(new Emitter<void>());
|
||||
public readonly onDidChangeVisibility = this.#onDidChangeVisibility.event;
|
||||
|
||||
readonly #onDidDispose = this._register(new Emitter<void>());
|
||||
public readonly onDidDispose = this.#onDidDispose.event;
|
||||
|
||||
public get title(): string | undefined {
|
||||
this.assertNotDisposed();
|
||||
return this.#title;
|
||||
}
|
||||
|
||||
public set title(value: string | undefined) {
|
||||
this.assertNotDisposed();
|
||||
if (this.#title !== value) {
|
||||
this.#title = value;
|
||||
this.#proxy.$setWebviewViewTitle(this.#handle, value);
|
||||
}
|
||||
}
|
||||
|
||||
public get visible(): boolean { return this.#isVisible; }
|
||||
|
||||
public get webview(): vscode.Webview { return this.#webview; }
|
||||
|
||||
public get viewType(): string { return this.#viewType; }
|
||||
|
||||
/* internal */ _setVisible(visible: boolean) {
|
||||
if (visible === this.#isVisible) {
|
||||
return;
|
||||
}
|
||||
|
||||
this.#isVisible = visible;
|
||||
this.#onDidChangeVisibility.fire();
|
||||
}
|
||||
|
||||
private assertNotDisposed() {
|
||||
if (this.#isDisposed) {
|
||||
throw new Error('Webview is disposed');
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostWebviewViews implements extHostProtocol.ExtHostWebviewViewsShape {
|
||||
|
||||
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
|
||||
|
||||
private readonly _viewProviders = new Map<string, {
|
||||
readonly provider: vscode.WebviewViewProvider;
|
||||
readonly extension: IExtensionDescription;
|
||||
}>();
|
||||
|
||||
private readonly _webviewViews = new Map<extHostProtocol.WebviewPanelHandle, ExtHostWebviewView>();
|
||||
|
||||
constructor(
|
||||
mainContext: extHostProtocol.IMainContext,
|
||||
private readonly _extHostWebview: ExtHostWebviews,
|
||||
) {
|
||||
this._proxy = mainContext.getProxy(extHostProtocol.MainContext.MainThreadWebviews);
|
||||
}
|
||||
|
||||
public registerWebviewViewProvider(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
provider: vscode.WebviewViewProvider,
|
||||
webviewOptions?: {
|
||||
retainContextWhenHidden?: boolean
|
||||
},
|
||||
): vscode.Disposable {
|
||||
if (this._viewProviders.has(viewType)) {
|
||||
throw new Error(`View provider for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._viewProviders.set(viewType, { provider, extension });
|
||||
this._proxy.$registerWebviewViewProvider(viewType, webviewOptions);
|
||||
|
||||
return new extHostTypes.Disposable(() => {
|
||||
this._viewProviders.delete(viewType);
|
||||
this._proxy.$unregisterWebviewViewProvider(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
async $resolveWebviewView(
|
||||
webviewHandle: string,
|
||||
viewType: string,
|
||||
state: any,
|
||||
cancellation: CancellationToken,
|
||||
): Promise<void> {
|
||||
const entry = this._viewProviders.get(viewType);
|
||||
if (!entry) {
|
||||
throw new Error(`No view provider found for '${viewType}'`);
|
||||
}
|
||||
|
||||
const { provider, extension } = entry;
|
||||
|
||||
const webview = this._extHostWebview.createNewWebview(webviewHandle, { /* todo */ }, extension);
|
||||
const revivedView = new ExtHostWebviewView(webviewHandle, this._proxy, viewType, webview, true);
|
||||
|
||||
this._webviewViews.set(webviewHandle, revivedView);
|
||||
|
||||
await provider.resolveWebviewView(revivedView, { state }, cancellation);
|
||||
}
|
||||
|
||||
async $onDidChangeWebviewViewVisibility(
|
||||
webviewHandle: string,
|
||||
visible: boolean
|
||||
) {
|
||||
const webviewView = this.getWebviewView(webviewHandle);
|
||||
webviewView._setVisible(visible);
|
||||
}
|
||||
|
||||
async $disposeWebviewView(webviewHandle: string) {
|
||||
const webviewView = this.getWebviewView(webviewHandle);
|
||||
this._webviewViews.delete(webviewHandle);
|
||||
webviewView.dispose();
|
||||
}
|
||||
|
||||
private getWebviewView(handle: string): ExtHostWebviewView {
|
||||
const entry = this._webviewViews.get(handle);
|
||||
if (!entry) {
|
||||
throw new Error('No webview found');
|
||||
}
|
||||
return entry;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user