build text diff editor

This commit is contained in:
rebornix
2020-08-20 16:52:19 -07:00
parent 509bc25f02
commit 88a7d66e28
7 changed files with 904 additions and 14 deletions
@@ -175,6 +175,9 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
private readonly _onDidUpdateDiff: Emitter<void> = this._register(new Emitter<void>());
public readonly onDidUpdateDiff: Event<void> = this._onDidUpdateDiff.event;
private readonly _onDidContentSizeChange: Emitter<editorCommon.IContentSizeChangedEvent> = this._register(new Emitter<editorCommon.IContentSizeChangedEvent>());
public readonly onDidContentSizeChange: Event<editorCommon.IContentSizeChangedEvent> = this._onDidContentSizeChange.event;
private readonly id: number;
private _state: editorBrowser.DiffEditorState;
private _updatingDiffProgress: IProgressRunner | null;
@@ -421,6 +424,10 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
return this._renderIndicators;
}
public getContentHeight(): number {
return this.modifiedEditor.getContentHeight();
}
private _setState(newState: editorBrowser.DiffEditorState): void {
if (this._state === newState) {
return;
@@ -555,6 +562,18 @@ export class DiffEditorWidget extends Disposable implements editorBrowser.IDiffE
}
}));
this._register(editor.onDidContentSizeChange(e => {
const width = this.originalEditor.getContentWidth() + this.modifiedEditor.getContentWidth();
const height = this.modifiedEditor.getContentHeight();
this._onDidContentSizeChange.fire({
contentHeight: height,
contentWidth: width,
contentHeightChanged: e.contentHeightChanged,
contentWidthChanged: e.contentWidthChanged
});
}));
return editor;
}
@@ -3,15 +3,13 @@
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
.notebook-diff-editor {
display: flex;
flex-direction: row;
height: 100%;
width: 100%;
}
.notebook-diff-editor-modified,
.notebook-diff-editor-original {
display: flex;
height: 100%;
width: 50%;
import { NotebookCellTextModel } from 'vs/workbench/contrib/notebook/common/model/notebookCellTextModel';
export class CellDiffViewModel {
constructor(
readonly original: NotebookCellTextModel | undefined,
readonly modified: NotebookCellTextModel | undefined,
readonly type: 'unchanged' | 'insert' | 'delete' | 'modified'
) {
}
}
@@ -0,0 +1,12 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel';
export interface INotebookTextDiffEditor {
getLayoutInfo(): NotebookLayoutInfo;
layoutNotebookCell(cell: CellDiffViewModel, height: number): void;
}
@@ -0,0 +1,73 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
/* .notebook-diff-editor {
display: flex;
flex-direction: row;
height: 100%;
width: 100%;
}
.notebook-diff-editor-modified,
.notebook-diff-editor-original {
display: flex;
height: 100%;
width: 50%;
} */
.notebook-text-diff-editor .cell-diff-editor-container {
margin: 8px;
}
.notebook-text-diff-editor .cell-diff-editor-container .metadata-container {
display: flex;
height: 24px;
align-items: center;
cursor: default;
}
.notebook-text-diff-editor .cell-diff-editor-container .metadata-container .metadata-folding-indicator .codicon {
visibility: visible;
padding: 4px 0 0 10px;
cursor: pointer;
}
.notebook-text-diff-editor .cell-diff-editor-container .metadata-container .metadata-status {
font-size: 12px;
}
.notebook-text-diff-editor .cell-diff-editor-container .metadata-container .metadata-status span {
margin: 0 8px;
line-height: 21px;
}
.notebook-text-diff-editor .cell-diff-editor-container.delete .editor-container {
display: inline-block;
width: calc(50% - 18px);
}
.notebook-text-diff-editor .cell-diff-editor-container.delete .diagonal-fill {
display: inline-block;
width: calc(50% + 18px);
}
.notebook-text-diff-editor .cell-diff-editor-container.insert .editor-container {
display: inline-block;
width: calc(50% + 18px);
}
.notebook-text-diff-editor .cell-diff-editor-container.insert .diagonal-fill {
display: inline-block;
width: calc(50% - 18px);
}
.notebook-text-diff-editor {
overflow: hidden;
}
.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row,
.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover,
.monaco-workbench .notebook-text-diff-editor > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused {
outline: none !important;
}
@@ -0,0 +1,267 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import * as nls from 'vs/nls';
import * as DOM from 'vs/base/browser/dom';
import { IStorageService } from 'vs/platform/storage/common/storage';
import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
import { IThemeService, registerThemingParticipant } from 'vs/platform/theme/common/themeService';
import { BaseEditor } from 'vs/workbench/browser/parts/editor/baseEditor';
import { EditorOptions } from 'vs/workbench/common/editor';
import { notebookCellBorder, NotebookEditorWidget, notebookOutputContainerColor } from 'vs/workbench/contrib/notebook/browser/notebookEditorWidget';
import { IEditorGroup } from 'vs/workbench/services/editor/common/editorGroupsService';
import { NotebookDiffEditorInput } from '../notebookDiffEditorInput';
import { CancellationToken } from 'vs/base/common/cancellation';
import { WorkbenchList } from 'vs/platform/list/browser/listService';
import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { CellDiffRenderer, NotebookCellTextDiffListDelegate, NotebookTextDiffList } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffList';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { diffDiagonalFill, editorBackground, focusBorder, foreground } from 'vs/platform/theme/common/colorRegistry';
import { INotebookEditorWorkerService } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerService';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { getZoomLevel } from 'vs/base/browser/browser';
import { NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common';
export class NotebookTextDiffEditor extends BaseEditor implements INotebookTextDiffEditor {
static readonly ID: string = 'workbench.editor.notebookTextDiffEditor';
private _rootElement!: HTMLElement;
private _dimension: DOM.Dimension | null = null;
private _list!: WorkbenchList<CellDiffViewModel>;
private _fontInfo: BareFontInfo | undefined;
constructor(
@IInstantiationService readonly instantiationService: IInstantiationService,
@IThemeService readonly themeService: IThemeService,
@IContextKeyService readonly contextKeyService: IContextKeyService,
@INotebookEditorWorkerService readonly notebookEditorWorkerService: INotebookEditorWorkerService,
@IConfigurationService private readonly configurationService: IConfigurationService,
@ITelemetryService telemetryService: ITelemetryService,
@IStorageService storageService: IStorageService,
) {
super(NotebookTextDiffEditor.ID, telemetryService, themeService, storageService);
const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
this._fontInfo = BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel());
}
protected createEditor(parent: HTMLElement): void {
this._rootElement = DOM.append(parent, DOM.$('.notebook-text-diff-editor'));
const renderer = this.instantiationService.createInstance(CellDiffRenderer, this);
this._list = this.instantiationService.createInstance(
NotebookTextDiffList,
'NotebookTextDiff',
this._rootElement,
this.instantiationService.createInstance(NotebookCellTextDiffListDelegate),
[
renderer
],
this.contextKeyService,
{
setRowLineHeight: false,
setRowHeight: false,
supportDynamicHeights: true,
horizontalScrolling: false,
keyboardSupport: false,
mouseSupport: true,
multipleSelectionSupport: false,
enableKeyboardNavigation: true,
additionalScrollHeight: 0,
// transformOptimization: (isMacintosh && isNative) || getTitleBarStyle(this.configurationService, this.environmentService) === 'native',
styleController: (_suffix: string) => { return this._list!; },
overrideStyles: {
listBackground: editorBackground,
listActiveSelectionBackground: editorBackground,
listActiveSelectionForeground: foreground,
listFocusAndSelectionBackground: editorBackground,
listFocusAndSelectionForeground: foreground,
listFocusBackground: editorBackground,
listFocusForeground: foreground,
listHoverForeground: foreground,
listHoverBackground: editorBackground,
listHoverOutline: focusBorder,
listFocusOutline: focusBorder,
listInactiveSelectionBackground: editorBackground,
listInactiveSelectionForeground: foreground,
listInactiveFocusBackground: editorBackground,
listInactiveFocusOutline: editorBackground,
},
accessibilityProvider: {
getAriaLabel() { return null; },
getWidgetAriaLabel() {
return nls.localize('notebookTreeAriaLabel', "Notebook Text Diff");
}
},
// focusNextPreviousDelegate: {
// onFocusNext: (applyFocusNext: () => void) => this._updateForCursorNavigationMode(applyFocusNext),
// onFocusPrevious: (applyFocusPrevious: () => void) => this._updateForCursorNavigationMode(applyFocusPrevious),
// }
}
);
}
async setInput(input: NotebookDiffEditorInput, options: EditorOptions | undefined, token: CancellationToken): Promise<void> {
// const group = this.group!;
await super.setInput(input, options, token);
const model = await input.resolve();
if (model === null) {
return;
}
const diffResult = await this.notebookEditorWorkerService.computeDiff(model.original.resource, model.modified.resource);
const cellChanges = diffResult.cellsDiff.changes;
const cellDiffViewModels: CellDiffViewModel[] = [];
const originalModel = model.original.notebook;
const modifiedModel = model.modified.notebook;
let originalCellIndex = 0;
let modifiedCellIndex = 0;
for (let i = 0; i < cellChanges.length; i++) {
const change = cellChanges[i];
// common cells
cellDiffViewModels.push(...originalModel.cells.slice(originalCellIndex, change.originalStart).map(cell => {
return new CellDiffViewModel(
cell,
undefined,
'unchanged'
);
}));
// modified cells
const modifiedLen = Math.min(change.originalLength, change.modifiedLength);
for (let j = 0; j < modifiedLen; j++) {
cellDiffViewModels.push(new CellDiffViewModel(
originalModel.cells[change.originalStart + j],
modifiedModel.cells[change.modifiedStart + j],
'modified'
));
}
for (let j = modifiedLen; j < change.originalLength; j++) {
// deletion
cellDiffViewModels.push(new CellDiffViewModel(
originalModel.cells[change.originalStart + j],
undefined,
'delete'
));
}
for (let j = modifiedLen; j < change.modifiedLength; j++) {
// insertion
cellDiffViewModels.push(new CellDiffViewModel(
undefined,
modifiedModel.cells[change.modifiedStart + j],
'insert'
));
}
originalCellIndex = change.originalStart + change.originalLength;
modifiedCellIndex = change.modifiedStart + change.modifiedLength;
}
for (let i = originalCellIndex; i < originalModel.cells.length; i++) {
cellDiffViewModels.push(new CellDiffViewModel(
originalModel.cells[i],
undefined,
'delete'
));
}
for (let i = modifiedCellIndex; i < modifiedModel.cells.length; i++) {
cellDiffViewModels.push(new CellDiffViewModel(
undefined,
modifiedModel.cells[i],
'insert'
));
}
this._list.splice(0, this._list.length, cellDiffViewModels);
}
layoutNotebookCell(cell: CellDiffViewModel, height: number) {
const index = this._list!.indexOf(cell);
if (index >= 0) {
this._list!.updateElementHeight(index, height);
}
}
getDomNode() {
return this._rootElement;
}
getControl(): NotebookEditorWidget | undefined {
return undefined;
}
setEditorVisible(visible: boolean, group: IEditorGroup | undefined): void {
super.setEditorVisible(visible, group);
}
focus() {
super.focus();
}
clearInput(): void {
super.clearInput();
}
getLayoutInfo(): NotebookLayoutInfo {
if (!this._list) {
throw new Error('Editor is not initalized successfully');
}
return {
width: this._dimension!.width,
height: this._dimension!.height,
fontInfo: this._fontInfo!
};
}
layout(dimension: DOM.Dimension): void {
this._rootElement.classList.toggle('mid-width', dimension.width < 1000 && dimension.width >= 600);
this._rootElement.classList.toggle('narrow-width', dimension.width < 600);
this._dimension = dimension;
this._list?.layout(this._dimension.height, this._dimension.width);
}
}
registerThemingParticipant((theme, collector) => {
const cellBorderColor = theme.getColor(notebookCellBorder);
if (cellBorderColor) {
collector.addRule(`.notebook-text-diff-editor .editor-container { border: 1px solid ${cellBorderColor};}`);
}
const diffDiagonalFillColor = theme.getColor(diffDiagonalFill);
collector.addRule(`
.notebook-text-diff-editor .diagonal-fill {
background-image: linear-gradient(
-45deg,
${diffDiagonalFillColor} 12.5%,
#0000 12.5%, #0000 50%,
${diffDiagonalFillColor} 50%, ${diffDiagonalFillColor} 62.5%,
#0000 62.5%, #0000 100%
);
background-size: 8px 8px;
}
`);
const containerBackground = theme.getColor(notebookOutputContainerColor);
if (containerBackground) {
collector.addRule(`.notebook-text-diff-editor .cell-diff-editor-container .metadata-container { background-color: ${containerBackground}; }`);
}
});
@@ -0,0 +1,521 @@
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import 'vs/css!./media/notebookDiff';
import { getZoomLevel } from 'vs/base/browser/browser';
import { IListRenderer, IListVirtualDelegate } from 'vs/base/browser/ui/list/list';
import * as DOM from 'vs/base/browser/dom';
import { IListStyles, IStyleController } from 'vs/base/browser/ui/list/listWidget';
import { Disposable, IDisposable } from 'vs/base/common/lifecycle';
import { IEditorOptions } from 'vs/editor/common/config/editorOptions';
import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
import { IListService, IWorkbenchListOptions, WorkbenchList } from 'vs/platform/list/browser/listService';
import { IThemeService } from 'vs/platform/theme/common/themeService';
import { CellDiffViewModel } from 'vs/workbench/contrib/notebook/browser/diff/celllDiffViewModel';
import { INotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/common';
import { EDITOR_BOTTOM_PADDING, EDITOR_TOP_PADDING } from 'vs/workbench/contrib/notebook/browser/constants';
import { CodeEditorWidget } from 'vs/editor/browser/widget/codeEditorWidget';
import { DiffEditorWidget } from 'vs/editor/browser/widget/diffEditorWidget';
import { isMacintosh } from 'vs/base/common/platform';
import { renderCodicons } from 'vs/base/common/codicons';
export interface CellDiffRenderTemplate {
readonly container: HTMLElement;
}
const fixedDiffEditorOptions: IEditorOptions = {
padding: {
top: 12,
bottom: 12
},
scrollBeyondLastLine: false,
scrollbar: {
verticalScrollbarSize: 14,
horizontal: 'auto',
useShadows: true,
verticalHasArrows: false,
horizontalHasArrows: false,
alwaysConsumeMouseWheel: false
},
renderLineHighlightOnlyWhenFocus: true,
overviewRulerLanes: 0,
selectOnLineNumbers: false,
wordWrap: 'off',
lineNumbers: 'off',
lineDecorationsWidth: 0,
glyphMargin: true,
fixedOverflowWidgets: true,
minimap: { enabled: false },
renderValidationDecorations: 'on'
};
const fixedEditorOptions: IEditorOptions = {
padding: {
top: 12,
bottom: 12
},
scrollBeyondLastLine: false,
scrollbar: {
verticalScrollbarSize: 14,
horizontal: 'auto',
useShadows: true,
verticalHasArrows: false,
horizontalHasArrows: false,
alwaysConsumeMouseWheel: false
},
renderLineHighlightOnlyWhenFocus: true,
overviewRulerLanes: 0,
selectOnLineNumbers: false,
wordWrap: 'off',
lineNumbers: 'off',
lineDecorationsWidth: 0,
glyphMargin: false,
fixedOverflowWidgets: true,
minimap: { enabled: false },
renderValidationDecorations: 'on'
};
export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate<CellDiffViewModel> {
private readonly lineHeight: number;
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService
) {
const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
this.lineHeight = BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel()).lineHeight;
}
getHeight(element: CellDiffViewModel): number {
return 100;
}
hasDynamicHeight(element: CellDiffViewModel): boolean {
return false;
}
getTemplateId(element: CellDiffViewModel): string {
return CellDiffRenderer.TEMPLATE_ID;
}
}
export class CellDiffRenderer implements IListRenderer<CellDiffViewModel, CellDiffRenderTemplate> {
static readonly TEMPLATE_ID = 'cell_diff';
constructor(
readonly notebookEditor: INotebookTextDiffEditor,
@IInstantiationService protected readonly instantiationService: IInstantiationService
) { }
get templateId() {
return CellDiffRenderer.TEMPLATE_ID;
}
renderTemplate(container: HTMLElement): CellDiffRenderTemplate {
return {
container
};
}
renderElement(element: CellDiffViewModel, index: number, templateData: CellDiffRenderTemplate, height: number | undefined): void {
templateData.container.innerText = '';
switch (element.type) {
case 'unchanged':
this.instantiationService.createInstance(UnchangedCell, this.notebookEditor, element, templateData);
return;
case 'delete':
this.instantiationService.createInstance(DeletedCell, this.notebookEditor, element, templateData);
return;
case 'insert':
this.instantiationService.createInstance(InsertCell, this.notebookEditor, element, templateData);
return;
case 'modified':
this.instantiationService.createInstance(ModifiedCell, this.notebookEditor, element, templateData);
return;
default:
break;
}
}
disposeTemplate(templateData: CellDiffRenderTemplate): void {
templateData.container.innerText = '';
}
}
class UnchangedCell extends Disposable {
private _editor!: CodeEditorWidget;
constructor(
readonly notebookEditor: INotebookTextDiffEditor,
readonly cell: CellDiffViewModel,
readonly templateData: CellDiffRenderTemplate,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
) {
super();
const diffEditorContainer = DOM.$('.cell-diff-editor-container');
DOM.append(templateData.container, diffEditorContainer);
const originalCell = cell.original!;
const lineCount = originalCell.textBuffer.getLineCount();
const lineHeight = notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17;
const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING;
const editorContainer = DOM.append(diffEditorContainer, DOM.$('.editor-container'));
const metadataContainer = DOM.append(diffEditorContainer, DOM.$('.metadata-container'));
this.buildMetadata(metadataContainer);
this._editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, {
...fixedEditorOptions,
dimension: {
width: notebookEditor.getLayoutInfo().width - 20,
height: editorHeight
}
}, {});
this._register(this._editor.onDidContentSizeChange((e) => {
if (e.contentHeightChanged) {
this._editor.layout({
width: notebookEditor.getLayoutInfo().width - 20,
height: e.contentHeight
});
this.notebookEditor.layoutNotebookCell(this.cell, e.contentHeight + 32 + 24);
}
}));
originalCell.resolveTextModelRef().then(ref => {
this._register(ref);
const textModel = ref.object.textEditorModel;
this._editor.setModel(textModel);
this._editor.layout({
width: notebookEditor.getLayoutInfo().width - 20,
height: this._editor.getContentHeight()
});
this.notebookEditor.layoutNotebookCell(this.cell, this._editor.getContentHeight() + 32 + 24);
});
}
buildMetadata(metadataContainer: HTMLElement) {
const foldingIndicator = DOM.append(metadataContainer, DOM.$('.metadata-folding-indicator'));
foldingIndicator.innerHTML = renderCodicons('$(chevron-right)');
const metadataStatus = DOM.append(metadataContainer, DOM.$('div.metadata-status'));
const metadataStatusSpan = DOM.append(metadataStatus, DOM.$('span'));
metadataStatusSpan.textContent = 'Metadata unchanged';
}
}
class DeletedCell extends Disposable {
private _editor!: CodeEditorWidget;
constructor(
readonly notebookEditor: INotebookTextDiffEditor,
readonly cell: CellDiffViewModel,
readonly templateData: CellDiffRenderTemplate,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
) {
super();
const diffEditorContainer = DOM.$('.cell-diff-editor-container');
DOM.append(templateData.container, diffEditorContainer);
DOM.addClass(diffEditorContainer, 'delete');
const originalCell = cell.original!;
const lineCount = originalCell.textBuffer.getLineCount();
const lineHeight = notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17;
const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING;
const editorContainer = DOM.append(diffEditorContainer, DOM.$('.editor-container'));
const diagonalFill = DOM.append(diffEditorContainer, DOM.$('.diagonal-fill'));
this._editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, {
...fixedEditorOptions,
dimension: {
width: (notebookEditor.getLayoutInfo().width - 20) / 2 - 18,
height: editorHeight
}
}, {});
diagonalFill.style.height = `${editorHeight}px`;
this._register(this._editor.onDidContentSizeChange((e) => {
if (e.contentHeightChanged) {
this._editor.layout({
width: (notebookEditor.getLayoutInfo().width - 20) / 2 - 18,
height: e.contentHeight
});
diagonalFill.style.height = `${e.contentHeight}px`;
this.notebookEditor.layoutNotebookCell(this.cell, e.contentHeight + 32);
}
}));
originalCell.resolveTextModelRef().then(ref => {
this._register(ref);
const textModel = ref.object.textEditorModel;
this._editor.setModel(textModel);
this.notebookEditor.layoutNotebookCell(this.cell, this._editor.getContentHeight() + 32);
diagonalFill.style.height = `${this._editor.getContentHeight()}px`;
});
}
}
class InsertCell extends Disposable {
private _editor!: CodeEditorWidget;
constructor(
readonly notebookEditor: INotebookTextDiffEditor,
readonly cell: CellDiffViewModel,
readonly templateData: CellDiffRenderTemplate,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
) {
super();
const diffEditorContainer = DOM.$('.cell-diff-editor-container');
DOM.append(templateData.container, diffEditorContainer);
DOM.addClass(diffEditorContainer, 'insert');
const modifiedCell = cell.modified!;
const lineCount = modifiedCell.textBuffer.getLineCount();
const lineHeight = notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17;
const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING;
const diagonalFill = DOM.append(diffEditorContainer, DOM.$('.diagonal-fill'));
const editorContainer = DOM.append(diffEditorContainer, DOM.$('.editor-container'));
this._editor = this.instantiationService.createInstance(CodeEditorWidget, editorContainer, {
...fixedEditorOptions,
dimension: {
width: (notebookEditor.getLayoutInfo().width - 20) / 2 - 18,
height: editorHeight
}
}, {});
diagonalFill.style.height = `${editorHeight}px`;
this._register(this._editor.onDidContentSizeChange((e) => {
if (e.contentHeightChanged) {
this._editor.layout({
width: (notebookEditor.getLayoutInfo().width - 20) / 2 - 18,
height: e.contentHeight
});
diagonalFill.style.height = `${e.contentHeight}px`;
this.notebookEditor.layoutNotebookCell(this.cell, e.contentHeight + 32);
}
}));
modifiedCell.resolveTextModelRef().then(ref => {
this._register(ref);
const textModel = ref.object.textEditorModel;
this._editor.setModel(textModel);
this.notebookEditor.layoutNotebookCell(this.cell, this._editor.getContentHeight() + 32);
diagonalFill.style.height = `${this._editor.getContentHeight()}px`;
});
}
}
class ModifiedCell extends Disposable {
private _editor!: DiffEditorWidget;
private _editorContainer!: HTMLElement;
constructor(
readonly notebookEditor: INotebookTextDiffEditor,
readonly cell: CellDiffViewModel,
readonly templateData: CellDiffRenderTemplate,
@IInstantiationService protected readonly instantiationService: IInstantiationService,
) {
super();
const diffEditorContainer = DOM.$('.cell-diff-editor-container');
DOM.append(templateData.container, diffEditorContainer);
const modifiedCell = cell.modified!;
const lineCount = modifiedCell.textBuffer.getLineCount();
const lineHeight = notebookEditor.getLayoutInfo().fontInfo.lineHeight || 17;
const editorHeight = lineCount * lineHeight + EDITOR_TOP_PADDING + EDITOR_BOTTOM_PADDING;
this._editorContainer = DOM.append(diffEditorContainer, DOM.$('.editor-container'));
this._editor = this.instantiationService.createInstance(DiffEditorWidget, this._editorContainer, {
...fixedDiffEditorOptions
});
this._editor.layout({
width: notebookEditor.getLayoutInfo().width - 20,
height: editorHeight
});
this._editorContainer.style.height = `${editorHeight}px`;
this._register(this._editor.onDidContentSizeChange((e) => {
if (e.contentHeightChanged) {
this._editorContainer.style.height = `${e.contentHeight}px`;
this.notebookEditor.layoutNotebookCell(this.cell, e.contentHeight + 32);
this._editor.layout();
}
}));
this.initialize();
}
async initialize() {
const originalCell = this.cell.original!;
const modifiedCell = this.cell.modified!;
const originalRef = await originalCell.resolveTextModelRef();
const modifiedRef = await modifiedCell.resolveTextModelRef();
const textModel = originalRef.object.textEditorModel;
const modifiedTextModel = modifiedRef.object.textEditorModel;
this._register(originalRef);
this._register(modifiedRef);
this._editor.setModel({
original: textModel,
modified: modifiedTextModel
});
const contentHeight = this._editor.getContentHeight();
this._editorContainer.style.height = `${contentHeight}px`;
this._editor.layout();
this.notebookEditor.layoutNotebookCell(this.cell, contentHeight + 32);
}
}
export class NotebookTextDiffList extends WorkbenchList<CellDiffViewModel> implements IDisposable, IStyleController {
private styleElement?: HTMLStyleElement;
constructor(
listUser: string,
container: HTMLElement,
delegate: IListVirtualDelegate<CellDiffViewModel>,
renderers: IListRenderer<CellDiffViewModel, CellDiffRenderTemplate>[],
contextKeyService: IContextKeyService,
options: IWorkbenchListOptions<CellDiffViewModel>,
@IListService listService: IListService,
@IThemeService themeService: IThemeService,
@IConfigurationService configurationService: IConfigurationService,
@IKeybindingService keybindingService: IKeybindingService,
@IInstantiationService instantiationService: IInstantiationService
) {
super(listUser, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService);
}
style(styles: IListStyles) {
const selectorSuffix = this.view.domId;
if (!this.styleElement) {
this.styleElement = DOM.createStyleSheet(this.view.domNode);
}
const suffix = selectorSuffix && `.${selectorSuffix}`;
const content: string[] = [];
if (styles.listBackground) {
if (styles.listBackground.isOpaque()) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows { background: ${styles.listBackground}; }`);
} else if (!isMacintosh) { // subpixel AA doesn't exist in macOS
console.warn(`List with id '${selectorSuffix}' was styled with a non-opaque background color. This will break sub-pixel antialiasing.`);
}
}
if (styles.listFocusBackground) {
content.push(`.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { background-color: ${styles.listFocusBackground}; }`);
content.push(`.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused:hover { background-color: ${styles.listFocusBackground}; }`); // overwrite :hover style in this case!
}
if (styles.listFocusForeground) {
content.push(`.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { color: ${styles.listFocusForeground}; }`);
}
if (styles.listActiveSelectionBackground) {
content.push(`.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected { background-color: ${styles.listActiveSelectionBackground}; }`);
content.push(`.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected:hover { background-color: ${styles.listActiveSelectionBackground}; }`); // overwrite :hover style in this case!
}
if (styles.listActiveSelectionForeground) {
content.push(`.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected { color: ${styles.listActiveSelectionForeground}; }`);
}
if (styles.listFocusAndSelectionBackground) {
content.push(`
.monaco-drag-image,
.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected.focused { background-color: ${styles.listFocusAndSelectionBackground}; }
`);
}
if (styles.listFocusAndSelectionForeground) {
content.push(`
.monaco-drag-image,
.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected.focused { color: ${styles.listFocusAndSelectionForeground}; }
`);
}
if (styles.listInactiveFocusBackground) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { background-color: ${styles.listInactiveFocusBackground}; }`);
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused:hover { background-color: ${styles.listInactiveFocusBackground}; }`); // overwrite :hover style in this case!
}
if (styles.listInactiveSelectionBackground) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected { background-color: ${styles.listInactiveSelectionBackground}; }`);
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected:hover { background-color: ${styles.listInactiveSelectionBackground}; }`); // overwrite :hover style in this case!
}
if (styles.listInactiveSelectionForeground) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected { color: ${styles.listInactiveSelectionForeground}; }`);
}
if (styles.listHoverBackground) {
content.push(`.monaco-list${suffix}:not(.drop-target) > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover:not(.selected):not(.focused) { background-color: ${styles.listHoverBackground}; }`);
}
if (styles.listHoverForeground) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover:not(.selected):not(.focused) { color: ${styles.listHoverForeground}; }`);
}
if (styles.listSelectionOutline) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.selected { outline: 1px dotted ${styles.listSelectionOutline}; outline-offset: -1px; }`);
}
if (styles.listFocusOutline) {
content.push(`
.monaco-drag-image,
.monaco-list${suffix}:focus > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { outline: 1px solid ${styles.listFocusOutline}; outline-offset: -1px; }
`);
}
if (styles.listInactiveFocusOutline) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.focused { outline: 1px dotted ${styles.listInactiveFocusOutline}; outline-offset: -1px; }`);
}
if (styles.listHoverOutline) {
content.push(`.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows > .monaco-list-row:hover { outline: 1px dashed ${styles.listHoverOutline}; outline-offset: -1px; }`);
}
if (styles.listDropBackground) {
content.push(`
.monaco-list${suffix}.drop-target,
.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-rows.drop-target,
.monaco-list${suffix} > div.monaco-scrollable-element > .monaco-list-row.drop-target { background-color: ${styles.listDropBackground} !important; color: inherit !important; }
`);
}
if (styles.listFilterWidgetBackground) {
content.push(`.monaco-list-type-filter { background-color: ${styles.listFilterWidgetBackground} }`);
}
if (styles.listFilterWidgetOutline) {
content.push(`.monaco-list-type-filter { border: 1px solid ${styles.listFilterWidgetOutline}; }`);
}
if (styles.listFilterWidgetNoMatchesOutline) {
content.push(`.monaco-list-type-filter.no-matches { border: 1px solid ${styles.listFilterWidgetNoMatchesOutline}; }`);
}
if (styles.listMatchesShadow) {
content.push(`.monaco-list-type-filter { box-shadow: 1px 1px 1px ${styles.listMatchesShadow}; }`);
}
const newStyles = content.join('\n');
if (newStyles !== this.styleElement.innerHTML) {
this.styleElement.innerHTML = newStyles;
}
}
}
@@ -43,7 +43,7 @@ import { INotebookEditorModelResolverService, NotebookModelResolverService } fro
import { ResourceEditorInput } from 'vs/workbench/common/editor/resourceEditorInput';
import { DiffEditorInput } from 'vs/workbench/common/editor/diffEditorInput';
import { NotebookDiffEditorInput } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditorInput';
import { NotebookDiffEditor } from 'vs/workbench/contrib/notebook/browser/notebookDiffEditor';
import { NotebookTextDiffEditor } from 'vs/workbench/contrib/notebook/browser/diff/notebookTextDiffEditor';
import { INotebookEditorWorkerService } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerService';
import { NotebookEditorWorkerServiceImpl } from 'vs/workbench/contrib/notebook/common/services/notebookWorkerServiceImpl';
@@ -79,8 +79,8 @@ Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
Registry.as<IEditorRegistry>(EditorExtensions.Editors).registerEditor(
EditorDescriptor.create(
NotebookDiffEditor,
NotebookDiffEditor.ID,
NotebookTextDiffEditor,
NotebookTextDiffEditor.ID,
'Notebook Diff Editor'
),
[