diff --git a/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts b/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts index a406d945ee0..4fbe1ac207f 100644 --- a/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts +++ b/src/vs/workbench/api/browser/mainThreadNotebookDocuments.ts @@ -17,6 +17,7 @@ import { ExtHostContext, ExtHostNotebookShape, IExtHostContext, MainThreadNotebo import { MainThreadNotebooksAndEditors } from 'vs/workbench/api/browser/mainThreadNotebookDocumentsAndEditors'; import { onUnexpectedError } from 'vs/base/common/errors'; import { Schemas } from 'vs/base/common/network'; +import { NotebookProviderInfo } from 'vs/workbench/contrib/notebook/common/notebookProvider'; export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsShape { @@ -121,10 +122,16 @@ export class MainThreadNotebookDocuments implements MainThreadNotebookDocumentsS async $tryCreateNotebook(options: { viewType: string, content?: NotebookDataDto }): Promise { + const info = this._notebookService.getContributedNotebookType(options.viewType); + if (!info) { + throw new Error('UNKNOWN view type: ' + options.viewType); + } + // find a free URI for the untitled case + const suffix = NotebookProviderInfo.possibleFileEnding(info.selectors) ?? ''; let uri: URI; for (let counter = 1; ; counter++) { - let candidate = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}`, query: options.viewType }); + let candidate = URI.from({ scheme: Schemas.untitled, path: `Untitled-${counter}${suffix}`, query: options.viewType }); if (!this._notebookService.getNotebookTextModel(candidate)) { uri = candidate; break; diff --git a/src/vs/workbench/contrib/notebook/common/notebookProvider.ts b/src/vs/workbench/contrib/notebook/common/notebookProvider.ts index 7d94ed56c4a..fbdce0aebbd 100644 --- a/src/vs/workbench/contrib/notebook/common/notebookProvider.ts +++ b/src/vs/workbench/contrib/notebook/common/notebookProvider.ts @@ -104,4 +104,38 @@ export class NotebookProviderInfo { return false; } + + static possibleFileEnding(selectors: NotebookSelector[]): string | undefined { + for (let selector of selectors) { + const ending = NotebookProviderInfo._possibleFileEnding(selector); + if (ending) { + return ending; + } + } + return undefined; + } + + private static _possibleFileEnding(selector: NotebookSelector): string | undefined { + + const pattern = /^.*(\.[a-zA-Z0-9_-]+)$/; + + let candidate: string | undefined; + + if (typeof selector === 'string') { + candidate = selector; + } else if (glob.isRelativePattern(selector)) { + candidate = selector.pattern; + } else if (selector.include) { + return NotebookProviderInfo._possibleFileEnding(selector.include); + } + + if (candidate) { + const match = pattern.exec(candidate); + if (match) { + return match[1]; + } + } + + return undefined; + } }