mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-30 18:46:00 +01:00
notebook diff
This commit is contained in:
@@ -0,0 +1,130 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { Disposable, DisposableStore } from 'vs/base/common/lifecycle';
|
||||
import { INotebookEditorContribution, INotebookEditor, INotebookDeltaDecoration } from '../../notebookBrowser';
|
||||
import { registerNotebookContribution } from '../../notebookEditorExtensions';
|
||||
import { ISCMService } from 'vs/workbench/contrib/scm/common/scm';
|
||||
import { createProviderComparer } from 'vs/workbench/contrib/scm/browser/dirtydiffDecorator';
|
||||
import { first } from 'vs/base/common/async';
|
||||
import { INotebookService } from '../../../common/notebookService';
|
||||
import { NotebookCellTextModel } from '../../../common/model/notebookCellTextModel';
|
||||
import { diff } from '../../../common/notebookCommon';
|
||||
|
||||
export class SCMController extends Disposable implements INotebookEditorContribution {
|
||||
static id: string = 'workbench.notebook.findController';
|
||||
private _lastDecorationId: string[] = [];
|
||||
private _localDisposable = new DisposableStore();
|
||||
|
||||
|
||||
constructor(
|
||||
private readonly _notebookEditor: INotebookEditor,
|
||||
@ISCMService private readonly _scmService: ISCMService,
|
||||
@INotebookService private readonly _notebookService: INotebookService
|
||||
|
||||
) {
|
||||
super();
|
||||
|
||||
this._register(this._notebookEditor.onDidChangeModel(() => {
|
||||
this._localDisposable.clear();
|
||||
this.update();
|
||||
|
||||
if (this._notebookEditor.textModel) {
|
||||
this._localDisposable.add(this._notebookEditor.textModel.onDidChangeContent(() => {
|
||||
this.update();
|
||||
}));
|
||||
|
||||
this._localDisposable.add(this._notebookEditor.textModel.onDidChangeCells(() => {
|
||||
this.update();
|
||||
}));
|
||||
}
|
||||
}));
|
||||
|
||||
this.update();
|
||||
}
|
||||
|
||||
async update() {
|
||||
const modifiedDocument = this._notebookEditor.textModel;
|
||||
if (!modifiedDocument) {
|
||||
return;
|
||||
}
|
||||
|
||||
const uri = modifiedDocument.uri;
|
||||
const providers = this._scmService.repositories.map(r => r.provider);
|
||||
const rootedProviders = providers.filter(p => !!p.rootUri);
|
||||
|
||||
rootedProviders.sort(createProviderComparer(uri));
|
||||
|
||||
const result = await first(rootedProviders.map(p => () => p.getOriginalResource(uri)));
|
||||
|
||||
if (!result) {
|
||||
this._clear();
|
||||
return;
|
||||
}
|
||||
|
||||
const originalDocument = await this._notebookService.resolveNotebook(modifiedDocument.viewType, result, false);
|
||||
|
||||
if (!originalDocument) {
|
||||
this._clear();
|
||||
return;
|
||||
}
|
||||
|
||||
// naive diff, runCode50
|
||||
// diff: 3.947998046875ms
|
||||
// diff: 2.615966796875ms
|
||||
|
||||
console.time('diff');
|
||||
|
||||
const cellDiffs = diff<NotebookCellTextModel>(originalDocument.cells, modifiedDocument.cells, a => {
|
||||
for (let i = 0; i < originalDocument.cells.length; i++) {
|
||||
const modifiedCell = originalDocument.cells[i];
|
||||
|
||||
if (modifiedCell.getValue() === a.getValue()) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}, (a, b) => {
|
||||
return a.getValue() === b.getValue();
|
||||
});
|
||||
|
||||
console.timeEnd('diff');
|
||||
|
||||
const decorations: INotebookDeltaDecoration[] = [];
|
||||
|
||||
cellDiffs.forEach(diff => {
|
||||
if (diff.deleteCount === 0) {
|
||||
// doesn't exist in original
|
||||
// insert
|
||||
decorations.push(...diff.toInsert.map(cell => ({
|
||||
handle: cell.handle,
|
||||
options: { gutterClassName: 'nb-gutter-cell-inserted' }
|
||||
})));
|
||||
} else {
|
||||
if (diff.toInsert.length === 0) {
|
||||
// diff.deleteCount
|
||||
// removed from original
|
||||
} else {
|
||||
// modification
|
||||
decorations.push(...diff.toInsert.map(cell => ({
|
||||
handle: cell.handle,
|
||||
options: { gutterClassName: 'nb-gutter-cell-changed' }
|
||||
})));
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
|
||||
|
||||
this._lastDecorationId = this._notebookEditor.deltaCellDecorations(this._lastDecorationId, decorations);
|
||||
}
|
||||
|
||||
private _clear() {
|
||||
this._lastDecorationId = this._notebookEditor.deltaCellDecorations(this._lastDecorationId, []);
|
||||
}
|
||||
}
|
||||
|
||||
registerNotebookContribution(SCMController.id, SCMController);
|
||||
@@ -11,6 +11,48 @@
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter {
|
||||
position: absolute;
|
||||
width: 6px;
|
||||
top: 0px;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter .monaco-list-row .cell {
|
||||
visibility: hidden;
|
||||
top: -8px;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter .monaco-list-row .cell.nb-gutter-cell-changed {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
width: 2px;
|
||||
transition: width 80ms linear, left 80ms linear;
|
||||
background-color: #66afe0;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter .monaco-list-row:hover .cell.nb-gutter-cell-changed {
|
||||
left: 0px;
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter .monaco-list-row .cell.nb-gutter-cell-inserted {
|
||||
position: relative;
|
||||
visibility: visible;
|
||||
width: 2px;
|
||||
transition: width 80ms linear, left 80ms linear;
|
||||
background-color: #81b88b;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter .monaco-list-row:hover .cell.nb-gutter-cell-inserted {
|
||||
left: 0px;
|
||||
width: 6px;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay .notebook-gutter .monaco-scrollable-element > .scrollbar{
|
||||
visibility: hidden;
|
||||
}
|
||||
|
||||
.monaco-workbench .cell.markdown {
|
||||
user-select: text;
|
||||
-webkit-user-select: text;
|
||||
@@ -55,6 +97,12 @@
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .notebook-gutter > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row {
|
||||
cursor: default;
|
||||
overflow: visible !important;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.monaco-workbench .notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element > .monaco-list-rows > .monaco-list-row.cell-drag-image {
|
||||
position: absolute;
|
||||
top: -500px;
|
||||
|
||||
@@ -51,6 +51,7 @@ import 'vs/workbench/contrib/notebook/browser/contrib/format/formatting';
|
||||
import 'vs/workbench/contrib/notebook/browser/contrib/toc/tocProvider';
|
||||
import 'vs/workbench/contrib/notebook/browser/contrib/marker/markerProvider';
|
||||
import 'vs/workbench/contrib/notebook/browser/contrib/status/editorStatus';
|
||||
import 'vs/workbench/contrib/notebook/browser/contrib/scm/scm';
|
||||
|
||||
// Output renderers registration
|
||||
|
||||
|
||||
@@ -154,6 +154,7 @@ export interface INotebookEditorContribution {
|
||||
|
||||
export interface INotebookCellDecorationOptions {
|
||||
className?: string;
|
||||
gutterClassName?: string;
|
||||
outputClassName?: string;
|
||||
}
|
||||
|
||||
@@ -375,6 +376,8 @@ export interface INotebookEditor extends IEditor {
|
||||
|
||||
setCellSelection(cell: ICellViewModel, selection: Range): void;
|
||||
|
||||
deltaCellDecorations(oldDecorations: string[], newDecorations: INotebookDeltaDecoration[]): string[];
|
||||
|
||||
/**
|
||||
* Change the decorations on cells.
|
||||
* The notebook is virtualized and this method should be called to create/delete editor decorations safely.
|
||||
|
||||
@@ -325,6 +325,7 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
this._list = this.instantiationService.createInstance(
|
||||
NotebookCellList,
|
||||
'NotebookCellList',
|
||||
this._overlayContainer,
|
||||
this._body,
|
||||
this.instantiationService.createInstance(NotebookCellListDelegate),
|
||||
renderers,
|
||||
@@ -1640,7 +1641,8 @@ export const cellSymbolHighlight = registerColor('notebook.symbolHighlightBackgr
|
||||
}, nls.localize('notebook.symbolHighlightBackground', "Background color of highlighted cell"));
|
||||
|
||||
registerThemingParticipant((theme, collector) => {
|
||||
collector.addRule(`.notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element {
|
||||
collector.addRule(`.notebookOverlay > .cell-list-container > .monaco-list > .monaco-scrollable-element,
|
||||
.notebookOverlay > .cell-list-container > .notebook-gutter > .monaco-list > .monaco-scrollable-element {
|
||||
padding-top: ${SCROLLABLE_ELEMENT_PADDING_TOP}px;
|
||||
box-sizing: border-box;
|
||||
}`);
|
||||
|
||||
@@ -3,10 +3,11 @@
|
||||
* 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 { IMouseWheelEvent } from 'vs/base/browser/mouseEvent';
|
||||
import { IListRenderer, IListVirtualDelegate, ListError } from 'vs/base/browser/ui/list/list';
|
||||
import { IListStyles, IStyleController } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { IListStyles, IStyleController, IListOptions } from 'vs/base/browser/ui/list/listWidget';
|
||||
import { Emitter, Event } from 'vs/base/common/event';
|
||||
import { DisposableStore, IDisposable } from 'vs/base/common/lifecycle';
|
||||
import { isMacintosh } from 'vs/base/common/platform';
|
||||
@@ -24,6 +25,9 @@ import { CellViewModel, NotebookViewModel } from 'vs/workbench/contrib/notebook/
|
||||
import { diff, IProcessedOutput, NOTEBOOK_EDITOR_CURSOR_BOUNDARY, CellKind } from 'vs/workbench/contrib/notebook/common/notebookCommon';
|
||||
import { clamp } from 'vs/base/common/numbers';
|
||||
import { SCROLLABLE_ELEMENT_PADDING_TOP } from 'vs/workbench/contrib/notebook/browser/constants';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { editorBackground, foreground, focusBorder } from 'vs/platform/theme/common/colorRegistry';
|
||||
import { NotebookGutter, NotebookGutterDelegate, GutterRenderer } from 'vs/workbench/contrib/notebook/browser/view/notebookGutter';
|
||||
|
||||
export interface IFocusNextPreviousDelegate {
|
||||
onFocusNext(applyFocusNext: () => void): void;
|
||||
@@ -62,8 +66,11 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
|
||||
private readonly _focusNextPreviousDelegate: IFocusNextPreviousDelegate;
|
||||
|
||||
private _cellListGutter: WorkbenchList<CellViewModel>;
|
||||
|
||||
constructor(
|
||||
private listUser: string,
|
||||
parentContainer: HTMLElement,
|
||||
container: HTMLElement,
|
||||
delegate: IListVirtualDelegate<CellViewModel>,
|
||||
renderers: IListRenderer<CellViewModel, BaseCellRenderTemplate>[],
|
||||
@@ -72,7 +79,8 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
@IListService listService: IListService,
|
||||
@IThemeService themeService: IThemeService,
|
||||
@IConfigurationService configurationService: IConfigurationService,
|
||||
@IKeybindingService keybindingService: IKeybindingService
|
||||
@IKeybindingService keybindingService: IKeybindingService,
|
||||
@IInstantiationService instantiationService: IInstantiationService
|
||||
) {
|
||||
super(listUser, container, delegate, renderers, options, contextKeyService, listService, themeService, configurationService, keybindingService);
|
||||
NOTEBOOK_CELL_LIST_FOCUSED.bindTo(this.contextKeyService).set(true);
|
||||
@@ -150,6 +158,81 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
focus.focusMode = CellFocusMode.Editor;
|
||||
}
|
||||
}));
|
||||
|
||||
const gutterContainer = DOM.append(container, DOM.$('.notebook-gutter'));
|
||||
|
||||
this._cellListGutter = instantiationService.createInstance(
|
||||
NotebookGutter,
|
||||
'NotebookGutter',
|
||||
gutterContainer,
|
||||
instantiationService.createInstance(NotebookGutterDelegate),
|
||||
[instantiationService.createInstance(GutterRenderer, (index, size) => {
|
||||
DOM.scheduleAtNextAnimationFrame(() => {
|
||||
this._cellListGutter?.updateElementHeight(index, size);
|
||||
});
|
||||
})],
|
||||
this.contextKeyService,
|
||||
{
|
||||
setRowLineHeight: false,
|
||||
setRowHeight: false,
|
||||
supportDynamicHeights: true,
|
||||
horizontalScrolling: false,
|
||||
keyboardSupport: false,
|
||||
mouseSupport: false,
|
||||
multipleSelectionSupport: false,
|
||||
enableKeyboardNavigation: false,
|
||||
additionalScrollHeight: 0,
|
||||
transformOptimization: false,
|
||||
styleController: (_suffix: string) => { return this; },
|
||||
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");
|
||||
}
|
||||
}
|
||||
},
|
||||
);
|
||||
|
||||
let scrolling = false;
|
||||
|
||||
this._localDisposableStore.add(this.onWillScroll(() => {
|
||||
scrolling = true;
|
||||
}));
|
||||
|
||||
this._localDisposableStore.add(this.onDidScroll(() => {
|
||||
if (this._cellListGutter.scrollTop !== this.scrollTop) {
|
||||
this._cellListGutter.scrollTop = this.scrollTop;
|
||||
}
|
||||
|
||||
scrolling = false;
|
||||
}));
|
||||
|
||||
this._localDisposableStore.add(this._cellListGutter.onDidScroll(() => {
|
||||
if (scrolling) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (this._cellListGutter.scrollTop !== this.scrollTop) {
|
||||
this.scrollTop = this._cellListGutter.scrollTop;
|
||||
}
|
||||
}));
|
||||
}
|
||||
|
||||
elementAt(position: number): ICellViewModel | undefined {
|
||||
@@ -375,6 +458,8 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
|
||||
super.splice(start, deleteCount, elements);
|
||||
|
||||
this._cellListGutter.splice(start, deleteCount, elements);
|
||||
|
||||
const selectionsLeft = [];
|
||||
this._viewModel!.selectionHandles.forEach(handle => {
|
||||
if (this._viewModel!.hasCell(handle)) {
|
||||
@@ -563,6 +648,7 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
|
||||
const focused = this.getFocus();
|
||||
this.view.updateElementHeight(index, size, focused.length ? focused[0] : null);
|
||||
this._cellListGutter.updateElementHeight(index, size);
|
||||
}
|
||||
|
||||
// override
|
||||
@@ -801,6 +887,19 @@ export class NotebookCellList extends WorkbenchList<CellViewModel> implements ID
|
||||
}
|
||||
}
|
||||
|
||||
updateOptions(options: IListOptions<ICellViewModel>) {
|
||||
super.updateOptions(options);
|
||||
|
||||
if (options.additionalScrollHeight !== undefined) {
|
||||
this._cellListGutter.updateOptions({ additionalScrollHeight: options.additionalScrollHeight });
|
||||
}
|
||||
}
|
||||
|
||||
layout(height?: number, width?: number): void {
|
||||
super.layout(height, width);
|
||||
this._cellListGutter.layout(height, width);
|
||||
}
|
||||
|
||||
|
||||
style(styles: IListStyles) {
|
||||
const selectorSuffix = this.view.domId;
|
||||
|
||||
@@ -0,0 +1,126 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import * as DOM from 'vs/base/browser/dom';
|
||||
import { WorkbenchList, IListService, IWorkbenchListOptions } from 'vs/platform/list/browser/listService';
|
||||
import { IListVirtualDelegate, IListRenderer } from 'vs/base/browser/ui/list/list';
|
||||
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
||||
import { IContextKeyService } from 'vs/platform/contextkey/common/contextkey';
|
||||
import { IThemeService } from 'vs/platform/theme/common/themeService';
|
||||
import { IKeybindingService } from 'vs/platform/keybinding/common/keybinding';
|
||||
import { IInstantiationService } from 'vs/platform/instantiation/common/instantiation';
|
||||
import { CellViewModel } from '../viewModel/notebookViewModel';
|
||||
import { DisposableStore } from 'vs/base/common/lifecycle';
|
||||
|
||||
|
||||
interface IGutterRendererTemplate {
|
||||
container: HTMLElement;
|
||||
cellContainer: HTMLElement;
|
||||
elementDisposables: DisposableStore;
|
||||
}
|
||||
|
||||
export class GutterRenderer implements IListRenderer<CellViewModel, IGutterRendererTemplate> {
|
||||
|
||||
static TEMPLATE_ID = 'notebook_gutter';
|
||||
|
||||
templateId = 'notebook_gutter';
|
||||
|
||||
constructor(
|
||||
private _elementHeightUpdateDelegate: (index: number, size: number) => void
|
||||
) {
|
||||
}
|
||||
|
||||
renderTemplate(container: HTMLElement): IGutterRendererTemplate {
|
||||
const cellContainer = DOM.append(container, DOM.$('.cell'));
|
||||
|
||||
return {
|
||||
container,
|
||||
cellContainer,
|
||||
elementDisposables: new DisposableStore()
|
||||
};
|
||||
}
|
||||
|
||||
renderElement(element: CellViewModel, index: number, templateData: IGutterRendererTemplate, height: number | undefined): void {
|
||||
templateData.cellContainer.style.height = `${element.layoutInfo.totalHeight}px`;
|
||||
let removedClassNames: string[] = [];
|
||||
templateData.cellContainer.classList.forEach(className => {
|
||||
if (/^nb\-.*$/.test(className)) {
|
||||
removedClassNames.push(className);
|
||||
}
|
||||
});
|
||||
|
||||
removedClassNames.forEach(className => {
|
||||
templateData.cellContainer.classList.remove(className);
|
||||
});
|
||||
|
||||
templateData.elementDisposables.add(element.onDidChangeLayout(() => {
|
||||
templateData.cellContainer.style.height = `${element.layoutInfo.totalHeight}px`;
|
||||
this._elementHeightUpdateDelegate(index, element.layoutInfo.totalHeight);
|
||||
}));
|
||||
|
||||
element.getCellDecorations().forEach(options => {
|
||||
if (options.gutterClassName) {
|
||||
DOM.addClass(templateData.cellContainer, options.gutterClassName);
|
||||
}
|
||||
});
|
||||
|
||||
templateData.elementDisposables.add(element.onCellDecorationsChanged((e) => {
|
||||
e.added.forEach(options => {
|
||||
if (options.gutterClassName) {
|
||||
DOM.addClass(templateData.cellContainer, options.gutterClassName);
|
||||
}
|
||||
});
|
||||
|
||||
e.removed.forEach(options => {
|
||||
if (options.gutterClassName) {
|
||||
DOM.removeClass(templateData.cellContainer, options.gutterClassName);
|
||||
}
|
||||
});
|
||||
}));
|
||||
}
|
||||
disposeTemplate(templateData: IGutterRendererTemplate): void {
|
||||
templateData.cellContainer.style.backgroundColor = `#fff`;
|
||||
|
||||
templateData.elementDisposables.clear();
|
||||
return;
|
||||
}
|
||||
|
||||
disposeElement(element: CellViewModel, index: number, templateData: IGutterRendererTemplate): void {
|
||||
templateData.elementDisposables.clear();
|
||||
}
|
||||
}
|
||||
|
||||
export class NotebookGutterDelegate implements IListVirtualDelegate<CellViewModel> {
|
||||
getHeight(element: CellViewModel): number {
|
||||
return element.layoutInfo.totalHeight;
|
||||
}
|
||||
|
||||
hasDynamicHeight(element: CellViewModel): boolean {
|
||||
return false;
|
||||
}
|
||||
|
||||
getTemplateId(element: CellViewModel): string {
|
||||
return GutterRenderer.TEMPLATE_ID;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
export class NotebookGutter extends WorkbenchList<CellViewModel> {
|
||||
constructor(
|
||||
listUser: string,
|
||||
container: HTMLElement,
|
||||
delegate: IListVirtualDelegate<CellViewModel>,
|
||||
renderers: IListRenderer<CellViewModel, IGutterRendererTemplate>[],
|
||||
contextKeyService: IContextKeyService,
|
||||
options: IWorkbenchListOptions<CellViewModel>,
|
||||
@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);
|
||||
}
|
||||
}
|
||||
@@ -507,7 +507,7 @@ interface IMutableSplice<T> extends ISplice<T> {
|
||||
deleteCount: number;
|
||||
}
|
||||
|
||||
export function diff<T>(before: T[], after: T[], contains: (a: T) => boolean): ISplice<T>[] {
|
||||
export function diff<T>(before: T[], after: T[], contains: (a: T) => boolean, equal: (a: T, b: T) => boolean = (a: T, b: T) => a === b): ISplice<T>[] {
|
||||
const result: IMutableSplice<T>[] = [];
|
||||
|
||||
function pushSplice(start: number, deleteCount: number, toInsert: T[]): void {
|
||||
@@ -542,7 +542,7 @@ export function diff<T>(before: T[], after: T[], contains: (a: T) => boolean): I
|
||||
const beforeElement = before[beforeIdx];
|
||||
const afterElement = after[afterIdx];
|
||||
|
||||
if (beforeElement === afterElement) {
|
||||
if (equal(beforeElement, afterElement)) {
|
||||
// equal
|
||||
beforeIdx += 1;
|
||||
afterIdx += 1;
|
||||
|
||||
@@ -12,7 +12,7 @@ import { BareFontInfo } from 'vs/editor/common/config/fontInfo';
|
||||
import { Range } from 'vs/editor/common/core/range';
|
||||
import { IUndoRedoService } from 'vs/platform/undoRedo/common/undoRedo';
|
||||
import { EditorModel } from 'vs/workbench/common/editor';
|
||||
import { ICellRange, ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { ICellRange, ICellViewModel, INotebookEditor, INotebookEditorContribution, INotebookEditorMouseEvent, NotebookLayoutInfo, INotebookDeltaDecoration } from 'vs/workbench/contrib/notebook/browser/notebookBrowser';
|
||||
import { OutputRenderer } from 'vs/workbench/contrib/notebook/browser/view/output/outputRenderer';
|
||||
import { NotebookEventDispatcher } from 'vs/workbench/contrib/notebook/browser/viewModel/eventDispatcher';
|
||||
import { CellViewModel, IModelDecorationsChangeAccessor, NotebookViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/notebookViewModel';
|
||||
@@ -258,6 +258,10 @@ export class TestNotebookEditor implements INotebookEditor {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
deltaCellDecorations(oldDecorations: string[], newDecorations: INotebookDeltaDecoration[]): string[] {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
deltaCellOutputContainerClassNames(cellId: string, added: string[], removed: string[]): void {
|
||||
throw new Error('Method not implemented.');
|
||||
}
|
||||
|
||||
@@ -982,7 +982,7 @@ function compareChanges(a: IChange, b: IChange): number {
|
||||
return a.originalEndLineNumber - b.originalEndLineNumber;
|
||||
}
|
||||
|
||||
function createProviderComparer(uri: URI): (a: ISCMProvider, b: ISCMProvider) => number {
|
||||
export function createProviderComparer(uri: URI): (a: ISCMProvider, b: ISCMProvider) => number {
|
||||
return (a, b) => {
|
||||
const aIsParent = isEqualOrParent(uri, a.rootUri!);
|
||||
const bIsParent = isEqualOrParent(uri, b.rootUri!);
|
||||
|
||||
Reference in New Issue
Block a user