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:
Cory Rivera
2022-02-25 11:58:59 -08:00
committed by GitHub
parent 02341088eb
commit ffdefd3b52
41 changed files with 649 additions and 278 deletions

View File

@@ -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>

View File

@@ -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) {

View File

@@ -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 {

View File

@@ -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;
}
}

View File

@@ -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.
*/

View File

@@ -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']
}
]
]

View File

@@ -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);

View File

@@ -236,7 +236,8 @@ suite.skip('NotebookService:', function (): void {
standardKernels: [{
name: 'kernel1',
connectionProviderIds: [],
displayName: 'Kernel 1'
displayName: 'Kernel 1',
supportedLanguages: ['python']
}],
provider: 'otherProvider'
};

View File

@@ -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']
}]);
});

View File

@@ -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.');