Convert .NET Interactive notebook's kernel spec to a VS Code compatible kernel when saving. (#19176)

This commit is contained in:
Cory Rivera
2022-04-22 16:00:13 -07:00
committed by GitHub
parent d9cf93cdae
commit 7b58568d26
5 changed files with 211 additions and 26 deletions

View File

@@ -12,10 +12,9 @@ import { CellTypes, MimeTypes, OutputTypes } from 'sql/workbench/services/notebo
import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants';
import { NotebookCellKind } from 'vs/workbench/api/common/extHostTypes';
export const DotnetInteractiveJupyterLanguagePrefix = '.net-';
export const DotnetInteractiveLanguagePrefix = 'dotnet-interactive.';
export const DotnetInteractiveJupyterLabelPrefix = '.NET (';
export const DotnetInteractiveLabel = '.NET Interactive';
const DotnetInteractiveJupyterKernelPrefix = '.net-';
const DotnetInteractiveLanguagePrefix = 'dotnet-interactive.';
export const DotnetInteractiveDisplayName = '.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>{
@@ -139,3 +138,87 @@ export function convertToVSCodeNotebookData(notebook: azdata.nb.INotebookContent
};
return result;
}
// #region .NET Interactive Kernel Metadata Conversion
/*
Since ADS relies on notebook kernelSpecs for provider metadata in a lot of places, we have to convert
a .NET Interactive notebook's Jupyter kernelSpec to an internal representation so that it matches up with
the contributed .NET Interactive notebook provider from the Jupyter extension. When saving a notebook, we
then need to restore the original kernelSpec state so that it will work with other notebook apps like
VS Code. VS Code does something similar by shifting a Jupyter notebook's original metadata over to a new
"custom" field, which is then shifted back when saving the notebook.
This is an example of an internal kernel representation we use to get compatibility working (C#, in this case):
kernelSpec: {
name: 'jupyter-notebook', // Matches the name of the notebook provider from the Jupyter extension
language: 'dotnet-interactive.csharp', // Matches the contributed languages from the .NET Interactive extension
display_name: '.NET Interactive' // The kernel name we need to show in our dropdown to match VS Code's kernel dropdown
}
This is how that C# kernel spec would need to be saved to work in VS Code:
kernelSpec: {
name: '.net-csharp',
language: 'C#',
display_name: '.NET (C#)'
}
*/
/**
* Stores equivalent external kernel metadata in a newly created .NET Interactive notebook, which is used as the default metadata when saving the notebook. This is so that ADS notebooks are still usable in other apps.
* @param kernelSpec The notebook kernel metadata to be modified.
*/
export function addExternalInteractiveKernelMetadata(kernelSpec: azdata.nb.IKernelSpec): void {
if (kernelSpec.name === 'jupyter-notebook' && kernelSpec.display_name === DotnetInteractiveDisplayName && kernelSpec.language) {
let language = kernelSpec.language.replace(DotnetInteractiveLanguagePrefix, '');
let displayLanguage: string;
switch (language) {
case 'csharp':
displayLanguage = 'C#';
break;
case 'fsharp':
displayLanguage = 'F#';
break;
case 'pwsh':
displayLanguage = 'PowerShell';
break;
default:
displayLanguage = language;
}
if (!kernelSpec.oldName) {
kernelSpec.oldName = `${DotnetInteractiveJupyterKernelPrefix}${language}`;
}
if (!kernelSpec.oldDisplayName) {
kernelSpec.oldDisplayName = `.NET (${displayLanguage})`;
}
if (!kernelSpec.oldLanguage) {
kernelSpec.oldLanguage = displayLanguage;
}
}
}
/**
* Converts a .NET Interactive notebook's metadata to an internal representation needed for VS Code notebook compatibility. This metadata is then restored when saving the notebook.
* @param metadata The notebook metadata to be modified.
*/
export function convertToInternalInteractiveKernelMetadata(metadata: azdata.nb.INotebookMetadata | undefined): void {
if (metadata?.kernelspec?.name?.startsWith(DotnetInteractiveJupyterKernelPrefix)) {
metadata.kernelspec.oldDisplayName = metadata.kernelspec.display_name;
metadata.kernelspec.display_name = DotnetInteractiveDisplayName;
let kernelName = metadata.kernelspec.name;
let baseLanguageName = kernelName.replace(DotnetInteractiveJupyterKernelPrefix, '');
if (baseLanguageName === 'powershell') {
baseLanguageName = 'pwsh';
}
let languageName = `${DotnetInteractiveLanguagePrefix}${baseLanguageName}`;
metadata.kernelspec.oldLanguage = metadata.kernelspec.language;
metadata.kernelspec.language = languageName;
metadata.language_info.oldName = metadata.language_info.name;
metadata.language_info.name = languageName;
}
}
// #endregion

View File

@@ -7,7 +7,7 @@ import type * as vscode from 'vscode';
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 { addExternalInteractiveKernelMetadata, convertToVSCodeNotebookCell } from 'sql/workbench/api/common/notebooks/notebookUtils';
import { CellTypes } from 'sql/workbench/services/notebook/common/contracts';
import { VSCodeNotebookDocument } from 'sql/workbench/api/common/notebooks/vscodeNotebookDocument';
import { URI } from 'vs/base/common/uri';
@@ -86,6 +86,9 @@ class VSCodeKernel implements azdata.nb.IKernel {
this._kernelSpec.supportedLanguages = this._controller.supportedLanguages;
}
// Store external kernel names for .NET Interactive kernels for when notebook gets saved, so that notebook is usable outside of ADS
addExternalInteractiveKernelMetadata(this._kernelSpec);
this._name = this._kernelSpec.name;
this._info = {
protocol_version: '',