Merge branch 'master' into master
This commit is contained in:
+5
-2
@@ -3,7 +3,6 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { isNode } from 'common/Platform';
|
||||
import { IColor, IColorRGB } from 'common/Types';
|
||||
|
||||
let $r = 0;
|
||||
@@ -117,9 +116,10 @@ export namespace color {
|
||||
* '#rrggbbaa').
|
||||
*/
|
||||
export namespace css {
|
||||
// Attempt to set get the shared canvas context
|
||||
let $ctx: CanvasRenderingContext2D | undefined;
|
||||
let $litmusColor: CanvasGradient | undefined;
|
||||
if (!isNode) {
|
||||
try {
|
||||
// This is guaranteed to run in the first window, so document should be correct
|
||||
const canvas = document.createElement('canvas');
|
||||
canvas.width = 1;
|
||||
@@ -133,6 +133,9 @@ export namespace css {
|
||||
$litmusColor = $ctx.createLinearGradient(0, 0, 1, 1);
|
||||
}
|
||||
}
|
||||
catch {
|
||||
// noop
|
||||
}
|
||||
|
||||
/**
|
||||
* Converts a css string to an IColor, this should handle all valid CSS color strings and will
|
||||
|
||||
@@ -2979,7 +2979,7 @@ export class InputHandler extends Disposable implements IInputHandler {
|
||||
if (args[1]) {
|
||||
return this._createHyperlink(args[0], args[1]);
|
||||
}
|
||||
if (args[0]) {
|
||||
if (args[0].trim()) {
|
||||
return false;
|
||||
}
|
||||
return this._finishHyperlink();
|
||||
|
||||
@@ -14,7 +14,7 @@ interface INavigator {
|
||||
declare const navigator: INavigator;
|
||||
declare const process: unknown;
|
||||
|
||||
export const isNode = (typeof process !== 'undefined') ? true : false;
|
||||
export const isNode = (typeof process !== 'undefined' && 'title' in (process as any)) ? true : false;
|
||||
const userAgent = (isNode) ? 'node' : navigator.userAgent;
|
||||
const platform = (isNode) ? 'node' : navigator.platform;
|
||||
|
||||
|
||||
+86
-10
@@ -3,16 +3,27 @@
|
||||
* @license MIT
|
||||
*/
|
||||
|
||||
import { IdleTaskQueue } from 'common/TaskQueue';
|
||||
|
||||
// Work variables to avoid garbage collection.
|
||||
let i = 0;
|
||||
|
||||
/**
|
||||
* A generic list that is maintained in sorted order and allows values with duplicate keys. This
|
||||
* list is based on binary search and as such locating a key will take O(log n) amortized, this
|
||||
* includes the by key iterator.
|
||||
* A generic list that is maintained in sorted order and allows values with duplicate keys. Deferred
|
||||
* batch insertion and deletion is used to significantly reduce the time it takes to insert and
|
||||
* delete a large amount of items in succession. This list is based on binary search and as such
|
||||
* locating a key will take O(log n) amortized, this includes the by key iterator.
|
||||
*/
|
||||
export class SortedList<T> {
|
||||
private readonly _array: T[] = [];
|
||||
private _array: T[] = [];
|
||||
|
||||
private readonly _insertedValues: T[] = [];
|
||||
private readonly _flushInsertedTask = new IdleTaskQueue();
|
||||
private _isFlushingInserted = false;
|
||||
|
||||
private readonly _deletedIndices: number[] = [];
|
||||
private readonly _flushDeletedTask = new IdleTaskQueue();
|
||||
private _isFlushingDeleted = false;
|
||||
|
||||
constructor(
|
||||
private readonly _getKey: (value: T) => number
|
||||
@@ -21,18 +32,50 @@ export class SortedList<T> {
|
||||
|
||||
public clear(): void {
|
||||
this._array.length = 0;
|
||||
this._insertedValues.length = 0;
|
||||
this._flushInsertedTask.clear();
|
||||
this._isFlushingInserted = false;
|
||||
this._deletedIndices.length = 0;
|
||||
this._flushDeletedTask.clear();
|
||||
this._isFlushingDeleted = false;
|
||||
}
|
||||
|
||||
public insert(value: T): void {
|
||||
if (this._array.length === 0) {
|
||||
this._array.push(value);
|
||||
return;
|
||||
this._flushCleanupDeleted();
|
||||
if (this._insertedValues.length === 0) {
|
||||
this._flushInsertedTask.enqueue(() => this._flushInserted());
|
||||
}
|
||||
this._insertedValues.push(value);
|
||||
}
|
||||
|
||||
private _flushInserted(): void {
|
||||
const sortedAddedValues = this._insertedValues.sort((a, b) => this._getKey(a) - this._getKey(b));
|
||||
let sortedAddedValuesIndex = 0;
|
||||
let arrayIndex = 0;
|
||||
|
||||
const newArray = new Array(this._array.length + this._insertedValues.length);
|
||||
|
||||
for (let newArrayIndex = 0; newArrayIndex < newArray.length; newArrayIndex++) {
|
||||
if (arrayIndex >= this._array.length || this._getKey(sortedAddedValues[sortedAddedValuesIndex]) <= this._getKey(this._array[arrayIndex])) {
|
||||
newArray[newArrayIndex] = sortedAddedValues[sortedAddedValuesIndex];
|
||||
sortedAddedValuesIndex++;
|
||||
} else {
|
||||
newArray[newArrayIndex] = this._array[arrayIndex++];
|
||||
}
|
||||
}
|
||||
|
||||
this._array = newArray;
|
||||
this._insertedValues.length = 0;
|
||||
}
|
||||
|
||||
private _flushCleanupInserted(): void {
|
||||
if (!this._isFlushingInserted && this._insertedValues.length > 0) {
|
||||
this._flushInsertedTask.flush();
|
||||
}
|
||||
i = this._search(this._getKey(value));
|
||||
this._array.splice(i, 0, value);
|
||||
}
|
||||
|
||||
public delete(value: T): boolean {
|
||||
this._flushCleanupInserted();
|
||||
if (this._array.length === 0) {
|
||||
return false;
|
||||
}
|
||||
@@ -49,14 +92,43 @@ export class SortedList<T> {
|
||||
}
|
||||
do {
|
||||
if (this._array[i] === value) {
|
||||
this._array.splice(i, 1);
|
||||
if (this._deletedIndices.length === 0) {
|
||||
this._flushDeletedTask.enqueue(() => this._flushDeleted());
|
||||
}
|
||||
this._deletedIndices.push(i);
|
||||
return true;
|
||||
}
|
||||
} while (++i < this._array.length && this._getKey(this._array[i]) === key);
|
||||
return false;
|
||||
}
|
||||
|
||||
private _flushDeleted(): void {
|
||||
this._isFlushingDeleted = true;
|
||||
const sortedDeletedIndices = this._deletedIndices.sort((a, b) => a - b);
|
||||
let sortedDeletedIndicesIndex = 0;
|
||||
const newArray = new Array(this._array.length - sortedDeletedIndices.length);
|
||||
let newArrayIndex = 0;
|
||||
for (let i = 0; i < this._array.length; i++) {
|
||||
if (sortedDeletedIndices[sortedDeletedIndicesIndex] === i) {
|
||||
sortedDeletedIndicesIndex++;
|
||||
} else {
|
||||
newArray[newArrayIndex++] = this._array[i];
|
||||
}
|
||||
}
|
||||
this._array = newArray;
|
||||
this._deletedIndices.length = 0;
|
||||
this._isFlushingDeleted = false;
|
||||
}
|
||||
|
||||
private _flushCleanupDeleted(): void {
|
||||
if (!this._isFlushingDeleted && this._deletedIndices.length > 0) {
|
||||
this._flushDeletedTask.flush();
|
||||
}
|
||||
}
|
||||
|
||||
public *getKeyIterator(key: number): IterableIterator<T> {
|
||||
this._flushCleanupInserted();
|
||||
this._flushCleanupDeleted();
|
||||
if (this._array.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -73,6 +145,8 @@ export class SortedList<T> {
|
||||
}
|
||||
|
||||
public forEachByKey(key: number, callback: (value: T) => void): void {
|
||||
this._flushCleanupInserted();
|
||||
this._flushCleanupDeleted();
|
||||
if (this._array.length === 0) {
|
||||
return;
|
||||
}
|
||||
@@ -89,6 +163,8 @@ export class SortedList<T> {
|
||||
}
|
||||
|
||||
public values(): IterableIterator<T> {
|
||||
this._flushCleanupInserted();
|
||||
this._flushCleanupDeleted();
|
||||
// Duplicate the array to avoid issues when _array changes while iterating
|
||||
return [...this._array].values();
|
||||
}
|
||||
|
||||
@@ -45,7 +45,8 @@ export class DecorationService extends Disposable implements IDecorationService
|
||||
const decoration = new Decoration(options);
|
||||
if (decoration) {
|
||||
const markerDispose = decoration.marker.onDispose(() => decoration.dispose());
|
||||
decoration.onDispose(() => {
|
||||
const listener = decoration.onDispose(() => {
|
||||
listener.dispose();
|
||||
if (decoration) {
|
||||
if (this._decorations.delete(decoration)) {
|
||||
this._onDecorationRemoved.fire(decoration);
|
||||
|
||||
Reference in New Issue
Block a user