mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-27 10:37:38 +01:00
build text diff editor
This commit is contained in:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
+9
-11
@@ -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'
|
||||
),
|
||||
[
|
||||
|
||||
Reference in New Issue
Block a user