mirror of
https://github.com/microsoft/vscode.git
synced 2026-09-27 10:37:38 +01:00
range map provider
This commit is contained in:
@@ -54,6 +54,10 @@ export interface IListViewOptionsUpdate {
|
||||
readonly horizontalScrolling?: boolean;
|
||||
}
|
||||
|
||||
export interface IListViewRangeMapProvider {
|
||||
(): RangeMap;
|
||||
}
|
||||
|
||||
export interface IListViewOptions<T> extends IListViewOptionsUpdate {
|
||||
readonly dnd?: IListViewDragAndDrop<T>;
|
||||
readonly useShadows?: boolean;
|
||||
@@ -64,6 +68,7 @@ export interface IListViewOptions<T> extends IListViewOptionsUpdate {
|
||||
readonly mouseSupport?: boolean;
|
||||
readonly accessibilityProvider?: IListViewAccessibilityProvider<T>;
|
||||
readonly transformOptimization?: boolean;
|
||||
readonly rangeMapProvider?: IListViewRangeMapProvider;
|
||||
}
|
||||
|
||||
const DefaultOptions = {
|
||||
@@ -209,6 +214,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
private items: IItem<T>[];
|
||||
private itemId: number;
|
||||
private rangeMap: RangeMap;
|
||||
private rangeMapProvider: IListViewRangeMapProvider;
|
||||
private cache: RowCache<T>;
|
||||
private renderers = new Map<string, IListRenderer<any /* TODO@joao */, any>>();
|
||||
private lastRenderTop: number;
|
||||
@@ -289,7 +295,8 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
this.items = [];
|
||||
this.itemId = 0;
|
||||
this.rangeMap = new RangeMap();
|
||||
this.rangeMapProvider = getOrDefault(options, o => o.rangeMapProvider, () => new RangeMap());
|
||||
this.rangeMap = this.rangeMapProvider();
|
||||
|
||||
for (const renderer of renderers) {
|
||||
this.renderers.set(renderer.templateId, renderer);
|
||||
@@ -469,7 +476,7 @@ export class ListView<T> implements ISpliceable<T>, IDisposable {
|
||||
|
||||
// TODO@joao: improve this optimization to catch even more cases
|
||||
if (start === 0 && deleteCount >= this.items.length) {
|
||||
this.rangeMap = new RangeMap();
|
||||
this.rangeMap = this.rangeMapProvider();
|
||||
this.rangeMap.splice(0, 0, inserted);
|
||||
this.items = inserted;
|
||||
deleted = [];
|
||||
|
||||
@@ -16,7 +16,7 @@ import { StandardKeyboardEvent, IKeyboardEvent } from 'vs/base/browser/keyboardE
|
||||
import { Event, Emitter, EventBufferer } from 'vs/base/common/event';
|
||||
import { domEvent } from 'vs/base/browser/event';
|
||||
import { IListVirtualDelegate, IListRenderer, IListEvent, IListContextMenuEvent, IListMouseEvent, IListTouchEvent, IListGestureEvent, IIdentityProvider, IKeyboardNavigationLabelProvider, IListDragAndDrop, IListDragOverReaction, ListError, IKeyboardNavigationDelegate } from './list';
|
||||
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider, IListViewOptionsUpdate } from './listView';
|
||||
import { ListView, IListViewOptions, IListViewDragAndDrop, IListViewAccessibilityProvider, IListViewOptionsUpdate, IListViewRangeMapProvider } from './listView';
|
||||
import { Color } from 'vs/base/common/color';
|
||||
import { mixin } from 'vs/base/common/objects';
|
||||
import { ScrollbarVisibility, ScrollEvent } from 'vs/base/common/scrollable';
|
||||
@@ -854,6 +854,7 @@ export interface IListOptions<T> {
|
||||
readonly horizontalScrolling?: boolean;
|
||||
readonly additionalScrollHeight?: number;
|
||||
readonly transformOptimization?: boolean;
|
||||
readonly rangeMapProvider?: IListViewRangeMapProvider;
|
||||
readonly smoothScrolling?: boolean;
|
||||
}
|
||||
|
||||
|
||||
@@ -83,25 +83,13 @@ export function consolidate(groups: IRangedGroup[]): IRangedGroup[] {
|
||||
* Concatenates several collections of ranged groups into a single
|
||||
* collection.
|
||||
*/
|
||||
function concat(...groups: IRangedGroup[][]): IRangedGroup[] {
|
||||
export function concat(...groups: IRangedGroup[][]): IRangedGroup[] {
|
||||
return consolidate(groups.reduce((r, g) => r.concat(g), []));
|
||||
}
|
||||
|
||||
export class ListWhitespace {
|
||||
|
||||
constructor(
|
||||
public afterIndex: number,
|
||||
public height: number,
|
||||
// height of all whitespaces before this whitespace (inclusive)
|
||||
public prefixSum: number
|
||||
) { }
|
||||
}
|
||||
|
||||
// [ { start: 0, len: 2, size: 2 }, { start: 2, len: 1, size: 3 }, {} ]
|
||||
export class RangeMap {
|
||||
|
||||
private groups: IRangedGroup[] = [];
|
||||
private whitespaces: ListWhitespace[] = [];
|
||||
private _size = 0;
|
||||
|
||||
splice(index: number, deleteCount: number, items: IItem[] = []): void {
|
||||
@@ -117,86 +105,6 @@ export class RangeMap {
|
||||
|
||||
this.groups = concat(before, middle, after);
|
||||
this._size = this.groups.reduce((t, g) => t + (g.size * (g.range.end - g.range.start)), 0);
|
||||
|
||||
const deleteRange = deleteCount > 0 ? [index, index + deleteCount - 1] : [];
|
||||
const indexDelta = items.length - deleteCount;
|
||||
let prefixSumDelta = 0;
|
||||
const pendingRemovalWhitespace: number[] = [];
|
||||
for (let i = 0; i < this.whitespaces.length; i++) {
|
||||
const whitespace = this.whitespaces[i];
|
||||
|
||||
if (whitespace.afterIndex < index) {
|
||||
continue;
|
||||
} else if (deleteRange.length > 0 && whitespace.afterIndex >= deleteRange[0] && whitespace.afterIndex <= deleteRange[1]) {
|
||||
// should be deleted
|
||||
pendingRemovalWhitespace.push(i);
|
||||
prefixSumDelta += whitespace.height;
|
||||
} else {
|
||||
whitespace.afterIndex += indexDelta;
|
||||
whitespace.prefixSum -= prefixSumDelta;
|
||||
}
|
||||
}
|
||||
|
||||
pendingRemovalWhitespace.reverse().forEach(index => {
|
||||
this.whitespaces.splice(index, 1);
|
||||
});
|
||||
}
|
||||
|
||||
public static findInsertionIndex(arr: ListWhitespace[], afterIndex: number): number {
|
||||
let low = 0;
|
||||
let high = arr.length;
|
||||
|
||||
while (low < high) {
|
||||
const mid = ((low + high) >>> 1);
|
||||
|
||||
if (afterIndex === arr[mid].afterIndex) {
|
||||
low = mid;
|
||||
break;
|
||||
} else if (afterIndex < arr[mid].afterIndex) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
insertWhitespace(afterIndex: number, height: number) {
|
||||
// TODO
|
||||
// 2. delay prefix sum update
|
||||
const insertIndex = RangeMap.findInsertionIndex(this.whitespaces, afterIndex);
|
||||
const prefixSum = insertIndex > 0 ? this.whitespaces[insertIndex - 1].prefixSum + height : height;
|
||||
const insertedItem = new ListWhitespace(afterIndex, height, prefixSum);
|
||||
this.whitespaces.splice(insertIndex, 0, insertedItem);
|
||||
|
||||
for (let i = insertIndex + 1; i < this.whitespaces.length; i++) {
|
||||
this.whitespaces[i].prefixSum += height;
|
||||
}
|
||||
}
|
||||
|
||||
// todo, allow multiple whitespaces after one index
|
||||
updateWhitespace(afterIndex: number, newHeight: number) {
|
||||
let delta = 0;
|
||||
let findWhitespace = false;
|
||||
for (let i = 0; i < this.whitespaces.length; i++) {
|
||||
if (this.whitespaces[i].afterIndex === afterIndex) {
|
||||
delta = newHeight - this.whitespaces[i].height;
|
||||
this.whitespaces[i].height = newHeight;
|
||||
this.whitespaces[i].prefixSum += delta;
|
||||
findWhitespace = true;
|
||||
} else if (this.whitespaces[i].afterIndex > afterIndex) {
|
||||
if (!findWhitespace) {
|
||||
this.insertWhitespace(afterIndex, newHeight);
|
||||
return;
|
||||
}
|
||||
this.whitespaces[i].prefixSum += delta;
|
||||
}
|
||||
}
|
||||
|
||||
if (!findWhitespace) {
|
||||
this.insertWhitespace(afterIndex, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -216,42 +124,7 @@ export class RangeMap {
|
||||
* Returns the sum of the sizes of all items in the range map.
|
||||
*/
|
||||
get size(): number {
|
||||
return this._size
|
||||
+ (this.whitespaces.length ? this.whitespaces[this.whitespaces.length - 1]?.prefixSum : 0);
|
||||
}
|
||||
|
||||
private _getWhitespaceAccumulatedHeightBeforeIndex(index: number): number {
|
||||
const lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeIndex(index);
|
||||
|
||||
if (lastWhitespaceBeforeLineNumber === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.whitespaces[lastWhitespaceBeforeLineNumber].prefixSum;
|
||||
}
|
||||
|
||||
private _findLastWhitespaceBeforeIndex(index: number): number {
|
||||
const arr = this.whitespaces;
|
||||
let low = 0;
|
||||
let high = arr.length - 1;
|
||||
|
||||
while (low <= high) {
|
||||
const delta = (high - low) | 0;
|
||||
const halfDelta = (delta / 2) | 0;
|
||||
const mid = (low + halfDelta) | 0;
|
||||
|
||||
if (arr[mid].afterIndex < index) {
|
||||
if (mid + 1 >= arr.length || arr[mid + 1].afterIndex >= index) {
|
||||
return mid;
|
||||
} else {
|
||||
low = (mid + 1) | 0;
|
||||
}
|
||||
} else {
|
||||
high = (mid - 1) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
return this._size;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -269,20 +142,7 @@ export class RangeMap {
|
||||
const count = group.range.end - group.range.start;
|
||||
const newSize = size + (count * group.size);
|
||||
|
||||
if (position < newSize + this._getWhitespaceAccumulatedHeightBeforeIndex(group.range.end + 1)) {
|
||||
// try to find the right index
|
||||
let currSize = size;
|
||||
// position > currSize + all whitespaces before current range
|
||||
for (let j = group.range.start; j < group.range.end; j++) {
|
||||
currSize = currSize + group.size;
|
||||
|
||||
if (position >= currSize + this._getWhitespaceAccumulatedHeightBeforeIndex(j + 1)) {
|
||||
continue;
|
||||
} else {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
if (position < newSize) {
|
||||
return index + Math.floor((position - size) / group.size);
|
||||
}
|
||||
|
||||
@@ -317,7 +177,7 @@ export class RangeMap {
|
||||
const newCount = count + groupCount;
|
||||
|
||||
if (index < newCount) {
|
||||
return position + ((index - count) * group.size) + this._getWhitespaceAccumulatedHeightBeforeIndex(index);
|
||||
return position + ((index - count) * group.size);
|
||||
}
|
||||
|
||||
position += groupCount * group.size;
|
||||
|
||||
@@ -24,6 +24,7 @@ import { CodeCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewMod
|
||||
import { MarkdownCellViewModel } from 'vs/workbench/contrib/notebook/browser/viewModel/markdownCellViewModel';
|
||||
import { FileService } from 'vs/platform/files/common/fileService';
|
||||
import { IFileService } from 'vs/platform/files/common/files';
|
||||
import { DiffComputer } from 'vs/editor/common/diff/diffComputer';
|
||||
|
||||
|
||||
export class NotebookDiffEditor extends BaseEditor {
|
||||
@@ -171,6 +172,47 @@ export class NotebookDiffEditor extends BaseEditor {
|
||||
]);
|
||||
});
|
||||
|
||||
// console.log(diffResult);
|
||||
|
||||
// diffResult.changes.forEach(change => {
|
||||
// if (change.modifiedLength === 0) {
|
||||
// // deletion ...
|
||||
// return;
|
||||
// }
|
||||
|
||||
// if (change.originalLength === 0) {
|
||||
// // insertion
|
||||
// return;
|
||||
// }
|
||||
|
||||
// for (let i = 0, len = Math.min(change.modifiedLength, change.originalLength); i < len; i++) {
|
||||
// let originalIndex = change.originalStart + i;
|
||||
// let modifiedIndex = change.modifiedStart + i;
|
||||
|
||||
// const originalCell = this._originalWidget!.viewModel!.viewCells[originalIndex];
|
||||
// const modifiedCell = this._widget!.viewModel!.viewCells[modifiedIndex];
|
||||
|
||||
// if (originalCell.getText() !== modifiedCell.getText()) {
|
||||
// console.log(`original cell ${originalIndex} content change`);
|
||||
// const originalLines = originalCell.textBuffer.getLinesContent();
|
||||
// const modifiedLines = modifiedCell.textBuffer.getLinesContent();
|
||||
// const diffComputer = new DiffComputer(originalLines, modifiedLines, {
|
||||
// shouldComputeCharChanges: true,
|
||||
// shouldPostProcessCharChanges: true,
|
||||
// shouldIgnoreTrimWhitespace: false,
|
||||
// shouldMakePrettyDiff: true,
|
||||
// maxComputationTime: 5000
|
||||
// });
|
||||
|
||||
// const diffResult = diffComputer.computeDiff();
|
||||
// console.log(diffResult);
|
||||
// } else {
|
||||
// console.log(`original cell ${originalIndex} metadata change`)
|
||||
// }
|
||||
|
||||
// }
|
||||
// });
|
||||
|
||||
this._originalCellDecorations = this._originalWidget.deltaCellDecorations(this._originalCellDecorations, originalDecorations);
|
||||
this._cellDecorations = this._widget.deltaCellDecorations(this._cellDecorations, modifiedDecorations);
|
||||
}
|
||||
|
||||
@@ -60,6 +60,7 @@ import { isMacintosh, isNative } from 'vs/base/common/platform';
|
||||
import { getTitleBarStyle } from 'vs/platform/windows/common/windows';
|
||||
import { IEnvironmentService } from 'vs/platform/environment/common/environment';
|
||||
import { CellDragAndDropController } from 'vs/workbench/contrib/notebook/browser/view/renderers/dnd';
|
||||
import { RangeMapWithWhitespace } from 'vs/workbench/contrib/notebook/browser/view/rangeMapWithWhitespace';
|
||||
|
||||
const $ = DOM.$;
|
||||
|
||||
@@ -413,6 +414,9 @@ export class NotebookEditorWidget extends Disposable implements INotebookEditor
|
||||
enableKeyboardNavigation: true,
|
||||
additionalScrollHeight: 0,
|
||||
transformOptimization: (isMacintosh && isNative) || getTitleBarStyle(this.configurationService, this.environmentService) === 'native',
|
||||
rangeMapProvider: () => {
|
||||
return new RangeMapWithWhitespace();
|
||||
},
|
||||
styleController: (_suffix: string) => { return this._list!; },
|
||||
overrideStyles: {
|
||||
listBackground: editorBackground,
|
||||
|
||||
@@ -0,0 +1,247 @@
|
||||
/*---------------------------------------------------------------------------------------------
|
||||
* Copyright (c) Microsoft Corporation. All rights reserved.
|
||||
* Licensed under the MIT License. See License.txt in the project root for license information.
|
||||
*--------------------------------------------------------------------------------------------*/
|
||||
|
||||
import { concat, groupIntersect, IItem, IRangedGroup, shift } from 'vs/base/browser/ui/list/rangeMap';
|
||||
|
||||
export class ListWhitespace {
|
||||
|
||||
constructor(
|
||||
public afterIndex: number,
|
||||
public height: number,
|
||||
// height of all whitespaces before this whitespace (inclusive)
|
||||
public prefixSum: number
|
||||
) { }
|
||||
}
|
||||
|
||||
// [ { start: 0, len: 2, size: 2 }, { start: 2, len: 1, size: 3 }, {} ]
|
||||
export class RangeMapWithWhitespace {
|
||||
|
||||
private groups: IRangedGroup[] = [];
|
||||
private whitespaces: ListWhitespace[] = [];
|
||||
private _size = 0;
|
||||
|
||||
splice(index: number, deleteCount: number, items: IItem[] = []): void {
|
||||
const diff = items.length - deleteCount;
|
||||
const before = groupIntersect({ start: 0, end: index }, this.groups);
|
||||
const after = groupIntersect({ start: index + deleteCount, end: Number.POSITIVE_INFINITY }, this.groups)
|
||||
.map<IRangedGroup>(g => ({ range: shift(g.range, diff), size: g.size }));
|
||||
|
||||
const middle = items.map<IRangedGroup>((item, i) => ({
|
||||
range: { start: index + i, end: index + i + 1 },
|
||||
size: item.size
|
||||
}));
|
||||
|
||||
this.groups = concat(before, middle, after);
|
||||
this._size = this.groups.reduce((t, g) => t + (g.size * (g.range.end - g.range.start)), 0);
|
||||
|
||||
const deleteRange = deleteCount > 0 ? [index, index + deleteCount - 1] : [];
|
||||
const indexDelta = items.length - deleteCount;
|
||||
let prefixSumDelta = 0;
|
||||
const pendingRemovalWhitespace: number[] = [];
|
||||
for (let i = 0; i < this.whitespaces.length; i++) {
|
||||
const whitespace = this.whitespaces[i];
|
||||
|
||||
if (whitespace.afterIndex < index) {
|
||||
continue;
|
||||
} else if (deleteRange.length > 0 && whitespace.afterIndex >= deleteRange[0] && whitespace.afterIndex <= deleteRange[1]) {
|
||||
// should be deleted
|
||||
pendingRemovalWhitespace.push(i);
|
||||
prefixSumDelta += whitespace.height;
|
||||
} else {
|
||||
whitespace.afterIndex += indexDelta;
|
||||
whitespace.prefixSum -= prefixSumDelta;
|
||||
}
|
||||
}
|
||||
|
||||
pendingRemovalWhitespace.reverse().forEach(index => {
|
||||
this.whitespaces.splice(index, 1);
|
||||
});
|
||||
}
|
||||
|
||||
public static findInsertionIndex(arr: ListWhitespace[], afterIndex: number): number {
|
||||
let low = 0;
|
||||
let high = arr.length;
|
||||
|
||||
while (low < high) {
|
||||
const mid = ((low + high) >>> 1);
|
||||
|
||||
if (afterIndex === arr[mid].afterIndex) {
|
||||
low = mid;
|
||||
break;
|
||||
} else if (afterIndex < arr[mid].afterIndex) {
|
||||
high = mid;
|
||||
} else {
|
||||
low = mid + 1;
|
||||
}
|
||||
}
|
||||
|
||||
return low;
|
||||
}
|
||||
|
||||
insertWhitespace(afterIndex: number, height: number) {
|
||||
// TODO
|
||||
// 2. delay prefix sum update
|
||||
const insertIndex = RangeMapWithWhitespace.findInsertionIndex(this.whitespaces, afterIndex);
|
||||
const prefixSum = insertIndex > 0 ? this.whitespaces[insertIndex - 1].prefixSum + height : height;
|
||||
const insertedItem = new ListWhitespace(afterIndex, height, prefixSum);
|
||||
this.whitespaces.splice(insertIndex, 0, insertedItem);
|
||||
|
||||
for (let i = insertIndex + 1; i < this.whitespaces.length; i++) {
|
||||
this.whitespaces[i].prefixSum += height;
|
||||
}
|
||||
}
|
||||
|
||||
// todo, allow multiple whitespaces after one index
|
||||
updateWhitespace(afterIndex: number, newHeight: number) {
|
||||
let delta = 0;
|
||||
let findWhitespace = false;
|
||||
for (let i = 0; i < this.whitespaces.length; i++) {
|
||||
if (this.whitespaces[i].afterIndex === afterIndex) {
|
||||
delta = newHeight - this.whitespaces[i].height;
|
||||
this.whitespaces[i].height = newHeight;
|
||||
this.whitespaces[i].prefixSum += delta;
|
||||
findWhitespace = true;
|
||||
} else if (this.whitespaces[i].afterIndex > afterIndex) {
|
||||
if (!findWhitespace) {
|
||||
this.insertWhitespace(afterIndex, newHeight);
|
||||
return;
|
||||
}
|
||||
this.whitespaces[i].prefixSum += delta;
|
||||
}
|
||||
}
|
||||
|
||||
if (!findWhitespace) {
|
||||
this.insertWhitespace(afterIndex, newHeight);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the number of items in the range map.
|
||||
*/
|
||||
get count(): number {
|
||||
const len = this.groups.length;
|
||||
|
||||
if (!len) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.groups[len - 1].range.end;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the sum of the sizes of all items in the range map.
|
||||
*/
|
||||
get size(): number {
|
||||
return this._size
|
||||
+ (this.whitespaces.length ? this.whitespaces[this.whitespaces.length - 1]?.prefixSum : 0);
|
||||
}
|
||||
|
||||
private _getWhitespaceAccumulatedHeightBeforeIndex(index: number): number {
|
||||
const lastWhitespaceBeforeLineNumber = this._findLastWhitespaceBeforeIndex(index);
|
||||
|
||||
if (lastWhitespaceBeforeLineNumber === -1) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
return this.whitespaces[lastWhitespaceBeforeLineNumber].prefixSum;
|
||||
}
|
||||
|
||||
private _findLastWhitespaceBeforeIndex(index: number): number {
|
||||
const arr = this.whitespaces;
|
||||
let low = 0;
|
||||
let high = arr.length - 1;
|
||||
|
||||
while (low <= high) {
|
||||
const delta = (high - low) | 0;
|
||||
const halfDelta = (delta / 2) | 0;
|
||||
const mid = (low + halfDelta) | 0;
|
||||
|
||||
if (arr[mid].afterIndex < index) {
|
||||
if (mid + 1 >= arr.length || arr[mid + 1].afterIndex >= index) {
|
||||
return mid;
|
||||
} else {
|
||||
low = (mid + 1) | 0;
|
||||
}
|
||||
} else {
|
||||
high = (mid - 1) | 0;
|
||||
}
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the item at the given position.
|
||||
*/
|
||||
indexAt(position: number): number {
|
||||
if (position < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let index = 0;
|
||||
let size = 0;
|
||||
|
||||
for (let group of this.groups) {
|
||||
const count = group.range.end - group.range.start;
|
||||
const newSize = size + (count * group.size);
|
||||
|
||||
if (position < newSize + this._getWhitespaceAccumulatedHeightBeforeIndex(group.range.end + 1)) {
|
||||
// try to find the right index
|
||||
let currSize = size;
|
||||
// position > currSize + all whitespaces before current range
|
||||
for (let j = group.range.start; j < group.range.end; j++) {
|
||||
currSize = currSize + group.size;
|
||||
|
||||
if (position >= currSize + this._getWhitespaceAccumulatedHeightBeforeIndex(j + 1)) {
|
||||
continue;
|
||||
} else {
|
||||
return j;
|
||||
}
|
||||
}
|
||||
|
||||
return index + Math.floor((position - size) / group.size);
|
||||
}
|
||||
|
||||
index += count;
|
||||
size = newSize;
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the index of the item right after the item at the
|
||||
* index of the given position.
|
||||
*/
|
||||
indexAfter(position: number): number {
|
||||
return Math.min(this.indexAt(position) + 1, this.count);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the start position of the item at the given index.
|
||||
*/
|
||||
positionAt(index: number): number {
|
||||
if (index < 0) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
let position = 0;
|
||||
let count = 0;
|
||||
|
||||
for (let group of this.groups) {
|
||||
const groupCount = group.range.end - group.range.start;
|
||||
const newCount = count + groupCount;
|
||||
|
||||
if (index < newCount) {
|
||||
return position + ((index - count) * group.size) + this._getWhitespaceAccumulatedHeightBeforeIndex(index);
|
||||
}
|
||||
|
||||
position += groupCount * group.size;
|
||||
count = newCount;
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
@@ -108,8 +108,8 @@ export class NotebookCellTextModel extends Disposable implements ICell {
|
||||
return this._hash;
|
||||
}
|
||||
|
||||
// this._hash = hash([hash(this.getValue()), this._metadata]);
|
||||
this._hash = hash(this.getValue());
|
||||
this._hash = hash([hash(this.getValue()), this._metadata]);
|
||||
// this._hash = hash(this.getValue());
|
||||
return this._hash;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user