mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-20 09:35:38 -05:00
Merge from vscode 61d5f2b82f17bf9f99f56405204caab88a7e8747
This commit is contained in:
@@ -56,6 +56,7 @@ import './mainThreadWindow';
|
||||
import './mainThreadWebview';
|
||||
import './mainThreadWorkspace';
|
||||
import './mainThreadComments';
|
||||
import './mainThreadNotebook';
|
||||
// import './mainThreadTask'; {{SQL CARBON EDIT}} @anthonydresser comment out task
|
||||
import './mainThreadLabelService';
|
||||
import './mainThreadTunnelService';
|
||||
|
||||
@@ -261,6 +261,18 @@ export class MainThreadLanguageFeatures implements MainThreadLanguageFeaturesSha
|
||||
}));
|
||||
}
|
||||
|
||||
// --- on type rename
|
||||
|
||||
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[], stopPattern?: IRegExpDto): void {
|
||||
const revivedStopPattern = stopPattern ? MainThreadLanguageFeatures._reviveRegExp(stopPattern) : undefined;
|
||||
this._registrations.set(handle, modes.OnTypeRenameProviderRegistry.register(selector, <modes.OnTypeRenameProvider>{
|
||||
stopPattern: revivedStopPattern,
|
||||
provideOnTypeRenameRanges: (model: ITextModel, position: EditorPosition, token: CancellationToken): Promise<IRange[] | undefined> => {
|
||||
return this._proxy.$provideOnTypeRenameRanges(handle, model.uri, position, token);
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
// --- references
|
||||
|
||||
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void {
|
||||
|
||||
255
src/vs/workbench/api/browser/mainThreadNotebook.ts
Normal file
255
src/vs/workbench/api/browser/mainThreadNotebook.ts
Normal file
@@ -0,0 +1,255 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { extHostNamedCustomer } from 'vs/workbench/api/common/extHostCustomers';
|
||||
import { MainContext, MainThreadNotebookShape, NotebookExtensionDescription, IExtHostContext, ExtHostNotebookShape, ExtHostContext } from '../common/extHost.protocol';
|
||||
import { Disposable } from 'vs/base/common/lifecycle';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { INotebookService, IMainNotebookController } from 'vs/workbench/contrib/notebook/browser/notebookService';
|
||||
import { INotebookTextModel, INotebookMimeTypeSelector, NOTEBOOK_DISPLAY_ORDER, NotebookCellsSplice, NotebookCellOutputsSplice, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
|
||||
import { NotebookTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookTextModel';
|
||||
|
||||
export class MainThreadNotebookDocument extends Disposable {
|
||||
private _textModel: NotebookTextModel;
|
||||
|
||||
get textModel() {
|
||||
return this._textModel;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
public handle: number,
|
||||
public viewType: string,
|
||||
public uri: URI
|
||||
) {
|
||||
super();
|
||||
this._textModel = new NotebookTextModel(handle, viewType, uri);
|
||||
}
|
||||
|
||||
async deleteCell(uri: URI, index: number): Promise<boolean> {
|
||||
let deleteExtHostCell = await this._proxy.$deleteCell(this.viewType, uri, index);
|
||||
if (deleteExtHostCell) {
|
||||
this._textModel.removeCell(index);
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
dispose() {
|
||||
this._textModel.dispose();
|
||||
super.dispose();
|
||||
}
|
||||
}
|
||||
|
||||
@extHostNamedCustomer(MainContext.MainThreadNotebook)
|
||||
export class MainThreadNotebooks extends Disposable implements MainThreadNotebookShape {
|
||||
private readonly _notebookProviders = new Map<string, MainThreadNotebookController>();
|
||||
private readonly _proxy: ExtHostNotebookShape;
|
||||
|
||||
constructor(
|
||||
extHostContext: IExtHostContext,
|
||||
@INotebookService private _notebookService: INotebookService,
|
||||
@IConfigurationService private readonly configurationService: IConfigurationService
|
||||
) {
|
||||
super();
|
||||
this._proxy = extHostContext.getProxy(ExtHostContext.ExtHostNotebook);
|
||||
this.registerListeners();
|
||||
}
|
||||
|
||||
registerListeners() {
|
||||
this._register(this._notebookService.onDidChangeActiveEditor(e => {
|
||||
this._proxy.$updateActiveEditor(e.viewType, e.uri);
|
||||
}));
|
||||
|
||||
let userOrder = this.configurationService.getValue<string[]>('notebook.displayOrder');
|
||||
this._proxy.$acceptDisplayOrder({
|
||||
defaultOrder: NOTEBOOK_DISPLAY_ORDER,
|
||||
userOrder: userOrder
|
||||
});
|
||||
|
||||
this.configurationService.onDidChangeConfiguration(e => {
|
||||
if (e.affectedKeys.indexOf('notebook.displayOrder') >= 0) {
|
||||
let userOrder = this.configurationService.getValue<string[]>('notebook.displayOrder');
|
||||
|
||||
this._proxy.$acceptDisplayOrder({
|
||||
defaultOrder: NOTEBOOK_DISPLAY_ORDER,
|
||||
userOrder: userOrder
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
async $registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, handle: number, preloads: UriComponents[]): Promise<void> {
|
||||
this._notebookService.registerNotebookRenderer(handle, extension, type, selectors, preloads.map(uri => URI.revive(uri)));
|
||||
}
|
||||
|
||||
async $unregisterNotebookRenderer(handle: number): Promise<void> {
|
||||
this._notebookService.unregisterNotebookRenderer(handle);
|
||||
}
|
||||
|
||||
async $registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string): Promise<void> {
|
||||
let controller = new MainThreadNotebookController(this._proxy, this, viewType);
|
||||
this._notebookProviders.set(viewType, controller);
|
||||
this._notebookService.registerNotebookController(viewType, extension, controller);
|
||||
return;
|
||||
}
|
||||
|
||||
async $unregisterNotebookProvider(viewType: string): Promise<void> {
|
||||
this._notebookProviders.delete(viewType);
|
||||
this._notebookService.unregisterNotebookProvider(viewType);
|
||||
return;
|
||||
}
|
||||
|
||||
async $createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
|
||||
if (controller) {
|
||||
controller.createNotebookDocument(handle, viewType, resource);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
async $updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
|
||||
if (controller) {
|
||||
controller.updateLanguages(resource, languages);
|
||||
}
|
||||
}
|
||||
|
||||
async resolveNotebook(viewType: string, uri: URI): Promise<number | undefined> {
|
||||
let handle = await this._proxy.$resolveNotebook(viewType, uri);
|
||||
return handle;
|
||||
}
|
||||
|
||||
async $spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.spliceNotebookCells(resource, splices, renderers);
|
||||
}
|
||||
|
||||
async $spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void> {
|
||||
let controller = this._notebookProviders.get(viewType);
|
||||
controller?.spliceNotebookCellOutputs(resource, cellHandle, splices, renderers);
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI): Promise<void> {
|
||||
return this._proxy.$executeNotebook(viewType, uri, undefined);
|
||||
}
|
||||
}
|
||||
|
||||
export class MainThreadNotebookController implements IMainNotebookController {
|
||||
private _mapping: Map<string, MainThreadNotebookDocument> = new Map();
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: ExtHostNotebookShape,
|
||||
private _mainThreadNotebook: MainThreadNotebooks,
|
||||
private _viewType: string
|
||||
) {
|
||||
}
|
||||
|
||||
async resolveNotebook(viewType: string, uri: URI): Promise<NotebookTextModel | undefined> {
|
||||
// TODO: resolve notebook should wait for all notebook document destory operations to finish.
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
return mainthreadNotebook.textModel;
|
||||
}
|
||||
|
||||
let notebookHandle = await this._mainThreadNotebook.resolveNotebook(viewType, uri);
|
||||
if (notebookHandle !== undefined) {
|
||||
mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
return mainthreadNotebook?.textModel;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
spliceNotebookCells(resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): void {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
|
||||
mainthreadNotebook?.textModel.updateRenderers(renderers);
|
||||
mainthreadNotebook?.textModel.$spliceNotebookCells(splices);
|
||||
}
|
||||
|
||||
spliceNotebookCellOutputs(resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): void {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(resource).toString());
|
||||
mainthreadNotebook?.textModel.updateRenderers(renderers);
|
||||
mainthreadNotebook?.textModel.$spliceNotebookCellOutputs(cellHandle, splices);
|
||||
}
|
||||
|
||||
async executeNotebook(viewType: string, uri: URI): Promise<void> {
|
||||
this._mainThreadNotebook.executeNotebook(viewType, uri);
|
||||
}
|
||||
|
||||
// Methods for ExtHost
|
||||
async createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void> {
|
||||
let document = new MainThreadNotebookDocument(this._proxy, handle, viewType, URI.revive(resource));
|
||||
this._mapping.set(URI.revive(resource).toString(), document);
|
||||
}
|
||||
|
||||
updateLanguages(resource: UriComponents, languages: string[]) {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.updateLanguages(languages);
|
||||
}
|
||||
|
||||
updateNotebookRenderers(resource: UriComponents, renderers: number[]): void {
|
||||
let document = this._mapping.get(URI.from(resource).toString());
|
||||
document?.textModel.updateRenderers(renderers);
|
||||
}
|
||||
|
||||
updateNotebookActiveCell(uri: URI, cellHandle: number): void {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
mainthreadNotebook?.textModel.updateActiveCell(cellHandle);
|
||||
}
|
||||
|
||||
async createRawCell(uri: URI, index: number, language: string, type: CellKind): Promise<NotebookCellTextModel | undefined> {
|
||||
let cell = await this._proxy.$createEmptyCell(this._viewType, uri, index, language, type);
|
||||
if (cell) {
|
||||
let mainCell = new NotebookCellTextModel(URI.revive(cell.uri), cell.handle, cell.source, cell.language, cell.cellKind, cell.outputs);
|
||||
return mainCell;
|
||||
}
|
||||
|
||||
return undefined;
|
||||
}
|
||||
|
||||
async deleteCell(uri: URI, index: number): Promise<boolean> {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
|
||||
if (mainthreadNotebook) {
|
||||
return mainthreadNotebook.deleteCell(uri, index);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
executeNotebookActiveCell(uri: URI): void {
|
||||
let mainthreadNotebook = this._mapping.get(URI.from(uri).toString());
|
||||
|
||||
if (mainthreadNotebook && mainthreadNotebook.textModel.activeCell) {
|
||||
this._proxy.$executeNotebook(this._viewType, uri, mainthreadNotebook.textModel.activeCell.handle);
|
||||
}
|
||||
}
|
||||
|
||||
async destoryNotebookDocument(notebook: INotebookTextModel): Promise<void> {
|
||||
let document = this._mapping.get(URI.from(notebook.uri).toString());
|
||||
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
let removeFromExtHost = await this._proxy.$destoryNotebookDocument(this._viewType, notebook.uri);
|
||||
if (removeFromExtHost) {
|
||||
document.dispose();
|
||||
this._mapping.delete(URI.from(notebook.uri).toString());
|
||||
}
|
||||
}
|
||||
|
||||
async save(uri: URI): Promise<boolean> {
|
||||
return this._proxy.$saveNotebook(this._viewType, uri);
|
||||
}
|
||||
}
|
||||
@@ -68,6 +68,7 @@ import { IURITransformerService } from 'vs/workbench/api/common/extHostUriTransf
|
||||
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
|
||||
import { IExtHostInitDataService } from 'vs/workbench/api/common/extHostInitDataService';
|
||||
import { find } from 'vs/base/common/arrays';
|
||||
import { ExtHostNotebookController } from 'vs/workbench/api/common/extHostNotebook';
|
||||
import { ExtHostTheming } from 'vs/workbench/api/common/extHostTheming';
|
||||
import { IExtHostTunnelService } from 'vs/workbench/api/common/extHostTunnelService';
|
||||
import { IExtHostApiDeprecationService } from 'vs/workbench/api/common/extHostApiDeprecationService';
|
||||
@@ -130,7 +131,8 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
const extHostComment = rpcProtocol.set(ExtHostContext.ExtHostComments, new ExtHostComments(rpcProtocol, extHostCommands, extHostDocuments));
|
||||
const extHostWindow = rpcProtocol.set(ExtHostContext.ExtHostWindow, new ExtHostWindow(rpcProtocol));
|
||||
const extHostProgress = rpcProtocol.set(ExtHostContext.ExtHostProgress, new ExtHostProgress(rpcProtocol.getProxy(MainContext.MainThreadProgress)));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHostLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostLabelService = rpcProtocol.set(ExtHostContext.ExtHosLabelService, new ExtHostLabelService(rpcProtocol));
|
||||
const extHostNotebook = rpcProtocol.set(ExtHostContext.ExtHostNotebook, new ExtHostNotebookController(rpcProtocol, extHostDocumentsAndEditors));
|
||||
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));
|
||||
@@ -363,6 +365,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
registerDocumentHighlightProvider(selector: vscode.DocumentSelector, provider: vscode.DocumentHighlightProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerDocumentHighlightProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
registerOnTypeRenameProvider(selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider, stopPattern?: RegExp): vscode.Disposable {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostLanguageFeatures.registerOnTypeRenameProvider(extension, checkSelector(selector), provider, stopPattern);
|
||||
},
|
||||
registerReferenceProvider(selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
return extHostLanguageFeatures.registerReferenceProvider(extension, checkSelector(selector), provider);
|
||||
},
|
||||
@@ -597,6 +603,15 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
createInputBox(): vscode.InputBox {
|
||||
return extHostQuickOpen.createInputBox(extension.identifier);
|
||||
},
|
||||
registerNotebookProvider: (viewType: string, provider: vscode.NotebookProvider) => {
|
||||
return extHostNotebook.registerNotebookProvider(extension, viewType, provider);
|
||||
},
|
||||
registerNotebookOutputRenderer: (type: string, outputFilter: vscode.NotebookOutputSelector, renderer: vscode.NotebookOutputRenderer) => {
|
||||
return extHostNotebook.registerNotebookOutputRenderer(type, extension, outputFilter, renderer);
|
||||
},
|
||||
get activeNotebookDocument(): vscode.NotebookDocument | undefined {
|
||||
return extHostNotebook.activeNotebookDocument;
|
||||
},
|
||||
get activeColorTheme(): vscode.ColorTheme {
|
||||
checkProposedApiEnabled(extension);
|
||||
return extHostTheming.activeColorTheme;
|
||||
@@ -1036,7 +1051,9 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
|
||||
WebviewContentState: extHostTypes.WebviewContentState,
|
||||
UIKind: UIKind,
|
||||
ColorThemeKind: extHostTypes.ColorThemeKind,
|
||||
TimelineItem: extHostTypes.TimelineItem
|
||||
TimelineItem: extHostTypes.TimelineItem,
|
||||
CellKind: extHostTypes.CellKind,
|
||||
CellOutputKind: extHostTypes.CellOutputKind
|
||||
};
|
||||
};
|
||||
}
|
||||
|
||||
@@ -51,6 +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, IOutput, INotebookDisplayOrder } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
|
||||
import { Dto } from 'vs/base/common/types';
|
||||
|
||||
@@ -365,6 +366,7 @@ export interface MainThreadLanguageFeaturesShape extends IDisposable {
|
||||
$registerHoverProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerEvaluatableExpressionProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerDocumentHighlightProvider(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerOnTypeRenameProvider(handle: number, selector: IDocumentFilterDto[], stopPattern: IRegExpDto | undefined): void;
|
||||
$registerReferenceSupport(handle: number, selector: IDocumentFilterDto[]): void;
|
||||
$registerQuickFixSupport(handle: number, selector: IDocumentFilterDto[], metadata: ICodeActionProviderMetadataDto, displayName: string): void;
|
||||
$registerDocumentFormattingSupport(handle: number, selector: IDocumentFilterDto[], extensionId: ExtensionIdentifier, displayName: string): void;
|
||||
@@ -580,6 +582,16 @@ export interface WebviewExtensionDescription {
|
||||
readonly location: UriComponents;
|
||||
}
|
||||
|
||||
export interface NotebookExtensionDescription {
|
||||
readonly id: ExtensionIdentifier;
|
||||
readonly location: UriComponents;
|
||||
}
|
||||
|
||||
export enum WebviewEditorCapabilities {
|
||||
Editable,
|
||||
SupportsHotExit,
|
||||
}
|
||||
|
||||
export interface CustomTextEditorCapabilities {
|
||||
readonly supportsMove?: boolean;
|
||||
}
|
||||
@@ -639,6 +651,49 @@ export interface ExtHostWebviewsShape {
|
||||
$onMoveCustomEditor(handle: WebviewPanelHandle, newResource: UriComponents, viewType: string): Promise<void>;
|
||||
}
|
||||
|
||||
export enum CellKind {
|
||||
Markdown = 1,
|
||||
Code = 2
|
||||
}
|
||||
|
||||
export enum CellOutputKind {
|
||||
Text = 1,
|
||||
Error = 2,
|
||||
Rich = 3
|
||||
}
|
||||
|
||||
export interface ICellDto {
|
||||
handle: number;
|
||||
uri: UriComponents,
|
||||
source: string[];
|
||||
language: string;
|
||||
cellKind: CellKind;
|
||||
outputs: IOutput[];
|
||||
}
|
||||
|
||||
export type NotebookCellsSplice = [
|
||||
number /* start */,
|
||||
number /* delete count */,
|
||||
ICellDto[]
|
||||
];
|
||||
|
||||
export type NotebookCellOutputsSplice = [
|
||||
number /* start */,
|
||||
number /* delete count */,
|
||||
IOutput[]
|
||||
];
|
||||
|
||||
export interface MainThreadNotebookShape extends IDisposable {
|
||||
$registerNotebookProvider(extension: NotebookExtensionDescription, viewType: string): Promise<void>;
|
||||
$unregisterNotebookProvider(viewType: string): Promise<void>;
|
||||
$registerNotebookRenderer(extension: NotebookExtensionDescription, type: string, selectors: INotebookMimeTypeSelector, handle: number, preloads: UriComponents[]): Promise<void>;
|
||||
$unregisterNotebookRenderer(handle: number): Promise<void>;
|
||||
$createNotebookDocument(handle: number, viewType: string, resource: UriComponents): Promise<void>;
|
||||
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
|
||||
$spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void>;
|
||||
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>;
|
||||
}
|
||||
|
||||
export interface MainThreadUrlsShape extends IDisposable {
|
||||
$registerUriHandler(handle: number, extensionId: ExtensionIdentifier): Promise<void>;
|
||||
$unregisterUriHandler(handle: number): Promise<void>;
|
||||
@@ -1237,6 +1292,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>;
|
||||
$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;
|
||||
@@ -1466,6 +1522,17 @@ export interface ExtHostCommentsShape {
|
||||
$toggleReaction(commentControllerHandle: number, threadHandle: number, uri: UriComponents, comment: modes.Comment, reaction: modes.CommentReaction): Promise<void>;
|
||||
}
|
||||
|
||||
export interface ExtHostNotebookShape {
|
||||
$resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined>;
|
||||
$executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void>;
|
||||
$createEmptyCell(viewType: string, uri: UriComponents, index: number, language: string, type: CellKind): Promise<ICellDto | undefined>;
|
||||
$deleteCell(viewType: string, uri: UriComponents, index: number): Promise<boolean>;
|
||||
$saveNotebook(viewType: string, uri: UriComponents): Promise<boolean>;
|
||||
$updateActiveEditor(viewType: string, uri: UriComponents): Promise<void>;
|
||||
$destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean>;
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void;
|
||||
}
|
||||
|
||||
export interface ExtHostStorageShape {
|
||||
$acceptValue(shared: boolean, key: string, value: object | undefined): void;
|
||||
}
|
||||
@@ -1531,6 +1598,7 @@ export const MainContext = {
|
||||
MainThreadTask: createMainId<MainThreadTaskShape>('MainThreadTask'),
|
||||
MainThreadWindow: createMainId<MainThreadWindowShape>('MainThreadWindow'),
|
||||
MainThreadLabelService: createMainId<MainThreadLabelServiceShape>('MainThreadLabelService'),
|
||||
MainThreadNotebook: createMainId<MainThreadNotebookShape>('MainThreadNotebook'),
|
||||
MainThreadTheming: createMainId<MainThreadThemingShape>('MainThreadTheming'),
|
||||
MainThreadTunnelService: createMainId<MainThreadTunnelServiceShape>('MainThreadTunnelService'),
|
||||
MainThreadTimeline: createMainId<MainThreadTimelineShape>('MainThreadTimeline')
|
||||
@@ -1567,7 +1635,8 @@ export const ExtHostContext = {
|
||||
ExtHostStorage: createMainId<ExtHostStorageShape>('ExtHostStorage'),
|
||||
ExtHostUrls: createExtId<ExtHostUrlsShape>('ExtHostUrls'),
|
||||
ExtHostOutputService: createMainId<ExtHostOutputServiceShape>('ExtHostOutputService'),
|
||||
ExtHostLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService'),
|
||||
ExtHosLabelService: createMainId<ExtHostLabelServiceShape>('ExtHostLabelService'),
|
||||
ExtHostNotebook: createMainId<ExtHostNotebookShape>('ExtHostNotebook'),
|
||||
ExtHostTheming: createMainId<ExtHostThemingShape>('ExtHostTheming'),
|
||||
ExtHostTunnelService: createMainId<ExtHostTunnelServiceShape>('ExtHostTunnelService'),
|
||||
ExtHostAuthentication: createMainId<ExtHostAuthenticationShape>('ExtHostAuthentication'),
|
||||
|
||||
@@ -238,7 +238,7 @@ export class ExtHostDocumentData extends MirrorTextModel {
|
||||
}
|
||||
}
|
||||
|
||||
class ExtHostDocumentLine implements vscode.TextLine {
|
||||
export class ExtHostDocumentLine implements vscode.TextLine {
|
||||
|
||||
private readonly _line: number;
|
||||
private readonly _text: string;
|
||||
|
||||
@@ -318,6 +318,26 @@ class DocumentHighlightAdapter {
|
||||
}
|
||||
}
|
||||
|
||||
class OnTypeRenameAdapter {
|
||||
constructor(
|
||||
private readonly _documents: ExtHostDocuments,
|
||||
private readonly _provider: vscode.OnTypeRenameProvider
|
||||
) { }
|
||||
|
||||
provideOnTypeRenameRanges(resource: URI, position: IPosition, token: CancellationToken): Promise<IRange[] | 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));
|
||||
}
|
||||
return undefined;
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
class ReferenceAdapter {
|
||||
|
||||
constructor(
|
||||
@@ -1350,7 +1370,8 @@ type Adapter = DocumentSymbolAdapter | CodeLensAdapter | DefinitionAdapter | Hov
|
||||
| RangeFormattingAdapter | OnTypeFormattingAdapter | NavigateTypeAdapter | RenameAdapter
|
||||
| SuggestAdapter | SignatureHelpAdapter | LinkProviderAdapter | ImplementationAdapter
|
||||
| TypeDefinitionAdapter | ColorProviderAdapter | FoldingProviderAdapter | DeclarationAdapter
|
||||
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter;
|
||||
| SelectionRangeAdapter | CallHierarchyAdapter | DocumentSemanticTokensAdapter | DocumentRangeSemanticTokensAdapter | EvaluatableExpressionAdapter
|
||||
| OnTypeRenameAdapter;
|
||||
|
||||
class AdapterData {
|
||||
constructor(
|
||||
@@ -1594,6 +1615,19 @@ export class ExtHostLanguageFeatures implements extHostProtocol.ExtHostLanguageF
|
||||
return this._withAdapter(handle, DocumentHighlightAdapter, adapter => adapter.provideDocumentHighlights(URI.revive(resource), position, token), undefined);
|
||||
}
|
||||
|
||||
// --- on type rename
|
||||
|
||||
registerOnTypeRenameProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.OnTypeRenameProvider, stopPattern?: 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);
|
||||
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);
|
||||
}
|
||||
|
||||
// --- references
|
||||
|
||||
registerReferenceProvider(extension: IExtensionDescription, selector: vscode.DocumentSelector, provider: vscode.ReferenceProvider): vscode.Disposable {
|
||||
|
||||
621
src/vs/workbench/api/common/extHostNotebook.ts
Normal file
621
src/vs/workbench/api/common/extHostNotebook.ts
Normal file
@@ -0,0 +1,621 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as vscode from 'vscode';
|
||||
import { ExtHostNotebookShape, IMainContext, MainThreadNotebookShape, MainContext, ICellDto, NotebookCellsSplice, NotebookCellOutputsSplice, CellKind, CellOutputKind } from 'vs/workbench/api/common/extHost.protocol';
|
||||
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
|
||||
import { Disposable as VSCodeDisposable } from './extHostTypes';
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { DisposableStore, Disposable } from 'vs/base/common/lifecycle';
|
||||
import { readonly } from 'vs/base/common/errors';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
|
||||
import { INotebookDisplayOrder, ITransformedDisplayOutputDto, IOrderedMimeType, IStreamOutput, IErrorOutput, mimeTypeSupportedByCore, IOutput, sortMimeTypes, diff, CellUri } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { ISplice } from 'vs/base/common/sequence';
|
||||
|
||||
export class ExtHostCell implements vscode.NotebookCell {
|
||||
|
||||
public source: string[];
|
||||
private _outputs: any[];
|
||||
private _onDidChangeOutputs = new Emitter<ISplice<vscode.CellOutput>[]>();
|
||||
onDidChangeOutputs: Event<ISplice<vscode.CellOutput>[]> = this._onDidChangeOutputs.event;
|
||||
private _textDocument: vscode.TextDocument | undefined;
|
||||
private _initalVersion: number = -1;
|
||||
private _outputMapping = new Set<vscode.CellOutput>();
|
||||
|
||||
constructor(
|
||||
readonly handle: number,
|
||||
readonly uri: URI,
|
||||
private _content: string,
|
||||
public cellKind: CellKind,
|
||||
public language: string,
|
||||
outputs: any[]
|
||||
) {
|
||||
this.source = this._content.split(/\r|\n|\r\n/g);
|
||||
this._outputs = outputs;
|
||||
}
|
||||
|
||||
get outputs() {
|
||||
return this._outputs;
|
||||
}
|
||||
|
||||
set outputs(newOutputs: vscode.CellOutput[]) {
|
||||
let diffs = diff<vscode.CellOutput>(this._outputs || [], newOutputs || [], (a) => {
|
||||
return this._outputMapping.has(a);
|
||||
});
|
||||
|
||||
diffs.forEach(diff => {
|
||||
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
||||
this._outputMapping.delete(this._outputs[i]);
|
||||
}
|
||||
|
||||
diff.toInsert.forEach(output => {
|
||||
this._outputMapping.add(output);
|
||||
});
|
||||
});
|
||||
|
||||
this._outputs = newOutputs;
|
||||
this._onDidChangeOutputs.fire(diffs);
|
||||
}
|
||||
|
||||
getContent(): string {
|
||||
if (this._textDocument && this._initalVersion !== this._textDocument?.version) {
|
||||
return this._textDocument.getText();
|
||||
} else {
|
||||
return this.source.join('\n');
|
||||
}
|
||||
}
|
||||
|
||||
attachTextDocument(document: vscode.TextDocument) {
|
||||
this._textDocument = document;
|
||||
this._initalVersion = this._textDocument.version;
|
||||
}
|
||||
|
||||
detachTextDocument(document: vscode.TextDocument) {
|
||||
if (this._textDocument && this._textDocument.version !== this._initalVersion) {
|
||||
this.source = this._textDocument.getText().split(/\r|\n|\r\n/g);
|
||||
}
|
||||
|
||||
this._textDocument = undefined;
|
||||
this._initalVersion = -1;
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostNotebookDocument extends Disposable implements vscode.NotebookDocument {
|
||||
private static _handlePool: number = 0;
|
||||
readonly handle = ExtHostNotebookDocument._handlePool++;
|
||||
|
||||
private _cells: ExtHostCell[] = [];
|
||||
|
||||
private _cellDisposableMapping = new Map<number, DisposableStore>();
|
||||
|
||||
get cells() {
|
||||
return this._cells;
|
||||
}
|
||||
|
||||
set cells(newCells: ExtHostCell[]) {
|
||||
let diffs = diff<ExtHostCell>(this._cells, newCells, (a) => {
|
||||
return this._cellDisposableMapping.has(a.handle);
|
||||
});
|
||||
|
||||
diffs.forEach(diff => {
|
||||
for (let i = diff.start; i < diff.start + diff.deleteCount; i++) {
|
||||
this._cellDisposableMapping.get(this._cells[i].handle)?.clear();
|
||||
this._cellDisposableMapping.delete(this._cells[i].handle);
|
||||
}
|
||||
|
||||
diff.toInsert.forEach(cell => {
|
||||
this._cellDisposableMapping.set(cell.handle, new DisposableStore());
|
||||
this._cellDisposableMapping.get(cell.handle)?.add(cell.onDidChangeOutputs((outputDiffs) => {
|
||||
this.eventuallyUpdateCellOutputs(cell, outputDiffs);
|
||||
}));
|
||||
});
|
||||
});
|
||||
|
||||
this._cells = newCells;
|
||||
this.eventuallyUpdateCells(diffs);
|
||||
}
|
||||
|
||||
private _languages: string[] = [];
|
||||
|
||||
get languages() {
|
||||
return this._languages = [];
|
||||
}
|
||||
|
||||
set languages(newLanguages: string[]) {
|
||||
this._languages = newLanguages;
|
||||
this._proxy.$updateNotebookLanguages(this.viewType, this.uri, this._languages);
|
||||
}
|
||||
|
||||
private _displayOrder: string[] = [];
|
||||
|
||||
get displayOrder() {
|
||||
return this._displayOrder;
|
||||
}
|
||||
|
||||
set displayOrder(newOrder: string[]) {
|
||||
this._displayOrder = newOrder;
|
||||
}
|
||||
|
||||
constructor(
|
||||
private readonly _proxy: MainThreadNotebookShape,
|
||||
public viewType: string,
|
||||
public uri: URI,
|
||||
public renderingHandler: ExtHostNotebookOutputRenderingHandler
|
||||
) {
|
||||
super();
|
||||
}
|
||||
|
||||
dispose() {
|
||||
super.dispose();
|
||||
this._cellDisposableMapping.forEach(cell => cell.dispose());
|
||||
}
|
||||
|
||||
get fileName() { return this.uri.fsPath; }
|
||||
|
||||
get isDirty() { return false; }
|
||||
|
||||
eventuallyUpdateCells(diffs: ISplice<ExtHostCell>[]) {
|
||||
let renderers = new Set<number>();
|
||||
let diffDtos: NotebookCellsSplice[] = [];
|
||||
|
||||
diffDtos = diffs.map(diff => {
|
||||
let inserts = diff.toInsert;
|
||||
|
||||
let cellDtos = inserts.map(cell => {
|
||||
let outputs: IOutput[] = [];
|
||||
if (cell.outputs.length) {
|
||||
outputs = cell.outputs.map(output => {
|
||||
if (output.outputKind === CellOutputKind.Rich) {
|
||||
const ret = this.transformMimeTypes(cell, output);
|
||||
|
||||
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
|
||||
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
return output as IStreamOutput | IErrorOutput;
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
return {
|
||||
uri: cell.uri,
|
||||
handle: cell.handle,
|
||||
source: cell.source,
|
||||
language: cell.language,
|
||||
cellKind: cell.cellKind,
|
||||
outputs: outputs,
|
||||
isDirty: false
|
||||
};
|
||||
});
|
||||
|
||||
return [diff.start, diff.deleteCount, cellDtos];
|
||||
});
|
||||
|
||||
this._proxy.$spliceNotebookCells(
|
||||
this.viewType,
|
||||
this.uri,
|
||||
diffDtos,
|
||||
Array.from(renderers)
|
||||
);
|
||||
}
|
||||
|
||||
eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<vscode.CellOutput>[]) {
|
||||
let renderers = new Set<number>();
|
||||
let outputDtos: NotebookCellOutputsSplice[] = diffs.map(diff => {
|
||||
let outputs = diff.toInsert;
|
||||
|
||||
let transformedOutputs = outputs.map(output => {
|
||||
if (output.outputKind === CellOutputKind.Rich) {
|
||||
const ret = this.transformMimeTypes(cell, output);
|
||||
|
||||
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
|
||||
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
|
||||
}
|
||||
return ret;
|
||||
} else {
|
||||
return output as IStreamOutput | IErrorOutput;
|
||||
}
|
||||
});
|
||||
|
||||
return [diff.start, diff.deleteCount, transformedOutputs];
|
||||
});
|
||||
|
||||
this._proxy.$spliceNotebookCellOutputs(this.viewType, this.uri, cell.handle, outputDtos, Array.from(renderers));
|
||||
}
|
||||
|
||||
insertCell(index: number, cell: ExtHostCell) {
|
||||
this.cells.splice(index, 0, cell);
|
||||
|
||||
if (!this._cellDisposableMapping.has(cell.handle)) {
|
||||
this._cellDisposableMapping.set(cell.handle, new DisposableStore());
|
||||
}
|
||||
|
||||
let store = this._cellDisposableMapping.get(cell.handle)!;
|
||||
|
||||
store.add(cell.onDidChangeOutputs((diffs) => {
|
||||
this.eventuallyUpdateCellOutputs(cell, diffs);
|
||||
}));
|
||||
}
|
||||
|
||||
deleteCell(index: number): boolean {
|
||||
if (index >= this.cells.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let cell = this.cells[index];
|
||||
this._cellDisposableMapping.get(cell.handle)?.dispose();
|
||||
this._cellDisposableMapping.delete(cell.handle);
|
||||
|
||||
this.cells.splice(index, 1);
|
||||
return true;
|
||||
}
|
||||
|
||||
|
||||
transformMimeTypes(cell: ExtHostCell, output: vscode.CellDisplayOutput): ITransformedDisplayOutputDto {
|
||||
let mimeTypes = Object.keys(output.data);
|
||||
|
||||
// TODO@rebornix, the document display order might be assigned a bit later. We need to postpone sending the outputs to the core side.
|
||||
let coreDisplayOrder = this.renderingHandler.outputDisplayOrder;
|
||||
const sorted = sortMimeTypes(mimeTypes, coreDisplayOrder?.userOrder || [], this._displayOrder, coreDisplayOrder?.defaultOrder || []);
|
||||
|
||||
let orderMimeTypes: IOrderedMimeType[] = [];
|
||||
|
||||
sorted.forEach(mimeType => {
|
||||
let handlers = this.renderingHandler.findBestMatchedRenderer(mimeType);
|
||||
|
||||
if (handlers.length) {
|
||||
let renderedOutput = handlers[0].render(this, cell, output, mimeType);
|
||||
|
||||
orderMimeTypes.push({
|
||||
mimeType: mimeType,
|
||||
isResolved: true,
|
||||
rendererId: handlers[0].handle,
|
||||
output: renderedOutput
|
||||
});
|
||||
|
||||
for (let i = 1; i < handlers.length; i++) {
|
||||
orderMimeTypes.push({
|
||||
mimeType: mimeType,
|
||||
isResolved: false,
|
||||
rendererId: handlers[i].handle
|
||||
});
|
||||
}
|
||||
|
||||
if (mimeTypeSupportedByCore(mimeType)) {
|
||||
orderMimeTypes.push({
|
||||
mimeType: mimeType,
|
||||
isResolved: false,
|
||||
rendererId: -1
|
||||
});
|
||||
}
|
||||
} else {
|
||||
orderMimeTypes.push({
|
||||
mimeType: mimeType,
|
||||
isResolved: false
|
||||
});
|
||||
}
|
||||
});
|
||||
|
||||
return {
|
||||
outputKind: output.outputKind,
|
||||
data: output.data,
|
||||
orderedMimeTypes: orderMimeTypes,
|
||||
pickedMimeTypeIndex: 0
|
||||
};
|
||||
}
|
||||
|
||||
getCell(cellHandle: number) {
|
||||
return this.cells.find(cell => cell.handle === cellHandle);
|
||||
}
|
||||
|
||||
attachCellTextDocument(textDocument: vscode.TextDocument) {
|
||||
let cell = this.cells.find(cell => cell.uri.toString() === textDocument.uri.toString());
|
||||
if (cell) {
|
||||
cell.attachTextDocument(textDocument);
|
||||
}
|
||||
}
|
||||
|
||||
detachCellTextDocument(textDocument: vscode.TextDocument) {
|
||||
let cell = this.cells.find(cell => cell.uri.toString() === textDocument.uri.toString());
|
||||
if (cell) {
|
||||
cell.detachTextDocument(textDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
|
||||
private _viewColumn: vscode.ViewColumn | undefined;
|
||||
private static _cellhandlePool: number = 0;
|
||||
|
||||
constructor(
|
||||
viewType: string,
|
||||
readonly id: string,
|
||||
public uri: URI,
|
||||
public document: ExtHostNotebookDocument,
|
||||
private _documentsAndEditors: ExtHostDocumentsAndEditors
|
||||
) {
|
||||
super();
|
||||
this._register(this._documentsAndEditors.onDidAddDocuments(documents => {
|
||||
for (const { document: textDocument } of documents) {
|
||||
let data = CellUri.parse(textDocument.uri);
|
||||
if (data) {
|
||||
if (this.document.uri.toString() === data.notebook.toString()) {
|
||||
document.attachCellTextDocument(textDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
||||
this._register(this._documentsAndEditors.onDidRemoveDocuments(documents => {
|
||||
for (const { document: textDocument } of documents) {
|
||||
let data = CellUri.parse(textDocument.uri);
|
||||
if (data) {
|
||||
if (this.document.uri.toString() === data.notebook.toString()) {
|
||||
document.detachCellTextDocument(textDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
createCell(content: string, language: string, type: CellKind, outputs: vscode.CellOutput[]): vscode.NotebookCell {
|
||||
const handle = ExtHostNotebookEditor._cellhandlePool++;
|
||||
const uri = CellUri.generate(this.document.uri, handle);
|
||||
const cell = new ExtHostCell(handle, uri, content, type, language, outputs);
|
||||
return cell;
|
||||
}
|
||||
|
||||
get viewColumn(): vscode.ViewColumn | undefined {
|
||||
return this._viewColumn;
|
||||
}
|
||||
|
||||
set viewColumn(value) {
|
||||
throw readonly('viewColumn');
|
||||
}
|
||||
}
|
||||
|
||||
export class ExtHostNotebookOutputRenderer {
|
||||
private static _handlePool: number = 0;
|
||||
readonly handle = ExtHostNotebookOutputRenderer._handlePool++;
|
||||
|
||||
constructor(
|
||||
public type: string,
|
||||
public filter: vscode.NotebookOutputSelector,
|
||||
public renderer: vscode.NotebookOutputRenderer
|
||||
) {
|
||||
|
||||
}
|
||||
|
||||
matches(mimeType: string): boolean {
|
||||
if (this.filter.subTypes) {
|
||||
if (this.filter.subTypes.indexOf(mimeType) >= 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
render(document: ExtHostNotebookDocument, cell: ExtHostCell, output: vscode.CellOutput, mimeType: string): string {
|
||||
let html = this.renderer.render(document, cell, output, mimeType);
|
||||
|
||||
return html;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ExtHostNotebookOutputRenderingHandler {
|
||||
outputDisplayOrder: INotebookDisplayOrder | undefined;
|
||||
findBestMatchedRenderer(mimeType: string): ExtHostNotebookOutputRenderer[];
|
||||
}
|
||||
|
||||
export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostNotebookOutputRenderingHandler {
|
||||
private static _handlePool: number = 0;
|
||||
|
||||
private readonly _proxy: MainThreadNotebookShape;
|
||||
private readonly _notebookProviders = new Map<string, { readonly provider: vscode.NotebookProvider, readonly extension: IExtensionDescription }>();
|
||||
private readonly _documents = new Map<string, ExtHostNotebookDocument>();
|
||||
private readonly _editors = new Map<string, ExtHostNotebookEditor>();
|
||||
private readonly _notebookOutputRenderers = new Map<number, ExtHostNotebookOutputRenderer>();
|
||||
private _outputDisplayOrder: INotebookDisplayOrder | undefined;
|
||||
|
||||
get outputDisplayOrder(): INotebookDisplayOrder | undefined {
|
||||
return this._outputDisplayOrder;
|
||||
}
|
||||
|
||||
private _activeNotebookDocument: ExtHostNotebookDocument | undefined;
|
||||
|
||||
get activeNotebookDocument() {
|
||||
return this._activeNotebookDocument;
|
||||
}
|
||||
|
||||
constructor(mainContext: IMainContext, private _documentsAndEditors: ExtHostDocumentsAndEditors) {
|
||||
this._proxy = mainContext.getProxy(MainContext.MainThreadNotebook);
|
||||
}
|
||||
|
||||
registerNotebookOutputRenderer(
|
||||
type: string,
|
||||
extension: IExtensionDescription,
|
||||
filter: vscode.NotebookOutputSelector,
|
||||
renderer: vscode.NotebookOutputRenderer
|
||||
): vscode.Disposable {
|
||||
let extHostRenderer = new ExtHostNotebookOutputRenderer(type, filter, renderer);
|
||||
this._notebookOutputRenderers.set(extHostRenderer.handle, extHostRenderer);
|
||||
this._proxy.$registerNotebookRenderer({ id: extension.identifier, location: extension.extensionLocation }, type, filter, extHostRenderer.handle, renderer.preloads || []);
|
||||
return new VSCodeDisposable(() => {
|
||||
this._notebookOutputRenderers.delete(extHostRenderer.handle);
|
||||
this._proxy.$unregisterNotebookRenderer(extHostRenderer.handle);
|
||||
});
|
||||
}
|
||||
|
||||
findBestMatchedRenderer(mimeType: string): ExtHostNotebookOutputRenderer[] {
|
||||
let matches: ExtHostNotebookOutputRenderer[] = [];
|
||||
for (let renderer of this._notebookOutputRenderers) {
|
||||
if (renderer[1].matches(mimeType)) {
|
||||
matches.push(renderer[1]);
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
registerNotebookProvider(
|
||||
extension: IExtensionDescription,
|
||||
viewType: string,
|
||||
provider: vscode.NotebookProvider,
|
||||
): vscode.Disposable {
|
||||
|
||||
if (this._notebookProviders.has(viewType)) {
|
||||
throw new Error(`Notebook provider for '${viewType}' already registered`);
|
||||
}
|
||||
|
||||
this._notebookProviders.set(viewType, { extension, provider });
|
||||
this._proxy.$registerNotebookProvider({ id: extension.identifier, location: extension.extensionLocation }, viewType);
|
||||
return new VSCodeDisposable(() => {
|
||||
this._notebookProviders.delete(viewType);
|
||||
this._proxy.$unregisterNotebookProvider(viewType);
|
||||
});
|
||||
}
|
||||
|
||||
async $resolveNotebook(viewType: string, uri: UriComponents): Promise<number | undefined> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
|
||||
if (provider) {
|
||||
if (!this._documents.has(URI.revive(uri).toString())) {
|
||||
let document = new ExtHostNotebookDocument(this._proxy, viewType, URI.revive(uri), this);
|
||||
await this._proxy.$createNotebookDocument(
|
||||
document.handle,
|
||||
viewType,
|
||||
uri
|
||||
);
|
||||
|
||||
this._documents.set(URI.revive(uri).toString(), document);
|
||||
}
|
||||
|
||||
let editor = new ExtHostNotebookEditor(
|
||||
viewType,
|
||||
`${ExtHostNotebookController._handlePool++}`,
|
||||
URI.revive(uri),
|
||||
this._documents.get(URI.revive(uri).toString())!,
|
||||
this._documentsAndEditors
|
||||
);
|
||||
|
||||
this._editors.set(URI.revive(uri).toString(), editor);
|
||||
await provider.provider.resolveNotebook(editor);
|
||||
// await editor.document.$updateCells();
|
||||
return editor.document.handle;
|
||||
}
|
||||
|
||||
return Promise.resolve(undefined);
|
||||
}
|
||||
|
||||
async $executeNotebook(viewType: string, uri: UriComponents, cellHandle: number | undefined): Promise<void> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
|
||||
if (!provider) {
|
||||
return;
|
||||
}
|
||||
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (!document) {
|
||||
return;
|
||||
}
|
||||
|
||||
let cell = cellHandle !== undefined ? document.getCell(cellHandle) : undefined;
|
||||
return provider.provider.executeCell(document!, cell);
|
||||
}
|
||||
|
||||
async $createEmptyCell(viewType: string, uri: URI, index: number, language: string, type: CellKind): Promise<ICellDto | undefined> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
|
||||
if (provider) {
|
||||
let editor = this._editors.get(URI.revive(uri).toString());
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
let rawCell = editor?.createCell('', language, type, []) as ExtHostCell;
|
||||
document?.insertCell(index, rawCell!);
|
||||
|
||||
let allDocuments = this._documentsAndEditors.allDocuments();
|
||||
for (let { document: textDocument } of allDocuments) {
|
||||
let data = CellUri.parse(textDocument.uri);
|
||||
if (data) {
|
||||
if (uri.toString() === data.notebook.toString() && textDocument.uri.toString() === rawCell.uri.toString()) {
|
||||
rawCell.attachTextDocument(textDocument);
|
||||
}
|
||||
}
|
||||
}
|
||||
return {
|
||||
uri: rawCell.uri,
|
||||
handle: rawCell.handle,
|
||||
source: rawCell.source,
|
||||
language: rawCell.language,
|
||||
cellKind: rawCell.cellKind,
|
||||
outputs: []
|
||||
};
|
||||
}
|
||||
|
||||
return undefined; // {{SQL CARBON EDIT}} strict-null-check
|
||||
}
|
||||
|
||||
async $deleteCell(viewType: string, uri: UriComponents, index: number): Promise<boolean> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
|
||||
if (!provider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (document) {
|
||||
return document.deleteCell(index);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async $saveNotebook(viewType: string, uri: UriComponents): Promise<boolean> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (provider && document) {
|
||||
return await provider.provider.save(document);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
async $updateActiveEditor(viewType: string, uri: UriComponents): Promise<void> {
|
||||
this._activeNotebookDocument = this._documents.get(URI.revive(uri).toString());
|
||||
}
|
||||
|
||||
async $destoryNotebookDocument(viewType: string, uri: UriComponents): Promise<boolean> {
|
||||
let provider = this._notebookProviders.get(viewType);
|
||||
|
||||
if (!provider) {
|
||||
return false;
|
||||
}
|
||||
|
||||
let document = this._documents.get(URI.revive(uri).toString());
|
||||
|
||||
if (document) {
|
||||
document.dispose();
|
||||
this._documents.delete(URI.revive(uri).toString());
|
||||
}
|
||||
|
||||
let editor = this._editors.get(URI.revive(uri).toString());
|
||||
|
||||
if (editor) {
|
||||
editor.dispose();
|
||||
this._editors.delete(URI.revive(uri).toString());
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
$acceptDisplayOrder(displayOrder: INotebookDisplayOrder): void {
|
||||
this._outputDisplayOrder = displayOrder;
|
||||
}
|
||||
}
|
||||
@@ -2559,6 +2559,21 @@ export enum ColorThemeKind {
|
||||
|
||||
//#endregion Theming
|
||||
|
||||
//#region Notebook
|
||||
|
||||
export enum CellKind {
|
||||
Markdown = 1,
|
||||
Code = 2
|
||||
}
|
||||
|
||||
export enum CellOutputKind {
|
||||
Text = 1,
|
||||
Error = 2,
|
||||
Rich = 3
|
||||
}
|
||||
|
||||
//#endregion
|
||||
|
||||
//#region Timeline
|
||||
|
||||
@es5ClassCompat
|
||||
|
||||
Reference in New Issue
Block a user