Merge from vscode 1ec43773e37997841c5af42b33ddb180e9735bf2

This commit is contained in:
ADS Merger
2020-03-29 01:29:32 +00:00
parent 586ec50916
commit a64304602e
316 changed files with 6524 additions and 11687 deletions

View File

@@ -490,6 +490,10 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
checkProposedApiEnabled(extension);
return extHostTerminalService.onDidWriteTerminalData(listener, thisArg, disposables);
},
getEnvironmentVariableCollection(persistent?: boolean): vscode.EnvironmentVariableCollection {
checkProposedApiEnabled(extension);
return extHostTerminalService.getEnvironmentVariableCollection(extension, persistent);
},
get state() {
return extHostWindow.state;
},
@@ -600,15 +604,6 @@ 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;
@@ -925,6 +920,19 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
}
};
// namespace: notebook
const notebook: typeof vscode.notebook = {
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;
}
};
return <typeof vscode>{
// {{SQL CARBON EDIT}} - Expose the VS Code version here for extensions that rely on it
version: initData.vscodeVersion,
@@ -939,6 +947,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
comment,
comments,
tasks,
notebook,
window,
workspace,
// types
@@ -974,6 +983,7 @@ export function createApiFactoryAndRegisterActors(accessor: ServicesAccessor): I
DocumentLink: extHostTypes.DocumentLink,
DocumentSymbol: extHostTypes.DocumentSymbol,
EndOfLine: extHostTypes.EndOfLine,
EnvironmentVariableMutatorType: extHostTypes.EnvironmentVariableMutatorType,
EvaluatableExpression: extHostTypes.EvaluatableExpression,
EventEmitter: Emitter,
ExtensionKind: extHostTypes.ExtensionKind,

View File

@@ -51,9 +51,10 @@ 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, NotebookCellMetadata, NotebookDocumentMetadata } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { INotebookMimeTypeSelector, IOutput, INotebookDisplayOrder, NotebookCellMetadata, NotebookDocumentMetadata, ICellEditOperation, NotebookCellsChangedEvent } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { CallHierarchyItem } from 'vs/workbench/contrib/callHierarchy/common/callHierarchy';
import { Dto } from 'vs/base/common/types';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
// {{SQL CARBON EDIT}}
import { ITreeItem as sqlITreeItem } from 'sql/workbench/common/views';
@@ -161,8 +162,9 @@ export interface MainThreadAuthenticationShape extends IDisposable {
$registerAuthenticationProvider(id: string, displayName: string): void;
$unregisterAuthenticationProvider(id: string): void;
$onDidChangeSessions(providerId: string, event: modes.AuthenticationSessionsChangeEvent): void;
$getSessionsPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$loginPrompt(providerId: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$getSessionsPrompt(providerId: string, accountName: string, providerName: string, extensionId: string, extensionName: string): Promise<boolean>;
$loginPrompt(providerName: string, extensionName: string): Promise<boolean>;
$setTrustedExtension(providerId: string, accountName: string, extensionId: string, extensionName: string): Promise<void>;
}
export interface MainThreadConfigurationShape extends IDisposable {
@@ -440,6 +442,7 @@ export interface MainThreadTerminalServiceShape extends IDisposable {
$stopSendingDataEvents(): void;
$startHandlingLinks(): void;
$stopHandlingLinks(): void;
$setEnvironmentVariableCollection(extensionIdentifier: string, persistent: boolean, collection: ISerializableEnvironmentVariableCollection | undefined): void;
// Process
$sendProcessTitle(terminalId: number, title: string): void;
@@ -696,10 +699,10 @@ export interface MainThreadNotebookShape extends IDisposable {
$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>;
$tryApplyEdits(viewType: string, resource: UriComponents, modelVersionId: number, edits: ICellEditOperation[], renderers: number[]): Promise<boolean>;
$updateNotebookLanguages(viewType: string, resource: UriComponents, languages: string[]): Promise<void>;
$updateNotebookMetadata(viewType: string, resource: UriComponents, metadata: NotebookDocumentMetadata): Promise<void>;
$updateNotebookCellMetadata(viewType: string, resource: UriComponents, handle: number, metadata: NotebookCellMetadata | undefined): Promise<void>;
$spliceNotebookCells(viewType: string, resource: UriComponents, splices: NotebookCellsSplice[], renderers: number[]): Promise<void>;
$spliceNotebookCellOutputs(viewType: string, resource: UriComponents, cellHandle: number, splices: NotebookCellOutputsSplice[], renderers: number[]): Promise<void>;
$postMessage(handle: number, value: any): Promise<boolean>;
}
@@ -1391,6 +1394,7 @@ export interface ExtHostTerminalServiceShape {
$getAvailableShells(): Promise<IShellDefinitionDto[]>;
$getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
$handleLink(id: number, link: string): Promise<boolean>;
$initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
}
export interface ExtHostSCMShape {
@@ -1535,13 +1539,12 @@ export interface ExtHostCommentsShape {
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;
$onDidReceiveMessage(uri: UriComponents, message: any): void;
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void;
}
export interface ExtHostStorageShape {

View File

@@ -50,6 +50,7 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
getAccessToken: async () => {
const isAllowed = await this._proxy.$getSessionsPrompt(
provider.id,
session.accountName,
provider.displayName,
ExtensionIdentifier.toKey(requestingExtension.identifier),
requestingExtension.displayName || requestingExtension.name);
@@ -70,12 +71,15 @@ export class ExtHostAuthentication implements ExtHostAuthenticationShape {
throw new Error(`No authentication provider with id '${providerId}' is currently registered.`);
}
const isAllowed = await this._proxy.$loginPrompt(provider.id, provider.displayName, ExtensionIdentifier.toKey(requestingExtension.identifier), requestingExtension.displayName || requestingExtension.name);
const extensionName = requestingExtension.displayName || requestingExtension.name;
const isAllowed = await this._proxy.$loginPrompt(provider.displayName, extensionName);
if (!isAllowed) {
throw new Error('User did not consent to login.');
}
return provider.login(scopes);
const newSession = await provider.login(scopes);
await this._proxy.$setTrustedExtension(provider.id, newSession.accountName, ExtensionIdentifier.toKey(requestingExtension.identifier), extensionName);
return newSession;
}
registerAuthenticationProvider(provider: vscode.AuthenticationProvider): vscode.Disposable {

View File

@@ -3,17 +3,17 @@
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as vscode from 'vscode';
import { readonly } from 'vs/base/common/errors';
import { Emitter, Event } from 'vs/base/common/event';
import { Disposable, DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import { ISplice } from 'vs/base/common/sequence';
import { URI, UriComponents } from 'vs/base/common/uri';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { CellKind, CellOutputKind, ExtHostNotebookShape, ICellDto, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice, NotebookCellsSplice } from 'vs/workbench/api/common/extHost.protocol';
import { CellKind, CellOutputKind, ExtHostNotebookShape, IMainContext, MainContext, MainThreadNotebookShape, NotebookCellOutputsSplice } from 'vs/workbench/api/common/extHost.protocol';
import { ExtHostCommands } from 'vs/workbench/api/common/extHostCommands';
import { ExtHostDocumentsAndEditors } from 'vs/workbench/api/common/extHostDocumentsAndEditors';
import { CellUri, diff, IErrorOutput, INotebookDisplayOrder, IOrderedMimeType, IOutput, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, sortMimeTypes } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import * as vscode from 'vscode';
import { CellEditType, CellUri, diff, ICellEditOperation, ICellInsertEdit, IErrorOutput, INotebookDisplayOrder, INotebookEditData, IOrderedMimeType, IStreamOutput, ITransformedDisplayOutputDto, mimeTypeSupportedByCore, NotebookCellsChangedEvent, NotebookCellsSplice2, sortMimeTypes, ICellDeleteEdit } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { Disposable as VSCodeDisposable } from './extHostTypes';
interface IObservable<T> {
@@ -44,7 +44,8 @@ const notebookDocumentMetadataDefaults: vscode.NotebookDocumentMetadata = {
};
export class ExtHostCell extends Disposable implements vscode.NotebookCell {
public source: string[];
private originalSource: string[];
private _outputs: any[];
private _onDidChangeOutputs = new Emitter<ISplice<vscode.CellOutput>[]>();
onDidChangeOutputs: Event<ISplice<vscode.CellOutput>[]> = this._onDidChangeOutputs.event;
@@ -55,21 +56,28 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
private _metadataChangeListener: IDisposable;
get source() {
if (this._textDocument && this._initalVersion !== this._textDocument?.version) {
return this._textDocument.getText();
} else {
return this.originalSource.join('\n');
}
}
constructor(
private viewType: string,
private documentUri: URI,
readonly handle: number,
readonly uri: URI,
private _content: string,
public cellKind: CellKind,
public readonly cellKind: CellKind,
public language: string,
outputs: any[],
_metadata: vscode.NotebookCellMetadata | undefined,
private _proxy: MainThreadNotebookShape
) {
super();
this.source = this._content.split(/\r|\n|\r\n/g);
this.originalSource = this._content.split(/\r|\n|\r\n/g);
this._outputs = outputs;
const observableMetadata = getObservable(_metadata || {} as any);
@@ -106,7 +114,7 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
return this._metadata;
}
set metadata(newMetadata: vscode.NotebookCellMetadata | undefined) {
set metadata(newMetadata: vscode.NotebookCellMetadata) {
this._metadataChangeListener.dispose();
const observableMetadata = getObservable(newMetadata || {} as any); // TODO defaults
this._metadata = observableMetadata.proxy;
@@ -125,7 +133,7 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
if (this._textDocument && this._initalVersion !== this._textDocument?.version) {
return this._textDocument.getText();
} else {
return this.source.join('\n');
return this.originalSource.join('\n');
}
}
@@ -134,9 +142,9 @@ export class ExtHostCell extends Disposable implements vscode.NotebookCell {
this._initalVersion = this._textDocument.version;
}
detachTextDocument(document: vscode.TextDocument) {
detachTextDocument() {
if (this._textDocument && this._textDocument.version !== this._initalVersion) {
this.source = this._textDocument.getText().split(/\r|\n|\r\n/g);
this.originalSource = this._textDocument.getText().split(/\r|\n|\r\n/g);
}
this._textDocument = undefined;
@@ -156,29 +164,6 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
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() {
@@ -211,8 +196,15 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
this._displayOrder = newOrder;
}
private _versionId = 0;
get versionId() {
return this._versionId;
}
constructor(
private readonly _proxy: MainThreadNotebookShape,
private _documentsAndEditors: ExtHostDocumentsAndEditors,
public viewType: string,
public uri: URI,
public renderingHandler: ExtHostNotebookOutputRenderingHandler
@@ -229,51 +221,47 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
get isDirty() { return false; }
eventuallyUpdateCells(diffs: ISplice<ExtHostCell>[]) {
let renderers = new Set<number>();
let diffDtos: NotebookCellsSplice[] = [];
accpetModelChanged(event: NotebookCellsChangedEvent) {
this.$spliceNotebookCells(event.changes);
this._versionId = event.versionId;
}
diffDtos = diffs.map(diff => {
let inserts = diff.toInsert;
private $spliceNotebookCells(splices: NotebookCellsSplice2[]): void {
if (!splices.length) {
return;
}
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);
splices.reverse().forEach(splice => {
let cellDtos = splice[2];
let newCells = cellDtos.map(cell => {
const extCell = new ExtHostCell(this.viewType, this.uri, cell.handle, URI.revive(cell.uri), cell.source.join('\n'), cell.cellKind, cell.language, cell.outputs, cell.metadata, this._proxy);
const document = this._documentsAndEditors.getDocument(URI.revive(cell.uri));
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
}
return ret;
} else {
return output as IStreamOutput | IErrorOutput;
}
});
if (document) {
extCell.attachTextDocument(document.document);
}
return {
uri: cell.uri,
handle: cell.handle,
source: cell.source,
language: cell.language,
cellKind: cell.cellKind,
outputs: outputs,
metadata: cell.metadata,
isDirty: false
};
if (!this._cellDisposableMapping.has(extCell.handle)) {
this._cellDisposableMapping.set(extCell.handle, new DisposableStore());
}
let store = this._cellDisposableMapping.get(extCell.handle)!;
store.add(extCell.onDidChangeOutputs((diffs) => {
this.eventuallyUpdateCellOutputs(extCell, diffs);
}));
return extCell;
});
return [diff.start, diff.deleteCount, cellDtos];
});
for (let j = splice[0]; j < splice[0] + splice[1]; j++) {
this._cellDisposableMapping.get(this.cells[j].handle)?.dispose();
this._cellDisposableMapping.delete(this.cells[j].handle);
this._proxy.$spliceNotebookCells(
this.viewType,
this.uri,
diffDtos,
Array.from(renderers)
);
}
this.cells.splice(splice[0], splice[1], ...newCells);
});
}
eventuallyUpdateCellOutputs(cell: ExtHostCell, diffs: ISplice<vscode.CellOutput>[]) {
@@ -283,7 +271,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
let transformedOutputs = outputs.map(output => {
if (output.outputKind === CellOutputKind.Rich) {
const ret = this.transformMimeTypes(cell, output);
const ret = this.transformMimeTypes(output);
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
@@ -300,35 +288,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
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 {
transformMimeTypes(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.
@@ -341,7 +301,7 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
let handlers = this.renderingHandler.findBestMatchedRenderer(mimeType);
if (handlers.length) {
let renderedOutput = handlers[0].render(this, cell, output, mimeType);
let renderedOutput = handlers[0].render(this, output, mimeType);
orderMimeTypes.push({
mimeType: mimeType,
@@ -395,14 +355,84 @@ export class ExtHostNotebookDocument extends Disposable implements vscode.Notebo
detachCellTextDocument(textDocument: vscode.TextDocument) {
let cell = this.cells.find(cell => cell.uri.toString() === textDocument.uri.toString());
if (cell) {
cell.detachTextDocument(textDocument);
cell.detachTextDocument();
}
}
}
export class NotebookEditorCellEdit {
private _finalized: boolean = false;
private readonly _documentVersionId: number;
private _collectedEdits: ICellEditOperation[] = [];
private _renderers = new Set<number>();
constructor(
readonly editor: ExtHostNotebookEditor
) {
this._documentVersionId = editor.document.versionId;
}
finalize(): INotebookEditData {
this._finalized = true;
return {
documentVersionId: this._documentVersionId,
edits: this._collectedEdits,
renderers: Array.from(this._renderers)
};
}
private _throwIfFinalized() {
if (this._finalized) {
throw new Error('Edit is only valid while callback runs');
}
}
insert(index: number, content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): void {
this._throwIfFinalized();
let cell = {
source: [content],
language,
cellKind: type,
outputs: (outputs as any[]), // TODO@rebornix
metadata
};
const transformedOutputs = outputs.map(output => {
if (output.outputKind === CellOutputKind.Rich) {
const ret = this.editor.document.transformMimeTypes(output);
if (ret.orderedMimeTypes[ret.pickedMimeTypeIndex].isResolved) {
this._renderers.add(ret.orderedMimeTypes[ret.pickedMimeTypeIndex].rendererId!);
}
return ret;
} else {
return output as IStreamOutput | IErrorOutput;
}
});
cell.outputs = transformedOutputs;
this._collectedEdits.push({
editType: CellEditType.Insert,
index,
cells: [cell]
});
}
delete(index: number): void {
this._throwIfFinalized();
this._collectedEdits.push({
editType: CellEditType.Delete,
index,
count: 1
});
}
}
export class ExtHostNotebookEditor extends Disposable implements vscode.NotebookEditor {
private _viewColumn: vscode.ViewColumn | undefined;
private static _cellhandlePool: number = 0;
onDidReceiveMessage: vscode.Event<any> = this._onDidReceiveMessage.event;
constructor(
@@ -438,11 +468,52 @@ export class ExtHostNotebookEditor extends Disposable implements vscode.Notebook
}));
}
createCell(content: string, language: string, type: CellKind, outputs: vscode.CellOutput[], metadata: vscode.NotebookCellMetadata | undefined): vscode.NotebookCell {
const handle = ExtHostNotebookEditor._cellhandlePool++;
const uri = CellUri.generate(this.document.uri, handle);
const cell = new ExtHostCell(this.viewType, this.uri, handle, uri, content, type, language, outputs, metadata, this._proxy);
return cell;
edit(callback: (editBuilder: NotebookEditorCellEdit) => void): Thenable<boolean> {
const edit = new NotebookEditorCellEdit(this);
callback(edit);
return this._applyEdit(edit);
}
private _applyEdit(editBuilder: NotebookEditorCellEdit): Promise<boolean> {
const editData = editBuilder.finalize();
// return when there is nothing to do
if (editData.edits.length === 0) {
return Promise.resolve(true);
}
let compressedEdits: ICellEditOperation[] = [];
let compressedEditsIndex = -1;
for (let i = 0; i < editData.edits.length; i++) {
if (compressedEditsIndex < 0) {
compressedEdits.push(editData.edits[i]);
compressedEditsIndex++;
continue;
}
let prevIndex = compressedEditsIndex;
let prev = compressedEdits[prevIndex];
if (prev.editType === CellEditType.Insert && editData.edits[i].editType === CellEditType.Insert) {
if (prev.index === editData.edits[i].index) {
prev.cells.push(...(editData.edits[i] as ICellInsertEdit).cells);
continue;
}
}
if (prev.editType === CellEditType.Delete && editData.edits[i].editType === CellEditType.Delete) {
if (prev.index === editData.edits[i].index) {
prev.count += (editData.edits[i] as ICellDeleteEdit).count;
continue;
}
}
compressedEdits.push(editData.edits[i]);
compressedEditsIndex++;
}
return this._proxy.$tryApplyEdits(this.viewType, this.uri, editData.documentVersionId, compressedEdits, editData.renderers);
}
get viewColumn(): vscode.ViewColumn | undefined {
@@ -480,8 +551,8 @@ export class ExtHostNotebookOutputRenderer {
return false;
}
render(document: ExtHostNotebookDocument, cell: ExtHostCell, output: vscode.CellOutput, mimeType: string): string {
let html = this.renderer.render(document, cell, output, mimeType);
render(document: ExtHostNotebookDocument, output: vscode.CellOutput, mimeType: string): string {
let html = this.renderer.render(document, output, mimeType);
return html;
}
@@ -584,7 +655,7 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
if (provider) {
if (!this._documents.has(URI.revive(uri).toString())) {
let document = new ExtHostNotebookDocument(this._proxy, viewType, URI.revive(uri), this);
let document = new ExtHostNotebookDocument(this._proxy, this._documentsAndEditors, viewType, URI.revive(uri), this);
await this._proxy.$createNotebookDocument(
document.handle,
viewType,
@@ -632,55 +703,6 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
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?.editor.createCell('', language, type, [], { editable: true, runnable: true }) 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,
metadata: rawCell.metadata,
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());
@@ -732,4 +754,13 @@ export class ExtHostNotebookController implements ExtHostNotebookShape, ExtHostN
editor.onDidReceiveMessage.fire(message);
}
}
$acceptModelChanged(uriComponents: UriComponents, event: NotebookCellsChangedEvent): void {
let editor = this._editors.get(URI.revive(uriComponents).toString());
if (editor) {
editor.editor.document.accpetModelChanged(event);
}
}
}

View File

@@ -14,7 +14,9 @@ import { timeout } from 'vs/base/common/async';
import { IExtHostRpcService } from 'vs/workbench/api/common/extHostRpcService';
import { TerminalDataBufferer } from 'vs/workbench/contrib/terminal/common/terminalDataBuffering';
import { IDisposable, DisposableStore } from 'vs/base/common/lifecycle';
import { Disposable as VSCodeDisposable } from './extHostTypes';
import { Disposable as VSCodeDisposable, EnvironmentVariableMutatorType } from './extHostTypes';
import { IExtensionDescription } from 'vs/platform/extensions/common/extensions';
import { ISerializableEnvironmentVariableCollection } from 'vs/workbench/contrib/terminal/common/environmentVariable';
export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
@@ -35,7 +37,8 @@ export interface IExtHostTerminalService extends ExtHostTerminalServiceShape {
attachPtyToTerminal(id: number, pty: vscode.Pseudoterminal): void;
getDefaultShell(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string;
getDefaultShellArgs(useAutomationShell: boolean, configProvider: ExtHostConfigProvider): string[] | string;
registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable
registerLinkHandler(handler: vscode.TerminalLinkHandler): vscode.Disposable;
getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
}
export const IExtHostTerminalService = createDecorator<IExtHostTerminalService>('IExtHostTerminalService');
@@ -333,6 +336,8 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
public abstract $getAvailableShells(): Promise<IShellDefinitionDto[]>;
public abstract $getDefaultShellAndArgs(useAutomationShell: boolean): Promise<IShellAndArgsDto>;
public abstract $acceptWorkspacePermissionsChanged(isAllowed: boolean): void;
public abstract getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection;
public abstract $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void;
public createExtensionTerminal(options: vscode.ExtensionTerminalOptions): vscode.Terminal {
const terminal = new ExtHostTerminal(this._proxy, options, options.name);
@@ -637,6 +642,67 @@ export abstract class BaseExtHostTerminalService implements IExtHostTerminalServ
}
}
export class EnvironmentVariableCollection implements vscode.EnvironmentVariableCollection {
readonly map: Map<string, vscode.EnvironmentVariableMutator> = new Map();
protected readonly _onDidChangeCollection: Emitter<void> = new Emitter<void>();
get onDidChangeCollection(): Event<void> { return this._onDidChangeCollection && this._onDidChangeCollection.event; }
constructor(
readonly persistent: boolean,
serialized?: ISerializableEnvironmentVariableCollection
) {
this.map = new Map(serialized);
}
get size(): number {
return this.map.size;
}
replace(variable: string, value: string): void {
this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Replace });
}
append(variable: string, value: string): void {
this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Append });
}
prepend(variable: string, value: string): void {
this._setIfDiffers(variable, { value, type: EnvironmentVariableMutatorType.Prepend });
}
private _setIfDiffers(variable: string, mutator: vscode.EnvironmentVariableMutator): void {
const current = this.map.get(variable);
if (!current || current.value !== mutator.value || current.type !== mutator.type) {
this.map.set(variable, mutator);
this._onDidChangeCollection.fire();
}
}
get(variable: string): vscode.EnvironmentVariableMutator | undefined {
return this.map.get(variable);
}
forEach(callback: (variable: string, mutator: vscode.EnvironmentVariableMutator, collection: vscode.EnvironmentVariableCollection) => any, thisArg?: any): void {
this.map.forEach((value, key) => callback(key, value, this));
}
delete(variable: string): void {
this.map.delete(variable);
this._onDidChangeCollection.fire();
}
clear(): void {
this.map.clear();
this._onDidChangeCollection.fire();
}
dispose(): void {
this.map.clear();
this._onDidChangeCollection.fire();
}
}
export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
public createTerminal(name?: string, shellPath?: string, shellArgs?: string[] | string): vscode.Terminal {
throw new Error('Not implemented');
@@ -669,4 +735,13 @@ export class WorkerExtHostTerminalService extends BaseExtHostTerminalService {
public $acceptWorkspacePermissionsChanged(isAllowed: boolean): void {
// No-op for web worker ext host as workspace permissions aren't used
}
public getEnvironmentVariableCollection(extension: IExtensionDescription, persistent?: boolean): vscode.EnvironmentVariableCollection {
// This is not implemented so worker ext host extensions cannot influence terminal envs
throw new Error('Not implemented');
}
public $initEnvironmentVariableCollections(collections: [string, ISerializableEnvironmentVariableCollection][]): void {
// No-op for web worker ext host as collections aren't used
}
}

View File

@@ -17,6 +17,7 @@ import { RemoteAuthorityResolverErrorCode } from 'vs/platform/remote/common/remo
import type * as vscode from 'vscode';
import { Cache } from './cache';
import { assertIsDefined } from 'vs/base/common/types';
import { Schemas } from 'vs/base/common/network';
function es5ClassCompat(target: Function): any {
///@ts-ignore
@@ -483,6 +484,12 @@ export enum EndOfLine {
CRLF = 2
}
export enum EnvironmentVariableMutatorType {
Replace = 1,
Append = 2,
Prepend = 3
}
@es5ClassCompat
export class TextEdit {
@@ -2591,22 +2598,22 @@ interface EditState {
export class CustomDocument<EditType = unknown> implements vscode.CustomDocument<EditType> {
readonly #edits = new Cache<EditType>('edits');
#editState: EditState;
readonly #viewType: string;
readonly #uri: vscode.Uri;
#editState: EditState = {
allEdits: [],
currentIndex: -1,
saveIndex: -1,
};
#isDisposed = false;
#version = 1;
constructor(viewType: string, uri: vscode.Uri) {
this.#viewType = viewType;
this.#uri = uri;
this.#editState = {
allEdits: [],
currentIndex: 0,
saveIndex: 0
};
}
//#region Public API
@@ -2615,15 +2622,27 @@ export class CustomDocument<EditType = unknown> implements vscode.CustomDocument
public get uri(): vscode.Uri { return this.#uri; }
public get fileName(): string { return this.uri.fsPath; }
public get isUntitled() { return this.uri.scheme === Schemas.untitled; }
#onDidDispose = new Emitter<void>();
public readonly onDidDispose = this.#onDidDispose.event;
get appliedEdits() {
public get isClosed() { return this.#isDisposed; }
public get version() { return this.#version; }
public get isDirty() {
return this.#editState.currentIndex !== this.#editState.saveIndex;
}
public get appliedEdits() {
return this.#editState.allEdits.slice(0, this.#editState.currentIndex + 1)
.map(id => this._getEdit(id));
}
get savedEdits() {
public get savedEdits() {
return this.#editState.allEdits.slice(0, this.#editState.saveIndex + 1)
.map(id => this._getEdit(id));
}
@@ -2631,11 +2650,13 @@ export class CustomDocument<EditType = unknown> implements vscode.CustomDocument
//#endregion
/** @internal */ _dispose(): void {
this.#isDisposed = true;
this.#onDidDispose.fire();
this.#onDidDispose.dispose();
}
/** @internal */ _updateEditState(state: EditState) {
++this.#version;
this.#editState = state;
}

View File

@@ -24,73 +24,91 @@ import * as extHostTypes from './extHostTypes';
type IconPath = URI | { light: URI, dark: URI };
export class ExtHostWebview implements vscode.Webview {
private _html: string = '';
private _isDisposed: boolean = false;
private _hasCalledAsWebviewUri = false;
public readonly _onMessageEmitter = new Emitter<any>();
public readonly onDidReceiveMessage: Event<any> = this._onMessageEmitter.event;
readonly #handle: extHostProtocol.WebviewPanelHandle;
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
readonly #deprecationService: IExtHostApiDeprecationService;
readonly #initData: WebviewInitData;
readonly #workspace: IExtHostWorkspace | undefined;
readonly #extension: IExtensionDescription;
#html: string = '';
#options: vscode.WebviewOptions;
#isDisposed: boolean = false;
#hasCalledAsWebviewUri = false;
constructor(
private readonly _handle: extHostProtocol.WebviewPanelHandle,
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape,
private _options: vscode.WebviewOptions,
private readonly _initData: WebviewInitData,
private readonly _workspace: IExtHostWorkspace | undefined,
private readonly _extension: IExtensionDescription,
private readonly _deprecationService: IExtHostApiDeprecationService,
) { }
handle: extHostProtocol.WebviewPanelHandle,
proxy: extHostProtocol.MainThreadWebviewsShape,
options: vscode.WebviewOptions,
initData: WebviewInitData,
workspace: IExtHostWorkspace | undefined,
extension: IExtensionDescription,
deprecationService: IExtHostApiDeprecationService,
) {
this.#handle = handle;
this.#proxy = proxy;
this.#options = options;
this.#initData = initData;
this.#workspace = workspace;
this.#extension = extension;
this.#deprecationService = deprecationService;
}
/* internal */ readonly _onMessageEmitter = new Emitter<any>();
public readonly onDidReceiveMessage: Event<any> = this._onMessageEmitter.event;
public dispose() {
this._onMessageEmitter.dispose();
}
public asWebviewUri(resource: vscode.Uri): vscode.Uri {
this._hasCalledAsWebviewUri = true;
return asWebviewUri(this._initData, this._handle, resource);
this.#hasCalledAsWebviewUri = true;
return asWebviewUri(this.#initData, this.#handle, resource);
}
public get cspSource(): string {
return this._initData.webviewCspSource
.replace('{{uuid}}', this._handle);
return this.#initData.webviewCspSource
.replace('{{uuid}}', this.#handle);
}
public get html(): string {
this.assertNotDisposed();
return this._html;
return this.#html;
}
public set html(value: string) {
this.assertNotDisposed();
if (this._html !== value) {
this._html = value;
if (!this._hasCalledAsWebviewUri && /(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) {
this._hasCalledAsWebviewUri = true;
this._deprecationService.report('Webview vscode-resource: uris', this._extension,
if (this.#html !== value) {
this.#html = value;
if (!this.#hasCalledAsWebviewUri && /(["'])vscode-resource:([^\s'"]+?)(["'])/i.test(value)) {
this.#hasCalledAsWebviewUri = true;
this.#deprecationService.report('Webview vscode-resource: uris', this.#extension,
`Please migrate to use the 'webview.asWebviewUri' api instead: https://aka.ms/vscode-webview-use-aswebviewuri`);
}
this._proxy.$setHtml(this._handle, value);
this.#proxy.$setHtml(this.#handle, value);
}
}
public get options(): vscode.WebviewOptions {
this.assertNotDisposed();
return this._options;
return this.#options;
}
public set options(newOptions: vscode.WebviewOptions) {
this.assertNotDisposed();
this._proxy.$setOptions(this._handle, convertWebviewOptions(this._extension, this._workspace, newOptions));
this._options = newOptions;
this.#proxy.$setOptions(this.#handle, convertWebviewOptions(this.#extension, this.#workspace, newOptions));
this.#options = newOptions;
}
public postMessage(message: any): Promise<boolean> {
this.assertNotDisposed();
return this._proxy.$postMessage(this._handle, message);
return this.#proxy.$postMessage(this.#handle, message);
}
private assertNotDisposed() {
if (this._isDisposed) {
if (this.#isDisposed) {
throw new Error('Webview is disposed');
}
}
@@ -98,19 +116,18 @@ export class ExtHostWebview implements vscode.Webview {
export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPanel {
private readonly _handle: extHostProtocol.WebviewPanelHandle;
private readonly _proxy: extHostProtocol.MainThreadWebviewsShape;
private readonly _viewType: string;
private _title: string;
private _iconPath?: IconPath;
readonly #handle: extHostProtocol.WebviewPanelHandle;
readonly #proxy: extHostProtocol.MainThreadWebviewsShape;
readonly #viewType: string;
readonly #options: vscode.WebviewPanelOptions;
readonly #webview: ExtHostWebview;
readonly #options: vscode.WebviewPanelOptions;
#title: string;
#iconPath?: IconPath;
#viewColumn: vscode.ViewColumn | undefined = undefined;
#visible: boolean = true;
#active: boolean = true;
#isDisposed: boolean = false;
readonly #onDidDispose = this._register(new Emitter<void>());
@@ -129,12 +146,12 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
webview: ExtHostWebview
) {
super();
this._handle = handle;
this._proxy = proxy;
this._viewType = viewType;
this.#handle = handle;
this.#proxy = proxy;
this.#viewType = viewType;
this.#options = editorOptions;
this.#viewColumn = viewColumn;
this._title = title;
this.#title = title;
this.#webview = webview;
}
@@ -145,7 +162,7 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
this.#isDisposed = true;
this.#onDidDispose.fire();
this._proxy.$disposeWebview(this._handle);
this.#proxy.$disposeWebview(this.#handle);
this.#webview.dispose();
super.dispose();
@@ -158,33 +175,33 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
get viewType(): string {
this.assertNotDisposed();
return this._viewType;
return this.#viewType;
}
get title(): string {
this.assertNotDisposed();
return this._title;
return this.#title;
}
set title(value: string) {
this.assertNotDisposed();
if (this._title !== value) {
this._title = value;
this._proxy.$setTitle(this._handle, value);
if (this.#title !== value) {
this.#title = value;
this.#proxy.$setTitle(this.#handle, value);
}
}
get iconPath(): IconPath | undefined {
this.assertNotDisposed();
return this._iconPath;
return this.#iconPath;
}
set iconPath(value: IconPath | undefined) {
this.assertNotDisposed();
if (this._iconPath !== value) {
this._iconPath = value;
if (this.#iconPath !== value) {
this.#iconPath = value;
this._proxy.$setIconPath(this._handle, URI.isUri(value) ? { light: value, dark: value } : value);
this.#proxy.$setIconPath(this.#handle, URI.isUri(value) ? { light: value, dark: value } : value);
}
}
@@ -227,12 +244,12 @@ export class ExtHostWebviewEditor extends Disposable implements vscode.WebviewPa
public postMessage(message: any): Promise<boolean> {
this.assertNotDisposed();
return this._proxy.$postMessage(this._handle, message);
return this.#proxy.$postMessage(this.#handle, message);
}
public reveal(viewColumn?: vscode.ViewColumn, preserveFocus?: boolean): void {
this.assertNotDisposed();
this._proxy.$reveal(this._handle, {
this.#proxy.$reveal(this.#handle, {
viewColumn: viewColumn ? typeConverters.ViewColumn.from(viewColumn) : undefined,
preserveFocus: !!preserveFocus
});

View File

@@ -38,6 +38,7 @@ namespace schema {
case 'debug/toolbar': return MenuId.DebugToolBar;
case 'debug/toolBar': return MenuId.DebugToolBar;
case 'menuBar/file': return MenuId.MenubarFileMenu;
case 'menuBar/webNavigation': return MenuId.MenubarWebNavigationMenu;
case 'scm/title': return MenuId.SCMTitle;
case 'scm/sourceControl': return MenuId.SCMSourceControl;
case 'scm/resourceState/context': return MenuId.SCMResourceContext;
@@ -70,6 +71,7 @@ namespace schema {
switch (menuId) {
case MenuId.StatusBarWindowIndicatorMenu:
case MenuId.MenubarFileMenu:
case MenuId.MenubarWebNavigationMenu:
return true;
}
return false;