Files
azuredatastudio/src/sql/workbench/services/notebook/browser/notebookService.ts
Charles Gagnon 4a2b31f3ba Hook up Notebook execution edits (#17943)
* Start rerouting VSCode cell execution APIs.

* Add more conversion code.

* Convert VSCode notebook registrations into ADS equivalents.

* Update vscode notebook provider kernels when notebook controller's supportedLanguages are set.

* Update an error message.

* Add another session argument.

* Add base classes for converting notebook serializers.

* Disable some vscode notebook methods.

* Disable more vscode APIs.

* Disable more stuff.

* Start implementing serializer notebook data conversions.

* Use direct references to extension host notebook methods, rather than azdata ones.

* Add a comment.

* Remove a space.

* Use import type to fix module loading errors.

* Use internal cancellation token class.

* Start adding cell output conversion.

* Convert data from byte array to a string.

* More output work.

* Use a Set for proxy filtering.

* Start adding tests.

* Include metadata in cell conversion. Fix other test failures.

* Fix serialize tests.

* Add more tests.

* Remove wildcard characters from vscode filenames.

* Start implementing session details.

* Add more kernel info.

* Add kernel spec.

* Add Future callback wrapper class.

* Start implementing execute conversion.

* Pass notebook URI to requestExecute.

* Start working on CellExecution methods.

* Move some code around to fix layering issues.

* Use proxy to access browser code, rather than direct imports.

* Move files around to fix layering issues.

* Remove unused imports.

* Start implementing some notebook cell execution behaviors.

* Revert some unnecessary extHost API changes.

* Check for nbformat.

* Also handle nbformat in serialize case.

* Active notebook extensions when resolving NotebookInput.

* Fix nbformat handling.

* Disable VSCode notebooks code.

* Filter out notebook services from registration assertion.

* Wait for providers to load before calling canResolve.

* Use controller's viewType for notebook provider ID, instead of controller ID.

* Start adding extHostNotebook tests for new APIs.

* Re-order proxy calls.

* Remove commented code.

* Move vscode provider files to browser folder. Fix RPC serialization issues by using readonly field instead of getter for providerId.

* Add a comment.

* Remove unnecessary dispose call.

* Handle disposable from registerExecuteProvider.

* Remove a comment.

* Remove unnecessary provider fields.

* Remove reference to notebook service to fix circular reference issue in stringify.

* Add object types for methods in ADSNotebookController.

* Wait for controller languages to be ready before marking session manager as ready.

* Add correct promise.

* Add undefined return type for optional supportedLanguages property.

* Refine promise logic.

* Move vscode functionality back to ExtHostNotebook, since the NotebookService can't be passed back over RPC (some kind of circular reference error).

* Fix remaining issues from last commit.

* Replace "not implemented" methods with placeholder return types in order to enable testing.

* Also wait for execution handler to be set before marking session manager as ready.

* Fix usage of NotebookRegistry when updating provider description languages.

* Refine file extension conversion.

* Fix file extension conversion to match ADS extension behavior.

* Emit new provider registration event when adding supported languages.

* Remove checks for duplicate file providers and kernels.

* Fix a test failure.

* Fix file extension parsing.

* Use default executeManager if one isn't defined for provider in notebookModel.

* Add descriptors for waiting on standardKernels registration.

* Increase timeout

* Add an error message.

* Start working on retrieving default kernel from registered providers, rather than always falling back to SQL.

* Revert "Start working on retrieving default kernel from registered providers, rather than always falling back to SQL."

This reverts commit 1916ea1ce3a0072f51bec683116dc7bb6c7aefdc.

* Emit activation events after provider registration.

* Wait on standard kernels availability when getting an execute provider.

* Throw an error if session manager isn't ready yet.

* Actually resolve language promise correctly.

* Add some checks for undefined notebook data objects.

* Create kernel spec data correctly.

* Add extension changes for local testing only.

* Clean up test class.

* Add a reminder comment.

* Undo commented out notebook stuff

* Temporarily hard code default kernel.

* Retrieve default kernel in notebookModel if it's not already provided.

* Revert an import change.

* Remove unnecessary method from extHostNotebook.

* Move an interface around.

* wip

* Check for proposed API for some VSCode extHost methods.

* Remove a comment.

* Fix notebookUtils tests.

* Fix notebookModel tests.

* Fix notebookFindModel tests.

* Fix notebookViewsExtension tests.

* Fix remaining notebookView tests.

* Refactor output conversion functionality into separate methods.

* Update some unit tests for output conversion.

* Move a method.

* Rename conversion methods to fit acronym styling.

* Add another conversion test case.

* Revert local testing changes.

* Remove old method.

* cleanup

* Remove some comments.

* Move localized string to locConstants.

* Add a space to loc string.

* Add comments to new SQL Carbon Edit tags.

* Create constants for nbformat and nbformat_minor.

* Move some vscode-only fields to proposed APIs.

* Check for valid state

* Properly null check

* Adding logging for provider wait timeouts.

* wip update

* Fix compile

* Switch to cell edits

* Update docs

* Remove custom output type

* cleanup

* fix

* cleanup

* more cleanup

* Fixes

* Fix tests and lint errors

Co-authored-by: Cory Rivera <corivera@microsoft.com>
2022-01-04 16:35:16 -08:00

242 lines
8.9 KiB
TypeScript

/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the Source EULA. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as azdata from 'azdata';
import { Event } from 'vs/base/common/event';
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
import { URI, UriComponents } from 'vs/base/common/uri';
import { RenderMimeRegistry } from 'sql/workbench/services/notebook/browser/outputs/registry';
import { ModelFactory } from 'sql/workbench/services/notebook/browser/models/modelFactory';
import { IConnectionProfile } from 'sql/platform/connection/common/interfaces';
import { INotebookEditOperation } from 'sql/workbench/api/common/sqlExtHostTypes';
import { ICellModel, INotebookModel } from 'sql/workbench/services/notebook/browser/models/modelInterfaces';
import { NotebookChangeType, CellType } from 'sql/workbench/services/notebook/common/contracts';
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 { 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';
export const SERVICE_ID = 'sqlNotebookService';
export const INotebookService = createDecorator<INotebookService>(SERVICE_ID);
export const DEFAULT_NOTEBOOK_PROVIDER = 'builtin';
export const DEFAULT_NOTEBOOK_FILETYPE = '.ipynb';
export const SQL_NOTEBOOK_PROVIDER = 'sql';
export const OVERRIDE_EDITOR_THEMING_SETTING = 'notebook.overrideEditorTheming';
export interface ILanguageMagic {
magic: string;
language: string;
kernels?: string[];
executionTarget?: string;
}
/**
* Valid navigation providers.
*/
export enum NavigationProviders {
NotebooksNavigator = 'BookNavigator.Notebooks',
ProvidedBooksNavigator = 'BookNavigator.ProvidedBooks'
}
export const unsavedBooksContextKey = 'unsavedBooks';
export interface INotebookService {
_serviceBrand: undefined;
readonly onNotebookEditorAdd: Event<INotebookEditor>;
readonly onNotebookEditorRemove: Event<INotebookEditor>;
onNotebookEditorRename: Event<INotebookEditor>;
readonly isRegistrationComplete: boolean;
readonly registrationComplete: Promise<void>;
readonly languageMagics: ILanguageMagic[];
registerSerializationProvider(providerId: string, provider: ISerializationProvider): void;
registerExecuteProvider(providerId: string, provider: IExecuteProvider): void;
unregisterSerializationProvider(providerId: string): void;
unregisterExecuteProvider(providerId: string): void;
registerNavigationProvider(provider: INavigationProvider): void;
getNavigationProvider(notebookUri: URI): INavigationProvider;
getSupportedFileExtensions(): string[];
getProvidersForFileType(fileType: string): string[] | undefined;
getStandardKernelsForProvider(provider: string): Promise<azdata.nb.IStandardKernel[] | undefined>;
getOrCreateSerializationManager(providerId: string, uri: URI): Promise<ISerializationManager>;
getOrCreateExecuteManager(providerId: string, uri: URI): Thenable<IExecuteManager>;
addNotebookEditor(editor: INotebookEditor): void;
removeNotebookEditor(editor: INotebookEditor): void;
listNotebookEditors(): INotebookEditor[];
findNotebookEditor(notebookUri: URI): INotebookEditor | undefined;
getMimeRegistry(): RenderMimeRegistry;
renameNotebookEditor(oldUri: URI, newUri: URI, currentEditor: INotebookEditor): void;
/**
* Checks if a notebook has previously been marked as trusted, and that
* the notebook has not changed on disk since that time. If the notebook
* is currently dirty in the app, the previous trusted state will be used even
* if it's altered on disk since the version in our UI is based on previously trusted
* content.
* @param notebookUri the URI identifying a notebook
* @param isDirty is the notebook marked as dirty in by the text model trackers?
*/
isNotebookTrustCached(notebookUri: URI, isDirty: boolean): Promise<boolean>;
/**
* Serializes an impactful Notebook state change. This will result
* in trusted state being serialized if needed, and notifications being
* sent to listeners that can act on the point-in-time notebook state
* @param notebookUri The URI identifying a notebook.
* @param changeType The type of notebook state change to serialize.
* @param cell (Optional) The notebook cell associated with the state change.
* @param isTrusted (Optional) A manual override for the notebook's trusted state.
*/
serializeNotebookStateChange(notebookUri: URI, changeType: NotebookChangeType, cell?: ICellModel, isTrusted?: boolean): Promise<void>;
/**
*
* @param notebookUri URI of the notebook to navigate to
* @param sectionId ID of the section to navigate to
*/
navigateTo(notebookUri: URI, sectionId: string): void;
/**
* Sets the trusted mode for the specified notebook.
* @param notebookUri URI of the notebook to navigate to
* @param isTrusted True if notebook is to be set to trusted, false otherwise.
*/
setTrusted(notebookUri: URI, isTrusted: boolean): Promise<boolean>;
/**
* Event that gets fired when a cell is executed.
*/
onCodeCellExecutionStart: Event<void>;
/**
* Fires the onCodeCellExecutionStart event.
*/
notifyCellExecutionStarted(): void;
openNotebook(resource: UriComponents, options: INotebookShowOptions): Promise<IEditorPane | undefined>;
getUntitledUriPath(originalTitle: string): string;
}
export interface IExecuteProvider {
readonly providerId: string;
getExecuteManager(notebookUri: URI): Thenable<IExecuteManager>;
handleNotebookClosed(notebookUri: URI): void;
}
export interface ISerializationProvider {
readonly providerId: string;
getSerializationManager(notebookUri: URI): Thenable<ISerializationManager>;
}
export interface ISerializationManager {
providerId: string;
readonly contentManager: azdata.nb.ContentManager;
}
export interface IExecuteManager {
providerId: string;
readonly sessionManager: azdata.nb.SessionManager;
readonly serverManager: azdata.nb.ServerManager;
}
export interface IProviderInfo {
providerId: string;
providers: string[];
}
export interface INotebookParams extends IBootstrapParams {
notebookUri: URI;
input: INotebookInput;
providerInfo: Promise<IProviderInfo>;
profile?: IConnectionProfile;
modelFactory?: ModelFactory;
}
/**
* Defines a section in a notebook as the header text for that section,
* the relative URI that can be used to link to it inside Notebook documents
*/
export interface INotebookSection {
header: string;
relativeUri: string;
}
export interface ICellEditorProvider {
hasEditor(): boolean;
isCellOutput: boolean;
cellGuid(): string;
getEditor(): BaseTextEditor;
deltaDecorations(newDecorationsRange: NotebookRange | NotebookRange[], oldDecorationsRange: NotebookRange | NotebookRange[]): void;
}
export class NotebookRange extends Range {
updateActiveCell(cell: ICellModel) {
this.cell = cell;
}
cell: ICellModel;
isMarkdownSourceCell: boolean;
outputComponentIndex: number;
constructor(cell: ICellModel, startLineNumber: number, startColumn: number, endLineNumber: number, endColumn: number, markdownEditMode?: boolean, outputIndex?: number) {
super(startLineNumber, startColumn, endLineNumber, endColumn);
this.updateActiveCell(cell);
this.isMarkdownSourceCell = markdownEditMode ? markdownEditMode : false;
this.outputComponentIndex = outputIndex >= 0 ? outputIndex : -1;
}
}
export interface INotebookEditor {
readonly notebookParams: INotebookParams;
readonly id: string;
readonly cells?: ICellModel[];
readonly cellEditors: ICellEditorProvider[];
readonly modelReady: Promise<INotebookModel>;
readonly model: INotebookModel | null;
readonly views: NotebookViewsExtension | null;
isDirty(): boolean;
isActive(): boolean;
isVisible(): boolean;
executeEdits(edits: INotebookEditOperation[]): boolean;
runCell(cell: ICellModel): Promise<boolean>;
runAllCells(startCell?: ICellModel, endCell?: ICellModel): Promise<boolean>;
clearOutput(cell: ICellModel): Promise<boolean>;
clearAllOutputs(): Promise<boolean>;
getSections(): INotebookSection[];
navigateToSection(sectionId: string): void;
deltaDecorations(newDecorationsRange: NotebookRange | NotebookRange[], oldDecorationsRange: NotebookRange | NotebookRange[]): void;
addCell(cellType: CellType, index?: number, event?: UIEvent);
}
export interface INavigationProvider {
providerId: string;
hasNavigation: boolean;
getNavigation(uri: URI): Thenable<azdata.nb.NavigationResult>;
onNext(uri: URI): void;
onPrevious(uri: URI): void;
}