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:
@@ -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 });
|
||||
|
||||
Reference in New Issue
Block a user