mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-01-18 01:25:37 -05:00
Add notebook extension support for .NET Interactive. (#18334)
* Also updated kernel dropdown to only include SQL aliased kernels when using SQL notebook provider.
This commit is contained in:
@@ -102,8 +102,12 @@ export class MainThreadNotebook extends Disposable implements MainThreadNotebook
|
||||
}
|
||||
}
|
||||
|
||||
public $updateProviderDescriptionLanguages(providerId: string, languages: string[]): void {
|
||||
notebookRegistry.updateProviderDescriptionLanguages(providerId, languages);
|
||||
public $updateProviderKernels(providerId: string, languages: azdata.nb.IStandardKernel[]): void {
|
||||
notebookRegistry.updateProviderKernels(providerId, languages);
|
||||
}
|
||||
|
||||
public $updateKernelLanguages(providerId: string, kernelName: string, languages: string[]): void {
|
||||
notebookRegistry.updateKernelLanguages(providerId, kernelName, languages);
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -27,8 +27,6 @@ import { localize } from 'vs/nls';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { ITextFileService } from 'vs/workbench/services/textfile/common/textfiles';
|
||||
import { NotebookEditor } from 'sql/workbench/contrib/notebook/browser/notebookEditor';
|
||||
import { ICommandService } from 'vs/platform/commands/common/commands';
|
||||
import { NewNotebookAction } from 'sql/workbench/contrib/notebook/browser/notebookActions';
|
||||
|
||||
class MainThreadNotebookEditor extends Disposable {
|
||||
private _contentChangedEmitter = new Emitter<NotebookContentChange>();
|
||||
@@ -322,8 +320,7 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
@IInstantiationService private _instantiationService: IInstantiationService,
|
||||
@INotebookService private readonly _notebookService: INotebookService,
|
||||
@IFileService private readonly _fileService: IFileService,
|
||||
@ITextFileService private readonly _textFileService: ITextFileService,
|
||||
@ICommandService private readonly _commandService: ICommandService
|
||||
@ITextFileService private readonly _textFileService: ITextFileService
|
||||
) {
|
||||
super();
|
||||
if (extHostContext) {
|
||||
@@ -345,6 +342,11 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
}
|
||||
}
|
||||
|
||||
async $tryCreateNotebookDocument(options: INotebookShowOptions): Promise<UriComponents> {
|
||||
let input = await this._notebookService.createNotebookInput(options);
|
||||
return input.resource;
|
||||
}
|
||||
|
||||
$tryShowNotebookDocument(resource: UriComponents, options: INotebookShowOptions): Promise<string> {
|
||||
return Promise.resolve(this.doOpenEditor(resource, options));
|
||||
}
|
||||
@@ -712,12 +714,4 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$createNotebookDocument(providerId: string, contents: azdata.nb.INotebookContents): Promise<azdata.nb.NotebookDocument> {
|
||||
return this._commandService.executeCommand(NewNotebookAction.INTERNAL_NEW_NOTEBOOK_CMD_ID, {
|
||||
providerId: providerId,
|
||||
initialContent: contents,
|
||||
initialDirtyState: false
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
@@ -35,13 +35,9 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
||||
//#region APIs called by main thread
|
||||
async $getSerializationManagerDetails(providerHandle: number, notebookUri: UriComponents): Promise<ISerializationManagerDetails> {
|
||||
let uri = URI.revive(notebookUri);
|
||||
let uriString = uri.toString();
|
||||
let adapter = this.findSerializationManagerForUri(uriString);
|
||||
if (!adapter) {
|
||||
adapter = await this._withSerializationProvider(providerHandle, (provider) => {
|
||||
return this.getOrCreateSerializationManager(provider, uri);
|
||||
});
|
||||
}
|
||||
let adapter = await this._withSerializationProvider(providerHandle, (provider) => {
|
||||
return this.getOrCreateSerializationManager(provider, uri);
|
||||
});
|
||||
|
||||
return {
|
||||
handle: adapter.handle,
|
||||
@@ -50,13 +46,9 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
||||
}
|
||||
async $getExecuteManagerDetails(providerHandle: number, notebookUri: UriComponents): Promise<IExecuteManagerDetails> {
|
||||
let uri = URI.revive(notebookUri);
|
||||
let uriString = uri.toString();
|
||||
let adapter = this.findExecuteManagerForUri(uriString);
|
||||
if (!adapter) {
|
||||
adapter = await this._withExecuteProvider(providerHandle, (provider) => {
|
||||
return this.getOrCreateExecuteManager(provider, uri);
|
||||
});
|
||||
}
|
||||
let adapter = await this._withExecuteProvider(providerHandle, (provider) => {
|
||||
return this.getOrCreateExecuteManager(provider, uri);
|
||||
});
|
||||
|
||||
return {
|
||||
handle: adapter.handle,
|
||||
@@ -66,11 +58,10 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
||||
$handleNotebookClosed(notebookUri: UriComponents): void {
|
||||
let uri = URI.revive(notebookUri);
|
||||
let uriString = uri.toString();
|
||||
let manager = this.findExecuteManagerForUri(uriString);
|
||||
if (manager) {
|
||||
this.findExecuteManagersForUri(uriString).forEach(manager => {
|
||||
manager.provider.handleNotebookClosed(uri);
|
||||
this._adapters.delete(manager.handle);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
$doStartServer(managerHandle: number, kernelSpec: azdata.nb.IKernelSpec): Thenable<void> {
|
||||
@@ -264,8 +255,16 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
||||
}
|
||||
|
||||
createNotebookController(extension: IExtensionDescription, id: string, viewType: string, label: string, handler?: (cells: vscode.NotebookCell[], notebook: vscode.NotebookDocument, controller: vscode.NotebookController) => void | Thenable<void>, rendererScripts?: vscode.NotebookRendererScript[]): vscode.NotebookController {
|
||||
let addLanguagesHandler = (id, languages) => this._proxy.$updateProviderDescriptionLanguages(id, languages);
|
||||
let controller = new ADSNotebookController(extension, id, viewType, label, addLanguagesHandler, this._extHostNotebookDocumentsAndEditors, handler, extension.enableProposedApi ? rendererScripts : undefined);
|
||||
let languagesHandler = (languages: string[]) => this._proxy.$updateKernelLanguages(viewType, viewType, languages);
|
||||
let controller = new ADSNotebookController(extension, id, viewType, label, this._extHostNotebookDocumentsAndEditors, languagesHandler, handler, extension.enableProposedApi ? rendererScripts : undefined);
|
||||
let newKernel: azdata.nb.IStandardKernel = {
|
||||
name: viewType,
|
||||
displayName: controller.label,
|
||||
connectionProviderIds: [],
|
||||
supportedLanguages: [] // These will get set later from the controller
|
||||
};
|
||||
this._proxy.$updateProviderKernels(viewType, [newKernel]);
|
||||
|
||||
let executeProvider = new VSCodeExecuteProvider(controller);
|
||||
this.registerExecuteProvider(executeProvider);
|
||||
return controller;
|
||||
@@ -283,37 +282,29 @@ export class ExtHostNotebook implements ExtHostNotebookShape {
|
||||
return matchingAdapters;
|
||||
}
|
||||
|
||||
private findSerializationManagerForUri(uriString: string): SerializationManagerAdapter {
|
||||
for (let manager of this.getAdapters(SerializationManagerAdapter)) {
|
||||
if (manager.uriString === uriString) {
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
}
|
||||
|
||||
private findExecuteManagerForUri(uriString: string): ExecuteManagerAdapter {
|
||||
for (let manager of this.getAdapters(ExecuteManagerAdapter)) {
|
||||
if (manager.uriString === uriString) {
|
||||
return manager;
|
||||
}
|
||||
}
|
||||
return undefined;
|
||||
private findExecuteManagersForUri(uriString: string): ExecuteManagerAdapter[] {
|
||||
return this.getAdapters(ExecuteManagerAdapter).filter(adapter => adapter.uriString === uriString);
|
||||
}
|
||||
|
||||
private async getOrCreateSerializationManager(provider: azdata.nb.NotebookSerializationProvider, notebookUri: URI): Promise<SerializationManagerAdapter> {
|
||||
let manager = await provider.getSerializationManager(notebookUri);
|
||||
let uriString = notebookUri.toString();
|
||||
let adapter = new SerializationManagerAdapter(provider, manager, uriString);
|
||||
adapter.handle = this._addNewAdapter(adapter);
|
||||
let adapter = this.getAdapters(SerializationManagerAdapter).find(a => a.uriString === uriString && a.provider.providerId === provider.providerId);
|
||||
if (!adapter) {
|
||||
let manager = await provider.getSerializationManager(notebookUri);
|
||||
adapter = new SerializationManagerAdapter(provider, manager, uriString);
|
||||
adapter.handle = this._addNewAdapter(adapter);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
private async getOrCreateExecuteManager(provider: azdata.nb.NotebookExecuteProvider, notebookUri: URI): Promise<ExecuteManagerAdapter> {
|
||||
let manager = await provider.getExecuteManager(notebookUri);
|
||||
let uriString = notebookUri.toString();
|
||||
let adapter = new ExecuteManagerAdapter(provider, manager, uriString);
|
||||
adapter.handle = this._addNewAdapter(adapter);
|
||||
let adapter = this.getAdapters(ExecuteManagerAdapter).find(a => a.uriString === uriString && a.provider.providerId === provider.providerId);
|
||||
if (!adapter) {
|
||||
let manager = await provider.getExecuteManager(notebookUri);
|
||||
adapter = new ExecuteManagerAdapter(provider, manager, uriString);
|
||||
adapter.handle = this._addNewAdapter(adapter);
|
||||
}
|
||||
return adapter;
|
||||
}
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ import { ExtHostNotebookDocumentData } from 'sql/workbench/api/common/extHostNot
|
||||
import { ExtHostNotebookEditor } from 'sql/workbench/api/common/extHostNotebookEditor';
|
||||
import { VSCodeNotebookDocument } from 'sql/workbench/api/common/notebooks/vscodeNotebookDocument';
|
||||
import { VSCodeNotebookEditor } from 'sql/workbench/api/common/notebooks/vscodeNotebookEditor';
|
||||
import { docNotFoundForUriError } from 'sql/base/common/locConstants';
|
||||
|
||||
type Adapter = azdata.nb.NavigationProvider;
|
||||
|
||||
@@ -113,17 +114,19 @@ export class ExtHostNotebookDocumentsAndEditors implements ExtHostNotebookDocume
|
||||
if (delta.addedDocuments) {
|
||||
for (const data of delta.addedDocuments) {
|
||||
const resource = URI.revive(data.uri);
|
||||
ok(!this._documents.has(resource.toString()), `document '${resource} already exists!'`);
|
||||
|
||||
const documentData = new ExtHostNotebookDocumentData(
|
||||
this._proxy,
|
||||
resource,
|
||||
data.providerId,
|
||||
data.isDirty,
|
||||
data.cells
|
||||
);
|
||||
this._documents.set(resource.toString(), documentData);
|
||||
addedDocuments.push(documentData);
|
||||
// Can potentially have a document with this URI already if it was created
|
||||
// separately from the notebook editor.
|
||||
if (!this._documents.has(resource.toString())) {
|
||||
const documentData = new ExtHostNotebookDocumentData(
|
||||
this._proxy,
|
||||
resource,
|
||||
data.providerId,
|
||||
data.isDirty,
|
||||
data.cells
|
||||
);
|
||||
this._documents.set(resource.toString(), documentData);
|
||||
addedDocuments.push(documentData);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -220,6 +223,42 @@ export class ExtHostNotebookDocumentsAndEditors implements ExtHostNotebookDocume
|
||||
//#endregion
|
||||
|
||||
//#region Extension accessible methods
|
||||
async createNotebookDocument(providerId: string, contents?: azdata.nb.INotebookContents): Promise<URI> {
|
||||
let options: INotebookShowOptions = {};
|
||||
if (contents) {
|
||||
options.providerId = providerId;
|
||||
options.initialContent = JSON.stringify(contents);
|
||||
}
|
||||
let uriComps = await this._proxy.$tryCreateNotebookDocument(options);
|
||||
let uri = URI.revive(uriComps);
|
||||
let notebookCells = contents?.cells?.map<azdata.nb.NotebookCell>(cellContents => {
|
||||
return {
|
||||
contents: cellContents,
|
||||
uri: undefined
|
||||
};
|
||||
});
|
||||
|
||||
let documentData = new ExtHostNotebookDocumentData(
|
||||
this._proxy,
|
||||
uri,
|
||||
providerId,
|
||||
false,
|
||||
notebookCells ?? []
|
||||
);
|
||||
this._documents.set(uri.toString(), documentData);
|
||||
this._onDidOpenNotebook.fire(documentData.document);
|
||||
|
||||
return uri;
|
||||
}
|
||||
|
||||
async openNotebookDocument(uri: vscode.Uri): Promise<azdata.nb.NotebookDocument> {
|
||||
let docData = this._documents.get(uri.toString());
|
||||
if (!docData) {
|
||||
throw new Error(docNotFoundForUriError);
|
||||
}
|
||||
return docData.document;
|
||||
}
|
||||
|
||||
showNotebookDocument(uri: vscode.Uri, showOptions: azdata.nb.NotebookShowOptions): Thenable<azdata.nb.NotebookEditor> {
|
||||
return this.doShowNotebookDocument(uri, showOptions);
|
||||
}
|
||||
@@ -289,9 +328,5 @@ export class ExtHostNotebookDocumentsAndEditors implements ExtHostNotebookDocume
|
||||
this._adapters.delete(handle);
|
||||
});
|
||||
}
|
||||
|
||||
createNotebookDocument(providerId: string, contents: azdata.nb.INotebookContents): Promise<azdata.nb.NotebookDocument> {
|
||||
return this._proxy.$createNotebookDocument(providerId, contents);
|
||||
}
|
||||
//#endregion
|
||||
}
|
||||
|
||||
@@ -19,6 +19,7 @@ import { CancellationToken } from 'vs/base/common/cancellation';
|
||||
type SelectionChangedEvent = { selected: boolean, notebook: vscode.NotebookDocument; };
|
||||
type MessageReceivedEvent = { editor: vscode.NotebookEditor, message: any; };
|
||||
type ExecutionHandler = (cells: vscode.NotebookCell[], notebook: vscode.NotebookDocument, controller: vscode.NotebookController) => void | Thenable<void>;
|
||||
type LanguagesHandler = (languages: string[]) => void;
|
||||
type InterruptHandler = (notebook: vscode.NotebookDocument) => void | Promise<void>;
|
||||
|
||||
/**
|
||||
@@ -39,8 +40,8 @@ export class ADSNotebookController implements vscode.NotebookController {
|
||||
private _id: string,
|
||||
private _viewType: string,
|
||||
private _label: string,
|
||||
private _addLanguagesHandler: (providerId, languages) => void,
|
||||
private _extHostNotebookDocumentsAndEditors: ExtHostNotebookDocumentsAndEditors,
|
||||
private _languagesHandler: LanguagesHandler,
|
||||
private _handler?: ExecutionHandler,
|
||||
preloads?: vscode.NotebookRendererScript[]
|
||||
) {
|
||||
@@ -107,7 +108,7 @@ export class ADSNotebookController implements vscode.NotebookController {
|
||||
|
||||
public set supportedLanguages(value: string[]) {
|
||||
this._kernelData.supportedLanguages = value;
|
||||
this._addLanguagesHandler(this._viewType, value);
|
||||
this._languagesHandler(value);
|
||||
this._languagesAdded.resolve();
|
||||
}
|
||||
|
||||
|
||||
@@ -8,21 +8,30 @@ import type * as azdata from 'azdata';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { asArray } from 'vs/base/common/arrays';
|
||||
import { VSBuffer } from 'vs/base/common/buffer';
|
||||
import { OutputTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { CellTypes, MimeTypes, OutputTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
|
||||
import { NotebookCellKind } from 'vs/workbench/api/common/extHostTypes';
|
||||
|
||||
export function convertToVSCodeNotebookCell(cellSource: string | string[], index: number, uri: URI, language: string): vscode.NotebookCell {
|
||||
export const DotnetInteractiveJupyterLanguagePrefix = '.net-';
|
||||
export const DotnetInteractiveLanguagePrefix = 'dotnet-interactive.';
|
||||
export const DotnetInteractiveJupyterLabelPrefix = '.NET (';
|
||||
export const DotnetInteractiveLabel = '.NET Interactive';
|
||||
|
||||
export function convertToVSCodeNotebookCell(cellKind: azdata.nb.CellType, cellIndex: number, cellUri: URI, docUri: URI, cellLanguage: string, cellSource?: string | string[]): vscode.NotebookCell {
|
||||
return <vscode.NotebookCell>{
|
||||
index: index,
|
||||
kind: cellKind === CellTypes.Code ? NotebookCellKind.Code : NotebookCellKind.Markup,
|
||||
index: cellIndex,
|
||||
document: <vscode.TextDocument>{
|
||||
uri: uri,
|
||||
languageId: language,
|
||||
getText: () => Array.isArray(cellSource) ? cellSource.join('') : cellSource,
|
||||
uri: cellUri,
|
||||
languageId: cellLanguage,
|
||||
getText: () => Array.isArray(cellSource) ? cellSource.join('') : (cellSource ?? ''),
|
||||
},
|
||||
notebook: <vscode.NotebookDocument>{
|
||||
uri: uri
|
||||
}
|
||||
uri: docUri
|
||||
},
|
||||
outputs: [],
|
||||
metadata: {},
|
||||
mime: undefined
|
||||
};
|
||||
}
|
||||
|
||||
@@ -33,7 +42,7 @@ export function convertToADSCellOutput(outputs: vscode.NotebookCellOutput | vsco
|
||||
outputData[item.mime] = VSBuffer.wrap(item.data).toString();
|
||||
}
|
||||
return {
|
||||
output_type: 'execute_result',
|
||||
output_type: OutputTypes.ExecuteResult,
|
||||
data: outputData,
|
||||
execution_count: executionOrder,
|
||||
metadata: output.metadata,
|
||||
@@ -59,7 +68,7 @@ export function convertToVSCodeCellOutput(output: azdata.nb.ICellOutput): vscode
|
||||
case OutputTypes.Stream:
|
||||
let streamOutput = output as azdata.nb.IStreamResult;
|
||||
convertedOutputItems = [{
|
||||
mime: 'text/html',
|
||||
mime: MimeTypes.HTML,
|
||||
data: VSBuffer.fromString(Array.isArray(streamOutput.text) ? streamOutput.text.join('') : streamOutput.text).buffer
|
||||
}];
|
||||
break;
|
||||
@@ -67,7 +76,7 @@ export function convertToVSCodeCellOutput(output: azdata.nb.ICellOutput): vscode
|
||||
let errorOutput = output as azdata.nb.IErrorResult;
|
||||
let errorString = errorOutput.ename + ': ' + errorOutput.evalue + (errorOutput.traceback ? '\n' + errorOutput.traceback?.join('\n') : '');
|
||||
convertedOutputItems = [{
|
||||
mime: 'text/html',
|
||||
mime: MimeTypes.HTML,
|
||||
data: VSBuffer.fromString(errorString).buffer
|
||||
}];
|
||||
break;
|
||||
@@ -79,28 +88,26 @@ export function convertToVSCodeCellOutput(output: azdata.nb.ICellOutput): vscode
|
||||
};
|
||||
}
|
||||
|
||||
export function convertToADSNotebookContents(notebookData: vscode.NotebookData): azdata.nb.INotebookContents {
|
||||
export function convertToADSNotebookContents(notebookData: vscode.NotebookData | undefined): azdata.nb.INotebookContents {
|
||||
let result = {
|
||||
cells: notebookData.cells?.map<azdata.nb.ICellContents>(cell => {
|
||||
cells: notebookData?.cells?.map<azdata.nb.ICellContents>(cell => {
|
||||
let executionOrder = cell.executionSummary?.executionOrder;
|
||||
return {
|
||||
cell_type: cell.kind === NotebookCellKind.Code ? 'code' : 'markdown',
|
||||
let convertedCell: azdata.nb.ICellContents = {
|
||||
cell_type: cell.kind === NotebookCellKind.Code ? CellTypes.Code : CellTypes.Markdown,
|
||||
source: cell.value,
|
||||
metadata: {
|
||||
language: cell.languageId
|
||||
},
|
||||
execution_count: executionOrder,
|
||||
outputs: cell.outputs ? convertToADSCellOutput(cell.outputs, executionOrder) : undefined
|
||||
};
|
||||
convertedCell.metadata = cell.metadata?.custom?.metadata ?? {};
|
||||
if (!convertedCell.metadata.language) {
|
||||
convertedCell.metadata.language = cell.languageId;
|
||||
}
|
||||
return convertedCell;
|
||||
}),
|
||||
metadata: notebookData.metadata ?? {},
|
||||
nbformat: notebookData.metadata?.custom?.nbformat ?? NBFORMAT,
|
||||
nbformat_minor: notebookData.metadata?.custom?.nbformat_minor ?? NBFORMAT_MINOR
|
||||
metadata: notebookData?.metadata?.custom?.metadata ?? {},
|
||||
nbformat: notebookData?.metadata?.custom?.nbformat ?? NBFORMAT,
|
||||
nbformat_minor: notebookData?.metadata?.custom?.nbformat_minor ?? NBFORMAT_MINOR
|
||||
};
|
||||
|
||||
// Clear out extra lingering vscode custom metadata
|
||||
delete result.metadata.custom;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -108,20 +115,27 @@ export function convertToVSCodeNotebookData(notebook: azdata.nb.INotebookContent
|
||||
let result: vscode.NotebookData = {
|
||||
cells: notebook.cells?.map<vscode.NotebookCellData>(cell => {
|
||||
return {
|
||||
kind: cell.cell_type === 'code' ? NotebookCellKind.Code : NotebookCellKind.Markup,
|
||||
value: Array.isArray(cell.source) ? cell.source.join('\n') : cell.source,
|
||||
languageId: cell.metadata?.language,
|
||||
kind: cell.cell_type === CellTypes.Code ? NotebookCellKind.Code : NotebookCellKind.Markup,
|
||||
value: Array.isArray(cell.source) ? cell.source.join('') : cell.source,
|
||||
languageId: cell.metadata?.language ?? notebook.metadata.language_info?.name,
|
||||
outputs: cell.outputs?.map<vscode.NotebookCellOutput>(output => convertToVSCodeCellOutput(output)),
|
||||
executionSummary: {
|
||||
executionOrder: cell.execution_count
|
||||
},
|
||||
metadata: {
|
||||
custom: {
|
||||
metadata: cell.metadata
|
||||
}
|
||||
}
|
||||
};
|
||||
}),
|
||||
metadata: notebook.metadata
|
||||
};
|
||||
result.metadata.custom = {
|
||||
nbformat: notebook.nbformat,
|
||||
nbformat_minor: notebook.nbformat_minor
|
||||
metadata: {
|
||||
custom: {
|
||||
metadata: notebook.metadata,
|
||||
nbformat: notebook.nbformat,
|
||||
nbformat_minor: notebook.nbformat_minor
|
||||
}
|
||||
}
|
||||
};
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -8,6 +8,7 @@ import type * as azdata from 'azdata';
|
||||
import { ADSNotebookController } from 'sql/workbench/api/common/notebooks/adsNotebookController';
|
||||
import * as nls from 'vs/nls';
|
||||
import { convertToVSCodeNotebookCell } from 'sql/workbench/api/common/notebooks/notebookUtils';
|
||||
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
|
||||
|
||||
class VSCodeFuture implements azdata.nb.IFuture {
|
||||
private _inProgress = true;
|
||||
@@ -71,16 +72,25 @@ class VSCodeKernel implements azdata.nb.IKernel {
|
||||
private readonly _info: azdata.nb.IInfoReply;
|
||||
private readonly _kernelSpec: azdata.nb.IKernelSpec;
|
||||
|
||||
constructor(private readonly _controller: ADSNotebookController, private readonly _options: azdata.nb.ISessionOptions, language: string) {
|
||||
constructor(private readonly _controller: ADSNotebookController, private readonly _options: azdata.nb.ISessionOptions) {
|
||||
this._id = this._options.kernelId ?? (VSCodeKernel.kernelId++).toString();
|
||||
this._name = this._options.kernelName ?? this._controller.notebookType;
|
||||
this._kernelSpec = this._options.kernelSpec ?? {
|
||||
name: this._controller.notebookType,
|
||||
display_name: this._controller.label,
|
||||
};
|
||||
if (!this._kernelSpec.language) {
|
||||
this._kernelSpec.language = this._controller.supportedLanguages[0];
|
||||
this._kernelSpec.supportedLanguages = this._controller.supportedLanguages;
|
||||
}
|
||||
|
||||
this._name = this._kernelSpec.name;
|
||||
this._info = {
|
||||
protocol_version: '',
|
||||
implementation: '',
|
||||
implementation_version: '',
|
||||
language_info: {
|
||||
name: language,
|
||||
version: '',
|
||||
name: this._kernelSpec.language,
|
||||
oldName: this._kernelSpec.oldLanguage
|
||||
},
|
||||
banner: '',
|
||||
help_links: [{
|
||||
@@ -88,11 +98,6 @@ class VSCodeKernel implements azdata.nb.IKernel {
|
||||
url: ''
|
||||
}]
|
||||
};
|
||||
this._kernelSpec = {
|
||||
name: this._name,
|
||||
language: language,
|
||||
display_name: this._name
|
||||
};
|
||||
}
|
||||
|
||||
public get id(): string {
|
||||
@@ -123,17 +128,20 @@ class VSCodeKernel implements azdata.nb.IKernel {
|
||||
return this._info;
|
||||
}
|
||||
|
||||
public get spec(): azdata.nb.IKernelSpec {
|
||||
return this._kernelSpec;
|
||||
}
|
||||
|
||||
getSpec(): Thenable<azdata.nb.IKernelSpec> {
|
||||
return Promise.resolve(this._kernelSpec);
|
||||
return Promise.resolve(this.spec);
|
||||
}
|
||||
|
||||
requestExecute(content: azdata.nb.IExecuteRequest, disposeOnDone?: boolean): azdata.nb.IFuture {
|
||||
let executePromise: Promise<void>;
|
||||
if (this._controller.executeHandler) {
|
||||
let cell = convertToVSCodeNotebookCell(content.code, content.cellIndex, content.notebookUri, this._kernelSpec.language);
|
||||
let cell = convertToVSCodeNotebookCell(CellTypes.Code, content.cellIndex, content.cellUri, content.notebookUri, content.language ?? this._kernelSpec.language, content.code);
|
||||
executePromise = Promise.resolve(this._controller.executeHandler([cell], cell.notebook, this._controller));
|
||||
}
|
||||
else {
|
||||
} else {
|
||||
executePromise = Promise.resolve();
|
||||
}
|
||||
|
||||
@@ -153,8 +161,8 @@ class VSCodeKernel implements azdata.nb.IKernel {
|
||||
class VSCodeSession implements azdata.nb.ISession {
|
||||
private _kernel: VSCodeKernel;
|
||||
private _defaultKernelLoaded = false;
|
||||
constructor(controller: ADSNotebookController, private readonly _options: azdata.nb.ISessionOptions, language: string) {
|
||||
this._kernel = new VSCodeKernel(controller, this._options, language);
|
||||
constructor(controller: ADSNotebookController, private readonly _options: azdata.nb.ISessionOptions) {
|
||||
this._kernel = new VSCodeKernel(controller, this._options);
|
||||
}
|
||||
|
||||
public set defaultKernelLoaded(value) {
|
||||
@@ -189,10 +197,14 @@ class VSCodeSession implements azdata.nb.ISession {
|
||||
return 'connected';
|
||||
}
|
||||
|
||||
public get kernel(): azdata.nb.IKernel {
|
||||
public get vsKernel(): VSCodeKernel {
|
||||
return this._kernel;
|
||||
}
|
||||
|
||||
public get kernel(): azdata.nb.IKernel {
|
||||
return this.vsKernel;
|
||||
}
|
||||
|
||||
changeKernel(kernelInfo: azdata.nb.IKernelSpec): Thenable<azdata.nb.IKernel> {
|
||||
return Promise.resolve(this._kernel);
|
||||
}
|
||||
@@ -207,7 +219,7 @@ class VSCodeSession implements azdata.nb.ISession {
|
||||
}
|
||||
|
||||
class VSCodeSessionManager implements azdata.nb.SessionManager {
|
||||
private _sessions: azdata.nb.ISession[] = [];
|
||||
private _sessions: VSCodeSession[] = [];
|
||||
|
||||
constructor(private readonly _controller: ADSNotebookController) {
|
||||
}
|
||||
@@ -221,16 +233,16 @@ class VSCodeSessionManager implements azdata.nb.SessionManager {
|
||||
}
|
||||
|
||||
public get specs(): azdata.nb.IAllKernels {
|
||||
let languages = this._controller.supportedLanguages?.length > 0 ? this._controller.supportedLanguages : [this._controller.label];
|
||||
// Have to return the default kernel here, since the manager specs are accessed before kernels get added
|
||||
let defaultKernel: azdata.nb.IKernelSpec = {
|
||||
name: this._controller.notebookType,
|
||||
language: this._controller.supportedLanguages[0],
|
||||
display_name: this._controller.label,
|
||||
supportedLanguages: this._controller.supportedLanguages ?? []
|
||||
};
|
||||
return {
|
||||
defaultKernel: languages[0],
|
||||
kernels: languages.map<azdata.nb.IKernelSpec>(language => {
|
||||
return {
|
||||
name: language,
|
||||
language: language,
|
||||
display_name: language
|
||||
};
|
||||
})
|
||||
defaultKernel: defaultKernel.name,
|
||||
kernels: [defaultKernel]
|
||||
};
|
||||
}
|
||||
|
||||
@@ -238,8 +250,7 @@ class VSCodeSessionManager implements azdata.nb.SessionManager {
|
||||
if (!this.isReady) {
|
||||
return Promise.reject(new Error(nls.localize('errorStartBeforeReady', "Cannot start a session, the manager is not yet initialized")));
|
||||
}
|
||||
|
||||
let session: azdata.nb.ISession = new VSCodeSession(this._controller, options, this.specs.defaultKernel);
|
||||
let session = new VSCodeSession(this._controller, options);
|
||||
let index = this._sessions.findIndex(session => session.path === options.path);
|
||||
if (index > -1) {
|
||||
this._sessions.splice(index);
|
||||
|
||||
@@ -11,7 +11,7 @@ export class VSCodeNotebookDocument implements vscode.NotebookDocument {
|
||||
private readonly _convertedCells: vscode.NotebookCell[];
|
||||
|
||||
constructor(private readonly _notebookDoc: azdata.nb.NotebookDocument) {
|
||||
this._convertedCells = this._notebookDoc.cells?.map((cell, index) => convertToVSCodeNotebookCell(cell.contents.source, index, this._notebookDoc.uri, this._notebookDoc.kernelSpec?.language));
|
||||
this._convertedCells = this._notebookDoc.cells?.map((cell, index) => convertToVSCodeNotebookCell(cell.contents.cell_type, index, cell.uri, this._notebookDoc.uri, cell.contents.metadata?.language, cell.contents.source));
|
||||
}
|
||||
|
||||
public get uri() { return this._notebookDoc.uri; }
|
||||
|
||||
@@ -956,7 +956,8 @@ export interface MainThreadNotebookShape extends IDisposable {
|
||||
$unregisterExecuteProvider(handle: number): void;
|
||||
$onFutureMessage(futureId: number, type: FutureMessageType, payload: azdata.nb.IMessage): void;
|
||||
$onFutureDone(futureId: number, done: INotebookFutureDone): void;
|
||||
$updateProviderDescriptionLanguages(providerId: string, languages: string[]): void;
|
||||
$updateProviderKernels(providerId: string, languages: azdata.nb.IStandardKernel[]): void;
|
||||
$updateKernelLanguages(providerId: string, kernelName: string, languages: string[]): void;
|
||||
}
|
||||
|
||||
export interface INotebookDocumentsAndEditorsDelta {
|
||||
@@ -1011,6 +1012,7 @@ export interface ExtHostNotebookDocumentsAndEditorsShape {
|
||||
export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable {
|
||||
$trySetTrusted(_uri: UriComponents, isTrusted: boolean): Thenable<boolean>;
|
||||
$trySaveDocument(uri: UriComponents): Thenable<boolean>;
|
||||
$tryCreateNotebookDocument(options: INotebookShowOptions): Promise<UriComponents>;
|
||||
$tryShowNotebookDocument(resource: UriComponents, options: INotebookShowOptions): Promise<string>;
|
||||
$tryApplyEdits(id: string, modelVersionId: number, edits: INotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
|
||||
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
|
||||
@@ -1019,7 +1021,6 @@ export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable
|
||||
$clearAllOutputs(id: string): Promise<boolean>;
|
||||
$changeKernel(id: string, kernel: azdata.nb.IKernelSpec): Promise<boolean>;
|
||||
$registerNavigationProvider(providerId: string, handle: number);
|
||||
$createNotebookDocument(providerId: string, contents: azdata.nb.INotebookContents): Promise<azdata.nb.NotebookDocument>;
|
||||
}
|
||||
|
||||
export interface ExtHostExtensionManagementShape {
|
||||
|
||||
@@ -552,6 +552,19 @@ export class SqlThemeIcon {
|
||||
}
|
||||
}
|
||||
|
||||
export interface ICellMetadata {
|
||||
language?: string | undefined;
|
||||
tags?: string[] | undefined;
|
||||
azdata_cell_guid?: string | undefined;
|
||||
connection_name?: string;
|
||||
/**
|
||||
* .NET Interactive metadata. This is only required for compatibility with the .NET Interactive extension.
|
||||
*/
|
||||
dotnet_interactive?: {
|
||||
language: string;
|
||||
}
|
||||
}
|
||||
|
||||
export interface ISerializationManagerDetails {
|
||||
handle: number;
|
||||
hasContentManager: boolean;
|
||||
|
||||
@@ -12,7 +12,12 @@
|
||||
<div #editor class="editor"></div>
|
||||
</div>
|
||||
</div>
|
||||
<collapse-component *ngIf="cellModel.cellType === 'code' && cellModel.source && cellModel.source.length > 1" [cellModel]="cellModel" [activeCellId]="activeCellId"></collapse-component>
|
||||
<div style="display: flex; flex-flow: row; justify-content: flex-end;">
|
||||
<collapse-component *ngIf="cellModel.cellType === 'code' && cellModel.source && cellModel.source.length > 1" [cellModel]="cellModel" [activeCellId]="activeCellId"></collapse-component>
|
||||
<div #cellLanguage class="cellLanguage" *ngIf="cellModel.cellType === 'code' && cellModel.language">
|
||||
{{cellModel.displayLanguage}}
|
||||
</div>
|
||||
</div>
|
||||
<div #parameter class="parameter" *ngIf="cellModel.cellType === 'code' && cellModel.isParameter">
|
||||
<span>{{parametersText}}</span>
|
||||
</div>
|
||||
|
||||
@@ -48,6 +48,7 @@ const DEFAULT_OR_LOCAL_CONTEXT_ID = '-1';
|
||||
export class CodeComponent extends CellView implements OnInit, OnChanges {
|
||||
@ViewChild('toolbar', { read: ElementRef }) private toolbarElement: ElementRef;
|
||||
@ViewChild('editor', { read: ElementRef }) private codeElement: ElementRef;
|
||||
@ViewChild('cellLanguage', { read: ElementRef }) private languageElement: ElementRef;
|
||||
|
||||
public get cellModel(): ICellModel {
|
||||
return this._cellModel;
|
||||
@@ -265,6 +266,12 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
|
||||
this.setFocusAndScroll();
|
||||
}
|
||||
}));
|
||||
this._register(this.cellModel.onLanguageChanged(language => {
|
||||
let nativeElement = <HTMLElement>this.languageElement.nativeElement;
|
||||
nativeElement.innerText = this.cellModel.displayLanguage;
|
||||
this.updateLanguageMode();
|
||||
this._changeRef.detectChanges();
|
||||
}));
|
||||
this._register(this.cellModel.onCollapseStateChanged(isCollapsed => {
|
||||
this.onCellCollapse(isCollapsed);
|
||||
}));
|
||||
@@ -379,8 +386,6 @@ export class CodeComponent extends CellView implements OnInit, OnChanges {
|
||||
this.cellModel.setOverrideLanguage(magic.language);
|
||||
this.updateLanguageMode();
|
||||
}
|
||||
} else {
|
||||
this.cellModel.setOverrideLanguage(undefined);
|
||||
}
|
||||
}
|
||||
} catch (err) {
|
||||
|
||||
@@ -98,6 +98,10 @@ code-component .carbon-taskbar .codicon.hideIcon.execCountHundred {
|
||||
margin-left: -6px;
|
||||
}
|
||||
|
||||
code-component collapse-component {
|
||||
flex-grow: 1;
|
||||
}
|
||||
|
||||
code-component .hide-component-button {
|
||||
height: 16px;
|
||||
width: 100%;
|
||||
@@ -106,6 +110,15 @@ code-component .hide-component-button {
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
background-color: transparent;
|
||||
margin-top: 4px;
|
||||
margin-bottom: 4px;
|
||||
}
|
||||
|
||||
code-component .cellLanguage {
|
||||
padding: 2px 15px;
|
||||
display: inline-block;
|
||||
text-align: center;
|
||||
font-size: 16px;
|
||||
}
|
||||
|
||||
code-component .parameter {
|
||||
|
||||
@@ -40,6 +40,7 @@ import { LocalContentManager } from 'sql/workbench/services/notebook/common/loca
|
||||
import { Registry } from 'vs/platform/registry/common/platform';
|
||||
import { Extensions as LanguageAssociationExtensions, ILanguageAssociationRegistry } from 'sql/workbench/services/languageAssociation/common/languageAssociation';
|
||||
import { NotebookLanguage } from 'sql/workbench/common/constants';
|
||||
import { DotnetInteractiveLabel, DotnetInteractiveJupyterLabelPrefix, DotnetInteractiveJupyterLanguagePrefix, DotnetInteractiveLanguagePrefix } from 'sql/workbench/api/common/notebooks/notebookUtils';
|
||||
|
||||
export type ModeViewSaveHandler = (handle: number) => Thenable<boolean>;
|
||||
const languageAssociationRegistry = Registry.as<ILanguageAssociationRegistry>(LanguageAssociationExtensions.LanguageAssociations);
|
||||
@@ -351,7 +352,8 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
||||
connectionProviderIds: kernel.connectionProviderIds,
|
||||
name: kernel.name,
|
||||
displayName: kernel.displayName,
|
||||
notebookProvider: kernel.notebookProvider
|
||||
notebookProvider: kernel.notebookProvider,
|
||||
supportedLanguages: kernel.supportedLanguages
|
||||
});
|
||||
});
|
||||
}
|
||||
@@ -540,6 +542,26 @@ export class NotebookEditorContentLoader implements IContentLoader {
|
||||
|
||||
async loadContent(): Promise<azdata.nb.INotebookContents> {
|
||||
let notebookEditorModel = await this.notebookInput.resolve();
|
||||
return this.contentManager.deserializeNotebook(notebookEditorModel.contentString);
|
||||
let notebookContents = await this.contentManager.deserializeNotebook(notebookEditorModel.contentString);
|
||||
|
||||
// Special case .NET Interactive kernel spec to handle inconsistencies between notebook providers and jupyter kernel specs
|
||||
if (notebookContents.metadata?.kernelspec?.display_name?.startsWith(DotnetInteractiveJupyterLabelPrefix)) {
|
||||
notebookContents.metadata.kernelspec.oldDisplayName = notebookContents.metadata.kernelspec.display_name;
|
||||
notebookContents.metadata.kernelspec.display_name = DotnetInteractiveLabel;
|
||||
|
||||
let kernelName = notebookContents.metadata.kernelspec.name;
|
||||
let baseLanguageName = kernelName.replace(DotnetInteractiveJupyterLanguagePrefix, '');
|
||||
if (baseLanguageName === 'powershell') {
|
||||
baseLanguageName = 'pwsh';
|
||||
}
|
||||
let languageName = `${DotnetInteractiveLanguagePrefix}${baseLanguageName}`;
|
||||
|
||||
notebookContents.metadata.kernelspec.oldLanguage = notebookContents.metadata.kernelspec.language;
|
||||
notebookContents.metadata.kernelspec.language = languageName;
|
||||
|
||||
notebookContents.metadata.language_info.oldName = notebookContents.metadata.language_info.name;
|
||||
notebookContents.metadata.language_info.name = languageName;
|
||||
}
|
||||
return notebookContents;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -410,7 +410,9 @@ registerComponentType({
|
||||
mimeTypes: [
|
||||
'text/plain',
|
||||
'application/vnd.jupyter.stdout',
|
||||
'application/vnd.jupyter.stderr'
|
||||
'application/vnd.jupyter.stderr',
|
||||
'application/vnd.code.notebook.stdout',
|
||||
'application/vnd.code.notebook.stderr'
|
||||
],
|
||||
rank: 120,
|
||||
safe: true,
|
||||
@@ -418,6 +420,19 @@ registerComponentType({
|
||||
selector: MimeRendererComponent.SELECTOR
|
||||
});
|
||||
|
||||
/**
|
||||
* A mime renderer component for VS Code Notebook error data.
|
||||
*/
|
||||
registerComponentType({
|
||||
mimeTypes: [
|
||||
'application/vnd.code.notebook.error'
|
||||
],
|
||||
rank: 121,
|
||||
safe: true,
|
||||
ctor: MimeRendererComponent,
|
||||
selector: MimeRendererComponent.SELECTOR
|
||||
});
|
||||
|
||||
/**
|
||||
* A placeholder component for deprecated rendered JavaScript.
|
||||
*/
|
||||
|
||||
@@ -67,7 +67,8 @@ class TestNotebookModel extends NotebookModelStub {
|
||||
name: 'StandardKernel1',
|
||||
displayName: 'StandardKernel1',
|
||||
connectionProviderIds: ['Kernel1 connection 1', 'Kernel1 connection2'],
|
||||
notebookProvider: 'kernel provider1'
|
||||
notebookProvider: 'kernel provider1',
|
||||
supportedLanguages: ['python']
|
||||
}
|
||||
],
|
||||
[
|
||||
@@ -76,7 +77,8 @@ class TestNotebookModel extends NotebookModelStub {
|
||||
name: 'StandardKernel2',
|
||||
displayName: 'StandardKernel2',
|
||||
connectionProviderIds: ['Kernel1 connection 2', 'Kernel1 connection2'],
|
||||
notebookProvider: 'kernel provider2'
|
||||
notebookProvider: 'kernel provider2',
|
||||
supportedLanguages: ['python']
|
||||
}
|
||||
]
|
||||
]
|
||||
|
||||
@@ -40,7 +40,8 @@ suite('Notebook Input', function (): void {
|
||||
name: 'TestName',
|
||||
displayName: 'TestDisplayName',
|
||||
connectionProviderIds: ['TestId'],
|
||||
notebookProvider: testProvider
|
||||
notebookProvider: testProvider,
|
||||
supportedLanguages: ['python']
|
||||
}]);
|
||||
});
|
||||
let testManager: ISerializationManager = {
|
||||
@@ -129,12 +130,14 @@ suite('Notebook Input', function (): void {
|
||||
name: 'TestName1',
|
||||
displayName: 'TestDisplayName1',
|
||||
connectionProviderIds: ['TestId1'],
|
||||
notebookProvider: 'TestProvider'
|
||||
notebookProvider: 'TestProvider',
|
||||
supportedLanguages: ['python']
|
||||
}, {
|
||||
name: 'TestName2',
|
||||
displayName: 'TestDisplayName2',
|
||||
connectionProviderIds: ['TestId2'],
|
||||
notebookProvider: 'TestProvider'
|
||||
notebookProvider: 'TestProvider',
|
||||
supportedLanguages: ['python']
|
||||
}];
|
||||
untitledNotebookInput.standardKernels = testKernels;
|
||||
assert.deepStrictEqual(untitledNotebookInput.standardKernels, testKernels);
|
||||
|
||||
@@ -236,7 +236,8 @@ suite.skip('NotebookService:', function (): void {
|
||||
standardKernels: [{
|
||||
name: 'kernel1',
|
||||
connectionProviderIds: [],
|
||||
displayName: 'Kernel 1'
|
||||
displayName: 'Kernel 1',
|
||||
supportedLanguages: ['python']
|
||||
}],
|
||||
provider: 'otherProvider'
|
||||
};
|
||||
|
||||
@@ -21,12 +21,14 @@ suite('notebookUtils', function (): void {
|
||||
const testKernel: nb.IStandardKernel = {
|
||||
name: 'testName',
|
||||
displayName: 'testDisplayName',
|
||||
connectionProviderIds: ['testId1', 'testId2']
|
||||
connectionProviderIds: ['testId1', 'testId2'],
|
||||
supportedLanguages: ['python']
|
||||
};
|
||||
const sqlStandardKernel: nb.IStandardKernel = {
|
||||
name: notebookConstants.SQL,
|
||||
displayName: notebookConstants.SQL,
|
||||
connectionProviderIds: [notebookConstants.SQL_CONNECTION_PROVIDER]
|
||||
connectionProviderIds: [notebookConstants.SQL_CONNECTION_PROVIDER],
|
||||
supportedLanguages: ['sql']
|
||||
};
|
||||
|
||||
function setupMockNotebookService() {
|
||||
@@ -108,7 +110,8 @@ suite('notebookUtils', function (): void {
|
||||
name: 'testName',
|
||||
displayName: 'testDisplayName',
|
||||
connectionProviderIds: ['testId1', 'testId2'],
|
||||
notebookProvider: 'testProvider'
|
||||
notebookProvider: 'testProvider',
|
||||
supportedLanguages: ['python']
|
||||
}]);
|
||||
});
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ import { ConnectionProfile } from 'sql/platform/connection/common/connectionProf
|
||||
import { URI, UriComponents } from 'vs/base/common/uri';
|
||||
import { QueryTextEditor } from 'sql/workbench/browser/modelComponents/queryTextEditor';
|
||||
import { IContextViewProvider, IDelegate } from 'vs/base/browser/ui/contextview/contextview';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
import { INotebookView, INotebookViewCell, INotebookViewMetadata, INotebookViews } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViews';
|
||||
@@ -235,6 +235,9 @@ export class ServerManagerStub implements nb.ServerManager {
|
||||
}
|
||||
|
||||
export class NotebookServiceStub implements INotebookService {
|
||||
createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
_serviceBrand: undefined;
|
||||
get onNotebookEditorAdd(): vsEvent.Event<INotebookEditor> {
|
||||
throw new Error('Method not implemented.');
|
||||
|
||||
@@ -33,6 +33,8 @@ import { IInsightOptions } from 'sql/workbench/common/editor/query/chartState';
|
||||
import { IPosition } from 'vs/editor/common/core/position';
|
||||
import { CellOutputEdit, CellOutputDataEdit } from 'sql/workbench/services/notebook/browser/models/cellEdit';
|
||||
import { ILogService } from 'vs/platform/log/common/log';
|
||||
import { IModeService } from 'vs/editor/common/services/modeService';
|
||||
import { ICellMetadata } from 'sql/workbench/api/common/sqlExtHostTypes';
|
||||
|
||||
let modelId = 0;
|
||||
const ads_execute_command = 'ads_execute_command';
|
||||
@@ -70,8 +72,9 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
private _onCellLoaded = new Emitter<string>();
|
||||
private _loaded: boolean;
|
||||
private _stdInVisible: boolean;
|
||||
private _metadata: nb.ICellMetadata;
|
||||
private _metadata: ICellMetadata;
|
||||
private _isCollapsed: boolean;
|
||||
private _onLanguageChanged = new Emitter<string>();
|
||||
private _onCollapseStateChanged = new Emitter<boolean>();
|
||||
private _modelContentChangedEvent: IModelContentChangedEvent;
|
||||
private _isCommandExecutionSettingEnabled: boolean = false;
|
||||
@@ -95,7 +98,8 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
@optional(INotebookService) private _notebookService?: INotebookService,
|
||||
@optional(ICommandService) private _commandService?: ICommandService,
|
||||
@optional(IConfigurationService) private _configurationService?: IConfigurationService,
|
||||
@optional(ILogService) private _logService?: ILogService
|
||||
@optional(ILogService) private _logService?: ILogService,
|
||||
@optional(IModeService) private _modeService?: IModeService
|
||||
) {
|
||||
super();
|
||||
this.id = `${modelId++}`;
|
||||
@@ -124,6 +128,10 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
return other !== undefined && other.id === this.id;
|
||||
}
|
||||
|
||||
public get onLanguageChanged(): Event<string> {
|
||||
return this._onLanguageChanged.event;
|
||||
}
|
||||
|
||||
public get onCollapseStateChanged(): Event<boolean> {
|
||||
return this._onCollapseStateChanged.event;
|
||||
}
|
||||
@@ -385,6 +393,19 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
return this._options.notebook.language;
|
||||
}
|
||||
|
||||
public get displayLanguage(): string {
|
||||
let result: string;
|
||||
if (this._cellType === CellTypes.Markdown) {
|
||||
result = 'Markdown';
|
||||
} else if (this._modeService) {
|
||||
let language = this._modeService.getLanguageName(this.language);
|
||||
result = language ?? this.language;
|
||||
} else {
|
||||
result = this.language;
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
public get savedConnectionName(): string | undefined {
|
||||
return this._savedConnectionName;
|
||||
}
|
||||
@@ -394,7 +415,10 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
}
|
||||
|
||||
public setOverrideLanguage(newLanguage: string) {
|
||||
this._language = newLanguage;
|
||||
if (newLanguage !== this._language) {
|
||||
this._language = newLanguage;
|
||||
this._onLanguageChanged.fire(newLanguage);
|
||||
}
|
||||
}
|
||||
|
||||
public get onExecutionStateChange(): Event<CellExecutionState> {
|
||||
@@ -616,7 +640,9 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
code: content,
|
||||
cellIndex: this.notebookModel.findCellIndex(this),
|
||||
stop_on_error: true,
|
||||
notebookUri: this.notebookModel.notebookUri
|
||||
notebookUri: this.notebookModel.notebookUri,
|
||||
cellUri: this.cellUri,
|
||||
language: this.language
|
||||
}, false);
|
||||
this.setFuture(future as FutureInternal);
|
||||
this.fireExecutionStateChanged();
|
||||
@@ -728,7 +754,7 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
this._future = future;
|
||||
future.setReplyHandler({ handle: (msg) => this.handleReply(msg) });
|
||||
future.setIOPubHandler({ handle: (msg) => this.handleIOPub(msg) });
|
||||
future.setStdInHandler({ handle: (msg) => this.handleSdtIn(msg) });
|
||||
future.setStdInHandler({ handle: (msg) => this.handleStdIn(msg) });
|
||||
}
|
||||
/**
|
||||
* Clear outputs can be done as part of the "Clear Outputs" action on a cell or as part of running a cell
|
||||
@@ -933,7 +959,7 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
* components. If one is registered the cell will call and wait on it, if not
|
||||
* it will immediately return to unblock error handling
|
||||
*/
|
||||
private handleSdtIn(msg: nb.IStdinMessage): void | Thenable<void> {
|
||||
private handleStdIn(msg: nb.IStdinMessage): void | Thenable<void> {
|
||||
let handler = async () => {
|
||||
if (!this._stdInHandler) {
|
||||
// No-op
|
||||
@@ -995,7 +1021,7 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
}
|
||||
this._attachments = cell.attachments;
|
||||
this._cellGuid = cell.metadata && cell.metadata.azdata_cell_guid ? cell.metadata.azdata_cell_guid : generateUuid();
|
||||
this.setLanguageFromContents(cell);
|
||||
this.setLanguageFromContents(cell.cell_type, cell.metadata);
|
||||
this._savedConnectionName = this._metadata.connection_name;
|
||||
if (cell.outputs) {
|
||||
for (let output of cell.outputs) {
|
||||
@@ -1051,13 +1077,16 @@ export class CellModel extends Disposable implements ICellModel {
|
||||
this.fireOutputsChanged(false);
|
||||
}
|
||||
|
||||
private setLanguageFromContents(cell: nb.ICellContents): void {
|
||||
if (cell.cell_type === CellTypes.Markdown) {
|
||||
private setLanguageFromContents(cellType: string, metadata: ICellMetadata): void {
|
||||
if (cellType === CellTypes.Markdown) {
|
||||
this._language = 'markdown';
|
||||
} else if (cell.metadata && cell.metadata.language) {
|
||||
this._language = cell.metadata.language;
|
||||
} else if (metadata?.language) {
|
||||
this._language = metadata.language;
|
||||
} else if (metadata?.dotnet_interactive?.language) {
|
||||
this._language = `dotnet-interactive.${metadata.dotnet_interactive.language}`;
|
||||
} else {
|
||||
this._language = this._options?.notebook?.language;
|
||||
}
|
||||
// else skip, we set default language anyhow
|
||||
}
|
||||
|
||||
private addOutput(output: nb.ICellOutput) {
|
||||
|
||||
@@ -99,25 +99,25 @@ export class ClientSession implements IClientSession {
|
||||
await this._executeManager.sessionManager.ready;
|
||||
}
|
||||
if (this._defaultKernel) {
|
||||
await this.startSessionInstance(this._defaultKernel.name);
|
||||
await this.startSessionInstance(this._defaultKernel);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private async startSessionInstance(kernelName: string): Promise<void> {
|
||||
private async startSessionInstance(kernelSpec: nb.IKernelSpec): Promise<void> {
|
||||
let session: nb.ISession;
|
||||
try {
|
||||
// TODO #3164 should use URI instead of path for startNew
|
||||
session = await this._executeManager.sessionManager.startNew({
|
||||
path: this.notebookUri.fsPath,
|
||||
kernelName: kernelName
|
||||
// TODO add kernel name if saved in the document
|
||||
kernelName: kernelSpec.name,
|
||||
kernelSpec: kernelSpec
|
||||
});
|
||||
session.defaultKernelLoaded = true;
|
||||
} catch (err) {
|
||||
// TODO move registration
|
||||
if (err && err.response && err.response.status === 501) {
|
||||
this.options.notificationService.warn(localize('kernelRequiresConnection', "Kernel {0} was not found. The default kernel will be used instead.", kernelName));
|
||||
this.options.notificationService.warn(localize('kernelRequiresConnection', "Kernel {0} was not found. The default kernel will be used instead.", kernelSpec.name));
|
||||
session = await this._executeManager.sessionManager.startNew({
|
||||
path: this.notebookUri.fsPath,
|
||||
kernelName: undefined
|
||||
@@ -128,7 +128,7 @@ export class ClientSession implements IClientSession {
|
||||
}
|
||||
}
|
||||
this._session = session;
|
||||
await this.runKernelConfigActions(kernelName);
|
||||
await this.runKernelConfigActions(kernelSpec.name);
|
||||
this._statusChangedEmitter.fire(session);
|
||||
}
|
||||
|
||||
@@ -278,7 +278,7 @@ export class ClientSession implements IClientSession {
|
||||
kernel = await this._session.changeKernel(options);
|
||||
await this.runKernelConfigActions(kernel.name);
|
||||
} else {
|
||||
kernel = await this.startSessionInstance(options.name).then(() => this.kernel);
|
||||
kernel = await this.startSessionInstance(options).then(() => this.kernel);
|
||||
}
|
||||
return kernel;
|
||||
}
|
||||
|
||||
@@ -501,6 +501,7 @@ export interface ICellModel {
|
||||
cellUri: URI;
|
||||
id: string;
|
||||
readonly language: string;
|
||||
readonly displayLanguage: string;
|
||||
readonly cellGuid: string;
|
||||
source: string | string[];
|
||||
cellType: CellType;
|
||||
@@ -530,6 +531,7 @@ export interface ICellModel {
|
||||
isCollapsed: boolean;
|
||||
isParameter: boolean;
|
||||
isInjectedParameter: boolean;
|
||||
readonly onLanguageChanged: Event<string>;
|
||||
readonly onCollapseStateChanged: Event<boolean>;
|
||||
readonly onParameterStateChanged: Event<boolean>;
|
||||
readonly onCellModeChanged: Event<boolean>;
|
||||
|
||||
@@ -38,6 +38,7 @@ import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
|
||||
import { AddCellEdit, CellOutputEdit, ConvertCellTypeEdit, DeleteCellEdit, MoveCellEdit, CellOutputDataEdit, SplitCellEdit } from 'sql/workbench/services/notebook/browser/models/cellEdit';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { deepClone } from 'vs/base/common/objects';
|
||||
import { DotnetInteractiveLabel } from 'sql/workbench/api/common/notebooks/notebookUtils';
|
||||
|
||||
/*
|
||||
* Used to control whether a message in a dialog/wizard is displayed as an error,
|
||||
@@ -1006,7 +1007,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
}
|
||||
}
|
||||
|
||||
if (this._capabilitiesService?.providers) {
|
||||
if (this._capabilitiesService?.providers && this.executeManager.providerId === SQL_NOTEBOOK_PROVIDER) {
|
||||
let providers = this._capabilitiesService.providers;
|
||||
for (const server in providers) {
|
||||
let alias = providers[server].connection.notebookKernelAlias;
|
||||
@@ -1045,6 +1046,7 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
this._defaultKernel = notebookConstants.sqlKernelSpec;
|
||||
this._providerId = SQL_NOTEBOOK_PROVIDER;
|
||||
}
|
||||
|
||||
if (!this._defaultLanguageInfo?.name) {
|
||||
// update default language
|
||||
this._defaultLanguageInfo = {
|
||||
@@ -1136,12 +1138,22 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
language = KernelsLanguage.Python;
|
||||
} else if (language.toLowerCase() === 'c#') {
|
||||
language = KernelsLanguage.CSharp;
|
||||
} else if (language.toLowerCase() === 'f#') {
|
||||
language = KernelsLanguage.FSharp;
|
||||
}
|
||||
} else {
|
||||
language = KernelsLanguage.Python;
|
||||
}
|
||||
|
||||
// Update cell language if it was using the previous default, but skip updating the cell
|
||||
// if it was using a more specific language.
|
||||
let oldLanguage = this._language;
|
||||
this._language = language.toLowerCase();
|
||||
this._cells?.forEach(cell => {
|
||||
if (!cell.language || cell.language === oldLanguage) {
|
||||
cell.setOverrideLanguage(this._language);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public changeKernel(displayName: string): void {
|
||||
@@ -1336,6 +1348,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
}
|
||||
let standardKernel = this._standardKernels.find(kernel => kernel.displayName === displayName || displayName.startsWith(kernel.displayName));
|
||||
if (standardKernel && this._savedKernelInfo.name && this._savedKernelInfo.name !== standardKernel.name) {
|
||||
// Special case .NET Interactive kernel name to handle inconsistencies between notebook providers and jupyter kernel specs
|
||||
if (this._savedKernelInfo.display_name === DotnetInteractiveLabel) {
|
||||
this._savedKernelInfo.oldName = this._savedKernelInfo.name;
|
||||
}
|
||||
|
||||
this._savedKernelInfo.name = standardKernel.name;
|
||||
this._savedKernelInfo.display_name = standardKernel.displayName;
|
||||
}
|
||||
@@ -1421,7 +1438,11 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
this._savedKernelInfo = {
|
||||
name: kernel.name,
|
||||
display_name: spec.display_name,
|
||||
language: spec.language
|
||||
language: spec.language,
|
||||
supportedLanguages: spec.supportedLanguages,
|
||||
oldName: spec.oldName,
|
||||
oldDisplayName: spec.oldDisplayName,
|
||||
oldLanguage: spec.oldLanguage
|
||||
};
|
||||
this.clientSession?.configureKernel(this._savedKernelInfo);
|
||||
} catch (err) {
|
||||
@@ -1547,7 +1568,29 @@ export class NotebookModel extends Disposable implements INotebookModel {
|
||||
let metadata = Object.create(null) as nb.INotebookMetadata;
|
||||
// TODO update language and kernel when these change
|
||||
metadata.kernelspec = this._savedKernelInfo;
|
||||
delete metadata.kernelspec?.supportedLanguages;
|
||||
|
||||
metadata.language_info = this.languageInfo;
|
||||
|
||||
// Undo special casing for .NET Interactive
|
||||
if (metadata.kernelspec?.oldName) {
|
||||
metadata.kernelspec.name = metadata.kernelspec.oldName;
|
||||
delete metadata.kernelspec.oldName;
|
||||
}
|
||||
if (metadata.kernelspec?.oldDisplayName) {
|
||||
metadata.kernelspec.display_name = metadata.kernelspec.oldDisplayName;
|
||||
delete metadata.kernelspec.oldDisplayName;
|
||||
}
|
||||
if (metadata.kernelspec?.oldLanguage) {
|
||||
metadata.kernelspec.language = metadata.kernelspec.oldLanguage;
|
||||
delete metadata.kernelspec.oldLanguage;
|
||||
}
|
||||
if (metadata.language_info?.oldName) {
|
||||
metadata.language_info.name = metadata.language_info?.oldName;
|
||||
delete metadata.language_info?.oldName;
|
||||
}
|
||||
|
||||
|
||||
metadata.tags = this._tags;
|
||||
metadata.multi_connection_mode = this._multiConnectionMode ? this._multiConnectionMode : undefined;
|
||||
if (this.configurationService.getValue(saveConnectionNameConfigName)) {
|
||||
|
||||
@@ -59,6 +59,7 @@ export interface IStandardKernelWithProvider {
|
||||
readonly displayName: string;
|
||||
readonly connectionProviderIds: string[];
|
||||
readonly notebookProvider: string;
|
||||
readonly supportedLanguages: string[];
|
||||
}
|
||||
|
||||
export interface IEndpoint {
|
||||
|
||||
@@ -17,7 +17,7 @@ import { NotebookChangeType, CellType } from 'sql/workbench/services/notebook/co
|
||||
import { IBootstrapParams } from 'sql/workbench/services/bootstrap/common/bootstrapParams';
|
||||
import { BaseTextEditor } from 'vs/workbench/browser/parts/editor/textEditor';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { INotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
||||
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import { NotebookViewsExtension } from 'sql/workbench/services/notebook/browser/notebookViews/notebookViewsExtension';
|
||||
@@ -137,6 +137,8 @@ export interface INotebookService {
|
||||
*/
|
||||
notifyCellExecutionStarted(): void;
|
||||
|
||||
createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput | undefined>;
|
||||
|
||||
openNotebook(resource: UriComponents, options: INotebookShowOptions): Promise<IEditorPane | undefined>;
|
||||
|
||||
getUntitledUriPath(originalTitle: string): string;
|
||||
|
||||
@@ -248,13 +248,18 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
lifecycleService.onWillShutdown(() => this.shutdown());
|
||||
}
|
||||
|
||||
public async openNotebook(resource: UriComponents, options: INotebookShowOptions): Promise<IEditorPane | undefined> {
|
||||
const uri = URI.revive(resource);
|
||||
|
||||
const editorOptions: ITextEditorOptions = {
|
||||
preserveFocus: options.preserveFocus,
|
||||
pinned: !options.preview
|
||||
};
|
||||
public async createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput | undefined> {
|
||||
let uri: URI;
|
||||
if (resource) {
|
||||
uri = URI.revive(resource);
|
||||
} else {
|
||||
// Need to create a new untitled URI, so find the lowest numbered one that's available
|
||||
let counter = 1;
|
||||
do {
|
||||
uri = URI.from({ scheme: Schemas.untitled, path: `Notebook-${counter}` });
|
||||
counter++;
|
||||
} while (this._untitledEditorService.get(uri));
|
||||
}
|
||||
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
||||
|
||||
let fileInput: IEditorInput;
|
||||
@@ -269,6 +274,7 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
fileInput = this._editorService.createEditorInput({ forceFile: true, resource: uri, mode: 'notebook' });
|
||||
}
|
||||
}
|
||||
|
||||
// We only need to get the Notebook language association as such we only need to use ipynb
|
||||
const inputCreator = languageAssociationRegistry.getAssociationForLanguage(NotebookLanguage.Ipynb);
|
||||
if (inputCreator) {
|
||||
@@ -286,7 +292,21 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
}
|
||||
}
|
||||
}
|
||||
return await this._editorService.openEditor(fileInput, editorOptions, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
||||
|
||||
if (!fileInput) {
|
||||
throw new Error(localize('failedToCreateNotebookInput', "Failed to create notebook input for provider '{0}'", options.providerId));
|
||||
}
|
||||
|
||||
return fileInput;
|
||||
}
|
||||
|
||||
public async openNotebook(resource: UriComponents, options: INotebookShowOptions): Promise<IEditorPane | undefined> {
|
||||
const editorOptions: ITextEditorOptions = {
|
||||
preserveFocus: options.preserveFocus,
|
||||
pinned: !options.preview
|
||||
};
|
||||
let input = await this.createNotebookInput(options, resource);
|
||||
return await this._editorService.openEditor(input, editorOptions, viewColumnToEditorGroup(this._editorGroupService, options.position));
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -321,7 +341,8 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
let descriptor = new StandardKernelsDescriptor(notebookConstants.SQL, [{
|
||||
name: notebookConstants.SQL,
|
||||
displayName: notebookConstants.SQL,
|
||||
connectionProviderIds: sqlConnectionTypes
|
||||
connectionProviderIds: sqlConnectionTypes,
|
||||
supportedLanguages: [notebookConstants.sqlKernelSpec.language]
|
||||
}]);
|
||||
this._providerToStandardKernels.set(notebookConstants.SQL, descriptor);
|
||||
}
|
||||
@@ -785,7 +806,12 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
notebookRegistry.registerProviderDescription({
|
||||
provider: serializationProvider.providerId,
|
||||
fileExtensions: [DEFAULT_NOTEBOOK_FILETYPE],
|
||||
standardKernels: [{ name: notebookConstants.SQL, displayName: notebookConstants.SQL, connectionProviderIds: [notebookConstants.SQL_CONNECTION_PROVIDER] }]
|
||||
standardKernels: [{
|
||||
name: notebookConstants.SQL,
|
||||
displayName: notebookConstants.SQL,
|
||||
connectionProviderIds: [notebookConstants.SQL_CONNECTION_PROVIDER],
|
||||
supportedLanguages: [notebookConstants.sqlKernelSpec.language]
|
||||
}]
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
@@ -55,12 +55,26 @@ export const textRendererFactory: IRenderMime.IRendererFactory = {
|
||||
mimeTypes: [
|
||||
'text/plain',
|
||||
'application/vnd.jupyter.stdout',
|
||||
'application/vnd.jupyter.stderr'
|
||||
'application/vnd.jupyter.stderr',
|
||||
'application/vnd.code.notebook.stdout',
|
||||
'application/vnd.code.notebook.stderr'
|
||||
],
|
||||
defaultRank: 120,
|
||||
createRenderer: options => new widgets.RenderedText(options)
|
||||
};
|
||||
|
||||
/**
|
||||
* A mime renderer factory for VS Code Notebook error data.
|
||||
*/
|
||||
export const errorRendererFactory: IRenderMime.IRendererFactory = {
|
||||
safe: true,
|
||||
mimeTypes: [
|
||||
'application/vnd.code.notebook.error'
|
||||
],
|
||||
defaultRank: 121,
|
||||
createRenderer: options => new widgets.ErrorText(options)
|
||||
};
|
||||
|
||||
/**
|
||||
* A placeholder factory for deprecated rendered JavaScript.
|
||||
*/
|
||||
@@ -101,6 +115,7 @@ export const standardRendererFactories: ReadonlyArray<IRenderMime.IRendererFacto
|
||||
imageRendererFactory,
|
||||
javaScriptRendererFactory,
|
||||
textRendererFactory,
|
||||
errorRendererFactory,
|
||||
dataResourceRendererFactory,
|
||||
ipywidgetFactory
|
||||
];
|
||||
|
||||
@@ -319,6 +319,34 @@ export class RenderedText extends RenderedCommon {
|
||||
}
|
||||
}
|
||||
|
||||
export class ErrorText extends RenderedCommon {
|
||||
/**
|
||||
* Construct a new error text widget.
|
||||
*
|
||||
* @param options - The options for initializing the widget.
|
||||
*/
|
||||
constructor(options: IRenderMime.IRendererOptions) {
|
||||
super(options);
|
||||
this.addClass('jp-ErrorText');
|
||||
}
|
||||
|
||||
/**
|
||||
* Render a mime model.
|
||||
*
|
||||
* @param model - The mime model to render.
|
||||
*
|
||||
* @returns A promise which resolves when rendering is complete.
|
||||
*/
|
||||
render(model: IRenderMime.IMimeModel): Promise<void> {
|
||||
let err = JSON.parse(String(model.data[this.mimeType]));
|
||||
let text = err.name && err.message ? `${err.name}: ${err.message}` : err.name || err.message;
|
||||
return renderers.renderText({
|
||||
host: this.node,
|
||||
source: text
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* A widget for displaying deprecated JavaScript output.
|
||||
*/
|
||||
|
||||
@@ -22,5 +22,6 @@ export enum KernelsLanguage {
|
||||
SparkScala = 'scala',
|
||||
SparkR = 'sparkr',
|
||||
PowerShell = 'powershell',
|
||||
CSharp = 'cs'
|
||||
CSharp = 'csharp',
|
||||
FSharp = 'fsharp'
|
||||
}
|
||||
|
||||
@@ -55,6 +55,12 @@ let providerDescriptionType: IJSONSchema = {
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
},
|
||||
supportedLanguages: {
|
||||
type: 'array',
|
||||
items: {
|
||||
type: 'string'
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -112,7 +118,8 @@ export interface INotebookProviderRegistry {
|
||||
|
||||
readonly onNewDescriptionRegistration: Event<{ id: string, registration: ProviderDescriptionRegistration }>;
|
||||
|
||||
updateProviderDescriptionLanguages(providerId: string, languages: string[]): void;
|
||||
updateProviderKernels(providerId: string, kernels: azdata.nb.IStandardKernel[]): void;
|
||||
updateKernelLanguages(providerId: string, kernelName: string, languages: string[]): void;
|
||||
registerProviderDescription(provider: ProviderDescriptionRegistration): void;
|
||||
registerNotebookLanguageMagic(magic: NotebookLanguageMagicRegistration): void;
|
||||
}
|
||||
@@ -124,24 +131,33 @@ class NotebookProviderRegistry implements INotebookProviderRegistry {
|
||||
private _onNewDescriptionRegistration = new Emitter<{ id: string, registration: ProviderDescriptionRegistration }>();
|
||||
public readonly onNewDescriptionRegistration: Event<{ id: string, registration: ProviderDescriptionRegistration }> = this._onNewDescriptionRegistration.event;
|
||||
|
||||
updateProviderDescriptionLanguages(providerId: string, languages: string[]): void {
|
||||
private readonly providerNotInRegistryError = (providerId: string): string => localize('providerNotInRegistryError', "The specified provider '{0}' is not present in the notebook registry.", providerId);
|
||||
|
||||
updateProviderKernels(providerId: string, kernels: azdata.nb.IStandardKernel[]): void {
|
||||
let registration = this._providerDescriptionRegistration.get(providerId);
|
||||
if (!registration) {
|
||||
throw new Error(localize('providerNotInRegistryError', "The specified provider '{0}' is not present in the notebook registry.", providerId));
|
||||
throw new Error(this.providerNotInRegistryError(providerId));
|
||||
}
|
||||
let kernels = languages.map<azdata.nb.IStandardKernel>(language => {
|
||||
return {
|
||||
name: language,
|
||||
displayName: language,
|
||||
connectionProviderIds: []
|
||||
};
|
||||
});
|
||||
registration.standardKernels = kernels;
|
||||
|
||||
// Update provider description with new info
|
||||
this.registerProviderDescription(registration);
|
||||
}
|
||||
|
||||
updateKernelLanguages(providerId: string, kernelName: string, languages: string[]): void {
|
||||
let registration = this._providerDescriptionRegistration.get(providerId);
|
||||
if (!registration) {
|
||||
throw new Error(this.providerNotInRegistryError(providerId));
|
||||
}
|
||||
let kernel = registration.standardKernels?.find(kernel => kernel.name === kernelName);
|
||||
if (kernel) {
|
||||
kernel.supportedLanguages = languages;
|
||||
}
|
||||
|
||||
// Update provider description with new info
|
||||
this.registerProviderDescription(registration);
|
||||
}
|
||||
|
||||
registerProviderDescription(registration: ProviderDescriptionRegistration): void {
|
||||
this._providerDescriptionRegistration.set(registration.provider, registration);
|
||||
this._onNewDescriptionRegistration.fire({ id: registration.provider, registration: registration });
|
||||
|
||||
@@ -64,21 +64,23 @@ suite('Notebook Serializer', () => {
|
||||
}
|
||||
}],
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'python3',
|
||||
display_name: 'Python 3',
|
||||
language: 'python'
|
||||
},
|
||||
language_info: {
|
||||
name: 'python',
|
||||
version: '3.8.10',
|
||||
mimetype: 'text/x-python',
|
||||
codemirror_mode: {
|
||||
name: 'ipython',
|
||||
version: '3'
|
||||
}
|
||||
},
|
||||
custom: {
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'python3',
|
||||
display_name: 'Python 3',
|
||||
language: 'python'
|
||||
},
|
||||
language_info: {
|
||||
name: 'python',
|
||||
version: '3.8.10',
|
||||
mimetype: 'text/x-python',
|
||||
codemirror_mode: {
|
||||
name: 'ipython',
|
||||
version: '3'
|
||||
}
|
||||
}
|
||||
},
|
||||
nbformat: NBFORMAT,
|
||||
nbformat_minor: NBFORMAT_MINOR
|
||||
}
|
||||
@@ -161,6 +163,13 @@ suite('Notebook Serializer', () => {
|
||||
}],
|
||||
executionSummary: {
|
||||
executionOrder: 1
|
||||
},
|
||||
metadata: {
|
||||
custom: {
|
||||
metadata: {
|
||||
language: 'python'
|
||||
}
|
||||
}
|
||||
}
|
||||
}, {
|
||||
kind: NotebookCellKind.Code,
|
||||
@@ -176,24 +185,33 @@ suite('Notebook Serializer', () => {
|
||||
}],
|
||||
executionSummary: {
|
||||
executionOrder: 2
|
||||
},
|
||||
metadata: {
|
||||
custom: {
|
||||
metadata: {
|
||||
language: 'python'
|
||||
}
|
||||
}
|
||||
}
|
||||
}],
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'python3',
|
||||
display_name: 'Python 3',
|
||||
language: 'python'
|
||||
},
|
||||
language_info: {
|
||||
name: 'python',
|
||||
version: '3.8.10',
|
||||
mimetype: 'text/x-python',
|
||||
codemirror_mode: {
|
||||
name: 'ipython',
|
||||
version: '3'
|
||||
}
|
||||
},
|
||||
custom: {
|
||||
metadata: {
|
||||
kernelspec: {
|
||||
name: 'python3',
|
||||
display_name: 'Python 3',
|
||||
language: 'python'
|
||||
},
|
||||
language_info: {
|
||||
name: 'python',
|
||||
version: '3.8.10',
|
||||
mimetype: 'text/x-python',
|
||||
codemirror_mode: {
|
||||
name: 'ipython',
|
||||
version: '3'
|
||||
}
|
||||
}
|
||||
},
|
||||
nbformat: NBFORMAT,
|
||||
nbformat_minor: NBFORMAT_MINOR
|
||||
}
|
||||
@@ -349,7 +367,10 @@ suite('Notebook Serializer', () => {
|
||||
cells: [{
|
||||
contents: {
|
||||
cell_type: 'code',
|
||||
source: '1+1'
|
||||
source: '1+1',
|
||||
metadata: {
|
||||
language: 'python'
|
||||
}
|
||||
}
|
||||
}, {
|
||||
contents: {
|
||||
@@ -413,7 +434,7 @@ suite('Notebook Serializer', () => {
|
||||
}
|
||||
|
||||
test('Retrieve range of cells from VS Code NotebookDocument', async () => {
|
||||
let expectedCells: vscode.NotebookCell[] = testDoc.cells.map((cell, index) => convertToVSCodeNotebookCell(cell.contents.source, index, testDoc.uri, testDoc.kernelSpec.language));
|
||||
let expectedCells: vscode.NotebookCell[] = testDoc.cells.map((cell, index) => convertToVSCodeNotebookCell(cell.contents.cell_type, index, cell.uri, testDoc.uri, cell.contents.metadata?.language, cell.contents.source));
|
||||
let vsDoc = new VSCodeNotebookDocument(testDoc);
|
||||
|
||||
let actualCells = vsDoc.getCells();
|
||||
@@ -430,7 +451,7 @@ suite('Notebook Serializer', () => {
|
||||
});
|
||||
|
||||
test('Retrieve specific cell from VS Code NotebookDocument', async () => {
|
||||
let expectedCells: vscode.NotebookCell[] = testDoc.cells.map((cell, index) => convertToVSCodeNotebookCell(cell.contents.source, index, testDoc.uri, testDoc.kernelSpec.language));
|
||||
let expectedCells: vscode.NotebookCell[] = testDoc.cells.map((cell, index) => convertToVSCodeNotebookCell(cell.contents.cell_type, index, cell.uri, testDoc.uri, cell.contents.metadata?.language, cell.contents.source));
|
||||
let vsDoc = new VSCodeNotebookDocument(testDoc);
|
||||
|
||||
let firstCell = vsDoc.cellAt(0);
|
||||
|
||||
Reference in New Issue
Block a user