提交 ebb2e250 编写于 作者: J Johannes Rieken

add CellContentProvider, more injection

上级 6395ca17
...@@ -14,9 +14,15 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchCo ...@@ -14,9 +14,15 @@ import { Extensions as WorkbenchExtensions, IWorkbenchContribution, IWorkbenchCo
import { IEditorInput } from 'vs/workbench/common/editor'; import { IEditorInput } from 'vs/workbench/common/editor';
import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor'; import { NotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookEditor';
import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput'; import { NotebookEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookService, NotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { INotebookService, NotebookService, parseCellUri } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService'; import { IEditorService, IOpenEditorOverride } from 'vs/workbench/services/editor/common/editorService';
import { ITextModelContentProvider, ITextModelService } from 'vs/editor/common/services/resolverService';
import { ITextModel } from 'vs/editor/common/model';
import { URI } from 'vs/base/common/uri';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IDisposable } from 'vs/base/common/lifecycle';
// Output renderers registration // Output renderers registration
...@@ -25,7 +31,6 @@ import 'vs/workbench/contrib/notebook/browser/output/transforms/errorTransform'; ...@@ -25,7 +31,6 @@ import 'vs/workbench/contrib/notebook/browser/output/transforms/errorTransform';
import 'vs/workbench/contrib/notebook/browser/output/transforms/richTransform'; import 'vs/workbench/contrib/notebook/browser/output/transforms/richTransform';
// Actions // Actions
import 'vs/workbench/contrib/notebook/browser/notebookActions'; import 'vs/workbench/contrib/notebook/browser/notebookActions';
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor( Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
...@@ -89,7 +94,48 @@ export class NotebookContribution implements IWorkbenchContribution { ...@@ -89,7 +94,48 @@ export class NotebookContribution implements IWorkbenchContribution {
} }
} }
class CellContentProvider implements ITextModelContentProvider {
private readonly _registration: IDisposable;
constructor(
@ITextModelService textModelService: ITextModelService,
@IModelService private readonly _modelService: IModelService,
@IModeService private readonly _modeService: IModeService,
@INotebookService private readonly _notebookService: INotebookService,
) {
this._registration = textModelService.registerTextModelContentProvider('vscode-notebook', this);
}
dispose(): void {
this._registration.dispose();
}
async provideTextContent(resource: URI): Promise<ITextModel | null> {
const data = parseCellUri(resource);
if (!data) {
return null;
}
const notebook = await this._notebookService.resolveNotebook(data.viewType, data.notebook);
if (!notebook) {
return null;
}
for (let cell of notebook.cells) {
if (cell.handle === data.cellHandle) {
return this._modelService.createModel(
cell.source.join('\n'),
this._modeService.createByFilepathOrFirstLine(resource, cell.source[0]),
resource
);
}
}
return null;
}
}
const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench); const workbenchContributionsRegistry = Registry.as<IWorkbenchContributionsRegistry>(WorkbenchExtensions.Workbench);
workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting); workbenchContributionsRegistry.registerWorkbenchContribution(NotebookContribution, LifecyclePhase.Starting);
workbenchContributionsRegistry.registerWorkbenchContribution(CellContentProvider, LifecyclePhase.Starting);
registerSingleton(INotebookService, NotebookService); registerSingleton(INotebookService, NotebookService);
...@@ -11,14 +11,11 @@ import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle'; ...@@ -11,14 +11,11 @@ import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
import 'vs/css!./notebook'; import 'vs/css!./notebook';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions'; import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo'; import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { IModelService } from 'vs/editor/common/services/modelService';
import { IModeService } from 'vs/editor/common/services/modeService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration'; import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey'; import { IContextKey, IContextKeyService, RawContextKey } from 'vs/platform/contextkey/common/contextkey';
import { IEnvironmentService } from 'vs/platform/environment/common/environment'; import { IEnvironmentService } from 'vs/platform/environment/common/environment';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation'; import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { WorkbenchList } from 'vs/platform/list/browser/listService'; import { WorkbenchList } from 'vs/platform/list/browser/listService';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { IStorageService } from 'vs/platform/storage/common/storage'; import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry'; import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { contrastBorder, editorBackground, focusBorder, foreground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry'; import { contrastBorder, editorBackground, focusBorder, foreground, textBlockQuoteBackground, textBlockQuoteBorder, textLinkActiveForeground, textLinkForeground, textPreformatForeground } from 'vs/platform/theme/common/colorRegistry';
...@@ -27,7 +24,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor'; ...@@ -27,7 +24,7 @@ import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorOptions, IEditorMemento } from 'vs/workbench/common/editor'; import { EditorOptions, IEditorMemento } from 'vs/workbench/common/editor';
import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser'; import { INotebookEditor } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput'; import { NotebookEditorInput, NotebookEditorModel } from 'vs/workbench/contrib/notebook/browser/notebookEditorInput';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService'; import { INotebookService, createCellUri } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/output/outputRenderer'; import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/output/outputRenderer';
import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/renderers/backLayerWebView'; import { BackLayerWebView } from 'vs/workbench/contrib/notebook/browser/renderers/backLayerWebView';
import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/renderers/cellRenderer'; import { CodeCellRenderer, MarkdownCellRenderer, NotebookCellListDelegate } from 'vs/workbench/contrib/notebook/browser/renderers/cellRenderer';
...@@ -36,6 +33,7 @@ import { CELL_MARGIN, INotebook } from 'vs/workbench/contrib/notebook/common/not ...@@ -36,6 +33,7 @@ import { CELL_MARGIN, INotebook } from 'vs/workbench/contrib/notebook/common/not
import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview'; import { IWebviewService } from 'vs/workbench/contrib/webview/browser/webview';
import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils'; import { getExtraColor } from 'vs/workbench/contrib/welcome/walkThrough/common/walkThroughUtils';
import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService'; import { IEditorGroup, IEditorGroupsService } from 'vs/workbench/services/editor/common/editorGroupsService';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
const $ = DOM.$; const $ = DOM.$;
const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState'; const NOTEBOOK_EDITOR_VIEW_STATE_PREFERENCE_KEY = 'NotebookEditorViewState';
...@@ -70,8 +68,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -70,8 +68,6 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
@ITelemetryService telemetryService: ITelemetryService, @ITelemetryService telemetryService: ITelemetryService,
@IThemeService themeService: IThemeService, @IThemeService themeService: IThemeService,
@IInstantiationService private readonly instantiationService: IInstantiationService, @IInstantiationService private readonly instantiationService: IInstantiationService,
@IModelService private readonly modelService: IModelService,
@IModeService private readonly modeService: IModeService,
@IStorageService storageService: IStorageService, @IStorageService storageService: IStorageService,
@IWebviewService private webviewService: IWebviewService, @IWebviewService private webviewService: IWebviewService,
@INotebookService private notebookService: INotebookService, @INotebookService private notebookService: INotebookService,
...@@ -79,7 +75,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -79,7 +75,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
@IConfigurationService private readonly configurationService: IConfigurationService, @IConfigurationService private readonly configurationService: IConfigurationService,
@IEnvironmentService private readonly environmentSerice: IEnvironmentService, @IEnvironmentService private readonly environmentSerice: IEnvironmentService,
@IContextKeyService private readonly contextKeyService: IContextKeyService, @IContextKeyService private readonly contextKeyService: IContextKeyService,
@IOpenerService private readonly openerService: IOpenerService @ITextModelService private readonly textModelService: ITextModelService,
) { ) {
super(NotebookEditor.ID, telemetryService, themeService, storageService); super(NotebookEditor.ID, telemetryService, themeService, storageService);
...@@ -222,7 +218,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -222,7 +218,7 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
.then(() => { .then(() => {
return input.resolve(); return input.resolve();
}) })
.then(model => { .then(async model => {
if (this.model !== undefined && this.model.textModel === model.textModel && this.webview !== null) { if (this.model !== undefined && this.model.textModel === model.textModel && this.webview !== null) {
return; return;
} }
...@@ -249,10 +245,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -249,10 +245,12 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
this.notebook = model.getNotebook(); this.notebook = model.getNotebook();
this.webview.updateRendererPreloads(this.notebook.renderers); this.webview.updateRendererPreloads(this.notebook.renderers);
this.viewType = input.viewType; this.viewType = input.viewType;
this.viewCells = this.notebook!.cells.map(cell => { this.viewCells = await Promise.all(this.notebook!.cells.map(async cell => {
const uri = createCellUri(input.viewType!, this.notebook!, cell);
const ref = await this.textModelService.createModelReference(uri);
const isEditing = viewState && viewState.editingCells[cell.handle]; const isEditing = viewState && viewState.editingCells[cell.handle];
return new CellViewModel(input.viewType!, this.notebook!.handle, cell, !!isEditing, this.modelService, this.modeService, this.openerService, this.notebookService, this.themeService); return this.instantiationService.createInstance(CellViewModel, input.viewType!, this.notebook!.handle, cell, ref.object.textEditorModel, !!isEditing);
}); }));
const updateScrollPosition = () => { const updateScrollPosition = () => {
let scrollTop = this.list?.scrollTop || 0; let scrollTop = this.list?.scrollTop || 0;
...@@ -383,7 +381,9 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor { ...@@ -383,7 +381,9 @@ export class NotebookEditor extends BaseEditor implements INotebookEditor {
const insertIndex = direction === 'above' ? index : index + 1; const insertIndex = direction === 'above' ? index : index + 1;
let newModeCell = await this.notebookService.createNotebookCell(this.viewType!, this.notebook!.uri, insertIndex, language, type); let newModeCell = await this.notebookService.createNotebookCell(this.viewType!, this.notebook!.uri, insertIndex, language, type);
let newCell = new CellViewModel(this.viewType!, this.notebook!.handle, newModeCell!, false, this.modelService, this.modeService, this.openerService, this.notebookService, this.themeService); let uri = createCellUri(this.viewType!, this.notebook!, newModeCell!);
let ref = await this.textModelService.createModelReference(uri);
let newCell = this.instantiationService.createInstance(CellViewModel, this.viewType!, this.notebook!.handle, newModeCell!, ref.object.textEditorModel, false);
this.viewCells!.splice(insertIndex, 0, newCell); this.viewCells!.splice(insertIndex, 0, newCell);
this.model!.insertCell(newCell.cell, insertIndex); this.model!.insertCell(newCell.cell, insertIndex);
......
...@@ -12,6 +12,28 @@ import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.pr ...@@ -12,6 +12,28 @@ import { NotebookExtensionDescription } from 'vs/workbench/api/common/extHost.pr
import { Emitter, Event } from 'vs/base/common/event'; import { Emitter, Event } from 'vs/base/common/event';
import { IMarkdownString } from 'vs/base/common/htmlContent'; import { IMarkdownString } from 'vs/base/common/htmlContent';
import { INotebook, ICell, INotebookMimeTypeSelector } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { INotebook, ICell, INotebookMimeTypeSelector } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { basename, extname } from 'vs/base/common/path';
export function createCellUri(viewType: string, notebook: INotebook, cell: ICell): URI {
//vscode-notebook://<viewType>/cell_<cellHandle>.ext
return URI.from({
scheme: 'vscode-notebook',
authority: viewType,
path: `/cell_${cell.handle}.${cell.cell_type === 'markdown' ? 'md' : 'py'}`,
query: notebook.uri.toString()
});
}
export function parseCellUri(resource: URI): { viewType: string, notebook: URI, cellHandle: number } | undefined {
//vscode-notebook://<viewType>/cell_<cellHandle>.ext
const match = /cell_(\d+)/.exec(basename(resource.path, extname(resource.path)));
if (!match) {
return undefined;
}
const viewType = resource.authority;
const notebook = URI.parse(resource.query);
return { viewType, notebook, cellHandle: parseInt(match[1]) };
}
function MODEL_ID(resource: URI): string { function MODEL_ID(resource: URI): string {
return resource.toString(); return resource.toString();
...@@ -144,25 +166,24 @@ export class NotebookService extends Disposable implements INotebookService { ...@@ -144,25 +166,24 @@ export class NotebookService extends Disposable implements INotebookService {
} }
async resolveNotebook(viewType: string, uri: URI): Promise<INotebook | undefined> { async resolveNotebook(viewType: string, uri: URI): Promise<INotebook | undefined> {
let provider = this._notebookProviders.get(viewType); const provider = this._notebookProviders.get(viewType);
if (!provider) {
return undefined;
}
if (provider) { const notebookModel = await provider.controller.resolveNotebook(viewType, uri);
let notebookModel = await provider.controller.resolveNotebook(viewType, uri); if (!notebookModel) {
return undefined;
if (notebookModel) {
// new notebook model created
const modelId = MODEL_ID(uri);
const modelData = new ModelData(
notebookModel,
(model) => this._onWillDispose(model),
);
this._models[modelId] = modelData;
return modelData.model;
}
} }
return; // new notebook model created
const modelId = MODEL_ID(uri);
const modelData = new ModelData(
notebookModel,
(model) => this._onWillDispose(model),
);
this._models[modelId] = modelData;
return modelData.model;
} }
updateNotebookActiveCell(viewType: string, resource: URI, cellHandle: number): void { updateNotebookActiveCell(viewType: string, resource: URI, cellHandle: number): void {
......
...@@ -3,21 +3,16 @@ ...@@ -3,21 +3,16 @@
* Licensed under the MIT License. See License.txt in the project root for license information. * Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/ *--------------------------------------------------------------------------------------------*/
import { IModelService } from 'vs/editor/common/services/modelService';
import { URI } from 'vs/base/common/uri';
import { Disposable } from 'vs/base/common/lifecycle'; import { Disposable } from 'vs/base/common/lifecycle';
import { ITextModel } from 'vs/editor/common/model'; import { ITextModel } from 'vs/editor/common/model';
import { IModeService } from 'vs/editor/common/services/modeService';
import { Emitter } from 'vs/base/common/event'; import { Emitter } from 'vs/base/common/event';
import * as UUID from 'vs/base/common/uuid'; import * as UUID from 'vs/base/common/uuid';
import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/renderers/mdRenderer'; import { MarkdownRenderer } from 'vs/workbench/contrib/notebook/browser/renderers/mdRenderer';
import { IOpenerService } from 'vs/platform/opener/common/opener';
import { INotebookService } from 'vs/workbench/contrib/notebook/browser/notebookService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon'; import { ICell } from 'vs/workbench/contrib/notebook/common/notebookCommon';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
export class CellViewModel extends Disposable { export class CellViewModel extends Disposable {
private _textModel: ITextModel | null = null;
private _mdRenderer: MarkdownRenderer | null = null; private _mdRenderer: MarkdownRenderer | null = null;
private _html: HTMLElement | null = null; private _html: HTMLElement | null = null;
private _dynamicHeight: number | null = null; private _dynamicHeight: number | null = null;
...@@ -51,24 +46,26 @@ export class CellViewModel extends Disposable { ...@@ -51,24 +46,26 @@ export class CellViewModel extends Disposable {
get dynamicHeight(): number | null { get dynamicHeight(): number | null {
return this._dynamicHeight; return this._dynamicHeight;
} }
id: string;
readonly id: string = UUID.generateUuid();
constructor( constructor(
public viewType: string, readonly viewType: string,
public notebookHandle: number, readonly notebookHandle: number,
public cell: ICell, readonly cell: ICell,
private _textModel: ITextModel,
private _isEditing: boolean, private _isEditing: boolean,
private readonly modelService: IModelService, @IInstantiationService private readonly _instaService: IInstantiationService,
private readonly modeService: IModeService, ) {
private readonly openerService: IOpenerService,
private readonly notebookService: INotebookService,
private readonly themeService: IThemeService) {
super(); super();
this.id = UUID.generateUuid();
this._register(this._textModel.onDidChangeContent(() => {
this.cell.isDirty = true;
}));
if (this.cell.onDidChangeOutputs) { if (this.cell.onDidChangeOutputs) {
this.cell.onDidChangeOutputs(() => { this._register(this.cell.onDidChangeOutputs(() => {
this._onDidChangeOutputs.fire(); this._onDidChangeOutputs.fire();
}); }));
} }
} }
hasDynamicHeight() { hasDynamicHeight() {
...@@ -107,7 +104,7 @@ export class CellViewModel extends Disposable { ...@@ -107,7 +104,7 @@ export class CellViewModel extends Disposable {
this._html = null; this._html = null;
} }
save() { save() {
if (this._textModel && (this.cell.isDirty || this.isEditing)) { if (this.cell.isDirty || this.isEditing) {
let cnt = this._textModel.getLineCount(); let cnt = this._textModel.getLineCount();
this.cell.source = this._textModel.getLinesContent().map((str, index) => str + (index !== cnt - 1 ? '\n' : '')); this.cell.source = this._textModel.getLinesContent().map((str, index) => str + (index !== cnt - 1 ? '\n' : ''));
} }
...@@ -115,6 +112,7 @@ export class CellViewModel extends Disposable { ...@@ -115,6 +112,7 @@ export class CellViewModel extends Disposable {
getText(): string { getText(): string {
return this.cell.source.join('\n'); return this.cell.source.join('\n');
} }
getHTML(): HTMLElement | null { getHTML(): HTMLElement | null {
if (this.cellType === 'markdown') { if (this.cellType === 'markdown') {
if (this._html) { if (this._html) {
...@@ -126,25 +124,14 @@ export class CellViewModel extends Disposable { ...@@ -126,25 +124,14 @@ export class CellViewModel extends Disposable {
} }
return null; return null;
} }
getTextModel(): ITextModel { getTextModel(): ITextModel {
if (!this._textModel) {
let mode = this.modeService.create(this.cellType === 'markdown' ? 'markdown' : this.cell.language);
let ext = this.cellType === 'markdown' ? 'md' : 'py';
let resource = URI.parse(`notebookcell-${Date.now()}.${ext}`);
resource = resource.with({ authority: `notebook+${this.viewType}-${this.notebookHandle}-${this.cell.handle}` });
let content = this.cell.source.join('\n');
this._textModel = this.modelService.createModel(content, mode, resource, false);
this._register(this._textModel);
this._register(this._textModel.onDidChangeContent(() => {
this.cell.isDirty = true;
}));
}
return this._textModel; return this._textModel;
} }
getMarkdownRenderer() { getMarkdownRenderer() {
if (!this._mdRenderer) { if (!this._mdRenderer) {
this._mdRenderer = new MarkdownRenderer(this.viewType, this.modeService, this.openerService, this.notebookService, this.themeService); this._mdRenderer = this._instaService.createInstance(MarkdownRenderer, this.viewType);
} }
return this._mdRenderer; return this._mdRenderer;
} }
......
...@@ -30,10 +30,10 @@ export class MarkdownRenderer extends Disposable { ...@@ -30,10 +30,10 @@ export class MarkdownRenderer extends Disposable {
constructor( constructor(
private readonly viewType: string, private readonly viewType: string,
private readonly _modeService: IModeService, @IModeService private readonly _modeService: IModeService,
private readonly _openerService: IOpenerService, @IOpenerService private readonly _openerService: IOpenerService,
private readonly _notebookService: INotebookService, @INotebookService private readonly _notebookService: INotebookService,
private readonly _themeService: IThemeService @IThemeService private readonly _themeService: IThemeService,
) { ) {
super(); super();
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册