diff --git a/src/sql/workbench/api/common/notebooks/notebookUtils.ts b/src/sql/workbench/api/common/notebooks/notebookUtils.ts index 66a8bd990e..24d134e400 100644 --- a/src/sql/workbench/api/common/notebooks/notebookUtils.ts +++ b/src/sql/workbench/api/common/notebooks/notebookUtils.ts @@ -13,7 +13,7 @@ import { NBFORMAT, NBFORMAT_MINOR } from 'sql/workbench/common/constants'; import { NotebookCellKind } from 'vs/workbench/api/common/extHostTypes'; const DotnetInteractiveJupyterKernelPrefix = '.net-'; -const DotnetInteractiveLanguagePrefix = 'dotnet-interactive.'; +export 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 { diff --git a/src/sql/workbench/contrib/notebook/test/electron-browser/cell.test.ts b/src/sql/workbench/contrib/notebook/test/electron-browser/cell.test.ts index 2f74df6ba6..328dd5f50d 100644 --- a/src/sql/workbench/contrib/notebook/test/electron-browser/cell.test.ts +++ b/src/sql/workbench/contrib/notebook/test/electron-browser/cell.test.ts @@ -27,6 +27,7 @@ import { TestNotificationService } from 'vs/platform/notification/test/common/te import { ICommandService, NullCommandService } from 'vs/platform/commands/common/commands'; import { ControlType, IChartOption } from 'sql/workbench/contrib/charts/browser/chartOptions'; import { CellModel } from 'sql/workbench/services/notebook/browser/models/cell'; +import { ICellMetadata } from 'sql/workbench/api/common/sqlExtHostTypes'; let instantiationService: IInstantiationService; @@ -1508,4 +1509,45 @@ suite('Cell Model', function (): void { }); + test('should set .NET Interactive cell metadata when converting to JSON', async function () { + let notebookModel = new NotebookModelStub({ + name: '', + version: '', + mimetype: '' + }); + let contents: nb.ICellContents = { + cell_type: CellTypes.Code, + source: '', + metadata: { + language: 'dotnet-interactive.csharp' + } + }; + let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false }); + assert((model.metadata as ICellMetadata).dotnet_interactive === undefined, 'dotnet_interactive field should not be set in cell metadata before converting to JSON'); + let cellJson = model.toJSON(); + assert((cellJson.metadata as ICellMetadata).dotnet_interactive !== undefined, 'dotnet_interactive field should be set in JSON cell metadata'); + assert.strictEqual((cellJson.metadata as ICellMetadata).dotnet_interactive.language, 'csharp', 'Expected dotnet_interactive language field to be csharp'); + }); + + test('should overwrite pre-existing .NET Interactive cell metadata when converting to JSON', async function () { + let notebookModel = new NotebookModelStub({ + name: '', + version: '', + mimetype: '' + }); + let contents: nb.ICellContents = { + cell_type: CellTypes.Code, + source: '', + metadata: { + language: 'dotnet-interactive.csharp' + } + }; + (contents.metadata as ICellMetadata).dotnet_interactive = { language: 'fsharp' }; + + let model = factory.createCell(contents, { notebook: notebookModel, isTrusted: false }); + assert((model.metadata as ICellMetadata).dotnet_interactive !== undefined, 'dotnet_interactive field should exist in cell metadata'); + let cellJson = model.toJSON(); + assert((cellJson.metadata as ICellMetadata).dotnet_interactive !== undefined, 'dotnet_interactive field should be set in JSON cell metadata'); + assert.strictEqual((cellJson.metadata as ICellMetadata).dotnet_interactive.language, 'csharp', 'Expected dotnet_interactive language field to be csharp'); + }); }); diff --git a/src/sql/workbench/services/notebook/browser/models/cell.ts b/src/sql/workbench/services/notebook/browser/models/cell.ts index e0a78418de..d18fc8455f 100644 --- a/src/sql/workbench/services/notebook/browser/models/cell.ts +++ b/src/sql/workbench/services/notebook/browser/models/cell.ts @@ -37,6 +37,7 @@ import { IModeService } from 'vs/editor/common/services/modeService'; import { ICellMetadata } from 'sql/workbench/api/common/sqlExtHostTypes'; import { alert } from 'vs/base/browser/ui/aria/aria'; import { CELL_URI_PATH_PREFIX } from 'sql/workbench/common/constants'; +import { DotnetInteractiveLanguagePrefix } from 'sql/workbench/api/common/notebooks/notebookUtils'; let modelId = 0; const ads_execute_command = 'ads_execute_command'; @@ -1015,6 +1016,10 @@ export class CellModel extends Disposable implements ICellModel { if (this._configurationService?.getValue('notebook.saveConnectionName')) { metadata.connection_name = this._savedConnectionName; } + // Set .NET Interactive language field for vscode compatibility + if (this._language?.startsWith(DotnetInteractiveLanguagePrefix)) { + (cellJson.metadata as ICellMetadata).dotnet_interactive = { language: this._language.replace(DotnetInteractiveLanguagePrefix, '') }; + } } else if (this._cellType === CellTypes.Markdown && this._attachments) { cellJson.attachments = this._attachments; }