mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 09:35:41 -05:00
Correctly handle creating and saving untitled notebook .dib files. (#18744)
This commit is contained in:
@@ -342,8 +342,8 @@ export class MainThreadNotebookDocumentsAndEditors extends Disposable implements
|
||||
}
|
||||
}
|
||||
|
||||
async $tryCreateNotebookDocument(options: INotebookShowOptions): Promise<UriComponents> {
|
||||
let input = await this._notebookService.createNotebookInput(options);
|
||||
async $tryCreateNotebookDocument(providerId: string, contents?: azdata.nb.INotebookContents): Promise<UriComponents> {
|
||||
let input = await this._notebookService.createNotebookInputFromContents(providerId, contents);
|
||||
return input.resource;
|
||||
}
|
||||
|
||||
|
||||
@@ -224,12 +224,7 @@ export class ExtHostNotebookDocumentsAndEditors implements ExtHostNotebookDocume
|
||||
|
||||
//#region Extension accessible methods
|
||||
async createNotebookDocument(providerId: string, contents?: azdata.nb.INotebookContents): Promise<URI> {
|
||||
let options: INotebookShowOptions = {};
|
||||
if (contents) {
|
||||
options.providerId = providerId;
|
||||
options.initialContent = JSON.stringify(contents);
|
||||
}
|
||||
let uriComps = await this._proxy.$tryCreateNotebookDocument(options);
|
||||
let uriComps = await this._proxy.$tryCreateNotebookDocument(providerId, contents);
|
||||
let uri = URI.revive(uriComps);
|
||||
let notebookCells = contents?.cells?.map<azdata.nb.NotebookCell>(cellContents => {
|
||||
return {
|
||||
|
||||
@@ -1012,7 +1012,7 @@ export interface ExtHostNotebookDocumentsAndEditorsShape {
|
||||
export interface MainThreadNotebookDocumentsAndEditorsShape extends IDisposable {
|
||||
$trySetTrusted(_uri: UriComponents, isTrusted: boolean): Thenable<boolean>;
|
||||
$trySaveDocument(uri: UriComponents): Thenable<boolean>;
|
||||
$tryCreateNotebookDocument(options: INotebookShowOptions): Promise<UriComponents>;
|
||||
$tryCreateNotebookDocument(providerId: string, contents?: azdata.nb.INotebookContents): Promise<UriComponents>;
|
||||
$tryShowNotebookDocument(resource: UriComponents, options: INotebookShowOptions): Promise<string>;
|
||||
$tryApplyEdits(id: string, modelVersionId: number, edits: INotebookEditOperation[], opts: IUndoStopOptions): Promise<boolean>;
|
||||
$runCell(id: string, cellUri: UriComponents): Promise<boolean>;
|
||||
|
||||
@@ -36,6 +36,9 @@ export const FILE_QUERY_EDITOR_TYPEID = 'workbench.editorInput.fileQueryInput';
|
||||
export const RESOURCE_VIEWER_TYPEID = 'workbench.editorInput.resourceViewerInput';
|
||||
|
||||
export const JUPYTER_PROVIDER_ID = 'jupyter';
|
||||
export const INTERACTIVE_PROVIDER_ID = 'dotnet-interactive';
|
||||
export const INTERACTIVE_LANGUAGE_MODE = 'dib';
|
||||
export const DEFAULT_NB_LANGUAGE_MODE = 'notebook';
|
||||
export const TSGOPS_WEB_QUALITY = 'tsgops-image';
|
||||
|
||||
// The version of the notebook file format that we support
|
||||
|
||||
@@ -447,7 +447,11 @@ export abstract class NotebookInput extends EditorInput implements INotebookInpu
|
||||
|
||||
private async assignProviders(): Promise<void> {
|
||||
await this.extensionService.whenInstalledExtensionsRegistered();
|
||||
let providerIds: string[] = getProvidersForFileName(this._title, this.notebookService);
|
||||
let mode: string;
|
||||
if (this._textInput instanceof UntitledTextEditorInput) {
|
||||
mode = this._textInput.model.getMode();
|
||||
}
|
||||
let providerIds: string[] = getProvidersForFileName(this._title, this.notebookService, mode);
|
||||
if (providerIds && providerIds.length > 0) {
|
||||
this._providerId = providerIds.filter(provider => provider !== DEFAULT_NOTEBOOK_PROVIDER)[0];
|
||||
this._providers = providerIds;
|
||||
|
||||
@@ -27,7 +27,7 @@ export class UntitledNotebookInput extends NotebookInput {
|
||||
) {
|
||||
super(title, resource, textInput, true, textModelService, instantiationService, notebookService, extensionService);
|
||||
// Set the mode explicitly so that the auto language detection doesn't run and mark the model as being JSON
|
||||
this.textInput.resolve().then(() => this.setMode('notebook'));
|
||||
this.textInput.resolve().then(() => this.setMode(textInput.model.getMode()));
|
||||
}
|
||||
|
||||
public override get textInput(): UntitledTextEditorInput {
|
||||
|
||||
@@ -238,7 +238,7 @@ export class NotebookServiceStub implements INotebookService {
|
||||
getSupportedLanguagesForProvider(provider: string, kernelDisplayName?: string): Promise<string[]> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput> {
|
||||
createNotebookInputFromContents(providerId: string, contents?: nb.INotebookContents, resource?: UriComponents): Promise<IEditorInput> {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
_serviceBrand: undefined;
|
||||
|
||||
@@ -7,6 +7,7 @@ import * as path from 'vs/base/common/path';
|
||||
import { nb, ServerInfo } from 'azdata';
|
||||
import { DEFAULT_NOTEBOOK_PROVIDER, DEFAULT_NOTEBOOK_FILETYPE, INotebookService, SQL_NOTEBOOK_PROVIDER } from 'sql/workbench/services/notebook/browser/notebookService';
|
||||
import { URI } from 'vs/base/common/uri';
|
||||
import { DEFAULT_NB_LANGUAGE_MODE } from 'sql/workbench/common/constants';
|
||||
|
||||
export const clusterEndpointsProperty = 'clusterEndpoints';
|
||||
export const hadoopEndpointNameGateway = 'gateway';
|
||||
@@ -17,8 +18,11 @@ export function isStream(output: nb.ICellOutput): output is nb.IStreamResult {
|
||||
return output.output_type === 'stream';
|
||||
}
|
||||
|
||||
export function getProvidersForFileName(fileName: string, notebookService: INotebookService): string[] {
|
||||
export function getProvidersForFileName(fileName: string, notebookService: INotebookService, languageMode?: string): string[] {
|
||||
let fileExt = path.extname(fileName);
|
||||
if (!fileExt && languageMode && languageMode !== DEFAULT_NB_LANGUAGE_MODE) {
|
||||
fileExt = `.${languageMode}`;
|
||||
}
|
||||
let providers: string[];
|
||||
// First try to get provider for actual file type
|
||||
if (fileExt) {
|
||||
|
||||
@@ -139,7 +139,7 @@ export interface INotebookService {
|
||||
*/
|
||||
notifyCellExecutionStarted(): void;
|
||||
|
||||
createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput | undefined>;
|
||||
createNotebookInputFromContents(providerId: string, contents?: azdata.nb.INotebookContents, resource?: UriComponents): Promise<IEditorInput | undefined>;
|
||||
|
||||
openNotebook(resource: UriComponents, options: INotebookShowOptions): Promise<IEditorPane | undefined>;
|
||||
|
||||
|
||||
@@ -50,7 +50,7 @@ import { IEditorGroupsService } from 'vs/workbench/services/editor/common/editor
|
||||
import { IEditorInput, IEditorPane } from 'vs/workbench/common/editor';
|
||||
import { isINotebookInput } from 'sql/workbench/services/notebook/browser/interface';
|
||||
import { INotebookShowOptions } from 'sql/workbench/api/common/sqlExtHost.protocol';
|
||||
import { JUPYTER_PROVIDER_ID, NotebookLanguage } from 'sql/workbench/common/constants';
|
||||
import { DEFAULT_NB_LANGUAGE_MODE, INTERACTIVE_LANGUAGE_MODE, INTERACTIVE_PROVIDER_ID, JUPYTER_PROVIDER_ID, NotebookLanguage } from 'sql/workbench/common/constants';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { SqlSerializationProvider } from 'sql/workbench/services/notebook/browser/sql/sqlSerializationProvider';
|
||||
|
||||
@@ -248,30 +248,60 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
lifecycleService.onWillShutdown(() => this.shutdown());
|
||||
}
|
||||
|
||||
public async createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput | undefined> {
|
||||
private getUntitledFileUri(): URI {
|
||||
// Need to create a new untitled URI, so find the lowest numbered one that's available
|
||||
let uri: URI;
|
||||
let counter = 1;
|
||||
do {
|
||||
uri = URI.from({ scheme: Schemas.untitled, path: `Notebook-${counter}` });
|
||||
counter++;
|
||||
} while (this._untitledEditorService.get(uri));
|
||||
return uri;
|
||||
}
|
||||
|
||||
public async createNotebookInputFromContents(providerId: string, contents?: nb.INotebookContents, resource?: UriComponents): Promise<IEditorInput> {
|
||||
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));
|
||||
uri = this.getUntitledFileUri();
|
||||
resource = uri;
|
||||
}
|
||||
|
||||
let serializedContent: string;
|
||||
if (contents) {
|
||||
// Have to serialize contents again first, since our notebook code assumes input is based on the raw file contents
|
||||
let manager = await this.getOrCreateSerializationManager(providerId, uri);
|
||||
serializedContent = await manager.contentManager.serializeNotebook(contents);
|
||||
}
|
||||
|
||||
let options: INotebookShowOptions = {
|
||||
providerId: providerId,
|
||||
initialContent: serializedContent
|
||||
};
|
||||
return this.createNotebookInput(options, resource);
|
||||
}
|
||||
|
||||
private async createNotebookInput(options: INotebookShowOptions, resource?: UriComponents): Promise<IEditorInput | undefined> {
|
||||
let uri: URI;
|
||||
if (resource) {
|
||||
uri = URI.revive(resource);
|
||||
} else {
|
||||
uri = this.getUntitledFileUri();
|
||||
}
|
||||
let isUntitled: boolean = uri.scheme === Schemas.untitled;
|
||||
|
||||
let fileInput: IEditorInput;
|
||||
let languageMode = options.providerId === INTERACTIVE_PROVIDER_ID ? INTERACTIVE_LANGUAGE_MODE : DEFAULT_NB_LANGUAGE_MODE;
|
||||
if (isUntitled && path.isAbsolute(uri.fsPath)) {
|
||||
const model = this._untitledEditorService.create({ associatedResource: uri, mode: 'notebook', initialValue: options.initialContent });
|
||||
const model = this._untitledEditorService.create({ associatedResource: uri, mode: languageMode, initialValue: options.initialContent });
|
||||
fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||
} else {
|
||||
if (isUntitled) {
|
||||
const model = this._untitledEditorService.create({ untitledResource: uri, mode: 'notebook', initialValue: options.initialContent });
|
||||
const model = this._untitledEditorService.create({ untitledResource: uri, mode: languageMode, initialValue: options.initialContent });
|
||||
fileInput = this._instantiationService.createInstance(UntitledTextEditorInput, model);
|
||||
} else {
|
||||
fileInput = this._editorService.createEditorInput({ forceFile: true, resource: uri, mode: 'notebook' });
|
||||
fileInput = this._editorService.createEditorInput({ forceFile: true, resource: uri, mode: languageMode });
|
||||
}
|
||||
}
|
||||
|
||||
@@ -478,8 +508,9 @@ export class NotebookService extends Disposable implements INotebookService {
|
||||
}
|
||||
|
||||
getProvidersForFileType(fileType: string): string[] | undefined {
|
||||
let providers = this._fileToProviderDescriptions.get(fileType.toLowerCase());
|
||||
return providers?.map(provider => provider.provider);
|
||||
let provDescriptions = this._fileToProviderDescriptions.get(fileType.toLowerCase());
|
||||
let providers = provDescriptions?.map(provider => provider.provider);
|
||||
return [...new Set(providers)]; // Remove duplicates
|
||||
}
|
||||
|
||||
public async getStandardKernelsForProvider(provider: string): Promise<nb.IStandardKernel[] | undefined> {
|
||||
|
||||
Reference in New Issue
Block a user