Skip to content

Commit

Permalink
fix #7269: complete support vscode.workspace.fs API
Browse files Browse the repository at this point in the history
Signed-off-by: Anton Kosyakov <[email protected]>
  • Loading branch information
akosyakov committed Jun 3, 2020
1 parent 99a7aa3 commit b80c7a9
Show file tree
Hide file tree
Showing 40 changed files with 5,670 additions and 1,473 deletions.
71 changes: 68 additions & 3 deletions packages/core/src/common/event.ts
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@

import { Disposable } from './disposable';
import { MaybePromise } from './types';
import { CancellationToken } from './cancellation';

/**
* Represents a typed event.
Expand Down Expand Up @@ -152,7 +153,7 @@ export class Emitter<T = any> {
private static _noop = function (): void { };

private _event: Event<T>;
private _callbacks: CallbackList | undefined;
protected _callbacks: CallbackList | undefined;
private _disposed = false;

private _leakingStacks: Map<string, number> | undefined;
Expand Down Expand Up @@ -199,8 +200,8 @@ export class Emitter<T = any> {

return result;
}, {
maxListeners: Emitter.LEAK_WARNING_THRESHHOLD
}
maxListeners: Emitter.LEAK_WARNING_THRESHHOLD
}
);
}
return this._event;
Expand Down Expand Up @@ -308,6 +309,9 @@ export interface WaitUntilEvent {
/* eslint-enable @typescript-eslint/no-explicit-any */
}
export namespace WaitUntilEvent {
/**
* Fire all listeners in the same tick.
*/
export async function fire<T extends WaitUntilEvent>(
emitter: Emitter<T>,
event: Pick<T, Exclude<keyof T, 'waitUntil'>>,
Expand Down Expand Up @@ -339,4 +343,65 @@ export namespace WaitUntilEvent {
await Promise.all(waitables);
}
}
/**
* Fire listeners async one after another.
*/
export function fireAsync<T extends WaitUntilEvent>(
emitter: Emitter<T>,
event: Pick<T, Exclude<keyof T, 'waitUntil'>>,
token: CancellationToken,
// eslint-disable-next-line @typescript-eslint/no-explicit-any
promiseJoin?: (p: Promise<any>, listener: Function) => Promise<any>
): MaybePromise<void> {
const callbacks = emitter['_callbacks'];
if (!callbacks) {
return;
}
const listeners = [...callbacks];
const deliver = async () => {
for (const listener of listeners) {
if (token.isCancellationRequested) {
return;
}
const waitables: Promise<void>[] = [];
const asyncEvent = Object.assign(event, {
// eslint-disable-next-line @typescript-eslint/no-explicit-any
waitUntil: (thenable: Promise<any>) => {
if (Object.isFrozen(waitables)) {
throw new Error('waitUntil cannot be called asynchronously.');
}
if (promiseJoin) {
thenable = promiseJoin(thenable, listener);
}
waitables.push(thenable);
}
}) as T;
try {
listener(event);
// Asynchronous calls to `waitUntil` should fail.
Object.freeze(waitables);
} catch (e) {
console.error(e);
} finally {
delete asyncEvent['waitUntil'];
}
if (!waitables.length) {
return;
}
try {
await Promise.all(waitables);
} catch (e) {
console.error(e);
}
}
};
interface AsyncEmitter<T> extends Emitter<T> {
deliveryQueue?: Promise<void>
}
const asyncEmitter: AsyncEmitter<T> = emitter;
if (asyncEmitter.deliveryQueue) {
return asyncEmitter.deliveryQueue = asyncEmitter.deliveryQueue.then(deliver);
}
return asyncEmitter.deliveryQueue = deliver();
}
}
241 changes: 241 additions & 0 deletions packages/languages/src/common/language-selector/strings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
*--------------------------------------------------------------------------------------------*/

import { CharCode } from './char-code';
import { Constants } from './uint';
/**
* Determines if haystack ends with needle.
*/
Expand Down Expand Up @@ -89,6 +90,23 @@ function doEqualsIgnoreCase(a: string, b: string, stopAt = a.length): boolean {
return true;
}

/**
* @returns the length of the common prefix of the two strings.
*/
export function commonPrefixLength(a: string, b: string): number {

let i: number;
const len = Math.min(a.length, b.length);

for (i = 0; i < len; i++) {
if (a.charCodeAt(i) !== b.charCodeAt(i)) {
return i;
}
}

return len;
}

/**
* Escapes regular expression characters in a given string
*/
Expand Down Expand Up @@ -125,3 +143,226 @@ export function escapeInvisibleChars(value: string): string {
export function unescapeInvisibleChars(value: string): string {
return value.replace(/\\n/g, '\n').replace(/\\r/g, '\r');
}

export function compare(a: string, b: string): number {
if (a < b) {
return -1;
} else if (a > b) {
return 1;
} else {
return 0;
}
}

export function compareSubstring(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {
for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {
const codeA = a.charCodeAt(aStart);
const codeB = b.charCodeAt(bStart);
if (codeA < codeB) {
return -1;
} else if (codeA > codeB) {
return 1;
}
}
const aLen = aEnd - aStart;
const bLen = bEnd - bStart;
if (aLen < bLen) {
return -1;
} else if (aLen > bLen) {
return 1;
}
return 0;
}

export function compareIgnoreCase(a: string, b: string): number {
return compareSubstringIgnoreCase(a, b, 0, a.length, 0, b.length);
}

export function compareSubstringIgnoreCase(a: string, b: string, aStart: number = 0, aEnd: number = a.length, bStart: number = 0, bEnd: number = b.length): number {

for (; aStart < aEnd && bStart < bEnd; aStart++, bStart++) {

const codeA = a.charCodeAt(aStart);
const codeB = b.charCodeAt(bStart);

if (codeA === codeB) {
// equal
continue;
}

const diff = codeA - codeB;
if (diff === 32 && isUpperAsciiLetter(codeB)) { // codeB =[65-90] && codeA =[97-122]
continue;

} else if (diff === -32 && isUpperAsciiLetter(codeA)) { // codeB =[97-122] && codeA =[65-90]
continue;
}

if (isLowerAsciiLetter(codeA) && isLowerAsciiLetter(codeB)) {
//
return diff;

} else {
return compareSubstring(a.toLowerCase(), b.toLowerCase(), aStart, aEnd, bStart, bEnd);
}
}

const aLen = aEnd - aStart;
const bLen = bEnd - bStart;

if (aLen < bLen) {
return -1;
} else if (aLen > bLen) {
return 1;
}

return 0;
}

/**
* See http://en.wikipedia.org/wiki/Surrogate_pair
*/
export function isHighSurrogate(charCode: number): boolean {
return (0xD800 <= charCode && charCode <= 0xDBFF);
}

/**
* See http://en.wikipedia.org/wiki/Surrogate_pair
*/
export function isLowSurrogate(charCode: number): boolean {
return (0xDC00 <= charCode && charCode <= 0xDFFF);
}

/**
* See http://en.wikipedia.org/wiki/Surrogate_pair
*/
export function computeCodePoint(highSurrogate: number, lowSurrogate: number): number {
return ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000;
}

/**
* get the code point that begins at offset `offset`
*/
export function getNextCodePoint(str: string, len: number, offset: number): number {
const charCode = str.charCodeAt(offset);
if (isHighSurrogate(charCode) && offset + 1 < len) {
const nextCharCode = str.charCodeAt(offset + 1);
if (isLowSurrogate(nextCharCode)) {
return computeCodePoint(charCode, nextCharCode);
}
}
return charCode;
}

/**
* A manual encoding of `str` to UTF8.
* Use only in environments which do not offer native conversion methods!
*/
export function encodeUTF8(str: string): Uint8Array {
const strLen = str.length;

// See https://en.wikipedia.org/wiki/UTF-8

// first loop to establish needed buffer size
let neededSize = 0;
let strOffset = 0;
while (strOffset < strLen) {
const codePoint = getNextCodePoint(str, strLen, strOffset);
strOffset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);

if (codePoint < 0x0080) {
neededSize += 1;
} else if (codePoint < 0x0800) {
neededSize += 2;
} else if (codePoint < 0x10000) {
neededSize += 3;
} else {
neededSize += 4;
}
}

// second loop to actually encode
const arr = new Uint8Array(neededSize);
strOffset = 0;
let arrOffset = 0;
while (strOffset < strLen) {
const codePoint = getNextCodePoint(str, strLen, strOffset);
strOffset += (codePoint >= Constants.UNICODE_SUPPLEMENTARY_PLANE_BEGIN ? 2 : 1);

if (codePoint < 0x0080) {
arr[arrOffset++] = codePoint;
} else if (codePoint < 0x0800) {
arr[arrOffset++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6);
arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);
} else if (codePoint < 0x10000) {
arr[arrOffset++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12);
arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);
arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);
} else {
arr[arrOffset++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18);
arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12);
arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6);
arr[arrOffset++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0);
}
}

return arr;
}

/**
* A manual decoding of a UTF8 string.
* Use only in environments which do not offer native conversion methods!
*/
export function decodeUTF8(buffer: Uint8Array): string {
// https://en.wikipedia.org/wiki/UTF-8

const len = buffer.byteLength;
const result: string[] = [];
let offset = 0;
while (offset < len) {
const v0 = buffer[offset];
let codePoint: number;
if (v0 >= 0b11110000 && offset + 3 < len) {
// 4 bytes
codePoint = (
(((buffer[offset++] & 0b00000111) << 18) >>> 0)
| (((buffer[offset++] & 0b00111111) << 12) >>> 0)
| (((buffer[offset++] & 0b00111111) << 6) >>> 0)
| (((buffer[offset++] & 0b00111111) << 0) >>> 0)
);
} else if (v0 >= 0b11100000 && offset + 2 < len) {
// 3 bytes
codePoint = (
(((buffer[offset++] & 0b00001111) << 12) >>> 0)
| (((buffer[offset++] & 0b00111111) << 6) >>> 0)
| (((buffer[offset++] & 0b00111111) << 0) >>> 0)
);
} else if (v0 >= 0b11000000 && offset + 1 < len) {
// 2 bytes
codePoint = (
(((buffer[offset++] & 0b00011111) << 6) >>> 0)
| (((buffer[offset++] & 0b00111111) << 0) >>> 0)
);
} else {
// 1 byte
codePoint = buffer[offset++];
}

if ((codePoint >= 0 && codePoint <= 0xD7FF) || (codePoint >= 0xE000 && codePoint <= 0xFFFF)) {
// Basic Multilingual Plane
result.push(String.fromCharCode(codePoint));
} else if (codePoint >= 0x010000 && codePoint <= 0x10FFFF) {
// Supplementary Planes
const uPrime = codePoint - 0x10000;
const w1 = 0xD800 + ((uPrime & 0b11111111110000000000) >>> 10);
const w2 = 0xDC00 + ((uPrime & 0b00000000001111111111) >>> 0);
result.push(String.fromCharCode(w1));
result.push(String.fromCharCode(w2));
} else {
// illegal code point
result.push(String.fromCharCode(0xFFFD));
}
}

return result.join('');
}
Loading

0 comments on commit b80c7a9

Please sign in to comment.