Merge from vscode 61d5f2b82f17bf9f99f56405204caab88a7e8747

This commit is contained in:
ADS Merger
2020-03-19 06:57:07 +00:00
parent 03ce5d1ba7
commit 84f67f61c4
137 changed files with 13234 additions and 796 deletions

View File

@@ -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';

View File

@@ -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 {

View 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);
}
}

View File

@@ -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
};
};
}

View File

@@ -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'),

View File

@@ -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;

View File

@@ -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 {

View 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;
}
}

View File

@@ -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