提交 7475ded2 编写于 作者: R rebornix

💄

上级 14de6bab
......@@ -4,13 +4,11 @@
*--------------------------------------------------------------------------------------------*/
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';
......@@ -86,9 +84,9 @@ export class NotebookCellTextDiffListDelegate implements IListVirtualDelegate<Ce
// private readonly lineHeight: number;
constructor(
@IConfigurationService private readonly configurationService: IConfigurationService
@IConfigurationService readonly configurationService: IConfigurationService
) {
const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
// const editorOptions = this.configurationService.getValue<IEditorOptions>('editor');
// this.lineHeight = BareFontInfo.createFromRawSettings(editorOptions, getZoomLevel()).lineHeight;
}
......
/*---------------------------------------------------------------------------------------------
* Copyright (c) Microsoft Corporation. All rights reserved.
* Licensed under the MIT License. See License.txt in the project root for license information.
*--------------------------------------------------------------------------------------------*/
import { consolidate, groupIntersect, IItem, IRangedGroup, RangeMap, 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
) { }
}
function concat(...groups: IRangedGroup[][]): IRangedGroup[] {
return consolidate(groups.reduce((r, g) => r.concat(g), []));
}
// [ { start: 0, len: 10, size: 100 } ]
// [ { start: 0, len: 5, size: 100 }, { start: 5, len: 1, size: 200 }, { start: 6, len: 5, size: 100 } ]
// [ { afterIndex: 0, height: 20 }, { afterIndex: 2, height: 20 } ]
// 0: 0
// 1: 100 + 20
// 2: 100*2 + 20
// 3: 100*3 + 20 + 20
// [ { start: 0, len: 2, size: 2 }, { start: 2, len: 1, size: 3 }, {} ]
export class RangeMapWithWhitespace extends RangeMap {
private rangeGroups: IRangedGroup[] = [];
private whitespaces: ListWhitespace[] = [];
private _mapSize = 0;
constructor() {
super();
}
splice(index: number, deleteCount: number, items: IItem[] = []): void {
const diff = items.length - deleteCount;
const before = groupIntersect({ start: 0, end: index }, this.rangeGroups);
const after = groupIntersect({ start: index + deleteCount, end: Number.POSITIVE_INFINITY }, this.rangeGroups)
.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.rangeGroups = concat(before, middle, after);
this._mapSize = this.rangeGroups.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.rangeGroups.length;
if (!len) {
return 0;
}
return this.rangeGroups[len - 1].range.end;
}
/**
* Returns the sum of the sizes of all items in the range map.
*/
get size(): number {
return this._mapSize
+ (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.rangeGroups) {
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.rangeGroups) {
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;
}
}
......@@ -8,7 +8,6 @@ import { NOTEBOOK_DISPLAY_ORDER, sortMimeTypes, CellKind, diff, CellUri } from '
import { TestCell, setupInstantiationService } from 'vs/workbench/contrib/notebook/test/testNotebookEditor';
import { URI } from 'vs/base/common/uri';
import { ITextModelService } from 'vs/editor/common/services/resolverService';
import { RangeMapWithWhitespace } from 'vs/workbench/contrib/notebook/browser/view/rangeMapWithWhitespace';
suite('NotebookCommon', () => {
const instantiationService = setupInstantiationService();
......@@ -356,172 +355,3 @@ suite('CellUri', function () {
assert.equal(actual?.notebook.toString(), nb.toString());
});
});
suite('RangeMap', () => {
let rangeMap: RangeMapWithWhitespace;
setup(() => {
rangeMap = new RangeMapWithWhitespace();
});
const one = { size: 1 };
const two = { size: 2 };
const three = { size: 3 };
test('insert whitespace 1', () => {
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(5), 5);
assert.equal(rangeMap.indexAt(9), 9);
assert.equal(rangeMap.indexAt(10), 10);
assert.equal(rangeMap.indexAt(11), 10);
for (let i = 0; i < 10; i++) {
rangeMap.insertWhitespace(i, 1);
}
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 0);
assert.equal(rangeMap.indexAt(2), 1);
assert.equal(rangeMap.indexAt(3), 1);
assert.equal(rangeMap.indexAt(4), 2);
assert.equal(rangeMap.indexAt(5), 2);
assert.equal(rangeMap.indexAt(6), 3);
assert.equal(rangeMap.indexAt(7), 3);
assert.equal(rangeMap.indexAt(8), 4);
assert.equal(rangeMap.indexAt(9), 4);
});
test('insert whitespace 2', () => {
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(5), 5);
assert.equal(rangeMap.indexAt(9), 9);
assert.equal(rangeMap.indexAt(10), 10);
assert.equal(rangeMap.indexAt(11), 10);
rangeMap.insertWhitespace(0, 2);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 0);
assert.equal(rangeMap.indexAt(2), 0);
assert.equal(rangeMap.indexAt(3), 1);
assert.equal(rangeMap.indexAt(4), 2);
assert.equal(rangeMap.indexAt(5), 3);
assert.equal(rangeMap.indexAt(10), 8);
rangeMap.insertWhitespace(3, 3);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 0);
assert.equal(rangeMap.indexAt(2), 0);
assert.equal(rangeMap.indexAt(3), 1);
assert.equal(rangeMap.indexAt(4), 2);
assert.equal(rangeMap.indexAt(5), 3);
assert.equal(rangeMap.indexAt(6), 3);
assert.equal(rangeMap.indexAt(7), 3);
assert.equal(rangeMap.indexAt(8), 3);
assert.equal(rangeMap.indexAt(9), 4);
assert.equal(rangeMap.indexAt(10), 5);
});
test('insert whitespace 3', () => {
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(5), 5);
assert.equal(rangeMap.indexAt(9), 9);
assert.equal(rangeMap.indexAt(10), 10);
assert.equal(rangeMap.indexAt(11), 10);
rangeMap.insertWhitespace(0, 2);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 0);
assert.equal(rangeMap.indexAt(2), 0);
assert.equal(rangeMap.indexAt(3), 1);
assert.equal(rangeMap.indexAt(4), 2);
assert.equal(rangeMap.indexAt(5), 3);
assert.equal(rangeMap.indexAt(10), 8);
rangeMap.insertWhitespace(3, 3);
rangeMap.updateWhitespace(0, 3);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 0);
assert.equal(rangeMap.indexAt(2), 0);
assert.equal(rangeMap.indexAt(3), 0);
assert.equal(rangeMap.indexAt(4), 1);
assert.equal(rangeMap.indexAt(5), 2);
assert.equal(rangeMap.indexAt(6), 3);
assert.equal(rangeMap.indexAt(7), 3);
assert.equal(rangeMap.indexAt(8), 3);
assert.equal(rangeMap.indexAt(9), 3);
assert.equal(rangeMap.indexAt(10), 4);
});
test('insert whitespace, positionAt', () => {
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 1);
assert.equal(rangeMap.positionAt(5), 5);
assert.equal(rangeMap.positionAt(9), 9);
rangeMap.insertWhitespace(0, 2);
assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 3);
assert.equal(rangeMap.positionAt(2), 4);
assert.equal(rangeMap.positionAt(3), 5);
});
test('insert whitespace, positionAt 2', () => {
rangeMap.splice(0, 0, [one]);
rangeMap.splice(1, 0, [two]);
rangeMap.splice(2, 0, [three]);
assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 1);
assert.equal(rangeMap.positionAt(2), 3);
rangeMap.insertWhitespace(0, 2);
assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 3);
assert.equal(rangeMap.positionAt(2), 5);
});
test('update whitespace when range map splices', () => {
rangeMap.splice(0, 0, [one, one, one, one, one, one, one, one, one, one]);
rangeMap.insertWhitespace(1, 2);
rangeMap.insertWhitespace(5, 3);
assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 1);
assert.equal(rangeMap.positionAt(2), 4);
assert.equal(rangeMap.positionAt(3), 5);
assert.equal(rangeMap.positionAt(4), 6);
assert.equal(rangeMap.positionAt(5), 7);
assert.equal(rangeMap.positionAt(6), 11);
assert.equal(rangeMap.positionAt(7), 12);
assert.equal(rangeMap.positionAt(8), 13);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(2), 1);
assert.equal(rangeMap.indexAt(3), 1);
assert.equal(rangeMap.indexAt(4), 2);
rangeMap.splice(1, 2);
assert.equal(rangeMap.positionAt(0), 0);
assert.equal(rangeMap.positionAt(1), 1);
assert.equal(rangeMap.positionAt(2), 2);
assert.equal(rangeMap.positionAt(3), 3);
assert.equal(rangeMap.positionAt(4), 7);
assert.equal(rangeMap.positionAt(5), 8);
assert.equal(rangeMap.positionAt(6), 9);
assert.equal(rangeMap.indexAt(0), 0);
assert.equal(rangeMap.indexAt(1), 1);
assert.equal(rangeMap.indexAt(2), 2);
assert.equal(rangeMap.indexAt(3), 3);
assert.equal(rangeMap.indexAt(4), 3);
});
});
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册