/*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // Avoid circular dependency on EventEmitter by implementing a subset of the interface. class ErrorHandler { constructor() { this.listeners = []; this.unexpectedErrorHandler = function (e) { setTimeout(() => { if (e.stack) { if (ErrorNoTelemetry.isErrorNoTelemetry(e)) { throw new ErrorNoTelemetry(e.message + '\n\n' + e.stack); } throw new Error(e.message + '\n\n' + e.stack); } throw e; }, 0); }; } emit(e) { this.listeners.forEach((listener) => { listener(e); }); } onUnexpectedError(e) { this.unexpectedErrorHandler(e); this.emit(e); } // For external errors, we don't want the listeners to be called onUnexpectedExternalError(e) { this.unexpectedErrorHandler(e); } } const errorHandler = new ErrorHandler(); function onUnexpectedError(e) { // ignore errors from cancelled promises if (!isCancellationError(e)) { errorHandler.onUnexpectedError(e); } return undefined; } function transformErrorForSerialization(error) { if (error instanceof Error) { const { name, message } = error; const stack = error.stacktrace || error.stack; return { $isError: true, name, message, stack, noTelemetry: ErrorNoTelemetry.isErrorNoTelemetry(error) }; } // return as is return error; } const canceledName = 'Canceled'; /** * Checks if the given error is a promise in canceled state */ function isCancellationError(error) { if (error instanceof CancellationError) { return true; } return error instanceof Error && error.name === canceledName && error.message === canceledName; } // !!!IMPORTANT!!! // Do NOT change this class because it is also used as an API-type. class CancellationError extends Error { constructor() { super(canceledName); this.name = this.message; } } /** * Error that when thrown won't be logged in telemetry as an unhandled error. */ class ErrorNoTelemetry extends Error { constructor(msg) { super(msg); this.name = 'CodeExpectedError'; } static fromError(err) { if (err instanceof ErrorNoTelemetry) { return err; } const result = new ErrorNoTelemetry(); result.message = err.message; result.stack = err.stack; return result; } static isErrorNoTelemetry(err) { return err.name === 'CodeExpectedError'; } } /** * This error indicates a bug. * Do not throw this for invalid user input. * Only catch this error to recover gracefully from bugs. */ class BugIndicatingError extends Error { constructor(message) { super(message || 'An unexpected bug occurred.'); Object.setPrototypeOf(this, BugIndicatingError.prototype); // Because we know for sure only buggy code throws this, // we definitely want to break here and fix the bug. // eslint-disable-next-line no-debugger // debugger; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Given a function, returns a function that is only calling that function once. */ function createSingleCallFunction(fn, fnDidRunCallback) { const _this = this; let didCall = false; let result; return function () { if (didCall) { return result; } didCall = true; { result = fn.apply(_this, arguments); } return result; }; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var Iterable; (function (Iterable) { function is(thing) { return thing && typeof thing === 'object' && typeof thing[Symbol.iterator] === 'function'; } Iterable.is = is; const _empty = Object.freeze([]); function empty() { return _empty; } Iterable.empty = empty; function* single(element) { yield element; } Iterable.single = single; function wrap(iterableOrElement) { if (is(iterableOrElement)) { return iterableOrElement; } else { return single(iterableOrElement); } } Iterable.wrap = wrap; function from(iterable) { return iterable || _empty; } Iterable.from = from; function* reverse(array) { for (let i = array.length - 1; i >= 0; i--) { yield array[i]; } } Iterable.reverse = reverse; function isEmpty(iterable) { return !iterable || iterable[Symbol.iterator]().next().done === true; } Iterable.isEmpty = isEmpty; function first(iterable) { return iterable[Symbol.iterator]().next().value; } Iterable.first = first; function some(iterable, predicate) { let i = 0; for (const element of iterable) { if (predicate(element, i++)) { return true; } } return false; } Iterable.some = some; function find(iterable, predicate) { for (const element of iterable) { if (predicate(element)) { return element; } } return undefined; } Iterable.find = find; function* filter(iterable, predicate) { for (const element of iterable) { if (predicate(element)) { yield element; } } } Iterable.filter = filter; function* map(iterable, fn) { let index = 0; for (const element of iterable) { yield fn(element, index++); } } Iterable.map = map; function* flatMap(iterable, fn) { let index = 0; for (const element of iterable) { yield* fn(element, index++); } } Iterable.flatMap = flatMap; function* concat(...iterables) { for (const iterable of iterables) { yield* iterable; } } Iterable.concat = concat; function reduce(iterable, reducer, initialValue) { let value = initialValue; for (const element of iterable) { value = reducer(value, element); } return value; } Iterable.reduce = reduce; /** * Returns an iterable slice of the array, with the same semantics as `array.slice()`. */ function* slice(arr, from, to = arr.length) { if (from < 0) { from += arr.length; } if (to < 0) { to += arr.length; } else if (to > arr.length) { to = arr.length; } for (; from < to; from++) { yield arr[from]; } } Iterable.slice = slice; /** * Consumes `atMost` elements from iterable and returns the consumed elements, * and an iterable for the rest of the elements. */ function consume(iterable, atMost = Number.POSITIVE_INFINITY) { const consumed = []; if (atMost === 0) { return [consumed, iterable]; } const iterator = iterable[Symbol.iterator](); for (let i = 0; i < atMost; i++) { const next = iterator.next(); if (next.done) { return [consumed, Iterable.empty()]; } consumed.push(next.value); } return [consumed, { [Symbol.iterator]() { return iterator; } }]; } Iterable.consume = consume; async function asyncToArray(iterable) { const result = []; for await (const item of iterable) { result.push(item); } return Promise.resolve(result); } Iterable.asyncToArray = asyncToArray; })(Iterable || (Iterable = {})); function trackDisposable(x) { return x; } function setParentOfDisposable(child, parent) { } function dispose(arg) { if (Iterable.is(arg)) { const errors = []; for (const d of arg) { if (d) { try { d.dispose(); } catch (e) { errors.push(e); } } } if (errors.length === 1) { throw errors[0]; } else if (errors.length > 1) { throw new AggregateError(errors, 'Encountered errors while disposing of store'); } return Array.isArray(arg) ? [] : arg; } else if (arg) { arg.dispose(); return arg; } } /** * Combine multiple disposable values into a single {@link IDisposable}. */ function combinedDisposable(...disposables) { const parent = toDisposable(() => dispose(disposables)); return parent; } /** * Turn a function that implements dispose into an {@link IDisposable}. * * @param fn Clean up function, guaranteed to be called only **once**. */ function toDisposable(fn) { const self = trackDisposable({ dispose: createSingleCallFunction(() => { fn(); }) }); return self; } /** * Manages a collection of disposable values. * * This is the preferred way to manage multiple disposables. A `DisposableStore` is safer to work with than an * `IDisposable[]` as it considers edge cases, such as registering the same value multiple times or adding an item to a * store that has already been disposed of. */ class DisposableStore { static { this.DISABLE_DISPOSED_WARNING = false; } constructor() { this._toDispose = new Set(); this._isDisposed = false; } /** * Dispose of all registered disposables and mark this object as disposed. * * Any future disposables added to this object will be disposed of on `add`. */ dispose() { if (this._isDisposed) { return; } this._isDisposed = true; this.clear(); } /** * @return `true` if this object has been disposed of. */ get isDisposed() { return this._isDisposed; } /** * Dispose of all registered disposables but do not mark this object as disposed. */ clear() { if (this._toDispose.size === 0) { return; } try { dispose(this._toDispose); } finally { this._toDispose.clear(); } } /** * Add a new {@link IDisposable disposable} to the collection. */ add(o) { if (!o) { return o; } if (o === this) { throw new Error('Cannot register a disposable on itself!'); } if (this._isDisposed) { if (!DisposableStore.DISABLE_DISPOSED_WARNING) { console.warn(new Error('Trying to add a disposable to a DisposableStore that has already been disposed of. The added object will be leaked!').stack); } } else { this._toDispose.add(o); } return o; } /** * Deletes the value from the store, but does not dispose it. */ deleteAndLeak(o) { if (!o) { return; } if (this._toDispose.has(o)) { this._toDispose.delete(o); } } } /** * Abstract base class for a {@link IDisposable disposable} object. * * Subclasses can {@linkcode _register} disposables that will be automatically cleaned up when this object is disposed of. */ class Disposable { /** * A disposable that does nothing when it is disposed of. * * TODO: This should not be a static property. */ static { this.None = Object.freeze({ dispose() { } }); } constructor() { this._store = new DisposableStore(); setParentOfDisposable(this._store); } dispose() { this._store.dispose(); } /** * Adds `o` to the collection of disposables managed by this object. */ _register(o) { if (o === this) { throw new Error('Cannot register a disposable on itself!'); } return this._store.add(o); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class Node { static { this.Undefined = new Node(undefined); } constructor(element) { this.element = element; this.next = Node.Undefined; this.prev = Node.Undefined; } } class LinkedList { constructor() { this._first = Node.Undefined; this._last = Node.Undefined; this._size = 0; } get size() { return this._size; } isEmpty() { return this._first === Node.Undefined; } clear() { let node = this._first; while (node !== Node.Undefined) { const next = node.next; node.prev = Node.Undefined; node.next = Node.Undefined; node = next; } this._first = Node.Undefined; this._last = Node.Undefined; this._size = 0; } unshift(element) { return this._insert(element, false); } push(element) { return this._insert(element, true); } _insert(element, atTheEnd) { const newNode = new Node(element); if (this._first === Node.Undefined) { this._first = newNode; this._last = newNode; } else if (atTheEnd) { // push const oldLast = this._last; this._last = newNode; newNode.prev = oldLast; oldLast.next = newNode; } else { // unshift const oldFirst = this._first; this._first = newNode; newNode.next = oldFirst; oldFirst.prev = newNode; } this._size += 1; let didRemove = false; return () => { if (!didRemove) { didRemove = true; this._remove(newNode); } }; } shift() { if (this._first === Node.Undefined) { return undefined; } else { const res = this._first.element; this._remove(this._first); return res; } } pop() { if (this._last === Node.Undefined) { return undefined; } else { const res = this._last.element; this._remove(this._last); return res; } } _remove(node) { if (node.prev !== Node.Undefined && node.next !== Node.Undefined) { // middle const anchor = node.prev; anchor.next = node.next; node.next.prev = anchor; } else if (node.prev === Node.Undefined && node.next === Node.Undefined) { // only node this._first = Node.Undefined; this._last = Node.Undefined; } else if (node.next === Node.Undefined) { // last this._last = this._last.prev; this._last.next = Node.Undefined; } else if (node.prev === Node.Undefined) { // first this._first = this._first.next; this._first.prev = Node.Undefined; } // done this._size -= 1; } *[Symbol.iterator]() { let node = this._first; while (node !== Node.Undefined) { yield node.element; node = node.next; } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const hasPerformanceNow = (globalThis.performance && typeof globalThis.performance.now === 'function'); class StopWatch { static create(highResolution) { return new StopWatch(highResolution); } constructor(highResolution) { this._now = hasPerformanceNow && highResolution === false ? Date.now : globalThis.performance.now.bind(globalThis.performance); this._startTime = this._now(); this._stopTime = -1; } stop() { this._stopTime = this._now(); } reset() { this._startTime = this._now(); this._stopTime = -1; } elapsed() { if (this._stopTime !== -1) { return this._stopTime - this._startTime; } return this._now() - this._startTime; } } var Event; (function (Event) { Event.None = () => Disposable.None; /** * Given an event, returns another event which debounces calls and defers the listeners to a later task via a shared * `setTimeout`. The event is converted into a signal (`Event`) to avoid additional object creation as a * result of merging events and to try prevent race conditions that could arise when using related deferred and * non-deferred events. * * This is useful for deferring non-critical work (eg. general UI updates) to ensure it does not block critical work * (eg. latency of keypress to text rendered). * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. * * @param event The event source for the new event. * @param disposable A disposable store to add the new EventEmitter to. */ function defer(event, disposable) { return debounce(event, () => void 0, 0, undefined, true, undefined, disposable); } Event.defer = defer; /** * Given an event, returns another event which only fires once. * * @param event The event source for the new event. */ function once(event) { return (listener, thisArgs = null, disposables) => { // we need this, in case the event fires during the listener call let didFire = false; let result = undefined; result = event(e => { if (didFire) { return; } else if (result) { result.dispose(); } else { didFire = true; } return listener.call(thisArgs, e); }, null, disposables); if (didFire) { result.dispose(); } return result; }; } Event.once = once; /** * Given an event, returns another event which only fires once, and only when the condition is met. * * @param event The event source for the new event. */ function onceIf(event, condition) { return Event.once(Event.filter(event, condition)); } Event.onceIf = onceIf; /** * Maps an event of one type into an event of another type using a mapping function, similar to how * `Array.prototype.map` works. * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. * * @param event The event source for the new event. * @param map The mapping function. * @param disposable A disposable store to add the new EventEmitter to. */ function map(event, map, disposable) { return snapshot((listener, thisArgs = null, disposables) => event(i => listener.call(thisArgs, map(i)), null, disposables), disposable); } Event.map = map; /** * Wraps an event in another event that performs some function on the event object before firing. * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. * * @param event The event source for the new event. * @param each The function to perform on the event object. * @param disposable A disposable store to add the new EventEmitter to. */ function forEach(event, each, disposable) { return snapshot((listener, thisArgs = null, disposables) => event(i => { each(i); listener.call(thisArgs, i); }, null, disposables), disposable); } Event.forEach = forEach; function filter(event, filter, disposable) { return snapshot((listener, thisArgs = null, disposables) => event(e => filter(e) && listener.call(thisArgs, e), null, disposables), disposable); } Event.filter = filter; /** * Given an event, returns the same event but typed as `Event`. */ function signal(event) { return event; } Event.signal = signal; function any(...events) { return (listener, thisArgs = null, disposables) => { const disposable = combinedDisposable(...events.map(event => event(e => listener.call(thisArgs, e)))); return addAndReturnDisposable(disposable, disposables); }; } Event.any = any; /** * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. */ function reduce(event, merge, initial, disposable) { let output = initial; return map(event, e => { output = merge(output, e); return output; }, disposable); } Event.reduce = reduce; function snapshot(event, disposable) { let listener; const options = { onWillAddFirstListener() { listener = event(emitter.fire, emitter); }, onDidRemoveLastListener() { listener?.dispose(); } }; const emitter = new Emitter(options); disposable?.add(emitter); return emitter.event; } /** * Adds the IDisposable to the store if it's set, and returns it. Useful to * Event function implementation. */ function addAndReturnDisposable(d, store) { if (store instanceof Array) { store.push(d); } else if (store) { store.add(d); } return d; } function debounce(event, merge, delay = 100, leading = false, flushOnListenerRemove = false, leakWarningThreshold, disposable) { let subscription; let output = undefined; let handle = undefined; let numDebouncedCalls = 0; let doFire; const options = { leakWarningThreshold, onWillAddFirstListener() { subscription = event(cur => { numDebouncedCalls++; output = merge(output, cur); if (leading && !handle) { emitter.fire(output); output = undefined; } doFire = () => { const _output = output; output = undefined; handle = undefined; if (!leading || numDebouncedCalls > 1) { emitter.fire(_output); } numDebouncedCalls = 0; }; if (typeof delay === 'number') { clearTimeout(handle); handle = setTimeout(doFire, delay); } else { if (handle === undefined) { handle = 0; queueMicrotask(doFire); } } }); }, onWillRemoveListener() { if (flushOnListenerRemove && numDebouncedCalls > 0) { doFire?.(); } }, onDidRemoveLastListener() { doFire = undefined; subscription.dispose(); } }; const emitter = new Emitter(options); disposable?.add(emitter); return emitter.event; } Event.debounce = debounce; /** * Debounces an event, firing after some delay (default=0) with an array of all event original objects. * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. */ function accumulate(event, delay = 0, disposable) { return Event.debounce(event, (last, e) => { if (!last) { return [e]; } last.push(e); return last; }, delay, undefined, true, undefined, disposable); } Event.accumulate = accumulate; /** * Filters an event such that some condition is _not_ met more than once in a row, effectively ensuring duplicate * event objects from different sources do not fire the same event object. * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. * * @param event The event source for the new event. * @param equals The equality condition. * @param disposable A disposable store to add the new EventEmitter to. * * @example * ``` * // Fire only one time when a single window is opened or focused * Event.latch(Event.any(onDidOpenWindow, onDidFocusWindow)) * ``` */ function latch(event, equals = (a, b) => a === b, disposable) { let firstCall = true; let cache; return filter(event, value => { const shouldEmit = firstCall || !equals(value, cache); firstCall = false; cache = value; return shouldEmit; }, disposable); } Event.latch = latch; /** * Splits an event whose parameter is a union type into 2 separate events for each type in the union. * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. * * @example * ``` * const event = new EventEmitter().event; * const [numberEvent, undefinedEvent] = Event.split(event, isUndefined); * ``` * * @param event The event source for the new event. * @param isT A function that determines what event is of the first type. * @param disposable A disposable store to add the new EventEmitter to. */ function split(event, isT, disposable) { return [ Event.filter(event, isT, disposable), Event.filter(event, e => !isT(e), disposable), ]; } Event.split = split; /** * Buffers an event until it has a listener attached. * * *NOTE* that this function returns an `Event` and it MUST be called with a `DisposableStore` whenever the returned * event is accessible to "third parties", e.g the event is a public property. Otherwise a leaked listener on the * returned event causes this utility to leak a listener on the original event. * * @param event The event source for the new event. * @param flushAfterTimeout Determines whether to flush the buffer after a timeout immediately or after a * `setTimeout` when the first event listener is added. * @param _buffer Internal: A source event array used for tests. * * @example * ``` * // Start accumulating events, when the first listener is attached, flush * // the event after a timeout such that multiple listeners attached before * // the timeout would receive the event * this.onInstallExtension = Event.buffer(service.onInstallExtension, true); * ``` */ function buffer(event, flushAfterTimeout = false, _buffer = [], disposable) { let buffer = _buffer.slice(); let listener = event(e => { if (buffer) { buffer.push(e); } else { emitter.fire(e); } }); if (disposable) { disposable.add(listener); } const flush = () => { buffer?.forEach(e => emitter.fire(e)); buffer = null; }; const emitter = new Emitter({ onWillAddFirstListener() { if (!listener) { listener = event(e => emitter.fire(e)); if (disposable) { disposable.add(listener); } } }, onDidAddFirstListener() { if (buffer) { if (flushAfterTimeout) { setTimeout(flush); } else { flush(); } } }, onDidRemoveLastListener() { if (listener) { listener.dispose(); } listener = null; } }); if (disposable) { disposable.add(emitter); } return emitter.event; } Event.buffer = buffer; /** * Wraps the event in an {@link IChainableEvent}, allowing a more functional programming style. * * @example * ``` * // Normal * const onEnterPressNormal = Event.filter( * Event.map(onKeyPress.event, e => new StandardKeyboardEvent(e)), * e.keyCode === KeyCode.Enter * ).event; * * // Using chain * const onEnterPressChain = Event.chain(onKeyPress.event, $ => $ * .map(e => new StandardKeyboardEvent(e)) * .filter(e => e.keyCode === KeyCode.Enter) * ); * ``` */ function chain(event, sythensize) { const fn = (listener, thisArgs, disposables) => { const cs = sythensize(new ChainableSynthesis()); return event(function (value) { const result = cs.evaluate(value); if (result !== HaltChainable) { listener.call(thisArgs, result); } }, undefined, disposables); }; return fn; } Event.chain = chain; const HaltChainable = Symbol('HaltChainable'); class ChainableSynthesis { constructor() { this.steps = []; } map(fn) { this.steps.push(fn); return this; } forEach(fn) { this.steps.push(v => { fn(v); return v; }); return this; } filter(fn) { this.steps.push(v => fn(v) ? v : HaltChainable); return this; } reduce(merge, initial) { let last = initial; this.steps.push(v => { last = merge(last, v); return last; }); return this; } latch(equals = (a, b) => a === b) { let firstCall = true; let cache; this.steps.push(value => { const shouldEmit = firstCall || !equals(value, cache); firstCall = false; cache = value; return shouldEmit ? value : HaltChainable; }); return this; } evaluate(value) { for (const step of this.steps) { value = step(value); if (value === HaltChainable) { break; } } return value; } } /** * Creates an {@link Event} from a node event emitter. */ function fromNodeEventEmitter(emitter, eventName, map = id => id) { const fn = (...args) => result.fire(map(...args)); const onFirstListenerAdd = () => emitter.on(eventName, fn); const onLastListenerRemove = () => emitter.removeListener(eventName, fn); const result = new Emitter({ onWillAddFirstListener: onFirstListenerAdd, onDidRemoveLastListener: onLastListenerRemove }); return result.event; } Event.fromNodeEventEmitter = fromNodeEventEmitter; /** * Creates an {@link Event} from a DOM event emitter. */ function fromDOMEventEmitter(emitter, eventName, map = id => id) { const fn = (...args) => result.fire(map(...args)); const onFirstListenerAdd = () => emitter.addEventListener(eventName, fn); const onLastListenerRemove = () => emitter.removeEventListener(eventName, fn); const result = new Emitter({ onWillAddFirstListener: onFirstListenerAdd, onDidRemoveLastListener: onLastListenerRemove }); return result.event; } Event.fromDOMEventEmitter = fromDOMEventEmitter; /** * Creates a promise out of an event, using the {@link Event.once} helper. */ function toPromise(event) { return new Promise(resolve => once(event)(resolve)); } Event.toPromise = toPromise; /** * Creates an event out of a promise that fires once when the promise is * resolved with the result of the promise or `undefined`. */ function fromPromise(promise) { const result = new Emitter(); promise.then(res => { result.fire(res); }, () => { result.fire(undefined); }).finally(() => { result.dispose(); }); return result.event; } Event.fromPromise = fromPromise; /** * A convenience function for forwarding an event to another emitter which * improves readability. * * This is similar to {@link Relay} but allows instantiating and forwarding * on a single line and also allows for multiple source events. * @param from The event to forward. * @param to The emitter to forward the event to. * @example * Event.forward(event, emitter); * // equivalent to * event(e => emitter.fire(e)); * // equivalent to * event(emitter.fire, emitter); */ function forward(from, to) { return from(e => to.fire(e)); } Event.forward = forward; function runAndSubscribe(event, handler, initial) { handler(initial); return event(e => handler(e)); } Event.runAndSubscribe = runAndSubscribe; class EmitterObserver { constructor(_observable, store) { this._observable = _observable; this._counter = 0; this._hasChanged = false; const options = { onWillAddFirstListener: () => { _observable.addObserver(this); // Communicate to the observable that we received its current value and would like to be notified about future changes. this._observable.reportChanges(); }, onDidRemoveLastListener: () => { _observable.removeObserver(this); } }; this.emitter = new Emitter(options); if (store) { store.add(this.emitter); } } beginUpdate(_observable) { // assert(_observable === this.obs); this._counter++; } handlePossibleChange(_observable) { // assert(_observable === this.obs); } handleChange(_observable, _change) { // assert(_observable === this.obs); this._hasChanged = true; } endUpdate(_observable) { // assert(_observable === this.obs); this._counter--; if (this._counter === 0) { this._observable.reportChanges(); if (this._hasChanged) { this._hasChanged = false; this.emitter.fire(this._observable.get()); } } } } /** * Creates an event emitter that is fired when the observable changes. * Each listeners subscribes to the emitter. */ function fromObservable(obs, store) { const observer = new EmitterObserver(obs, store); return observer.emitter.event; } Event.fromObservable = fromObservable; /** * Each listener is attached to the observable directly. */ function fromObservableLight(observable) { return (listener, thisArgs, disposables) => { let count = 0; let didChange = false; const observer = { beginUpdate() { count++; }, endUpdate() { count--; if (count === 0) { observable.reportChanges(); if (didChange) { didChange = false; listener.call(thisArgs); } } }, handlePossibleChange() { // noop }, handleChange() { didChange = true; } }; observable.addObserver(observer); observable.reportChanges(); const disposable = { dispose() { observable.removeObserver(observer); } }; if (disposables instanceof DisposableStore) { disposables.add(disposable); } else if (Array.isArray(disposables)) { disposables.push(disposable); } return disposable; }; } Event.fromObservableLight = fromObservableLight; })(Event || (Event = {})); class EventProfiling { static { this.all = new Set(); } static { this._idPool = 0; } constructor(name) { this.listenerCount = 0; this.invocationCount = 0; this.elapsedOverall = 0; this.durations = []; this.name = `${name}_${EventProfiling._idPool++}`; EventProfiling.all.add(this); } start(listenerCount) { this._stopWatch = new StopWatch(); this.listenerCount = listenerCount; } stop() { if (this._stopWatch) { const elapsed = this._stopWatch.elapsed(); this.durations.push(elapsed); this.elapsedOverall += elapsed; this.invocationCount += 1; this._stopWatch = undefined; } } } let _globalLeakWarningThreshold = -1; class LeakageMonitor { static { this._idPool = 1; } constructor(_errorHandler, threshold, name = (LeakageMonitor._idPool++).toString(16).padStart(3, '0')) { this._errorHandler = _errorHandler; this.threshold = threshold; this.name = name; this._warnCountdown = 0; } dispose() { this._stacks?.clear(); } check(stack, listenerCount) { const threshold = this.threshold; if (threshold <= 0 || listenerCount < threshold) { return undefined; } if (!this._stacks) { this._stacks = new Map(); } const count = (this._stacks.get(stack.value) || 0); this._stacks.set(stack.value, count + 1); this._warnCountdown -= 1; if (this._warnCountdown <= 0) { // only warn on first exceed and then every time the limit // is exceeded by 50% again this._warnCountdown = threshold * 0.5; const [topStack, topCount] = this.getMostFrequentStack(); const message = `[${this.name}] potential listener LEAK detected, having ${listenerCount} listeners already. MOST frequent listener (${topCount}):`; console.warn(message); console.warn(topStack); const error = new ListenerLeakError(message, topStack); this._errorHandler(error); } return () => { const count = (this._stacks.get(stack.value) || 0); this._stacks.set(stack.value, count - 1); }; } getMostFrequentStack() { if (!this._stacks) { return undefined; } let topStack; let topCount = 0; for (const [stack, count] of this._stacks) { if (!topStack || topCount < count) { topStack = [stack, count]; topCount = count; } } return topStack; } } class Stacktrace { static create() { const err = new Error(); return new Stacktrace(err.stack ?? ''); } constructor(value) { this.value = value; } print() { console.warn(this.value.split('\n').slice(2).join('\n')); } } // error that is logged when going over the configured listener threshold class ListenerLeakError extends Error { constructor(message, stack) { super(message); this.name = 'ListenerLeakError'; this.stack = stack; } } // SEVERE error that is logged when having gone way over the configured listener // threshold so that the emitter refuses to accept more listeners class ListenerRefusalError extends Error { constructor(message, stack) { super(message); this.name = 'ListenerRefusalError'; this.stack = stack; } } class UniqueContainer { constructor(value) { this.value = value; } } const compactionThreshold = 2; /** * The Emitter can be used to expose an Event to the public * to fire it from the insides. * Sample: class Document { private readonly _onDidChange = new Emitter<(value:string)=>any>(); public onDidChange = this._onDidChange.event; // getter-style // get onDidChange(): Event<(value:string)=>any> { // return this._onDidChange.event; // } private _doIt() { //... this._onDidChange.fire(value); } } */ class Emitter { constructor(options) { this._size = 0; this._options = options; this._leakageMon = (this._options?.leakWarningThreshold) ? new LeakageMonitor(options?.onListenerError ?? onUnexpectedError, this._options?.leakWarningThreshold ?? _globalLeakWarningThreshold) : undefined; this._perfMon = this._options?._profName ? new EventProfiling(this._options._profName) : undefined; this._deliveryQueue = this._options?.deliveryQueue; } dispose() { if (!this._disposed) { this._disposed = true; // It is bad to have listeners at the time of disposing an emitter, it is worst to have listeners keep the emitter // alive via the reference that's embedded in their disposables. Therefore we loop over all remaining listeners and // unset their subscriptions/disposables. Looping and blaming remaining listeners is done on next tick because the // the following programming pattern is very popular: // // const someModel = this._disposables.add(new ModelObject()); // (1) create and register model // this._disposables.add(someModel.onDidChange(() => { ... }); // (2) subscribe and register model-event listener // ...later... // this._disposables.dispose(); disposes (1) then (2): don't warn after (1) but after the "overall dispose" is done if (this._deliveryQueue?.current === this) { this._deliveryQueue.reset(); } if (this._listeners) { this._listeners = undefined; this._size = 0; } this._options?.onDidRemoveLastListener?.(); this._leakageMon?.dispose(); } } /** * For the public to allow to subscribe * to events from this Emitter */ get event() { this._event ??= (callback, thisArgs, disposables) => { if (this._leakageMon && this._size > this._leakageMon.threshold ** 2) { const message = `[${this._leakageMon.name}] REFUSES to accept new listeners because it exceeded its threshold by far (${this._size} vs ${this._leakageMon.threshold})`; console.warn(message); const tuple = this._leakageMon.getMostFrequentStack() ?? ['UNKNOWN stack', -1]; const error = new ListenerRefusalError(`${message}. HINT: Stack shows most frequent listener (${tuple[1]}-times)`, tuple[0]); const errorHandler = this._options?.onListenerError || onUnexpectedError; errorHandler(error); return Disposable.None; } if (this._disposed) { // todo: should we warn if a listener is added to a disposed emitter? This happens often return Disposable.None; } if (thisArgs) { callback = callback.bind(thisArgs); } const contained = new UniqueContainer(callback); let removeMonitor; if (this._leakageMon && this._size >= Math.ceil(this._leakageMon.threshold * 0.2)) { // check and record this emitter for potential leakage contained.stack = Stacktrace.create(); removeMonitor = this._leakageMon.check(contained.stack, this._size + 1); } if (!this._listeners) { this._options?.onWillAddFirstListener?.(this); this._listeners = contained; this._options?.onDidAddFirstListener?.(this); } else if (this._listeners instanceof UniqueContainer) { this._deliveryQueue ??= new EventDeliveryQueuePrivate(); this._listeners = [this._listeners, contained]; } else { this._listeners.push(contained); } this._size++; const result = toDisposable(() => { removeMonitor?.(); this._removeListener(contained); }); if (disposables instanceof DisposableStore) { disposables.add(result); } else if (Array.isArray(disposables)) { disposables.push(result); } return result; }; return this._event; } _removeListener(listener) { this._options?.onWillRemoveListener?.(this); if (!this._listeners) { return; // expected if a listener gets disposed } if (this._size === 1) { this._listeners = undefined; this._options?.onDidRemoveLastListener?.(this); this._size = 0; return; } // size > 1 which requires that listeners be a list: const listeners = this._listeners; const index = listeners.indexOf(listener); if (index === -1) { console.log('disposed?', this._disposed); console.log('size?', this._size); console.log('arr?', JSON.stringify(this._listeners)); throw new Error('Attempted to dispose unknown listener'); } this._size--; listeners[index] = undefined; const adjustDeliveryQueue = this._deliveryQueue.current === this; if (this._size * compactionThreshold <= listeners.length) { let n = 0; for (let i = 0; i < listeners.length; i++) { if (listeners[i]) { listeners[n++] = listeners[i]; } else if (adjustDeliveryQueue) { this._deliveryQueue.end--; if (n < this._deliveryQueue.i) { this._deliveryQueue.i--; } } } listeners.length = n; } } _deliver(listener, value) { if (!listener) { return; } const errorHandler = this._options?.onListenerError || onUnexpectedError; if (!errorHandler) { listener.value(value); return; } try { listener.value(value); } catch (e) { errorHandler(e); } } /** Delivers items in the queue. Assumes the queue is ready to go. */ _deliverQueue(dq) { const listeners = dq.current._listeners; while (dq.i < dq.end) { // important: dq.i is incremented before calling deliver() because it might reenter deliverQueue() this._deliver(listeners[dq.i++], dq.value); } dq.reset(); } /** * To be kept private to fire an event to * subscribers */ fire(event) { if (this._deliveryQueue?.current) { this._deliverQueue(this._deliveryQueue); this._perfMon?.stop(); // last fire() will have starting perfmon, stop it before starting the next dispatch } this._perfMon?.start(this._size); if (!this._listeners) ; else if (this._listeners instanceof UniqueContainer) { this._deliver(this._listeners, event); } else { const dq = this._deliveryQueue; dq.enqueue(this, event, this._listeners.length); this._deliverQueue(dq); } this._perfMon?.stop(); } hasListeners() { return this._size > 0; } } class EventDeliveryQueuePrivate { constructor() { /** * Index in current's listener list. */ this.i = -1; /** * The last index in the listener's list to deliver. */ this.end = 0; } enqueue(emitter, value, end) { this.i = 0; this.end = end; this.current = emitter; this.value = value; } reset() { this.i = this.end; // force any current emission loop to stop, mainly for during dispose this.current = undefined; this.value = undefined; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /* * This module exists so that the AMD build of the monaco editor can replace this with an async loader plugin. * If you add new functions to this module make sure that they are also provided in the AMD build of the monaco editor. */ function getNLSMessages() { return globalThis._VSCODE_NLS_MESSAGES; } function getNLSLanguage() { return globalThis._VSCODE_NLS_LANGUAGE; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // eslint-disable-next-line local/code-import-patterns const isPseudo = getNLSLanguage() === 'pseudo' || (typeof document !== 'undefined' && document.location && document.location.hash.indexOf('pseudo=true') >= 0); function _format$1(message, args) { let result; if (args.length === 0) { result = message; } else { result = message.replace(/\{(\d+)\}/g, (match, rest) => { const index = rest[0]; const arg = args[index]; let result = match; if (typeof arg === 'string') { result = arg; } else if (typeof arg === 'number' || typeof arg === 'boolean' || arg === void 0 || arg === null) { result = String(arg); } return result; }); } if (isPseudo) { // FF3B and FF3D is the Unicode zenkaku representation for [ and ] result = '\uFF3B' + result.replace(/[aouei]/g, '$&$&') + '\uFF3D'; } return result; } /** * @skipMangle */ function localize(data /* | number when built */, message /* | null when built */, ...args) { if (typeof data === 'number') { return _format$1(lookupMessage(data, message), args); } return _format$1(message, args); } /** * Only used when built: Looks up the message in the global NLS table. * This table is being made available as a global through bootstrapping * depending on the target context. */ function lookupMessage(index, fallback) { const message = getNLSMessages()?.[index]; if (typeof message !== 'string') { if (typeof fallback === 'string') { return fallback; } throw new Error(`!!! NLS MISSING: ${index} !!!`); } return message; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const LANGUAGE_DEFAULT = 'en'; let _isWindows = false; let _isMacintosh = false; let _isLinux = false; let _isNative = false; let _isWeb = false; let _locale = undefined; let _language = LANGUAGE_DEFAULT; let _platformLocale = LANGUAGE_DEFAULT; let _translationsConfigFile = undefined; let _userAgent = undefined; const $globalThis = globalThis; let nodeProcess = undefined; if (typeof $globalThis.vscode !== 'undefined' && typeof $globalThis.vscode.process !== 'undefined') { // Native environment (sandboxed) nodeProcess = $globalThis.vscode.process; } else if (typeof process !== 'undefined' && typeof process?.versions?.node === 'string') { // Native environment (non-sandboxed) nodeProcess = process; } const isElectronProcess = typeof nodeProcess?.versions?.electron === 'string'; const isElectronRenderer = isElectronProcess && nodeProcess?.type === 'renderer'; // Native environment if (typeof nodeProcess === 'object') { _isWindows = (nodeProcess.platform === 'win32'); _isMacintosh = (nodeProcess.platform === 'darwin'); _isLinux = (nodeProcess.platform === 'linux'); _isLinux && !!nodeProcess.env['SNAP'] && !!nodeProcess.env['SNAP_REVISION']; !!nodeProcess.env['CI'] || !!nodeProcess.env['BUILD_ARTIFACTSTAGINGDIRECTORY']; _locale = LANGUAGE_DEFAULT; _language = LANGUAGE_DEFAULT; const rawNlsConfig = nodeProcess.env['VSCODE_NLS_CONFIG']; if (rawNlsConfig) { try { const nlsConfig = JSON.parse(rawNlsConfig); _locale = nlsConfig.userLocale; _platformLocale = nlsConfig.osLocale; _language = nlsConfig.resolvedLanguage || LANGUAGE_DEFAULT; _translationsConfigFile = nlsConfig.languagePack?.translationsConfigFile; } catch (e) { } } _isNative = true; } // Web environment else if (typeof navigator === 'object' && !isElectronRenderer) { _userAgent = navigator.userAgent; _isWindows = _userAgent.indexOf('Windows') >= 0; _isMacintosh = _userAgent.indexOf('Macintosh') >= 0; (_userAgent.indexOf('Macintosh') >= 0 || _userAgent.indexOf('iPad') >= 0 || _userAgent.indexOf('iPhone') >= 0) && !!navigator.maxTouchPoints && navigator.maxTouchPoints > 0; _isLinux = _userAgent.indexOf('Linux') >= 0; _userAgent?.indexOf('Mobi') >= 0; _isWeb = true; _language = getNLSLanguage() || LANGUAGE_DEFAULT; _locale = navigator.language.toLowerCase(); _platformLocale = _locale; } // Unknown environment else { console.error('Unable to resolve platform.'); } const isWindows = _isWindows; const isMacintosh = _isMacintosh; const isNative = _isNative; const isWeb = _isWeb; const isWebWorker = (_isWeb && typeof $globalThis.importScripts === 'function'); const webWorkerOrigin = isWebWorker ? $globalThis.origin : undefined; const userAgent = _userAgent; const setTimeout0IsFaster = (typeof $globalThis.postMessage === 'function' && !$globalThis.importScripts); /** * See https://html.spec.whatwg.org/multipage/timers-and-user-prompts.html#:~:text=than%204%2C%20then-,set%20timeout%20to%204,-. * * Works similarly to `setTimeout(0)` but doesn't suffer from the 4ms artificial delay * that browsers set when the nesting level is > 5. */ (() => { if (setTimeout0IsFaster) { const pending = []; $globalThis.addEventListener('message', (e) => { if (e.data && e.data.vscodeScheduleAsyncWork) { for (let i = 0, len = pending.length; i < len; i++) { const candidate = pending[i]; if (candidate.id === e.data.vscodeScheduleAsyncWork) { pending.splice(i, 1); candidate.callback(); return; } } } }); let lastId = 0; return (callback) => { const myId = ++lastId; pending.push({ id: myId, callback: callback }); $globalThis.postMessage({ vscodeScheduleAsyncWork: myId }, '*'); }; } return (callback) => setTimeout(callback); })(); const isChrome = !!(userAgent && userAgent.indexOf('Chrome') >= 0); !!(userAgent && userAgent.indexOf('Firefox') >= 0); !!(!isChrome && (userAgent && userAgent.indexOf('Safari') >= 0)); !!(userAgent && userAgent.indexOf('Edg/') >= 0); !!(userAgent && userAgent.indexOf('Android') >= 0); function identity(t) { return t; } /** * Uses a LRU cache to make a given parametrized function cached. * Caches just the last key/value. */ class LRUCachedFunction { constructor(arg1, arg2) { this.lastCache = undefined; this.lastArgKey = undefined; if (typeof arg1 === 'function') { this._fn = arg1; this._computeKey = identity; } else { this._fn = arg2; this._computeKey = arg1.getCacheKey; } } get(arg) { const key = this._computeKey(arg); if (this.lastArgKey !== key) { this.lastArgKey = key; this.lastCache = this._fn(arg); } return this.lastCache; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class Lazy { constructor(executor) { this.executor = executor; this._didRun = false; } /** * Get the wrapped value. * * This will force evaluation of the lazy value if it has not been resolved yet. Lazy values are only * resolved once. `getValue` will re-throw exceptions that are hit while resolving the value */ get value() { if (!this._didRun) { try { this._value = this.executor(); } catch (err) { this._error = err; } finally { this._didRun = true; } } if (this._error) { throw this._error; } return this._value; } /** * Get the wrapped value without forcing evaluation. */ get rawValue() { return this._value; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Escapes regular expression characters in a given string */ function escapeRegExpCharacters(value) { return value.replace(/[\\\{\}\*\+\?\|\^\$\.\[\]\(\)]/g, '\\$&'); } function splitLines(str) { return str.split(/\r\n|\r|\n/); } /** * Returns first index of the string that is not whitespace. * If string is empty or contains only whitespaces, returns -1 */ function firstNonWhitespaceIndex(str) { for (let i = 0, len = str.length; i < len; i++) { const chCode = str.charCodeAt(i); if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) { return i; } } return -1; } /** * Returns last index of the string that is not whitespace. * If string is empty or contains only whitespaces, returns -1 */ function lastNonWhitespaceIndex(str, startIndex = str.length - 1) { for (let i = startIndex; i >= 0; i--) { const chCode = str.charCodeAt(i); if (chCode !== 32 /* CharCode.Space */ && chCode !== 9 /* CharCode.Tab */) { return i; } } return -1; } function isUpperAsciiLetter(code) { return code >= 65 /* CharCode.A */ && code <= 90 /* CharCode.Z */; } /** * See http://en.wikipedia.org/wiki/Surrogate_pair */ function isHighSurrogate(charCode) { return (0xD800 <= charCode && charCode <= 0xDBFF); } /** * See http://en.wikipedia.org/wiki/Surrogate_pair */ function isLowSurrogate(charCode) { return (0xDC00 <= charCode && charCode <= 0xDFFF); } /** * See http://en.wikipedia.org/wiki/Surrogate_pair */ function computeCodePoint(highSurrogate, lowSurrogate) { return ((highSurrogate - 0xD800) << 10) + (lowSurrogate - 0xDC00) + 0x10000; } /** * get the code point that begins at offset `offset` */ function getNextCodePoint(str, len, offset) { 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; } const IS_BASIC_ASCII = /^[\t\n\r\x20-\x7E]*$/; /** * Returns true if `str` contains only basic ASCII characters in the range 32 - 126 (including 32 and 126) or \n, \r, \t */ function isBasicASCII(str) { return IS_BASIC_ASCII.test(str); } class AmbiguousCharacters { static { this.ambiguousCharacterData = new Lazy(() => { // Generated using https://github.com/hediet/vscode-unicode-data // Stored as key1, value1, key2, value2, ... return JSON.parse('{\"_common\":[8232,32,8233,32,5760,32,8192,32,8193,32,8194,32,8195,32,8196,32,8197,32,8198,32,8200,32,8201,32,8202,32,8287,32,8199,32,8239,32,2042,95,65101,95,65102,95,65103,95,8208,45,8209,45,8210,45,65112,45,1748,45,8259,45,727,45,8722,45,10134,45,11450,45,1549,44,1643,44,8218,44,184,44,42233,44,894,59,2307,58,2691,58,1417,58,1795,58,1796,58,5868,58,65072,58,6147,58,6153,58,8282,58,1475,58,760,58,42889,58,8758,58,720,58,42237,58,451,33,11601,33,660,63,577,63,2429,63,5038,63,42731,63,119149,46,8228,46,1793,46,1794,46,42510,46,68176,46,1632,46,1776,46,42232,46,1373,96,65287,96,8219,96,8242,96,1370,96,1523,96,8175,96,65344,96,900,96,8189,96,8125,96,8127,96,8190,96,697,96,884,96,712,96,714,96,715,96,756,96,699,96,701,96,700,96,702,96,42892,96,1497,96,2036,96,2037,96,5194,96,5836,96,94033,96,94034,96,65339,91,10088,40,10098,40,12308,40,64830,40,65341,93,10089,41,10099,41,12309,41,64831,41,10100,123,119060,123,10101,125,65342,94,8270,42,1645,42,8727,42,66335,42,5941,47,8257,47,8725,47,8260,47,9585,47,10187,47,10744,47,119354,47,12755,47,12339,47,11462,47,20031,47,12035,47,65340,92,65128,92,8726,92,10189,92,10741,92,10745,92,119311,92,119355,92,12756,92,20022,92,12034,92,42872,38,708,94,710,94,5869,43,10133,43,66203,43,8249,60,10094,60,706,60,119350,60,5176,60,5810,60,5120,61,11840,61,12448,61,42239,61,8250,62,10095,62,707,62,119351,62,5171,62,94015,62,8275,126,732,126,8128,126,8764,126,65372,124,65293,45,120784,50,120794,50,120804,50,120814,50,120824,50,130034,50,42842,50,423,50,1000,50,42564,50,5311,50,42735,50,119302,51,120785,51,120795,51,120805,51,120815,51,120825,51,130035,51,42923,51,540,51,439,51,42858,51,11468,51,1248,51,94011,51,71882,51,120786,52,120796,52,120806,52,120816,52,120826,52,130036,52,5070,52,71855,52,120787,53,120797,53,120807,53,120817,53,120827,53,130037,53,444,53,71867,53,120788,54,120798,54,120808,54,120818,54,120828,54,130038,54,11474,54,5102,54,71893,54,119314,55,120789,55,120799,55,120809,55,120819,55,120829,55,130039,55,66770,55,71878,55,2819,56,2538,56,2666,56,125131,56,120790,56,120800,56,120810,56,120820,56,120830,56,130040,56,547,56,546,56,66330,56,2663,57,2920,57,2541,57,3437,57,120791,57,120801,57,120811,57,120821,57,120831,57,130041,57,42862,57,11466,57,71884,57,71852,57,71894,57,9082,97,65345,97,119834,97,119886,97,119938,97,119990,97,120042,97,120094,97,120146,97,120198,97,120250,97,120302,97,120354,97,120406,97,120458,97,593,97,945,97,120514,97,120572,97,120630,97,120688,97,120746,97,65313,65,119808,65,119860,65,119912,65,119964,65,120016,65,120068,65,120120,65,120172,65,120224,65,120276,65,120328,65,120380,65,120432,65,913,65,120488,65,120546,65,120604,65,120662,65,120720,65,5034,65,5573,65,42222,65,94016,65,66208,65,119835,98,119887,98,119939,98,119991,98,120043,98,120095,98,120147,98,120199,98,120251,98,120303,98,120355,98,120407,98,120459,98,388,98,5071,98,5234,98,5551,98,65314,66,8492,66,119809,66,119861,66,119913,66,120017,66,120069,66,120121,66,120173,66,120225,66,120277,66,120329,66,120381,66,120433,66,42932,66,914,66,120489,66,120547,66,120605,66,120663,66,120721,66,5108,66,5623,66,42192,66,66178,66,66209,66,66305,66,65347,99,8573,99,119836,99,119888,99,119940,99,119992,99,120044,99,120096,99,120148,99,120200,99,120252,99,120304,99,120356,99,120408,99,120460,99,7428,99,1010,99,11429,99,43951,99,66621,99,128844,67,71922,67,71913,67,65315,67,8557,67,8450,67,8493,67,119810,67,119862,67,119914,67,119966,67,120018,67,120174,67,120226,67,120278,67,120330,67,120382,67,120434,67,1017,67,11428,67,5087,67,42202,67,66210,67,66306,67,66581,67,66844,67,8574,100,8518,100,119837,100,119889,100,119941,100,119993,100,120045,100,120097,100,120149,100,120201,100,120253,100,120305,100,120357,100,120409,100,120461,100,1281,100,5095,100,5231,100,42194,100,8558,68,8517,68,119811,68,119863,68,119915,68,119967,68,120019,68,120071,68,120123,68,120175,68,120227,68,120279,68,120331,68,120383,68,120435,68,5024,68,5598,68,5610,68,42195,68,8494,101,65349,101,8495,101,8519,101,119838,101,119890,101,119942,101,120046,101,120098,101,120150,101,120202,101,120254,101,120306,101,120358,101,120410,101,120462,101,43826,101,1213,101,8959,69,65317,69,8496,69,119812,69,119864,69,119916,69,120020,69,120072,69,120124,69,120176,69,120228,69,120280,69,120332,69,120384,69,120436,69,917,69,120492,69,120550,69,120608,69,120666,69,120724,69,11577,69,5036,69,42224,69,71846,69,71854,69,66182,69,119839,102,119891,102,119943,102,119995,102,120047,102,120099,102,120151,102,120203,102,120255,102,120307,102,120359,102,120411,102,120463,102,43829,102,42905,102,383,102,7837,102,1412,102,119315,70,8497,70,119813,70,119865,70,119917,70,120021,70,120073,70,120125,70,120177,70,120229,70,120281,70,120333,70,120385,70,120437,70,42904,70,988,70,120778,70,5556,70,42205,70,71874,70,71842,70,66183,70,66213,70,66853,70,65351,103,8458,103,119840,103,119892,103,119944,103,120048,103,120100,103,120152,103,120204,103,120256,103,120308,103,120360,103,120412,103,120464,103,609,103,7555,103,397,103,1409,103,119814,71,119866,71,119918,71,119970,71,120022,71,120074,71,120126,71,120178,71,120230,71,120282,71,120334,71,120386,71,120438,71,1292,71,5056,71,5107,71,42198,71,65352,104,8462,104,119841,104,119945,104,119997,104,120049,104,120101,104,120153,104,120205,104,120257,104,120309,104,120361,104,120413,104,120465,104,1211,104,1392,104,5058,104,65320,72,8459,72,8460,72,8461,72,119815,72,119867,72,119919,72,120023,72,120179,72,120231,72,120283,72,120335,72,120387,72,120439,72,919,72,120494,72,120552,72,120610,72,120668,72,120726,72,11406,72,5051,72,5500,72,42215,72,66255,72,731,105,9075,105,65353,105,8560,105,8505,105,8520,105,119842,105,119894,105,119946,105,119998,105,120050,105,120102,105,120154,105,120206,105,120258,105,120310,105,120362,105,120414,105,120466,105,120484,105,618,105,617,105,953,105,8126,105,890,105,120522,105,120580,105,120638,105,120696,105,120754,105,1110,105,42567,105,1231,105,43893,105,5029,105,71875,105,65354,106,8521,106,119843,106,119895,106,119947,106,119999,106,120051,106,120103,106,120155,106,120207,106,120259,106,120311,106,120363,106,120415,106,120467,106,1011,106,1112,106,65322,74,119817,74,119869,74,119921,74,119973,74,120025,74,120077,74,120129,74,120181,74,120233,74,120285,74,120337,74,120389,74,120441,74,42930,74,895,74,1032,74,5035,74,5261,74,42201,74,119844,107,119896,107,119948,107,120000,107,120052,107,120104,107,120156,107,120208,107,120260,107,120312,107,120364,107,120416,107,120468,107,8490,75,65323,75,119818,75,119870,75,119922,75,119974,75,120026,75,120078,75,120130,75,120182,75,120234,75,120286,75,120338,75,120390,75,120442,75,922,75,120497,75,120555,75,120613,75,120671,75,120729,75,11412,75,5094,75,5845,75,42199,75,66840,75,1472,108,8739,73,9213,73,65512,73,1633,108,1777,73,66336,108,125127,108,120783,73,120793,73,120803,73,120813,73,120823,73,130033,73,65321,73,8544,73,8464,73,8465,73,119816,73,119868,73,119920,73,120024,73,120128,73,120180,73,120232,73,120284,73,120336,73,120388,73,120440,73,65356,108,8572,73,8467,108,119845,108,119897,108,119949,108,120001,108,120053,108,120105,73,120157,73,120209,73,120261,73,120313,73,120365,73,120417,73,120469,73,448,73,120496,73,120554,73,120612,73,120670,73,120728,73,11410,73,1030,73,1216,73,1493,108,1503,108,1575,108,126464,108,126592,108,65166,108,65165,108,1994,108,11599,73,5825,73,42226,73,93992,73,66186,124,66313,124,119338,76,8556,76,8466,76,119819,76,119871,76,119923,76,120027,76,120079,76,120131,76,120183,76,120235,76,120287,76,120339,76,120391,76,120443,76,11472,76,5086,76,5290,76,42209,76,93974,76,71843,76,71858,76,66587,76,66854,76,65325,77,8559,77,8499,77,119820,77,119872,77,119924,77,120028,77,120080,77,120132,77,120184,77,120236,77,120288,77,120340,77,120392,77,120444,77,924,77,120499,77,120557,77,120615,77,120673,77,120731,77,1018,77,11416,77,5047,77,5616,77,5846,77,42207,77,66224,77,66321,77,119847,110,119899,110,119951,110,120003,110,120055,110,120107,110,120159,110,120211,110,120263,110,120315,110,120367,110,120419,110,120471,110,1400,110,1404,110,65326,78,8469,78,119821,78,119873,78,119925,78,119977,78,120029,78,120081,78,120185,78,120237,78,120289,78,120341,78,120393,78,120445,78,925,78,120500,78,120558,78,120616,78,120674,78,120732,78,11418,78,42208,78,66835,78,3074,111,3202,111,3330,111,3458,111,2406,111,2662,111,2790,111,3046,111,3174,111,3302,111,3430,111,3664,111,3792,111,4160,111,1637,111,1781,111,65359,111,8500,111,119848,111,119900,111,119952,111,120056,111,120108,111,120160,111,120212,111,120264,111,120316,111,120368,111,120420,111,120472,111,7439,111,7441,111,43837,111,959,111,120528,111,120586,111,120644,111,120702,111,120760,111,963,111,120532,111,120590,111,120648,111,120706,111,120764,111,11423,111,4351,111,1413,111,1505,111,1607,111,126500,111,126564,111,126596,111,65259,111,65260,111,65258,111,65257,111,1726,111,64428,111,64429,111,64427,111,64426,111,1729,111,64424,111,64425,111,64423,111,64422,111,1749,111,3360,111,4125,111,66794,111,71880,111,71895,111,66604,111,1984,79,2534,79,2918,79,12295,79,70864,79,71904,79,120782,79,120792,79,120802,79,120812,79,120822,79,130032,79,65327,79,119822,79,119874,79,119926,79,119978,79,120030,79,120082,79,120134,79,120186,79,120238,79,120290,79,120342,79,120394,79,120446,79,927,79,120502,79,120560,79,120618,79,120676,79,120734,79,11422,79,1365,79,11604,79,4816,79,2848,79,66754,79,42227,79,71861,79,66194,79,66219,79,66564,79,66838,79,9076,112,65360,112,119849,112,119901,112,119953,112,120005,112,120057,112,120109,112,120161,112,120213,112,120265,112,120317,112,120369,112,120421,112,120473,112,961,112,120530,112,120544,112,120588,112,120602,112,120646,112,120660,112,120704,112,120718,112,120762,112,120776,112,11427,112,65328,80,8473,80,119823,80,119875,80,119927,80,119979,80,120031,80,120083,80,120187,80,120239,80,120291,80,120343,80,120395,80,120447,80,929,80,120504,80,120562,80,120620,80,120678,80,120736,80,11426,80,5090,80,5229,80,42193,80,66197,80,119850,113,119902,113,119954,113,120006,113,120058,113,120110,113,120162,113,120214,113,120266,113,120318,113,120370,113,120422,113,120474,113,1307,113,1379,113,1382,113,8474,81,119824,81,119876,81,119928,81,119980,81,120032,81,120084,81,120188,81,120240,81,120292,81,120344,81,120396,81,120448,81,11605,81,119851,114,119903,114,119955,114,120007,114,120059,114,120111,114,120163,114,120215,114,120267,114,120319,114,120371,114,120423,114,120475,114,43847,114,43848,114,7462,114,11397,114,43905,114,119318,82,8475,82,8476,82,8477,82,119825,82,119877,82,119929,82,120033,82,120189,82,120241,82,120293,82,120345,82,120397,82,120449,82,422,82,5025,82,5074,82,66740,82,5511,82,42211,82,94005,82,65363,115,119852,115,119904,115,119956,115,120008,115,120060,115,120112,115,120164,115,120216,115,120268,115,120320,115,120372,115,120424,115,120476,115,42801,115,445,115,1109,115,43946,115,71873,115,66632,115,65331,83,119826,83,119878,83,119930,83,119982,83,120034,83,120086,83,120138,83,120190,83,120242,83,120294,83,120346,83,120398,83,120450,83,1029,83,1359,83,5077,83,5082,83,42210,83,94010,83,66198,83,66592,83,119853,116,119905,116,119957,116,120009,116,120061,116,120113,116,120165,116,120217,116,120269,116,120321,116,120373,116,120425,116,120477,116,8868,84,10201,84,128872,84,65332,84,119827,84,119879,84,119931,84,119983,84,120035,84,120087,84,120139,84,120191,84,120243,84,120295,84,120347,84,120399,84,120451,84,932,84,120507,84,120565,84,120623,84,120681,84,120739,84,11430,84,5026,84,42196,84,93962,84,71868,84,66199,84,66225,84,66325,84,119854,117,119906,117,119958,117,120010,117,120062,117,120114,117,120166,117,120218,117,120270,117,120322,117,120374,117,120426,117,120478,117,42911,117,7452,117,43854,117,43858,117,651,117,965,117,120534,117,120592,117,120650,117,120708,117,120766,117,1405,117,66806,117,71896,117,8746,85,8899,85,119828,85,119880,85,119932,85,119984,85,120036,85,120088,85,120140,85,120192,85,120244,85,120296,85,120348,85,120400,85,120452,85,1357,85,4608,85,66766,85,5196,85,42228,85,94018,85,71864,85,8744,118,8897,118,65366,118,8564,118,119855,118,119907,118,119959,118,120011,118,120063,118,120115,118,120167,118,120219,118,120271,118,120323,118,120375,118,120427,118,120479,118,7456,118,957,118,120526,118,120584,118,120642,118,120700,118,120758,118,1141,118,1496,118,71430,118,43945,118,71872,118,119309,86,1639,86,1783,86,8548,86,119829,86,119881,86,119933,86,119985,86,120037,86,120089,86,120141,86,120193,86,120245,86,120297,86,120349,86,120401,86,120453,86,1140,86,11576,86,5081,86,5167,86,42719,86,42214,86,93960,86,71840,86,66845,86,623,119,119856,119,119908,119,119960,119,120012,119,120064,119,120116,119,120168,119,120220,119,120272,119,120324,119,120376,119,120428,119,120480,119,7457,119,1121,119,1309,119,1377,119,71434,119,71438,119,71439,119,43907,119,71919,87,71910,87,119830,87,119882,87,119934,87,119986,87,120038,87,120090,87,120142,87,120194,87,120246,87,120298,87,120350,87,120402,87,120454,87,1308,87,5043,87,5076,87,42218,87,5742,120,10539,120,10540,120,10799,120,65368,120,8569,120,119857,120,119909,120,119961,120,120013,120,120065,120,120117,120,120169,120,120221,120,120273,120,120325,120,120377,120,120429,120,120481,120,5441,120,5501,120,5741,88,9587,88,66338,88,71916,88,65336,88,8553,88,119831,88,119883,88,119935,88,119987,88,120039,88,120091,88,120143,88,120195,88,120247,88,120299,88,120351,88,120403,88,120455,88,42931,88,935,88,120510,88,120568,88,120626,88,120684,88,120742,88,11436,88,11613,88,5815,88,42219,88,66192,88,66228,88,66327,88,66855,88,611,121,7564,121,65369,121,119858,121,119910,121,119962,121,120014,121,120066,121,120118,121,120170,121,120222,121,120274,121,120326,121,120378,121,120430,121,120482,121,655,121,7935,121,43866,121,947,121,8509,121,120516,121,120574,121,120632,121,120690,121,120748,121,1199,121,4327,121,71900,121,65337,89,119832,89,119884,89,119936,89,119988,89,120040,89,120092,89,120144,89,120196,89,120248,89,120300,89,120352,89,120404,89,120456,89,933,89,978,89,120508,89,120566,89,120624,89,120682,89,120740,89,11432,89,1198,89,5033,89,5053,89,42220,89,94019,89,71844,89,66226,89,119859,122,119911,122,119963,122,120015,122,120067,122,120119,122,120171,122,120223,122,120275,122,120327,122,120379,122,120431,122,120483,122,7458,122,43923,122,71876,122,66293,90,71909,90,65338,90,8484,90,8488,90,119833,90,119885,90,119937,90,119989,90,120041,90,120197,90,120249,90,120301,90,120353,90,120405,90,120457,90,918,90,120493,90,120551,90,120609,90,120667,90,120725,90,5059,90,42204,90,71849,90,65282,34,65284,36,65285,37,65286,38,65290,42,65291,43,65294,46,65295,47,65296,48,65297,49,65298,50,65299,51,65300,52,65301,53,65302,54,65303,55,65304,56,65305,57,65308,60,65309,61,65310,62,65312,64,65316,68,65318,70,65319,71,65324,76,65329,81,65330,82,65333,85,65334,86,65335,87,65343,95,65346,98,65348,100,65350,102,65355,107,65357,109,65358,110,65361,113,65362,114,65364,116,65365,117,65367,119,65370,122,65371,123,65373,125,119846,109],\"_default\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"cs\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"de\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"es\":[8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"fr\":[65374,126,65306,58,65281,33,8216,96,8245,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"it\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"ja\":[8211,45,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65292,44,65307,59],\"ko\":[8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"pl\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"pt-BR\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"qps-ploc\":[160,32,8211,45,65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"ru\":[65374,126,65306,58,65281,33,8216,96,8217,96,8245,96,180,96,12494,47,305,105,921,73,1009,112,215,120,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"tr\":[160,32,8211,45,65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65288,40,65289,41,65292,44,65307,59,65311,63],\"zh-hans\":[65374,126,65306,58,65281,33,8245,96,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65288,40,65289,41],\"zh-hant\":[8211,45,65374,126,180,96,12494,47,1047,51,1073,54,1072,97,1040,65,1068,98,1042,66,1089,99,1057,67,1077,101,1045,69,1053,72,305,105,1050,75,921,73,1052,77,1086,111,1054,79,1009,112,1088,112,1056,80,1075,114,1058,84,215,120,1093,120,1061,88,1091,121,1059,89,65283,35,65307,59]}'); }); } static { this.cache = new LRUCachedFunction({ getCacheKey: JSON.stringify }, (locales) => { function arrayToMap(arr) { const result = new Map(); for (let i = 0; i < arr.length; i += 2) { result.set(arr[i], arr[i + 1]); } return result; } function mergeMaps(map1, map2) { const result = new Map(map1); for (const [key, value] of map2) { result.set(key, value); } return result; } function intersectMaps(map1, map2) { if (!map1) { return map2; } const result = new Map(); for (const [key, value] of map1) { if (map2.has(key)) { result.set(key, value); } } return result; } const data = this.ambiguousCharacterData.value; let filteredLocales = locales.filter((l) => !l.startsWith('_') && l in data); if (filteredLocales.length === 0) { filteredLocales = ['_default']; } let languageSpecificMap = undefined; for (const locale of filteredLocales) { const map = arrayToMap(data[locale]); languageSpecificMap = intersectMaps(languageSpecificMap, map); } const commonMap = arrayToMap(data['_common']); const map = mergeMaps(commonMap, languageSpecificMap); return new AmbiguousCharacters(map); }); } static getInstance(locales) { return AmbiguousCharacters.cache.get(Array.from(locales)); } static { this._locales = new Lazy(() => Object.keys(AmbiguousCharacters.ambiguousCharacterData.value).filter((k) => !k.startsWith('_'))); } static getLocales() { return AmbiguousCharacters._locales.value; } constructor(confusableDictionary) { this.confusableDictionary = confusableDictionary; } isAmbiguous(codePoint) { return this.confusableDictionary.has(codePoint); } /** * Returns the non basic ASCII code point that the given code point can be confused, * or undefined if such code point does note exist. */ getPrimaryConfusable(codePoint) { return this.confusableDictionary.get(codePoint); } getConfusableCodePoints() { return new Set(this.confusableDictionary.keys()); } } class InvisibleCharacters { static getRawData() { // Generated using https://github.com/hediet/vscode-unicode-data return JSON.parse('[9,10,11,12,13,32,127,160,173,847,1564,4447,4448,6068,6069,6155,6156,6157,6158,7355,7356,8192,8193,8194,8195,8196,8197,8198,8199,8200,8201,8202,8203,8204,8205,8206,8207,8234,8235,8236,8237,8238,8239,8287,8288,8289,8290,8291,8292,8293,8294,8295,8296,8297,8298,8299,8300,8301,8302,8303,10240,12288,12644,65024,65025,65026,65027,65028,65029,65030,65031,65032,65033,65034,65035,65036,65037,65038,65039,65279,65440,65520,65521,65522,65523,65524,65525,65526,65527,65528,65532,78844,119155,119156,119157,119158,119159,119160,119161,119162,917504,917505,917506,917507,917508,917509,917510,917511,917512,917513,917514,917515,917516,917517,917518,917519,917520,917521,917522,917523,917524,917525,917526,917527,917528,917529,917530,917531,917532,917533,917534,917535,917536,917537,917538,917539,917540,917541,917542,917543,917544,917545,917546,917547,917548,917549,917550,917551,917552,917553,917554,917555,917556,917557,917558,917559,917560,917561,917562,917563,917564,917565,917566,917567,917568,917569,917570,917571,917572,917573,917574,917575,917576,917577,917578,917579,917580,917581,917582,917583,917584,917585,917586,917587,917588,917589,917590,917591,917592,917593,917594,917595,917596,917597,917598,917599,917600,917601,917602,917603,917604,917605,917606,917607,917608,917609,917610,917611,917612,917613,917614,917615,917616,917617,917618,917619,917620,917621,917622,917623,917624,917625,917626,917627,917628,917629,917630,917631,917760,917761,917762,917763,917764,917765,917766,917767,917768,917769,917770,917771,917772,917773,917774,917775,917776,917777,917778,917779,917780,917781,917782,917783,917784,917785,917786,917787,917788,917789,917790,917791,917792,917793,917794,917795,917796,917797,917798,917799,917800,917801,917802,917803,917804,917805,917806,917807,917808,917809,917810,917811,917812,917813,917814,917815,917816,917817,917818,917819,917820,917821,917822,917823,917824,917825,917826,917827,917828,917829,917830,917831,917832,917833,917834,917835,917836,917837,917838,917839,917840,917841,917842,917843,917844,917845,917846,917847,917848,917849,917850,917851,917852,917853,917854,917855,917856,917857,917858,917859,917860,917861,917862,917863,917864,917865,917866,917867,917868,917869,917870,917871,917872,917873,917874,917875,917876,917877,917878,917879,917880,917881,917882,917883,917884,917885,917886,917887,917888,917889,917890,917891,917892,917893,917894,917895,917896,917897,917898,917899,917900,917901,917902,917903,917904,917905,917906,917907,917908,917909,917910,917911,917912,917913,917914,917915,917916,917917,917918,917919,917920,917921,917922,917923,917924,917925,917926,917927,917928,917929,917930,917931,917932,917933,917934,917935,917936,917937,917938,917939,917940,917941,917942,917943,917944,917945,917946,917947,917948,917949,917950,917951,917952,917953,917954,917955,917956,917957,917958,917959,917960,917961,917962,917963,917964,917965,917966,917967,917968,917969,917970,917971,917972,917973,917974,917975,917976,917977,917978,917979,917980,917981,917982,917983,917984,917985,917986,917987,917988,917989,917990,917991,917992,917993,917994,917995,917996,917997,917998,917999]'); } static { this._data = undefined; } static getData() { if (!this._data) { this._data = new Set(InvisibleCharacters.getRawData()); } return this._data; } static isInvisibleCharacter(codePoint) { return InvisibleCharacters.getData().has(codePoint); } static get codePoints() { return InvisibleCharacters.getData(); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ let safeProcess; // Native sandbox environment const vscodeGlobal = globalThis.vscode; if (typeof vscodeGlobal !== 'undefined' && typeof vscodeGlobal.process !== 'undefined') { const sandboxProcess = vscodeGlobal.process; safeProcess = { get platform() { return sandboxProcess.platform; }, get arch() { return sandboxProcess.arch; }, get env() { return sandboxProcess.env; }, cwd() { return sandboxProcess.cwd(); } }; } // Native node.js environment else if (typeof process !== 'undefined' && typeof process?.versions?.node === 'string') { safeProcess = { get platform() { return process.platform; }, get arch() { return process.arch; }, get env() { return process.env; }, cwd() { return process.env['VSCODE_CWD'] || process.cwd(); } }; } // Web environment else { safeProcess = { // Supported get platform() { return isWindows ? 'win32' : isMacintosh ? 'darwin' : 'linux'; }, get arch() { return undefined; /* arch is undefined in web */ }, // Unsupported get env() { return {}; }, cwd() { return '/'; } }; } /** * Provides safe access to the `cwd` property in node.js, sandboxed or web * environments. * * Note: in web, this property is hardcoded to be `/`. * * @skipMangle */ const cwd = safeProcess.cwd; /** * Provides safe access to the `env` property in node.js, sandboxed or web * environments. * * Note: in web, this property is hardcoded to be `{}`. */ const env = safeProcess.env; /** * Provides safe access to the `platform` property in node.js, sandboxed or web * environments. */ const platform = safeProcess.platform; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // NOTE: VSCode's copy of nodejs path library to be usable in common (non-node) namespace // Copied from: https://github.com/nodejs/node/commits/v20.9.0/lib/path.js // Excluding: the change that adds primordials // (https://github.com/nodejs/node/commit/187a862d221dec42fa9a5c4214e7034d9092792f and others) /** * Copyright Joyent, Inc. and other Node contributors. * * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the * "Software"), to deal in the Software without restriction, including * without limitation the rights to use, copy, modify, merge, publish, * distribute, sublicense, and/or sell copies of the Software, and to permit * persons to whom the Software is furnished to do so, subject to the * following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN * NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE * USE OR OTHER DEALINGS IN THE SOFTWARE. */ const CHAR_UPPERCASE_A = 65; /* A */ const CHAR_LOWERCASE_A = 97; /* a */ const CHAR_UPPERCASE_Z = 90; /* Z */ const CHAR_LOWERCASE_Z = 122; /* z */ const CHAR_DOT = 46; /* . */ const CHAR_FORWARD_SLASH = 47; /* / */ const CHAR_BACKWARD_SLASH = 92; /* \ */ const CHAR_COLON = 58; /* : */ const CHAR_QUESTION_MARK = 63; /* ? */ class ErrorInvalidArgType extends Error { constructor(name, expected, actual) { // determiner: 'must be' or 'must not be' let determiner; if (typeof expected === 'string' && expected.indexOf('not ') === 0) { determiner = 'must not be'; expected = expected.replace(/^not /, ''); } else { determiner = 'must be'; } const type = name.indexOf('.') !== -1 ? 'property' : 'argument'; let msg = `The "${name}" ${type} ${determiner} of type ${expected}`; msg += `. Received type ${typeof actual}`; super(msg); this.code = 'ERR_INVALID_ARG_TYPE'; } } function validateObject(pathObject, name) { if (pathObject === null || typeof pathObject !== 'object') { throw new ErrorInvalidArgType(name, 'Object', pathObject); } } function validateString(value, name) { if (typeof value !== 'string') { throw new ErrorInvalidArgType(name, 'string', value); } } const platformIsWin32 = (platform === 'win32'); function isPathSeparator(code) { return code === CHAR_FORWARD_SLASH || code === CHAR_BACKWARD_SLASH; } function isPosixPathSeparator(code) { return code === CHAR_FORWARD_SLASH; } function isWindowsDeviceRoot(code) { return (code >= CHAR_UPPERCASE_A && code <= CHAR_UPPERCASE_Z) || (code >= CHAR_LOWERCASE_A && code <= CHAR_LOWERCASE_Z); } // Resolves . and .. elements in a path with directory names function normalizeString(path, allowAboveRoot, separator, isPathSeparator) { let res = ''; let lastSegmentLength = 0; let lastSlash = -1; let dots = 0; let code = 0; for (let i = 0; i <= path.length; ++i) { if (i < path.length) { code = path.charCodeAt(i); } else if (isPathSeparator(code)) { break; } else { code = CHAR_FORWARD_SLASH; } if (isPathSeparator(code)) { if (lastSlash === i - 1 || dots === 1) ; else if (dots === 2) { if (res.length < 2 || lastSegmentLength !== 2 || res.charCodeAt(res.length - 1) !== CHAR_DOT || res.charCodeAt(res.length - 2) !== CHAR_DOT) { if (res.length > 2) { const lastSlashIndex = res.lastIndexOf(separator); if (lastSlashIndex === -1) { res = ''; lastSegmentLength = 0; } else { res = res.slice(0, lastSlashIndex); lastSegmentLength = res.length - 1 - res.lastIndexOf(separator); } lastSlash = i; dots = 0; continue; } else if (res.length !== 0) { res = ''; lastSegmentLength = 0; lastSlash = i; dots = 0; continue; } } if (allowAboveRoot) { res += res.length > 0 ? `${separator}..` : '..'; lastSegmentLength = 2; } } else { if (res.length > 0) { res += `${separator}${path.slice(lastSlash + 1, i)}`; } else { res = path.slice(lastSlash + 1, i); } lastSegmentLength = i - lastSlash - 1; } lastSlash = i; dots = 0; } else if (code === CHAR_DOT && dots !== -1) { ++dots; } else { dots = -1; } } return res; } function formatExt(ext) { return ext ? `${ext[0] === '.' ? '' : '.'}${ext}` : ''; } function _format(sep, pathObject) { validateObject(pathObject, 'pathObject'); const dir = pathObject.dir || pathObject.root; const base = pathObject.base || `${pathObject.name || ''}${formatExt(pathObject.ext)}`; if (!dir) { return base; } return dir === pathObject.root ? `${dir}${base}` : `${dir}${sep}${base}`; } const win32 = { // path.resolve([from ...], to) resolve(...pathSegments) { let resolvedDevice = ''; let resolvedTail = ''; let resolvedAbsolute = false; for (let i = pathSegments.length - 1; i >= -1; i--) { let path; if (i >= 0) { path = pathSegments[i]; validateString(path, `paths[${i}]`); // Skip empty entries if (path.length === 0) { continue; } } else if (resolvedDevice.length === 0) { path = cwd(); } else { // Windows has the concept of drive-specific current working // directories. If we've resolved a drive letter but not yet an // absolute path, get cwd for that drive, or the process cwd if // the drive cwd is not available. We're sure the device is not // a UNC path at this points, because UNC paths are always absolute. path = env[`=${resolvedDevice}`] || cwd(); // Verify that a cwd was found and that it actually points // to our drive. If not, default to the drive's root. if (path === undefined || (path.slice(0, 2).toLowerCase() !== resolvedDevice.toLowerCase() && path.charCodeAt(2) === CHAR_BACKWARD_SLASH)) { path = `${resolvedDevice}\\`; } } const len = path.length; let rootEnd = 0; let device = ''; let isAbsolute = false; const code = path.charCodeAt(0); // Try to match a root if (len === 1) { if (isPathSeparator(code)) { // `path` contains just a path separator rootEnd = 1; isAbsolute = true; } } else if (isPathSeparator(code)) { // Possible UNC root // If we started with a separator, we know we at least have an // absolute path of some kind (UNC or otherwise) isAbsolute = true; if (isPathSeparator(path.charCodeAt(1))) { // Matched double path separator at beginning let j = 2; let last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { const firstPart = path.slice(last, j); // Matched! last = j; // Match 1 or more path separators while (j < len && isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j === len || j !== last) { // We matched a UNC root device = `\\\\${firstPart}\\${path.slice(last, j)}`; rootEnd = j; } } } } else { rootEnd = 1; } } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { // Possible device root device = path.slice(0, 2); rootEnd = 2; if (len > 2 && isPathSeparator(path.charCodeAt(2))) { // Treat separator following drive name as an absolute path // indicator isAbsolute = true; rootEnd = 3; } } if (device.length > 0) { if (resolvedDevice.length > 0) { if (device.toLowerCase() !== resolvedDevice.toLowerCase()) { // This path points to another device so it is not applicable continue; } } else { resolvedDevice = device; } } if (resolvedAbsolute) { if (resolvedDevice.length > 0) { break; } } else { resolvedTail = `${path.slice(rootEnd)}\\${resolvedTail}`; resolvedAbsolute = isAbsolute; if (isAbsolute && resolvedDevice.length > 0) { break; } } } // At this point the path should be resolved to a full absolute path, // but handle relative paths to be safe (might happen when process.cwd() // fails) // Normalize the tail path resolvedTail = normalizeString(resolvedTail, !resolvedAbsolute, '\\', isPathSeparator); return resolvedAbsolute ? `${resolvedDevice}\\${resolvedTail}` : `${resolvedDevice}${resolvedTail}` || '.'; }, normalize(path) { validateString(path, 'path'); const len = path.length; if (len === 0) { return '.'; } let rootEnd = 0; let device; let isAbsolute = false; const code = path.charCodeAt(0); // Try to match a root if (len === 1) { // `path` contains just a single char, exit early to avoid // unnecessary work return isPosixPathSeparator(code) ? '\\' : path; } if (isPathSeparator(code)) { // Possible UNC root // If we started with a separator, we know we at least have an absolute // path of some kind (UNC or otherwise) isAbsolute = true; if (isPathSeparator(path.charCodeAt(1))) { // Matched double path separator at beginning let j = 2; let last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { const firstPart = path.slice(last, j); // Matched! last = j; // Match 1 or more path separators while (j < len && isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j === len) { // We matched a UNC root only // Return the normalized version of the UNC root since there // is nothing left to process return `\\\\${firstPart}\\${path.slice(last)}\\`; } if (j !== last) { // We matched a UNC root with leftovers device = `\\\\${firstPart}\\${path.slice(last, j)}`; rootEnd = j; } } } } else { rootEnd = 1; } } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { // Possible device root device = path.slice(0, 2); rootEnd = 2; if (len > 2 && isPathSeparator(path.charCodeAt(2))) { // Treat separator following drive name as an absolute path // indicator isAbsolute = true; rootEnd = 3; } } let tail = rootEnd < len ? normalizeString(path.slice(rootEnd), !isAbsolute, '\\', isPathSeparator) : ''; if (tail.length === 0 && !isAbsolute) { tail = '.'; } if (tail.length > 0 && isPathSeparator(path.charCodeAt(len - 1))) { tail += '\\'; } if (device === undefined) { return isAbsolute ? `\\${tail}` : tail; } return isAbsolute ? `${device}\\${tail}` : `${device}${tail}`; }, isAbsolute(path) { validateString(path, 'path'); const len = path.length; if (len === 0) { return false; } const code = path.charCodeAt(0); return isPathSeparator(code) || // Possible device root (len > 2 && isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON && isPathSeparator(path.charCodeAt(2))); }, join(...paths) { if (paths.length === 0) { return '.'; } let joined; let firstPart; for (let i = 0; i < paths.length; ++i) { const arg = paths[i]; validateString(arg, 'path'); if (arg.length > 0) { if (joined === undefined) { joined = firstPart = arg; } else { joined += `\\${arg}`; } } } if (joined === undefined) { return '.'; } // Make sure that the joined path doesn't start with two slashes, because // normalize() will mistake it for a UNC path then. // // This step is skipped when it is very clear that the user actually // intended to point at a UNC path. This is assumed when the first // non-empty string arguments starts with exactly two slashes followed by // at least one more non-slash character. // // Note that for normalize() to treat a path as a UNC path it needs to // have at least 2 components, so we don't filter for that here. // This means that the user can use join to construct UNC paths from // a server name and a share name; for example: // path.join('//server', 'share') -> '\\\\server\\share\\') let needsReplace = true; let slashCount = 0; if (typeof firstPart === 'string' && isPathSeparator(firstPart.charCodeAt(0))) { ++slashCount; const firstLen = firstPart.length; if (firstLen > 1 && isPathSeparator(firstPart.charCodeAt(1))) { ++slashCount; if (firstLen > 2) { if (isPathSeparator(firstPart.charCodeAt(2))) { ++slashCount; } else { // We matched a UNC path in the first part needsReplace = false; } } } } if (needsReplace) { // Find any more consecutive slashes we need to replace while (slashCount < joined.length && isPathSeparator(joined.charCodeAt(slashCount))) { slashCount++; } // Replace the slashes if needed if (slashCount >= 2) { joined = `\\${joined.slice(slashCount)}`; } } return win32.normalize(joined); }, // It will solve the relative path from `from` to `to`, for instance: // from = 'C:\\orandea\\test\\aaa' // to = 'C:\\orandea\\impl\\bbb' // The output of the function should be: '..\\..\\impl\\bbb' relative(from, to) { validateString(from, 'from'); validateString(to, 'to'); if (from === to) { return ''; } const fromOrig = win32.resolve(from); const toOrig = win32.resolve(to); if (fromOrig === toOrig) { return ''; } from = fromOrig.toLowerCase(); to = toOrig.toLowerCase(); if (from === to) { return ''; } // Trim any leading backslashes let fromStart = 0; while (fromStart < from.length && from.charCodeAt(fromStart) === CHAR_BACKWARD_SLASH) { fromStart++; } // Trim trailing backslashes (applicable to UNC paths only) let fromEnd = from.length; while (fromEnd - 1 > fromStart && from.charCodeAt(fromEnd - 1) === CHAR_BACKWARD_SLASH) { fromEnd--; } const fromLen = fromEnd - fromStart; // Trim any leading backslashes let toStart = 0; while (toStart < to.length && to.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) { toStart++; } // Trim trailing backslashes (applicable to UNC paths only) let toEnd = to.length; while (toEnd - 1 > toStart && to.charCodeAt(toEnd - 1) === CHAR_BACKWARD_SLASH) { toEnd--; } const toLen = toEnd - toStart; // Compare paths to find the longest common path from root const length = fromLen < toLen ? fromLen : toLen; let lastCommonSep = -1; let i = 0; for (; i < length; i++) { const fromCode = from.charCodeAt(fromStart + i); if (fromCode !== to.charCodeAt(toStart + i)) { break; } else if (fromCode === CHAR_BACKWARD_SLASH) { lastCommonSep = i; } } // We found a mismatch before the first common path separator was seen, so // return the original `to`. if (i !== length) { if (lastCommonSep === -1) { return toOrig; } } else { if (toLen > length) { if (to.charCodeAt(toStart + i) === CHAR_BACKWARD_SLASH) { // We get here if `from` is the exact base path for `to`. // For example: from='C:\\foo\\bar'; to='C:\\foo\\bar\\baz' return toOrig.slice(toStart + i + 1); } if (i === 2) { // We get here if `from` is the device root. // For example: from='C:\\'; to='C:\\foo' return toOrig.slice(toStart + i); } } if (fromLen > length) { if (from.charCodeAt(fromStart + i) === CHAR_BACKWARD_SLASH) { // We get here if `to` is the exact base path for `from`. // For example: from='C:\\foo\\bar'; to='C:\\foo' lastCommonSep = i; } else if (i === 2) { // We get here if `to` is the device root. // For example: from='C:\\foo\\bar'; to='C:\\' lastCommonSep = 3; } } if (lastCommonSep === -1) { lastCommonSep = 0; } } let out = ''; // Generate the relative path based on the path difference between `to` and // `from` for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { if (i === fromEnd || from.charCodeAt(i) === CHAR_BACKWARD_SLASH) { out += out.length === 0 ? '..' : '\\..'; } } toStart += lastCommonSep; // Lastly, append the rest of the destination (`to`) path that comes after // the common path parts if (out.length > 0) { return `${out}${toOrig.slice(toStart, toEnd)}`; } if (toOrig.charCodeAt(toStart) === CHAR_BACKWARD_SLASH) { ++toStart; } return toOrig.slice(toStart, toEnd); }, toNamespacedPath(path) { // Note: this will *probably* throw somewhere. if (typeof path !== 'string' || path.length === 0) { return path; } const resolvedPath = win32.resolve(path); if (resolvedPath.length <= 2) { return path; } if (resolvedPath.charCodeAt(0) === CHAR_BACKWARD_SLASH) { // Possible UNC root if (resolvedPath.charCodeAt(1) === CHAR_BACKWARD_SLASH) { const code = resolvedPath.charCodeAt(2); if (code !== CHAR_QUESTION_MARK && code !== CHAR_DOT) { // Matched non-long UNC root, convert the path to a long UNC path return `\\\\?\\UNC\\${resolvedPath.slice(2)}`; } } } else if (isWindowsDeviceRoot(resolvedPath.charCodeAt(0)) && resolvedPath.charCodeAt(1) === CHAR_COLON && resolvedPath.charCodeAt(2) === CHAR_BACKWARD_SLASH) { // Matched device root, convert the path to a long UNC path return `\\\\?\\${resolvedPath}`; } return path; }, dirname(path) { validateString(path, 'path'); const len = path.length; if (len === 0) { return '.'; } let rootEnd = -1; let offset = 0; const code = path.charCodeAt(0); if (len === 1) { // `path` contains just a path separator, exit early to avoid // unnecessary work or a dot. return isPathSeparator(code) ? path : '.'; } // Try to match a root if (isPathSeparator(code)) { // Possible UNC root rootEnd = offset = 1; if (isPathSeparator(path.charCodeAt(1))) { // Matched double path separator at beginning let j = 2; let last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more path separators while (j < len && isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j === len) { // We matched a UNC root only return path; } if (j !== last) { // We matched a UNC root with leftovers // Offset by 1 to include the separator after the UNC root to // treat it as a "normal root" on top of a (UNC) root rootEnd = offset = j + 1; } } } } // Possible device root } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { rootEnd = len > 2 && isPathSeparator(path.charCodeAt(2)) ? 3 : 2; offset = rootEnd; } let end = -1; let matchedSlash = true; for (let i = len - 1; i >= offset; --i) { if (isPathSeparator(path.charCodeAt(i))) { if (!matchedSlash) { end = i; break; } } else { // We saw the first non-path separator matchedSlash = false; } } if (end === -1) { if (rootEnd === -1) { return '.'; } end = rootEnd; } return path.slice(0, end); }, basename(path, suffix) { if (suffix !== undefined) { validateString(suffix, 'suffix'); } validateString(path, 'path'); let start = 0; let end = -1; let matchedSlash = true; let i; // Check for a drive letter prefix so as not to mistake the following // path separator as an extra separator at the end of the path that can be // disregarded if (path.length >= 2 && isWindowsDeviceRoot(path.charCodeAt(0)) && path.charCodeAt(1) === CHAR_COLON) { start = 2; } if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) { if (suffix === path) { return ''; } let extIdx = suffix.length - 1; let firstNonSlashEnd = -1; for (i = path.length - 1; i >= start; --i) { const code = path.charCodeAt(i); if (isPathSeparator(code)) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { start = i + 1; break; } } else { if (firstNonSlashEnd === -1) { // We saw the first non-path separator, remember this index in case // we need it if the extension ends up not matching matchedSlash = false; firstNonSlashEnd = i + 1; } if (extIdx >= 0) { // Try to match the explicit extension if (code === suffix.charCodeAt(extIdx)) { if (--extIdx === -1) { // We matched the extension, so mark this as the end of our path // component end = i; } } else { // Extension does not match, so our result is the entire path // component extIdx = -1; end = firstNonSlashEnd; } } } } if (start === end) { end = firstNonSlashEnd; } else if (end === -1) { end = path.length; } return path.slice(start, end); } for (i = path.length - 1; i >= start; --i) { if (isPathSeparator(path.charCodeAt(i))) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { start = i + 1; break; } } else if (end === -1) { // We saw the first non-path separator, mark this as the end of our // path component matchedSlash = false; end = i + 1; } } if (end === -1) { return ''; } return path.slice(start, end); }, extname(path) { validateString(path, 'path'); let start = 0; let startDot = -1; let startPart = 0; let end = -1; let matchedSlash = true; // Track the state of characters (if any) we see before our first dot and // after any path separator we find let preDotState = 0; // Check for a drive letter prefix so as not to mistake the following // path separator as an extra separator at the end of the path that can be // disregarded if (path.length >= 2 && path.charCodeAt(1) === CHAR_COLON && isWindowsDeviceRoot(path.charCodeAt(0))) { start = startPart = 2; } for (let i = path.length - 1; i >= start; --i) { const code = path.charCodeAt(i); if (isPathSeparator(code)) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { startPart = i + 1; break; } continue; } if (end === -1) { // We saw the first non-path separator, mark this as the end of our // extension matchedSlash = false; end = i + 1; } if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) { startDot = i; } else if (preDotState !== 1) { preDotState = 1; } } else if (startDot !== -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension preDotState = -1; } } if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot preDotState === 0 || // The (right-most) trimmed path component is exactly '..' (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) { return ''; } return path.slice(startDot, end); }, format: _format.bind(null, '\\'), parse(path) { validateString(path, 'path'); const ret = { root: '', dir: '', base: '', ext: '', name: '' }; if (path.length === 0) { return ret; } const len = path.length; let rootEnd = 0; let code = path.charCodeAt(0); if (len === 1) { if (isPathSeparator(code)) { // `path` contains just a path separator, exit early to avoid // unnecessary work ret.root = ret.dir = path; return ret; } ret.base = ret.name = path; return ret; } // Try to match a root if (isPathSeparator(code)) { // Possible UNC root rootEnd = 1; if (isPathSeparator(path.charCodeAt(1))) { // Matched double path separator at beginning let j = 2; let last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more path separators while (j < len && isPathSeparator(path.charCodeAt(j))) { j++; } if (j < len && j !== last) { // Matched! last = j; // Match 1 or more non-path separators while (j < len && !isPathSeparator(path.charCodeAt(j))) { j++; } if (j === len) { // We matched a UNC root only rootEnd = j; } else if (j !== last) { // We matched a UNC root with leftovers rootEnd = j + 1; } } } } } else if (isWindowsDeviceRoot(code) && path.charCodeAt(1) === CHAR_COLON) { // Possible device root if (len <= 2) { // `path` contains just a drive root, exit early to avoid // unnecessary work ret.root = ret.dir = path; return ret; } rootEnd = 2; if (isPathSeparator(path.charCodeAt(2))) { if (len === 3) { // `path` contains just a drive root, exit early to avoid // unnecessary work ret.root = ret.dir = path; return ret; } rootEnd = 3; } } if (rootEnd > 0) { ret.root = path.slice(0, rootEnd); } let startDot = -1; let startPart = rootEnd; let end = -1; let matchedSlash = true; let i = path.length - 1; // Track the state of characters (if any) we see before our first dot and // after any path separator we find let preDotState = 0; // Get non-dir info for (; i >= rootEnd; --i) { code = path.charCodeAt(i); if (isPathSeparator(code)) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { startPart = i + 1; break; } continue; } if (end === -1) { // We saw the first non-path separator, mark this as the end of our // extension matchedSlash = false; end = i + 1; } if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) { startDot = i; } else if (preDotState !== 1) { preDotState = 1; } } else if (startDot !== -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension preDotState = -1; } } if (end !== -1) { if (startDot === -1 || // We saw a non-dot character immediately before the dot preDotState === 0 || // The (right-most) trimmed path component is exactly '..' (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) { ret.base = ret.name = path.slice(startPart, end); } else { ret.name = path.slice(startPart, startDot); ret.base = path.slice(startPart, end); ret.ext = path.slice(startDot, end); } } // If the directory is the root, use the entire root as the `dir` including // the trailing slash if any (`C:\abc` -> `C:\`). Otherwise, strip out the // trailing slash (`C:\abc\def` -> `C:\abc`). if (startPart > 0 && startPart !== rootEnd) { ret.dir = path.slice(0, startPart - 1); } else { ret.dir = ret.root; } return ret; }, sep: '\\', delimiter: ';', win32: null, posix: null }; const posixCwd = (() => { if (platformIsWin32) { // Converts Windows' backslash path separators to POSIX forward slashes // and truncates any drive indicator const regexp = /\\/g; return () => { const cwd$1 = cwd().replace(regexp, '/'); return cwd$1.slice(cwd$1.indexOf('/')); }; } // We're already on POSIX, no need for any transformations return () => cwd(); })(); const posix = { // path.resolve([from ...], to) resolve(...pathSegments) { let resolvedPath = ''; let resolvedAbsolute = false; for (let i = pathSegments.length - 1; i >= -1 && !resolvedAbsolute; i--) { const path = i >= 0 ? pathSegments[i] : posixCwd(); validateString(path, `paths[${i}]`); // Skip empty entries if (path.length === 0) { continue; } resolvedPath = `${path}/${resolvedPath}`; resolvedAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; } // At this point the path should be resolved to a full absolute path, but // handle relative paths to be safe (might happen when process.cwd() fails) // Normalize the path resolvedPath = normalizeString(resolvedPath, !resolvedAbsolute, '/', isPosixPathSeparator); if (resolvedAbsolute) { return `/${resolvedPath}`; } return resolvedPath.length > 0 ? resolvedPath : '.'; }, normalize(path) { validateString(path, 'path'); if (path.length === 0) { return '.'; } const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; const trailingSeparator = path.charCodeAt(path.length - 1) === CHAR_FORWARD_SLASH; // Normalize the path path = normalizeString(path, !isAbsolute, '/', isPosixPathSeparator); if (path.length === 0) { if (isAbsolute) { return '/'; } return trailingSeparator ? './' : '.'; } if (trailingSeparator) { path += '/'; } return isAbsolute ? `/${path}` : path; }, isAbsolute(path) { validateString(path, 'path'); return path.length > 0 && path.charCodeAt(0) === CHAR_FORWARD_SLASH; }, join(...paths) { if (paths.length === 0) { return '.'; } let joined; for (let i = 0; i < paths.length; ++i) { const arg = paths[i]; validateString(arg, 'path'); if (arg.length > 0) { if (joined === undefined) { joined = arg; } else { joined += `/${arg}`; } } } if (joined === undefined) { return '.'; } return posix.normalize(joined); }, relative(from, to) { validateString(from, 'from'); validateString(to, 'to'); if (from === to) { return ''; } // Trim leading forward slashes. from = posix.resolve(from); to = posix.resolve(to); if (from === to) { return ''; } const fromStart = 1; const fromEnd = from.length; const fromLen = fromEnd - fromStart; const toStart = 1; const toLen = to.length - toStart; // Compare paths to find the longest common path from root const length = (fromLen < toLen ? fromLen : toLen); let lastCommonSep = -1; let i = 0; for (; i < length; i++) { const fromCode = from.charCodeAt(fromStart + i); if (fromCode !== to.charCodeAt(toStart + i)) { break; } else if (fromCode === CHAR_FORWARD_SLASH) { lastCommonSep = i; } } if (i === length) { if (toLen > length) { if (to.charCodeAt(toStart + i) === CHAR_FORWARD_SLASH) { // We get here if `from` is the exact base path for `to`. // For example: from='/foo/bar'; to='/foo/bar/baz' return to.slice(toStart + i + 1); } if (i === 0) { // We get here if `from` is the root // For example: from='/'; to='/foo' return to.slice(toStart + i); } } else if (fromLen > length) { if (from.charCodeAt(fromStart + i) === CHAR_FORWARD_SLASH) { // We get here if `to` is the exact base path for `from`. // For example: from='/foo/bar/baz'; to='/foo/bar' lastCommonSep = i; } else if (i === 0) { // We get here if `to` is the root. // For example: from='/foo/bar'; to='/' lastCommonSep = 0; } } } let out = ''; // Generate the relative path based on the path difference between `to` // and `from`. for (i = fromStart + lastCommonSep + 1; i <= fromEnd; ++i) { if (i === fromEnd || from.charCodeAt(i) === CHAR_FORWARD_SLASH) { out += out.length === 0 ? '..' : '/..'; } } // Lastly, append the rest of the destination (`to`) path that comes after // the common path parts. return `${out}${to.slice(toStart + lastCommonSep)}`; }, toNamespacedPath(path) { // Non-op on posix systems return path; }, dirname(path) { validateString(path, 'path'); if (path.length === 0) { return '.'; } const hasRoot = path.charCodeAt(0) === CHAR_FORWARD_SLASH; let end = -1; let matchedSlash = true; for (let i = path.length - 1; i >= 1; --i) { if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { if (!matchedSlash) { end = i; break; } } else { // We saw the first non-path separator matchedSlash = false; } } if (end === -1) { return hasRoot ? '/' : '.'; } if (hasRoot && end === 1) { return '//'; } return path.slice(0, end); }, basename(path, suffix) { if (suffix !== undefined) { validateString(suffix, 'ext'); } validateString(path, 'path'); let start = 0; let end = -1; let matchedSlash = true; let i; if (suffix !== undefined && suffix.length > 0 && suffix.length <= path.length) { if (suffix === path) { return ''; } let extIdx = suffix.length - 1; let firstNonSlashEnd = -1; for (i = path.length - 1; i >= 0; --i) { const code = path.charCodeAt(i); if (code === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { start = i + 1; break; } } else { if (firstNonSlashEnd === -1) { // We saw the first non-path separator, remember this index in case // we need it if the extension ends up not matching matchedSlash = false; firstNonSlashEnd = i + 1; } if (extIdx >= 0) { // Try to match the explicit extension if (code === suffix.charCodeAt(extIdx)) { if (--extIdx === -1) { // We matched the extension, so mark this as the end of our path // component end = i; } } else { // Extension does not match, so our result is the entire path // component extIdx = -1; end = firstNonSlashEnd; } } } } if (start === end) { end = firstNonSlashEnd; } else if (end === -1) { end = path.length; } return path.slice(start, end); } for (i = path.length - 1; i >= 0; --i) { if (path.charCodeAt(i) === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { start = i + 1; break; } } else if (end === -1) { // We saw the first non-path separator, mark this as the end of our // path component matchedSlash = false; end = i + 1; } } if (end === -1) { return ''; } return path.slice(start, end); }, extname(path) { validateString(path, 'path'); let startDot = -1; let startPart = 0; let end = -1; let matchedSlash = true; // Track the state of characters (if any) we see before our first dot and // after any path separator we find let preDotState = 0; for (let i = path.length - 1; i >= 0; --i) { const code = path.charCodeAt(i); if (code === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { startPart = i + 1; break; } continue; } if (end === -1) { // We saw the first non-path separator, mark this as the end of our // extension matchedSlash = false; end = i + 1; } if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) { startDot = i; } else if (preDotState !== 1) { preDotState = 1; } } else if (startDot !== -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension preDotState = -1; } } if (startDot === -1 || end === -1 || // We saw a non-dot character immediately before the dot preDotState === 0 || // The (right-most) trimmed path component is exactly '..' (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) { return ''; } return path.slice(startDot, end); }, format: _format.bind(null, '/'), parse(path) { validateString(path, 'path'); const ret = { root: '', dir: '', base: '', ext: '', name: '' }; if (path.length === 0) { return ret; } const isAbsolute = path.charCodeAt(0) === CHAR_FORWARD_SLASH; let start; if (isAbsolute) { ret.root = '/'; start = 1; } else { start = 0; } let startDot = -1; let startPart = 0; let end = -1; let matchedSlash = true; let i = path.length - 1; // Track the state of characters (if any) we see before our first dot and // after any path separator we find let preDotState = 0; // Get non-dir info for (; i >= start; --i) { const code = path.charCodeAt(i); if (code === CHAR_FORWARD_SLASH) { // If we reached a path separator that was not part of a set of path // separators at the end of the string, stop now if (!matchedSlash) { startPart = i + 1; break; } continue; } if (end === -1) { // We saw the first non-path separator, mark this as the end of our // extension matchedSlash = false; end = i + 1; } if (code === CHAR_DOT) { // If this is our first dot, mark it as the start of our extension if (startDot === -1) { startDot = i; } else if (preDotState !== 1) { preDotState = 1; } } else if (startDot !== -1) { // We saw a non-dot and non-path separator before our dot, so we should // have a good chance at having a non-empty extension preDotState = -1; } } if (end !== -1) { const start = startPart === 0 && isAbsolute ? 1 : startPart; if (startDot === -1 || // We saw a non-dot character immediately before the dot preDotState === 0 || // The (right-most) trimmed path component is exactly '..' (preDotState === 1 && startDot === end - 1 && startDot === startPart + 1)) { ret.base = ret.name = path.slice(start, end); } else { ret.name = path.slice(start, startDot); ret.base = path.slice(start, end); ret.ext = path.slice(startDot, end); } } if (startPart > 0) { ret.dir = path.slice(0, startPart - 1); } else if (isAbsolute) { ret.dir = '/'; } return ret; }, sep: '/', delimiter: ':', win32: null, posix: null }; posix.win32 = win32.win32 = win32; posix.posix = win32.posix = posix; (platformIsWin32 ? win32.normalize : posix.normalize); const join = (platformIsWin32 ? win32.join : posix.join); (platformIsWin32 ? win32.resolve : posix.resolve); (platformIsWin32 ? win32.relative : posix.relative); (platformIsWin32 ? win32.dirname : posix.dirname); (platformIsWin32 ? win32.basename : posix.basename); (platformIsWin32 ? win32.extname : posix.extname); (platformIsWin32 ? win32.sep : posix.sep); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const _schemePattern = /^\w[\w\d+.-]*$/; const _singleSlashStart = /^\//; const _doubleSlashStart = /^\/\//; function _validateUri(ret, _strict) { // scheme, must be set if (!ret.scheme && _strict) { throw new Error(`[UriError]: Scheme is missing: {scheme: "", authority: "${ret.authority}", path: "${ret.path}", query: "${ret.query}", fragment: "${ret.fragment}"}`); } // scheme, https://tools.ietf.org/html/rfc3986#section-3.1 // ALPHA *( ALPHA / DIGIT / "+" / "-" / "." ) if (ret.scheme && !_schemePattern.test(ret.scheme)) { throw new Error('[UriError]: Scheme contains illegal characters.'); } // path, http://tools.ietf.org/html/rfc3986#section-3.3 // If a URI contains an authority component, then the path component // must either be empty or begin with a slash ("/") character. If a URI // does not contain an authority component, then the path cannot begin // with two slash characters ("//"). if (ret.path) { if (ret.authority) { if (!_singleSlashStart.test(ret.path)) { throw new Error('[UriError]: If a URI contains an authority component, then the path component must either be empty or begin with a slash ("/") character'); } } else { if (_doubleSlashStart.test(ret.path)) { throw new Error('[UriError]: If a URI does not contain an authority component, then the path cannot begin with two slash characters ("//")'); } } } } // for a while we allowed uris *without* schemes and this is the migration // for them, e.g. an uri without scheme and without strict-mode warns and falls // back to the file-scheme. that should cause the least carnage and still be a // clear warning function _schemeFix(scheme, _strict) { if (!scheme && !_strict) { return 'file'; } return scheme; } // implements a bit of https://tools.ietf.org/html/rfc3986#section-5 function _referenceResolution(scheme, path) { // the slash-character is our 'default base' as we don't // support constructing URIs relative to other URIs. This // also means that we alter and potentially break paths. // see https://tools.ietf.org/html/rfc3986#section-5.1.4 switch (scheme) { case 'https': case 'http': case 'file': if (!path) { path = _slash; } else if (path[0] !== _slash) { path = _slash + path; } break; } return path; } const _empty = ''; const _slash = '/'; const _regexp = /^(([^:/?#]+?):)?(\/\/([^/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; /** * Uniform Resource Identifier (URI) http://tools.ietf.org/html/rfc3986. * This class is a simple parser which creates the basic component parts * (http://tools.ietf.org/html/rfc3986#section-3) with minimal validation * and encoding. * * ```txt * foo://example.com:8042/over/there?name=ferret#nose * \_/ \______________/\_________/ \_________/ \__/ * | | | | | * scheme authority path query fragment * | _____________________|__ * / \ / \ * urn:example:animal:ferret:nose * ``` */ class URI { static isUri(thing) { if (thing instanceof URI) { return true; } if (!thing) { return false; } return typeof thing.authority === 'string' && typeof thing.fragment === 'string' && typeof thing.path === 'string' && typeof thing.query === 'string' && typeof thing.scheme === 'string' && typeof thing.fsPath === 'string' && typeof thing.with === 'function' && typeof thing.toString === 'function'; } /** * @internal */ constructor(schemeOrData, authority, path, query, fragment, _strict = false) { if (typeof schemeOrData === 'object') { this.scheme = schemeOrData.scheme || _empty; this.authority = schemeOrData.authority || _empty; this.path = schemeOrData.path || _empty; this.query = schemeOrData.query || _empty; this.fragment = schemeOrData.fragment || _empty; // no validation because it's this URI // that creates uri components. // _validateUri(this); } else { this.scheme = _schemeFix(schemeOrData, _strict); this.authority = authority || _empty; this.path = _referenceResolution(this.scheme, path || _empty); this.query = query || _empty; this.fragment = fragment || _empty; _validateUri(this, _strict); } } // ---- filesystem path ----------------------- /** * Returns a string representing the corresponding file system path of this URI. * Will handle UNC paths, normalizes windows drive letters to lower-case, and uses the * platform specific path separator. * * * Will *not* validate the path for invalid characters and semantics. * * Will *not* look at the scheme of this URI. * * The result shall *not* be used for display purposes but for accessing a file on disk. * * * The *difference* to `URI#path` is the use of the platform specific separator and the handling * of UNC paths. See the below sample of a file-uri with an authority (UNC path). * * ```ts const u = URI.parse('file://server/c$/folder/file.txt') u.authority === 'server' u.path === '/shares/c$/file.txt' u.fsPath === '\\server\c$\folder\file.txt' ``` * * Using `URI#path` to read a file (using fs-apis) would not be enough because parts of the path, * namely the server name, would be missing. Therefore `URI#fsPath` exists - it's sugar to ease working * with URIs that represent files on disk (`file` scheme). */ get fsPath() { // if (this.scheme !== 'file') { // console.warn(`[UriError] calling fsPath with scheme ${this.scheme}`); // } return uriToFsPath(this, false); } // ---- modify to new ------------------------- with(change) { if (!change) { return this; } let { scheme, authority, path, query, fragment } = change; if (scheme === undefined) { scheme = this.scheme; } else if (scheme === null) { scheme = _empty; } if (authority === undefined) { authority = this.authority; } else if (authority === null) { authority = _empty; } if (path === undefined) { path = this.path; } else if (path === null) { path = _empty; } if (query === undefined) { query = this.query; } else if (query === null) { query = _empty; } if (fragment === undefined) { fragment = this.fragment; } else if (fragment === null) { fragment = _empty; } if (scheme === this.scheme && authority === this.authority && path === this.path && query === this.query && fragment === this.fragment) { return this; } return new Uri(scheme, authority, path, query, fragment); } // ---- parse & validate ------------------------ /** * Creates a new URI from a string, e.g. `http://www.example.com/some/path`, * `file:///usr/home`, or `scheme:with/path`. * * @param value A string which represents an URI (see `URI#toString`). */ static parse(value, _strict = false) { const match = _regexp.exec(value); if (!match) { return new Uri(_empty, _empty, _empty, _empty, _empty); } return new Uri(match[2] || _empty, percentDecode(match[4] || _empty), percentDecode(match[5] || _empty), percentDecode(match[7] || _empty), percentDecode(match[9] || _empty), _strict); } /** * Creates a new URI from a file system path, e.g. `c:\my\files`, * `/usr/home`, or `\\server\share\some\path`. * * The *difference* between `URI#parse` and `URI#file` is that the latter treats the argument * as path, not as stringified-uri. E.g. `URI.file(path)` is **not the same as** * `URI.parse('file://' + path)` because the path might contain characters that are * interpreted (# and ?). See the following sample: * ```ts const good = URI.file('/coding/c#/project1'); good.scheme === 'file'; good.path === '/coding/c#/project1'; good.fragment === ''; const bad = URI.parse('file://' + '/coding/c#/project1'); bad.scheme === 'file'; bad.path === '/coding/c'; // path is now broken bad.fragment === '/project1'; ``` * * @param path A file system path (see `URI#fsPath`) */ static file(path) { let authority = _empty; // normalize to fwd-slashes on windows, // on other systems bwd-slashes are valid // filename character, eg /f\oo/ba\r.txt if (isWindows) { path = path.replace(/\\/g, _slash); } // check for authority as used in UNC shares // or use the path as given if (path[0] === _slash && path[1] === _slash) { const idx = path.indexOf(_slash, 2); if (idx === -1) { authority = path.substring(2); path = _slash; } else { authority = path.substring(2, idx); path = path.substring(idx) || _slash; } } return new Uri('file', authority, path, _empty, _empty); } /** * Creates new URI from uri components. * * Unless `strict` is `true` the scheme is defaults to be `file`. This function performs * validation and should be used for untrusted uri components retrieved from storage, * user input, command arguments etc */ static from(components, strict) { const result = new Uri(components.scheme, components.authority, components.path, components.query, components.fragment, strict); return result; } /** * Join a URI path with path fragments and normalizes the resulting path. * * @param uri The input URI. * @param pathFragment The path fragment to add to the URI path. * @returns The resulting URI. */ static joinPath(uri, ...pathFragment) { if (!uri.path) { throw new Error(`[UriError]: cannot call joinPath on URI without path`); } let newPath; if (isWindows && uri.scheme === 'file') { newPath = URI.file(win32.join(uriToFsPath(uri, true), ...pathFragment)).path; } else { newPath = posix.join(uri.path, ...pathFragment); } return uri.with({ path: newPath }); } // ---- printing/externalize --------------------------- /** * Creates a string representation for this URI. It's guaranteed that calling * `URI.parse` with the result of this function creates an URI which is equal * to this URI. * * * The result shall *not* be used for display purposes but for externalization or transport. * * The result will be encoded using the percentage encoding and encoding happens mostly * ignore the scheme-specific encoding rules. * * @param skipEncoding Do not encode the result, default is `false` */ toString(skipEncoding = false) { return _asFormatted(this, skipEncoding); } toJSON() { return this; } static revive(data) { if (!data) { return data; } else if (data instanceof URI) { return data; } else { const result = new Uri(data); result._formatted = data.external ?? null; result._fsPath = data._sep === _pathSepMarker ? data.fsPath ?? null : null; return result; } } } const _pathSepMarker = isWindows ? 1 : undefined; // This class exists so that URI is compatible with vscode.Uri (API). class Uri extends URI { constructor() { super(...arguments); this._formatted = null; this._fsPath = null; } get fsPath() { if (!this._fsPath) { this._fsPath = uriToFsPath(this, false); } return this._fsPath; } toString(skipEncoding = false) { if (!skipEncoding) { if (!this._formatted) { this._formatted = _asFormatted(this, false); } return this._formatted; } else { // we don't cache that return _asFormatted(this, true); } } toJSON() { const res = { $mid: 1 /* MarshalledId.Uri */ }; // cached state if (this._fsPath) { res.fsPath = this._fsPath; res._sep = _pathSepMarker; } if (this._formatted) { res.external = this._formatted; } //--- uri components if (this.path) { res.path = this.path; } // TODO // this isn't correct and can violate the UriComponents contract but // this is part of the vscode.Uri API and we shouldn't change how that // works anymore if (this.scheme) { res.scheme = this.scheme; } if (this.authority) { res.authority = this.authority; } if (this.query) { res.query = this.query; } if (this.fragment) { res.fragment = this.fragment; } return res; } } // reserved characters: https://tools.ietf.org/html/rfc3986#section-2.2 const encodeTable = { [58 /* CharCode.Colon */]: '%3A', // gen-delims [47 /* CharCode.Slash */]: '%2F', [63 /* CharCode.QuestionMark */]: '%3F', [35 /* CharCode.Hash */]: '%23', [91 /* CharCode.OpenSquareBracket */]: '%5B', [93 /* CharCode.CloseSquareBracket */]: '%5D', [64 /* CharCode.AtSign */]: '%40', [33 /* CharCode.ExclamationMark */]: '%21', // sub-delims [36 /* CharCode.DollarSign */]: '%24', [38 /* CharCode.Ampersand */]: '%26', [39 /* CharCode.SingleQuote */]: '%27', [40 /* CharCode.OpenParen */]: '%28', [41 /* CharCode.CloseParen */]: '%29', [42 /* CharCode.Asterisk */]: '%2A', [43 /* CharCode.Plus */]: '%2B', [44 /* CharCode.Comma */]: '%2C', [59 /* CharCode.Semicolon */]: '%3B', [61 /* CharCode.Equals */]: '%3D', [32 /* CharCode.Space */]: '%20', }; function encodeURIComponentFast(uriComponent, isPath, isAuthority) { let res = undefined; let nativeEncodePos = -1; for (let pos = 0; pos < uriComponent.length; pos++) { const code = uriComponent.charCodeAt(pos); // unreserved characters: https://tools.ietf.org/html/rfc3986#section-2.3 if ((code >= 97 /* CharCode.a */ && code <= 122 /* CharCode.z */) || (code >= 65 /* CharCode.A */ && code <= 90 /* CharCode.Z */) || (code >= 48 /* CharCode.Digit0 */ && code <= 57 /* CharCode.Digit9 */) || code === 45 /* CharCode.Dash */ || code === 46 /* CharCode.Period */ || code === 95 /* CharCode.Underline */ || code === 126 /* CharCode.Tilde */ || (isPath && code === 47 /* CharCode.Slash */) || (isAuthority && code === 91 /* CharCode.OpenSquareBracket */) || (isAuthority && code === 93 /* CharCode.CloseSquareBracket */) || (isAuthority && code === 58 /* CharCode.Colon */)) { // check if we are delaying native encode if (nativeEncodePos !== -1) { res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos)); nativeEncodePos = -1; } // check if we write into a new string (by default we try to return the param) if (res !== undefined) { res += uriComponent.charAt(pos); } } else { // encoding needed, we need to allocate a new string if (res === undefined) { res = uriComponent.substr(0, pos); } // check with default table first const escaped = encodeTable[code]; if (escaped !== undefined) { // check if we are delaying native encode if (nativeEncodePos !== -1) { res += encodeURIComponent(uriComponent.substring(nativeEncodePos, pos)); nativeEncodePos = -1; } // append escaped variant to result res += escaped; } else if (nativeEncodePos === -1) { // use native encode only when needed nativeEncodePos = pos; } } } if (nativeEncodePos !== -1) { res += encodeURIComponent(uriComponent.substring(nativeEncodePos)); } return res !== undefined ? res : uriComponent; } function encodeURIComponentMinimal(path) { let res = undefined; for (let pos = 0; pos < path.length; pos++) { const code = path.charCodeAt(pos); if (code === 35 /* CharCode.Hash */ || code === 63 /* CharCode.QuestionMark */) { if (res === undefined) { res = path.substr(0, pos); } res += encodeTable[code]; } else { if (res !== undefined) { res += path[pos]; } } } return res !== undefined ? res : path; } /** * Compute `fsPath` for the given uri */ function uriToFsPath(uri, keepDriveLetterCasing) { let value; if (uri.authority && uri.path.length > 1 && uri.scheme === 'file') { // unc path: file://shares/c$/far/boo value = `//${uri.authority}${uri.path}`; } else if (uri.path.charCodeAt(0) === 47 /* CharCode.Slash */ && (uri.path.charCodeAt(1) >= 65 /* CharCode.A */ && uri.path.charCodeAt(1) <= 90 /* CharCode.Z */ || uri.path.charCodeAt(1) >= 97 /* CharCode.a */ && uri.path.charCodeAt(1) <= 122 /* CharCode.z */) && uri.path.charCodeAt(2) === 58 /* CharCode.Colon */) { if (!keepDriveLetterCasing) { // windows drive letter: file:///c:/far/boo value = uri.path[1].toLowerCase() + uri.path.substr(2); } else { value = uri.path.substr(1); } } else { // other path value = uri.path; } if (isWindows) { value = value.replace(/\//g, '\\'); } return value; } /** * Create the external version of a uri */ function _asFormatted(uri, skipEncoding) { const encoder = !skipEncoding ? encodeURIComponentFast : encodeURIComponentMinimal; let res = ''; let { scheme, authority, path, query, fragment } = uri; if (scheme) { res += scheme; res += ':'; } if (authority || scheme === 'file') { res += _slash; res += _slash; } if (authority) { let idx = authority.indexOf('@'); if (idx !== -1) { // @ const userinfo = authority.substr(0, idx); authority = authority.substr(idx + 1); idx = userinfo.lastIndexOf(':'); if (idx === -1) { res += encoder(userinfo, false, false); } else { // :@ res += encoder(userinfo.substr(0, idx), false, false); res += ':'; res += encoder(userinfo.substr(idx + 1), false, true); } res += '@'; } authority = authority.toLowerCase(); idx = authority.lastIndexOf(':'); if (idx === -1) { res += encoder(authority, false, true); } else { // : res += encoder(authority.substr(0, idx), false, true); res += authority.substr(idx); } } if (path) { // lower-case windows drive letters in /C:/fff or C:/fff if (path.length >= 3 && path.charCodeAt(0) === 47 /* CharCode.Slash */ && path.charCodeAt(2) === 58 /* CharCode.Colon */) { const code = path.charCodeAt(1); if (code >= 65 /* CharCode.A */ && code <= 90 /* CharCode.Z */) { path = `/${String.fromCharCode(code + 32)}:${path.substr(3)}`; // "/c:".length === 3 } } else if (path.length >= 2 && path.charCodeAt(1) === 58 /* CharCode.Colon */) { const code = path.charCodeAt(0); if (code >= 65 /* CharCode.A */ && code <= 90 /* CharCode.Z */) { path = `${String.fromCharCode(code + 32)}:${path.substr(2)}`; // "/c:".length === 3 } } // encode the rest of the path res += encoder(path, true, false); } if (query) { res += '?'; res += encoder(query, false, false); } if (fragment) { res += '#'; res += !skipEncoding ? encodeURIComponentFast(fragment, false, false) : fragment; } return res; } // --- decode function decodeURIComponentGraceful(str) { try { return decodeURIComponent(str); } catch { if (str.length > 3) { return str.substr(0, 3) + decodeURIComponentGraceful(str.substr(3)); } else { return str; } } } const _rEncodedAsHex = /(%[0-9A-Za-z][0-9A-Za-z])+/g; function percentDecode(str) { if (!str.match(_rEncodedAsHex)) { return str; } return str.replace(_rEncodedAsHex, (match) => decodeURIComponentGraceful(match)); } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var Schemas; (function (Schemas) { /** * A schema that is used for models that exist in memory * only and that have no correspondence on a server or such. */ Schemas.inMemory = 'inmemory'; /** * A schema that is used for setting files */ Schemas.vscode = 'vscode'; /** * A schema that is used for internal private files */ Schemas.internal = 'private'; /** * A walk-through document. */ Schemas.walkThrough = 'walkThrough'; /** * An embedded code snippet. */ Schemas.walkThroughSnippet = 'walkThroughSnippet'; Schemas.http = 'http'; Schemas.https = 'https'; Schemas.file = 'file'; Schemas.mailto = 'mailto'; Schemas.untitled = 'untitled'; Schemas.data = 'data'; Schemas.command = 'command'; Schemas.vscodeRemote = 'vscode-remote'; Schemas.vscodeRemoteResource = 'vscode-remote-resource'; Schemas.vscodeManagedRemoteResource = 'vscode-managed-remote-resource'; Schemas.vscodeUserData = 'vscode-userdata'; Schemas.vscodeCustomEditor = 'vscode-custom-editor'; Schemas.vscodeNotebookCell = 'vscode-notebook-cell'; Schemas.vscodeNotebookCellMetadata = 'vscode-notebook-cell-metadata'; Schemas.vscodeNotebookCellMetadataDiff = 'vscode-notebook-cell-metadata-diff'; Schemas.vscodeNotebookCellOutput = 'vscode-notebook-cell-output'; Schemas.vscodeNotebookCellOutputDiff = 'vscode-notebook-cell-output-diff'; Schemas.vscodeNotebookMetadata = 'vscode-notebook-metadata'; Schemas.vscodeInteractiveInput = 'vscode-interactive-input'; Schemas.vscodeSettings = 'vscode-settings'; Schemas.vscodeWorkspaceTrust = 'vscode-workspace-trust'; Schemas.vscodeTerminal = 'vscode-terminal'; /** Scheme used for code blocks in chat. */ Schemas.vscodeChatCodeBlock = 'vscode-chat-code-block'; /** Scheme used for LHS of code compare (aka diff) blocks in chat. */ Schemas.vscodeChatCodeCompareBlock = 'vscode-chat-code-compare-block'; /** Scheme used for the chat input editor. */ Schemas.vscodeChatSesssion = 'vscode-chat-editor'; /** * Scheme used internally for webviews that aren't linked to a resource (i.e. not custom editors) */ Schemas.webviewPanel = 'webview-panel'; /** * Scheme used for loading the wrapper html and script in webviews. */ Schemas.vscodeWebview = 'vscode-webview'; /** * Scheme used for extension pages */ Schemas.extension = 'extension'; /** * Scheme used as a replacement of `file` scheme to load * files with our custom protocol handler (desktop only). */ Schemas.vscodeFileResource = 'vscode-file'; /** * Scheme used for temporary resources */ Schemas.tmp = 'tmp'; /** * Scheme used vs live share */ Schemas.vsls = 'vsls'; /** * Scheme used for the Source Control commit input's text document */ Schemas.vscodeSourceControl = 'vscode-scm'; /** * Scheme used for input box for creating comments. */ Schemas.commentsInput = 'comment'; /** * Scheme used for special rendering of settings in the release notes */ Schemas.codeSetting = 'code-setting'; /** * Scheme used for output panel resources */ Schemas.outputChannel = 'output'; })(Schemas || (Schemas = {})); const connectionTokenQueryName = 'tkn'; class RemoteAuthoritiesImpl { constructor() { this._hosts = Object.create(null); this._ports = Object.create(null); this._connectionTokens = Object.create(null); this._preferredWebSchema = 'http'; this._delegate = null; this._serverRootPath = '/'; } setPreferredWebSchema(schema) { this._preferredWebSchema = schema; } get _remoteResourcesPath() { return posix.join(this._serverRootPath, Schemas.vscodeRemoteResource); } rewrite(uri) { if (this._delegate) { try { return this._delegate(uri); } catch (err) { onUnexpectedError(err); return uri; } } const authority = uri.authority; let host = this._hosts[authority]; if (host && host.indexOf(':') !== -1 && host.indexOf('[') === -1) { host = `[${host}]`; } const port = this._ports[authority]; const connectionToken = this._connectionTokens[authority]; let query = `path=${encodeURIComponent(uri.path)}`; if (typeof connectionToken === 'string') { query += `&${connectionTokenQueryName}=${encodeURIComponent(connectionToken)}`; } return URI.from({ scheme: isWeb ? this._preferredWebSchema : Schemas.vscodeRemoteResource, authority: `${host}:${port}`, path: this._remoteResourcesPath, query }); } } const RemoteAuthorities = new RemoteAuthoritiesImpl(); const VSCODE_AUTHORITY = 'vscode-app'; class FileAccessImpl { static { this.FALLBACK_AUTHORITY = VSCODE_AUTHORITY; } /** * Returns a URI to use in contexts where the browser is responsible * for loading (e.g. fetch()) or when used within the DOM. * * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context. */ asBrowserUri(resourcePath) { // ESM-comment-begin // const uri = this.toUri(resourcePath, require); // ESM-comment-end // ESM-uncomment-begin const uri = this.toUri(resourcePath); // ESM-uncomment-end return this.uriToBrowserUri(uri); } /** * Returns a URI to use in contexts where the browser is responsible * for loading (e.g. fetch()) or when used within the DOM. * * **Note:** use `dom.ts#asCSSUrl` whenever the URL is to be used in CSS context. */ uriToBrowserUri(uri) { // Handle remote URIs via `RemoteAuthorities` if (uri.scheme === Schemas.vscodeRemote) { return RemoteAuthorities.rewrite(uri); } // Convert to `vscode-file` resource.. if ( // ...only ever for `file` resources uri.scheme === Schemas.file && ( // ...and we run in native environments isNative || // ...or web worker extensions on desktop (webWorkerOrigin === `${Schemas.vscodeFileResource}://${FileAccessImpl.FALLBACK_AUTHORITY}`))) { return uri.with({ scheme: Schemas.vscodeFileResource, // We need to provide an authority here so that it can serve // as origin for network and loading matters in chromium. // If the URI is not coming with an authority already, we // add our own authority: uri.authority || FileAccessImpl.FALLBACK_AUTHORITY, query: null, fragment: null }); } return uri; } toUri(uriOrModule, moduleIdToUrl) { if (URI.isUri(uriOrModule)) { return uriOrModule; } if (globalThis._VSCODE_FILE_ROOT) { const rootUriOrPath = globalThis._VSCODE_FILE_ROOT; // File URL (with scheme) if (/^\w[\w\d+.-]*:\/\//.test(rootUriOrPath)) { return URI.joinPath(URI.parse(rootUriOrPath, true), uriOrModule); } // File Path (no scheme) const modulePath = join(rootUriOrPath, uriOrModule); return URI.file(modulePath); } return URI.parse(moduleIdToUrl.toUrl(uriOrModule)); } } const FileAccess = new FileAccessImpl(); var COI; (function (COI) { const coiHeaders = new Map([ ['1', { 'Cross-Origin-Opener-Policy': 'same-origin' }], ['2', { 'Cross-Origin-Embedder-Policy': 'require-corp' }], ['3', { 'Cross-Origin-Opener-Policy': 'same-origin', 'Cross-Origin-Embedder-Policy': 'require-corp' }], ]); COI.CoopAndCoep = Object.freeze(coiHeaders.get('3')); const coiSearchParamName = 'vscode-coi'; /** * Extract desired headers from `vscode-coi` invocation */ function getHeadersFromQuery(url) { let params; if (typeof url === 'string') { params = new URL(url).searchParams; } else if (url instanceof URL) { params = url.searchParams; } else if (URI.isUri(url)) { params = new URL(url.toString(true)).searchParams; } const value = params?.get(coiSearchParamName); if (!value) { return undefined; } return coiHeaders.get(value); } COI.getHeadersFromQuery = getHeadersFromQuery; /** * Add the `vscode-coi` query attribute based on wanting `COOP` and `COEP`. Will be a noop when `crossOriginIsolated` * isn't enabled the current context */ function addSearchParam(urlOrSearch, coop, coep) { if (!globalThis.crossOriginIsolated) { // depends on the current context being COI return; } const value = coop && coep ? '3' : coep ? '2' : '1'; if (urlOrSearch instanceof URLSearchParams) { urlOrSearch.set(coiSearchParamName, value); } else { urlOrSearch[coiSearchParamName] = value; } } COI.addSearchParam = addSearchParam; })(COI || (COI = {})); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // ESM-uncomment-end const DEFAULT_CHANNEL = 'default'; const INITIALIZE = '$initialize'; class RequestMessage { constructor(vsWorker, req, channel, method, args) { this.vsWorker = vsWorker; this.req = req; this.channel = channel; this.method = method; this.args = args; this.type = 0 /* MessageType.Request */; } } class ReplyMessage { constructor(vsWorker, seq, res, err) { this.vsWorker = vsWorker; this.seq = seq; this.res = res; this.err = err; this.type = 1 /* MessageType.Reply */; } } class SubscribeEventMessage { constructor(vsWorker, req, channel, eventName, arg) { this.vsWorker = vsWorker; this.req = req; this.channel = channel; this.eventName = eventName; this.arg = arg; this.type = 2 /* MessageType.SubscribeEvent */; } } class EventMessage { constructor(vsWorker, req, event) { this.vsWorker = vsWorker; this.req = req; this.event = event; this.type = 3 /* MessageType.Event */; } } class UnsubscribeEventMessage { constructor(vsWorker, req) { this.vsWorker = vsWorker; this.req = req; this.type = 4 /* MessageType.UnsubscribeEvent */; } } class SimpleWorkerProtocol { constructor(handler) { this._workerId = -1; this._handler = handler; this._lastSentReq = 0; this._pendingReplies = Object.create(null); this._pendingEmitters = new Map(); this._pendingEvents = new Map(); } setWorkerId(workerId) { this._workerId = workerId; } sendMessage(channel, method, args) { const req = String(++this._lastSentReq); return new Promise((resolve, reject) => { this._pendingReplies[req] = { resolve: resolve, reject: reject }; this._send(new RequestMessage(this._workerId, req, channel, method, args)); }); } listen(channel, eventName, arg) { let req = null; const emitter = new Emitter({ onWillAddFirstListener: () => { req = String(++this._lastSentReq); this._pendingEmitters.set(req, emitter); this._send(new SubscribeEventMessage(this._workerId, req, channel, eventName, arg)); }, onDidRemoveLastListener: () => { this._pendingEmitters.delete(req); this._send(new UnsubscribeEventMessage(this._workerId, req)); req = null; } }); return emitter.event; } handleMessage(message) { if (!message || !message.vsWorker) { return; } if (this._workerId !== -1 && message.vsWorker !== this._workerId) { return; } this._handleMessage(message); } createProxyToRemoteChannel(channel, sendMessageBarrier) { const handler = { get: (target, name) => { if (typeof name === 'string' && !target[name]) { if (propertyIsDynamicEvent(name)) { // onDynamic... target[name] = (arg) => { return this.listen(channel, name, arg); }; } else if (propertyIsEvent(name)) { // on... target[name] = this.listen(channel, name, undefined); } else if (name.charCodeAt(0) === 36 /* CharCode.DollarSign */) { // $... target[name] = async (...myArgs) => { await sendMessageBarrier?.(); return this.sendMessage(channel, name, myArgs); }; } } return target[name]; } }; return new Proxy(Object.create(null), handler); } _handleMessage(msg) { switch (msg.type) { case 1 /* MessageType.Reply */: return this._handleReplyMessage(msg); case 0 /* MessageType.Request */: return this._handleRequestMessage(msg); case 2 /* MessageType.SubscribeEvent */: return this._handleSubscribeEventMessage(msg); case 3 /* MessageType.Event */: return this._handleEventMessage(msg); case 4 /* MessageType.UnsubscribeEvent */: return this._handleUnsubscribeEventMessage(msg); } } _handleReplyMessage(replyMessage) { if (!this._pendingReplies[replyMessage.seq]) { console.warn('Got reply to unknown seq'); return; } const reply = this._pendingReplies[replyMessage.seq]; delete this._pendingReplies[replyMessage.seq]; if (replyMessage.err) { let err = replyMessage.err; if (replyMessage.err.$isError) { err = new Error(); err.name = replyMessage.err.name; err.message = replyMessage.err.message; err.stack = replyMessage.err.stack; } reply.reject(err); return; } reply.resolve(replyMessage.res); } _handleRequestMessage(requestMessage) { const req = requestMessage.req; const result = this._handler.handleMessage(requestMessage.channel, requestMessage.method, requestMessage.args); result.then((r) => { this._send(new ReplyMessage(this._workerId, req, r, undefined)); }, (e) => { if (e.detail instanceof Error) { // Loading errors have a detail property that points to the actual error e.detail = transformErrorForSerialization(e.detail); } this._send(new ReplyMessage(this._workerId, req, undefined, transformErrorForSerialization(e))); }); } _handleSubscribeEventMessage(msg) { const req = msg.req; const disposable = this._handler.handleEvent(msg.channel, msg.eventName, msg.arg)((event) => { this._send(new EventMessage(this._workerId, req, event)); }); this._pendingEvents.set(req, disposable); } _handleEventMessage(msg) { if (!this._pendingEmitters.has(msg.req)) { console.warn('Got event for unknown req'); return; } this._pendingEmitters.get(msg.req).fire(msg.event); } _handleUnsubscribeEventMessage(msg) { if (!this._pendingEvents.has(msg.req)) { console.warn('Got unsubscribe for unknown req'); return; } this._pendingEvents.get(msg.req).dispose(); this._pendingEvents.delete(msg.req); } _send(msg) { const transfer = []; if (msg.type === 0 /* MessageType.Request */) { for (let i = 0; i < msg.args.length; i++) { if (msg.args[i] instanceof ArrayBuffer) { transfer.push(msg.args[i]); } } } else if (msg.type === 1 /* MessageType.Reply */) { if (msg.res instanceof ArrayBuffer) { transfer.push(msg.res); } } this._handler.sendMessage(msg, transfer); } } function propertyIsEvent(name) { // Assume a property is an event if it has a form of "onSomething" return name[0] === 'o' && name[1] === 'n' && isUpperAsciiLetter(name.charCodeAt(2)); } function propertyIsDynamicEvent(name) { // Assume a property is a dynamic event (a method that returns an event) if it has a form of "onDynamicSomething" return /^onDynamic/.test(name) && isUpperAsciiLetter(name.charCodeAt(9)); } /** * Worker side */ class SimpleWorkerServer { constructor(postMessage, requestHandlerFactory) { this._localChannels = new Map(); this._remoteChannels = new Map(); this._requestHandlerFactory = requestHandlerFactory; this._requestHandler = null; this._protocol = new SimpleWorkerProtocol({ sendMessage: (msg, transfer) => { postMessage(msg, transfer); }, handleMessage: (channel, method, args) => this._handleMessage(channel, method, args), handleEvent: (channel, eventName, arg) => this._handleEvent(channel, eventName, arg) }); } onmessage(msg) { this._protocol.handleMessage(msg); } _handleMessage(channel, method, args) { if (channel === DEFAULT_CHANNEL && method === INITIALIZE) { return this.initialize(args[0], args[1], args[2]); } const requestHandler = (channel === DEFAULT_CHANNEL ? this._requestHandler : this._localChannels.get(channel)); if (!requestHandler) { return Promise.reject(new Error(`Missing channel ${channel} on worker thread`)); } if (typeof requestHandler[method] !== 'function') { return Promise.reject(new Error(`Missing method ${method} on worker thread channel ${channel}`)); } try { return Promise.resolve(requestHandler[method].apply(requestHandler, args)); } catch (e) { return Promise.reject(e); } } _handleEvent(channel, eventName, arg) { const requestHandler = (channel === DEFAULT_CHANNEL ? this._requestHandler : this._localChannels.get(channel)); if (!requestHandler) { throw new Error(`Missing channel ${channel} on worker thread`); } if (propertyIsDynamicEvent(eventName)) { const event = requestHandler[eventName].call(requestHandler, arg); if (typeof event !== 'function') { throw new Error(`Missing dynamic event ${eventName} on request handler.`); } return event; } if (propertyIsEvent(eventName)) { const event = requestHandler[eventName]; if (typeof event !== 'function') { throw new Error(`Missing event ${eventName} on request handler.`); } return event; } throw new Error(`Malformed event name ${eventName}`); } getChannel(channel) { if (!this._remoteChannels.has(channel)) { const inst = this._protocol.createProxyToRemoteChannel(channel); this._remoteChannels.set(channel, inst); } return this._remoteChannels.get(channel); } async initialize(workerId, loaderConfig, moduleId) { this._protocol.setWorkerId(workerId); if (this._requestHandlerFactory) { // static request handler this._requestHandler = this._requestHandlerFactory(this); return; } if (loaderConfig) { // Remove 'baseUrl', handling it is beyond scope for now if (typeof loaderConfig.baseUrl !== 'undefined') { delete loaderConfig['baseUrl']; } if (typeof loaderConfig.paths !== 'undefined') { if (typeof loaderConfig.paths.vs !== 'undefined') { delete loaderConfig.paths['vs']; } } if (typeof loaderConfig.trustedTypesPolicy !== 'undefined') { // don't use, it has been destroyed during serialize delete loaderConfig['trustedTypesPolicy']; } // Since this is in a web worker, enable catching errors loaderConfig.catchError = true; globalThis.require.config(loaderConfig); } { const url = FileAccess.asBrowserUri(`${moduleId}.js`).toString(true); return import(`${url}`).then((module) => { this._requestHandler = module.create(this); if (!this._requestHandler) { throw new Error(`No RequestHandler!`); } }); } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Represents information about a specific difference between two sequences. */ class DiffChange { /** * Constructs a new DiffChange with the given sequence information * and content. */ constructor(originalStart, originalLength, modifiedStart, modifiedLength) { //Debug.Assert(originalLength > 0 || modifiedLength > 0, "originalLength and modifiedLength cannot both be <= 0"); this.originalStart = originalStart; this.originalLength = originalLength; this.modifiedStart = modifiedStart; this.modifiedLength = modifiedLength; } /** * The end point (exclusive) of the change in the original sequence. */ getOriginalEnd() { return this.originalStart + this.originalLength; } /** * The end point (exclusive) of the change in the modified sequence. */ getModifiedEnd() { return this.modifiedStart + this.modifiedLength; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function numberHash(val, initialHashVal) { return (((initialHashVal << 5) - initialHashVal) + val) | 0; // hashVal * 31 + ch, keep as int32 } function stringHash(s, hashVal) { hashVal = numberHash(149417, hashVal); for (let i = 0, length = s.length; i < length; i++) { hashVal = numberHash(s.charCodeAt(i), hashVal); } return hashVal; } function leftRotate(value, bits, totalBits = 32) { // delta + bits = totalBits const delta = totalBits - bits; // All ones, expect `delta` zeros aligned to the right const mask = ~((1 << delta) - 1); // Join (value left-shifted `bits` bits) with (masked value right-shifted `delta` bits) return ((value << bits) | ((mask & value) >>> delta)) >>> 0; } function fill(dest, index = 0, count = dest.byteLength, value = 0) { for (let i = 0; i < count; i++) { dest[index + i] = value; } } function leftPad(value, length, char = '0') { while (value.length < length) { value = char + value; } return value; } function toHexString(bufferOrValue, bitsize = 32) { if (bufferOrValue instanceof ArrayBuffer) { return Array.from(new Uint8Array(bufferOrValue)).map(b => b.toString(16).padStart(2, '0')).join(''); } return leftPad((bufferOrValue >>> 0).toString(16), bitsize / 4); } /** * A SHA1 implementation that works with strings and does not allocate. */ class StringSHA1 { static { this._bigBlock32 = new DataView(new ArrayBuffer(320)); } // 80 * 4 = 320 constructor() { this._h0 = 0x67452301; this._h1 = 0xEFCDAB89; this._h2 = 0x98BADCFE; this._h3 = 0x10325476; this._h4 = 0xC3D2E1F0; this._buff = new Uint8Array(64 /* SHA1Constant.BLOCK_SIZE */ + 3 /* to fit any utf-8 */); this._buffDV = new DataView(this._buff.buffer); this._buffLen = 0; this._totalLen = 0; this._leftoverHighSurrogate = 0; this._finished = false; } update(str) { const strLen = str.length; if (strLen === 0) { return; } const buff = this._buff; let buffLen = this._buffLen; let leftoverHighSurrogate = this._leftoverHighSurrogate; let charCode; let offset; if (leftoverHighSurrogate !== 0) { charCode = leftoverHighSurrogate; offset = -1; leftoverHighSurrogate = 0; } else { charCode = str.charCodeAt(0); offset = 0; } while (true) { let codePoint = charCode; if (isHighSurrogate(charCode)) { if (offset + 1 < strLen) { const nextCharCode = str.charCodeAt(offset + 1); if (isLowSurrogate(nextCharCode)) { offset++; codePoint = computeCodePoint(charCode, nextCharCode); } else { // illegal => unicode replacement character codePoint = 65533 /* SHA1Constant.UNICODE_REPLACEMENT */; } } else { // last character is a surrogate pair leftoverHighSurrogate = charCode; break; } } else if (isLowSurrogate(charCode)) { // illegal => unicode replacement character codePoint = 65533 /* SHA1Constant.UNICODE_REPLACEMENT */; } buffLen = this._push(buff, buffLen, codePoint); offset++; if (offset < strLen) { charCode = str.charCodeAt(offset); } else { break; } } this._buffLen = buffLen; this._leftoverHighSurrogate = leftoverHighSurrogate; } _push(buff, buffLen, codePoint) { if (codePoint < 0x0080) { buff[buffLen++] = codePoint; } else if (codePoint < 0x0800) { buff[buffLen++] = 0b11000000 | ((codePoint & 0b00000000000000000000011111000000) >>> 6); buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0); } else if (codePoint < 0x10000) { buff[buffLen++] = 0b11100000 | ((codePoint & 0b00000000000000001111000000000000) >>> 12); buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6); buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0); } else { buff[buffLen++] = 0b11110000 | ((codePoint & 0b00000000000111000000000000000000) >>> 18); buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000111111000000000000) >>> 12); buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000111111000000) >>> 6); buff[buffLen++] = 0b10000000 | ((codePoint & 0b00000000000000000000000000111111) >>> 0); } if (buffLen >= 64 /* SHA1Constant.BLOCK_SIZE */) { this._step(); buffLen -= 64 /* SHA1Constant.BLOCK_SIZE */; this._totalLen += 64 /* SHA1Constant.BLOCK_SIZE */; // take last 3 in case of UTF8 overflow buff[0] = buff[64 /* SHA1Constant.BLOCK_SIZE */ + 0]; buff[1] = buff[64 /* SHA1Constant.BLOCK_SIZE */ + 1]; buff[2] = buff[64 /* SHA1Constant.BLOCK_SIZE */ + 2]; } return buffLen; } digest() { if (!this._finished) { this._finished = true; if (this._leftoverHighSurrogate) { // illegal => unicode replacement character this._leftoverHighSurrogate = 0; this._buffLen = this._push(this._buff, this._buffLen, 65533 /* SHA1Constant.UNICODE_REPLACEMENT */); } this._totalLen += this._buffLen; this._wrapUp(); } return toHexString(this._h0) + toHexString(this._h1) + toHexString(this._h2) + toHexString(this._h3) + toHexString(this._h4); } _wrapUp() { this._buff[this._buffLen++] = 0x80; fill(this._buff, this._buffLen); if (this._buffLen > 56) { this._step(); fill(this._buff); } // this will fit because the mantissa can cover up to 52 bits const ml = 8 * this._totalLen; this._buffDV.setUint32(56, Math.floor(ml / 4294967296), false); this._buffDV.setUint32(60, ml % 4294967296, false); this._step(); } _step() { const bigBlock32 = StringSHA1._bigBlock32; const data = this._buffDV; for (let j = 0; j < 64 /* 16*4 */; j += 4) { bigBlock32.setUint32(j, data.getUint32(j, false), false); } for (let j = 64; j < 320 /* 80*4 */; j += 4) { bigBlock32.setUint32(j, leftRotate((bigBlock32.getUint32(j - 12, false) ^ bigBlock32.getUint32(j - 32, false) ^ bigBlock32.getUint32(j - 56, false) ^ bigBlock32.getUint32(j - 64, false)), 1), false); } let a = this._h0; let b = this._h1; let c = this._h2; let d = this._h3; let e = this._h4; let f, k; let temp; for (let j = 0; j < 80; j++) { if (j < 20) { f = (b & c) | ((~b) & d); k = 0x5A827999; } else if (j < 40) { f = b ^ c ^ d; k = 0x6ED9EBA1; } else if (j < 60) { f = (b & c) | (b & d) | (c & d); k = 0x8F1BBCDC; } else { f = b ^ c ^ d; k = 0xCA62C1D6; } temp = (leftRotate(a, 5) + f + e + k + bigBlock32.getUint32(j * 4, false)) & 0xffffffff; e = d; d = c; c = leftRotate(b, 30); b = a; a = temp; } this._h0 = (this._h0 + a) & 0xffffffff; this._h1 = (this._h1 + b) & 0xffffffff; this._h2 = (this._h2 + c) & 0xffffffff; this._h3 = (this._h3 + d) & 0xffffffff; this._h4 = (this._h4 + e) & 0xffffffff; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class StringDiffSequence { constructor(source) { this.source = source; } getElements() { const source = this.source; const characters = new Int32Array(source.length); for (let i = 0, len = source.length; i < len; i++) { characters[i] = source.charCodeAt(i); } return characters; } } function stringDiff(original, modified, pretty) { return new LcsDiff(new StringDiffSequence(original), new StringDiffSequence(modified)).ComputeDiff(pretty).changes; } // // The code below has been ported from a C# implementation in VS // class Debug { static Assert(condition, message) { if (!condition) { throw new Error(message); } } } class MyArray { /** * Copies a range of elements from an Array starting at the specified source index and pastes * them to another Array starting at the specified destination index. The length and the indexes * are specified as 64-bit integers. * sourceArray: * The Array that contains the data to copy. * sourceIndex: * A 64-bit integer that represents the index in the sourceArray at which copying begins. * destinationArray: * The Array that receives the data. * destinationIndex: * A 64-bit integer that represents the index in the destinationArray at which storing begins. * length: * A 64-bit integer that represents the number of elements to copy. */ static Copy(sourceArray, sourceIndex, destinationArray, destinationIndex, length) { for (let i = 0; i < length; i++) { destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i]; } } static Copy2(sourceArray, sourceIndex, destinationArray, destinationIndex, length) { for (let i = 0; i < length; i++) { destinationArray[destinationIndex + i] = sourceArray[sourceIndex + i]; } } } /** * A utility class which helps to create the set of DiffChanges from * a difference operation. This class accepts original DiffElements and * modified DiffElements that are involved in a particular change. The * MarkNextChange() method can be called to mark the separation between * distinct changes. At the end, the Changes property can be called to retrieve * the constructed changes. */ class DiffChangeHelper { /** * Constructs a new DiffChangeHelper for the given DiffSequences. */ constructor() { this.m_changes = []; this.m_originalStart = 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */; this.m_modifiedStart = 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */; this.m_originalCount = 0; this.m_modifiedCount = 0; } /** * Marks the beginning of the next change in the set of differences. */ MarkNextChange() { // Only add to the list if there is something to add if (this.m_originalCount > 0 || this.m_modifiedCount > 0) { // Add the new change to our list this.m_changes.push(new DiffChange(this.m_originalStart, this.m_originalCount, this.m_modifiedStart, this.m_modifiedCount)); } // Reset for the next change this.m_originalCount = 0; this.m_modifiedCount = 0; this.m_originalStart = 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */; this.m_modifiedStart = 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */; } /** * Adds the original element at the given position to the elements * affected by the current change. The modified index gives context * to the change position with respect to the original sequence. * @param originalIndex The index of the original element to add. * @param modifiedIndex The index of the modified element that provides corresponding position in the modified sequence. */ AddOriginalElement(originalIndex, modifiedIndex) { // The 'true' start index is the smallest of the ones we've seen this.m_originalStart = Math.min(this.m_originalStart, originalIndex); this.m_modifiedStart = Math.min(this.m_modifiedStart, modifiedIndex); this.m_originalCount++; } /** * Adds the modified element at the given position to the elements * affected by the current change. The original index gives context * to the change position with respect to the modified sequence. * @param originalIndex The index of the original element that provides corresponding position in the original sequence. * @param modifiedIndex The index of the modified element to add. */ AddModifiedElement(originalIndex, modifiedIndex) { // The 'true' start index is the smallest of the ones we've seen this.m_originalStart = Math.min(this.m_originalStart, originalIndex); this.m_modifiedStart = Math.min(this.m_modifiedStart, modifiedIndex); this.m_modifiedCount++; } /** * Retrieves all of the changes marked by the class. */ getChanges() { if (this.m_originalCount > 0 || this.m_modifiedCount > 0) { // Finish up on whatever is left this.MarkNextChange(); } return this.m_changes; } /** * Retrieves all of the changes marked by the class in the reverse order */ getReverseChanges() { if (this.m_originalCount > 0 || this.m_modifiedCount > 0) { // Finish up on whatever is left this.MarkNextChange(); } this.m_changes.reverse(); return this.m_changes; } } /** * An implementation of the difference algorithm described in * "An O(ND) Difference Algorithm and its variations" by Eugene W. Myers */ class LcsDiff { /** * Constructs the DiffFinder */ constructor(originalSequence, modifiedSequence, continueProcessingPredicate = null) { this.ContinueProcessingPredicate = continueProcessingPredicate; this._originalSequence = originalSequence; this._modifiedSequence = modifiedSequence; const [originalStringElements, originalElementsOrHash, originalHasStrings] = LcsDiff._getElements(originalSequence); const [modifiedStringElements, modifiedElementsOrHash, modifiedHasStrings] = LcsDiff._getElements(modifiedSequence); this._hasStrings = (originalHasStrings && modifiedHasStrings); this._originalStringElements = originalStringElements; this._originalElementsOrHash = originalElementsOrHash; this._modifiedStringElements = modifiedStringElements; this._modifiedElementsOrHash = modifiedElementsOrHash; this.m_forwardHistory = []; this.m_reverseHistory = []; } static _isStringArray(arr) { return (arr.length > 0 && typeof arr[0] === 'string'); } static _getElements(sequence) { const elements = sequence.getElements(); if (LcsDiff._isStringArray(elements)) { const hashes = new Int32Array(elements.length); for (let i = 0, len = elements.length; i < len; i++) { hashes[i] = stringHash(elements[i], 0); } return [elements, hashes, true]; } if (elements instanceof Int32Array) { return [[], elements, false]; } return [[], new Int32Array(elements), false]; } ElementsAreEqual(originalIndex, newIndex) { if (this._originalElementsOrHash[originalIndex] !== this._modifiedElementsOrHash[newIndex]) { return false; } return (this._hasStrings ? this._originalStringElements[originalIndex] === this._modifiedStringElements[newIndex] : true); } ElementsAreStrictEqual(originalIndex, newIndex) { if (!this.ElementsAreEqual(originalIndex, newIndex)) { return false; } const originalElement = LcsDiff._getStrictElement(this._originalSequence, originalIndex); const modifiedElement = LcsDiff._getStrictElement(this._modifiedSequence, newIndex); return (originalElement === modifiedElement); } static _getStrictElement(sequence, index) { if (typeof sequence.getStrictElement === 'function') { return sequence.getStrictElement(index); } return null; } OriginalElementsAreEqual(index1, index2) { if (this._originalElementsOrHash[index1] !== this._originalElementsOrHash[index2]) { return false; } return (this._hasStrings ? this._originalStringElements[index1] === this._originalStringElements[index2] : true); } ModifiedElementsAreEqual(index1, index2) { if (this._modifiedElementsOrHash[index1] !== this._modifiedElementsOrHash[index2]) { return false; } return (this._hasStrings ? this._modifiedStringElements[index1] === this._modifiedStringElements[index2] : true); } ComputeDiff(pretty) { return this._ComputeDiff(0, this._originalElementsOrHash.length - 1, 0, this._modifiedElementsOrHash.length - 1, pretty); } /** * Computes the differences between the original and modified input * sequences on the bounded range. * @returns An array of the differences between the two input sequences. */ _ComputeDiff(originalStart, originalEnd, modifiedStart, modifiedEnd, pretty) { const quitEarlyArr = [false]; let changes = this.ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr); if (pretty) { // We have to clean up the computed diff to be more intuitive // but it turns out this cannot be done correctly until the entire set // of diffs have been computed changes = this.PrettifyChanges(changes); } return { quitEarly: quitEarlyArr[0], changes: changes }; } /** * Private helper method which computes the differences on the bounded range * recursively. * @returns An array of the differences between the two input sequences. */ ComputeDiffRecursive(originalStart, originalEnd, modifiedStart, modifiedEnd, quitEarlyArr) { quitEarlyArr[0] = false; // Find the start of the differences while (originalStart <= originalEnd && modifiedStart <= modifiedEnd && this.ElementsAreEqual(originalStart, modifiedStart)) { originalStart++; modifiedStart++; } // Find the end of the differences while (originalEnd >= originalStart && modifiedEnd >= modifiedStart && this.ElementsAreEqual(originalEnd, modifiedEnd)) { originalEnd--; modifiedEnd--; } // In the special case where we either have all insertions or all deletions or the sequences are identical if (originalStart > originalEnd || modifiedStart > modifiedEnd) { let changes; if (modifiedStart <= modifiedEnd) { Debug.Assert(originalStart === originalEnd + 1, 'originalStart should only be one more than originalEnd'); // All insertions changes = [ new DiffChange(originalStart, 0, modifiedStart, modifiedEnd - modifiedStart + 1) ]; } else if (originalStart <= originalEnd) { Debug.Assert(modifiedStart === modifiedEnd + 1, 'modifiedStart should only be one more than modifiedEnd'); // All deletions changes = [ new DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, 0) ]; } else { Debug.Assert(originalStart === originalEnd + 1, 'originalStart should only be one more than originalEnd'); Debug.Assert(modifiedStart === modifiedEnd + 1, 'modifiedStart should only be one more than modifiedEnd'); // Identical sequences - No differences changes = []; } return changes; } // This problem can be solved using the Divide-And-Conquer technique. const midOriginalArr = [0]; const midModifiedArr = [0]; const result = this.ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr); const midOriginal = midOriginalArr[0]; const midModified = midModifiedArr[0]; if (result !== null) { // Result is not-null when there was enough memory to compute the changes while // searching for the recursion point return result; } else if (!quitEarlyArr[0]) { // We can break the problem down recursively by finding the changes in the // First Half: (originalStart, modifiedStart) to (midOriginal, midModified) // Second Half: (midOriginal + 1, minModified + 1) to (originalEnd, modifiedEnd) // NOTE: ComputeDiff() is inclusive, therefore the second range starts on the next point const leftChanges = this.ComputeDiffRecursive(originalStart, midOriginal, modifiedStart, midModified, quitEarlyArr); let rightChanges = []; if (!quitEarlyArr[0]) { rightChanges = this.ComputeDiffRecursive(midOriginal + 1, originalEnd, midModified + 1, modifiedEnd, quitEarlyArr); } else { // We didn't have time to finish the first half, so we don't have time to compute this half. // Consider the entire rest of the sequence different. rightChanges = [ new DiffChange(midOriginal + 1, originalEnd - (midOriginal + 1) + 1, midModified + 1, modifiedEnd - (midModified + 1) + 1) ]; } return this.ConcatenateChanges(leftChanges, rightChanges); } // If we hit here, we quit early, and so can't return anything meaningful return [ new DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, modifiedEnd - modifiedStart + 1) ]; } WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, forwardPoints, reversePoints, originalIndex, originalEnd, midOriginalArr, modifiedIndex, modifiedEnd, midModifiedArr, deltaIsEven, quitEarlyArr) { let forwardChanges = null; let reverseChanges = null; // First, walk backward through the forward diagonals history let changeHelper = new DiffChangeHelper(); let diagonalMin = diagonalForwardStart; let diagonalMax = diagonalForwardEnd; let diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalForwardOffset; let lastOriginalIndex = -1073741824 /* Constants.MIN_SAFE_SMALL_INTEGER */; let historyIndex = this.m_forwardHistory.length - 1; do { // Get the diagonal index from the relative diagonal number const diagonal = diagonalRelative + diagonalForwardBase; // Figure out where we came from if (diagonal === diagonalMin || (diagonal < diagonalMax && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) { // Vertical line (the element is an insert) originalIndex = forwardPoints[diagonal + 1]; modifiedIndex = originalIndex - diagonalRelative - diagonalForwardOffset; if (originalIndex < lastOriginalIndex) { changeHelper.MarkNextChange(); } lastOriginalIndex = originalIndex; changeHelper.AddModifiedElement(originalIndex + 1, modifiedIndex); diagonalRelative = (diagonal + 1) - diagonalForwardBase; //Setup for the next iteration } else { // Horizontal line (the element is a deletion) originalIndex = forwardPoints[diagonal - 1] + 1; modifiedIndex = originalIndex - diagonalRelative - diagonalForwardOffset; if (originalIndex < lastOriginalIndex) { changeHelper.MarkNextChange(); } lastOriginalIndex = originalIndex - 1; changeHelper.AddOriginalElement(originalIndex, modifiedIndex + 1); diagonalRelative = (diagonal - 1) - diagonalForwardBase; //Setup for the next iteration } if (historyIndex >= 0) { forwardPoints = this.m_forwardHistory[historyIndex]; diagonalForwardBase = forwardPoints[0]; //We stored this in the first spot diagonalMin = 1; diagonalMax = forwardPoints.length - 1; } } while (--historyIndex >= -1); // Ironically, we get the forward changes as the reverse of the // order we added them since we technically added them backwards forwardChanges = changeHelper.getReverseChanges(); if (quitEarlyArr[0]) { // TODO: Calculate a partial from the reverse diagonals. // For now, just assume everything after the midOriginal/midModified point is a diff let originalStartPoint = midOriginalArr[0] + 1; let modifiedStartPoint = midModifiedArr[0] + 1; if (forwardChanges !== null && forwardChanges.length > 0) { const lastForwardChange = forwardChanges[forwardChanges.length - 1]; originalStartPoint = Math.max(originalStartPoint, lastForwardChange.getOriginalEnd()); modifiedStartPoint = Math.max(modifiedStartPoint, lastForwardChange.getModifiedEnd()); } reverseChanges = [ new DiffChange(originalStartPoint, originalEnd - originalStartPoint + 1, modifiedStartPoint, modifiedEnd - modifiedStartPoint + 1) ]; } else { // Now walk backward through the reverse diagonals history changeHelper = new DiffChangeHelper(); diagonalMin = diagonalReverseStart; diagonalMax = diagonalReverseEnd; diagonalRelative = (midOriginalArr[0] - midModifiedArr[0]) - diagonalReverseOffset; lastOriginalIndex = 1073741824 /* Constants.MAX_SAFE_SMALL_INTEGER */; historyIndex = (deltaIsEven) ? this.m_reverseHistory.length - 1 : this.m_reverseHistory.length - 2; do { // Get the diagonal index from the relative diagonal number const diagonal = diagonalRelative + diagonalReverseBase; // Figure out where we came from if (diagonal === diagonalMin || (diagonal < diagonalMax && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) { // Horizontal line (the element is a deletion)) originalIndex = reversePoints[diagonal + 1] - 1; modifiedIndex = originalIndex - diagonalRelative - diagonalReverseOffset; if (originalIndex > lastOriginalIndex) { changeHelper.MarkNextChange(); } lastOriginalIndex = originalIndex + 1; changeHelper.AddOriginalElement(originalIndex + 1, modifiedIndex + 1); diagonalRelative = (diagonal + 1) - diagonalReverseBase; //Setup for the next iteration } else { // Vertical line (the element is an insertion) originalIndex = reversePoints[diagonal - 1]; modifiedIndex = originalIndex - diagonalRelative - diagonalReverseOffset; if (originalIndex > lastOriginalIndex) { changeHelper.MarkNextChange(); } lastOriginalIndex = originalIndex; changeHelper.AddModifiedElement(originalIndex + 1, modifiedIndex + 1); diagonalRelative = (diagonal - 1) - diagonalReverseBase; //Setup for the next iteration } if (historyIndex >= 0) { reversePoints = this.m_reverseHistory[historyIndex]; diagonalReverseBase = reversePoints[0]; //We stored this in the first spot diagonalMin = 1; diagonalMax = reversePoints.length - 1; } } while (--historyIndex >= -1); // There are cases where the reverse history will find diffs that // are correct, but not intuitive, so we need shift them. reverseChanges = changeHelper.getChanges(); } return this.ConcatenateChanges(forwardChanges, reverseChanges); } /** * Given the range to compute the diff on, this method finds the point: * (midOriginal, midModified) * that exists in the middle of the LCS of the two sequences and * is the point at which the LCS problem may be broken down recursively. * This method will try to keep the LCS trace in memory. If the LCS recursion * point is calculated and the full trace is available in memory, then this method * will return the change list. * @param originalStart The start bound of the original sequence range * @param originalEnd The end bound of the original sequence range * @param modifiedStart The start bound of the modified sequence range * @param modifiedEnd The end bound of the modified sequence range * @param midOriginal The middle point of the original sequence range * @param midModified The middle point of the modified sequence range * @returns The diff changes, if available, otherwise null */ ComputeRecursionPoint(originalStart, originalEnd, modifiedStart, modifiedEnd, midOriginalArr, midModifiedArr, quitEarlyArr) { let originalIndex = 0, modifiedIndex = 0; let diagonalForwardStart = 0, diagonalForwardEnd = 0; let diagonalReverseStart = 0, diagonalReverseEnd = 0; // To traverse the edit graph and produce the proper LCS, our actual // start position is just outside the given boundary originalStart--; modifiedStart--; // We set these up to make the compiler happy, but they will // be replaced before we return with the actual recursion point midOriginalArr[0] = 0; midModifiedArr[0] = 0; // Clear out the history this.m_forwardHistory = []; this.m_reverseHistory = []; // Each cell in the two arrays corresponds to a diagonal in the edit graph. // The integer value in the cell represents the originalIndex of the furthest // reaching point found so far that ends in that diagonal. // The modifiedIndex can be computed mathematically from the originalIndex and the diagonal number. const maxDifferences = (originalEnd - originalStart) + (modifiedEnd - modifiedStart); const numDiagonals = maxDifferences + 1; const forwardPoints = new Int32Array(numDiagonals); const reversePoints = new Int32Array(numDiagonals); // diagonalForwardBase: Index into forwardPoints of the diagonal which passes through (originalStart, modifiedStart) // diagonalReverseBase: Index into reversePoints of the diagonal which passes through (originalEnd, modifiedEnd) const diagonalForwardBase = (modifiedEnd - modifiedStart); const diagonalReverseBase = (originalEnd - originalStart); // diagonalForwardOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the // diagonal number (relative to diagonalForwardBase) // diagonalReverseOffset: Geometric offset which allows modifiedIndex to be computed from originalIndex and the // diagonal number (relative to diagonalReverseBase) const diagonalForwardOffset = (originalStart - modifiedStart); const diagonalReverseOffset = (originalEnd - modifiedEnd); // delta: The difference between the end diagonal and the start diagonal. This is used to relate diagonal numbers // relative to the start diagonal with diagonal numbers relative to the end diagonal. // The Even/Oddn-ness of this delta is important for determining when we should check for overlap const delta = diagonalReverseBase - diagonalForwardBase; const deltaIsEven = (delta % 2 === 0); // Here we set up the start and end points as the furthest points found so far // in both the forward and reverse directions, respectively forwardPoints[diagonalForwardBase] = originalStart; reversePoints[diagonalReverseBase] = originalEnd; // Remember if we quit early, and thus need to do a best-effort result instead of a real result. quitEarlyArr[0] = false; // A couple of points: // --With this method, we iterate on the number of differences between the two sequences. // The more differences there actually are, the longer this will take. // --Also, as the number of differences increases, we have to search on diagonals further // away from the reference diagonal (which is diagonalForwardBase for forward, diagonalReverseBase for reverse). // --We extend on even diagonals (relative to the reference diagonal) only when numDifferences // is even and odd diagonals only when numDifferences is odd. for (let numDifferences = 1; numDifferences <= (maxDifferences / 2) + 1; numDifferences++) { let furthestOriginalIndex = 0; let furthestModifiedIndex = 0; // Run the algorithm in the forward direction diagonalForwardStart = this.ClipDiagonalBound(diagonalForwardBase - numDifferences, numDifferences, diagonalForwardBase, numDiagonals); diagonalForwardEnd = this.ClipDiagonalBound(diagonalForwardBase + numDifferences, numDifferences, diagonalForwardBase, numDiagonals); for (let diagonal = diagonalForwardStart; diagonal <= diagonalForwardEnd; diagonal += 2) { // STEP 1: We extend the furthest reaching point in the present diagonal // by looking at the diagonals above and below and picking the one whose point // is further away from the start point (originalStart, modifiedStart) if (diagonal === diagonalForwardStart || (diagonal < diagonalForwardEnd && forwardPoints[diagonal - 1] < forwardPoints[diagonal + 1])) { originalIndex = forwardPoints[diagonal + 1]; } else { originalIndex = forwardPoints[diagonal - 1] + 1; } modifiedIndex = originalIndex - (diagonal - diagonalForwardBase) - diagonalForwardOffset; // Save the current originalIndex so we can test for false overlap in step 3 const tempOriginalIndex = originalIndex; // STEP 2: We can continue to extend the furthest reaching point in the present diagonal // so long as the elements are equal. while (originalIndex < originalEnd && modifiedIndex < modifiedEnd && this.ElementsAreEqual(originalIndex + 1, modifiedIndex + 1)) { originalIndex++; modifiedIndex++; } forwardPoints[diagonal] = originalIndex; if (originalIndex + modifiedIndex > furthestOriginalIndex + furthestModifiedIndex) { furthestOriginalIndex = originalIndex; furthestModifiedIndex = modifiedIndex; } // STEP 3: If delta is odd (overlap first happens on forward when delta is odd) // and diagonal is in the range of reverse diagonals computed for numDifferences-1 // (the previous iteration; we haven't computed reverse diagonals for numDifferences yet) // then check for overlap. if (!deltaIsEven && Math.abs(diagonal - diagonalReverseBase) <= (numDifferences - 1)) { if (originalIndex >= reversePoints[diagonal]) { midOriginalArr[0] = originalIndex; midModifiedArr[0] = modifiedIndex; if (tempOriginalIndex <= reversePoints[diagonal] && 1447 /* LocalConstants.MaxDifferencesHistory */ > 0 && numDifferences <= (1447 /* LocalConstants.MaxDifferencesHistory */ + 1)) { // BINGO! We overlapped, and we have the full trace in memory! return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, forwardPoints, reversePoints, originalIndex, originalEnd, midOriginalArr, modifiedIndex, modifiedEnd, midModifiedArr, deltaIsEven, quitEarlyArr); } else { // Either false overlap, or we didn't have enough memory for the full trace // Just return the recursion point return null; } } } } // Check to see if we should be quitting early, before moving on to the next iteration. const matchLengthOfLongest = ((furthestOriginalIndex - originalStart) + (furthestModifiedIndex - modifiedStart) - numDifferences) / 2; if (this.ContinueProcessingPredicate !== null && !this.ContinueProcessingPredicate(furthestOriginalIndex, matchLengthOfLongest)) { // We can't finish, so skip ahead to generating a result from what we have. quitEarlyArr[0] = true; // Use the furthest distance we got in the forward direction. midOriginalArr[0] = furthestOriginalIndex; midModifiedArr[0] = furthestModifiedIndex; if (matchLengthOfLongest > 0 && 1447 /* LocalConstants.MaxDifferencesHistory */ > 0 && numDifferences <= (1447 /* LocalConstants.MaxDifferencesHistory */ + 1)) { // Enough of the history is in memory to walk it backwards return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, forwardPoints, reversePoints, originalIndex, originalEnd, midOriginalArr, modifiedIndex, modifiedEnd, midModifiedArr, deltaIsEven, quitEarlyArr); } else { // We didn't actually remember enough of the history. //Since we are quitting the diff early, we need to shift back the originalStart and modified start //back into the boundary limits since we decremented their value above beyond the boundary limit. originalStart++; modifiedStart++; return [ new DiffChange(originalStart, originalEnd - originalStart + 1, modifiedStart, modifiedEnd - modifiedStart + 1) ]; } } // Run the algorithm in the reverse direction diagonalReverseStart = this.ClipDiagonalBound(diagonalReverseBase - numDifferences, numDifferences, diagonalReverseBase, numDiagonals); diagonalReverseEnd = this.ClipDiagonalBound(diagonalReverseBase + numDifferences, numDifferences, diagonalReverseBase, numDiagonals); for (let diagonal = diagonalReverseStart; diagonal <= diagonalReverseEnd; diagonal += 2) { // STEP 1: We extend the furthest reaching point in the present diagonal // by looking at the diagonals above and below and picking the one whose point // is further away from the start point (originalEnd, modifiedEnd) if (diagonal === diagonalReverseStart || (diagonal < diagonalReverseEnd && reversePoints[diagonal - 1] >= reversePoints[diagonal + 1])) { originalIndex = reversePoints[diagonal + 1] - 1; } else { originalIndex = reversePoints[diagonal - 1]; } modifiedIndex = originalIndex - (diagonal - diagonalReverseBase) - diagonalReverseOffset; // Save the current originalIndex so we can test for false overlap const tempOriginalIndex = originalIndex; // STEP 2: We can continue to extend the furthest reaching point in the present diagonal // as long as the elements are equal. while (originalIndex > originalStart && modifiedIndex > modifiedStart && this.ElementsAreEqual(originalIndex, modifiedIndex)) { originalIndex--; modifiedIndex--; } reversePoints[diagonal] = originalIndex; // STEP 4: If delta is even (overlap first happens on reverse when delta is even) // and diagonal is in the range of forward diagonals computed for numDifferences // then check for overlap. if (deltaIsEven && Math.abs(diagonal - diagonalForwardBase) <= numDifferences) { if (originalIndex <= forwardPoints[diagonal]) { midOriginalArr[0] = originalIndex; midModifiedArr[0] = modifiedIndex; if (tempOriginalIndex >= forwardPoints[diagonal] && 1447 /* LocalConstants.MaxDifferencesHistory */ > 0 && numDifferences <= (1447 /* LocalConstants.MaxDifferencesHistory */ + 1)) { // BINGO! We overlapped, and we have the full trace in memory! return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, forwardPoints, reversePoints, originalIndex, originalEnd, midOriginalArr, modifiedIndex, modifiedEnd, midModifiedArr, deltaIsEven, quitEarlyArr); } else { // Either false overlap, or we didn't have enough memory for the full trace // Just return the recursion point return null; } } } } // Save current vectors to history before the next iteration if (numDifferences <= 1447 /* LocalConstants.MaxDifferencesHistory */) { // We are allocating space for one extra int, which we fill with // the index of the diagonal base index let temp = new Int32Array(diagonalForwardEnd - diagonalForwardStart + 2); temp[0] = diagonalForwardBase - diagonalForwardStart + 1; MyArray.Copy2(forwardPoints, diagonalForwardStart, temp, 1, diagonalForwardEnd - diagonalForwardStart + 1); this.m_forwardHistory.push(temp); temp = new Int32Array(diagonalReverseEnd - diagonalReverseStart + 2); temp[0] = diagonalReverseBase - diagonalReverseStart + 1; MyArray.Copy2(reversePoints, diagonalReverseStart, temp, 1, diagonalReverseEnd - diagonalReverseStart + 1); this.m_reverseHistory.push(temp); } } // If we got here, then we have the full trace in history. We just have to convert it to a change list // NOTE: This part is a bit messy return this.WALKTRACE(diagonalForwardBase, diagonalForwardStart, diagonalForwardEnd, diagonalForwardOffset, diagonalReverseBase, diagonalReverseStart, diagonalReverseEnd, diagonalReverseOffset, forwardPoints, reversePoints, originalIndex, originalEnd, midOriginalArr, modifiedIndex, modifiedEnd, midModifiedArr, deltaIsEven, quitEarlyArr); } /** * Shifts the given changes to provide a more intuitive diff. * While the first element in a diff matches the first element after the diff, * we shift the diff down. * * @param changes The list of changes to shift * @returns The shifted changes */ PrettifyChanges(changes) { // Shift all the changes down first for (let i = 0; i < changes.length; i++) { const change = changes[i]; const originalStop = (i < changes.length - 1) ? changes[i + 1].originalStart : this._originalElementsOrHash.length; const modifiedStop = (i < changes.length - 1) ? changes[i + 1].modifiedStart : this._modifiedElementsOrHash.length; const checkOriginal = change.originalLength > 0; const checkModified = change.modifiedLength > 0; while (change.originalStart + change.originalLength < originalStop && change.modifiedStart + change.modifiedLength < modifiedStop && (!checkOriginal || this.OriginalElementsAreEqual(change.originalStart, change.originalStart + change.originalLength)) && (!checkModified || this.ModifiedElementsAreEqual(change.modifiedStart, change.modifiedStart + change.modifiedLength))) { const startStrictEqual = this.ElementsAreStrictEqual(change.originalStart, change.modifiedStart); const endStrictEqual = this.ElementsAreStrictEqual(change.originalStart + change.originalLength, change.modifiedStart + change.modifiedLength); if (endStrictEqual && !startStrictEqual) { // moving the change down would create an equal change, but the elements are not strict equal break; } change.originalStart++; change.modifiedStart++; } const mergedChangeArr = [null]; if (i < changes.length - 1 && this.ChangesOverlap(changes[i], changes[i + 1], mergedChangeArr)) { changes[i] = mergedChangeArr[0]; changes.splice(i + 1, 1); i--; continue; } } // Shift changes back up until we hit empty or whitespace-only lines for (let i = changes.length - 1; i >= 0; i--) { const change = changes[i]; let originalStop = 0; let modifiedStop = 0; if (i > 0) { const prevChange = changes[i - 1]; originalStop = prevChange.originalStart + prevChange.originalLength; modifiedStop = prevChange.modifiedStart + prevChange.modifiedLength; } const checkOriginal = change.originalLength > 0; const checkModified = change.modifiedLength > 0; let bestDelta = 0; let bestScore = this._boundaryScore(change.originalStart, change.originalLength, change.modifiedStart, change.modifiedLength); for (let delta = 1;; delta++) { const originalStart = change.originalStart - delta; const modifiedStart = change.modifiedStart - delta; if (originalStart < originalStop || modifiedStart < modifiedStop) { break; } if (checkOriginal && !this.OriginalElementsAreEqual(originalStart, originalStart + change.originalLength)) { break; } if (checkModified && !this.ModifiedElementsAreEqual(modifiedStart, modifiedStart + change.modifiedLength)) { break; } const touchingPreviousChange = (originalStart === originalStop && modifiedStart === modifiedStop); const score = ((touchingPreviousChange ? 5 : 0) + this._boundaryScore(originalStart, change.originalLength, modifiedStart, change.modifiedLength)); if (score > bestScore) { bestScore = score; bestDelta = delta; } } change.originalStart -= bestDelta; change.modifiedStart -= bestDelta; const mergedChangeArr = [null]; if (i > 0 && this.ChangesOverlap(changes[i - 1], changes[i], mergedChangeArr)) { changes[i - 1] = mergedChangeArr[0]; changes.splice(i, 1); i++; continue; } } // There could be multiple longest common substrings. // Give preference to the ones containing longer lines if (this._hasStrings) { for (let i = 1, len = changes.length; i < len; i++) { const aChange = changes[i - 1]; const bChange = changes[i]; const matchedLength = bChange.originalStart - aChange.originalStart - aChange.originalLength; const aOriginalStart = aChange.originalStart; const bOriginalEnd = bChange.originalStart + bChange.originalLength; const abOriginalLength = bOriginalEnd - aOriginalStart; const aModifiedStart = aChange.modifiedStart; const bModifiedEnd = bChange.modifiedStart + bChange.modifiedLength; const abModifiedLength = bModifiedEnd - aModifiedStart; // Avoid wasting a lot of time with these searches if (matchedLength < 5 && abOriginalLength < 20 && abModifiedLength < 20) { const t = this._findBetterContiguousSequence(aOriginalStart, abOriginalLength, aModifiedStart, abModifiedLength, matchedLength); if (t) { const [originalMatchStart, modifiedMatchStart] = t; if (originalMatchStart !== aChange.originalStart + aChange.originalLength || modifiedMatchStart !== aChange.modifiedStart + aChange.modifiedLength) { // switch to another sequence that has a better score aChange.originalLength = originalMatchStart - aChange.originalStart; aChange.modifiedLength = modifiedMatchStart - aChange.modifiedStart; bChange.originalStart = originalMatchStart + matchedLength; bChange.modifiedStart = modifiedMatchStart + matchedLength; bChange.originalLength = bOriginalEnd - bChange.originalStart; bChange.modifiedLength = bModifiedEnd - bChange.modifiedStart; } } } } } return changes; } _findBetterContiguousSequence(originalStart, originalLength, modifiedStart, modifiedLength, desiredLength) { if (originalLength < desiredLength || modifiedLength < desiredLength) { return null; } const originalMax = originalStart + originalLength - desiredLength + 1; const modifiedMax = modifiedStart + modifiedLength - desiredLength + 1; let bestScore = 0; let bestOriginalStart = 0; let bestModifiedStart = 0; for (let i = originalStart; i < originalMax; i++) { for (let j = modifiedStart; j < modifiedMax; j++) { const score = this._contiguousSequenceScore(i, j, desiredLength); if (score > 0 && score > bestScore) { bestScore = score; bestOriginalStart = i; bestModifiedStart = j; } } } if (bestScore > 0) { return [bestOriginalStart, bestModifiedStart]; } return null; } _contiguousSequenceScore(originalStart, modifiedStart, length) { let score = 0; for (let l = 0; l < length; l++) { if (!this.ElementsAreEqual(originalStart + l, modifiedStart + l)) { return 0; } score += this._originalStringElements[originalStart + l].length; } return score; } _OriginalIsBoundary(index) { if (index <= 0 || index >= this._originalElementsOrHash.length - 1) { return true; } return (this._hasStrings && /^\s*$/.test(this._originalStringElements[index])); } _OriginalRegionIsBoundary(originalStart, originalLength) { if (this._OriginalIsBoundary(originalStart) || this._OriginalIsBoundary(originalStart - 1)) { return true; } if (originalLength > 0) { const originalEnd = originalStart + originalLength; if (this._OriginalIsBoundary(originalEnd - 1) || this._OriginalIsBoundary(originalEnd)) { return true; } } return false; } _ModifiedIsBoundary(index) { if (index <= 0 || index >= this._modifiedElementsOrHash.length - 1) { return true; } return (this._hasStrings && /^\s*$/.test(this._modifiedStringElements[index])); } _ModifiedRegionIsBoundary(modifiedStart, modifiedLength) { if (this._ModifiedIsBoundary(modifiedStart) || this._ModifiedIsBoundary(modifiedStart - 1)) { return true; } if (modifiedLength > 0) { const modifiedEnd = modifiedStart + modifiedLength; if (this._ModifiedIsBoundary(modifiedEnd - 1) || this._ModifiedIsBoundary(modifiedEnd)) { return true; } } return false; } _boundaryScore(originalStart, originalLength, modifiedStart, modifiedLength) { const originalScore = (this._OriginalRegionIsBoundary(originalStart, originalLength) ? 1 : 0); const modifiedScore = (this._ModifiedRegionIsBoundary(modifiedStart, modifiedLength) ? 1 : 0); return (originalScore + modifiedScore); } /** * Concatenates the two input DiffChange lists and returns the resulting * list. * @param The left changes * @param The right changes * @returns The concatenated list */ ConcatenateChanges(left, right) { const mergedChangeArr = []; if (left.length === 0 || right.length === 0) { return (right.length > 0) ? right : left; } else if (this.ChangesOverlap(left[left.length - 1], right[0], mergedChangeArr)) { // Since we break the problem down recursively, it is possible that we // might recurse in the middle of a change thereby splitting it into // two changes. Here in the combining stage, we detect and fuse those // changes back together const result = new Array(left.length + right.length - 1); MyArray.Copy(left, 0, result, 0, left.length - 1); result[left.length - 1] = mergedChangeArr[0]; MyArray.Copy(right, 1, result, left.length, right.length - 1); return result; } else { const result = new Array(left.length + right.length); MyArray.Copy(left, 0, result, 0, left.length); MyArray.Copy(right, 0, result, left.length, right.length); return result; } } /** * Returns true if the two changes overlap and can be merged into a single * change * @param left The left change * @param right The right change * @param mergedChange The merged change if the two overlap, null otherwise * @returns True if the two changes overlap */ ChangesOverlap(left, right, mergedChangeArr) { Debug.Assert(left.originalStart <= right.originalStart, 'Left change is not less than or equal to right change'); Debug.Assert(left.modifiedStart <= right.modifiedStart, 'Left change is not less than or equal to right change'); if (left.originalStart + left.originalLength >= right.originalStart || left.modifiedStart + left.modifiedLength >= right.modifiedStart) { const originalStart = left.originalStart; let originalLength = left.originalLength; const modifiedStart = left.modifiedStart; let modifiedLength = left.modifiedLength; if (left.originalStart + left.originalLength >= right.originalStart) { originalLength = right.originalStart + right.originalLength - left.originalStart; } if (left.modifiedStart + left.modifiedLength >= right.modifiedStart) { modifiedLength = right.modifiedStart + right.modifiedLength - left.modifiedStart; } mergedChangeArr[0] = new DiffChange(originalStart, originalLength, modifiedStart, modifiedLength); return true; } else { mergedChangeArr[0] = null; return false; } } /** * Helper method used to clip a diagonal index to the range of valid * diagonals. This also decides whether or not the diagonal index, * if it exceeds the boundary, should be clipped to the boundary or clipped * one inside the boundary depending on the Even/Odd status of the boundary * and numDifferences. * @param diagonal The index of the diagonal to clip. * @param numDifferences The current number of differences being iterated upon. * @param diagonalBaseIndex The base reference diagonal. * @param numDiagonals The total number of diagonals. * @returns The clipped diagonal index. */ ClipDiagonalBound(diagonal, numDifferences, diagonalBaseIndex, numDiagonals) { if (diagonal >= 0 && diagonal < numDiagonals) { // Nothing to clip, its in range return diagonal; } // diagonalsBelow: The number of diagonals below the reference diagonal // diagonalsAbove: The number of diagonals above the reference diagonal const diagonalsBelow = diagonalBaseIndex; const diagonalsAbove = numDiagonals - diagonalBaseIndex - 1; const diffEven = (numDifferences % 2 === 0); if (diagonal < 0) { const lowerBoundEven = (diagonalsBelow % 2 === 0); return (diffEven === lowerBoundEven) ? 0 : 1; } else { const upperBoundEven = (diagonalsAbove % 2 === 0); return (diffEven === upperBoundEven) ? numDiagonals - 1 : numDiagonals - 2; } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A position in the editor. */ class Position { constructor(lineNumber, column) { this.lineNumber = lineNumber; this.column = column; } /** * Create a new position from this position. * * @param newLineNumber new line number * @param newColumn new column */ with(newLineNumber = this.lineNumber, newColumn = this.column) { if (newLineNumber === this.lineNumber && newColumn === this.column) { return this; } else { return new Position(newLineNumber, newColumn); } } /** * Derive a new position from this position. * * @param deltaLineNumber line number delta * @param deltaColumn column delta */ delta(deltaLineNumber = 0, deltaColumn = 0) { return this.with(this.lineNumber + deltaLineNumber, this.column + deltaColumn); } /** * Test if this position equals other position */ equals(other) { return Position.equals(this, other); } /** * Test if position `a` equals position `b` */ static equals(a, b) { if (!a && !b) { return true; } return (!!a && !!b && a.lineNumber === b.lineNumber && a.column === b.column); } /** * Test if this position is before other position. * If the two positions are equal, the result will be false. */ isBefore(other) { return Position.isBefore(this, other); } /** * Test if position `a` is before position `b`. * If the two positions are equal, the result will be false. */ static isBefore(a, b) { if (a.lineNumber < b.lineNumber) { return true; } if (b.lineNumber < a.lineNumber) { return false; } return a.column < b.column; } /** * Test if this position is before other position. * If the two positions are equal, the result will be true. */ isBeforeOrEqual(other) { return Position.isBeforeOrEqual(this, other); } /** * Test if position `a` is before position `b`. * If the two positions are equal, the result will be true. */ static isBeforeOrEqual(a, b) { if (a.lineNumber < b.lineNumber) { return true; } if (b.lineNumber < a.lineNumber) { return false; } return a.column <= b.column; } /** * A function that compares positions, useful for sorting */ static compare(a, b) { const aLineNumber = a.lineNumber | 0; const bLineNumber = b.lineNumber | 0; if (aLineNumber === bLineNumber) { const aColumn = a.column | 0; const bColumn = b.column | 0; return aColumn - bColumn; } return aLineNumber - bLineNumber; } /** * Clone this position. */ clone() { return new Position(this.lineNumber, this.column); } /** * Convert to a human-readable representation. */ toString() { return '(' + this.lineNumber + ',' + this.column + ')'; } // --- /** * Create a `Position` from an `IPosition`. */ static lift(pos) { return new Position(pos.lineNumber, pos.column); } /** * Test if `obj` is an `IPosition`. */ static isIPosition(obj) { return (obj && (typeof obj.lineNumber === 'number') && (typeof obj.column === 'number')); } toJSON() { return { lineNumber: this.lineNumber, column: this.column }; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A range in the editor. (startLineNumber,startColumn) is <= (endLineNumber,endColumn) */ class Range { constructor(startLineNumber, startColumn, endLineNumber, endColumn) { if ((startLineNumber > endLineNumber) || (startLineNumber === endLineNumber && startColumn > endColumn)) { this.startLineNumber = endLineNumber; this.startColumn = endColumn; this.endLineNumber = startLineNumber; this.endColumn = startColumn; } else { this.startLineNumber = startLineNumber; this.startColumn = startColumn; this.endLineNumber = endLineNumber; this.endColumn = endColumn; } } /** * Test if this range is empty. */ isEmpty() { return Range.isEmpty(this); } /** * Test if `range` is empty. */ static isEmpty(range) { return (range.startLineNumber === range.endLineNumber && range.startColumn === range.endColumn); } /** * Test if position is in this range. If the position is at the edges, will return true. */ containsPosition(position) { return Range.containsPosition(this, position); } /** * Test if `position` is in `range`. If the position is at the edges, will return true. */ static containsPosition(range, position) { if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) { return false; } if (position.lineNumber === range.startLineNumber && position.column < range.startColumn) { return false; } if (position.lineNumber === range.endLineNumber && position.column > range.endColumn) { return false; } return true; } /** * Test if `position` is in `range`. If the position is at the edges, will return false. * @internal */ static strictContainsPosition(range, position) { if (position.lineNumber < range.startLineNumber || position.lineNumber > range.endLineNumber) { return false; } if (position.lineNumber === range.startLineNumber && position.column <= range.startColumn) { return false; } if (position.lineNumber === range.endLineNumber && position.column >= range.endColumn) { return false; } return true; } /** * Test if range is in this range. If the range is equal to this range, will return true. */ containsRange(range) { return Range.containsRange(this, range); } /** * Test if `otherRange` is in `range`. If the ranges are equal, will return true. */ static containsRange(range, otherRange) { if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { return false; } if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { return false; } if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn < range.startColumn) { return false; } if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn > range.endColumn) { return false; } return true; } /** * Test if `range` is strictly in this range. `range` must start after and end before this range for the result to be true. */ strictContainsRange(range) { return Range.strictContainsRange(this, range); } /** * Test if `otherRange` is strictly in `range` (must start after, and end before). If the ranges are equal, will return false. */ static strictContainsRange(range, otherRange) { if (otherRange.startLineNumber < range.startLineNumber || otherRange.endLineNumber < range.startLineNumber) { return false; } if (otherRange.startLineNumber > range.endLineNumber || otherRange.endLineNumber > range.endLineNumber) { return false; } if (otherRange.startLineNumber === range.startLineNumber && otherRange.startColumn <= range.startColumn) { return false; } if (otherRange.endLineNumber === range.endLineNumber && otherRange.endColumn >= range.endColumn) { return false; } return true; } /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. */ plusRange(range) { return Range.plusRange(this, range); } /** * A reunion of the two ranges. * The smallest position will be used as the start point, and the largest one as the end point. */ static plusRange(a, b) { let startLineNumber; let startColumn; let endLineNumber; let endColumn; if (b.startLineNumber < a.startLineNumber) { startLineNumber = b.startLineNumber; startColumn = b.startColumn; } else if (b.startLineNumber === a.startLineNumber) { startLineNumber = b.startLineNumber; startColumn = Math.min(b.startColumn, a.startColumn); } else { startLineNumber = a.startLineNumber; startColumn = a.startColumn; } if (b.endLineNumber > a.endLineNumber) { endLineNumber = b.endLineNumber; endColumn = b.endColumn; } else if (b.endLineNumber === a.endLineNumber) { endLineNumber = b.endLineNumber; endColumn = Math.max(b.endColumn, a.endColumn); } else { endLineNumber = a.endLineNumber; endColumn = a.endColumn; } return new Range(startLineNumber, startColumn, endLineNumber, endColumn); } /** * A intersection of the two ranges. */ intersectRanges(range) { return Range.intersectRanges(this, range); } /** * A intersection of the two ranges. */ static intersectRanges(a, b) { let resultStartLineNumber = a.startLineNumber; let resultStartColumn = a.startColumn; let resultEndLineNumber = a.endLineNumber; let resultEndColumn = a.endColumn; const otherStartLineNumber = b.startLineNumber; const otherStartColumn = b.startColumn; const otherEndLineNumber = b.endLineNumber; const otherEndColumn = b.endColumn; if (resultStartLineNumber < otherStartLineNumber) { resultStartLineNumber = otherStartLineNumber; resultStartColumn = otherStartColumn; } else if (resultStartLineNumber === otherStartLineNumber) { resultStartColumn = Math.max(resultStartColumn, otherStartColumn); } if (resultEndLineNumber > otherEndLineNumber) { resultEndLineNumber = otherEndLineNumber; resultEndColumn = otherEndColumn; } else if (resultEndLineNumber === otherEndLineNumber) { resultEndColumn = Math.min(resultEndColumn, otherEndColumn); } // Check if selection is now empty if (resultStartLineNumber > resultEndLineNumber) { return null; } if (resultStartLineNumber === resultEndLineNumber && resultStartColumn > resultEndColumn) { return null; } return new Range(resultStartLineNumber, resultStartColumn, resultEndLineNumber, resultEndColumn); } /** * Test if this range equals other. */ equalsRange(other) { return Range.equalsRange(this, other); } /** * Test if range `a` equals `b`. */ static equalsRange(a, b) { if (!a && !b) { return true; } return (!!a && !!b && a.startLineNumber === b.startLineNumber && a.startColumn === b.startColumn && a.endLineNumber === b.endLineNumber && a.endColumn === b.endColumn); } /** * Return the end position (which will be after or equal to the start position) */ getEndPosition() { return Range.getEndPosition(this); } /** * Return the end position (which will be after or equal to the start position) */ static getEndPosition(range) { return new Position(range.endLineNumber, range.endColumn); } /** * Return the start position (which will be before or equal to the end position) */ getStartPosition() { return Range.getStartPosition(this); } /** * Return the start position (which will be before or equal to the end position) */ static getStartPosition(range) { return new Position(range.startLineNumber, range.startColumn); } /** * Transform to a user presentable string representation. */ toString() { return '[' + this.startLineNumber + ',' + this.startColumn + ' -> ' + this.endLineNumber + ',' + this.endColumn + ']'; } /** * Create a new range using this range's start position, and using endLineNumber and endColumn as the end position. */ setEndPosition(endLineNumber, endColumn) { return new Range(this.startLineNumber, this.startColumn, endLineNumber, endColumn); } /** * Create a new range using this range's end position, and using startLineNumber and startColumn as the start position. */ setStartPosition(startLineNumber, startColumn) { return new Range(startLineNumber, startColumn, this.endLineNumber, this.endColumn); } /** * Create a new empty range using this range's start position. */ collapseToStart() { return Range.collapseToStart(this); } /** * Create a new empty range using this range's start position. */ static collapseToStart(range) { return new Range(range.startLineNumber, range.startColumn, range.startLineNumber, range.startColumn); } /** * Create a new empty range using this range's end position. */ collapseToEnd() { return Range.collapseToEnd(this); } /** * Create a new empty range using this range's end position. */ static collapseToEnd(range) { return new Range(range.endLineNumber, range.endColumn, range.endLineNumber, range.endColumn); } /** * Moves the range by the given amount of lines. */ delta(lineCount) { return new Range(this.startLineNumber + lineCount, this.startColumn, this.endLineNumber + lineCount, this.endColumn); } // --- static fromPositions(start, end = start) { return new Range(start.lineNumber, start.column, end.lineNumber, end.column); } static lift(range) { if (!range) { return null; } return new Range(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn); } /** * Test if `obj` is an `IRange`. */ static isIRange(obj) { return (obj && (typeof obj.startLineNumber === 'number') && (typeof obj.startColumn === 'number') && (typeof obj.endLineNumber === 'number') && (typeof obj.endColumn === 'number')); } /** * Test if the two ranges are touching in any way. */ static areIntersectingOrTouching(a, b) { // Check if `a` is before `b` if (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn < b.startColumn)) { return false; } // Check if `b` is before `a` if (b.endLineNumber < a.startLineNumber || (b.endLineNumber === a.startLineNumber && b.endColumn < a.startColumn)) { return false; } // These ranges must intersect return true; } /** * Test if the two ranges are intersecting. If the ranges are touching it returns true. */ static areIntersecting(a, b) { // Check if `a` is before `b` if (a.endLineNumber < b.startLineNumber || (a.endLineNumber === b.startLineNumber && a.endColumn <= b.startColumn)) { return false; } // Check if `b` is before `a` if (b.endLineNumber < a.startLineNumber || (b.endLineNumber === a.startLineNumber && b.endColumn <= a.startColumn)) { return false; } // These ranges must intersect return true; } /** * A function that compares ranges, useful for sorting ranges * It will first compare ranges on the startPosition and then on the endPosition */ static compareRangesUsingStarts(a, b) { if (a && b) { const aStartLineNumber = a.startLineNumber | 0; const bStartLineNumber = b.startLineNumber | 0; if (aStartLineNumber === bStartLineNumber) { const aStartColumn = a.startColumn | 0; const bStartColumn = b.startColumn | 0; if (aStartColumn === bStartColumn) { const aEndLineNumber = a.endLineNumber | 0; const bEndLineNumber = b.endLineNumber | 0; if (aEndLineNumber === bEndLineNumber) { const aEndColumn = a.endColumn | 0; const bEndColumn = b.endColumn | 0; return aEndColumn - bEndColumn; } return aEndLineNumber - bEndLineNumber; } return aStartColumn - bStartColumn; } return aStartLineNumber - bStartLineNumber; } const aExists = (a ? 1 : 0); const bExists = (b ? 1 : 0); return aExists - bExists; } /** * A function that compares ranges, useful for sorting ranges * It will first compare ranges on the endPosition and then on the startPosition */ static compareRangesUsingEnds(a, b) { if (a.endLineNumber === b.endLineNumber) { if (a.endColumn === b.endColumn) { if (a.startLineNumber === b.startLineNumber) { return a.startColumn - b.startColumn; } return a.startLineNumber - b.startLineNumber; } return a.endColumn - b.endColumn; } return a.endLineNumber - b.endLineNumber; } /** * Test if the range spans multiple lines. */ static spansMultipleLines(range) { return range.endLineNumber > range.startLineNumber; } toJSON() { return this; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function toUint8(v) { if (v < 0) { return 0; } if (v > 255 /* Constants.MAX_UINT_8 */) { return 255 /* Constants.MAX_UINT_8 */; } return v | 0; } function toUint32(v) { if (v < 0) { return 0; } if (v > 4294967295 /* Constants.MAX_UINT_32 */) { return 4294967295 /* Constants.MAX_UINT_32 */; } return v | 0; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A fast character classifier that uses a compact array for ASCII values. */ class CharacterClassifier { constructor(_defaultValue) { const defaultValue = toUint8(_defaultValue); this._defaultValue = defaultValue; this._asciiMap = CharacterClassifier._createAsciiMap(defaultValue); this._map = new Map(); } static _createAsciiMap(defaultValue) { const asciiMap = new Uint8Array(256); asciiMap.fill(defaultValue); return asciiMap; } set(charCode, _value) { const value = toUint8(_value); if (charCode >= 0 && charCode < 256) { this._asciiMap[charCode] = value; } else { this._map.set(charCode, value); } } get(charCode) { if (charCode >= 0 && charCode < 256) { return this._asciiMap[charCode]; } else { return (this._map.get(charCode) || this._defaultValue); } } clear() { this._asciiMap.fill(this._defaultValue); this._map.clear(); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class Uint8Matrix { constructor(rows, cols, defaultValue) { const data = new Uint8Array(rows * cols); for (let i = 0, len = rows * cols; i < len; i++) { data[i] = defaultValue; } this._data = data; this.rows = rows; this.cols = cols; } get(row, col) { return this._data[row * this.cols + col]; } set(row, col, value) { this._data[row * this.cols + col] = value; } } class StateMachine { constructor(edges) { let maxCharCode = 0; let maxState = 0 /* State.Invalid */; for (let i = 0, len = edges.length; i < len; i++) { const [from, chCode, to] = edges[i]; if (chCode > maxCharCode) { maxCharCode = chCode; } if (from > maxState) { maxState = from; } if (to > maxState) { maxState = to; } } maxCharCode++; maxState++; const states = new Uint8Matrix(maxState, maxCharCode, 0 /* State.Invalid */); for (let i = 0, len = edges.length; i < len; i++) { const [from, chCode, to] = edges[i]; states.set(from, chCode, to); } this._states = states; this._maxCharCode = maxCharCode; } nextState(currentState, chCode) { if (chCode < 0 || chCode >= this._maxCharCode) { return 0 /* State.Invalid */; } return this._states.get(currentState, chCode); } } // State machine for http:// or https:// or file:// let _stateMachine = null; function getStateMachine() { if (_stateMachine === null) { _stateMachine = new StateMachine([ [1 /* State.Start */, 104 /* CharCode.h */, 2 /* State.H */], [1 /* State.Start */, 72 /* CharCode.H */, 2 /* State.H */], [1 /* State.Start */, 102 /* CharCode.f */, 6 /* State.F */], [1 /* State.Start */, 70 /* CharCode.F */, 6 /* State.F */], [2 /* State.H */, 116 /* CharCode.t */, 3 /* State.HT */], [2 /* State.H */, 84 /* CharCode.T */, 3 /* State.HT */], [3 /* State.HT */, 116 /* CharCode.t */, 4 /* State.HTT */], [3 /* State.HT */, 84 /* CharCode.T */, 4 /* State.HTT */], [4 /* State.HTT */, 112 /* CharCode.p */, 5 /* State.HTTP */], [4 /* State.HTT */, 80 /* CharCode.P */, 5 /* State.HTTP */], [5 /* State.HTTP */, 115 /* CharCode.s */, 9 /* State.BeforeColon */], [5 /* State.HTTP */, 83 /* CharCode.S */, 9 /* State.BeforeColon */], [5 /* State.HTTP */, 58 /* CharCode.Colon */, 10 /* State.AfterColon */], [6 /* State.F */, 105 /* CharCode.i */, 7 /* State.FI */], [6 /* State.F */, 73 /* CharCode.I */, 7 /* State.FI */], [7 /* State.FI */, 108 /* CharCode.l */, 8 /* State.FIL */], [7 /* State.FI */, 76 /* CharCode.L */, 8 /* State.FIL */], [8 /* State.FIL */, 101 /* CharCode.e */, 9 /* State.BeforeColon */], [8 /* State.FIL */, 69 /* CharCode.E */, 9 /* State.BeforeColon */], [9 /* State.BeforeColon */, 58 /* CharCode.Colon */, 10 /* State.AfterColon */], [10 /* State.AfterColon */, 47 /* CharCode.Slash */, 11 /* State.AlmostThere */], [11 /* State.AlmostThere */, 47 /* CharCode.Slash */, 12 /* State.End */], ]); } return _stateMachine; } let _classifier = null; function getClassifier() { if (_classifier === null) { _classifier = new CharacterClassifier(0 /* CharacterClass.None */); // allow-any-unicode-next-line const FORCE_TERMINATION_CHARACTERS = ' \t<>\'\"、。。、,.:;‘〈「『〔([{「」}])〕』」〉’`~…'; for (let i = 0; i < FORCE_TERMINATION_CHARACTERS.length; i++) { _classifier.set(FORCE_TERMINATION_CHARACTERS.charCodeAt(i), 1 /* CharacterClass.ForceTermination */); } const CANNOT_END_WITH_CHARACTERS = '.,;:'; for (let i = 0; i < CANNOT_END_WITH_CHARACTERS.length; i++) { _classifier.set(CANNOT_END_WITH_CHARACTERS.charCodeAt(i), 2 /* CharacterClass.CannotEndIn */); } } return _classifier; } class LinkComputer { static _createLink(classifier, line, lineNumber, linkBeginIndex, linkEndIndex) { // Do not allow to end link in certain characters... let lastIncludedCharIndex = linkEndIndex - 1; do { const chCode = line.charCodeAt(lastIncludedCharIndex); const chClass = classifier.get(chCode); if (chClass !== 2 /* CharacterClass.CannotEndIn */) { break; } lastIncludedCharIndex--; } while (lastIncludedCharIndex > linkBeginIndex); // Handle links enclosed in parens, square brackets and curlys. if (linkBeginIndex > 0) { const charCodeBeforeLink = line.charCodeAt(linkBeginIndex - 1); const lastCharCodeInLink = line.charCodeAt(lastIncludedCharIndex); if ((charCodeBeforeLink === 40 /* CharCode.OpenParen */ && lastCharCodeInLink === 41 /* CharCode.CloseParen */) || (charCodeBeforeLink === 91 /* CharCode.OpenSquareBracket */ && lastCharCodeInLink === 93 /* CharCode.CloseSquareBracket */) || (charCodeBeforeLink === 123 /* CharCode.OpenCurlyBrace */ && lastCharCodeInLink === 125 /* CharCode.CloseCurlyBrace */)) { // Do not end in ) if ( is before the link start // Do not end in ] if [ is before the link start // Do not end in } if { is before the link start lastIncludedCharIndex--; } } return { range: { startLineNumber: lineNumber, startColumn: linkBeginIndex + 1, endLineNumber: lineNumber, endColumn: lastIncludedCharIndex + 2 }, url: line.substring(linkBeginIndex, lastIncludedCharIndex + 1) }; } static computeLinks(model, stateMachine = getStateMachine()) { const classifier = getClassifier(); const result = []; for (let i = 1, lineCount = model.getLineCount(); i <= lineCount; i++) { const line = model.getLineContent(i); const len = line.length; let j = 0; let linkBeginIndex = 0; let linkBeginChCode = 0; let state = 1 /* State.Start */; let hasOpenParens = false; let hasOpenSquareBracket = false; let inSquareBrackets = false; let hasOpenCurlyBracket = false; while (j < len) { let resetStateMachine = false; const chCode = line.charCodeAt(j); if (state === 13 /* State.Accept */) { let chClass; switch (chCode) { case 40 /* CharCode.OpenParen */: hasOpenParens = true; chClass = 0 /* CharacterClass.None */; break; case 41 /* CharCode.CloseParen */: chClass = (hasOpenParens ? 0 /* CharacterClass.None */ : 1 /* CharacterClass.ForceTermination */); break; case 91 /* CharCode.OpenSquareBracket */: inSquareBrackets = true; hasOpenSquareBracket = true; chClass = 0 /* CharacterClass.None */; break; case 93 /* CharCode.CloseSquareBracket */: inSquareBrackets = false; chClass = (hasOpenSquareBracket ? 0 /* CharacterClass.None */ : 1 /* CharacterClass.ForceTermination */); break; case 123 /* CharCode.OpenCurlyBrace */: hasOpenCurlyBracket = true; chClass = 0 /* CharacterClass.None */; break; case 125 /* CharCode.CloseCurlyBrace */: chClass = (hasOpenCurlyBracket ? 0 /* CharacterClass.None */ : 1 /* CharacterClass.ForceTermination */); break; // The following three rules make it that ' or " or ` are allowed inside links // only if the link is wrapped by some other quote character case 39 /* CharCode.SingleQuote */: case 34 /* CharCode.DoubleQuote */: case 96 /* CharCode.BackTick */: if (linkBeginChCode === chCode) { chClass = 1 /* CharacterClass.ForceTermination */; } else if (linkBeginChCode === 39 /* CharCode.SingleQuote */ || linkBeginChCode === 34 /* CharCode.DoubleQuote */ || linkBeginChCode === 96 /* CharCode.BackTick */) { chClass = 0 /* CharacterClass.None */; } else { chClass = 1 /* CharacterClass.ForceTermination */; } break; case 42 /* CharCode.Asterisk */: // `*` terminates a link if the link began with `*` chClass = (linkBeginChCode === 42 /* CharCode.Asterisk */) ? 1 /* CharacterClass.ForceTermination */ : 0 /* CharacterClass.None */; break; case 124 /* CharCode.Pipe */: // `|` terminates a link if the link began with `|` chClass = (linkBeginChCode === 124 /* CharCode.Pipe */) ? 1 /* CharacterClass.ForceTermination */ : 0 /* CharacterClass.None */; break; case 32 /* CharCode.Space */: // ` ` allow space in between [ and ] chClass = (inSquareBrackets ? 0 /* CharacterClass.None */ : 1 /* CharacterClass.ForceTermination */); break; default: chClass = classifier.get(chCode); } // Check if character terminates link if (chClass === 1 /* CharacterClass.ForceTermination */) { result.push(LinkComputer._createLink(classifier, line, i, linkBeginIndex, j)); resetStateMachine = true; } } else if (state === 12 /* State.End */) { let chClass; if (chCode === 91 /* CharCode.OpenSquareBracket */) { // Allow for the authority part to contain ipv6 addresses which contain [ and ] hasOpenSquareBracket = true; chClass = 0 /* CharacterClass.None */; } else { chClass = classifier.get(chCode); } // Check if character terminates link if (chClass === 1 /* CharacterClass.ForceTermination */) { resetStateMachine = true; } else { state = 13 /* State.Accept */; } } else { state = stateMachine.nextState(state, chCode); if (state === 0 /* State.Invalid */) { resetStateMachine = true; } } if (resetStateMachine) { state = 1 /* State.Start */; hasOpenParens = false; hasOpenSquareBracket = false; hasOpenCurlyBracket = false; // Record where the link started linkBeginIndex = j + 1; linkBeginChCode = chCode; } j++; } if (state === 13 /* State.Accept */) { result.push(LinkComputer._createLink(classifier, line, i, linkBeginIndex, len)); } } return result; } } /** * Returns an array of all links contains in the provided * document. *Note* that this operation is computational * expensive and should not run in the UI thread. */ function computeLinks(model) { if (!model || typeof model.getLineCount !== 'function' || typeof model.getLineContent !== 'function') { // Unknown caller! return []; } return LinkComputer.computeLinks(model); } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class BasicInplaceReplace { constructor() { this._defaultValueSet = [ ['true', 'false'], ['True', 'False'], ['Private', 'Public', 'Friend', 'ReadOnly', 'Partial', 'Protected', 'WriteOnly'], ['public', 'protected', 'private'], ]; } static { this.INSTANCE = new BasicInplaceReplace(); } navigateValueSet(range1, text1, range2, text2, up) { if (range1 && text1) { const result = this.doNavigateValueSet(text1, up); if (result) { return { range: range1, value: result }; } } if (range2 && text2) { const result = this.doNavigateValueSet(text2, up); if (result) { return { range: range2, value: result }; } } return null; } doNavigateValueSet(text, up) { const numberResult = this.numberReplace(text, up); if (numberResult !== null) { return numberResult; } return this.textReplace(text, up); } numberReplace(value, up) { const precision = Math.pow(10, value.length - (value.lastIndexOf('.') + 1)); let n1 = Number(value); const n2 = parseFloat(value); if (!isNaN(n1) && !isNaN(n2) && n1 === n2) { if (n1 === 0 && !up) { return null; // don't do negative // } else if(n1 === 9 && up) { // return null; // don't insert 10 into a number } else { n1 = Math.floor(n1 * precision); n1 += up ? precision : -precision; return String(n1 / precision); } } return null; } textReplace(value, up) { return this.valueSetsReplace(this._defaultValueSet, value, up); } valueSetsReplace(valueSets, value, up) { let result = null; for (let i = 0, len = valueSets.length; result === null && i < len; i++) { result = this.valueSetReplace(valueSets[i], value, up); } return result; } valueSetReplace(valueSet, value, up) { let idx = valueSet.indexOf(value); if (idx >= 0) { idx += up ? +1 : -1; if (idx < 0) { idx = valueSet.length - 1; } else { idx %= valueSet.length; } return valueSet[idx]; } return null; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const shortcutEvent = Object.freeze(function (callback, context) { const handle = setTimeout(callback.bind(context), 0); return { dispose() { clearTimeout(handle); } }; }); var CancellationToken; (function (CancellationToken) { function isCancellationToken(thing) { if (thing === CancellationToken.None || thing === CancellationToken.Cancelled) { return true; } if (thing instanceof MutableToken) { return true; } if (!thing || typeof thing !== 'object') { return false; } return typeof thing.isCancellationRequested === 'boolean' && typeof thing.onCancellationRequested === 'function'; } CancellationToken.isCancellationToken = isCancellationToken; CancellationToken.None = Object.freeze({ isCancellationRequested: false, onCancellationRequested: Event.None }); CancellationToken.Cancelled = Object.freeze({ isCancellationRequested: true, onCancellationRequested: shortcutEvent }); })(CancellationToken || (CancellationToken = {})); class MutableToken { constructor() { this._isCancelled = false; this._emitter = null; } cancel() { if (!this._isCancelled) { this._isCancelled = true; if (this._emitter) { this._emitter.fire(undefined); this.dispose(); } } } get isCancellationRequested() { return this._isCancelled; } get onCancellationRequested() { if (this._isCancelled) { return shortcutEvent; } if (!this._emitter) { this._emitter = new Emitter(); } return this._emitter.event; } dispose() { if (this._emitter) { this._emitter.dispose(); this._emitter = null; } } } class CancellationTokenSource { constructor(parent) { this._token = undefined; this._parentListener = undefined; this._parentListener = parent && parent.onCancellationRequested(this.cancel, this); } get token() { if (!this._token) { // be lazy and create the token only when // actually needed this._token = new MutableToken(); } return this._token; } cancel() { if (!this._token) { // save an object by returning the default // cancelled token when cancellation happens // before someone asks for the token this._token = CancellationToken.Cancelled; } else if (this._token instanceof MutableToken) { // actually cancel this._token.cancel(); } } dispose(cancel = false) { if (cancel) { this.cancel(); } this._parentListener?.dispose(); if (!this._token) { // ensure to initialize with an empty token if we had none this._token = CancellationToken.None; } else if (this._token instanceof MutableToken) { // actually dispose this._token.dispose(); } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class KeyCodeStrMap { constructor() { this._keyCodeToStr = []; this._strToKeyCode = Object.create(null); } define(keyCode, str) { this._keyCodeToStr[keyCode] = str; this._strToKeyCode[str.toLowerCase()] = keyCode; } keyCodeToStr(keyCode) { return this._keyCodeToStr[keyCode]; } strToKeyCode(str) { return this._strToKeyCode[str.toLowerCase()] || 0 /* KeyCode.Unknown */; } } const uiMap = new KeyCodeStrMap(); const userSettingsUSMap = new KeyCodeStrMap(); const userSettingsGeneralMap = new KeyCodeStrMap(); const EVENT_KEY_CODE_MAP = new Array(230); const scanCodeStrToInt = Object.create(null); const scanCodeLowerCaseStrToInt = Object.create(null); (function () { // See https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx // See https://github.com/microsoft/node-native-keymap/blob/88c0b0e5/deps/chromium/keyboard_codes_win.h const empty = ''; const mappings = [ // immutable, scanCode, scanCodeStr, keyCode, keyCodeStr, eventKeyCode, vkey, usUserSettingsLabel, generalUserSettingsLabel [1, 0 /* ScanCode.None */, 'None', 0 /* KeyCode.Unknown */, 'unknown', 0, 'VK_UNKNOWN', empty, empty], [1, 1 /* ScanCode.Hyper */, 'Hyper', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 2 /* ScanCode.Super */, 'Super', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 3 /* ScanCode.Fn */, 'Fn', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 4 /* ScanCode.FnLock */, 'FnLock', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 5 /* ScanCode.Suspend */, 'Suspend', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 6 /* ScanCode.Resume */, 'Resume', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 7 /* ScanCode.Turbo */, 'Turbo', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 8 /* ScanCode.Sleep */, 'Sleep', 0 /* KeyCode.Unknown */, empty, 0, 'VK_SLEEP', empty, empty], [1, 9 /* ScanCode.WakeUp */, 'WakeUp', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [0, 10 /* ScanCode.KeyA */, 'KeyA', 31 /* KeyCode.KeyA */, 'A', 65, 'VK_A', empty, empty], [0, 11 /* ScanCode.KeyB */, 'KeyB', 32 /* KeyCode.KeyB */, 'B', 66, 'VK_B', empty, empty], [0, 12 /* ScanCode.KeyC */, 'KeyC', 33 /* KeyCode.KeyC */, 'C', 67, 'VK_C', empty, empty], [0, 13 /* ScanCode.KeyD */, 'KeyD', 34 /* KeyCode.KeyD */, 'D', 68, 'VK_D', empty, empty], [0, 14 /* ScanCode.KeyE */, 'KeyE', 35 /* KeyCode.KeyE */, 'E', 69, 'VK_E', empty, empty], [0, 15 /* ScanCode.KeyF */, 'KeyF', 36 /* KeyCode.KeyF */, 'F', 70, 'VK_F', empty, empty], [0, 16 /* ScanCode.KeyG */, 'KeyG', 37 /* KeyCode.KeyG */, 'G', 71, 'VK_G', empty, empty], [0, 17 /* ScanCode.KeyH */, 'KeyH', 38 /* KeyCode.KeyH */, 'H', 72, 'VK_H', empty, empty], [0, 18 /* ScanCode.KeyI */, 'KeyI', 39 /* KeyCode.KeyI */, 'I', 73, 'VK_I', empty, empty], [0, 19 /* ScanCode.KeyJ */, 'KeyJ', 40 /* KeyCode.KeyJ */, 'J', 74, 'VK_J', empty, empty], [0, 20 /* ScanCode.KeyK */, 'KeyK', 41 /* KeyCode.KeyK */, 'K', 75, 'VK_K', empty, empty], [0, 21 /* ScanCode.KeyL */, 'KeyL', 42 /* KeyCode.KeyL */, 'L', 76, 'VK_L', empty, empty], [0, 22 /* ScanCode.KeyM */, 'KeyM', 43 /* KeyCode.KeyM */, 'M', 77, 'VK_M', empty, empty], [0, 23 /* ScanCode.KeyN */, 'KeyN', 44 /* KeyCode.KeyN */, 'N', 78, 'VK_N', empty, empty], [0, 24 /* ScanCode.KeyO */, 'KeyO', 45 /* KeyCode.KeyO */, 'O', 79, 'VK_O', empty, empty], [0, 25 /* ScanCode.KeyP */, 'KeyP', 46 /* KeyCode.KeyP */, 'P', 80, 'VK_P', empty, empty], [0, 26 /* ScanCode.KeyQ */, 'KeyQ', 47 /* KeyCode.KeyQ */, 'Q', 81, 'VK_Q', empty, empty], [0, 27 /* ScanCode.KeyR */, 'KeyR', 48 /* KeyCode.KeyR */, 'R', 82, 'VK_R', empty, empty], [0, 28 /* ScanCode.KeyS */, 'KeyS', 49 /* KeyCode.KeyS */, 'S', 83, 'VK_S', empty, empty], [0, 29 /* ScanCode.KeyT */, 'KeyT', 50 /* KeyCode.KeyT */, 'T', 84, 'VK_T', empty, empty], [0, 30 /* ScanCode.KeyU */, 'KeyU', 51 /* KeyCode.KeyU */, 'U', 85, 'VK_U', empty, empty], [0, 31 /* ScanCode.KeyV */, 'KeyV', 52 /* KeyCode.KeyV */, 'V', 86, 'VK_V', empty, empty], [0, 32 /* ScanCode.KeyW */, 'KeyW', 53 /* KeyCode.KeyW */, 'W', 87, 'VK_W', empty, empty], [0, 33 /* ScanCode.KeyX */, 'KeyX', 54 /* KeyCode.KeyX */, 'X', 88, 'VK_X', empty, empty], [0, 34 /* ScanCode.KeyY */, 'KeyY', 55 /* KeyCode.KeyY */, 'Y', 89, 'VK_Y', empty, empty], [0, 35 /* ScanCode.KeyZ */, 'KeyZ', 56 /* KeyCode.KeyZ */, 'Z', 90, 'VK_Z', empty, empty], [0, 36 /* ScanCode.Digit1 */, 'Digit1', 22 /* KeyCode.Digit1 */, '1', 49, 'VK_1', empty, empty], [0, 37 /* ScanCode.Digit2 */, 'Digit2', 23 /* KeyCode.Digit2 */, '2', 50, 'VK_2', empty, empty], [0, 38 /* ScanCode.Digit3 */, 'Digit3', 24 /* KeyCode.Digit3 */, '3', 51, 'VK_3', empty, empty], [0, 39 /* ScanCode.Digit4 */, 'Digit4', 25 /* KeyCode.Digit4 */, '4', 52, 'VK_4', empty, empty], [0, 40 /* ScanCode.Digit5 */, 'Digit5', 26 /* KeyCode.Digit5 */, '5', 53, 'VK_5', empty, empty], [0, 41 /* ScanCode.Digit6 */, 'Digit6', 27 /* KeyCode.Digit6 */, '6', 54, 'VK_6', empty, empty], [0, 42 /* ScanCode.Digit7 */, 'Digit7', 28 /* KeyCode.Digit7 */, '7', 55, 'VK_7', empty, empty], [0, 43 /* ScanCode.Digit8 */, 'Digit8', 29 /* KeyCode.Digit8 */, '8', 56, 'VK_8', empty, empty], [0, 44 /* ScanCode.Digit9 */, 'Digit9', 30 /* KeyCode.Digit9 */, '9', 57, 'VK_9', empty, empty], [0, 45 /* ScanCode.Digit0 */, 'Digit0', 21 /* KeyCode.Digit0 */, '0', 48, 'VK_0', empty, empty], [1, 46 /* ScanCode.Enter */, 'Enter', 3 /* KeyCode.Enter */, 'Enter', 13, 'VK_RETURN', empty, empty], [1, 47 /* ScanCode.Escape */, 'Escape', 9 /* KeyCode.Escape */, 'Escape', 27, 'VK_ESCAPE', empty, empty], [1, 48 /* ScanCode.Backspace */, 'Backspace', 1 /* KeyCode.Backspace */, 'Backspace', 8, 'VK_BACK', empty, empty], [1, 49 /* ScanCode.Tab */, 'Tab', 2 /* KeyCode.Tab */, 'Tab', 9, 'VK_TAB', empty, empty], [1, 50 /* ScanCode.Space */, 'Space', 10 /* KeyCode.Space */, 'Space', 32, 'VK_SPACE', empty, empty], [0, 51 /* ScanCode.Minus */, 'Minus', 88 /* KeyCode.Minus */, '-', 189, 'VK_OEM_MINUS', '-', 'OEM_MINUS'], [0, 52 /* ScanCode.Equal */, 'Equal', 86 /* KeyCode.Equal */, '=', 187, 'VK_OEM_PLUS', '=', 'OEM_PLUS'], [0, 53 /* ScanCode.BracketLeft */, 'BracketLeft', 92 /* KeyCode.BracketLeft */, '[', 219, 'VK_OEM_4', '[', 'OEM_4'], [0, 54 /* ScanCode.BracketRight */, 'BracketRight', 94 /* KeyCode.BracketRight */, ']', 221, 'VK_OEM_6', ']', 'OEM_6'], [0, 55 /* ScanCode.Backslash */, 'Backslash', 93 /* KeyCode.Backslash */, '\\', 220, 'VK_OEM_5', '\\', 'OEM_5'], [0, 56 /* ScanCode.IntlHash */, 'IntlHash', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], // has been dropped from the w3c spec [0, 57 /* ScanCode.Semicolon */, 'Semicolon', 85 /* KeyCode.Semicolon */, ';', 186, 'VK_OEM_1', ';', 'OEM_1'], [0, 58 /* ScanCode.Quote */, 'Quote', 95 /* KeyCode.Quote */, '\'', 222, 'VK_OEM_7', '\'', 'OEM_7'], [0, 59 /* ScanCode.Backquote */, 'Backquote', 91 /* KeyCode.Backquote */, '`', 192, 'VK_OEM_3', '`', 'OEM_3'], [0, 60 /* ScanCode.Comma */, 'Comma', 87 /* KeyCode.Comma */, ',', 188, 'VK_OEM_COMMA', ',', 'OEM_COMMA'], [0, 61 /* ScanCode.Period */, 'Period', 89 /* KeyCode.Period */, '.', 190, 'VK_OEM_PERIOD', '.', 'OEM_PERIOD'], [0, 62 /* ScanCode.Slash */, 'Slash', 90 /* KeyCode.Slash */, '/', 191, 'VK_OEM_2', '/', 'OEM_2'], [1, 63 /* ScanCode.CapsLock */, 'CapsLock', 8 /* KeyCode.CapsLock */, 'CapsLock', 20, 'VK_CAPITAL', empty, empty], [1, 64 /* ScanCode.F1 */, 'F1', 59 /* KeyCode.F1 */, 'F1', 112, 'VK_F1', empty, empty], [1, 65 /* ScanCode.F2 */, 'F2', 60 /* KeyCode.F2 */, 'F2', 113, 'VK_F2', empty, empty], [1, 66 /* ScanCode.F3 */, 'F3', 61 /* KeyCode.F3 */, 'F3', 114, 'VK_F3', empty, empty], [1, 67 /* ScanCode.F4 */, 'F4', 62 /* KeyCode.F4 */, 'F4', 115, 'VK_F4', empty, empty], [1, 68 /* ScanCode.F5 */, 'F5', 63 /* KeyCode.F5 */, 'F5', 116, 'VK_F5', empty, empty], [1, 69 /* ScanCode.F6 */, 'F6', 64 /* KeyCode.F6 */, 'F6', 117, 'VK_F6', empty, empty], [1, 70 /* ScanCode.F7 */, 'F7', 65 /* KeyCode.F7 */, 'F7', 118, 'VK_F7', empty, empty], [1, 71 /* ScanCode.F8 */, 'F8', 66 /* KeyCode.F8 */, 'F8', 119, 'VK_F8', empty, empty], [1, 72 /* ScanCode.F9 */, 'F9', 67 /* KeyCode.F9 */, 'F9', 120, 'VK_F9', empty, empty], [1, 73 /* ScanCode.F10 */, 'F10', 68 /* KeyCode.F10 */, 'F10', 121, 'VK_F10', empty, empty], [1, 74 /* ScanCode.F11 */, 'F11', 69 /* KeyCode.F11 */, 'F11', 122, 'VK_F11', empty, empty], [1, 75 /* ScanCode.F12 */, 'F12', 70 /* KeyCode.F12 */, 'F12', 123, 'VK_F12', empty, empty], [1, 76 /* ScanCode.PrintScreen */, 'PrintScreen', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 77 /* ScanCode.ScrollLock */, 'ScrollLock', 84 /* KeyCode.ScrollLock */, 'ScrollLock', 145, 'VK_SCROLL', empty, empty], [1, 78 /* ScanCode.Pause */, 'Pause', 7 /* KeyCode.PauseBreak */, 'PauseBreak', 19, 'VK_PAUSE', empty, empty], [1, 79 /* ScanCode.Insert */, 'Insert', 19 /* KeyCode.Insert */, 'Insert', 45, 'VK_INSERT', empty, empty], [1, 80 /* ScanCode.Home */, 'Home', 14 /* KeyCode.Home */, 'Home', 36, 'VK_HOME', empty, empty], [1, 81 /* ScanCode.PageUp */, 'PageUp', 11 /* KeyCode.PageUp */, 'PageUp', 33, 'VK_PRIOR', empty, empty], [1, 82 /* ScanCode.Delete */, 'Delete', 20 /* KeyCode.Delete */, 'Delete', 46, 'VK_DELETE', empty, empty], [1, 83 /* ScanCode.End */, 'End', 13 /* KeyCode.End */, 'End', 35, 'VK_END', empty, empty], [1, 84 /* ScanCode.PageDown */, 'PageDown', 12 /* KeyCode.PageDown */, 'PageDown', 34, 'VK_NEXT', empty, empty], [1, 85 /* ScanCode.ArrowRight */, 'ArrowRight', 17 /* KeyCode.RightArrow */, 'RightArrow', 39, 'VK_RIGHT', 'Right', empty], [1, 86 /* ScanCode.ArrowLeft */, 'ArrowLeft', 15 /* KeyCode.LeftArrow */, 'LeftArrow', 37, 'VK_LEFT', 'Left', empty], [1, 87 /* ScanCode.ArrowDown */, 'ArrowDown', 18 /* KeyCode.DownArrow */, 'DownArrow', 40, 'VK_DOWN', 'Down', empty], [1, 88 /* ScanCode.ArrowUp */, 'ArrowUp', 16 /* KeyCode.UpArrow */, 'UpArrow', 38, 'VK_UP', 'Up', empty], [1, 89 /* ScanCode.NumLock */, 'NumLock', 83 /* KeyCode.NumLock */, 'NumLock', 144, 'VK_NUMLOCK', empty, empty], [1, 90 /* ScanCode.NumpadDivide */, 'NumpadDivide', 113 /* KeyCode.NumpadDivide */, 'NumPad_Divide', 111, 'VK_DIVIDE', empty, empty], [1, 91 /* ScanCode.NumpadMultiply */, 'NumpadMultiply', 108 /* KeyCode.NumpadMultiply */, 'NumPad_Multiply', 106, 'VK_MULTIPLY', empty, empty], [1, 92 /* ScanCode.NumpadSubtract */, 'NumpadSubtract', 111 /* KeyCode.NumpadSubtract */, 'NumPad_Subtract', 109, 'VK_SUBTRACT', empty, empty], [1, 93 /* ScanCode.NumpadAdd */, 'NumpadAdd', 109 /* KeyCode.NumpadAdd */, 'NumPad_Add', 107, 'VK_ADD', empty, empty], [1, 94 /* ScanCode.NumpadEnter */, 'NumpadEnter', 3 /* KeyCode.Enter */, empty, 0, empty, empty, empty], [1, 95 /* ScanCode.Numpad1 */, 'Numpad1', 99 /* KeyCode.Numpad1 */, 'NumPad1', 97, 'VK_NUMPAD1', empty, empty], [1, 96 /* ScanCode.Numpad2 */, 'Numpad2', 100 /* KeyCode.Numpad2 */, 'NumPad2', 98, 'VK_NUMPAD2', empty, empty], [1, 97 /* ScanCode.Numpad3 */, 'Numpad3', 101 /* KeyCode.Numpad3 */, 'NumPad3', 99, 'VK_NUMPAD3', empty, empty], [1, 98 /* ScanCode.Numpad4 */, 'Numpad4', 102 /* KeyCode.Numpad4 */, 'NumPad4', 100, 'VK_NUMPAD4', empty, empty], [1, 99 /* ScanCode.Numpad5 */, 'Numpad5', 103 /* KeyCode.Numpad5 */, 'NumPad5', 101, 'VK_NUMPAD5', empty, empty], [1, 100 /* ScanCode.Numpad6 */, 'Numpad6', 104 /* KeyCode.Numpad6 */, 'NumPad6', 102, 'VK_NUMPAD6', empty, empty], [1, 101 /* ScanCode.Numpad7 */, 'Numpad7', 105 /* KeyCode.Numpad7 */, 'NumPad7', 103, 'VK_NUMPAD7', empty, empty], [1, 102 /* ScanCode.Numpad8 */, 'Numpad8', 106 /* KeyCode.Numpad8 */, 'NumPad8', 104, 'VK_NUMPAD8', empty, empty], [1, 103 /* ScanCode.Numpad9 */, 'Numpad9', 107 /* KeyCode.Numpad9 */, 'NumPad9', 105, 'VK_NUMPAD9', empty, empty], [1, 104 /* ScanCode.Numpad0 */, 'Numpad0', 98 /* KeyCode.Numpad0 */, 'NumPad0', 96, 'VK_NUMPAD0', empty, empty], [1, 105 /* ScanCode.NumpadDecimal */, 'NumpadDecimal', 112 /* KeyCode.NumpadDecimal */, 'NumPad_Decimal', 110, 'VK_DECIMAL', empty, empty], [0, 106 /* ScanCode.IntlBackslash */, 'IntlBackslash', 97 /* KeyCode.IntlBackslash */, 'OEM_102', 226, 'VK_OEM_102', empty, empty], [1, 107 /* ScanCode.ContextMenu */, 'ContextMenu', 58 /* KeyCode.ContextMenu */, 'ContextMenu', 93, empty, empty, empty], [1, 108 /* ScanCode.Power */, 'Power', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 109 /* ScanCode.NumpadEqual */, 'NumpadEqual', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 110 /* ScanCode.F13 */, 'F13', 71 /* KeyCode.F13 */, 'F13', 124, 'VK_F13', empty, empty], [1, 111 /* ScanCode.F14 */, 'F14', 72 /* KeyCode.F14 */, 'F14', 125, 'VK_F14', empty, empty], [1, 112 /* ScanCode.F15 */, 'F15', 73 /* KeyCode.F15 */, 'F15', 126, 'VK_F15', empty, empty], [1, 113 /* ScanCode.F16 */, 'F16', 74 /* KeyCode.F16 */, 'F16', 127, 'VK_F16', empty, empty], [1, 114 /* ScanCode.F17 */, 'F17', 75 /* KeyCode.F17 */, 'F17', 128, 'VK_F17', empty, empty], [1, 115 /* ScanCode.F18 */, 'F18', 76 /* KeyCode.F18 */, 'F18', 129, 'VK_F18', empty, empty], [1, 116 /* ScanCode.F19 */, 'F19', 77 /* KeyCode.F19 */, 'F19', 130, 'VK_F19', empty, empty], [1, 117 /* ScanCode.F20 */, 'F20', 78 /* KeyCode.F20 */, 'F20', 131, 'VK_F20', empty, empty], [1, 118 /* ScanCode.F21 */, 'F21', 79 /* KeyCode.F21 */, 'F21', 132, 'VK_F21', empty, empty], [1, 119 /* ScanCode.F22 */, 'F22', 80 /* KeyCode.F22 */, 'F22', 133, 'VK_F22', empty, empty], [1, 120 /* ScanCode.F23 */, 'F23', 81 /* KeyCode.F23 */, 'F23', 134, 'VK_F23', empty, empty], [1, 121 /* ScanCode.F24 */, 'F24', 82 /* KeyCode.F24 */, 'F24', 135, 'VK_F24', empty, empty], [1, 122 /* ScanCode.Open */, 'Open', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 123 /* ScanCode.Help */, 'Help', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 124 /* ScanCode.Select */, 'Select', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 125 /* ScanCode.Again */, 'Again', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 126 /* ScanCode.Undo */, 'Undo', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 127 /* ScanCode.Cut */, 'Cut', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 128 /* ScanCode.Copy */, 'Copy', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 129 /* ScanCode.Paste */, 'Paste', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 130 /* ScanCode.Find */, 'Find', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 131 /* ScanCode.AudioVolumeMute */, 'AudioVolumeMute', 117 /* KeyCode.AudioVolumeMute */, 'AudioVolumeMute', 173, 'VK_VOLUME_MUTE', empty, empty], [1, 132 /* ScanCode.AudioVolumeUp */, 'AudioVolumeUp', 118 /* KeyCode.AudioVolumeUp */, 'AudioVolumeUp', 175, 'VK_VOLUME_UP', empty, empty], [1, 133 /* ScanCode.AudioVolumeDown */, 'AudioVolumeDown', 119 /* KeyCode.AudioVolumeDown */, 'AudioVolumeDown', 174, 'VK_VOLUME_DOWN', empty, empty], [1, 134 /* ScanCode.NumpadComma */, 'NumpadComma', 110 /* KeyCode.NUMPAD_SEPARATOR */, 'NumPad_Separator', 108, 'VK_SEPARATOR', empty, empty], [0, 135 /* ScanCode.IntlRo */, 'IntlRo', 115 /* KeyCode.ABNT_C1 */, 'ABNT_C1', 193, 'VK_ABNT_C1', empty, empty], [1, 136 /* ScanCode.KanaMode */, 'KanaMode', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [0, 137 /* ScanCode.IntlYen */, 'IntlYen', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 138 /* ScanCode.Convert */, 'Convert', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 139 /* ScanCode.NonConvert */, 'NonConvert', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 140 /* ScanCode.Lang1 */, 'Lang1', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 141 /* ScanCode.Lang2 */, 'Lang2', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 142 /* ScanCode.Lang3 */, 'Lang3', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 143 /* ScanCode.Lang4 */, 'Lang4', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 144 /* ScanCode.Lang5 */, 'Lang5', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 145 /* ScanCode.Abort */, 'Abort', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 146 /* ScanCode.Props */, 'Props', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 147 /* ScanCode.NumpadParenLeft */, 'NumpadParenLeft', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 148 /* ScanCode.NumpadParenRight */, 'NumpadParenRight', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 149 /* ScanCode.NumpadBackspace */, 'NumpadBackspace', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 150 /* ScanCode.NumpadMemoryStore */, 'NumpadMemoryStore', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 151 /* ScanCode.NumpadMemoryRecall */, 'NumpadMemoryRecall', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 152 /* ScanCode.NumpadMemoryClear */, 'NumpadMemoryClear', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 153 /* ScanCode.NumpadMemoryAdd */, 'NumpadMemoryAdd', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 154 /* ScanCode.NumpadMemorySubtract */, 'NumpadMemorySubtract', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 155 /* ScanCode.NumpadClear */, 'NumpadClear', 131 /* KeyCode.Clear */, 'Clear', 12, 'VK_CLEAR', empty, empty], [1, 156 /* ScanCode.NumpadClearEntry */, 'NumpadClearEntry', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 0 /* ScanCode.None */, empty, 5 /* KeyCode.Ctrl */, 'Ctrl', 17, 'VK_CONTROL', empty, empty], [1, 0 /* ScanCode.None */, empty, 4 /* KeyCode.Shift */, 'Shift', 16, 'VK_SHIFT', empty, empty], [1, 0 /* ScanCode.None */, empty, 6 /* KeyCode.Alt */, 'Alt', 18, 'VK_MENU', empty, empty], [1, 0 /* ScanCode.None */, empty, 57 /* KeyCode.Meta */, 'Meta', 91, 'VK_COMMAND', empty, empty], [1, 157 /* ScanCode.ControlLeft */, 'ControlLeft', 5 /* KeyCode.Ctrl */, empty, 0, 'VK_LCONTROL', empty, empty], [1, 158 /* ScanCode.ShiftLeft */, 'ShiftLeft', 4 /* KeyCode.Shift */, empty, 0, 'VK_LSHIFT', empty, empty], [1, 159 /* ScanCode.AltLeft */, 'AltLeft', 6 /* KeyCode.Alt */, empty, 0, 'VK_LMENU', empty, empty], [1, 160 /* ScanCode.MetaLeft */, 'MetaLeft', 57 /* KeyCode.Meta */, empty, 0, 'VK_LWIN', empty, empty], [1, 161 /* ScanCode.ControlRight */, 'ControlRight', 5 /* KeyCode.Ctrl */, empty, 0, 'VK_RCONTROL', empty, empty], [1, 162 /* ScanCode.ShiftRight */, 'ShiftRight', 4 /* KeyCode.Shift */, empty, 0, 'VK_RSHIFT', empty, empty], [1, 163 /* ScanCode.AltRight */, 'AltRight', 6 /* KeyCode.Alt */, empty, 0, 'VK_RMENU', empty, empty], [1, 164 /* ScanCode.MetaRight */, 'MetaRight', 57 /* KeyCode.Meta */, empty, 0, 'VK_RWIN', empty, empty], [1, 165 /* ScanCode.BrightnessUp */, 'BrightnessUp', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 166 /* ScanCode.BrightnessDown */, 'BrightnessDown', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 167 /* ScanCode.MediaPlay */, 'MediaPlay', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 168 /* ScanCode.MediaRecord */, 'MediaRecord', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 169 /* ScanCode.MediaFastForward */, 'MediaFastForward', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 170 /* ScanCode.MediaRewind */, 'MediaRewind', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 171 /* ScanCode.MediaTrackNext */, 'MediaTrackNext', 124 /* KeyCode.MediaTrackNext */, 'MediaTrackNext', 176, 'VK_MEDIA_NEXT_TRACK', empty, empty], [1, 172 /* ScanCode.MediaTrackPrevious */, 'MediaTrackPrevious', 125 /* KeyCode.MediaTrackPrevious */, 'MediaTrackPrevious', 177, 'VK_MEDIA_PREV_TRACK', empty, empty], [1, 173 /* ScanCode.MediaStop */, 'MediaStop', 126 /* KeyCode.MediaStop */, 'MediaStop', 178, 'VK_MEDIA_STOP', empty, empty], [1, 174 /* ScanCode.Eject */, 'Eject', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 175 /* ScanCode.MediaPlayPause */, 'MediaPlayPause', 127 /* KeyCode.MediaPlayPause */, 'MediaPlayPause', 179, 'VK_MEDIA_PLAY_PAUSE', empty, empty], [1, 176 /* ScanCode.MediaSelect */, 'MediaSelect', 128 /* KeyCode.LaunchMediaPlayer */, 'LaunchMediaPlayer', 181, 'VK_MEDIA_LAUNCH_MEDIA_SELECT', empty, empty], [1, 177 /* ScanCode.LaunchMail */, 'LaunchMail', 129 /* KeyCode.LaunchMail */, 'LaunchMail', 180, 'VK_MEDIA_LAUNCH_MAIL', empty, empty], [1, 178 /* ScanCode.LaunchApp2 */, 'LaunchApp2', 130 /* KeyCode.LaunchApp2 */, 'LaunchApp2', 183, 'VK_MEDIA_LAUNCH_APP2', empty, empty], [1, 179 /* ScanCode.LaunchApp1 */, 'LaunchApp1', 0 /* KeyCode.Unknown */, empty, 0, 'VK_MEDIA_LAUNCH_APP1', empty, empty], [1, 180 /* ScanCode.SelectTask */, 'SelectTask', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 181 /* ScanCode.LaunchScreenSaver */, 'LaunchScreenSaver', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 182 /* ScanCode.BrowserSearch */, 'BrowserSearch', 120 /* KeyCode.BrowserSearch */, 'BrowserSearch', 170, 'VK_BROWSER_SEARCH', empty, empty], [1, 183 /* ScanCode.BrowserHome */, 'BrowserHome', 121 /* KeyCode.BrowserHome */, 'BrowserHome', 172, 'VK_BROWSER_HOME', empty, empty], [1, 184 /* ScanCode.BrowserBack */, 'BrowserBack', 122 /* KeyCode.BrowserBack */, 'BrowserBack', 166, 'VK_BROWSER_BACK', empty, empty], [1, 185 /* ScanCode.BrowserForward */, 'BrowserForward', 123 /* KeyCode.BrowserForward */, 'BrowserForward', 167, 'VK_BROWSER_FORWARD', empty, empty], [1, 186 /* ScanCode.BrowserStop */, 'BrowserStop', 0 /* KeyCode.Unknown */, empty, 0, 'VK_BROWSER_STOP', empty, empty], [1, 187 /* ScanCode.BrowserRefresh */, 'BrowserRefresh', 0 /* KeyCode.Unknown */, empty, 0, 'VK_BROWSER_REFRESH', empty, empty], [1, 188 /* ScanCode.BrowserFavorites */, 'BrowserFavorites', 0 /* KeyCode.Unknown */, empty, 0, 'VK_BROWSER_FAVORITES', empty, empty], [1, 189 /* ScanCode.ZoomToggle */, 'ZoomToggle', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 190 /* ScanCode.MailReply */, 'MailReply', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 191 /* ScanCode.MailForward */, 'MailForward', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], [1, 192 /* ScanCode.MailSend */, 'MailSend', 0 /* KeyCode.Unknown */, empty, 0, empty, empty, empty], // See https://lists.w3.org/Archives/Public/www-dom/2010JulSep/att-0182/keyCode-spec.html // If an Input Method Editor is processing key input and the event is keydown, return 229. [1, 0 /* ScanCode.None */, empty, 114 /* KeyCode.KEY_IN_COMPOSITION */, 'KeyInComposition', 229, empty, empty, empty], [1, 0 /* ScanCode.None */, empty, 116 /* KeyCode.ABNT_C2 */, 'ABNT_C2', 194, 'VK_ABNT_C2', empty, empty], [1, 0 /* ScanCode.None */, empty, 96 /* KeyCode.OEM_8 */, 'OEM_8', 223, 'VK_OEM_8', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_KANA', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_HANGUL', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_JUNJA', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_FINAL', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_HANJA', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_KANJI', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_CONVERT', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_NONCONVERT', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_ACCEPT', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_MODECHANGE', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_SELECT', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_PRINT', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_EXECUTE', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_SNAPSHOT', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_HELP', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_APPS', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_PROCESSKEY', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_PACKET', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_DBE_SBCSCHAR', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_DBE_DBCSCHAR', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_ATTN', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_CRSEL', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_EXSEL', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_EREOF', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_PLAY', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_ZOOM', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_NONAME', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_PA1', empty, empty], [1, 0 /* ScanCode.None */, empty, 0 /* KeyCode.Unknown */, empty, 0, 'VK_OEM_CLEAR', empty, empty], ]; const seenKeyCode = []; const seenScanCode = []; for (const mapping of mappings) { const [immutable, scanCode, scanCodeStr, keyCode, keyCodeStr, eventKeyCode, vkey, usUserSettingsLabel, generalUserSettingsLabel] = mapping; if (!seenScanCode[scanCode]) { seenScanCode[scanCode] = true; scanCodeStrToInt[scanCodeStr] = scanCode; scanCodeLowerCaseStrToInt[scanCodeStr.toLowerCase()] = scanCode; } if (!seenKeyCode[keyCode]) { seenKeyCode[keyCode] = true; if (!keyCodeStr) { throw new Error(`String representation missing for key code ${keyCode} around scan code ${scanCodeStr}`); } uiMap.define(keyCode, keyCodeStr); userSettingsUSMap.define(keyCode, usUserSettingsLabel || keyCodeStr); userSettingsGeneralMap.define(keyCode, generalUserSettingsLabel || usUserSettingsLabel || keyCodeStr); } if (eventKeyCode) { EVENT_KEY_CODE_MAP[eventKeyCode] = keyCode; } } })(); var KeyCodeUtils; (function (KeyCodeUtils) { function toString(keyCode) { return uiMap.keyCodeToStr(keyCode); } KeyCodeUtils.toString = toString; function fromString(key) { return uiMap.strToKeyCode(key); } KeyCodeUtils.fromString = fromString; function toUserSettingsUS(keyCode) { return userSettingsUSMap.keyCodeToStr(keyCode); } KeyCodeUtils.toUserSettingsUS = toUserSettingsUS; function toUserSettingsGeneral(keyCode) { return userSettingsGeneralMap.keyCodeToStr(keyCode); } KeyCodeUtils.toUserSettingsGeneral = toUserSettingsGeneral; function fromUserSettings(key) { return userSettingsUSMap.strToKeyCode(key) || userSettingsGeneralMap.strToKeyCode(key); } KeyCodeUtils.fromUserSettings = fromUserSettings; function toElectronAccelerator(keyCode) { if (keyCode >= 98 /* KeyCode.Numpad0 */ && keyCode <= 113 /* KeyCode.NumpadDivide */) { // [Electron Accelerators] Electron is able to parse numpad keys, but unfortunately it // renders them just as regular keys in menus. For example, num0 is rendered as "0", // numdiv is rendered as "/", numsub is rendered as "-". // // This can lead to incredible confusion, as it makes numpad based keybindings indistinguishable // from keybindings based on regular keys. // // We therefore need to fall back to custom rendering for numpad keys. return null; } switch (keyCode) { case 16 /* KeyCode.UpArrow */: return 'Up'; case 18 /* KeyCode.DownArrow */: return 'Down'; case 15 /* KeyCode.LeftArrow */: return 'Left'; case 17 /* KeyCode.RightArrow */: return 'Right'; } return uiMap.keyCodeToStr(keyCode); } KeyCodeUtils.toElectronAccelerator = toElectronAccelerator; })(KeyCodeUtils || (KeyCodeUtils = {})); function KeyChord(firstPart, secondPart) { const chordPart = ((secondPart & 0x0000FFFF) << 16) >>> 0; return (firstPart | chordPart) >>> 0; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A selection in the editor. * The selection is a range that has an orientation. */ class Selection extends Range { constructor(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn) { super(selectionStartLineNumber, selectionStartColumn, positionLineNumber, positionColumn); this.selectionStartLineNumber = selectionStartLineNumber; this.selectionStartColumn = selectionStartColumn; this.positionLineNumber = positionLineNumber; this.positionColumn = positionColumn; } /** * Transform to a human-readable representation. */ toString() { return '[' + this.selectionStartLineNumber + ',' + this.selectionStartColumn + ' -> ' + this.positionLineNumber + ',' + this.positionColumn + ']'; } /** * Test if equals other selection. */ equalsSelection(other) { return (Selection.selectionsEqual(this, other)); } /** * Test if the two selections are equal. */ static selectionsEqual(a, b) { return (a.selectionStartLineNumber === b.selectionStartLineNumber && a.selectionStartColumn === b.selectionStartColumn && a.positionLineNumber === b.positionLineNumber && a.positionColumn === b.positionColumn); } /** * Get directions (LTR or RTL). */ getDirection() { if (this.selectionStartLineNumber === this.startLineNumber && this.selectionStartColumn === this.startColumn) { return 0 /* SelectionDirection.LTR */; } return 1 /* SelectionDirection.RTL */; } /** * Create a new selection with a different `positionLineNumber` and `positionColumn`. */ setEndPosition(endLineNumber, endColumn) { if (this.getDirection() === 0 /* SelectionDirection.LTR */) { return new Selection(this.startLineNumber, this.startColumn, endLineNumber, endColumn); } return new Selection(endLineNumber, endColumn, this.startLineNumber, this.startColumn); } /** * Get the position at `positionLineNumber` and `positionColumn`. */ getPosition() { return new Position(this.positionLineNumber, this.positionColumn); } /** * Get the position at the start of the selection. */ getSelectionStart() { return new Position(this.selectionStartLineNumber, this.selectionStartColumn); } /** * Create a new selection with a different `selectionStartLineNumber` and `selectionStartColumn`. */ setStartPosition(startLineNumber, startColumn) { if (this.getDirection() === 0 /* SelectionDirection.LTR */) { return new Selection(startLineNumber, startColumn, this.endLineNumber, this.endColumn); } return new Selection(this.endLineNumber, this.endColumn, startLineNumber, startColumn); } // ---- /** * Create a `Selection` from one or two positions */ static fromPositions(start, end = start) { return new Selection(start.lineNumber, start.column, end.lineNumber, end.column); } /** * Creates a `Selection` from a range, given a direction. */ static fromRange(range, direction) { if (direction === 0 /* SelectionDirection.LTR */) { return new Selection(range.startLineNumber, range.startColumn, range.endLineNumber, range.endColumn); } else { return new Selection(range.endLineNumber, range.endColumn, range.startLineNumber, range.startColumn); } } /** * Create a `Selection` from an `ISelection`. */ static liftSelection(sel) { return new Selection(sel.selectionStartLineNumber, sel.selectionStartColumn, sel.positionLineNumber, sel.positionColumn); } /** * `a` equals `b`. */ static selectionsArrEqual(a, b) { if (a && !b || !a && b) { return false; } if (!a && !b) { return true; } if (a.length !== b.length) { return false; } for (let i = 0, len = a.length; i < len; i++) { if (!this.selectionsEqual(a[i], b[i])) { return false; } } return true; } /** * Test if `obj` is an `ISelection`. */ static isISelection(obj) { return (obj && (typeof obj.selectionStartLineNumber === 'number') && (typeof obj.selectionStartColumn === 'number') && (typeof obj.positionLineNumber === 'number') && (typeof obj.positionColumn === 'number')); } /** * Create with a direction. */ static createWithDirection(startLineNumber, startColumn, endLineNumber, endColumn, direction) { if (direction === 0 /* SelectionDirection.LTR */) { return new Selection(startLineNumber, startColumn, endLineNumber, endColumn); } return new Selection(endLineNumber, endColumn, startLineNumber, startColumn); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * @returns whether the provided parameter is a JavaScript String or not. */ function isString(str) { return (typeof str === 'string'); } const _codiconFontCharacters = Object.create(null); function register(id, fontCharacter) { if (isString(fontCharacter)) { const val = _codiconFontCharacters[fontCharacter]; if (val === undefined) { throw new Error(`${id} references an unknown codicon: ${fontCharacter}`); } fontCharacter = val; } _codiconFontCharacters[id] = fontCharacter; return { id }; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // This file is automatically generated by (microsoft/vscode-codicons)/scripts/export-to-ts.js // Please don't edit it, as your changes will be overwritten. // Instead, add mappings to codiconsDerived in codicons.ts. const codiconsLibrary = { add: register('add', 0xea60), plus: register('plus', 0xea60), gistNew: register('gist-new', 0xea60), repoCreate: register('repo-create', 0xea60), lightbulb: register('lightbulb', 0xea61), lightBulb: register('light-bulb', 0xea61), repo: register('repo', 0xea62), repoDelete: register('repo-delete', 0xea62), gistFork: register('gist-fork', 0xea63), repoForked: register('repo-forked', 0xea63), gitPullRequest: register('git-pull-request', 0xea64), gitPullRequestAbandoned: register('git-pull-request-abandoned', 0xea64), recordKeys: register('record-keys', 0xea65), keyboard: register('keyboard', 0xea65), tag: register('tag', 0xea66), gitPullRequestLabel: register('git-pull-request-label', 0xea66), tagAdd: register('tag-add', 0xea66), tagRemove: register('tag-remove', 0xea66), person: register('person', 0xea67), personFollow: register('person-follow', 0xea67), personOutline: register('person-outline', 0xea67), personFilled: register('person-filled', 0xea67), gitBranch: register('git-branch', 0xea68), gitBranchCreate: register('git-branch-create', 0xea68), gitBranchDelete: register('git-branch-delete', 0xea68), sourceControl: register('source-control', 0xea68), mirror: register('mirror', 0xea69), mirrorPublic: register('mirror-public', 0xea69), star: register('star', 0xea6a), starAdd: register('star-add', 0xea6a), starDelete: register('star-delete', 0xea6a), starEmpty: register('star-empty', 0xea6a), comment: register('comment', 0xea6b), commentAdd: register('comment-add', 0xea6b), alert: register('alert', 0xea6c), warning: register('warning', 0xea6c), search: register('search', 0xea6d), searchSave: register('search-save', 0xea6d), logOut: register('log-out', 0xea6e), signOut: register('sign-out', 0xea6e), logIn: register('log-in', 0xea6f), signIn: register('sign-in', 0xea6f), eye: register('eye', 0xea70), eyeUnwatch: register('eye-unwatch', 0xea70), eyeWatch: register('eye-watch', 0xea70), circleFilled: register('circle-filled', 0xea71), primitiveDot: register('primitive-dot', 0xea71), closeDirty: register('close-dirty', 0xea71), debugBreakpoint: register('debug-breakpoint', 0xea71), debugBreakpointDisabled: register('debug-breakpoint-disabled', 0xea71), debugHint: register('debug-hint', 0xea71), terminalDecorationSuccess: register('terminal-decoration-success', 0xea71), primitiveSquare: register('primitive-square', 0xea72), edit: register('edit', 0xea73), pencil: register('pencil', 0xea73), info: register('info', 0xea74), issueOpened: register('issue-opened', 0xea74), gistPrivate: register('gist-private', 0xea75), gitForkPrivate: register('git-fork-private', 0xea75), lock: register('lock', 0xea75), mirrorPrivate: register('mirror-private', 0xea75), close: register('close', 0xea76), removeClose: register('remove-close', 0xea76), x: register('x', 0xea76), repoSync: register('repo-sync', 0xea77), sync: register('sync', 0xea77), clone: register('clone', 0xea78), desktopDownload: register('desktop-download', 0xea78), beaker: register('beaker', 0xea79), microscope: register('microscope', 0xea79), vm: register('vm', 0xea7a), deviceDesktop: register('device-desktop', 0xea7a), file: register('file', 0xea7b), fileText: register('file-text', 0xea7b), more: register('more', 0xea7c), ellipsis: register('ellipsis', 0xea7c), kebabHorizontal: register('kebab-horizontal', 0xea7c), mailReply: register('mail-reply', 0xea7d), reply: register('reply', 0xea7d), organization: register('organization', 0xea7e), organizationFilled: register('organization-filled', 0xea7e), organizationOutline: register('organization-outline', 0xea7e), newFile: register('new-file', 0xea7f), fileAdd: register('file-add', 0xea7f), newFolder: register('new-folder', 0xea80), fileDirectoryCreate: register('file-directory-create', 0xea80), trash: register('trash', 0xea81), trashcan: register('trashcan', 0xea81), history: register('history', 0xea82), clock: register('clock', 0xea82), folder: register('folder', 0xea83), fileDirectory: register('file-directory', 0xea83), symbolFolder: register('symbol-folder', 0xea83), logoGithub: register('logo-github', 0xea84), markGithub: register('mark-github', 0xea84), github: register('github', 0xea84), terminal: register('terminal', 0xea85), console: register('console', 0xea85), repl: register('repl', 0xea85), zap: register('zap', 0xea86), symbolEvent: register('symbol-event', 0xea86), error: register('error', 0xea87), stop: register('stop', 0xea87), variable: register('variable', 0xea88), symbolVariable: register('symbol-variable', 0xea88), array: register('array', 0xea8a), symbolArray: register('symbol-array', 0xea8a), symbolModule: register('symbol-module', 0xea8b), symbolPackage: register('symbol-package', 0xea8b), symbolNamespace: register('symbol-namespace', 0xea8b), symbolObject: register('symbol-object', 0xea8b), symbolMethod: register('symbol-method', 0xea8c), symbolFunction: register('symbol-function', 0xea8c), symbolConstructor: register('symbol-constructor', 0xea8c), symbolBoolean: register('symbol-boolean', 0xea8f), symbolNull: register('symbol-null', 0xea8f), symbolNumeric: register('symbol-numeric', 0xea90), symbolNumber: register('symbol-number', 0xea90), symbolStructure: register('symbol-structure', 0xea91), symbolStruct: register('symbol-struct', 0xea91), symbolParameter: register('symbol-parameter', 0xea92), symbolTypeParameter: register('symbol-type-parameter', 0xea92), symbolKey: register('symbol-key', 0xea93), symbolText: register('symbol-text', 0xea93), symbolReference: register('symbol-reference', 0xea94), goToFile: register('go-to-file', 0xea94), symbolEnum: register('symbol-enum', 0xea95), symbolValue: register('symbol-value', 0xea95), symbolRuler: register('symbol-ruler', 0xea96), symbolUnit: register('symbol-unit', 0xea96), activateBreakpoints: register('activate-breakpoints', 0xea97), archive: register('archive', 0xea98), arrowBoth: register('arrow-both', 0xea99), arrowDown: register('arrow-down', 0xea9a), arrowLeft: register('arrow-left', 0xea9b), arrowRight: register('arrow-right', 0xea9c), arrowSmallDown: register('arrow-small-down', 0xea9d), arrowSmallLeft: register('arrow-small-left', 0xea9e), arrowSmallRight: register('arrow-small-right', 0xea9f), arrowSmallUp: register('arrow-small-up', 0xeaa0), arrowUp: register('arrow-up', 0xeaa1), bell: register('bell', 0xeaa2), bold: register('bold', 0xeaa3), book: register('book', 0xeaa4), bookmark: register('bookmark', 0xeaa5), debugBreakpointConditionalUnverified: register('debug-breakpoint-conditional-unverified', 0xeaa6), debugBreakpointConditional: register('debug-breakpoint-conditional', 0xeaa7), debugBreakpointConditionalDisabled: register('debug-breakpoint-conditional-disabled', 0xeaa7), debugBreakpointDataUnverified: register('debug-breakpoint-data-unverified', 0xeaa8), debugBreakpointData: register('debug-breakpoint-data', 0xeaa9), debugBreakpointDataDisabled: register('debug-breakpoint-data-disabled', 0xeaa9), debugBreakpointLogUnverified: register('debug-breakpoint-log-unverified', 0xeaaa), debugBreakpointLog: register('debug-breakpoint-log', 0xeaab), debugBreakpointLogDisabled: register('debug-breakpoint-log-disabled', 0xeaab), briefcase: register('briefcase', 0xeaac), broadcast: register('broadcast', 0xeaad), browser: register('browser', 0xeaae), bug: register('bug', 0xeaaf), calendar: register('calendar', 0xeab0), caseSensitive: register('case-sensitive', 0xeab1), check: register('check', 0xeab2), checklist: register('checklist', 0xeab3), chevronDown: register('chevron-down', 0xeab4), chevronLeft: register('chevron-left', 0xeab5), chevronRight: register('chevron-right', 0xeab6), chevronUp: register('chevron-up', 0xeab7), chromeClose: register('chrome-close', 0xeab8), chromeMaximize: register('chrome-maximize', 0xeab9), chromeMinimize: register('chrome-minimize', 0xeaba), chromeRestore: register('chrome-restore', 0xeabb), circleOutline: register('circle-outline', 0xeabc), circle: register('circle', 0xeabc), debugBreakpointUnverified: register('debug-breakpoint-unverified', 0xeabc), terminalDecorationIncomplete: register('terminal-decoration-incomplete', 0xeabc), circleSlash: register('circle-slash', 0xeabd), circuitBoard: register('circuit-board', 0xeabe), clearAll: register('clear-all', 0xeabf), clippy: register('clippy', 0xeac0), closeAll: register('close-all', 0xeac1), cloudDownload: register('cloud-download', 0xeac2), cloudUpload: register('cloud-upload', 0xeac3), code: register('code', 0xeac4), collapseAll: register('collapse-all', 0xeac5), colorMode: register('color-mode', 0xeac6), commentDiscussion: register('comment-discussion', 0xeac7), creditCard: register('credit-card', 0xeac9), dash: register('dash', 0xeacc), dashboard: register('dashboard', 0xeacd), database: register('database', 0xeace), debugContinue: register('debug-continue', 0xeacf), debugDisconnect: register('debug-disconnect', 0xead0), debugPause: register('debug-pause', 0xead1), debugRestart: register('debug-restart', 0xead2), debugStart: register('debug-start', 0xead3), debugStepInto: register('debug-step-into', 0xead4), debugStepOut: register('debug-step-out', 0xead5), debugStepOver: register('debug-step-over', 0xead6), debugStop: register('debug-stop', 0xead7), debug: register('debug', 0xead8), deviceCameraVideo: register('device-camera-video', 0xead9), deviceCamera: register('device-camera', 0xeada), deviceMobile: register('device-mobile', 0xeadb), diffAdded: register('diff-added', 0xeadc), diffIgnored: register('diff-ignored', 0xeadd), diffModified: register('diff-modified', 0xeade), diffRemoved: register('diff-removed', 0xeadf), diffRenamed: register('diff-renamed', 0xeae0), diff: register('diff', 0xeae1), diffSidebyside: register('diff-sidebyside', 0xeae1), discard: register('discard', 0xeae2), editorLayout: register('editor-layout', 0xeae3), emptyWindow: register('empty-window', 0xeae4), exclude: register('exclude', 0xeae5), extensions: register('extensions', 0xeae6), eyeClosed: register('eye-closed', 0xeae7), fileBinary: register('file-binary', 0xeae8), fileCode: register('file-code', 0xeae9), fileMedia: register('file-media', 0xeaea), filePdf: register('file-pdf', 0xeaeb), fileSubmodule: register('file-submodule', 0xeaec), fileSymlinkDirectory: register('file-symlink-directory', 0xeaed), fileSymlinkFile: register('file-symlink-file', 0xeaee), fileZip: register('file-zip', 0xeaef), files: register('files', 0xeaf0), filter: register('filter', 0xeaf1), flame: register('flame', 0xeaf2), foldDown: register('fold-down', 0xeaf3), foldUp: register('fold-up', 0xeaf4), fold: register('fold', 0xeaf5), folderActive: register('folder-active', 0xeaf6), folderOpened: register('folder-opened', 0xeaf7), gear: register('gear', 0xeaf8), gift: register('gift', 0xeaf9), gistSecret: register('gist-secret', 0xeafa), gist: register('gist', 0xeafb), gitCommit: register('git-commit', 0xeafc), gitCompare: register('git-compare', 0xeafd), compareChanges: register('compare-changes', 0xeafd), gitMerge: register('git-merge', 0xeafe), githubAction: register('github-action', 0xeaff), githubAlt: register('github-alt', 0xeb00), globe: register('globe', 0xeb01), grabber: register('grabber', 0xeb02), graph: register('graph', 0xeb03), gripper: register('gripper', 0xeb04), heart: register('heart', 0xeb05), home: register('home', 0xeb06), horizontalRule: register('horizontal-rule', 0xeb07), hubot: register('hubot', 0xeb08), inbox: register('inbox', 0xeb09), issueReopened: register('issue-reopened', 0xeb0b), issues: register('issues', 0xeb0c), italic: register('italic', 0xeb0d), jersey: register('jersey', 0xeb0e), json: register('json', 0xeb0f), kebabVertical: register('kebab-vertical', 0xeb10), key: register('key', 0xeb11), law: register('law', 0xeb12), lightbulbAutofix: register('lightbulb-autofix', 0xeb13), linkExternal: register('link-external', 0xeb14), link: register('link', 0xeb15), listOrdered: register('list-ordered', 0xeb16), listUnordered: register('list-unordered', 0xeb17), liveShare: register('live-share', 0xeb18), loading: register('loading', 0xeb19), location: register('location', 0xeb1a), mailRead: register('mail-read', 0xeb1b), mail: register('mail', 0xeb1c), markdown: register('markdown', 0xeb1d), megaphone: register('megaphone', 0xeb1e), mention: register('mention', 0xeb1f), milestone: register('milestone', 0xeb20), gitPullRequestMilestone: register('git-pull-request-milestone', 0xeb20), mortarBoard: register('mortar-board', 0xeb21), move: register('move', 0xeb22), multipleWindows: register('multiple-windows', 0xeb23), mute: register('mute', 0xeb24), noNewline: register('no-newline', 0xeb25), note: register('note', 0xeb26), octoface: register('octoface', 0xeb27), openPreview: register('open-preview', 0xeb28), package: register('package', 0xeb29), paintcan: register('paintcan', 0xeb2a), pin: register('pin', 0xeb2b), play: register('play', 0xeb2c), run: register('run', 0xeb2c), plug: register('plug', 0xeb2d), preserveCase: register('preserve-case', 0xeb2e), preview: register('preview', 0xeb2f), project: register('project', 0xeb30), pulse: register('pulse', 0xeb31), question: register('question', 0xeb32), quote: register('quote', 0xeb33), radioTower: register('radio-tower', 0xeb34), reactions: register('reactions', 0xeb35), references: register('references', 0xeb36), refresh: register('refresh', 0xeb37), regex: register('regex', 0xeb38), remoteExplorer: register('remote-explorer', 0xeb39), remote: register('remote', 0xeb3a), remove: register('remove', 0xeb3b), replaceAll: register('replace-all', 0xeb3c), replace: register('replace', 0xeb3d), repoClone: register('repo-clone', 0xeb3e), repoForcePush: register('repo-force-push', 0xeb3f), repoPull: register('repo-pull', 0xeb40), repoPush: register('repo-push', 0xeb41), report: register('report', 0xeb42), requestChanges: register('request-changes', 0xeb43), rocket: register('rocket', 0xeb44), rootFolderOpened: register('root-folder-opened', 0xeb45), rootFolder: register('root-folder', 0xeb46), rss: register('rss', 0xeb47), ruby: register('ruby', 0xeb48), saveAll: register('save-all', 0xeb49), saveAs: register('save-as', 0xeb4a), save: register('save', 0xeb4b), screenFull: register('screen-full', 0xeb4c), screenNormal: register('screen-normal', 0xeb4d), searchStop: register('search-stop', 0xeb4e), server: register('server', 0xeb50), settingsGear: register('settings-gear', 0xeb51), settings: register('settings', 0xeb52), shield: register('shield', 0xeb53), smiley: register('smiley', 0xeb54), sortPrecedence: register('sort-precedence', 0xeb55), splitHorizontal: register('split-horizontal', 0xeb56), splitVertical: register('split-vertical', 0xeb57), squirrel: register('squirrel', 0xeb58), starFull: register('star-full', 0xeb59), starHalf: register('star-half', 0xeb5a), symbolClass: register('symbol-class', 0xeb5b), symbolColor: register('symbol-color', 0xeb5c), symbolConstant: register('symbol-constant', 0xeb5d), symbolEnumMember: register('symbol-enum-member', 0xeb5e), symbolField: register('symbol-field', 0xeb5f), symbolFile: register('symbol-file', 0xeb60), symbolInterface: register('symbol-interface', 0xeb61), symbolKeyword: register('symbol-keyword', 0xeb62), symbolMisc: register('symbol-misc', 0xeb63), symbolOperator: register('symbol-operator', 0xeb64), symbolProperty: register('symbol-property', 0xeb65), wrench: register('wrench', 0xeb65), wrenchSubaction: register('wrench-subaction', 0xeb65), symbolSnippet: register('symbol-snippet', 0xeb66), tasklist: register('tasklist', 0xeb67), telescope: register('telescope', 0xeb68), textSize: register('text-size', 0xeb69), threeBars: register('three-bars', 0xeb6a), thumbsdown: register('thumbsdown', 0xeb6b), thumbsup: register('thumbsup', 0xeb6c), tools: register('tools', 0xeb6d), triangleDown: register('triangle-down', 0xeb6e), triangleLeft: register('triangle-left', 0xeb6f), triangleRight: register('triangle-right', 0xeb70), triangleUp: register('triangle-up', 0xeb71), twitter: register('twitter', 0xeb72), unfold: register('unfold', 0xeb73), unlock: register('unlock', 0xeb74), unmute: register('unmute', 0xeb75), unverified: register('unverified', 0xeb76), verified: register('verified', 0xeb77), versions: register('versions', 0xeb78), vmActive: register('vm-active', 0xeb79), vmOutline: register('vm-outline', 0xeb7a), vmRunning: register('vm-running', 0xeb7b), watch: register('watch', 0xeb7c), whitespace: register('whitespace', 0xeb7d), wholeWord: register('whole-word', 0xeb7e), window: register('window', 0xeb7f), wordWrap: register('word-wrap', 0xeb80), zoomIn: register('zoom-in', 0xeb81), zoomOut: register('zoom-out', 0xeb82), listFilter: register('list-filter', 0xeb83), listFlat: register('list-flat', 0xeb84), listSelection: register('list-selection', 0xeb85), selection: register('selection', 0xeb85), listTree: register('list-tree', 0xeb86), debugBreakpointFunctionUnverified: register('debug-breakpoint-function-unverified', 0xeb87), debugBreakpointFunction: register('debug-breakpoint-function', 0xeb88), debugBreakpointFunctionDisabled: register('debug-breakpoint-function-disabled', 0xeb88), debugStackframeActive: register('debug-stackframe-active', 0xeb89), circleSmallFilled: register('circle-small-filled', 0xeb8a), debugStackframeDot: register('debug-stackframe-dot', 0xeb8a), terminalDecorationMark: register('terminal-decoration-mark', 0xeb8a), debugStackframe: register('debug-stackframe', 0xeb8b), debugStackframeFocused: register('debug-stackframe-focused', 0xeb8b), debugBreakpointUnsupported: register('debug-breakpoint-unsupported', 0xeb8c), symbolString: register('symbol-string', 0xeb8d), debugReverseContinue: register('debug-reverse-continue', 0xeb8e), debugStepBack: register('debug-step-back', 0xeb8f), debugRestartFrame: register('debug-restart-frame', 0xeb90), debugAlt: register('debug-alt', 0xeb91), callIncoming: register('call-incoming', 0xeb92), callOutgoing: register('call-outgoing', 0xeb93), menu: register('menu', 0xeb94), expandAll: register('expand-all', 0xeb95), feedback: register('feedback', 0xeb96), gitPullRequestReviewer: register('git-pull-request-reviewer', 0xeb96), groupByRefType: register('group-by-ref-type', 0xeb97), ungroupByRefType: register('ungroup-by-ref-type', 0xeb98), account: register('account', 0xeb99), gitPullRequestAssignee: register('git-pull-request-assignee', 0xeb99), bellDot: register('bell-dot', 0xeb9a), debugConsole: register('debug-console', 0xeb9b), library: register('library', 0xeb9c), output: register('output', 0xeb9d), runAll: register('run-all', 0xeb9e), syncIgnored: register('sync-ignored', 0xeb9f), pinned: register('pinned', 0xeba0), githubInverted: register('github-inverted', 0xeba1), serverProcess: register('server-process', 0xeba2), serverEnvironment: register('server-environment', 0xeba3), pass: register('pass', 0xeba4), issueClosed: register('issue-closed', 0xeba4), stopCircle: register('stop-circle', 0xeba5), playCircle: register('play-circle', 0xeba6), record: register('record', 0xeba7), debugAltSmall: register('debug-alt-small', 0xeba8), vmConnect: register('vm-connect', 0xeba9), cloud: register('cloud', 0xebaa), merge: register('merge', 0xebab), export: register('export', 0xebac), graphLeft: register('graph-left', 0xebad), magnet: register('magnet', 0xebae), notebook: register('notebook', 0xebaf), redo: register('redo', 0xebb0), checkAll: register('check-all', 0xebb1), pinnedDirty: register('pinned-dirty', 0xebb2), passFilled: register('pass-filled', 0xebb3), circleLargeFilled: register('circle-large-filled', 0xebb4), circleLarge: register('circle-large', 0xebb5), circleLargeOutline: register('circle-large-outline', 0xebb5), combine: register('combine', 0xebb6), gather: register('gather', 0xebb6), table: register('table', 0xebb7), variableGroup: register('variable-group', 0xebb8), typeHierarchy: register('type-hierarchy', 0xebb9), typeHierarchySub: register('type-hierarchy-sub', 0xebba), typeHierarchySuper: register('type-hierarchy-super', 0xebbb), gitPullRequestCreate: register('git-pull-request-create', 0xebbc), runAbove: register('run-above', 0xebbd), runBelow: register('run-below', 0xebbe), notebookTemplate: register('notebook-template', 0xebbf), debugRerun: register('debug-rerun', 0xebc0), workspaceTrusted: register('workspace-trusted', 0xebc1), workspaceUntrusted: register('workspace-untrusted', 0xebc2), workspaceUnknown: register('workspace-unknown', 0xebc3), terminalCmd: register('terminal-cmd', 0xebc4), terminalDebian: register('terminal-debian', 0xebc5), terminalLinux: register('terminal-linux', 0xebc6), terminalPowershell: register('terminal-powershell', 0xebc7), terminalTmux: register('terminal-tmux', 0xebc8), terminalUbuntu: register('terminal-ubuntu', 0xebc9), terminalBash: register('terminal-bash', 0xebca), arrowSwap: register('arrow-swap', 0xebcb), copy: register('copy', 0xebcc), personAdd: register('person-add', 0xebcd), filterFilled: register('filter-filled', 0xebce), wand: register('wand', 0xebcf), debugLineByLine: register('debug-line-by-line', 0xebd0), inspect: register('inspect', 0xebd1), layers: register('layers', 0xebd2), layersDot: register('layers-dot', 0xebd3), layersActive: register('layers-active', 0xebd4), compass: register('compass', 0xebd5), compassDot: register('compass-dot', 0xebd6), compassActive: register('compass-active', 0xebd7), azure: register('azure', 0xebd8), issueDraft: register('issue-draft', 0xebd9), gitPullRequestClosed: register('git-pull-request-closed', 0xebda), gitPullRequestDraft: register('git-pull-request-draft', 0xebdb), debugAll: register('debug-all', 0xebdc), debugCoverage: register('debug-coverage', 0xebdd), runErrors: register('run-errors', 0xebde), folderLibrary: register('folder-library', 0xebdf), debugContinueSmall: register('debug-continue-small', 0xebe0), beakerStop: register('beaker-stop', 0xebe1), graphLine: register('graph-line', 0xebe2), graphScatter: register('graph-scatter', 0xebe3), pieChart: register('pie-chart', 0xebe4), bracket: register('bracket', 0xeb0f), bracketDot: register('bracket-dot', 0xebe5), bracketError: register('bracket-error', 0xebe6), lockSmall: register('lock-small', 0xebe7), azureDevops: register('azure-devops', 0xebe8), verifiedFilled: register('verified-filled', 0xebe9), newline: register('newline', 0xebea), layout: register('layout', 0xebeb), layoutActivitybarLeft: register('layout-activitybar-left', 0xebec), layoutActivitybarRight: register('layout-activitybar-right', 0xebed), layoutPanelLeft: register('layout-panel-left', 0xebee), layoutPanelCenter: register('layout-panel-center', 0xebef), layoutPanelJustify: register('layout-panel-justify', 0xebf0), layoutPanelRight: register('layout-panel-right', 0xebf1), layoutPanel: register('layout-panel', 0xebf2), layoutSidebarLeft: register('layout-sidebar-left', 0xebf3), layoutSidebarRight: register('layout-sidebar-right', 0xebf4), layoutStatusbar: register('layout-statusbar', 0xebf5), layoutMenubar: register('layout-menubar', 0xebf6), layoutCentered: register('layout-centered', 0xebf7), target: register('target', 0xebf8), indent: register('indent', 0xebf9), recordSmall: register('record-small', 0xebfa), errorSmall: register('error-small', 0xebfb), terminalDecorationError: register('terminal-decoration-error', 0xebfb), arrowCircleDown: register('arrow-circle-down', 0xebfc), arrowCircleLeft: register('arrow-circle-left', 0xebfd), arrowCircleRight: register('arrow-circle-right', 0xebfe), arrowCircleUp: register('arrow-circle-up', 0xebff), layoutSidebarRightOff: register('layout-sidebar-right-off', 0xec00), layoutPanelOff: register('layout-panel-off', 0xec01), layoutSidebarLeftOff: register('layout-sidebar-left-off', 0xec02), blank: register('blank', 0xec03), heartFilled: register('heart-filled', 0xec04), map: register('map', 0xec05), mapHorizontal: register('map-horizontal', 0xec05), foldHorizontal: register('fold-horizontal', 0xec05), mapFilled: register('map-filled', 0xec06), mapHorizontalFilled: register('map-horizontal-filled', 0xec06), foldHorizontalFilled: register('fold-horizontal-filled', 0xec06), circleSmall: register('circle-small', 0xec07), bellSlash: register('bell-slash', 0xec08), bellSlashDot: register('bell-slash-dot', 0xec09), commentUnresolved: register('comment-unresolved', 0xec0a), gitPullRequestGoToChanges: register('git-pull-request-go-to-changes', 0xec0b), gitPullRequestNewChanges: register('git-pull-request-new-changes', 0xec0c), searchFuzzy: register('search-fuzzy', 0xec0d), commentDraft: register('comment-draft', 0xec0e), send: register('send', 0xec0f), sparkle: register('sparkle', 0xec10), insert: register('insert', 0xec11), mic: register('mic', 0xec12), thumbsdownFilled: register('thumbsdown-filled', 0xec13), thumbsupFilled: register('thumbsup-filled', 0xec14), coffee: register('coffee', 0xec15), snake: register('snake', 0xec16), game: register('game', 0xec17), vr: register('vr', 0xec18), chip: register('chip', 0xec19), piano: register('piano', 0xec1a), music: register('music', 0xec1b), micFilled: register('mic-filled', 0xec1c), repoFetch: register('repo-fetch', 0xec1d), copilot: register('copilot', 0xec1e), lightbulbSparkle: register('lightbulb-sparkle', 0xec1f), robot: register('robot', 0xec20), sparkleFilled: register('sparkle-filled', 0xec21), diffSingle: register('diff-single', 0xec22), diffMultiple: register('diff-multiple', 0xec23), surroundWith: register('surround-with', 0xec24), share: register('share', 0xec25), gitStash: register('git-stash', 0xec26), gitStashApply: register('git-stash-apply', 0xec27), gitStashPop: register('git-stash-pop', 0xec28), vscode: register('vscode', 0xec29), vscodeInsiders: register('vscode-insiders', 0xec2a), codeOss: register('code-oss', 0xec2b), runCoverage: register('run-coverage', 0xec2c), runAllCoverage: register('run-all-coverage', 0xec2d), coverage: register('coverage', 0xec2e), githubProject: register('github-project', 0xec2f), mapVertical: register('map-vertical', 0xec30), foldVertical: register('fold-vertical', 0xec30), mapVerticalFilled: register('map-vertical-filled', 0xec31), foldVerticalFilled: register('fold-vertical-filled', 0xec31), goToSearch: register('go-to-search', 0xec32), percentage: register('percentage', 0xec33), sortPercentage: register('sort-percentage', 0xec33), attach: register('attach', 0xec34), }; /** * Derived icons, that could become separate icons. * These mappings should be moved into the mapping file in the vscode-codicons repo at some point. */ const codiconsDerived = { dialogError: register('dialog-error', 'error'), dialogWarning: register('dialog-warning', 'warning'), dialogInfo: register('dialog-info', 'info'), dialogClose: register('dialog-close', 'close'), treeItemExpanded: register('tree-item-expanded', 'chevron-down'), // collapsed is done with rotation treeFilterOnTypeOn: register('tree-filter-on-type-on', 'list-filter'), treeFilterOnTypeOff: register('tree-filter-on-type-off', 'list-selection'), treeFilterClear: register('tree-filter-clear', 'close'), treeItemLoading: register('tree-item-loading', 'loading'), menuSelection: register('menu-selection', 'check'), menuSubmenu: register('menu-submenu', 'chevron-right'), menuBarMore: register('menubar-more', 'more'), scrollbarButtonLeft: register('scrollbar-button-left', 'triangle-left'), scrollbarButtonRight: register('scrollbar-button-right', 'triangle-right'), scrollbarButtonUp: register('scrollbar-button-up', 'triangle-up'), scrollbarButtonDown: register('scrollbar-button-down', 'triangle-down'), toolBarMore: register('toolbar-more', 'more'), quickInputBack: register('quick-input-back', 'arrow-left'), dropDownButton: register('drop-down-button', 0xeab4), symbolCustomColor: register('symbol-customcolor', 0xeb5c), exportIcon: register('export', 0xebac), workspaceUnspecified: register('workspace-unspecified', 0xebc3), newLine: register('newline', 0xebea), thumbsDownFilled: register('thumbsdown-filled', 0xec13), thumbsUpFilled: register('thumbsup-filled', 0xec14), gitFetch: register('git-fetch', 0xec1d), lightbulbSparkleAutofix: register('lightbulb-sparkle-autofix', 0xec1f), debugBreakpointPending: register('debug-breakpoint-pending', 0xebd9), }; /** * The Codicon library is a set of default icons that are built-in in VS Code. * * In the product (outside of base) Codicons should only be used as defaults. In order to have all icons in VS Code * themeable, component should define new, UI component specific icons using `iconRegistry.registerIcon`. * In that call a Codicon can be named as default. */ const Codicon = { ...codiconsLibrary, ...codiconsDerived }; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class TokenizationRegistry { constructor() { this._tokenizationSupports = new Map(); this._factories = new Map(); this._onDidChange = new Emitter(); this.onDidChange = this._onDidChange.event; this._colorMap = null; } handleChange(languageIds) { this._onDidChange.fire({ changedLanguages: languageIds, changedColorMap: false }); } register(languageId, support) { this._tokenizationSupports.set(languageId, support); this.handleChange([languageId]); return toDisposable(() => { if (this._tokenizationSupports.get(languageId) !== support) { return; } this._tokenizationSupports.delete(languageId); this.handleChange([languageId]); }); } get(languageId) { return this._tokenizationSupports.get(languageId) || null; } registerFactory(languageId, factory) { this._factories.get(languageId)?.dispose(); const myData = new TokenizationSupportFactoryData(this, languageId, factory); this._factories.set(languageId, myData); return toDisposable(() => { const v = this._factories.get(languageId); if (!v || v !== myData) { return; } this._factories.delete(languageId); v.dispose(); }); } async getOrCreate(languageId) { // check first if the support is already set const tokenizationSupport = this.get(languageId); if (tokenizationSupport) { return tokenizationSupport; } const factory = this._factories.get(languageId); if (!factory || factory.isResolved) { // no factory or factory.resolve already finished return null; } await factory.resolve(); return this.get(languageId); } isResolved(languageId) { const tokenizationSupport = this.get(languageId); if (tokenizationSupport) { return true; } const factory = this._factories.get(languageId); if (!factory || factory.isResolved) { return true; } return false; } setColorMap(colorMap) { this._colorMap = colorMap; this._onDidChange.fire({ changedLanguages: Array.from(this._tokenizationSupports.keys()), changedColorMap: true }); } getColorMap() { return this._colorMap; } getDefaultBackground() { if (this._colorMap && this._colorMap.length > 2 /* ColorId.DefaultBackground */) { return this._colorMap[2 /* ColorId.DefaultBackground */]; } return null; } } class TokenizationSupportFactoryData extends Disposable { get isResolved() { return this._isResolved; } constructor(_registry, _languageId, _factory) { super(); this._registry = _registry; this._languageId = _languageId; this._factory = _factory; this._isDisposed = false; this._resolvePromise = null; this._isResolved = false; } dispose() { this._isDisposed = true; super.dispose(); } async resolve() { if (!this._resolvePromise) { this._resolvePromise = this._create(); } return this._resolvePromise; } async _create() { const value = await this._factory.tokenizationSupport; this._isResolved = true; if (value && !this._isDisposed) { this._register(this._registry.register(this._languageId, value)); } } } class Token { constructor(offset, type, language) { this.offset = offset; this.type = type; this.language = language; this._tokenBrand = undefined; } toString() { return '(' + this.offset + ', ' + this.type + ')'; } } var HoverVerbosityAction$1; (function (HoverVerbosityAction) { /** * Increase the verbosity of the hover */ HoverVerbosityAction[HoverVerbosityAction["Increase"] = 0] = "Increase"; /** * Decrease the verbosity of the hover */ HoverVerbosityAction[HoverVerbosityAction["Decrease"] = 1] = "Decrease"; })(HoverVerbosityAction$1 || (HoverVerbosityAction$1 = {})); /** * @internal */ var CompletionItemKinds; (function (CompletionItemKinds) { const byKind = new Map(); byKind.set(0 /* CompletionItemKind.Method */, Codicon.symbolMethod); byKind.set(1 /* CompletionItemKind.Function */, Codicon.symbolFunction); byKind.set(2 /* CompletionItemKind.Constructor */, Codicon.symbolConstructor); byKind.set(3 /* CompletionItemKind.Field */, Codicon.symbolField); byKind.set(4 /* CompletionItemKind.Variable */, Codicon.symbolVariable); byKind.set(5 /* CompletionItemKind.Class */, Codicon.symbolClass); byKind.set(6 /* CompletionItemKind.Struct */, Codicon.symbolStruct); byKind.set(7 /* CompletionItemKind.Interface */, Codicon.symbolInterface); byKind.set(8 /* CompletionItemKind.Module */, Codicon.symbolModule); byKind.set(9 /* CompletionItemKind.Property */, Codicon.symbolProperty); byKind.set(10 /* CompletionItemKind.Event */, Codicon.symbolEvent); byKind.set(11 /* CompletionItemKind.Operator */, Codicon.symbolOperator); byKind.set(12 /* CompletionItemKind.Unit */, Codicon.symbolUnit); byKind.set(13 /* CompletionItemKind.Value */, Codicon.symbolValue); byKind.set(15 /* CompletionItemKind.Enum */, Codicon.symbolEnum); byKind.set(14 /* CompletionItemKind.Constant */, Codicon.symbolConstant); byKind.set(15 /* CompletionItemKind.Enum */, Codicon.symbolEnum); byKind.set(16 /* CompletionItemKind.EnumMember */, Codicon.symbolEnumMember); byKind.set(17 /* CompletionItemKind.Keyword */, Codicon.symbolKeyword); byKind.set(27 /* CompletionItemKind.Snippet */, Codicon.symbolSnippet); byKind.set(18 /* CompletionItemKind.Text */, Codicon.symbolText); byKind.set(19 /* CompletionItemKind.Color */, Codicon.symbolColor); byKind.set(20 /* CompletionItemKind.File */, Codicon.symbolFile); byKind.set(21 /* CompletionItemKind.Reference */, Codicon.symbolReference); byKind.set(22 /* CompletionItemKind.Customcolor */, Codicon.symbolCustomColor); byKind.set(23 /* CompletionItemKind.Folder */, Codicon.symbolFolder); byKind.set(24 /* CompletionItemKind.TypeParameter */, Codicon.symbolTypeParameter); byKind.set(25 /* CompletionItemKind.User */, Codicon.account); byKind.set(26 /* CompletionItemKind.Issue */, Codicon.issues); /** * @internal */ function toIcon(kind) { let codicon = byKind.get(kind); if (!codicon) { console.info('No codicon found for CompletionItemKind ' + kind); codicon = Codicon.symbolProperty; } return codicon; } CompletionItemKinds.toIcon = toIcon; const data = new Map(); data.set('method', 0 /* CompletionItemKind.Method */); data.set('function', 1 /* CompletionItemKind.Function */); data.set('constructor', 2 /* CompletionItemKind.Constructor */); data.set('field', 3 /* CompletionItemKind.Field */); data.set('variable', 4 /* CompletionItemKind.Variable */); data.set('class', 5 /* CompletionItemKind.Class */); data.set('struct', 6 /* CompletionItemKind.Struct */); data.set('interface', 7 /* CompletionItemKind.Interface */); data.set('module', 8 /* CompletionItemKind.Module */); data.set('property', 9 /* CompletionItemKind.Property */); data.set('event', 10 /* CompletionItemKind.Event */); data.set('operator', 11 /* CompletionItemKind.Operator */); data.set('unit', 12 /* CompletionItemKind.Unit */); data.set('value', 13 /* CompletionItemKind.Value */); data.set('constant', 14 /* CompletionItemKind.Constant */); data.set('enum', 15 /* CompletionItemKind.Enum */); data.set('enum-member', 16 /* CompletionItemKind.EnumMember */); data.set('enumMember', 16 /* CompletionItemKind.EnumMember */); data.set('keyword', 17 /* CompletionItemKind.Keyword */); data.set('snippet', 27 /* CompletionItemKind.Snippet */); data.set('text', 18 /* CompletionItemKind.Text */); data.set('color', 19 /* CompletionItemKind.Color */); data.set('file', 20 /* CompletionItemKind.File */); data.set('reference', 21 /* CompletionItemKind.Reference */); data.set('customcolor', 22 /* CompletionItemKind.Customcolor */); data.set('folder', 23 /* CompletionItemKind.Folder */); data.set('type-parameter', 24 /* CompletionItemKind.TypeParameter */); data.set('typeParameter', 24 /* CompletionItemKind.TypeParameter */); data.set('account', 25 /* CompletionItemKind.User */); data.set('issue', 26 /* CompletionItemKind.Issue */); /** * @internal */ function fromString(value, strict) { let res = data.get(value); if (typeof res === 'undefined' && !strict) { res = 9 /* CompletionItemKind.Property */; } return res; } CompletionItemKinds.fromString = fromString; })(CompletionItemKinds || (CompletionItemKinds = {})); /** * How an {@link InlineCompletionsProvider inline completion provider} was triggered. */ var InlineCompletionTriggerKind$1; (function (InlineCompletionTriggerKind) { /** * Completion was triggered automatically while editing. * It is sufficient to return a single completion item in this case. */ InlineCompletionTriggerKind[InlineCompletionTriggerKind["Automatic"] = 0] = "Automatic"; /** * Completion was triggered explicitly by a user gesture. * Return multiple completion items to enable cycling through them. */ InlineCompletionTriggerKind[InlineCompletionTriggerKind["Explicit"] = 1] = "Explicit"; })(InlineCompletionTriggerKind$1 || (InlineCompletionTriggerKind$1 = {})); /** * @internal */ var DocumentPasteTriggerKind; (function (DocumentPasteTriggerKind) { DocumentPasteTriggerKind[DocumentPasteTriggerKind["Automatic"] = 0] = "Automatic"; DocumentPasteTriggerKind[DocumentPasteTriggerKind["PasteAs"] = 1] = "PasteAs"; })(DocumentPasteTriggerKind || (DocumentPasteTriggerKind = {})); var SignatureHelpTriggerKind$1; (function (SignatureHelpTriggerKind) { SignatureHelpTriggerKind[SignatureHelpTriggerKind["Invoke"] = 1] = "Invoke"; SignatureHelpTriggerKind[SignatureHelpTriggerKind["TriggerCharacter"] = 2] = "TriggerCharacter"; SignatureHelpTriggerKind[SignatureHelpTriggerKind["ContentChange"] = 3] = "ContentChange"; })(SignatureHelpTriggerKind$1 || (SignatureHelpTriggerKind$1 = {})); /** * A document highlight kind. */ var DocumentHighlightKind$1; (function (DocumentHighlightKind) { /** * A textual occurrence. */ DocumentHighlightKind[DocumentHighlightKind["Text"] = 0] = "Text"; /** * Read-access of a symbol, like reading a variable. */ DocumentHighlightKind[DocumentHighlightKind["Read"] = 1] = "Read"; /** * Write-access of a symbol, like writing to a variable. */ DocumentHighlightKind[DocumentHighlightKind["Write"] = 2] = "Write"; })(DocumentHighlightKind$1 || (DocumentHighlightKind$1 = {})); /** * @internal */ ({ [17 /* SymbolKind.Array */]: localize('Array', "array"), [16 /* SymbolKind.Boolean */]: localize('Boolean', "boolean"), [4 /* SymbolKind.Class */]: localize('Class', "class"), [13 /* SymbolKind.Constant */]: localize('Constant', "constant"), [8 /* SymbolKind.Constructor */]: localize('Constructor', "constructor"), [9 /* SymbolKind.Enum */]: localize('Enum', "enumeration"), [21 /* SymbolKind.EnumMember */]: localize('EnumMember', "enumeration member"), [23 /* SymbolKind.Event */]: localize('Event', "event"), [7 /* SymbolKind.Field */]: localize('Field', "field"), [0 /* SymbolKind.File */]: localize('File', "file"), [11 /* SymbolKind.Function */]: localize('Function', "function"), [10 /* SymbolKind.Interface */]: localize('Interface', "interface"), [19 /* SymbolKind.Key */]: localize('Key', "key"), [5 /* SymbolKind.Method */]: localize('Method', "method"), [1 /* SymbolKind.Module */]: localize('Module', "module"), [2 /* SymbolKind.Namespace */]: localize('Namespace', "namespace"), [20 /* SymbolKind.Null */]: localize('Null', "null"), [15 /* SymbolKind.Number */]: localize('Number', "number"), [18 /* SymbolKind.Object */]: localize('Object', "object"), [24 /* SymbolKind.Operator */]: localize('Operator', "operator"), [3 /* SymbolKind.Package */]: localize('Package', "package"), [6 /* SymbolKind.Property */]: localize('Property', "property"), [14 /* SymbolKind.String */]: localize('String', "string"), [22 /* SymbolKind.Struct */]: localize('Struct', "struct"), [25 /* SymbolKind.TypeParameter */]: localize('TypeParameter', "type parameter"), [12 /* SymbolKind.Variable */]: localize('Variable', "variable"), }); /** * @internal */ var SymbolKinds; (function (SymbolKinds) { const byKind = new Map(); byKind.set(0 /* SymbolKind.File */, Codicon.symbolFile); byKind.set(1 /* SymbolKind.Module */, Codicon.symbolModule); byKind.set(2 /* SymbolKind.Namespace */, Codicon.symbolNamespace); byKind.set(3 /* SymbolKind.Package */, Codicon.symbolPackage); byKind.set(4 /* SymbolKind.Class */, Codicon.symbolClass); byKind.set(5 /* SymbolKind.Method */, Codicon.symbolMethod); byKind.set(6 /* SymbolKind.Property */, Codicon.symbolProperty); byKind.set(7 /* SymbolKind.Field */, Codicon.symbolField); byKind.set(8 /* SymbolKind.Constructor */, Codicon.symbolConstructor); byKind.set(9 /* SymbolKind.Enum */, Codicon.symbolEnum); byKind.set(10 /* SymbolKind.Interface */, Codicon.symbolInterface); byKind.set(11 /* SymbolKind.Function */, Codicon.symbolFunction); byKind.set(12 /* SymbolKind.Variable */, Codicon.symbolVariable); byKind.set(13 /* SymbolKind.Constant */, Codicon.symbolConstant); byKind.set(14 /* SymbolKind.String */, Codicon.symbolString); byKind.set(15 /* SymbolKind.Number */, Codicon.symbolNumber); byKind.set(16 /* SymbolKind.Boolean */, Codicon.symbolBoolean); byKind.set(17 /* SymbolKind.Array */, Codicon.symbolArray); byKind.set(18 /* SymbolKind.Object */, Codicon.symbolObject); byKind.set(19 /* SymbolKind.Key */, Codicon.symbolKey); byKind.set(20 /* SymbolKind.Null */, Codicon.symbolNull); byKind.set(21 /* SymbolKind.EnumMember */, Codicon.symbolEnumMember); byKind.set(22 /* SymbolKind.Struct */, Codicon.symbolStruct); byKind.set(23 /* SymbolKind.Event */, Codicon.symbolEvent); byKind.set(24 /* SymbolKind.Operator */, Codicon.symbolOperator); byKind.set(25 /* SymbolKind.TypeParameter */, Codicon.symbolTypeParameter); /** * @internal */ function toIcon(kind) { let icon = byKind.get(kind); if (!icon) { console.info('No codicon found for SymbolKind ' + kind); icon = Codicon.symbolProperty; } return icon; } SymbolKinds.toIcon = toIcon; })(SymbolKinds || (SymbolKinds = {})); class FoldingRangeKind { /** * Kind for folding range representing a comment. The value of the kind is 'comment'. */ static { this.Comment = new FoldingRangeKind('comment'); } /** * Kind for folding range representing a import. The value of the kind is 'imports'. */ static { this.Imports = new FoldingRangeKind('imports'); } /** * Kind for folding range representing regions (for example marked by `#region`, `#endregion`). * The value of the kind is 'region'. */ static { this.Region = new FoldingRangeKind('region'); } /** * Returns a {@link FoldingRangeKind} for the given value. * * @param value of the kind. */ static fromValue(value) { switch (value) { case 'comment': return FoldingRangeKind.Comment; case 'imports': return FoldingRangeKind.Imports; case 'region': return FoldingRangeKind.Region; } return new FoldingRangeKind(value); } /** * Creates a new {@link FoldingRangeKind}. * * @param value of the kind. */ constructor(value) { this.value = value; } } var NewSymbolNameTag$1; (function (NewSymbolNameTag) { NewSymbolNameTag[NewSymbolNameTag["AIGenerated"] = 1] = "AIGenerated"; })(NewSymbolNameTag$1 || (NewSymbolNameTag$1 = {})); var NewSymbolNameTriggerKind$1; (function (NewSymbolNameTriggerKind) { NewSymbolNameTriggerKind[NewSymbolNameTriggerKind["Invoke"] = 0] = "Invoke"; NewSymbolNameTriggerKind[NewSymbolNameTriggerKind["Automatic"] = 1] = "Automatic"; })(NewSymbolNameTriggerKind$1 || (NewSymbolNameTriggerKind$1 = {})); /** * @internal */ var Command; (function (Command) { /** * @internal */ function is(obj) { if (!obj || typeof obj !== 'object') { return false; } return typeof obj.id === 'string' && typeof obj.title === 'string'; } Command.is = is; })(Command || (Command = {})); var InlayHintKind$1; (function (InlayHintKind) { InlayHintKind[InlayHintKind["Type"] = 1] = "Type"; InlayHintKind[InlayHintKind["Parameter"] = 2] = "Parameter"; })(InlayHintKind$1 || (InlayHintKind$1 = {})); /** * @internal */ new TokenizationRegistry(); /** * @internal */ new TokenizationRegistry(); var InlineEditTriggerKind$1; (function (InlineEditTriggerKind) { InlineEditTriggerKind[InlineEditTriggerKind["Invoke"] = 0] = "Invoke"; InlineEditTriggerKind[InlineEditTriggerKind["Automatic"] = 1] = "Automatic"; })(InlineEditTriggerKind$1 || (InlineEditTriggerKind$1 = {})); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ // THIS IS A GENERATED FILE. DO NOT EDIT DIRECTLY. var AccessibilitySupport; (function (AccessibilitySupport) { /** * This should be the browser case where it is not known if a screen reader is attached or no. */ AccessibilitySupport[AccessibilitySupport["Unknown"] = 0] = "Unknown"; AccessibilitySupport[AccessibilitySupport["Disabled"] = 1] = "Disabled"; AccessibilitySupport[AccessibilitySupport["Enabled"] = 2] = "Enabled"; })(AccessibilitySupport || (AccessibilitySupport = {})); var CodeActionTriggerType; (function (CodeActionTriggerType) { CodeActionTriggerType[CodeActionTriggerType["Invoke"] = 1] = "Invoke"; CodeActionTriggerType[CodeActionTriggerType["Auto"] = 2] = "Auto"; })(CodeActionTriggerType || (CodeActionTriggerType = {})); var CompletionItemInsertTextRule; (function (CompletionItemInsertTextRule) { CompletionItemInsertTextRule[CompletionItemInsertTextRule["None"] = 0] = "None"; /** * Adjust whitespace/indentation of multiline insert texts to * match the current line indentation. */ CompletionItemInsertTextRule[CompletionItemInsertTextRule["KeepWhitespace"] = 1] = "KeepWhitespace"; /** * `insertText` is a snippet. */ CompletionItemInsertTextRule[CompletionItemInsertTextRule["InsertAsSnippet"] = 4] = "InsertAsSnippet"; })(CompletionItemInsertTextRule || (CompletionItemInsertTextRule = {})); var CompletionItemKind; (function (CompletionItemKind) { CompletionItemKind[CompletionItemKind["Method"] = 0] = "Method"; CompletionItemKind[CompletionItemKind["Function"] = 1] = "Function"; CompletionItemKind[CompletionItemKind["Constructor"] = 2] = "Constructor"; CompletionItemKind[CompletionItemKind["Field"] = 3] = "Field"; CompletionItemKind[CompletionItemKind["Variable"] = 4] = "Variable"; CompletionItemKind[CompletionItemKind["Class"] = 5] = "Class"; CompletionItemKind[CompletionItemKind["Struct"] = 6] = "Struct"; CompletionItemKind[CompletionItemKind["Interface"] = 7] = "Interface"; CompletionItemKind[CompletionItemKind["Module"] = 8] = "Module"; CompletionItemKind[CompletionItemKind["Property"] = 9] = "Property"; CompletionItemKind[CompletionItemKind["Event"] = 10] = "Event"; CompletionItemKind[CompletionItemKind["Operator"] = 11] = "Operator"; CompletionItemKind[CompletionItemKind["Unit"] = 12] = "Unit"; CompletionItemKind[CompletionItemKind["Value"] = 13] = "Value"; CompletionItemKind[CompletionItemKind["Constant"] = 14] = "Constant"; CompletionItemKind[CompletionItemKind["Enum"] = 15] = "Enum"; CompletionItemKind[CompletionItemKind["EnumMember"] = 16] = "EnumMember"; CompletionItemKind[CompletionItemKind["Keyword"] = 17] = "Keyword"; CompletionItemKind[CompletionItemKind["Text"] = 18] = "Text"; CompletionItemKind[CompletionItemKind["Color"] = 19] = "Color"; CompletionItemKind[CompletionItemKind["File"] = 20] = "File"; CompletionItemKind[CompletionItemKind["Reference"] = 21] = "Reference"; CompletionItemKind[CompletionItemKind["Customcolor"] = 22] = "Customcolor"; CompletionItemKind[CompletionItemKind["Folder"] = 23] = "Folder"; CompletionItemKind[CompletionItemKind["TypeParameter"] = 24] = "TypeParameter"; CompletionItemKind[CompletionItemKind["User"] = 25] = "User"; CompletionItemKind[CompletionItemKind["Issue"] = 26] = "Issue"; CompletionItemKind[CompletionItemKind["Snippet"] = 27] = "Snippet"; })(CompletionItemKind || (CompletionItemKind = {})); var CompletionItemTag; (function (CompletionItemTag) { CompletionItemTag[CompletionItemTag["Deprecated"] = 1] = "Deprecated"; })(CompletionItemTag || (CompletionItemTag = {})); /** * How a suggest provider was triggered. */ var CompletionTriggerKind; (function (CompletionTriggerKind) { CompletionTriggerKind[CompletionTriggerKind["Invoke"] = 0] = "Invoke"; CompletionTriggerKind[CompletionTriggerKind["TriggerCharacter"] = 1] = "TriggerCharacter"; CompletionTriggerKind[CompletionTriggerKind["TriggerForIncompleteCompletions"] = 2] = "TriggerForIncompleteCompletions"; })(CompletionTriggerKind || (CompletionTriggerKind = {})); /** * A positioning preference for rendering content widgets. */ var ContentWidgetPositionPreference; (function (ContentWidgetPositionPreference) { /** * Place the content widget exactly at a position */ ContentWidgetPositionPreference[ContentWidgetPositionPreference["EXACT"] = 0] = "EXACT"; /** * Place the content widget above a position */ ContentWidgetPositionPreference[ContentWidgetPositionPreference["ABOVE"] = 1] = "ABOVE"; /** * Place the content widget below a position */ ContentWidgetPositionPreference[ContentWidgetPositionPreference["BELOW"] = 2] = "BELOW"; })(ContentWidgetPositionPreference || (ContentWidgetPositionPreference = {})); /** * Describes the reason the cursor has changed its position. */ var CursorChangeReason; (function (CursorChangeReason) { /** * Unknown or not set. */ CursorChangeReason[CursorChangeReason["NotSet"] = 0] = "NotSet"; /** * A `model.setValue()` was called. */ CursorChangeReason[CursorChangeReason["ContentFlush"] = 1] = "ContentFlush"; /** * The `model` has been changed outside of this cursor and the cursor recovers its position from associated markers. */ CursorChangeReason[CursorChangeReason["RecoverFromMarkers"] = 2] = "RecoverFromMarkers"; /** * There was an explicit user gesture. */ CursorChangeReason[CursorChangeReason["Explicit"] = 3] = "Explicit"; /** * There was a Paste. */ CursorChangeReason[CursorChangeReason["Paste"] = 4] = "Paste"; /** * There was an Undo. */ CursorChangeReason[CursorChangeReason["Undo"] = 5] = "Undo"; /** * There was a Redo. */ CursorChangeReason[CursorChangeReason["Redo"] = 6] = "Redo"; })(CursorChangeReason || (CursorChangeReason = {})); /** * The default end of line to use when instantiating models. */ var DefaultEndOfLine; (function (DefaultEndOfLine) { /** * Use line feed (\n) as the end of line character. */ DefaultEndOfLine[DefaultEndOfLine["LF"] = 1] = "LF"; /** * Use carriage return and line feed (\r\n) as the end of line character. */ DefaultEndOfLine[DefaultEndOfLine["CRLF"] = 2] = "CRLF"; })(DefaultEndOfLine || (DefaultEndOfLine = {})); /** * A document highlight kind. */ var DocumentHighlightKind; (function (DocumentHighlightKind) { /** * A textual occurrence. */ DocumentHighlightKind[DocumentHighlightKind["Text"] = 0] = "Text"; /** * Read-access of a symbol, like reading a variable. */ DocumentHighlightKind[DocumentHighlightKind["Read"] = 1] = "Read"; /** * Write-access of a symbol, like writing to a variable. */ DocumentHighlightKind[DocumentHighlightKind["Write"] = 2] = "Write"; })(DocumentHighlightKind || (DocumentHighlightKind = {})); /** * Configuration options for auto indentation in the editor */ var EditorAutoIndentStrategy; (function (EditorAutoIndentStrategy) { EditorAutoIndentStrategy[EditorAutoIndentStrategy["None"] = 0] = "None"; EditorAutoIndentStrategy[EditorAutoIndentStrategy["Keep"] = 1] = "Keep"; EditorAutoIndentStrategy[EditorAutoIndentStrategy["Brackets"] = 2] = "Brackets"; EditorAutoIndentStrategy[EditorAutoIndentStrategy["Advanced"] = 3] = "Advanced"; EditorAutoIndentStrategy[EditorAutoIndentStrategy["Full"] = 4] = "Full"; })(EditorAutoIndentStrategy || (EditorAutoIndentStrategy = {})); var EditorOption; (function (EditorOption) { EditorOption[EditorOption["acceptSuggestionOnCommitCharacter"] = 0] = "acceptSuggestionOnCommitCharacter"; EditorOption[EditorOption["acceptSuggestionOnEnter"] = 1] = "acceptSuggestionOnEnter"; EditorOption[EditorOption["accessibilitySupport"] = 2] = "accessibilitySupport"; EditorOption[EditorOption["accessibilityPageSize"] = 3] = "accessibilityPageSize"; EditorOption[EditorOption["ariaLabel"] = 4] = "ariaLabel"; EditorOption[EditorOption["ariaRequired"] = 5] = "ariaRequired"; EditorOption[EditorOption["autoClosingBrackets"] = 6] = "autoClosingBrackets"; EditorOption[EditorOption["autoClosingComments"] = 7] = "autoClosingComments"; EditorOption[EditorOption["screenReaderAnnounceInlineSuggestion"] = 8] = "screenReaderAnnounceInlineSuggestion"; EditorOption[EditorOption["autoClosingDelete"] = 9] = "autoClosingDelete"; EditorOption[EditorOption["autoClosingOvertype"] = 10] = "autoClosingOvertype"; EditorOption[EditorOption["autoClosingQuotes"] = 11] = "autoClosingQuotes"; EditorOption[EditorOption["autoIndent"] = 12] = "autoIndent"; EditorOption[EditorOption["automaticLayout"] = 13] = "automaticLayout"; EditorOption[EditorOption["autoSurround"] = 14] = "autoSurround"; EditorOption[EditorOption["bracketPairColorization"] = 15] = "bracketPairColorization"; EditorOption[EditorOption["guides"] = 16] = "guides"; EditorOption[EditorOption["codeLens"] = 17] = "codeLens"; EditorOption[EditorOption["codeLensFontFamily"] = 18] = "codeLensFontFamily"; EditorOption[EditorOption["codeLensFontSize"] = 19] = "codeLensFontSize"; EditorOption[EditorOption["colorDecorators"] = 20] = "colorDecorators"; EditorOption[EditorOption["colorDecoratorsLimit"] = 21] = "colorDecoratorsLimit"; EditorOption[EditorOption["columnSelection"] = 22] = "columnSelection"; EditorOption[EditorOption["comments"] = 23] = "comments"; EditorOption[EditorOption["contextmenu"] = 24] = "contextmenu"; EditorOption[EditorOption["copyWithSyntaxHighlighting"] = 25] = "copyWithSyntaxHighlighting"; EditorOption[EditorOption["cursorBlinking"] = 26] = "cursorBlinking"; EditorOption[EditorOption["cursorSmoothCaretAnimation"] = 27] = "cursorSmoothCaretAnimation"; EditorOption[EditorOption["cursorStyle"] = 28] = "cursorStyle"; EditorOption[EditorOption["cursorSurroundingLines"] = 29] = "cursorSurroundingLines"; EditorOption[EditorOption["cursorSurroundingLinesStyle"] = 30] = "cursorSurroundingLinesStyle"; EditorOption[EditorOption["cursorWidth"] = 31] = "cursorWidth"; EditorOption[EditorOption["disableLayerHinting"] = 32] = "disableLayerHinting"; EditorOption[EditorOption["disableMonospaceOptimizations"] = 33] = "disableMonospaceOptimizations"; EditorOption[EditorOption["domReadOnly"] = 34] = "domReadOnly"; EditorOption[EditorOption["dragAndDrop"] = 35] = "dragAndDrop"; EditorOption[EditorOption["dropIntoEditor"] = 36] = "dropIntoEditor"; EditorOption[EditorOption["emptySelectionClipboard"] = 37] = "emptySelectionClipboard"; EditorOption[EditorOption["experimentalWhitespaceRendering"] = 38] = "experimentalWhitespaceRendering"; EditorOption[EditorOption["extraEditorClassName"] = 39] = "extraEditorClassName"; EditorOption[EditorOption["fastScrollSensitivity"] = 40] = "fastScrollSensitivity"; EditorOption[EditorOption["find"] = 41] = "find"; EditorOption[EditorOption["fixedOverflowWidgets"] = 42] = "fixedOverflowWidgets"; EditorOption[EditorOption["folding"] = 43] = "folding"; EditorOption[EditorOption["foldingStrategy"] = 44] = "foldingStrategy"; EditorOption[EditorOption["foldingHighlight"] = 45] = "foldingHighlight"; EditorOption[EditorOption["foldingImportsByDefault"] = 46] = "foldingImportsByDefault"; EditorOption[EditorOption["foldingMaximumRegions"] = 47] = "foldingMaximumRegions"; EditorOption[EditorOption["unfoldOnClickAfterEndOfLine"] = 48] = "unfoldOnClickAfterEndOfLine"; EditorOption[EditorOption["fontFamily"] = 49] = "fontFamily"; EditorOption[EditorOption["fontInfo"] = 50] = "fontInfo"; EditorOption[EditorOption["fontLigatures"] = 51] = "fontLigatures"; EditorOption[EditorOption["fontSize"] = 52] = "fontSize"; EditorOption[EditorOption["fontWeight"] = 53] = "fontWeight"; EditorOption[EditorOption["fontVariations"] = 54] = "fontVariations"; EditorOption[EditorOption["formatOnPaste"] = 55] = "formatOnPaste"; EditorOption[EditorOption["formatOnType"] = 56] = "formatOnType"; EditorOption[EditorOption["glyphMargin"] = 57] = "glyphMargin"; EditorOption[EditorOption["gotoLocation"] = 58] = "gotoLocation"; EditorOption[EditorOption["hideCursorInOverviewRuler"] = 59] = "hideCursorInOverviewRuler"; EditorOption[EditorOption["hover"] = 60] = "hover"; EditorOption[EditorOption["inDiffEditor"] = 61] = "inDiffEditor"; EditorOption[EditorOption["inlineSuggest"] = 62] = "inlineSuggest"; EditorOption[EditorOption["inlineEdit"] = 63] = "inlineEdit"; EditorOption[EditorOption["letterSpacing"] = 64] = "letterSpacing"; EditorOption[EditorOption["lightbulb"] = 65] = "lightbulb"; EditorOption[EditorOption["lineDecorationsWidth"] = 66] = "lineDecorationsWidth"; EditorOption[EditorOption["lineHeight"] = 67] = "lineHeight"; EditorOption[EditorOption["lineNumbers"] = 68] = "lineNumbers"; EditorOption[EditorOption["lineNumbersMinChars"] = 69] = "lineNumbersMinChars"; EditorOption[EditorOption["linkedEditing"] = 70] = "linkedEditing"; EditorOption[EditorOption["links"] = 71] = "links"; EditorOption[EditorOption["matchBrackets"] = 72] = "matchBrackets"; EditorOption[EditorOption["minimap"] = 73] = "minimap"; EditorOption[EditorOption["mouseStyle"] = 74] = "mouseStyle"; EditorOption[EditorOption["mouseWheelScrollSensitivity"] = 75] = "mouseWheelScrollSensitivity"; EditorOption[EditorOption["mouseWheelZoom"] = 76] = "mouseWheelZoom"; EditorOption[EditorOption["multiCursorMergeOverlapping"] = 77] = "multiCursorMergeOverlapping"; EditorOption[EditorOption["multiCursorModifier"] = 78] = "multiCursorModifier"; EditorOption[EditorOption["multiCursorPaste"] = 79] = "multiCursorPaste"; EditorOption[EditorOption["multiCursorLimit"] = 80] = "multiCursorLimit"; EditorOption[EditorOption["occurrencesHighlight"] = 81] = "occurrencesHighlight"; EditorOption[EditorOption["overviewRulerBorder"] = 82] = "overviewRulerBorder"; EditorOption[EditorOption["overviewRulerLanes"] = 83] = "overviewRulerLanes"; EditorOption[EditorOption["padding"] = 84] = "padding"; EditorOption[EditorOption["pasteAs"] = 85] = "pasteAs"; EditorOption[EditorOption["parameterHints"] = 86] = "parameterHints"; EditorOption[EditorOption["peekWidgetDefaultFocus"] = 87] = "peekWidgetDefaultFocus"; EditorOption[EditorOption["placeholder"] = 88] = "placeholder"; EditorOption[EditorOption["definitionLinkOpensInPeek"] = 89] = "definitionLinkOpensInPeek"; EditorOption[EditorOption["quickSuggestions"] = 90] = "quickSuggestions"; EditorOption[EditorOption["quickSuggestionsDelay"] = 91] = "quickSuggestionsDelay"; EditorOption[EditorOption["readOnly"] = 92] = "readOnly"; EditorOption[EditorOption["readOnlyMessage"] = 93] = "readOnlyMessage"; EditorOption[EditorOption["renameOnType"] = 94] = "renameOnType"; EditorOption[EditorOption["renderControlCharacters"] = 95] = "renderControlCharacters"; EditorOption[EditorOption["renderFinalNewline"] = 96] = "renderFinalNewline"; EditorOption[EditorOption["renderLineHighlight"] = 97] = "renderLineHighlight"; EditorOption[EditorOption["renderLineHighlightOnlyWhenFocus"] = 98] = "renderLineHighlightOnlyWhenFocus"; EditorOption[EditorOption["renderValidationDecorations"] = 99] = "renderValidationDecorations"; EditorOption[EditorOption["renderWhitespace"] = 100] = "renderWhitespace"; EditorOption[EditorOption["revealHorizontalRightPadding"] = 101] = "revealHorizontalRightPadding"; EditorOption[EditorOption["roundedSelection"] = 102] = "roundedSelection"; EditorOption[EditorOption["rulers"] = 103] = "rulers"; EditorOption[EditorOption["scrollbar"] = 104] = "scrollbar"; EditorOption[EditorOption["scrollBeyondLastColumn"] = 105] = "scrollBeyondLastColumn"; EditorOption[EditorOption["scrollBeyondLastLine"] = 106] = "scrollBeyondLastLine"; EditorOption[EditorOption["scrollPredominantAxis"] = 107] = "scrollPredominantAxis"; EditorOption[EditorOption["selectionClipboard"] = 108] = "selectionClipboard"; EditorOption[EditorOption["selectionHighlight"] = 109] = "selectionHighlight"; EditorOption[EditorOption["selectOnLineNumbers"] = 110] = "selectOnLineNumbers"; EditorOption[EditorOption["showFoldingControls"] = 111] = "showFoldingControls"; EditorOption[EditorOption["showUnused"] = 112] = "showUnused"; EditorOption[EditorOption["snippetSuggestions"] = 113] = "snippetSuggestions"; EditorOption[EditorOption["smartSelect"] = 114] = "smartSelect"; EditorOption[EditorOption["smoothScrolling"] = 115] = "smoothScrolling"; EditorOption[EditorOption["stickyScroll"] = 116] = "stickyScroll"; EditorOption[EditorOption["stickyTabStops"] = 117] = "stickyTabStops"; EditorOption[EditorOption["stopRenderingLineAfter"] = 118] = "stopRenderingLineAfter"; EditorOption[EditorOption["suggest"] = 119] = "suggest"; EditorOption[EditorOption["suggestFontSize"] = 120] = "suggestFontSize"; EditorOption[EditorOption["suggestLineHeight"] = 121] = "suggestLineHeight"; EditorOption[EditorOption["suggestOnTriggerCharacters"] = 122] = "suggestOnTriggerCharacters"; EditorOption[EditorOption["suggestSelection"] = 123] = "suggestSelection"; EditorOption[EditorOption["tabCompletion"] = 124] = "tabCompletion"; EditorOption[EditorOption["tabIndex"] = 125] = "tabIndex"; EditorOption[EditorOption["unicodeHighlighting"] = 126] = "unicodeHighlighting"; EditorOption[EditorOption["unusualLineTerminators"] = 127] = "unusualLineTerminators"; EditorOption[EditorOption["useShadowDOM"] = 128] = "useShadowDOM"; EditorOption[EditorOption["useTabStops"] = 129] = "useTabStops"; EditorOption[EditorOption["wordBreak"] = 130] = "wordBreak"; EditorOption[EditorOption["wordSegmenterLocales"] = 131] = "wordSegmenterLocales"; EditorOption[EditorOption["wordSeparators"] = 132] = "wordSeparators"; EditorOption[EditorOption["wordWrap"] = 133] = "wordWrap"; EditorOption[EditorOption["wordWrapBreakAfterCharacters"] = 134] = "wordWrapBreakAfterCharacters"; EditorOption[EditorOption["wordWrapBreakBeforeCharacters"] = 135] = "wordWrapBreakBeforeCharacters"; EditorOption[EditorOption["wordWrapColumn"] = 136] = "wordWrapColumn"; EditorOption[EditorOption["wordWrapOverride1"] = 137] = "wordWrapOverride1"; EditorOption[EditorOption["wordWrapOverride2"] = 138] = "wordWrapOverride2"; EditorOption[EditorOption["wrappingIndent"] = 139] = "wrappingIndent"; EditorOption[EditorOption["wrappingStrategy"] = 140] = "wrappingStrategy"; EditorOption[EditorOption["showDeprecated"] = 141] = "showDeprecated"; EditorOption[EditorOption["inlayHints"] = 142] = "inlayHints"; EditorOption[EditorOption["editorClassName"] = 143] = "editorClassName"; EditorOption[EditorOption["pixelRatio"] = 144] = "pixelRatio"; EditorOption[EditorOption["tabFocusMode"] = 145] = "tabFocusMode"; EditorOption[EditorOption["layoutInfo"] = 146] = "layoutInfo"; EditorOption[EditorOption["wrappingInfo"] = 147] = "wrappingInfo"; EditorOption[EditorOption["defaultColorDecorators"] = 148] = "defaultColorDecorators"; EditorOption[EditorOption["colorDecoratorsActivatedOn"] = 149] = "colorDecoratorsActivatedOn"; EditorOption[EditorOption["inlineCompletionsAccessibilityVerbose"] = 150] = "inlineCompletionsAccessibilityVerbose"; })(EditorOption || (EditorOption = {})); /** * End of line character preference. */ var EndOfLinePreference; (function (EndOfLinePreference) { /** * Use the end of line character identified in the text buffer. */ EndOfLinePreference[EndOfLinePreference["TextDefined"] = 0] = "TextDefined"; /** * Use line feed (\n) as the end of line character. */ EndOfLinePreference[EndOfLinePreference["LF"] = 1] = "LF"; /** * Use carriage return and line feed (\r\n) as the end of line character. */ EndOfLinePreference[EndOfLinePreference["CRLF"] = 2] = "CRLF"; })(EndOfLinePreference || (EndOfLinePreference = {})); /** * End of line character preference. */ var EndOfLineSequence; (function (EndOfLineSequence) { /** * Use line feed (\n) as the end of line character. */ EndOfLineSequence[EndOfLineSequence["LF"] = 0] = "LF"; /** * Use carriage return and line feed (\r\n) as the end of line character. */ EndOfLineSequence[EndOfLineSequence["CRLF"] = 1] = "CRLF"; })(EndOfLineSequence || (EndOfLineSequence = {})); /** * Vertical Lane in the glyph margin of the editor. */ var GlyphMarginLane$1; (function (GlyphMarginLane) { GlyphMarginLane[GlyphMarginLane["Left"] = 1] = "Left"; GlyphMarginLane[GlyphMarginLane["Center"] = 2] = "Center"; GlyphMarginLane[GlyphMarginLane["Right"] = 3] = "Right"; })(GlyphMarginLane$1 || (GlyphMarginLane$1 = {})); var HoverVerbosityAction; (function (HoverVerbosityAction) { /** * Increase the verbosity of the hover */ HoverVerbosityAction[HoverVerbosityAction["Increase"] = 0] = "Increase"; /** * Decrease the verbosity of the hover */ HoverVerbosityAction[HoverVerbosityAction["Decrease"] = 1] = "Decrease"; })(HoverVerbosityAction || (HoverVerbosityAction = {})); /** * Describes what to do with the indentation when pressing Enter. */ var IndentAction; (function (IndentAction) { /** * Insert new line and copy the previous line's indentation. */ IndentAction[IndentAction["None"] = 0] = "None"; /** * Insert new line and indent once (relative to the previous line's indentation). */ IndentAction[IndentAction["Indent"] = 1] = "Indent"; /** * Insert two new lines: * - the first one indented which will hold the cursor * - the second one at the same indentation level */ IndentAction[IndentAction["IndentOutdent"] = 2] = "IndentOutdent"; /** * Insert new line and outdent once (relative to the previous line's indentation). */ IndentAction[IndentAction["Outdent"] = 3] = "Outdent"; })(IndentAction || (IndentAction = {})); var InjectedTextCursorStops$1; (function (InjectedTextCursorStops) { InjectedTextCursorStops[InjectedTextCursorStops["Both"] = 0] = "Both"; InjectedTextCursorStops[InjectedTextCursorStops["Right"] = 1] = "Right"; InjectedTextCursorStops[InjectedTextCursorStops["Left"] = 2] = "Left"; InjectedTextCursorStops[InjectedTextCursorStops["None"] = 3] = "None"; })(InjectedTextCursorStops$1 || (InjectedTextCursorStops$1 = {})); var InlayHintKind; (function (InlayHintKind) { InlayHintKind[InlayHintKind["Type"] = 1] = "Type"; InlayHintKind[InlayHintKind["Parameter"] = 2] = "Parameter"; })(InlayHintKind || (InlayHintKind = {})); /** * How an {@link InlineCompletionsProvider inline completion provider} was triggered. */ var InlineCompletionTriggerKind; (function (InlineCompletionTriggerKind) { /** * Completion was triggered automatically while editing. * It is sufficient to return a single completion item in this case. */ InlineCompletionTriggerKind[InlineCompletionTriggerKind["Automatic"] = 0] = "Automatic"; /** * Completion was triggered explicitly by a user gesture. * Return multiple completion items to enable cycling through them. */ InlineCompletionTriggerKind[InlineCompletionTriggerKind["Explicit"] = 1] = "Explicit"; })(InlineCompletionTriggerKind || (InlineCompletionTriggerKind = {})); var InlineEditTriggerKind; (function (InlineEditTriggerKind) { InlineEditTriggerKind[InlineEditTriggerKind["Invoke"] = 0] = "Invoke"; InlineEditTriggerKind[InlineEditTriggerKind["Automatic"] = 1] = "Automatic"; })(InlineEditTriggerKind || (InlineEditTriggerKind = {})); /** * Virtual Key Codes, the value does not hold any inherent meaning. * Inspired somewhat from https://msdn.microsoft.com/en-us/library/windows/desktop/dd375731(v=vs.85).aspx * But these are "more general", as they should work across browsers & OS`s. */ var KeyCode; (function (KeyCode) { KeyCode[KeyCode["DependsOnKbLayout"] = -1] = "DependsOnKbLayout"; /** * Placed first to cover the 0 value of the enum. */ KeyCode[KeyCode["Unknown"] = 0] = "Unknown"; KeyCode[KeyCode["Backspace"] = 1] = "Backspace"; KeyCode[KeyCode["Tab"] = 2] = "Tab"; KeyCode[KeyCode["Enter"] = 3] = "Enter"; KeyCode[KeyCode["Shift"] = 4] = "Shift"; KeyCode[KeyCode["Ctrl"] = 5] = "Ctrl"; KeyCode[KeyCode["Alt"] = 6] = "Alt"; KeyCode[KeyCode["PauseBreak"] = 7] = "PauseBreak"; KeyCode[KeyCode["CapsLock"] = 8] = "CapsLock"; KeyCode[KeyCode["Escape"] = 9] = "Escape"; KeyCode[KeyCode["Space"] = 10] = "Space"; KeyCode[KeyCode["PageUp"] = 11] = "PageUp"; KeyCode[KeyCode["PageDown"] = 12] = "PageDown"; KeyCode[KeyCode["End"] = 13] = "End"; KeyCode[KeyCode["Home"] = 14] = "Home"; KeyCode[KeyCode["LeftArrow"] = 15] = "LeftArrow"; KeyCode[KeyCode["UpArrow"] = 16] = "UpArrow"; KeyCode[KeyCode["RightArrow"] = 17] = "RightArrow"; KeyCode[KeyCode["DownArrow"] = 18] = "DownArrow"; KeyCode[KeyCode["Insert"] = 19] = "Insert"; KeyCode[KeyCode["Delete"] = 20] = "Delete"; KeyCode[KeyCode["Digit0"] = 21] = "Digit0"; KeyCode[KeyCode["Digit1"] = 22] = "Digit1"; KeyCode[KeyCode["Digit2"] = 23] = "Digit2"; KeyCode[KeyCode["Digit3"] = 24] = "Digit3"; KeyCode[KeyCode["Digit4"] = 25] = "Digit4"; KeyCode[KeyCode["Digit5"] = 26] = "Digit5"; KeyCode[KeyCode["Digit6"] = 27] = "Digit6"; KeyCode[KeyCode["Digit7"] = 28] = "Digit7"; KeyCode[KeyCode["Digit8"] = 29] = "Digit8"; KeyCode[KeyCode["Digit9"] = 30] = "Digit9"; KeyCode[KeyCode["KeyA"] = 31] = "KeyA"; KeyCode[KeyCode["KeyB"] = 32] = "KeyB"; KeyCode[KeyCode["KeyC"] = 33] = "KeyC"; KeyCode[KeyCode["KeyD"] = 34] = "KeyD"; KeyCode[KeyCode["KeyE"] = 35] = "KeyE"; KeyCode[KeyCode["KeyF"] = 36] = "KeyF"; KeyCode[KeyCode["KeyG"] = 37] = "KeyG"; KeyCode[KeyCode["KeyH"] = 38] = "KeyH"; KeyCode[KeyCode["KeyI"] = 39] = "KeyI"; KeyCode[KeyCode["KeyJ"] = 40] = "KeyJ"; KeyCode[KeyCode["KeyK"] = 41] = "KeyK"; KeyCode[KeyCode["KeyL"] = 42] = "KeyL"; KeyCode[KeyCode["KeyM"] = 43] = "KeyM"; KeyCode[KeyCode["KeyN"] = 44] = "KeyN"; KeyCode[KeyCode["KeyO"] = 45] = "KeyO"; KeyCode[KeyCode["KeyP"] = 46] = "KeyP"; KeyCode[KeyCode["KeyQ"] = 47] = "KeyQ"; KeyCode[KeyCode["KeyR"] = 48] = "KeyR"; KeyCode[KeyCode["KeyS"] = 49] = "KeyS"; KeyCode[KeyCode["KeyT"] = 50] = "KeyT"; KeyCode[KeyCode["KeyU"] = 51] = "KeyU"; KeyCode[KeyCode["KeyV"] = 52] = "KeyV"; KeyCode[KeyCode["KeyW"] = 53] = "KeyW"; KeyCode[KeyCode["KeyX"] = 54] = "KeyX"; KeyCode[KeyCode["KeyY"] = 55] = "KeyY"; KeyCode[KeyCode["KeyZ"] = 56] = "KeyZ"; KeyCode[KeyCode["Meta"] = 57] = "Meta"; KeyCode[KeyCode["ContextMenu"] = 58] = "ContextMenu"; KeyCode[KeyCode["F1"] = 59] = "F1"; KeyCode[KeyCode["F2"] = 60] = "F2"; KeyCode[KeyCode["F3"] = 61] = "F3"; KeyCode[KeyCode["F4"] = 62] = "F4"; KeyCode[KeyCode["F5"] = 63] = "F5"; KeyCode[KeyCode["F6"] = 64] = "F6"; KeyCode[KeyCode["F7"] = 65] = "F7"; KeyCode[KeyCode["F8"] = 66] = "F8"; KeyCode[KeyCode["F9"] = 67] = "F9"; KeyCode[KeyCode["F10"] = 68] = "F10"; KeyCode[KeyCode["F11"] = 69] = "F11"; KeyCode[KeyCode["F12"] = 70] = "F12"; KeyCode[KeyCode["F13"] = 71] = "F13"; KeyCode[KeyCode["F14"] = 72] = "F14"; KeyCode[KeyCode["F15"] = 73] = "F15"; KeyCode[KeyCode["F16"] = 74] = "F16"; KeyCode[KeyCode["F17"] = 75] = "F17"; KeyCode[KeyCode["F18"] = 76] = "F18"; KeyCode[KeyCode["F19"] = 77] = "F19"; KeyCode[KeyCode["F20"] = 78] = "F20"; KeyCode[KeyCode["F21"] = 79] = "F21"; KeyCode[KeyCode["F22"] = 80] = "F22"; KeyCode[KeyCode["F23"] = 81] = "F23"; KeyCode[KeyCode["F24"] = 82] = "F24"; KeyCode[KeyCode["NumLock"] = 83] = "NumLock"; KeyCode[KeyCode["ScrollLock"] = 84] = "ScrollLock"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the ';:' key */ KeyCode[KeyCode["Semicolon"] = 85] = "Semicolon"; /** * For any country/region, the '+' key * For the US standard keyboard, the '=+' key */ KeyCode[KeyCode["Equal"] = 86] = "Equal"; /** * For any country/region, the ',' key * For the US standard keyboard, the ',<' key */ KeyCode[KeyCode["Comma"] = 87] = "Comma"; /** * For any country/region, the '-' key * For the US standard keyboard, the '-_' key */ KeyCode[KeyCode["Minus"] = 88] = "Minus"; /** * For any country/region, the '.' key * For the US standard keyboard, the '.>' key */ KeyCode[KeyCode["Period"] = 89] = "Period"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '/?' key */ KeyCode[KeyCode["Slash"] = 90] = "Slash"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '`~' key */ KeyCode[KeyCode["Backquote"] = 91] = "Backquote"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '[{' key */ KeyCode[KeyCode["BracketLeft"] = 92] = "BracketLeft"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the '\|' key */ KeyCode[KeyCode["Backslash"] = 93] = "Backslash"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the ']}' key */ KeyCode[KeyCode["BracketRight"] = 94] = "BracketRight"; /** * Used for miscellaneous characters; it can vary by keyboard. * For the US standard keyboard, the ''"' key */ KeyCode[KeyCode["Quote"] = 95] = "Quote"; /** * Used for miscellaneous characters; it can vary by keyboard. */ KeyCode[KeyCode["OEM_8"] = 96] = "OEM_8"; /** * Either the angle bracket key or the backslash key on the RT 102-key keyboard. */ KeyCode[KeyCode["IntlBackslash"] = 97] = "IntlBackslash"; KeyCode[KeyCode["Numpad0"] = 98] = "Numpad0"; KeyCode[KeyCode["Numpad1"] = 99] = "Numpad1"; KeyCode[KeyCode["Numpad2"] = 100] = "Numpad2"; KeyCode[KeyCode["Numpad3"] = 101] = "Numpad3"; KeyCode[KeyCode["Numpad4"] = 102] = "Numpad4"; KeyCode[KeyCode["Numpad5"] = 103] = "Numpad5"; KeyCode[KeyCode["Numpad6"] = 104] = "Numpad6"; KeyCode[KeyCode["Numpad7"] = 105] = "Numpad7"; KeyCode[KeyCode["Numpad8"] = 106] = "Numpad8"; KeyCode[KeyCode["Numpad9"] = 107] = "Numpad9"; KeyCode[KeyCode["NumpadMultiply"] = 108] = "NumpadMultiply"; KeyCode[KeyCode["NumpadAdd"] = 109] = "NumpadAdd"; KeyCode[KeyCode["NUMPAD_SEPARATOR"] = 110] = "NUMPAD_SEPARATOR"; KeyCode[KeyCode["NumpadSubtract"] = 111] = "NumpadSubtract"; KeyCode[KeyCode["NumpadDecimal"] = 112] = "NumpadDecimal"; KeyCode[KeyCode["NumpadDivide"] = 113] = "NumpadDivide"; /** * Cover all key codes when IME is processing input. */ KeyCode[KeyCode["KEY_IN_COMPOSITION"] = 114] = "KEY_IN_COMPOSITION"; KeyCode[KeyCode["ABNT_C1"] = 115] = "ABNT_C1"; KeyCode[KeyCode["ABNT_C2"] = 116] = "ABNT_C2"; KeyCode[KeyCode["AudioVolumeMute"] = 117] = "AudioVolumeMute"; KeyCode[KeyCode["AudioVolumeUp"] = 118] = "AudioVolumeUp"; KeyCode[KeyCode["AudioVolumeDown"] = 119] = "AudioVolumeDown"; KeyCode[KeyCode["BrowserSearch"] = 120] = "BrowserSearch"; KeyCode[KeyCode["BrowserHome"] = 121] = "BrowserHome"; KeyCode[KeyCode["BrowserBack"] = 122] = "BrowserBack"; KeyCode[KeyCode["BrowserForward"] = 123] = "BrowserForward"; KeyCode[KeyCode["MediaTrackNext"] = 124] = "MediaTrackNext"; KeyCode[KeyCode["MediaTrackPrevious"] = 125] = "MediaTrackPrevious"; KeyCode[KeyCode["MediaStop"] = 126] = "MediaStop"; KeyCode[KeyCode["MediaPlayPause"] = 127] = "MediaPlayPause"; KeyCode[KeyCode["LaunchMediaPlayer"] = 128] = "LaunchMediaPlayer"; KeyCode[KeyCode["LaunchMail"] = 129] = "LaunchMail"; KeyCode[KeyCode["LaunchApp2"] = 130] = "LaunchApp2"; /** * VK_CLEAR, 0x0C, CLEAR key */ KeyCode[KeyCode["Clear"] = 131] = "Clear"; /** * Placed last to cover the length of the enum. * Please do not depend on this value! */ KeyCode[KeyCode["MAX_VALUE"] = 132] = "MAX_VALUE"; })(KeyCode || (KeyCode = {})); var MarkerSeverity; (function (MarkerSeverity) { MarkerSeverity[MarkerSeverity["Hint"] = 1] = "Hint"; MarkerSeverity[MarkerSeverity["Info"] = 2] = "Info"; MarkerSeverity[MarkerSeverity["Warning"] = 4] = "Warning"; MarkerSeverity[MarkerSeverity["Error"] = 8] = "Error"; })(MarkerSeverity || (MarkerSeverity = {})); var MarkerTag; (function (MarkerTag) { MarkerTag[MarkerTag["Unnecessary"] = 1] = "Unnecessary"; MarkerTag[MarkerTag["Deprecated"] = 2] = "Deprecated"; })(MarkerTag || (MarkerTag = {})); /** * Position in the minimap to render the decoration. */ var MinimapPosition; (function (MinimapPosition) { MinimapPosition[MinimapPosition["Inline"] = 1] = "Inline"; MinimapPosition[MinimapPosition["Gutter"] = 2] = "Gutter"; })(MinimapPosition || (MinimapPosition = {})); /** * Section header style. */ var MinimapSectionHeaderStyle; (function (MinimapSectionHeaderStyle) { MinimapSectionHeaderStyle[MinimapSectionHeaderStyle["Normal"] = 1] = "Normal"; MinimapSectionHeaderStyle[MinimapSectionHeaderStyle["Underlined"] = 2] = "Underlined"; })(MinimapSectionHeaderStyle || (MinimapSectionHeaderStyle = {})); /** * Type of hit element with the mouse in the editor. */ var MouseTargetType; (function (MouseTargetType) { /** * Mouse is on top of an unknown element. */ MouseTargetType[MouseTargetType["UNKNOWN"] = 0] = "UNKNOWN"; /** * Mouse is on top of the textarea used for input. */ MouseTargetType[MouseTargetType["TEXTAREA"] = 1] = "TEXTAREA"; /** * Mouse is on top of the glyph margin */ MouseTargetType[MouseTargetType["GUTTER_GLYPH_MARGIN"] = 2] = "GUTTER_GLYPH_MARGIN"; /** * Mouse is on top of the line numbers */ MouseTargetType[MouseTargetType["GUTTER_LINE_NUMBERS"] = 3] = "GUTTER_LINE_NUMBERS"; /** * Mouse is on top of the line decorations */ MouseTargetType[MouseTargetType["GUTTER_LINE_DECORATIONS"] = 4] = "GUTTER_LINE_DECORATIONS"; /** * Mouse is on top of the whitespace left in the gutter by a view zone. */ MouseTargetType[MouseTargetType["GUTTER_VIEW_ZONE"] = 5] = "GUTTER_VIEW_ZONE"; /** * Mouse is on top of text in the content. */ MouseTargetType[MouseTargetType["CONTENT_TEXT"] = 6] = "CONTENT_TEXT"; /** * Mouse is on top of empty space in the content (e.g. after line text or below last line) */ MouseTargetType[MouseTargetType["CONTENT_EMPTY"] = 7] = "CONTENT_EMPTY"; /** * Mouse is on top of a view zone in the content. */ MouseTargetType[MouseTargetType["CONTENT_VIEW_ZONE"] = 8] = "CONTENT_VIEW_ZONE"; /** * Mouse is on top of a content widget. */ MouseTargetType[MouseTargetType["CONTENT_WIDGET"] = 9] = "CONTENT_WIDGET"; /** * Mouse is on top of the decorations overview ruler. */ MouseTargetType[MouseTargetType["OVERVIEW_RULER"] = 10] = "OVERVIEW_RULER"; /** * Mouse is on top of a scrollbar. */ MouseTargetType[MouseTargetType["SCROLLBAR"] = 11] = "SCROLLBAR"; /** * Mouse is on top of an overlay widget. */ MouseTargetType[MouseTargetType["OVERLAY_WIDGET"] = 12] = "OVERLAY_WIDGET"; /** * Mouse is outside of the editor. */ MouseTargetType[MouseTargetType["OUTSIDE_EDITOR"] = 13] = "OUTSIDE_EDITOR"; })(MouseTargetType || (MouseTargetType = {})); var NewSymbolNameTag; (function (NewSymbolNameTag) { NewSymbolNameTag[NewSymbolNameTag["AIGenerated"] = 1] = "AIGenerated"; })(NewSymbolNameTag || (NewSymbolNameTag = {})); var NewSymbolNameTriggerKind; (function (NewSymbolNameTriggerKind) { NewSymbolNameTriggerKind[NewSymbolNameTriggerKind["Invoke"] = 0] = "Invoke"; NewSymbolNameTriggerKind[NewSymbolNameTriggerKind["Automatic"] = 1] = "Automatic"; })(NewSymbolNameTriggerKind || (NewSymbolNameTriggerKind = {})); /** * A positioning preference for rendering overlay widgets. */ var OverlayWidgetPositionPreference; (function (OverlayWidgetPositionPreference) { /** * Position the overlay widget in the top right corner */ OverlayWidgetPositionPreference[OverlayWidgetPositionPreference["TOP_RIGHT_CORNER"] = 0] = "TOP_RIGHT_CORNER"; /** * Position the overlay widget in the bottom right corner */ OverlayWidgetPositionPreference[OverlayWidgetPositionPreference["BOTTOM_RIGHT_CORNER"] = 1] = "BOTTOM_RIGHT_CORNER"; /** * Position the overlay widget in the top center */ OverlayWidgetPositionPreference[OverlayWidgetPositionPreference["TOP_CENTER"] = 2] = "TOP_CENTER"; })(OverlayWidgetPositionPreference || (OverlayWidgetPositionPreference = {})); /** * Vertical Lane in the overview ruler of the editor. */ var OverviewRulerLane$1; (function (OverviewRulerLane) { OverviewRulerLane[OverviewRulerLane["Left"] = 1] = "Left"; OverviewRulerLane[OverviewRulerLane["Center"] = 2] = "Center"; OverviewRulerLane[OverviewRulerLane["Right"] = 4] = "Right"; OverviewRulerLane[OverviewRulerLane["Full"] = 7] = "Full"; })(OverviewRulerLane$1 || (OverviewRulerLane$1 = {})); /** * How a partial acceptance was triggered. */ var PartialAcceptTriggerKind; (function (PartialAcceptTriggerKind) { PartialAcceptTriggerKind[PartialAcceptTriggerKind["Word"] = 0] = "Word"; PartialAcceptTriggerKind[PartialAcceptTriggerKind["Line"] = 1] = "Line"; PartialAcceptTriggerKind[PartialAcceptTriggerKind["Suggest"] = 2] = "Suggest"; })(PartialAcceptTriggerKind || (PartialAcceptTriggerKind = {})); var PositionAffinity; (function (PositionAffinity) { /** * Prefers the left most position. */ PositionAffinity[PositionAffinity["Left"] = 0] = "Left"; /** * Prefers the right most position. */ PositionAffinity[PositionAffinity["Right"] = 1] = "Right"; /** * No preference. */ PositionAffinity[PositionAffinity["None"] = 2] = "None"; /** * If the given position is on injected text, prefers the position left of it. */ PositionAffinity[PositionAffinity["LeftOfInjectedText"] = 3] = "LeftOfInjectedText"; /** * If the given position is on injected text, prefers the position right of it. */ PositionAffinity[PositionAffinity["RightOfInjectedText"] = 4] = "RightOfInjectedText"; })(PositionAffinity || (PositionAffinity = {})); var RenderLineNumbersType; (function (RenderLineNumbersType) { RenderLineNumbersType[RenderLineNumbersType["Off"] = 0] = "Off"; RenderLineNumbersType[RenderLineNumbersType["On"] = 1] = "On"; RenderLineNumbersType[RenderLineNumbersType["Relative"] = 2] = "Relative"; RenderLineNumbersType[RenderLineNumbersType["Interval"] = 3] = "Interval"; RenderLineNumbersType[RenderLineNumbersType["Custom"] = 4] = "Custom"; })(RenderLineNumbersType || (RenderLineNumbersType = {})); var RenderMinimap; (function (RenderMinimap) { RenderMinimap[RenderMinimap["None"] = 0] = "None"; RenderMinimap[RenderMinimap["Text"] = 1] = "Text"; RenderMinimap[RenderMinimap["Blocks"] = 2] = "Blocks"; })(RenderMinimap || (RenderMinimap = {})); var ScrollType; (function (ScrollType) { ScrollType[ScrollType["Smooth"] = 0] = "Smooth"; ScrollType[ScrollType["Immediate"] = 1] = "Immediate"; })(ScrollType || (ScrollType = {})); var ScrollbarVisibility; (function (ScrollbarVisibility) { ScrollbarVisibility[ScrollbarVisibility["Auto"] = 1] = "Auto"; ScrollbarVisibility[ScrollbarVisibility["Hidden"] = 2] = "Hidden"; ScrollbarVisibility[ScrollbarVisibility["Visible"] = 3] = "Visible"; })(ScrollbarVisibility || (ScrollbarVisibility = {})); /** * The direction of a selection. */ var SelectionDirection; (function (SelectionDirection) { /** * The selection starts above where it ends. */ SelectionDirection[SelectionDirection["LTR"] = 0] = "LTR"; /** * The selection starts below where it ends. */ SelectionDirection[SelectionDirection["RTL"] = 1] = "RTL"; })(SelectionDirection || (SelectionDirection = {})); var ShowLightbulbIconMode; (function (ShowLightbulbIconMode) { ShowLightbulbIconMode["Off"] = "off"; ShowLightbulbIconMode["OnCode"] = "onCode"; ShowLightbulbIconMode["On"] = "on"; })(ShowLightbulbIconMode || (ShowLightbulbIconMode = {})); var SignatureHelpTriggerKind; (function (SignatureHelpTriggerKind) { SignatureHelpTriggerKind[SignatureHelpTriggerKind["Invoke"] = 1] = "Invoke"; SignatureHelpTriggerKind[SignatureHelpTriggerKind["TriggerCharacter"] = 2] = "TriggerCharacter"; SignatureHelpTriggerKind[SignatureHelpTriggerKind["ContentChange"] = 3] = "ContentChange"; })(SignatureHelpTriggerKind || (SignatureHelpTriggerKind = {})); /** * A symbol kind. */ var SymbolKind; (function (SymbolKind) { SymbolKind[SymbolKind["File"] = 0] = "File"; SymbolKind[SymbolKind["Module"] = 1] = "Module"; SymbolKind[SymbolKind["Namespace"] = 2] = "Namespace"; SymbolKind[SymbolKind["Package"] = 3] = "Package"; SymbolKind[SymbolKind["Class"] = 4] = "Class"; SymbolKind[SymbolKind["Method"] = 5] = "Method"; SymbolKind[SymbolKind["Property"] = 6] = "Property"; SymbolKind[SymbolKind["Field"] = 7] = "Field"; SymbolKind[SymbolKind["Constructor"] = 8] = "Constructor"; SymbolKind[SymbolKind["Enum"] = 9] = "Enum"; SymbolKind[SymbolKind["Interface"] = 10] = "Interface"; SymbolKind[SymbolKind["Function"] = 11] = "Function"; SymbolKind[SymbolKind["Variable"] = 12] = "Variable"; SymbolKind[SymbolKind["Constant"] = 13] = "Constant"; SymbolKind[SymbolKind["String"] = 14] = "String"; SymbolKind[SymbolKind["Number"] = 15] = "Number"; SymbolKind[SymbolKind["Boolean"] = 16] = "Boolean"; SymbolKind[SymbolKind["Array"] = 17] = "Array"; SymbolKind[SymbolKind["Object"] = 18] = "Object"; SymbolKind[SymbolKind["Key"] = 19] = "Key"; SymbolKind[SymbolKind["Null"] = 20] = "Null"; SymbolKind[SymbolKind["EnumMember"] = 21] = "EnumMember"; SymbolKind[SymbolKind["Struct"] = 22] = "Struct"; SymbolKind[SymbolKind["Event"] = 23] = "Event"; SymbolKind[SymbolKind["Operator"] = 24] = "Operator"; SymbolKind[SymbolKind["TypeParameter"] = 25] = "TypeParameter"; })(SymbolKind || (SymbolKind = {})); var SymbolTag; (function (SymbolTag) { SymbolTag[SymbolTag["Deprecated"] = 1] = "Deprecated"; })(SymbolTag || (SymbolTag = {})); /** * The kind of animation in which the editor's cursor should be rendered. */ var TextEditorCursorBlinkingStyle; (function (TextEditorCursorBlinkingStyle) { /** * Hidden */ TextEditorCursorBlinkingStyle[TextEditorCursorBlinkingStyle["Hidden"] = 0] = "Hidden"; /** * Blinking */ TextEditorCursorBlinkingStyle[TextEditorCursorBlinkingStyle["Blink"] = 1] = "Blink"; /** * Blinking with smooth fading */ TextEditorCursorBlinkingStyle[TextEditorCursorBlinkingStyle["Smooth"] = 2] = "Smooth"; /** * Blinking with prolonged filled state and smooth fading */ TextEditorCursorBlinkingStyle[TextEditorCursorBlinkingStyle["Phase"] = 3] = "Phase"; /** * Expand collapse animation on the y axis */ TextEditorCursorBlinkingStyle[TextEditorCursorBlinkingStyle["Expand"] = 4] = "Expand"; /** * No-Blinking */ TextEditorCursorBlinkingStyle[TextEditorCursorBlinkingStyle["Solid"] = 5] = "Solid"; })(TextEditorCursorBlinkingStyle || (TextEditorCursorBlinkingStyle = {})); /** * The style in which the editor's cursor should be rendered. */ var TextEditorCursorStyle; (function (TextEditorCursorStyle) { /** * As a vertical line (sitting between two characters). */ TextEditorCursorStyle[TextEditorCursorStyle["Line"] = 1] = "Line"; /** * As a block (sitting on top of a character). */ TextEditorCursorStyle[TextEditorCursorStyle["Block"] = 2] = "Block"; /** * As a horizontal line (sitting under a character). */ TextEditorCursorStyle[TextEditorCursorStyle["Underline"] = 3] = "Underline"; /** * As a thin vertical line (sitting between two characters). */ TextEditorCursorStyle[TextEditorCursorStyle["LineThin"] = 4] = "LineThin"; /** * As an outlined block (sitting on top of a character). */ TextEditorCursorStyle[TextEditorCursorStyle["BlockOutline"] = 5] = "BlockOutline"; /** * As a thin horizontal line (sitting under a character). */ TextEditorCursorStyle[TextEditorCursorStyle["UnderlineThin"] = 6] = "UnderlineThin"; })(TextEditorCursorStyle || (TextEditorCursorStyle = {})); /** * Describes the behavior of decorations when typing/editing near their edges. * Note: Please do not edit the values, as they very carefully match `DecorationRangeBehavior` */ var TrackedRangeStickiness; (function (TrackedRangeStickiness) { TrackedRangeStickiness[TrackedRangeStickiness["AlwaysGrowsWhenTypingAtEdges"] = 0] = "AlwaysGrowsWhenTypingAtEdges"; TrackedRangeStickiness[TrackedRangeStickiness["NeverGrowsWhenTypingAtEdges"] = 1] = "NeverGrowsWhenTypingAtEdges"; TrackedRangeStickiness[TrackedRangeStickiness["GrowsOnlyWhenTypingBefore"] = 2] = "GrowsOnlyWhenTypingBefore"; TrackedRangeStickiness[TrackedRangeStickiness["GrowsOnlyWhenTypingAfter"] = 3] = "GrowsOnlyWhenTypingAfter"; })(TrackedRangeStickiness || (TrackedRangeStickiness = {})); /** * Describes how to indent wrapped lines. */ var WrappingIndent; (function (WrappingIndent) { /** * No indentation => wrapped lines begin at column 1. */ WrappingIndent[WrappingIndent["None"] = 0] = "None"; /** * Same => wrapped lines get the same indentation as the parent. */ WrappingIndent[WrappingIndent["Same"] = 1] = "Same"; /** * Indent => wrapped lines get +1 indentation toward the parent. */ WrappingIndent[WrappingIndent["Indent"] = 2] = "Indent"; /** * DeepIndent => wrapped lines get +2 indentation toward the parent. */ WrappingIndent[WrappingIndent["DeepIndent"] = 3] = "DeepIndent"; })(WrappingIndent || (WrappingIndent = {})); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class KeyMod { static { this.CtrlCmd = 2048 /* ConstKeyMod.CtrlCmd */; } static { this.Shift = 1024 /* ConstKeyMod.Shift */; } static { this.Alt = 512 /* ConstKeyMod.Alt */; } static { this.WinCtrl = 256 /* ConstKeyMod.WinCtrl */; } static chord(firstPart, secondPart) { return KeyChord(firstPart, secondPart); } } function createMonacoBaseAPI() { return { editor: undefined, // undefined override expected here languages: undefined, // undefined override expected here CancellationTokenSource: CancellationTokenSource, Emitter: Emitter, KeyCode: KeyCode, KeyMod: KeyMod, Position: Position, Range: Range, Selection: Selection, SelectionDirection: SelectionDirection, MarkerSeverity: MarkerSeverity, MarkerTag: MarkerTag, Uri: URI, Token: Token }; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class EditorWorkerHost { static { this.CHANNEL_NAME = 'editorWorkerHost'; } static getChannel(workerServer) { return workerServer.getChannel(EditorWorkerHost.CHANNEL_NAME); } static setChannel(workerClient, obj) { workerClient.setChannel(EditorWorkerHost.CHANNEL_NAME, obj); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ var _b; class LinkedMap { constructor() { this[_b] = 'LinkedMap'; this._map = new Map(); this._head = undefined; this._tail = undefined; this._size = 0; this._state = 0; } clear() { this._map.clear(); this._head = undefined; this._tail = undefined; this._size = 0; this._state++; } isEmpty() { return !this._head && !this._tail; } get size() { return this._size; } get first() { return this._head?.value; } get last() { return this._tail?.value; } has(key) { return this._map.has(key); } get(key, touch = 0 /* Touch.None */) { const item = this._map.get(key); if (!item) { return undefined; } if (touch !== 0 /* Touch.None */) { this.touch(item, touch); } return item.value; } set(key, value, touch = 0 /* Touch.None */) { let item = this._map.get(key); if (item) { item.value = value; if (touch !== 0 /* Touch.None */) { this.touch(item, touch); } } else { item = { key, value, next: undefined, previous: undefined }; switch (touch) { case 0 /* Touch.None */: this.addItemLast(item); break; case 1 /* Touch.AsOld */: this.addItemFirst(item); break; case 2 /* Touch.AsNew */: this.addItemLast(item); break; default: this.addItemLast(item); break; } this._map.set(key, item); this._size++; } return this; } delete(key) { return !!this.remove(key); } remove(key) { const item = this._map.get(key); if (!item) { return undefined; } this._map.delete(key); this.removeItem(item); this._size--; return item.value; } shift() { if (!this._head && !this._tail) { return undefined; } if (!this._head || !this._tail) { throw new Error('Invalid list'); } const item = this._head; this._map.delete(item.key); this.removeItem(item); this._size--; return item.value; } forEach(callbackfn, thisArg) { const state = this._state; let current = this._head; while (current) { if (thisArg) { callbackfn.bind(thisArg)(current.value, current.key, this); } else { callbackfn(current.value, current.key, this); } if (this._state !== state) { throw new Error(`LinkedMap got modified during iteration.`); } current = current.next; } } keys() { const map = this; const state = this._state; let current = this._head; const iterator = { [Symbol.iterator]() { return iterator; }, next() { if (map._state !== state) { throw new Error(`LinkedMap got modified during iteration.`); } if (current) { const result = { value: current.key, done: false }; current = current.next; return result; } else { return { value: undefined, done: true }; } } }; return iterator; } values() { const map = this; const state = this._state; let current = this._head; const iterator = { [Symbol.iterator]() { return iterator; }, next() { if (map._state !== state) { throw new Error(`LinkedMap got modified during iteration.`); } if (current) { const result = { value: current.value, done: false }; current = current.next; return result; } else { return { value: undefined, done: true }; } } }; return iterator; } entries() { const map = this; const state = this._state; let current = this._head; const iterator = { [Symbol.iterator]() { return iterator; }, next() { if (map._state !== state) { throw new Error(`LinkedMap got modified during iteration.`); } if (current) { const result = { value: [current.key, current.value], done: false }; current = current.next; return result; } else { return { value: undefined, done: true }; } } }; return iterator; } [(_b = Symbol.toStringTag, Symbol.iterator)]() { return this.entries(); } trimOld(newSize) { if (newSize >= this.size) { return; } if (newSize === 0) { this.clear(); return; } let current = this._head; let currentSize = this.size; while (current && currentSize > newSize) { this._map.delete(current.key); current = current.next; currentSize--; } this._head = current; this._size = currentSize; if (current) { current.previous = undefined; } this._state++; } trimNew(newSize) { if (newSize >= this.size) { return; } if (newSize === 0) { this.clear(); return; } let current = this._tail; let currentSize = this.size; while (current && currentSize > newSize) { this._map.delete(current.key); current = current.previous; currentSize--; } this._tail = current; this._size = currentSize; if (current) { current.next = undefined; } this._state++; } addItemFirst(item) { // First time Insert if (!this._head && !this._tail) { this._tail = item; } else if (!this._head) { throw new Error('Invalid list'); } else { item.next = this._head; this._head.previous = item; } this._head = item; this._state++; } addItemLast(item) { // First time Insert if (!this._head && !this._tail) { this._head = item; } else if (!this._tail) { throw new Error('Invalid list'); } else { item.previous = this._tail; this._tail.next = item; } this._tail = item; this._state++; } removeItem(item) { if (item === this._head && item === this._tail) { this._head = undefined; this._tail = undefined; } else if (item === this._head) { // This can only happen if size === 1 which is handled // by the case above. if (!item.next) { throw new Error('Invalid list'); } item.next.previous = undefined; this._head = item.next; } else if (item === this._tail) { // This can only happen if size === 1 which is handled // by the case above. if (!item.previous) { throw new Error('Invalid list'); } item.previous.next = undefined; this._tail = item.previous; } else { const next = item.next; const previous = item.previous; if (!next || !previous) { throw new Error('Invalid list'); } next.previous = previous; previous.next = next; } item.next = undefined; item.previous = undefined; this._state++; } touch(item, touch) { if (!this._head || !this._tail) { throw new Error('Invalid list'); } if ((touch !== 1 /* Touch.AsOld */ && touch !== 2 /* Touch.AsNew */)) { return; } if (touch === 1 /* Touch.AsOld */) { if (item === this._head) { return; } const next = item.next; const previous = item.previous; // Unlink the item if (item === this._tail) { // previous must be defined since item was not head but is tail // So there are more than on item in the map previous.next = undefined; this._tail = previous; } else { // Both next and previous are not undefined since item was neither head nor tail. next.previous = previous; previous.next = next; } // Insert the node at head item.previous = undefined; item.next = this._head; this._head.previous = item; this._head = item; this._state++; } else if (touch === 2 /* Touch.AsNew */) { if (item === this._tail) { return; } const next = item.next; const previous = item.previous; // Unlink the item. if (item === this._head) { // next must be defined since item was not tail but is head // So there are more than on item in the map next.previous = undefined; this._head = next; } else { // Both next and previous are not undefined since item was neither head nor tail. next.previous = previous; previous.next = next; } item.next = undefined; item.previous = this._tail; this._tail.next = item; this._tail = item; this._state++; } } toJSON() { const data = []; this.forEach((value, key) => { data.push([key, value]); }); return data; } fromJSON(data) { this.clear(); for (const [key, value] of data) { this.set(key, value); } } } class Cache extends LinkedMap { constructor(limit, ratio = 1) { super(); this._limit = limit; this._ratio = Math.min(Math.max(0, ratio), 1); } get limit() { return this._limit; } set limit(limit) { this._limit = limit; this.checkTrim(); } get(key, touch = 2 /* Touch.AsNew */) { return super.get(key, touch); } peek(key) { return super.get(key, 0 /* Touch.None */); } set(key, value) { super.set(key, value, 2 /* Touch.AsNew */); return this; } checkTrim() { if (this.size > this._limit) { this.trim(Math.round(this._limit * this._ratio)); } } } class LRUCache extends Cache { constructor(limit, ratio = 1) { super(limit, ratio); } trim(newSize) { this.trimOld(newSize); } set(key, value) { super.set(key, value); this.checkTrim(); return this; } } class SetMap { constructor() { this.map = new Map(); } add(key, value) { let values = this.map.get(key); if (!values) { values = new Set(); this.map.set(key, values); } values.add(value); } delete(key, value) { const values = this.map.get(key); if (!values) { return; } values.delete(value); if (values.size === 0) { this.map.delete(key); } } forEach(key, fn) { const values = this.map.get(key); if (!values) { return; } values.forEach(fn); } get(key) { const values = this.map.get(key); if (!values) { return new Set(); } return values; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ new LRUCache(10); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function getAllPropertyNames(obj) { let res = []; while (Object.prototype !== obj) { res = res.concat(Object.getOwnPropertyNames(obj)); obj = Object.getPrototypeOf(obj); } return res; } function getAllMethodNames(obj) { const methods = []; for (const prop of getAllPropertyNames(obj)) { if (typeof obj[prop] === 'function') { methods.push(prop); } } return methods; } function createProxyObject(methodNames, invoke) { const createProxyMethod = (method) => { return function () { const args = Array.prototype.slice.call(arguments, 0); return invoke(method, args); }; }; const result = {}; for (const methodName of methodNames) { result[methodName] = createProxyMethod(methodName); } return result; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Vertical Lane in the overview ruler of the editor. */ var OverviewRulerLane; (function (OverviewRulerLane) { OverviewRulerLane[OverviewRulerLane["Left"] = 1] = "Left"; OverviewRulerLane[OverviewRulerLane["Center"] = 2] = "Center"; OverviewRulerLane[OverviewRulerLane["Right"] = 4] = "Right"; OverviewRulerLane[OverviewRulerLane["Full"] = 7] = "Full"; })(OverviewRulerLane || (OverviewRulerLane = {})); /** * Vertical Lane in the glyph margin of the editor. */ var GlyphMarginLane; (function (GlyphMarginLane) { GlyphMarginLane[GlyphMarginLane["Left"] = 1] = "Left"; GlyphMarginLane[GlyphMarginLane["Center"] = 2] = "Center"; GlyphMarginLane[GlyphMarginLane["Right"] = 3] = "Right"; })(GlyphMarginLane || (GlyphMarginLane = {})); var InjectedTextCursorStops; (function (InjectedTextCursorStops) { InjectedTextCursorStops[InjectedTextCursorStops["Both"] = 0] = "Both"; InjectedTextCursorStops[InjectedTextCursorStops["Right"] = 1] = "Right"; InjectedTextCursorStops[InjectedTextCursorStops["Left"] = 2] = "Left"; InjectedTextCursorStops[InjectedTextCursorStops["None"] = 3] = "None"; })(InjectedTextCursorStops || (InjectedTextCursorStops = {})); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function leftIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength) { if (matchStartIndex === 0) { // Match starts at start of string return true; } const charBefore = text.charCodeAt(matchStartIndex - 1); if (wordSeparators.get(charBefore) !== 0 /* WordCharacterClass.Regular */) { // The character before the match is a word separator return true; } if (charBefore === 13 /* CharCode.CarriageReturn */ || charBefore === 10 /* CharCode.LineFeed */) { // The character before the match is line break or carriage return. return true; } if (matchLength > 0) { const firstCharInMatch = text.charCodeAt(matchStartIndex); if (wordSeparators.get(firstCharInMatch) !== 0 /* WordCharacterClass.Regular */) { // The first character inside the match is a word separator return true; } } return false; } function rightIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength) { if (matchStartIndex + matchLength === textLength) { // Match ends at end of string return true; } const charAfter = text.charCodeAt(matchStartIndex + matchLength); if (wordSeparators.get(charAfter) !== 0 /* WordCharacterClass.Regular */) { // The character after the match is a word separator return true; } if (charAfter === 13 /* CharCode.CarriageReturn */ || charAfter === 10 /* CharCode.LineFeed */) { // The character after the match is line break or carriage return. return true; } if (matchLength > 0) { const lastCharInMatch = text.charCodeAt(matchStartIndex + matchLength - 1); if (wordSeparators.get(lastCharInMatch) !== 0 /* WordCharacterClass.Regular */) { // The last character in the match is a word separator return true; } } return false; } function isValidMatch(wordSeparators, text, textLength, matchStartIndex, matchLength) { return (leftIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength) && rightIsWordBounday(wordSeparators, text, textLength, matchStartIndex, matchLength)); } class Searcher { constructor(wordSeparators, searchRegex) { this._wordSeparators = wordSeparators; this._searchRegex = searchRegex; this._prevMatchStartIndex = -1; this._prevMatchLength = 0; } reset(lastIndex) { this._searchRegex.lastIndex = lastIndex; this._prevMatchStartIndex = -1; this._prevMatchLength = 0; } next(text) { const textLength = text.length; let m; do { if (this._prevMatchStartIndex + this._prevMatchLength === textLength) { // Reached the end of the line return null; } m = this._searchRegex.exec(text); if (!m) { return null; } const matchStartIndex = m.index; const matchLength = m[0].length; if (matchStartIndex === this._prevMatchStartIndex && matchLength === this._prevMatchLength) { if (matchLength === 0) { // the search result is an empty string and won't advance `regex.lastIndex`, so `regex.exec` will stuck here // we attempt to recover from that by advancing by two if surrogate pair found and by one otherwise if (getNextCodePoint(text, textLength, this._searchRegex.lastIndex) > 0xFFFF) { this._searchRegex.lastIndex += 2; } else { this._searchRegex.lastIndex += 1; } continue; } // Exit early if the regex matches the same range twice return null; } this._prevMatchStartIndex = matchStartIndex; this._prevMatchLength = matchLength; if (!this._wordSeparators || isValidMatch(this._wordSeparators, text, textLength, matchStartIndex, matchLength)) { return m; } } while (m); return null; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function assertNever(value, message = 'Unreachable') { throw new Error(message); } /** * condition must be side-effect free! */ function assertFn(condition) { if (!condition()) { // eslint-disable-next-line no-debugger debugger; // Reevaluate `condition` again to make debugging easier condition(); onUnexpectedError(new BugIndicatingError('Assertion Failed')); } } function checkAdjacentItems(items, predicate) { let i = 0; while (i < items.length - 1) { const a = items[i]; const b = items[i + 1]; if (!predicate(a, b)) { return false; } i++; } return true; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const USUAL_WORD_SEPARATORS = '`~!@#$%^&*()-=+[{]}\\|;:\'",.<>/?'; /** * Create a word definition regular expression based on default word separators. * Optionally provide allowed separators that should be included in words. * * The default would look like this: * /(-?\d*\.\d\w*)|([^\`\~\!\@\#\$\%\^\&\*\(\)\-\=\+\[\{\]\}\\\|\;\:\'\"\,\.\<\>\/\?\s]+)/g */ function createWordRegExp(allowInWords = '') { let source = '(-?\\d*\\.\\d\\w*)|([^'; for (const sep of USUAL_WORD_SEPARATORS) { if (allowInWords.indexOf(sep) >= 0) { continue; } source += '\\' + sep; } source += '\\s]+)'; return new RegExp(source, 'g'); } // catches numbers (including floating numbers) in the first group, and alphanum in the second const DEFAULT_WORD_REGEXP = createWordRegExp(); function ensureValidWordDefinition(wordDefinition) { let result = DEFAULT_WORD_REGEXP; if (wordDefinition && (wordDefinition instanceof RegExp)) { if (!wordDefinition.global) { let flags = 'g'; if (wordDefinition.ignoreCase) { flags += 'i'; } if (wordDefinition.multiline) { flags += 'm'; } if (wordDefinition.unicode) { flags += 'u'; } result = new RegExp(wordDefinition.source, flags); } else { result = wordDefinition; } } result.lastIndex = 0; return result; } const _defaultConfig = new LinkedList(); _defaultConfig.unshift({ maxLen: 1000, windowSize: 15, timeBudget: 150 }); function getWordAtText(column, wordDefinition, text, textOffset, config) { // Ensure the regex has the 'g' flag, otherwise this will loop forever wordDefinition = ensureValidWordDefinition(wordDefinition); if (!config) { config = Iterable.first(_defaultConfig); } if (text.length > config.maxLen) { // don't throw strings that long at the regexp // but use a sub-string in which a word must occur let start = column - config.maxLen / 2; if (start < 0) { start = 0; } else { textOffset += start; } text = text.substring(start, column + config.maxLen / 2); return getWordAtText(column, wordDefinition, text, textOffset, config); } const t1 = Date.now(); const pos = column - 1 - textOffset; let prevRegexIndex = -1; let match = null; for (let i = 1;; i++) { // check time budget if (Date.now() - t1 >= config.timeBudget) { break; } // reset the index at which the regexp should start matching, also know where it // should stop so that subsequent search don't repeat previous searches const regexIndex = pos - config.windowSize * i; wordDefinition.lastIndex = Math.max(0, regexIndex); const thisMatch = _findRegexMatchEnclosingPosition(wordDefinition, text, pos, prevRegexIndex); if (!thisMatch && match) { // stop: we have something break; } match = thisMatch; // stop: searched at start if (regexIndex <= 0) { break; } prevRegexIndex = regexIndex; } if (match) { const result = { word: match[0], startColumn: textOffset + 1 + match.index, endColumn: textOffset + 1 + match.index + match[0].length }; wordDefinition.lastIndex = 0; return result; } return null; } function _findRegexMatchEnclosingPosition(wordDefinition, text, pos, stopPos) { let match; while (match = wordDefinition.exec(text)) { const matchIndex = match.index || 0; if (matchIndex <= pos && wordDefinition.lastIndex >= pos) { return match; } else if (stopPos > 0 && matchIndex > stopPos) { return null; } } return null; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class UnicodeTextModelHighlighter { static computeUnicodeHighlights(model, options, range) { const startLine = range ? range.startLineNumber : 1; const endLine = range ? range.endLineNumber : model.getLineCount(); const codePointHighlighter = new CodePointHighlighter(options); const candidates = codePointHighlighter.getCandidateCodePoints(); let regex; if (candidates === 'allNonBasicAscii') { regex = new RegExp('[^\\t\\n\\r\\x20-\\x7E]', 'g'); } else { regex = new RegExp(`${buildRegExpCharClassExpr(Array.from(candidates))}`, 'g'); } const searcher = new Searcher(null, regex); const ranges = []; let hasMore = false; let m; let ambiguousCharacterCount = 0; let invisibleCharacterCount = 0; let nonBasicAsciiCharacterCount = 0; forLoop: for (let lineNumber = startLine, lineCount = endLine; lineNumber <= lineCount; lineNumber++) { const lineContent = model.getLineContent(lineNumber); const lineLength = lineContent.length; // Reset regex to search from the beginning searcher.reset(0); do { m = searcher.next(lineContent); if (m) { let startIndex = m.index; let endIndex = m.index + m[0].length; // Extend range to entire code point if (startIndex > 0) { const charCodeBefore = lineContent.charCodeAt(startIndex - 1); if (isHighSurrogate(charCodeBefore)) { startIndex--; } } if (endIndex + 1 < lineLength) { const charCodeBefore = lineContent.charCodeAt(endIndex - 1); if (isHighSurrogate(charCodeBefore)) { endIndex++; } } const str = lineContent.substring(startIndex, endIndex); let word = getWordAtText(startIndex + 1, DEFAULT_WORD_REGEXP, lineContent, 0); if (word && word.endColumn <= startIndex + 1) { // The word does not include the problematic character, ignore the word word = null; } const highlightReason = codePointHighlighter.shouldHighlightNonBasicASCII(str, word ? word.word : null); if (highlightReason !== 0 /* SimpleHighlightReason.None */) { if (highlightReason === 3 /* SimpleHighlightReason.Ambiguous */) { ambiguousCharacterCount++; } else if (highlightReason === 2 /* SimpleHighlightReason.Invisible */) { invisibleCharacterCount++; } else if (highlightReason === 1 /* SimpleHighlightReason.NonBasicASCII */) { nonBasicAsciiCharacterCount++; } else { assertNever(); } const MAX_RESULT_LENGTH = 1000; if (ranges.length >= MAX_RESULT_LENGTH) { hasMore = true; break forLoop; } ranges.push(new Range(lineNumber, startIndex + 1, lineNumber, endIndex + 1)); } } } while (m); } return { ranges, hasMore, ambiguousCharacterCount, invisibleCharacterCount, nonBasicAsciiCharacterCount }; } static computeUnicodeHighlightReason(char, options) { const codePointHighlighter = new CodePointHighlighter(options); const reason = codePointHighlighter.shouldHighlightNonBasicASCII(char, null); switch (reason) { case 0 /* SimpleHighlightReason.None */: return null; case 2 /* SimpleHighlightReason.Invisible */: return { kind: 1 /* UnicodeHighlighterReasonKind.Invisible */ }; case 3 /* SimpleHighlightReason.Ambiguous */: { const codePoint = char.codePointAt(0); const primaryConfusable = codePointHighlighter.ambiguousCharacters.getPrimaryConfusable(codePoint); const notAmbiguousInLocales = AmbiguousCharacters.getLocales().filter((l) => !AmbiguousCharacters.getInstance(new Set([...options.allowedLocales, l])).isAmbiguous(codePoint)); return { kind: 0 /* UnicodeHighlighterReasonKind.Ambiguous */, confusableWith: String.fromCodePoint(primaryConfusable), notAmbiguousInLocales }; } case 1 /* SimpleHighlightReason.NonBasicASCII */: return { kind: 2 /* UnicodeHighlighterReasonKind.NonBasicAscii */ }; } } } function buildRegExpCharClassExpr(codePoints, flags) { const src = `[${escapeRegExpCharacters(codePoints.map((i) => String.fromCodePoint(i)).join(''))}]`; return src; } class CodePointHighlighter { constructor(options) { this.options = options; this.allowedCodePoints = new Set(options.allowedCodePoints); this.ambiguousCharacters = AmbiguousCharacters.getInstance(new Set(options.allowedLocales)); } getCandidateCodePoints() { if (this.options.nonBasicASCII) { return 'allNonBasicAscii'; } const set = new Set(); if (this.options.invisibleCharacters) { for (const cp of InvisibleCharacters.codePoints) { if (!isAllowedInvisibleCharacter(String.fromCodePoint(cp))) { set.add(cp); } } } if (this.options.ambiguousCharacters) { for (const cp of this.ambiguousCharacters.getConfusableCodePoints()) { set.add(cp); } } for (const cp of this.allowedCodePoints) { set.delete(cp); } return set; } shouldHighlightNonBasicASCII(character, wordContext) { const codePoint = character.codePointAt(0); if (this.allowedCodePoints.has(codePoint)) { return 0 /* SimpleHighlightReason.None */; } if (this.options.nonBasicASCII) { return 1 /* SimpleHighlightReason.NonBasicASCII */; } let hasBasicASCIICharacters = false; let hasNonConfusableNonBasicAsciiCharacter = false; if (wordContext) { for (const char of wordContext) { const codePoint = char.codePointAt(0); const isBasicASCII$1 = isBasicASCII(char); hasBasicASCIICharacters = hasBasicASCIICharacters || isBasicASCII$1; if (!isBasicASCII$1 && !this.ambiguousCharacters.isAmbiguous(codePoint) && !InvisibleCharacters.isInvisibleCharacter(codePoint)) { hasNonConfusableNonBasicAsciiCharacter = true; } } } if ( /* Don't allow mixing weird looking characters with ASCII */ !hasBasicASCIICharacters && /* Is there an obviously weird looking character? */ hasNonConfusableNonBasicAsciiCharacter) { return 0 /* SimpleHighlightReason.None */; } if (this.options.invisibleCharacters) { // TODO check for emojis if (!isAllowedInvisibleCharacter(character) && InvisibleCharacters.isInvisibleCharacter(codePoint)) { return 2 /* SimpleHighlightReason.Invisible */; } } if (this.options.ambiguousCharacters) { if (this.ambiguousCharacters.isAmbiguous(codePoint)) { return 3 /* SimpleHighlightReason.Ambiguous */; } } return 0 /* SimpleHighlightReason.None */; } } function isAllowedInvisibleCharacter(character) { return character === ' ' || character === '\n' || character === '\t'; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class LinesDiff { constructor(changes, /** * Sorted by original line ranges. * The original line ranges and the modified line ranges must be disjoint (but can be touching). */ moves, /** * Indicates if the time out was reached. * In that case, the diffs might be an approximation and the user should be asked to rerun the diff with more time. */ hitTimeout) { this.changes = changes; this.moves = moves; this.hitTimeout = hitTimeout; } } class MovedText { constructor(lineRangeMapping, changes) { this.lineRangeMapping = lineRangeMapping; this.changes = changes; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A range of offsets (0-based). */ class OffsetRange { static addRange(range, sortedRanges) { let i = 0; while (i < sortedRanges.length && sortedRanges[i].endExclusive < range.start) { i++; } let j = i; while (j < sortedRanges.length && sortedRanges[j].start <= range.endExclusive) { j++; } if (i === j) { sortedRanges.splice(i, 0, range); } else { const start = Math.min(range.start, sortedRanges[i].start); const end = Math.max(range.endExclusive, sortedRanges[j - 1].endExclusive); sortedRanges.splice(i, j - i, new OffsetRange(start, end)); } } static tryCreate(start, endExclusive) { if (start > endExclusive) { return undefined; } return new OffsetRange(start, endExclusive); } static ofLength(length) { return new OffsetRange(0, length); } static ofStartAndLength(start, length) { return new OffsetRange(start, start + length); } constructor(start, endExclusive) { this.start = start; this.endExclusive = endExclusive; if (start > endExclusive) { throw new BugIndicatingError(`Invalid range: ${this.toString()}`); } } get isEmpty() { return this.start === this.endExclusive; } delta(offset) { return new OffsetRange(this.start + offset, this.endExclusive + offset); } deltaStart(offset) { return new OffsetRange(this.start + offset, this.endExclusive); } deltaEnd(offset) { return new OffsetRange(this.start, this.endExclusive + offset); } get length() { return this.endExclusive - this.start; } toString() { return `[${this.start}, ${this.endExclusive})`; } contains(offset) { return this.start <= offset && offset < this.endExclusive; } /** * for all numbers n: range1.contains(n) or range2.contains(n) => range1.join(range2).contains(n) * The joined range is the smallest range that contains both ranges. */ join(other) { return new OffsetRange(Math.min(this.start, other.start), Math.max(this.endExclusive, other.endExclusive)); } /** * for all numbers n: range1.contains(n) and range2.contains(n) <=> range1.intersect(range2).contains(n) * * The resulting range is empty if the ranges do not intersect, but touch. * If the ranges don't even touch, the result is undefined. */ intersect(other) { const start = Math.max(this.start, other.start); const end = Math.min(this.endExclusive, other.endExclusive); if (start <= end) { return new OffsetRange(start, end); } return undefined; } intersects(other) { const start = Math.max(this.start, other.start); const end = Math.min(this.endExclusive, other.endExclusive); return start < end; } isBefore(other) { return this.endExclusive <= other.start; } isAfter(other) { return this.start >= other.endExclusive; } slice(arr) { return arr.slice(this.start, this.endExclusive); } substring(str) { return str.substring(this.start, this.endExclusive); } /** * Returns the given value if it is contained in this instance, otherwise the closest value that is contained. * The range must not be empty. */ clip(value) { if (this.isEmpty) { throw new BugIndicatingError(`Invalid clipping range: ${this.toString()}`); } return Math.max(this.start, Math.min(this.endExclusive - 1, value)); } /** * Returns `r := value + k * length` such that `r` is contained in this range. * The range must not be empty. * * E.g. `[5, 10).clipCyclic(10) === 5`, `[5, 10).clipCyclic(11) === 6` and `[5, 10).clipCyclic(4) === 9`. */ clipCyclic(value) { if (this.isEmpty) { throw new BugIndicatingError(`Invalid clipping range: ${this.toString()}`); } if (value < this.start) { return this.endExclusive - ((this.start - value) % this.length); } if (value >= this.endExclusive) { return this.start + ((value - this.start) % this.length); } return value; } forEach(f) { for (let i = this.start; i < this.endExclusive; i++) { f(i); } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Finds the last item where predicate is true using binary search. * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`! * * @returns `undefined` if no item matches, otherwise the last item that matches the predicate. */ function findLastMonotonous(array, predicate) { const idx = findLastIdxMonotonous(array, predicate); return idx === -1 ? undefined : array[idx]; } /** * Finds the last item where predicate is true using binary search. * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`! * * @returns `startIdx - 1` if predicate is false for all items, otherwise the index of the last item that matches the predicate. */ function findLastIdxMonotonous(array, predicate, startIdx = 0, endIdxEx = array.length) { let i = startIdx; let j = endIdxEx; while (i < j) { const k = Math.floor((i + j) / 2); if (predicate(array[k])) { i = k + 1; } else { j = k; } } return i - 1; } /** * Finds the first item where predicate is true using binary search. * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`! * * @returns `undefined` if no item matches, otherwise the first item that matches the predicate. */ function findFirstMonotonous(array, predicate) { const idx = findFirstIdxMonotonousOrArrLen(array, predicate); return idx === array.length ? undefined : array[idx]; } /** * Finds the first item where predicate is true using binary search. * `predicate` must be monotonous, i.e. `arr.map(predicate)` must be like `[false, ..., false, true, ..., true]`! * * @returns `endIdxEx` if predicate is false for all items, otherwise the index of the first item that matches the predicate. */ function findFirstIdxMonotonousOrArrLen(array, predicate, startIdx = 0, endIdxEx = array.length) { let i = startIdx; let j = endIdxEx; while (i < j) { const k = Math.floor((i + j) / 2); if (predicate(array[k])) { j = k; } else { i = k + 1; } } return i; } /** * Use this when * * You have a sorted array * * You query this array with a monotonous predicate to find the last item that has a certain property. * * You query this array multiple times with monotonous predicates that get weaker and weaker. */ class MonotonousArray { static { this.assertInvariants = false; } constructor(_array) { this._array = _array; this._findLastMonotonousLastIdx = 0; } /** * The predicate must be monotonous, i.e. `arr.map(predicate)` must be like `[true, ..., true, false, ..., false]`! * For subsequent calls, current predicate must be weaker than (or equal to) the previous predicate, i.e. more entries must be `true`. */ findLastMonotonous(predicate) { if (MonotonousArray.assertInvariants) { if (this._prevFindLastPredicate) { for (const item of this._array) { if (this._prevFindLastPredicate(item) && !predicate(item)) { throw new Error('MonotonousArray: current predicate must be weaker than (or equal to) the previous predicate.'); } } } this._prevFindLastPredicate = predicate; } const idx = findLastIdxMonotonous(this._array, predicate, this._findLastMonotonousLastIdx); this._findLastMonotonousLastIdx = idx + 1; return idx === -1 ? undefined : this._array[idx]; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A range of lines (1-based). */ class LineRange { static fromRangeInclusive(range) { return new LineRange(range.startLineNumber, range.endLineNumber + 1); } /** * @param lineRanges An array of sorted line ranges. */ static joinMany(lineRanges) { if (lineRanges.length === 0) { return []; } let result = new LineRangeSet(lineRanges[0].slice()); for (let i = 1; i < lineRanges.length; i++) { result = result.getUnion(new LineRangeSet(lineRanges[i].slice())); } return result.ranges; } static join(lineRanges) { if (lineRanges.length === 0) { throw new BugIndicatingError('lineRanges cannot be empty'); } let startLineNumber = lineRanges[0].startLineNumber; let endLineNumberExclusive = lineRanges[0].endLineNumberExclusive; for (let i = 1; i < lineRanges.length; i++) { startLineNumber = Math.min(startLineNumber, lineRanges[i].startLineNumber); endLineNumberExclusive = Math.max(endLineNumberExclusive, lineRanges[i].endLineNumberExclusive); } return new LineRange(startLineNumber, endLineNumberExclusive); } static ofLength(startLineNumber, length) { return new LineRange(startLineNumber, startLineNumber + length); } /** * @internal */ static deserialize(lineRange) { return new LineRange(lineRange[0], lineRange[1]); } constructor(startLineNumber, endLineNumberExclusive) { if (startLineNumber > endLineNumberExclusive) { throw new BugIndicatingError(`startLineNumber ${startLineNumber} cannot be after endLineNumberExclusive ${endLineNumberExclusive}`); } this.startLineNumber = startLineNumber; this.endLineNumberExclusive = endLineNumberExclusive; } /** * Indicates if this line range contains the given line number. */ contains(lineNumber) { return this.startLineNumber <= lineNumber && lineNumber < this.endLineNumberExclusive; } /** * Indicates if this line range is empty. */ get isEmpty() { return this.startLineNumber === this.endLineNumberExclusive; } /** * Moves this line range by the given offset of line numbers. */ delta(offset) { return new LineRange(this.startLineNumber + offset, this.endLineNumberExclusive + offset); } deltaLength(offset) { return new LineRange(this.startLineNumber, this.endLineNumberExclusive + offset); } /** * The number of lines this line range spans. */ get length() { return this.endLineNumberExclusive - this.startLineNumber; } /** * Creates a line range that combines this and the given line range. */ join(other) { return new LineRange(Math.min(this.startLineNumber, other.startLineNumber), Math.max(this.endLineNumberExclusive, other.endLineNumberExclusive)); } toString() { return `[${this.startLineNumber},${this.endLineNumberExclusive})`; } /** * The resulting range is empty if the ranges do not intersect, but touch. * If the ranges don't even touch, the result is undefined. */ intersect(other) { const startLineNumber = Math.max(this.startLineNumber, other.startLineNumber); const endLineNumberExclusive = Math.min(this.endLineNumberExclusive, other.endLineNumberExclusive); if (startLineNumber <= endLineNumberExclusive) { return new LineRange(startLineNumber, endLineNumberExclusive); } return undefined; } intersectsStrict(other) { return this.startLineNumber < other.endLineNumberExclusive && other.startLineNumber < this.endLineNumberExclusive; } overlapOrTouch(other) { return this.startLineNumber <= other.endLineNumberExclusive && other.startLineNumber <= this.endLineNumberExclusive; } equals(b) { return this.startLineNumber === b.startLineNumber && this.endLineNumberExclusive === b.endLineNumberExclusive; } toInclusiveRange() { if (this.isEmpty) { return null; } return new Range(this.startLineNumber, 1, this.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER); } /** * @deprecated Using this function is discouraged because it might lead to bugs: The end position is not guaranteed to be a valid position! */ toExclusiveRange() { return new Range(this.startLineNumber, 1, this.endLineNumberExclusive, 1); } mapToLineArray(f) { const result = []; for (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) { result.push(f(lineNumber)); } return result; } forEach(f) { for (let lineNumber = this.startLineNumber; lineNumber < this.endLineNumberExclusive; lineNumber++) { f(lineNumber); } } /** * @internal */ serialize() { return [this.startLineNumber, this.endLineNumberExclusive]; } includes(lineNumber) { return this.startLineNumber <= lineNumber && lineNumber < this.endLineNumberExclusive; } /** * Converts this 1-based line range to a 0-based offset range (subtracts 1!). * @internal */ toOffsetRange() { return new OffsetRange(this.startLineNumber - 1, this.endLineNumberExclusive - 1); } } class LineRangeSet { constructor( /** * Sorted by start line number. * No two line ranges are touching or intersecting. */ _normalizedRanges = []) { this._normalizedRanges = _normalizedRanges; } get ranges() { return this._normalizedRanges; } addRange(range) { if (range.length === 0) { return; } // Idea: Find joinRange such that: // replaceRange = _normalizedRanges.replaceRange(joinRange, range.joinAll(joinRange.map(idx => this._normalizedRanges[idx]))) // idx of first element that touches range or that is after range const joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, r => r.endLineNumberExclusive >= range.startLineNumber); // idx of element after { last element that touches range or that is before range } const joinRangeEndIdxExclusive = findLastIdxMonotonous(this._normalizedRanges, r => r.startLineNumber <= range.endLineNumberExclusive) + 1; if (joinRangeStartIdx === joinRangeEndIdxExclusive) { // If there is no element that touches range, then joinRangeStartIdx === joinRangeEndIdxExclusive and that value is the index of the element after range this._normalizedRanges.splice(joinRangeStartIdx, 0, range); } else if (joinRangeStartIdx === joinRangeEndIdxExclusive - 1) { // Else, there is an element that touches range and in this case it is both the first and last element. Thus we can replace it const joinRange = this._normalizedRanges[joinRangeStartIdx]; this._normalizedRanges[joinRangeStartIdx] = joinRange.join(range); } else { // First and last element are different - we need to replace the entire range const joinRange = this._normalizedRanges[joinRangeStartIdx].join(this._normalizedRanges[joinRangeEndIdxExclusive - 1]).join(range); this._normalizedRanges.splice(joinRangeStartIdx, joinRangeEndIdxExclusive - joinRangeStartIdx, joinRange); } } contains(lineNumber) { const rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, r => r.startLineNumber <= lineNumber); return !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > lineNumber; } intersects(range) { const rangeThatStartsBeforeEnd = findLastMonotonous(this._normalizedRanges, r => r.startLineNumber < range.endLineNumberExclusive); return !!rangeThatStartsBeforeEnd && rangeThatStartsBeforeEnd.endLineNumberExclusive > range.startLineNumber; } getUnion(other) { if (this._normalizedRanges.length === 0) { return other; } if (other._normalizedRanges.length === 0) { return this; } const result = []; let i1 = 0; let i2 = 0; let current = null; while (i1 < this._normalizedRanges.length || i2 < other._normalizedRanges.length) { let next = null; if (i1 < this._normalizedRanges.length && i2 < other._normalizedRanges.length) { const lineRange1 = this._normalizedRanges[i1]; const lineRange2 = other._normalizedRanges[i2]; if (lineRange1.startLineNumber < lineRange2.startLineNumber) { next = lineRange1; i1++; } else { next = lineRange2; i2++; } } else if (i1 < this._normalizedRanges.length) { next = this._normalizedRanges[i1]; i1++; } else { next = other._normalizedRanges[i2]; i2++; } if (current === null) { current = next; } else { if (current.endLineNumberExclusive >= next.startLineNumber) { // merge current = new LineRange(current.startLineNumber, Math.max(current.endLineNumberExclusive, next.endLineNumberExclusive)); } else { // push result.push(current); current = next; } } } if (current !== null) { result.push(current); } return new LineRangeSet(result); } /** * Subtracts all ranges in this set from `range` and returns the result. */ subtractFrom(range) { // idx of first element that touches range or that is after range const joinRangeStartIdx = findFirstIdxMonotonousOrArrLen(this._normalizedRanges, r => r.endLineNumberExclusive >= range.startLineNumber); // idx of element after { last element that touches range or that is before range } const joinRangeEndIdxExclusive = findLastIdxMonotonous(this._normalizedRanges, r => r.startLineNumber <= range.endLineNumberExclusive) + 1; if (joinRangeStartIdx === joinRangeEndIdxExclusive) { return new LineRangeSet([range]); } const result = []; let startLineNumber = range.startLineNumber; for (let i = joinRangeStartIdx; i < joinRangeEndIdxExclusive; i++) { const r = this._normalizedRanges[i]; if (r.startLineNumber > startLineNumber) { result.push(new LineRange(startLineNumber, r.startLineNumber)); } startLineNumber = r.endLineNumberExclusive; } if (startLineNumber < range.endLineNumberExclusive) { result.push(new LineRange(startLineNumber, range.endLineNumberExclusive)); } return new LineRangeSet(result); } toString() { return this._normalizedRanges.map(r => r.toString()).join(', '); } getIntersection(other) { const result = []; let i1 = 0; let i2 = 0; while (i1 < this._normalizedRanges.length && i2 < other._normalizedRanges.length) { const r1 = this._normalizedRanges[i1]; const r2 = other._normalizedRanges[i2]; const i = r1.intersect(r2); if (i && !i.isEmpty) { result.push(i); } if (r1.endLineNumberExclusive < r2.endLineNumberExclusive) { i1++; } else { i2++; } } return new LineRangeSet(result); } getWithDelta(value) { return new LineRangeSet(this._normalizedRanges.map(r => r.delta(value))); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Represents a non-negative length of text in terms of line and column count. */ class TextLength { static { this.zero = new TextLength(0, 0); } static betweenPositions(position1, position2) { if (position1.lineNumber === position2.lineNumber) { return new TextLength(0, position2.column - position1.column); } else { return new TextLength(position2.lineNumber - position1.lineNumber, position2.column - 1); } } static ofRange(range) { return TextLength.betweenPositions(range.getStartPosition(), range.getEndPosition()); } static ofText(text) { let line = 0; let column = 0; for (const c of text) { if (c === '\n') { line++; column = 0; } else { column++; } } return new TextLength(line, column); } constructor(lineCount, columnCount) { this.lineCount = lineCount; this.columnCount = columnCount; } isGreaterThanOrEqualTo(other) { if (this.lineCount !== other.lineCount) { return this.lineCount > other.lineCount; } return this.columnCount >= other.columnCount; } createRange(startPosition) { if (this.lineCount === 0) { return new Range(startPosition.lineNumber, startPosition.column, startPosition.lineNumber, startPosition.column + this.columnCount); } else { return new Range(startPosition.lineNumber, startPosition.column, startPosition.lineNumber + this.lineCount, this.columnCount + 1); } } addToPosition(position) { if (this.lineCount === 0) { return new Position(position.lineNumber, position.column + this.columnCount); } else { return new Position(position.lineNumber + this.lineCount, this.columnCount + 1); } } toString() { return `${this.lineCount},${this.columnCount}`; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class SingleTextEdit { constructor(range, text) { this.range = range; this.text = text; } toSingleEditOperation() { return { range: this.range, text: this.text, }; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * Maps a line range in the original text model to a line range in the modified text model. */ class LineRangeMapping { static inverse(mapping, originalLineCount, modifiedLineCount) { const result = []; let lastOriginalEndLineNumber = 1; let lastModifiedEndLineNumber = 1; for (const m of mapping) { const r = new LineRangeMapping(new LineRange(lastOriginalEndLineNumber, m.original.startLineNumber), new LineRange(lastModifiedEndLineNumber, m.modified.startLineNumber)); if (!r.modified.isEmpty) { result.push(r); } lastOriginalEndLineNumber = m.original.endLineNumberExclusive; lastModifiedEndLineNumber = m.modified.endLineNumberExclusive; } const r = new LineRangeMapping(new LineRange(lastOriginalEndLineNumber, originalLineCount + 1), new LineRange(lastModifiedEndLineNumber, modifiedLineCount + 1)); if (!r.modified.isEmpty) { result.push(r); } return result; } static clip(mapping, originalRange, modifiedRange) { const result = []; for (const m of mapping) { const original = m.original.intersect(originalRange); const modified = m.modified.intersect(modifiedRange); if (original && !original.isEmpty && modified && !modified.isEmpty) { result.push(new LineRangeMapping(original, modified)); } } return result; } constructor(originalRange, modifiedRange) { this.original = originalRange; this.modified = modifiedRange; } toString() { return `{${this.original.toString()}->${this.modified.toString()}}`; } flip() { return new LineRangeMapping(this.modified, this.original); } join(other) { return new LineRangeMapping(this.original.join(other.original), this.modified.join(other.modified)); } /** * This method assumes that the LineRangeMapping describes a valid diff! * I.e. if one range is empty, the other range cannot be the entire document. * It avoids various problems when the line range points to non-existing line-numbers. */ toRangeMapping() { const origInclusiveRange = this.original.toInclusiveRange(); const modInclusiveRange = this.modified.toInclusiveRange(); if (origInclusiveRange && modInclusiveRange) { return new RangeMapping(origInclusiveRange, modInclusiveRange); } else if (this.original.startLineNumber === 1 || this.modified.startLineNumber === 1) { if (!(this.modified.startLineNumber === 1 && this.original.startLineNumber === 1)) { // If one line range starts at 1, the other one must start at 1 as well. throw new BugIndicatingError('not a valid diff'); } // Because one range is empty and both ranges start at line 1, none of the ranges can cover all lines. // Thus, `endLineNumberExclusive` is a valid line number. return new RangeMapping(new Range(this.original.startLineNumber, 1, this.original.endLineNumberExclusive, 1), new Range(this.modified.startLineNumber, 1, this.modified.endLineNumberExclusive, 1)); } else { // We can assume here that both startLineNumbers are greater than 1. return new RangeMapping(new Range(this.original.startLineNumber - 1, Number.MAX_SAFE_INTEGER, this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), new Range(this.modified.startLineNumber - 1, Number.MAX_SAFE_INTEGER, this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER)); } } /** * This method assumes that the LineRangeMapping describes a valid diff! * I.e. if one range is empty, the other range cannot be the entire document. * It avoids various problems when the line range points to non-existing line-numbers. */ toRangeMapping2(original, modified) { if (isValidLineNumber(this.original.endLineNumberExclusive, original) && isValidLineNumber(this.modified.endLineNumberExclusive, modified)) { return new RangeMapping(new Range(this.original.startLineNumber, 1, this.original.endLineNumberExclusive, 1), new Range(this.modified.startLineNumber, 1, this.modified.endLineNumberExclusive, 1)); } if (!this.original.isEmpty && !this.modified.isEmpty) { return new RangeMapping(Range.fromPositions(new Position(this.original.startLineNumber, 1), normalizePosition(new Position(this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), original)), Range.fromPositions(new Position(this.modified.startLineNumber, 1), normalizePosition(new Position(this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), modified))); } if (this.original.startLineNumber > 1 && this.modified.startLineNumber > 1) { return new RangeMapping(Range.fromPositions(normalizePosition(new Position(this.original.startLineNumber - 1, Number.MAX_SAFE_INTEGER), original), normalizePosition(new Position(this.original.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), original)), Range.fromPositions(normalizePosition(new Position(this.modified.startLineNumber - 1, Number.MAX_SAFE_INTEGER), modified), normalizePosition(new Position(this.modified.endLineNumberExclusive - 1, Number.MAX_SAFE_INTEGER), modified))); } // Situation now: one range is empty and one range touches the last line and one range starts at line 1. // I don't think this can happen. throw new BugIndicatingError(); } } function normalizePosition(position, content) { if (position.lineNumber < 1) { return new Position(1, 1); } if (position.lineNumber > content.length) { return new Position(content.length, content[content.length - 1].length + 1); } const line = content[position.lineNumber - 1]; if (position.column > line.length + 1) { return new Position(position.lineNumber, line.length + 1); } return position; } function isValidLineNumber(lineNumber, lines) { return lineNumber >= 1 && lineNumber <= lines.length; } /** * Maps a line range in the original text model to a line range in the modified text model. * Also contains inner range mappings. */ class DetailedLineRangeMapping extends LineRangeMapping { static fromRangeMappings(rangeMappings) { const originalRange = LineRange.join(rangeMappings.map(r => LineRange.fromRangeInclusive(r.originalRange))); const modifiedRange = LineRange.join(rangeMappings.map(r => LineRange.fromRangeInclusive(r.modifiedRange))); return new DetailedLineRangeMapping(originalRange, modifiedRange, rangeMappings); } constructor(originalRange, modifiedRange, innerChanges) { super(originalRange, modifiedRange); this.innerChanges = innerChanges; } flip() { return new DetailedLineRangeMapping(this.modified, this.original, this.innerChanges?.map(c => c.flip())); } withInnerChangesFromLineRanges() { return new DetailedLineRangeMapping(this.original, this.modified, [this.toRangeMapping()]); } } /** * Maps a range in the original text model to a range in the modified text model. */ class RangeMapping { static assertSorted(rangeMappings) { for (let i = 1; i < rangeMappings.length; i++) { const previous = rangeMappings[i - 1]; const current = rangeMappings[i]; if (!(previous.originalRange.getEndPosition().isBeforeOrEqual(current.originalRange.getStartPosition()) && previous.modifiedRange.getEndPosition().isBeforeOrEqual(current.modifiedRange.getStartPosition()))) { throw new BugIndicatingError('Range mappings must be sorted'); } } } constructor(originalRange, modifiedRange) { this.originalRange = originalRange; this.modifiedRange = modifiedRange; } toString() { return `{${this.originalRange.toString()}->${this.modifiedRange.toString()}}`; } flip() { return new RangeMapping(this.modifiedRange, this.originalRange); } /** * Creates a single text edit that describes the change from the original to the modified text. */ toTextEdit(modified) { const newText = modified.getValueOfRange(this.modifiedRange); return new SingleTextEdit(this.originalRange, newText); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const MINIMUM_MATCHING_CHARACTER_LENGTH = 3; class LegacyLinesDiffComputer { computeDiff(originalLines, modifiedLines, options) { const diffComputer = new DiffComputer(originalLines, modifiedLines, { maxComputationTime: options.maxComputationTimeMs, shouldIgnoreTrimWhitespace: options.ignoreTrimWhitespace, shouldComputeCharChanges: true, shouldMakePrettyDiff: true, shouldPostProcessCharChanges: true, }); const result = diffComputer.computeDiff(); const changes = []; let lastChange = null; for (const c of result.changes) { let originalRange; if (c.originalEndLineNumber === 0) { // Insertion originalRange = new LineRange(c.originalStartLineNumber + 1, c.originalStartLineNumber + 1); } else { originalRange = new LineRange(c.originalStartLineNumber, c.originalEndLineNumber + 1); } let modifiedRange; if (c.modifiedEndLineNumber === 0) { // Deletion modifiedRange = new LineRange(c.modifiedStartLineNumber + 1, c.modifiedStartLineNumber + 1); } else { modifiedRange = new LineRange(c.modifiedStartLineNumber, c.modifiedEndLineNumber + 1); } let change = new DetailedLineRangeMapping(originalRange, modifiedRange, c.charChanges?.map(c => new RangeMapping(new Range(c.originalStartLineNumber, c.originalStartColumn, c.originalEndLineNumber, c.originalEndColumn), new Range(c.modifiedStartLineNumber, c.modifiedStartColumn, c.modifiedEndLineNumber, c.modifiedEndColumn)))); if (lastChange) { if (lastChange.modified.endLineNumberExclusive === change.modified.startLineNumber || lastChange.original.endLineNumberExclusive === change.original.startLineNumber) { // join touching diffs. Probably moving diffs up/down in the algorithm causes touching diffs. change = new DetailedLineRangeMapping(lastChange.original.join(change.original), lastChange.modified.join(change.modified), lastChange.innerChanges && change.innerChanges ? lastChange.innerChanges.concat(change.innerChanges) : undefined); changes.pop(); } } changes.push(change); lastChange = change; } assertFn(() => { return checkAdjacentItems(changes, (m1, m2) => m2.original.startLineNumber - m1.original.endLineNumberExclusive === m2.modified.startLineNumber - m1.modified.endLineNumberExclusive && // There has to be an unchanged line in between (otherwise both diffs should have been joined) m1.original.endLineNumberExclusive < m2.original.startLineNumber && m1.modified.endLineNumberExclusive < m2.modified.startLineNumber); }); return new LinesDiff(changes, [], result.quitEarly); } } function computeDiff(originalSequence, modifiedSequence, continueProcessingPredicate, pretty) { const diffAlgo = new LcsDiff(originalSequence, modifiedSequence, continueProcessingPredicate); return diffAlgo.ComputeDiff(pretty); } let LineSequence$1 = class LineSequence { constructor(lines) { const startColumns = []; const endColumns = []; for (let i = 0, length = lines.length; i < length; i++) { startColumns[i] = getFirstNonBlankColumn(lines[i], 1); endColumns[i] = getLastNonBlankColumn(lines[i], 1); } this.lines = lines; this._startColumns = startColumns; this._endColumns = endColumns; } getElements() { const elements = []; for (let i = 0, len = this.lines.length; i < len; i++) { elements[i] = this.lines[i].substring(this._startColumns[i] - 1, this._endColumns[i] - 1); } return elements; } getStrictElement(index) { return this.lines[index]; } getStartLineNumber(i) { return i + 1; } getEndLineNumber(i) { return i + 1; } createCharSequence(shouldIgnoreTrimWhitespace, startIndex, endIndex) { const charCodes = []; const lineNumbers = []; const columns = []; let len = 0; for (let index = startIndex; index <= endIndex; index++) { const lineContent = this.lines[index]; const startColumn = (shouldIgnoreTrimWhitespace ? this._startColumns[index] : 1); const endColumn = (shouldIgnoreTrimWhitespace ? this._endColumns[index] : lineContent.length + 1); for (let col = startColumn; col < endColumn; col++) { charCodes[len] = lineContent.charCodeAt(col - 1); lineNumbers[len] = index + 1; columns[len] = col; len++; } if (!shouldIgnoreTrimWhitespace && index < endIndex) { // Add \n if trim whitespace is not ignored charCodes[len] = 10 /* CharCode.LineFeed */; lineNumbers[len] = index + 1; columns[len] = lineContent.length + 1; len++; } } return new CharSequence(charCodes, lineNumbers, columns); } }; class CharSequence { constructor(charCodes, lineNumbers, columns) { this._charCodes = charCodes; this._lineNumbers = lineNumbers; this._columns = columns; } toString() { return ('[' + this._charCodes.map((s, idx) => (s === 10 /* CharCode.LineFeed */ ? '\\n' : String.fromCharCode(s)) + `-(${this._lineNumbers[idx]},${this._columns[idx]})`).join(', ') + ']'); } _assertIndex(index, arr) { if (index < 0 || index >= arr.length) { throw new Error(`Illegal index`); } } getElements() { return this._charCodes; } getStartLineNumber(i) { if (i > 0 && i === this._lineNumbers.length) { // the start line number of the element after the last element // is the end line number of the last element return this.getEndLineNumber(i - 1); } this._assertIndex(i, this._lineNumbers); return this._lineNumbers[i]; } getEndLineNumber(i) { if (i === -1) { // the end line number of the element before the first element // is the start line number of the first element return this.getStartLineNumber(i + 1); } this._assertIndex(i, this._lineNumbers); if (this._charCodes[i] === 10 /* CharCode.LineFeed */) { return this._lineNumbers[i] + 1; } return this._lineNumbers[i]; } getStartColumn(i) { if (i > 0 && i === this._columns.length) { // the start column of the element after the last element // is the end column of the last element return this.getEndColumn(i - 1); } this._assertIndex(i, this._columns); return this._columns[i]; } getEndColumn(i) { if (i === -1) { // the end column of the element before the first element // is the start column of the first element return this.getStartColumn(i + 1); } this._assertIndex(i, this._columns); if (this._charCodes[i] === 10 /* CharCode.LineFeed */) { return 1; } return this._columns[i] + 1; } } class CharChange { constructor(originalStartLineNumber, originalStartColumn, originalEndLineNumber, originalEndColumn, modifiedStartLineNumber, modifiedStartColumn, modifiedEndLineNumber, modifiedEndColumn) { this.originalStartLineNumber = originalStartLineNumber; this.originalStartColumn = originalStartColumn; this.originalEndLineNumber = originalEndLineNumber; this.originalEndColumn = originalEndColumn; this.modifiedStartLineNumber = modifiedStartLineNumber; this.modifiedStartColumn = modifiedStartColumn; this.modifiedEndLineNumber = modifiedEndLineNumber; this.modifiedEndColumn = modifiedEndColumn; } static createFromDiffChange(diffChange, originalCharSequence, modifiedCharSequence) { const originalStartLineNumber = originalCharSequence.getStartLineNumber(diffChange.originalStart); const originalStartColumn = originalCharSequence.getStartColumn(diffChange.originalStart); const originalEndLineNumber = originalCharSequence.getEndLineNumber(diffChange.originalStart + diffChange.originalLength - 1); const originalEndColumn = originalCharSequence.getEndColumn(diffChange.originalStart + diffChange.originalLength - 1); const modifiedStartLineNumber = modifiedCharSequence.getStartLineNumber(diffChange.modifiedStart); const modifiedStartColumn = modifiedCharSequence.getStartColumn(diffChange.modifiedStart); const modifiedEndLineNumber = modifiedCharSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1); const modifiedEndColumn = modifiedCharSequence.getEndColumn(diffChange.modifiedStart + diffChange.modifiedLength - 1); return new CharChange(originalStartLineNumber, originalStartColumn, originalEndLineNumber, originalEndColumn, modifiedStartLineNumber, modifiedStartColumn, modifiedEndLineNumber, modifiedEndColumn); } } function postProcessCharChanges(rawChanges) { if (rawChanges.length <= 1) { return rawChanges; } const result = [rawChanges[0]]; let prevChange = result[0]; for (let i = 1, len = rawChanges.length; i < len; i++) { const currChange = rawChanges[i]; const originalMatchingLength = currChange.originalStart - (prevChange.originalStart + prevChange.originalLength); const modifiedMatchingLength = currChange.modifiedStart - (prevChange.modifiedStart + prevChange.modifiedLength); // Both of the above should be equal, but the continueProcessingPredicate may prevent this from being true const matchingLength = Math.min(originalMatchingLength, modifiedMatchingLength); if (matchingLength < MINIMUM_MATCHING_CHARACTER_LENGTH) { // Merge the current change into the previous one prevChange.originalLength = (currChange.originalStart + currChange.originalLength) - prevChange.originalStart; prevChange.modifiedLength = (currChange.modifiedStart + currChange.modifiedLength) - prevChange.modifiedStart; } else { // Add the current change result.push(currChange); prevChange = currChange; } } return result; } class LineChange { constructor(originalStartLineNumber, originalEndLineNumber, modifiedStartLineNumber, modifiedEndLineNumber, charChanges) { this.originalStartLineNumber = originalStartLineNumber; this.originalEndLineNumber = originalEndLineNumber; this.modifiedStartLineNumber = modifiedStartLineNumber; this.modifiedEndLineNumber = modifiedEndLineNumber; this.charChanges = charChanges; } static createFromDiffResult(shouldIgnoreTrimWhitespace, diffChange, originalLineSequence, modifiedLineSequence, continueCharDiff, shouldComputeCharChanges, shouldPostProcessCharChanges) { let originalStartLineNumber; let originalEndLineNumber; let modifiedStartLineNumber; let modifiedEndLineNumber; let charChanges = undefined; if (diffChange.originalLength === 0) { originalStartLineNumber = originalLineSequence.getStartLineNumber(diffChange.originalStart) - 1; originalEndLineNumber = 0; } else { originalStartLineNumber = originalLineSequence.getStartLineNumber(diffChange.originalStart); originalEndLineNumber = originalLineSequence.getEndLineNumber(diffChange.originalStart + diffChange.originalLength - 1); } if (diffChange.modifiedLength === 0) { modifiedStartLineNumber = modifiedLineSequence.getStartLineNumber(diffChange.modifiedStart) - 1; modifiedEndLineNumber = 0; } else { modifiedStartLineNumber = modifiedLineSequence.getStartLineNumber(diffChange.modifiedStart); modifiedEndLineNumber = modifiedLineSequence.getEndLineNumber(diffChange.modifiedStart + diffChange.modifiedLength - 1); } if (shouldComputeCharChanges && diffChange.originalLength > 0 && diffChange.originalLength < 20 && diffChange.modifiedLength > 0 && diffChange.modifiedLength < 20 && continueCharDiff()) { // Compute character changes for diff chunks of at most 20 lines... const originalCharSequence = originalLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.originalStart, diffChange.originalStart + diffChange.originalLength - 1); const modifiedCharSequence = modifiedLineSequence.createCharSequence(shouldIgnoreTrimWhitespace, diffChange.modifiedStart, diffChange.modifiedStart + diffChange.modifiedLength - 1); if (originalCharSequence.getElements().length > 0 && modifiedCharSequence.getElements().length > 0) { let rawChanges = computeDiff(originalCharSequence, modifiedCharSequence, continueCharDiff, true).changes; if (shouldPostProcessCharChanges) { rawChanges = postProcessCharChanges(rawChanges); } charChanges = []; for (let i = 0, length = rawChanges.length; i < length; i++) { charChanges.push(CharChange.createFromDiffChange(rawChanges[i], originalCharSequence, modifiedCharSequence)); } } } return new LineChange(originalStartLineNumber, originalEndLineNumber, modifiedStartLineNumber, modifiedEndLineNumber, charChanges); } } class DiffComputer { constructor(originalLines, modifiedLines, opts) { this.shouldComputeCharChanges = opts.shouldComputeCharChanges; this.shouldPostProcessCharChanges = opts.shouldPostProcessCharChanges; this.shouldIgnoreTrimWhitespace = opts.shouldIgnoreTrimWhitespace; this.shouldMakePrettyDiff = opts.shouldMakePrettyDiff; this.originalLines = originalLines; this.modifiedLines = modifiedLines; this.original = new LineSequence$1(originalLines); this.modified = new LineSequence$1(modifiedLines); this.continueLineDiff = createContinueProcessingPredicate(opts.maxComputationTime); this.continueCharDiff = createContinueProcessingPredicate(opts.maxComputationTime === 0 ? 0 : Math.min(opts.maxComputationTime, 5000)); // never run after 5s for character changes... } computeDiff() { if (this.original.lines.length === 1 && this.original.lines[0].length === 0) { // empty original => fast path if (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) { return { quitEarly: false, changes: [] }; } return { quitEarly: false, changes: [{ originalStartLineNumber: 1, originalEndLineNumber: 1, modifiedStartLineNumber: 1, modifiedEndLineNumber: this.modified.lines.length, charChanges: undefined }] }; } if (this.modified.lines.length === 1 && this.modified.lines[0].length === 0) { // empty modified => fast path return { quitEarly: false, changes: [{ originalStartLineNumber: 1, originalEndLineNumber: this.original.lines.length, modifiedStartLineNumber: 1, modifiedEndLineNumber: 1, charChanges: undefined }] }; } const diffResult = computeDiff(this.original, this.modified, this.continueLineDiff, this.shouldMakePrettyDiff); const rawChanges = diffResult.changes; const quitEarly = diffResult.quitEarly; // The diff is always computed with ignoring trim whitespace // This ensures we get the prettiest diff if (this.shouldIgnoreTrimWhitespace) { const lineChanges = []; for (let i = 0, length = rawChanges.length; i < length; i++) { lineChanges.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, rawChanges[i], this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges)); } return { quitEarly: quitEarly, changes: lineChanges }; } // Need to post-process and introduce changes where the trim whitespace is different // Note that we are looping starting at -1 to also cover the lines before the first change const result = []; let originalLineIndex = 0; let modifiedLineIndex = 0; for (let i = -1 /* !!!! */, len = rawChanges.length; i < len; i++) { const nextChange = (i + 1 < len ? rawChanges[i + 1] : null); const originalStop = (nextChange ? nextChange.originalStart : this.originalLines.length); const modifiedStop = (nextChange ? nextChange.modifiedStart : this.modifiedLines.length); while (originalLineIndex < originalStop && modifiedLineIndex < modifiedStop) { const originalLine = this.originalLines[originalLineIndex]; const modifiedLine = this.modifiedLines[modifiedLineIndex]; if (originalLine !== modifiedLine) { // These lines differ only in trim whitespace // Check the leading whitespace { let originalStartColumn = getFirstNonBlankColumn(originalLine, 1); let modifiedStartColumn = getFirstNonBlankColumn(modifiedLine, 1); while (originalStartColumn > 1 && modifiedStartColumn > 1) { const originalChar = originalLine.charCodeAt(originalStartColumn - 2); const modifiedChar = modifiedLine.charCodeAt(modifiedStartColumn - 2); if (originalChar !== modifiedChar) { break; } originalStartColumn--; modifiedStartColumn--; } if (originalStartColumn > 1 || modifiedStartColumn > 1) { this._pushTrimWhitespaceCharChange(result, originalLineIndex + 1, 1, originalStartColumn, modifiedLineIndex + 1, 1, modifiedStartColumn); } } // Check the trailing whitespace { let originalEndColumn = getLastNonBlankColumn(originalLine, 1); let modifiedEndColumn = getLastNonBlankColumn(modifiedLine, 1); const originalMaxColumn = originalLine.length + 1; const modifiedMaxColumn = modifiedLine.length + 1; while (originalEndColumn < originalMaxColumn && modifiedEndColumn < modifiedMaxColumn) { const originalChar = originalLine.charCodeAt(originalEndColumn - 1); const modifiedChar = originalLine.charCodeAt(modifiedEndColumn - 1); if (originalChar !== modifiedChar) { break; } originalEndColumn++; modifiedEndColumn++; } if (originalEndColumn < originalMaxColumn || modifiedEndColumn < modifiedMaxColumn) { this._pushTrimWhitespaceCharChange(result, originalLineIndex + 1, originalEndColumn, originalMaxColumn, modifiedLineIndex + 1, modifiedEndColumn, modifiedMaxColumn); } } } originalLineIndex++; modifiedLineIndex++; } if (nextChange) { // Emit the actual change result.push(LineChange.createFromDiffResult(this.shouldIgnoreTrimWhitespace, nextChange, this.original, this.modified, this.continueCharDiff, this.shouldComputeCharChanges, this.shouldPostProcessCharChanges)); originalLineIndex += nextChange.originalLength; modifiedLineIndex += nextChange.modifiedLength; } } return { quitEarly: quitEarly, changes: result }; } _pushTrimWhitespaceCharChange(result, originalLineNumber, originalStartColumn, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedEndColumn) { if (this._mergeTrimWhitespaceCharChange(result, originalLineNumber, originalStartColumn, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedEndColumn)) { // Merged into previous return; } let charChanges = undefined; if (this.shouldComputeCharChanges) { charChanges = [new CharChange(originalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn)]; } result.push(new LineChange(originalLineNumber, originalLineNumber, modifiedLineNumber, modifiedLineNumber, charChanges)); } _mergeTrimWhitespaceCharChange(result, originalLineNumber, originalStartColumn, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedEndColumn) { const len = result.length; if (len === 0) { return false; } const prevChange = result[len - 1]; if (prevChange.originalEndLineNumber === 0 || prevChange.modifiedEndLineNumber === 0) { // Don't merge with inserts/deletes return false; } if (prevChange.originalEndLineNumber === originalLineNumber && prevChange.modifiedEndLineNumber === modifiedLineNumber) { if (this.shouldComputeCharChanges && prevChange.charChanges) { prevChange.charChanges.push(new CharChange(originalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn)); } return true; } if (prevChange.originalEndLineNumber + 1 === originalLineNumber && prevChange.modifiedEndLineNumber + 1 === modifiedLineNumber) { prevChange.originalEndLineNumber = originalLineNumber; prevChange.modifiedEndLineNumber = modifiedLineNumber; if (this.shouldComputeCharChanges && prevChange.charChanges) { prevChange.charChanges.push(new CharChange(originalLineNumber, originalStartColumn, originalLineNumber, originalEndColumn, modifiedLineNumber, modifiedStartColumn, modifiedLineNumber, modifiedEndColumn)); } return true; } return false; } } function getFirstNonBlankColumn(txt, defaultValue) { const r = firstNonWhitespaceIndex(txt); if (r === -1) { return defaultValue; } return r + 1; } function getLastNonBlankColumn(txt, defaultValue) { const r = lastNonWhitespaceIndex(txt); if (r === -1) { return defaultValue; } return r + 2; } function createContinueProcessingPredicate(maximumRuntime) { if (maximumRuntime === 0) { return () => true; } const startTime = Date.now(); return () => { return Date.now() - startTime < maximumRuntime; }; } /** * Returns the last element of an array. * @param array The array. * @param n Which element from the end (default is zero). */ function equals(one, other, itemEquals = (a, b) => a === b) { if (one === other) { return true; } if (!one || !other) { return false; } if (one.length !== other.length) { return false; } for (let i = 0, len = one.length; i < len; i++) { if (!itemEquals(one[i], other[i])) { return false; } } return true; } /** * Splits the given items into a list of (non-empty) groups. * `shouldBeGrouped` is used to decide if two consecutive items should be in the same group. * The order of the items is preserved. */ function* groupAdjacentBy(items, shouldBeGrouped) { let currentGroup; let last; for (const item of items) { if (last !== undefined && shouldBeGrouped(last, item)) { currentGroup.push(item); } else { if (currentGroup) { yield currentGroup; } currentGroup = [item]; } last = item; } if (currentGroup) { yield currentGroup; } } function forEachAdjacent(arr, f) { for (let i = 0; i <= arr.length; i++) { f(i === 0 ? undefined : arr[i - 1], i === arr.length ? undefined : arr[i]); } } function forEachWithNeighbors(arr, f) { for (let i = 0; i < arr.length; i++) { f(i === 0 ? undefined : arr[i - 1], arr[i], i + 1 === arr.length ? undefined : arr[i + 1]); } } function pushMany(arr, items) { for (const item of items) { arr.push(item); } } var CompareResult; (function (CompareResult) { function isLessThan(result) { return result < 0; } CompareResult.isLessThan = isLessThan; function isLessThanOrEqual(result) { return result <= 0; } CompareResult.isLessThanOrEqual = isLessThanOrEqual; function isGreaterThan(result) { return result > 0; } CompareResult.isGreaterThan = isGreaterThan; function isNeitherLessOrGreaterThan(result) { return result === 0; } CompareResult.isNeitherLessOrGreaterThan = isNeitherLessOrGreaterThan; CompareResult.greaterThan = 1; CompareResult.lessThan = -1; CompareResult.neitherLessOrGreaterThan = 0; })(CompareResult || (CompareResult = {})); function compareBy(selector, comparator) { return (a, b) => comparator(selector(a), selector(b)); } /** * The natural order on numbers. */ const numberComparator = (a, b) => a - b; function reverseOrder(comparator) { return (a, b) => -comparator(a, b); } /** * This class is faster than an iterator and array for lazy computed data. */ class CallbackIterable { static { this.empty = new CallbackIterable(_callback => { }); } constructor( /** * Calls the callback for every item. * Stops when the callback returns false. */ iterate) { this.iterate = iterate; } toArray() { const result = []; this.iterate(item => { result.push(item); return true; }); return result; } filter(predicate) { return new CallbackIterable(cb => this.iterate(item => predicate(item) ? cb(item) : true)); } map(mapFn) { return new CallbackIterable(cb => this.iterate(item => cb(mapFn(item)))); } findLast(predicate) { let result; this.iterate(item => { if (predicate(item)) { result = item; } return true; }); return result; } findLastMaxBy(comparator) { let result; let first = true; this.iterate(item => { if (first || CompareResult.isGreaterThan(comparator(item, result))) { first = false; result = item; } return true; }); return result; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class DiffAlgorithmResult { static trivial(seq1, seq2) { return new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], false); } static trivialTimedOut(seq1, seq2) { return new DiffAlgorithmResult([new SequenceDiff(OffsetRange.ofLength(seq1.length), OffsetRange.ofLength(seq2.length))], true); } constructor(diffs, /** * Indicates if the time out was reached. * In that case, the diffs might be an approximation and the user should be asked to rerun the diff with more time. */ hitTimeout) { this.diffs = diffs; this.hitTimeout = hitTimeout; } } class SequenceDiff { static invert(sequenceDiffs, doc1Length) { const result = []; forEachAdjacent(sequenceDiffs, (a, b) => { result.push(SequenceDiff.fromOffsetPairs(a ? a.getEndExclusives() : OffsetPair.zero, b ? b.getStarts() : new OffsetPair(doc1Length, (a ? a.seq2Range.endExclusive - a.seq1Range.endExclusive : 0) + doc1Length))); }); return result; } static fromOffsetPairs(start, endExclusive) { return new SequenceDiff(new OffsetRange(start.offset1, endExclusive.offset1), new OffsetRange(start.offset2, endExclusive.offset2)); } static assertSorted(sequenceDiffs) { let last = undefined; for (const cur of sequenceDiffs) { if (last) { if (!(last.seq1Range.endExclusive <= cur.seq1Range.start && last.seq2Range.endExclusive <= cur.seq2Range.start)) { throw new BugIndicatingError('Sequence diffs must be sorted'); } } last = cur; } } constructor(seq1Range, seq2Range) { this.seq1Range = seq1Range; this.seq2Range = seq2Range; } swap() { return new SequenceDiff(this.seq2Range, this.seq1Range); } toString() { return `${this.seq1Range} <-> ${this.seq2Range}`; } join(other) { return new SequenceDiff(this.seq1Range.join(other.seq1Range), this.seq2Range.join(other.seq2Range)); } delta(offset) { if (offset === 0) { return this; } return new SequenceDiff(this.seq1Range.delta(offset), this.seq2Range.delta(offset)); } deltaStart(offset) { if (offset === 0) { return this; } return new SequenceDiff(this.seq1Range.deltaStart(offset), this.seq2Range.deltaStart(offset)); } deltaEnd(offset) { if (offset === 0) { return this; } return new SequenceDiff(this.seq1Range.deltaEnd(offset), this.seq2Range.deltaEnd(offset)); } intersect(other) { const i1 = this.seq1Range.intersect(other.seq1Range); const i2 = this.seq2Range.intersect(other.seq2Range); if (!i1 || !i2) { return undefined; } return new SequenceDiff(i1, i2); } getStarts() { return new OffsetPair(this.seq1Range.start, this.seq2Range.start); } getEndExclusives() { return new OffsetPair(this.seq1Range.endExclusive, this.seq2Range.endExclusive); } } class OffsetPair { static { this.zero = new OffsetPair(0, 0); } static { this.max = new OffsetPair(Number.MAX_SAFE_INTEGER, Number.MAX_SAFE_INTEGER); } constructor(offset1, offset2) { this.offset1 = offset1; this.offset2 = offset2; } toString() { return `${this.offset1} <-> ${this.offset2}`; } delta(offset) { if (offset === 0) { return this; } return new OffsetPair(this.offset1 + offset, this.offset2 + offset); } equals(other) { return this.offset1 === other.offset1 && this.offset2 === other.offset2; } } class InfiniteTimeout { static { this.instance = new InfiniteTimeout(); } isValid() { return true; } } class DateTimeout { constructor(timeout) { this.timeout = timeout; this.startTime = Date.now(); this.valid = true; if (timeout <= 0) { throw new BugIndicatingError('timeout must be positive'); } } // Recommendation: Set a log-point `{this.disable()}` in the body isValid() { const valid = Date.now() - this.startTime < this.timeout; if (!valid && this.valid) { this.valid = false; // timeout reached // eslint-disable-next-line no-debugger debugger; // WARNING: Most likely debugging caused the timeout. Call `this.disable()` to continue without timing out. } return this.valid; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class Array2D { constructor(width, height) { this.width = width; this.height = height; this.array = []; this.array = new Array(width * height); } get(x, y) { return this.array[x + y * this.width]; } set(x, y, value) { this.array[x + y * this.width] = value; } } function isSpace(charCode) { return charCode === 32 /* CharCode.Space */ || charCode === 9 /* CharCode.Tab */; } class LineRangeFragment { static { this.chrKeys = new Map(); } static getKey(chr) { let key = this.chrKeys.get(chr); if (key === undefined) { key = this.chrKeys.size; this.chrKeys.set(chr, key); } return key; } constructor(range, lines, source) { this.range = range; this.lines = lines; this.source = source; this.histogram = []; let counter = 0; for (let i = range.startLineNumber - 1; i < range.endLineNumberExclusive - 1; i++) { const line = lines[i]; for (let j = 0; j < line.length; j++) { counter++; const chr = line[j]; const key = LineRangeFragment.getKey(chr); this.histogram[key] = (this.histogram[key] || 0) + 1; } counter++; const key = LineRangeFragment.getKey('\n'); this.histogram[key] = (this.histogram[key] || 0) + 1; } this.totalCount = counter; } computeSimilarity(other) { let sumDifferences = 0; const maxLength = Math.max(this.histogram.length, other.histogram.length); for (let i = 0; i < maxLength; i++) { sumDifferences += Math.abs((this.histogram[i] ?? 0) - (other.histogram[i] ?? 0)); } return 1 - (sumDifferences / (this.totalCount + other.totalCount)); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * A O(MN) diffing algorithm that supports a score function. * The algorithm can be improved by processing the 2d array diagonally. */ class DynamicProgrammingDiffing { compute(sequence1, sequence2, timeout = InfiniteTimeout.instance, equalityScore) { if (sequence1.length === 0 || sequence2.length === 0) { return DiffAlgorithmResult.trivial(sequence1, sequence2); } /** * lcsLengths.get(i, j): Length of the longest common subsequence of sequence1.substring(0, i + 1) and sequence2.substring(0, j + 1). */ const lcsLengths = new Array2D(sequence1.length, sequence2.length); const directions = new Array2D(sequence1.length, sequence2.length); const lengths = new Array2D(sequence1.length, sequence2.length); // ==== Initializing lcsLengths ==== for (let s1 = 0; s1 < sequence1.length; s1++) { for (let s2 = 0; s2 < sequence2.length; s2++) { if (!timeout.isValid()) { return DiffAlgorithmResult.trivialTimedOut(sequence1, sequence2); } const horizontalLen = s1 === 0 ? 0 : lcsLengths.get(s1 - 1, s2); const verticalLen = s2 === 0 ? 0 : lcsLengths.get(s1, s2 - 1); let extendedSeqScore; if (sequence1.getElement(s1) === sequence2.getElement(s2)) { if (s1 === 0 || s2 === 0) { extendedSeqScore = 0; } else { extendedSeqScore = lcsLengths.get(s1 - 1, s2 - 1); } if (s1 > 0 && s2 > 0 && directions.get(s1 - 1, s2 - 1) === 3) { // Prefer consecutive diagonals extendedSeqScore += lengths.get(s1 - 1, s2 - 1); } extendedSeqScore += (equalityScore ? equalityScore(s1, s2) : 1); } else { extendedSeqScore = -1; } const newValue = Math.max(horizontalLen, verticalLen, extendedSeqScore); if (newValue === extendedSeqScore) { // Prefer diagonals const prevLen = s1 > 0 && s2 > 0 ? lengths.get(s1 - 1, s2 - 1) : 0; lengths.set(s1, s2, prevLen + 1); directions.set(s1, s2, 3); } else if (newValue === horizontalLen) { lengths.set(s1, s2, 0); directions.set(s1, s2, 1); } else if (newValue === verticalLen) { lengths.set(s1, s2, 0); directions.set(s1, s2, 2); } lcsLengths.set(s1, s2, newValue); } } // ==== Backtracking ==== const result = []; let lastAligningPosS1 = sequence1.length; let lastAligningPosS2 = sequence2.length; function reportDecreasingAligningPositions(s1, s2) { if (s1 + 1 !== lastAligningPosS1 || s2 + 1 !== lastAligningPosS2) { result.push(new SequenceDiff(new OffsetRange(s1 + 1, lastAligningPosS1), new OffsetRange(s2 + 1, lastAligningPosS2))); } lastAligningPosS1 = s1; lastAligningPosS2 = s2; } let s1 = sequence1.length - 1; let s2 = sequence2.length - 1; while (s1 >= 0 && s2 >= 0) { if (directions.get(s1, s2) === 3) { reportDecreasingAligningPositions(s1, s2); s1--; s2--; } else { if (directions.get(s1, s2) === 1) { s1--; } else { s2--; } } } reportDecreasingAligningPositions(-1, -1); result.reverse(); return new DiffAlgorithmResult(result, false); } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * An O(ND) diff algorithm that has a quadratic space worst-case complexity. */ class MyersDiffAlgorithm { compute(seq1, seq2, timeout = InfiniteTimeout.instance) { // These are common special cases. // The early return improves performance dramatically. if (seq1.length === 0 || seq2.length === 0) { return DiffAlgorithmResult.trivial(seq1, seq2); } const seqX = seq1; // Text on the x axis const seqY = seq2; // Text on the y axis function getXAfterSnake(x, y) { while (x < seqX.length && y < seqY.length && seqX.getElement(x) === seqY.getElement(y)) { x++; y++; } return x; } let d = 0; // V[k]: X value of longest d-line that ends in diagonal k. // d-line: path from (0,0) to (x,y) that uses exactly d non-diagonals. // diagonal k: Set of points (x,y) with x-y = k. // k=1 -> (1,0),(2,1) const V = new FastInt32Array(); V.set(0, getXAfterSnake(0, 0)); const paths = new FastArrayNegativeIndices(); paths.set(0, V.get(0) === 0 ? null : new SnakePath(null, 0, 0, V.get(0))); let k = 0; loop: while (true) { d++; if (!timeout.isValid()) { return DiffAlgorithmResult.trivialTimedOut(seqX, seqY); } // The paper has `for (k = -d; k <= d; k += 2)`, but we can ignore diagonals that cannot influence the result. const lowerBound = -Math.min(d, seqY.length + (d % 2)); const upperBound = Math.min(d, seqX.length + (d % 2)); for (k = lowerBound; k <= upperBound; k += 2) { // We can use the X values of (d-1)-lines to compute X value of the longest d-lines. const maxXofDLineTop = k === upperBound ? -1 : V.get(k + 1); // We take a vertical non-diagonal (add a symbol in seqX) const maxXofDLineLeft = k === lowerBound ? -1 : V.get(k - 1) + 1; // We take a horizontal non-diagonal (+1 x) (delete a symbol in seqX) const x = Math.min(Math.max(maxXofDLineTop, maxXofDLineLeft), seqX.length); const y = x - k; if (x > seqX.length || y > seqY.length) { // This diagonal is irrelevant for the result. // TODO: Don't pay the cost for this in the next iteration. continue; } const newMaxX = getXAfterSnake(x, y); V.set(k, newMaxX); const lastPath = x === maxXofDLineTop ? paths.get(k + 1) : paths.get(k - 1); paths.set(k, newMaxX !== x ? new SnakePath(lastPath, x, y, newMaxX - x) : lastPath); if (V.get(k) === seqX.length && V.get(k) - k === seqY.length) { break loop; } } } let path = paths.get(k); const result = []; let lastAligningPosS1 = seqX.length; let lastAligningPosS2 = seqY.length; while (true) { const endX = path ? path.x + path.length : 0; const endY = path ? path.y + path.length : 0; if (endX !== lastAligningPosS1 || endY !== lastAligningPosS2) { result.push(new SequenceDiff(new OffsetRange(endX, lastAligningPosS1), new OffsetRange(endY, lastAligningPosS2))); } if (!path) { break; } lastAligningPosS1 = path.x; lastAligningPosS2 = path.y; path = path.prev; } result.reverse(); return new DiffAlgorithmResult(result, false); } } class SnakePath { constructor(prev, x, y, length) { this.prev = prev; this.x = x; this.y = y; this.length = length; } } /** * An array that supports fast negative indices. */ class FastInt32Array { constructor() { this.positiveArr = new Int32Array(10); this.negativeArr = new Int32Array(10); } get(idx) { if (idx < 0) { idx = -idx - 1; return this.negativeArr[idx]; } else { return this.positiveArr[idx]; } } set(idx, value) { if (idx < 0) { idx = -idx - 1; if (idx >= this.negativeArr.length) { const arr = this.negativeArr; this.negativeArr = new Int32Array(arr.length * 2); this.negativeArr.set(arr); } this.negativeArr[idx] = value; } else { if (idx >= this.positiveArr.length) { const arr = this.positiveArr; this.positiveArr = new Int32Array(arr.length * 2); this.positiveArr.set(arr); } this.positiveArr[idx] = value; } } } /** * An array that supports fast negative indices. */ class FastArrayNegativeIndices { constructor() { this.positiveArr = []; this.negativeArr = []; } get(idx) { if (idx < 0) { idx = -idx - 1; return this.negativeArr[idx]; } else { return this.positiveArr[idx]; } } set(idx, value) { if (idx < 0) { idx = -idx - 1; this.negativeArr[idx] = value; } else { this.positiveArr[idx] = value; } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class LinesSliceCharSequence { constructor(lines, range, considerWhitespaceChanges) { this.lines = lines; this.range = range; this.considerWhitespaceChanges = considerWhitespaceChanges; this.elements = []; this.firstElementOffsetByLineIdx = []; this.lineStartOffsets = []; this.trimmedWsLengthsByLineIdx = []; this.firstElementOffsetByLineIdx.push(0); for (let lineNumber = this.range.startLineNumber; lineNumber <= this.range.endLineNumber; lineNumber++) { let line = lines[lineNumber - 1]; let lineStartOffset = 0; if (lineNumber === this.range.startLineNumber && this.range.startColumn > 1) { lineStartOffset = this.range.startColumn - 1; line = line.substring(lineStartOffset); } this.lineStartOffsets.push(lineStartOffset); let trimmedWsLength = 0; if (!considerWhitespaceChanges) { const trimmedStartLine = line.trimStart(); trimmedWsLength = line.length - trimmedStartLine.length; line = trimmedStartLine.trimEnd(); } this.trimmedWsLengthsByLineIdx.push(trimmedWsLength); const lineLength = lineNumber === this.range.endLineNumber ? Math.min(this.range.endColumn - 1 - lineStartOffset - trimmedWsLength, line.length) : line.length; for (let i = 0; i < lineLength; i++) { this.elements.push(line.charCodeAt(i)); } if (lineNumber < this.range.endLineNumber) { this.elements.push('\n'.charCodeAt(0)); this.firstElementOffsetByLineIdx.push(this.elements.length); } } } toString() { return `Slice: "${this.text}"`; } get text() { return this.getText(new OffsetRange(0, this.length)); } getText(range) { return this.elements.slice(range.start, range.endExclusive).map(e => String.fromCharCode(e)).join(''); } getElement(offset) { return this.elements[offset]; } get length() { return this.elements.length; } getBoundaryScore(length) { // a b c , d e f // 11 0 0 12 15 6 13 0 0 11 const prevCategory = getCategory(length > 0 ? this.elements[length - 1] : -1); const nextCategory = getCategory(length < this.elements.length ? this.elements[length] : -1); if (prevCategory === 7 /* CharBoundaryCategory.LineBreakCR */ && nextCategory === 8 /* CharBoundaryCategory.LineBreakLF */) { // don't break between \r and \n return 0; } if (prevCategory === 8 /* CharBoundaryCategory.LineBreakLF */) { // prefer the linebreak before the change return 150; } let score = 0; if (prevCategory !== nextCategory) { score += 10; if (prevCategory === 0 /* CharBoundaryCategory.WordLower */ && nextCategory === 1 /* CharBoundaryCategory.WordUpper */) { score += 1; } } score += getCategoryBoundaryScore(prevCategory); score += getCategoryBoundaryScore(nextCategory); return score; } translateOffset(offset, preference = 'right') { // find smallest i, so that lineBreakOffsets[i] <= offset using binary search const i = findLastIdxMonotonous(this.firstElementOffsetByLineIdx, (value) => value <= offset); const lineOffset = offset - this.firstElementOffsetByLineIdx[i]; return new Position(this.range.startLineNumber + i, 1 + this.lineStartOffsets[i] + lineOffset + ((lineOffset === 0 && preference === 'left') ? 0 : this.trimmedWsLengthsByLineIdx[i])); } translateRange(range) { const pos1 = this.translateOffset(range.start, 'right'); const pos2 = this.translateOffset(range.endExclusive, 'left'); if (pos2.isBefore(pos1)) { return Range.fromPositions(pos2, pos2); } return Range.fromPositions(pos1, pos2); } /** * Finds the word that contains the character at the given offset */ findWordContaining(offset) { if (offset < 0 || offset >= this.elements.length) { return undefined; } if (!isWordChar(this.elements[offset])) { return undefined; } // find start let start = offset; while (start > 0 && isWordChar(this.elements[start - 1])) { start--; } // find end let end = offset; while (end < this.elements.length && isWordChar(this.elements[end])) { end++; } return new OffsetRange(start, end); } countLinesIn(range) { return this.translateOffset(range.endExclusive).lineNumber - this.translateOffset(range.start).lineNumber; } isStronglyEqual(offset1, offset2) { return this.elements[offset1] === this.elements[offset2]; } extendToFullLines(range) { const start = findLastMonotonous(this.firstElementOffsetByLineIdx, x => x <= range.start) ?? 0; const end = findFirstMonotonous(this.firstElementOffsetByLineIdx, x => range.endExclusive <= x) ?? this.elements.length; return new OffsetRange(start, end); } } function isWordChar(charCode) { return charCode >= 97 /* CharCode.a */ && charCode <= 122 /* CharCode.z */ || charCode >= 65 /* CharCode.A */ && charCode <= 90 /* CharCode.Z */ || charCode >= 48 /* CharCode.Digit0 */ && charCode <= 57 /* CharCode.Digit9 */; } const score = { [0 /* CharBoundaryCategory.WordLower */]: 0, [1 /* CharBoundaryCategory.WordUpper */]: 0, [2 /* CharBoundaryCategory.WordNumber */]: 0, [3 /* CharBoundaryCategory.End */]: 10, [4 /* CharBoundaryCategory.Other */]: 2, [5 /* CharBoundaryCategory.Separator */]: 30, [6 /* CharBoundaryCategory.Space */]: 3, [7 /* CharBoundaryCategory.LineBreakCR */]: 10, [8 /* CharBoundaryCategory.LineBreakLF */]: 10, }; function getCategoryBoundaryScore(category) { return score[category]; } function getCategory(charCode) { if (charCode === 10 /* CharCode.LineFeed */) { return 8 /* CharBoundaryCategory.LineBreakLF */; } else if (charCode === 13 /* CharCode.CarriageReturn */) { return 7 /* CharBoundaryCategory.LineBreakCR */; } else if (isSpace(charCode)) { return 6 /* CharBoundaryCategory.Space */; } else if (charCode >= 97 /* CharCode.a */ && charCode <= 122 /* CharCode.z */) { return 0 /* CharBoundaryCategory.WordLower */; } else if (charCode >= 65 /* CharCode.A */ && charCode <= 90 /* CharCode.Z */) { return 1 /* CharBoundaryCategory.WordUpper */; } else if (charCode >= 48 /* CharCode.Digit0 */ && charCode <= 57 /* CharCode.Digit9 */) { return 2 /* CharBoundaryCategory.WordNumber */; } else if (charCode === -1) { return 3 /* CharBoundaryCategory.End */; } else if (charCode === 44 /* CharCode.Comma */ || charCode === 59 /* CharCode.Semicolon */) { return 5 /* CharBoundaryCategory.Separator */; } else { return 4 /* CharBoundaryCategory.Other */; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function computeMovedLines(changes, originalLines, modifiedLines, hashedOriginalLines, hashedModifiedLines, timeout) { let { moves, excludedChanges } = computeMovesFromSimpleDeletionsToSimpleInsertions(changes, originalLines, modifiedLines, timeout); if (!timeout.isValid()) { return []; } const filteredChanges = changes.filter(c => !excludedChanges.has(c)); const unchangedMoves = computeUnchangedMoves(filteredChanges, hashedOriginalLines, hashedModifiedLines, originalLines, modifiedLines, timeout); pushMany(moves, unchangedMoves); moves = joinCloseConsecutiveMoves(moves); // Ignore too short moves moves = moves.filter(current => { const lines = current.original.toOffsetRange().slice(originalLines).map(l => l.trim()); const originalText = lines.join('\n'); return originalText.length >= 15 && countWhere(lines, l => l.length >= 2) >= 2; }); moves = removeMovesInSameDiff(changes, moves); return moves; } function countWhere(arr, predicate) { let count = 0; for (const t of arr) { if (predicate(t)) { count++; } } return count; } function computeMovesFromSimpleDeletionsToSimpleInsertions(changes, originalLines, modifiedLines, timeout) { const moves = []; const deletions = changes .filter(c => c.modified.isEmpty && c.original.length >= 3) .map(d => new LineRangeFragment(d.original, originalLines, d)); const insertions = new Set(changes .filter(c => c.original.isEmpty && c.modified.length >= 3) .map(d => new LineRangeFragment(d.modified, modifiedLines, d))); const excludedChanges = new Set(); for (const deletion of deletions) { let highestSimilarity = -1; let best; for (const insertion of insertions) { const similarity = deletion.computeSimilarity(insertion); if (similarity > highestSimilarity) { highestSimilarity = similarity; best = insertion; } } if (highestSimilarity > 0.90 && best) { insertions.delete(best); moves.push(new LineRangeMapping(deletion.range, best.range)); excludedChanges.add(deletion.source); excludedChanges.add(best.source); } if (!timeout.isValid()) { return { moves, excludedChanges }; } } return { moves, excludedChanges }; } function computeUnchangedMoves(changes, hashedOriginalLines, hashedModifiedLines, originalLines, modifiedLines, timeout) { const moves = []; const original3LineHashes = new SetMap(); for (const change of changes) { for (let i = change.original.startLineNumber; i < change.original.endLineNumberExclusive - 2; i++) { const key = `${hashedOriginalLines[i - 1]}:${hashedOriginalLines[i + 1 - 1]}:${hashedOriginalLines[i + 2 - 1]}`; original3LineHashes.add(key, { range: new LineRange(i, i + 3) }); } } const possibleMappings = []; changes.sort(compareBy(c => c.modified.startLineNumber, numberComparator)); for (const change of changes) { let lastMappings = []; for (let i = change.modified.startLineNumber; i < change.modified.endLineNumberExclusive - 2; i++) { const key = `${hashedModifiedLines[i - 1]}:${hashedModifiedLines[i + 1 - 1]}:${hashedModifiedLines[i + 2 - 1]}`; const currentModifiedRange = new LineRange(i, i + 3); const nextMappings = []; original3LineHashes.forEach(key, ({ range }) => { for (const lastMapping of lastMappings) { // does this match extend some last match? if (lastMapping.originalLineRange.endLineNumberExclusive + 1 === range.endLineNumberExclusive && lastMapping.modifiedLineRange.endLineNumberExclusive + 1 === currentModifiedRange.endLineNumberExclusive) { lastMapping.originalLineRange = new LineRange(lastMapping.originalLineRange.startLineNumber, range.endLineNumberExclusive); lastMapping.modifiedLineRange = new LineRange(lastMapping.modifiedLineRange.startLineNumber, currentModifiedRange.endLineNumberExclusive); nextMappings.push(lastMapping); return; } } const mapping = { modifiedLineRange: currentModifiedRange, originalLineRange: range, }; possibleMappings.push(mapping); nextMappings.push(mapping); }); lastMappings = nextMappings; } if (!timeout.isValid()) { return []; } } possibleMappings.sort(reverseOrder(compareBy(m => m.modifiedLineRange.length, numberComparator))); const modifiedSet = new LineRangeSet(); const originalSet = new LineRangeSet(); for (const mapping of possibleMappings) { const diffOrigToMod = mapping.modifiedLineRange.startLineNumber - mapping.originalLineRange.startLineNumber; const modifiedSections = modifiedSet.subtractFrom(mapping.modifiedLineRange); const originalTranslatedSections = originalSet.subtractFrom(mapping.originalLineRange).getWithDelta(diffOrigToMod); const modifiedIntersectedSections = modifiedSections.getIntersection(originalTranslatedSections); for (const s of modifiedIntersectedSections.ranges) { if (s.length < 3) { continue; } const modifiedLineRange = s; const originalLineRange = s.delta(-diffOrigToMod); moves.push(new LineRangeMapping(originalLineRange, modifiedLineRange)); modifiedSet.addRange(modifiedLineRange); originalSet.addRange(originalLineRange); } } moves.sort(compareBy(m => m.original.startLineNumber, numberComparator)); const monotonousChanges = new MonotonousArray(changes); for (let i = 0; i < moves.length; i++) { const move = moves[i]; const firstTouchingChangeOrig = monotonousChanges.findLastMonotonous(c => c.original.startLineNumber <= move.original.startLineNumber); const firstTouchingChangeMod = findLastMonotonous(changes, c => c.modified.startLineNumber <= move.modified.startLineNumber); const linesAbove = Math.max(move.original.startLineNumber - firstTouchingChangeOrig.original.startLineNumber, move.modified.startLineNumber - firstTouchingChangeMod.modified.startLineNumber); const lastTouchingChangeOrig = monotonousChanges.findLastMonotonous(c => c.original.startLineNumber < move.original.endLineNumberExclusive); const lastTouchingChangeMod = findLastMonotonous(changes, c => c.modified.startLineNumber < move.modified.endLineNumberExclusive); const linesBelow = Math.max(lastTouchingChangeOrig.original.endLineNumberExclusive - move.original.endLineNumberExclusive, lastTouchingChangeMod.modified.endLineNumberExclusive - move.modified.endLineNumberExclusive); let extendToTop; for (extendToTop = 0; extendToTop < linesAbove; extendToTop++) { const origLine = move.original.startLineNumber - extendToTop - 1; const modLine = move.modified.startLineNumber - extendToTop - 1; if (origLine > originalLines.length || modLine > modifiedLines.length) { break; } if (modifiedSet.contains(modLine) || originalSet.contains(origLine)) { break; } if (!areLinesSimilar(originalLines[origLine - 1], modifiedLines[modLine - 1], timeout)) { break; } } if (extendToTop > 0) { originalSet.addRange(new LineRange(move.original.startLineNumber - extendToTop, move.original.startLineNumber)); modifiedSet.addRange(new LineRange(move.modified.startLineNumber - extendToTop, move.modified.startLineNumber)); } let extendToBottom; for (extendToBottom = 0; extendToBottom < linesBelow; extendToBottom++) { const origLine = move.original.endLineNumberExclusive + extendToBottom; const modLine = move.modified.endLineNumberExclusive + extendToBottom; if (origLine > originalLines.length || modLine > modifiedLines.length) { break; } if (modifiedSet.contains(modLine) || originalSet.contains(origLine)) { break; } if (!areLinesSimilar(originalLines[origLine - 1], modifiedLines[modLine - 1], timeout)) { break; } } if (extendToBottom > 0) { originalSet.addRange(new LineRange(move.original.endLineNumberExclusive, move.original.endLineNumberExclusive + extendToBottom)); modifiedSet.addRange(new LineRange(move.modified.endLineNumberExclusive, move.modified.endLineNumberExclusive + extendToBottom)); } if (extendToTop > 0 || extendToBottom > 0) { moves[i] = new LineRangeMapping(new LineRange(move.original.startLineNumber - extendToTop, move.original.endLineNumberExclusive + extendToBottom), new LineRange(move.modified.startLineNumber - extendToTop, move.modified.endLineNumberExclusive + extendToBottom)); } } return moves; } function areLinesSimilar(line1, line2, timeout) { if (line1.trim() === line2.trim()) { return true; } if (line1.length > 300 && line2.length > 300) { return false; } const myersDiffingAlgorithm = new MyersDiffAlgorithm(); const result = myersDiffingAlgorithm.compute(new LinesSliceCharSequence([line1], new Range(1, 1, 1, line1.length), false), new LinesSliceCharSequence([line2], new Range(1, 1, 1, line2.length), false), timeout); let commonNonSpaceCharCount = 0; const inverted = SequenceDiff.invert(result.diffs, line1.length); for (const seq of inverted) { seq.seq1Range.forEach(idx => { if (!isSpace(line1.charCodeAt(idx))) { commonNonSpaceCharCount++; } }); } function countNonWsChars(str) { let count = 0; for (let i = 0; i < line1.length; i++) { if (!isSpace(str.charCodeAt(i))) { count++; } } return count; } const longerLineLength = countNonWsChars(line1.length > line2.length ? line1 : line2); const r = commonNonSpaceCharCount / longerLineLength > 0.6 && longerLineLength > 10; return r; } function joinCloseConsecutiveMoves(moves) { if (moves.length === 0) { return moves; } moves.sort(compareBy(m => m.original.startLineNumber, numberComparator)); const result = [moves[0]]; for (let i = 1; i < moves.length; i++) { const last = result[result.length - 1]; const current = moves[i]; const originalDist = current.original.startLineNumber - last.original.endLineNumberExclusive; const modifiedDist = current.modified.startLineNumber - last.modified.endLineNumberExclusive; const currentMoveAfterLast = originalDist >= 0 && modifiedDist >= 0; if (currentMoveAfterLast && originalDist + modifiedDist <= 2) { result[result.length - 1] = last.join(current); continue; } result.push(current); } return result; } function removeMovesInSameDiff(changes, moves) { const changesMonotonous = new MonotonousArray(changes); moves = moves.filter(m => { const diffBeforeEndOfMoveOriginal = changesMonotonous.findLastMonotonous(c => c.original.startLineNumber < m.original.endLineNumberExclusive) || new LineRangeMapping(new LineRange(1, 1), new LineRange(1, 1)); const diffBeforeEndOfMoveModified = findLastMonotonous(changes, c => c.modified.startLineNumber < m.modified.endLineNumberExclusive); const differentDiffs = diffBeforeEndOfMoveOriginal !== diffBeforeEndOfMoveModified; return differentDiffs; }); return moves; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function optimizeSequenceDiffs(sequence1, sequence2, sequenceDiffs) { let result = sequenceDiffs; result = joinSequenceDiffsByShifting(sequence1, sequence2, result); // Sometimes, calling this function twice improves the result. // Uncomment the second invocation and run the tests to see the difference. result = joinSequenceDiffsByShifting(sequence1, sequence2, result); result = shiftSequenceDiffs(sequence1, sequence2, result); return result; } /** * This function fixes issues like this: * ``` * import { Baz, Bar } from "foo"; * ``` * <-> * ``` * import { Baz, Bar, Foo } from "foo"; * ``` * Computed diff: [ {Add "," after Bar}, {Add "Foo " after space} } * Improved diff: [{Add ", Foo" after Bar}] */ function joinSequenceDiffsByShifting(sequence1, sequence2, sequenceDiffs) { if (sequenceDiffs.length === 0) { return sequenceDiffs; } const result = []; result.push(sequenceDiffs[0]); // First move them all to the left as much as possible and join them if possible for (let i = 1; i < sequenceDiffs.length; i++) { const prevResult = result[result.length - 1]; let cur = sequenceDiffs[i]; if (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) { const length = cur.seq1Range.start - prevResult.seq1Range.endExclusive; let d; for (d = 1; d <= length; d++) { if (sequence1.getElement(cur.seq1Range.start - d) !== sequence1.getElement(cur.seq1Range.endExclusive - d) || sequence2.getElement(cur.seq2Range.start - d) !== sequence2.getElement(cur.seq2Range.endExclusive - d)) { break; } } d--; if (d === length) { // Merge previous and current diff result[result.length - 1] = new SequenceDiff(new OffsetRange(prevResult.seq1Range.start, cur.seq1Range.endExclusive - length), new OffsetRange(prevResult.seq2Range.start, cur.seq2Range.endExclusive - length)); continue; } cur = cur.delta(-d); } result.push(cur); } const result2 = []; // Then move them all to the right and join them again if possible for (let i = 0; i < result.length - 1; i++) { const nextResult = result[i + 1]; let cur = result[i]; if (cur.seq1Range.isEmpty || cur.seq2Range.isEmpty) { const length = nextResult.seq1Range.start - cur.seq1Range.endExclusive; let d; for (d = 0; d < length; d++) { if (!sequence1.isStronglyEqual(cur.seq1Range.start + d, cur.seq1Range.endExclusive + d) || !sequence2.isStronglyEqual(cur.seq2Range.start + d, cur.seq2Range.endExclusive + d)) { break; } } if (d === length) { // Merge previous and current diff, write to result! result[i + 1] = new SequenceDiff(new OffsetRange(cur.seq1Range.start + length, nextResult.seq1Range.endExclusive), new OffsetRange(cur.seq2Range.start + length, nextResult.seq2Range.endExclusive)); continue; } if (d > 0) { cur = cur.delta(d); } } result2.push(cur); } if (result.length > 0) { result2.push(result[result.length - 1]); } return result2; } // align character level diffs at whitespace characters // import { IBar } from "foo"; // import { I[Arr, I]Bar } from "foo"; // -> // import { [IArr, ]IBar } from "foo"; // import { ITransaction, observableValue, transaction } from 'vs/base/common/observable'; // import { ITransaction, observable[FromEvent, observable]Value, transaction } from 'vs/base/common/observable'; // -> // import { ITransaction, [observableFromEvent, ]observableValue, transaction } from 'vs/base/common/observable'; // collectBrackets(level + 1, levelPerBracketType); // collectBrackets(level + 1, levelPerBracket[ + 1, levelPerBracket]Type); // -> // collectBrackets(level + 1, [levelPerBracket + 1, ]levelPerBracketType); function shiftSequenceDiffs(sequence1, sequence2, sequenceDiffs) { if (!sequence1.getBoundaryScore || !sequence2.getBoundaryScore) { return sequenceDiffs; } for (let i = 0; i < sequenceDiffs.length; i++) { const prevDiff = (i > 0 ? sequenceDiffs[i - 1] : undefined); const diff = sequenceDiffs[i]; const nextDiff = (i + 1 < sequenceDiffs.length ? sequenceDiffs[i + 1] : undefined); const seq1ValidRange = new OffsetRange(prevDiff ? prevDiff.seq1Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq1Range.start - 1 : sequence1.length); const seq2ValidRange = new OffsetRange(prevDiff ? prevDiff.seq2Range.endExclusive + 1 : 0, nextDiff ? nextDiff.seq2Range.start - 1 : sequence2.length); if (diff.seq1Range.isEmpty) { sequenceDiffs[i] = shiftDiffToBetterPosition(diff, sequence1, sequence2, seq1ValidRange, seq2ValidRange); } else if (diff.seq2Range.isEmpty) { sequenceDiffs[i] = shiftDiffToBetterPosition(diff.swap(), sequence2, sequence1, seq2ValidRange, seq1ValidRange).swap(); } } return sequenceDiffs; } function shiftDiffToBetterPosition(diff, sequence1, sequence2, seq1ValidRange, seq2ValidRange) { const maxShiftLimit = 100; // To prevent performance issues // don't touch previous or next! let deltaBefore = 1; while (diff.seq1Range.start - deltaBefore >= seq1ValidRange.start && diff.seq2Range.start - deltaBefore >= seq2ValidRange.start && sequence2.isStronglyEqual(diff.seq2Range.start - deltaBefore, diff.seq2Range.endExclusive - deltaBefore) && deltaBefore < maxShiftLimit) { deltaBefore++; } deltaBefore--; let deltaAfter = 0; while (diff.seq1Range.start + deltaAfter < seq1ValidRange.endExclusive && diff.seq2Range.endExclusive + deltaAfter < seq2ValidRange.endExclusive && sequence2.isStronglyEqual(diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter) && deltaAfter < maxShiftLimit) { deltaAfter++; } if (deltaBefore === 0 && deltaAfter === 0) { return diff; } // Visualize `[sequence1.text, diff.seq1Range.start + deltaAfter]` // and `[sequence2.text, diff.seq2Range.start + deltaAfter, diff.seq2Range.endExclusive + deltaAfter]` let bestDelta = 0; let bestScore = -1; // find best scored delta for (let delta = -deltaBefore; delta <= deltaAfter; delta++) { const seq2OffsetStart = diff.seq2Range.start + delta; const seq2OffsetEndExclusive = diff.seq2Range.endExclusive + delta; const seq1Offset = diff.seq1Range.start + delta; const score = sequence1.getBoundaryScore(seq1Offset) + sequence2.getBoundaryScore(seq2OffsetStart) + sequence2.getBoundaryScore(seq2OffsetEndExclusive); if (score > bestScore) { bestScore = score; bestDelta = delta; } } return diff.delta(bestDelta); } function removeShortMatches(sequence1, sequence2, sequenceDiffs) { const result = []; for (const s of sequenceDiffs) { const last = result[result.length - 1]; if (!last) { result.push(s); continue; } if (s.seq1Range.start - last.seq1Range.endExclusive <= 2 || s.seq2Range.start - last.seq2Range.endExclusive <= 2) { result[result.length - 1] = new SequenceDiff(last.seq1Range.join(s.seq1Range), last.seq2Range.join(s.seq2Range)); } else { result.push(s); } } return result; } function extendDiffsToEntireWordIfAppropriate(sequence1, sequence2, sequenceDiffs) { const equalMappings = SequenceDiff.invert(sequenceDiffs, sequence1.length); const additional = []; let lastPoint = new OffsetPair(0, 0); function scanWord(pair, equalMapping) { if (pair.offset1 < lastPoint.offset1 || pair.offset2 < lastPoint.offset2) { return; } const w1 = sequence1.findWordContaining(pair.offset1); const w2 = sequence2.findWordContaining(pair.offset2); if (!w1 || !w2) { return; } let w = new SequenceDiff(w1, w2); const equalPart = w.intersect(equalMapping); let equalChars1 = equalPart.seq1Range.length; let equalChars2 = equalPart.seq2Range.length; // The words do not touch previous equals mappings, as we would have processed them already. // But they might touch the next ones. while (equalMappings.length > 0) { const next = equalMappings[0]; const intersects = next.seq1Range.intersects(w.seq1Range) || next.seq2Range.intersects(w.seq2Range); if (!intersects) { break; } const v1 = sequence1.findWordContaining(next.seq1Range.start); const v2 = sequence2.findWordContaining(next.seq2Range.start); // Because there is an intersection, we know that the words are not empty. const v = new SequenceDiff(v1, v2); const equalPart = v.intersect(next); equalChars1 += equalPart.seq1Range.length; equalChars2 += equalPart.seq2Range.length; w = w.join(v); if (w.seq1Range.endExclusive >= next.seq1Range.endExclusive) { // The word extends beyond the next equal mapping. equalMappings.shift(); } else { break; } } if (equalChars1 + equalChars2 < (w.seq1Range.length + w.seq2Range.length) * 2 / 3) { additional.push(w); } lastPoint = w.getEndExclusives(); } while (equalMappings.length > 0) { const next = equalMappings.shift(); if (next.seq1Range.isEmpty) { continue; } scanWord(next.getStarts(), next); // The equal parts are not empty, so -1 gives us a character that is equal in both parts. scanWord(next.getEndExclusives().delta(-1), next); } const merged = mergeSequenceDiffs(sequenceDiffs, additional); return merged; } function mergeSequenceDiffs(sequenceDiffs1, sequenceDiffs2) { const result = []; while (sequenceDiffs1.length > 0 || sequenceDiffs2.length > 0) { const sd1 = sequenceDiffs1[0]; const sd2 = sequenceDiffs2[0]; let next; if (sd1 && (!sd2 || sd1.seq1Range.start < sd2.seq1Range.start)) { next = sequenceDiffs1.shift(); } else { next = sequenceDiffs2.shift(); } if (result.length > 0 && result[result.length - 1].seq1Range.endExclusive >= next.seq1Range.start) { result[result.length - 1] = result[result.length - 1].join(next); } else { result.push(next); } } return result; } function removeVeryShortMatchingLinesBetweenDiffs(sequence1, _sequence2, sequenceDiffs) { let diffs = sequenceDiffs; if (diffs.length === 0) { return diffs; } let counter = 0; let shouldRepeat; do { shouldRepeat = false; const result = [ diffs[0] ]; for (let i = 1; i < diffs.length; i++) { const cur = diffs[i]; const lastResult = result[result.length - 1]; function shouldJoinDiffs(before, after) { const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start); const unchangedText = sequence1.getText(unchangedRange); const unchangedTextWithoutWs = unchangedText.replace(/\s/g, ''); if (unchangedTextWithoutWs.length <= 4 && (before.seq1Range.length + before.seq2Range.length > 5 || after.seq1Range.length + after.seq2Range.length > 5)) { return true; } return false; } const shouldJoin = shouldJoinDiffs(lastResult, cur); if (shouldJoin) { shouldRepeat = true; result[result.length - 1] = result[result.length - 1].join(cur); } else { result.push(cur); } } diffs = result; } while (counter++ < 10 && shouldRepeat); return diffs; } function removeVeryShortMatchingTextBetweenLongDiffs(sequence1, sequence2, sequenceDiffs) { let diffs = sequenceDiffs; if (diffs.length === 0) { return diffs; } let counter = 0; let shouldRepeat; do { shouldRepeat = false; const result = [ diffs[0] ]; for (let i = 1; i < diffs.length; i++) { const cur = diffs[i]; const lastResult = result[result.length - 1]; function shouldJoinDiffs(before, after) { const unchangedRange = new OffsetRange(lastResult.seq1Range.endExclusive, cur.seq1Range.start); const unchangedLineCount = sequence1.countLinesIn(unchangedRange); if (unchangedLineCount > 5 || unchangedRange.length > 500) { return false; } const unchangedText = sequence1.getText(unchangedRange).trim(); if (unchangedText.length > 20 || unchangedText.split(/\r\n|\r|\n/).length > 1) { return false; } const beforeLineCount1 = sequence1.countLinesIn(before.seq1Range); const beforeSeq1Length = before.seq1Range.length; const beforeLineCount2 = sequence2.countLinesIn(before.seq2Range); const beforeSeq2Length = before.seq2Range.length; const afterLineCount1 = sequence1.countLinesIn(after.seq1Range); const afterSeq1Length = after.seq1Range.length; const afterLineCount2 = sequence2.countLinesIn(after.seq2Range); const afterSeq2Length = after.seq2Range.length; // TODO: Maybe a neural net can be used to derive the result from these numbers const max = 2 * 40 + 50; function cap(v) { return Math.min(v, max); } if (Math.pow(Math.pow(cap(beforeLineCount1 * 40 + beforeSeq1Length), 1.5) + Math.pow(cap(beforeLineCount2 * 40 + beforeSeq2Length), 1.5), 1.5) + Math.pow(Math.pow(cap(afterLineCount1 * 40 + afterSeq1Length), 1.5) + Math.pow(cap(afterLineCount2 * 40 + afterSeq2Length), 1.5), 1.5) > ((max ** 1.5) ** 1.5) * 1.3) { return true; } return false; } const shouldJoin = shouldJoinDiffs(lastResult, cur); if (shouldJoin) { shouldRepeat = true; result[result.length - 1] = result[result.length - 1].join(cur); } else { result.push(cur); } } diffs = result; } while (counter++ < 10 && shouldRepeat); const newDiffs = []; // Remove short suffixes/prefixes forEachWithNeighbors(diffs, (prev, cur, next) => { let newDiff = cur; function shouldMarkAsChanged(text) { return text.length > 0 && text.trim().length <= 3 && cur.seq1Range.length + cur.seq2Range.length > 100; } const fullRange1 = sequence1.extendToFullLines(cur.seq1Range); const prefix = sequence1.getText(new OffsetRange(fullRange1.start, cur.seq1Range.start)); if (shouldMarkAsChanged(prefix)) { newDiff = newDiff.deltaStart(-prefix.length); } const suffix = sequence1.getText(new OffsetRange(cur.seq1Range.endExclusive, fullRange1.endExclusive)); if (shouldMarkAsChanged(suffix)) { newDiff = newDiff.deltaEnd(suffix.length); } const availableSpace = SequenceDiff.fromOffsetPairs(prev ? prev.getEndExclusives() : OffsetPair.zero, next ? next.getStarts() : OffsetPair.max); const result = newDiff.intersect(availableSpace); if (newDiffs.length > 0 && result.getStarts().equals(newDiffs[newDiffs.length - 1].getEndExclusives())) { newDiffs[newDiffs.length - 1] = newDiffs[newDiffs.length - 1].join(result); } else { newDiffs.push(result); } }); return newDiffs; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class LineSequence { constructor(trimmedHash, lines) { this.trimmedHash = trimmedHash; this.lines = lines; } getElement(offset) { return this.trimmedHash[offset]; } get length() { return this.trimmedHash.length; } getBoundaryScore(length) { const indentationBefore = length === 0 ? 0 : getIndentation(this.lines[length - 1]); const indentationAfter = length === this.lines.length ? 0 : getIndentation(this.lines[length]); return 1000 - (indentationBefore + indentationAfter); } getText(range) { return this.lines.slice(range.start, range.endExclusive).join('\n'); } isStronglyEqual(offset1, offset2) { return this.lines[offset1] === this.lines[offset2]; } } function getIndentation(str) { let i = 0; while (i < str.length && (str.charCodeAt(i) === 32 /* CharCode.Space */ || str.charCodeAt(i) === 9 /* CharCode.Tab */)) { i++; } return i; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class DefaultLinesDiffComputer { constructor() { this.dynamicProgrammingDiffing = new DynamicProgrammingDiffing(); this.myersDiffingAlgorithm = new MyersDiffAlgorithm(); } computeDiff(originalLines, modifiedLines, options) { if (originalLines.length <= 1 && equals(originalLines, modifiedLines, (a, b) => a === b)) { return new LinesDiff([], [], false); } if (originalLines.length === 1 && originalLines[0].length === 0 || modifiedLines.length === 1 && modifiedLines[0].length === 0) { return new LinesDiff([ new DetailedLineRangeMapping(new LineRange(1, originalLines.length + 1), new LineRange(1, modifiedLines.length + 1), [ new RangeMapping(new Range(1, 1, originalLines.length, originalLines[originalLines.length - 1].length + 1), new Range(1, 1, modifiedLines.length, modifiedLines[modifiedLines.length - 1].length + 1)) ]) ], [], false); } const timeout = options.maxComputationTimeMs === 0 ? InfiniteTimeout.instance : new DateTimeout(options.maxComputationTimeMs); const considerWhitespaceChanges = !options.ignoreTrimWhitespace; const perfectHashes = new Map(); function getOrCreateHash(text) { let hash = perfectHashes.get(text); if (hash === undefined) { hash = perfectHashes.size; perfectHashes.set(text, hash); } return hash; } const originalLinesHashes = originalLines.map((l) => getOrCreateHash(l.trim())); const modifiedLinesHashes = modifiedLines.map((l) => getOrCreateHash(l.trim())); const sequence1 = new LineSequence(originalLinesHashes, originalLines); const sequence2 = new LineSequence(modifiedLinesHashes, modifiedLines); const lineAlignmentResult = (() => { if (sequence1.length + sequence2.length < 1700) { // Use the improved algorithm for small files return this.dynamicProgrammingDiffing.compute(sequence1, sequence2, timeout, (offset1, offset2) => originalLines[offset1] === modifiedLines[offset2] ? modifiedLines[offset2].length === 0 ? 0.1 : 1 + Math.log(1 + modifiedLines[offset2].length) : 0.99); } return this.myersDiffingAlgorithm.compute(sequence1, sequence2, timeout); })(); let lineAlignments = lineAlignmentResult.diffs; let hitTimeout = lineAlignmentResult.hitTimeout; lineAlignments = optimizeSequenceDiffs(sequence1, sequence2, lineAlignments); lineAlignments = removeVeryShortMatchingLinesBetweenDiffs(sequence1, sequence2, lineAlignments); const alignments = []; const scanForWhitespaceChanges = (equalLinesCount) => { if (!considerWhitespaceChanges) { return; } for (let i = 0; i < equalLinesCount; i++) { const seq1Offset = seq1LastStart + i; const seq2Offset = seq2LastStart + i; if (originalLines[seq1Offset] !== modifiedLines[seq2Offset]) { // This is because of whitespace changes, diff these lines const characterDiffs = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(new OffsetRange(seq1Offset, seq1Offset + 1), new OffsetRange(seq2Offset, seq2Offset + 1)), timeout, considerWhitespaceChanges); for (const a of characterDiffs.mappings) { alignments.push(a); } if (characterDiffs.hitTimeout) { hitTimeout = true; } } } }; let seq1LastStart = 0; let seq2LastStart = 0; for (const diff of lineAlignments) { assertFn(() => diff.seq1Range.start - seq1LastStart === diff.seq2Range.start - seq2LastStart); const equalLinesCount = diff.seq1Range.start - seq1LastStart; scanForWhitespaceChanges(equalLinesCount); seq1LastStart = diff.seq1Range.endExclusive; seq2LastStart = diff.seq2Range.endExclusive; const characterDiffs = this.refineDiff(originalLines, modifiedLines, diff, timeout, considerWhitespaceChanges); if (characterDiffs.hitTimeout) { hitTimeout = true; } for (const a of characterDiffs.mappings) { alignments.push(a); } } scanForWhitespaceChanges(originalLines.length - seq1LastStart); const changes = lineRangeMappingFromRangeMappings(alignments, originalLines, modifiedLines); let moves = []; if (options.computeMoves) { moves = this.computeMoves(changes, originalLines, modifiedLines, originalLinesHashes, modifiedLinesHashes, timeout, considerWhitespaceChanges); } // Make sure all ranges are valid assertFn(() => { function validatePosition(pos, lines) { if (pos.lineNumber < 1 || pos.lineNumber > lines.length) { return false; } const line = lines[pos.lineNumber - 1]; if (pos.column < 1 || pos.column > line.length + 1) { return false; } return true; } function validateRange(range, lines) { if (range.startLineNumber < 1 || range.startLineNumber > lines.length + 1) { return false; } if (range.endLineNumberExclusive < 1 || range.endLineNumberExclusive > lines.length + 1) { return false; } return true; } for (const c of changes) { if (!c.innerChanges) { return false; } for (const ic of c.innerChanges) { const valid = validatePosition(ic.modifiedRange.getStartPosition(), modifiedLines) && validatePosition(ic.modifiedRange.getEndPosition(), modifiedLines) && validatePosition(ic.originalRange.getStartPosition(), originalLines) && validatePosition(ic.originalRange.getEndPosition(), originalLines); if (!valid) { return false; } } if (!validateRange(c.modified, modifiedLines) || !validateRange(c.original, originalLines)) { return false; } } return true; }); return new LinesDiff(changes, moves, hitTimeout); } computeMoves(changes, originalLines, modifiedLines, hashedOriginalLines, hashedModifiedLines, timeout, considerWhitespaceChanges) { const moves = computeMovedLines(changes, originalLines, modifiedLines, hashedOriginalLines, hashedModifiedLines, timeout); const movesWithDiffs = moves.map(m => { const moveChanges = this.refineDiff(originalLines, modifiedLines, new SequenceDiff(m.original.toOffsetRange(), m.modified.toOffsetRange()), timeout, considerWhitespaceChanges); const mappings = lineRangeMappingFromRangeMappings(moveChanges.mappings, originalLines, modifiedLines, true); return new MovedText(m, mappings); }); return movesWithDiffs; } refineDiff(originalLines, modifiedLines, diff, timeout, considerWhitespaceChanges) { const lineRangeMapping = toLineRangeMapping(diff); const rangeMapping = lineRangeMapping.toRangeMapping2(originalLines, modifiedLines); const slice1 = new LinesSliceCharSequence(originalLines, rangeMapping.originalRange, considerWhitespaceChanges); const slice2 = new LinesSliceCharSequence(modifiedLines, rangeMapping.modifiedRange, considerWhitespaceChanges); const diffResult = slice1.length + slice2.length < 500 ? this.dynamicProgrammingDiffing.compute(slice1, slice2, timeout) : this.myersDiffingAlgorithm.compute(slice1, slice2, timeout); let diffs = diffResult.diffs; diffs = optimizeSequenceDiffs(slice1, slice2, diffs); diffs = extendDiffsToEntireWordIfAppropriate(slice1, slice2, diffs); diffs = removeShortMatches(slice1, slice2, diffs); diffs = removeVeryShortMatchingTextBetweenLongDiffs(slice1, slice2, diffs); const result = diffs.map((d) => new RangeMapping(slice1.translateRange(d.seq1Range), slice2.translateRange(d.seq2Range))); // Assert: result applied on original should be the same as diff applied to original return { mappings: result, hitTimeout: diffResult.hitTimeout, }; } } function lineRangeMappingFromRangeMappings(alignments, originalLines, modifiedLines, dontAssertStartLine = false) { const changes = []; for (const g of groupAdjacentBy(alignments.map(a => getLineRangeMapping(a, originalLines, modifiedLines)), (a1, a2) => a1.original.overlapOrTouch(a2.original) || a1.modified.overlapOrTouch(a2.modified))) { const first = g[0]; const last = g[g.length - 1]; changes.push(new DetailedLineRangeMapping(first.original.join(last.original), first.modified.join(last.modified), g.map(a => a.innerChanges[0]))); } assertFn(() => { if (!dontAssertStartLine && changes.length > 0) { if (changes[0].modified.startLineNumber !== changes[0].original.startLineNumber) { return false; } if (modifiedLines.length - changes[changes.length - 1].modified.endLineNumberExclusive !== originalLines.length - changes[changes.length - 1].original.endLineNumberExclusive) { return false; } } return checkAdjacentItems(changes, (m1, m2) => m2.original.startLineNumber - m1.original.endLineNumberExclusive === m2.modified.startLineNumber - m1.modified.endLineNumberExclusive && // There has to be an unchanged line in between (otherwise both diffs should have been joined) m1.original.endLineNumberExclusive < m2.original.startLineNumber && m1.modified.endLineNumberExclusive < m2.modified.startLineNumber); }); return changes; } function getLineRangeMapping(rangeMapping, originalLines, modifiedLines) { let lineStartDelta = 0; let lineEndDelta = 0; // rangeMapping describes the edit that replaces `rangeMapping.originalRange` with `newText := getText(modifiedLines, rangeMapping.modifiedRange)`. // original: ]xxx \n <- this line is not modified // modified: ]xx \n if (rangeMapping.modifiedRange.endColumn === 1 && rangeMapping.originalRange.endColumn === 1 && rangeMapping.originalRange.startLineNumber + lineStartDelta <= rangeMapping.originalRange.endLineNumber && rangeMapping.modifiedRange.startLineNumber + lineStartDelta <= rangeMapping.modifiedRange.endLineNumber) { // We can only do this if the range is not empty yet lineEndDelta = -1; } // original: xxx[ \n <- this line is not modified // modified: xxx[ \n if (rangeMapping.modifiedRange.startColumn - 1 >= modifiedLines[rangeMapping.modifiedRange.startLineNumber - 1].length && rangeMapping.originalRange.startColumn - 1 >= originalLines[rangeMapping.originalRange.startLineNumber - 1].length && rangeMapping.originalRange.startLineNumber <= rangeMapping.originalRange.endLineNumber + lineEndDelta && rangeMapping.modifiedRange.startLineNumber <= rangeMapping.modifiedRange.endLineNumber + lineEndDelta) { // We can only do this if the range is not empty yet lineStartDelta = 1; } const originalLineRange = new LineRange(rangeMapping.originalRange.startLineNumber + lineStartDelta, rangeMapping.originalRange.endLineNumber + 1 + lineEndDelta); const modifiedLineRange = new LineRange(rangeMapping.modifiedRange.startLineNumber + lineStartDelta, rangeMapping.modifiedRange.endLineNumber + 1 + lineEndDelta); return new DetailedLineRangeMapping(originalLineRange, modifiedLineRange, [rangeMapping]); } function toLineRangeMapping(sequenceDiff) { return new LineRangeMapping(new LineRange(sequenceDiff.seq1Range.start + 1, sequenceDiff.seq1Range.endExclusive + 1), new LineRange(sequenceDiff.seq2Range.start + 1, sequenceDiff.seq2Range.endExclusive + 1)); } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const linesDiffComputers = { getLegacy: () => new LegacyLinesDiffComputer(), getDefault: () => new DefaultLinesDiffComputer(), }; /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function roundFloat(number, decimalPoints) { const decimal = Math.pow(10, decimalPoints); return Math.round(number * decimal) / decimal; } class RGBA { constructor(r, g, b, a = 1) { this._rgbaBrand = undefined; this.r = Math.min(255, Math.max(0, r)) | 0; this.g = Math.min(255, Math.max(0, g)) | 0; this.b = Math.min(255, Math.max(0, b)) | 0; this.a = roundFloat(Math.max(Math.min(1, a), 0), 3); } static equals(a, b) { return a.r === b.r && a.g === b.g && a.b === b.b && a.a === b.a; } } class HSLA { constructor(h, s, l, a) { this._hslaBrand = undefined; this.h = Math.max(Math.min(360, h), 0) | 0; this.s = roundFloat(Math.max(Math.min(1, s), 0), 3); this.l = roundFloat(Math.max(Math.min(1, l), 0), 3); this.a = roundFloat(Math.max(Math.min(1, a), 0), 3); } static equals(a, b) { return a.h === b.h && a.s === b.s && a.l === b.l && a.a === b.a; } /** * Converts an RGB color value to HSL. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSL_color_space. * Assumes r, g, and b are contained in the set [0, 255] and * returns h in the set [0, 360], s, and l in the set [0, 1]. */ static fromRGBA(rgba) { const r = rgba.r / 255; const g = rgba.g / 255; const b = rgba.b / 255; const a = rgba.a; const max = Math.max(r, g, b); const min = Math.min(r, g, b); let h = 0; let s = 0; const l = (min + max) / 2; const chroma = max - min; if (chroma > 0) { s = Math.min((l <= 0.5 ? chroma / (2 * l) : chroma / (2 - (2 * l))), 1); switch (max) { case r: h = (g - b) / chroma + (g < b ? 6 : 0); break; case g: h = (b - r) / chroma + 2; break; case b: h = (r - g) / chroma + 4; break; } h *= 60; h = Math.round(h); } return new HSLA(h, s, l, a); } static _hue2rgb(p, q, t) { if (t < 0) { t += 1; } if (t > 1) { t -= 1; } if (t < 1 / 6) { return p + (q - p) * 6 * t; } if (t < 1 / 2) { return q; } if (t < 2 / 3) { return p + (q - p) * (2 / 3 - t) * 6; } return p; } /** * Converts an HSL color value to RGB. Conversion formula * adapted from http://en.wikipedia.org/wiki/HSL_color_space. * Assumes h in the set [0, 360] s, and l are contained in the set [0, 1] and * returns r, g, and b in the set [0, 255]. */ static toRGBA(hsla) { const h = hsla.h / 360; const { s, l, a } = hsla; let r, g, b; if (s === 0) { r = g = b = l; // achromatic } else { const q = l < 0.5 ? l * (1 + s) : l + s - l * s; const p = 2 * l - q; r = HSLA._hue2rgb(p, q, h + 1 / 3); g = HSLA._hue2rgb(p, q, h); b = HSLA._hue2rgb(p, q, h - 1 / 3); } return new RGBA(Math.round(r * 255), Math.round(g * 255), Math.round(b * 255), a); } } class HSVA { constructor(h, s, v, a) { this._hsvaBrand = undefined; this.h = Math.max(Math.min(360, h), 0) | 0; this.s = roundFloat(Math.max(Math.min(1, s), 0), 3); this.v = roundFloat(Math.max(Math.min(1, v), 0), 3); this.a = roundFloat(Math.max(Math.min(1, a), 0), 3); } static equals(a, b) { return a.h === b.h && a.s === b.s && a.v === b.v && a.a === b.a; } // from http://www.rapidtables.com/convert/color/rgb-to-hsv.htm static fromRGBA(rgba) { const r = rgba.r / 255; const g = rgba.g / 255; const b = rgba.b / 255; const cmax = Math.max(r, g, b); const cmin = Math.min(r, g, b); const delta = cmax - cmin; const s = cmax === 0 ? 0 : (delta / cmax); let m; if (delta === 0) { m = 0; } else if (cmax === r) { m = ((((g - b) / delta) % 6) + 6) % 6; } else if (cmax === g) { m = ((b - r) / delta) + 2; } else { m = ((r - g) / delta) + 4; } return new HSVA(Math.round(m * 60), s, cmax, rgba.a); } // from http://www.rapidtables.com/convert/color/hsv-to-rgb.htm static toRGBA(hsva) { const { h, s, v, a } = hsva; const c = v * s; const x = c * (1 - Math.abs((h / 60) % 2 - 1)); const m = v - c; let [r, g, b] = [0, 0, 0]; if (h < 60) { r = c; g = x; } else if (h < 120) { r = x; g = c; } else if (h < 180) { g = c; b = x; } else if (h < 240) { g = x; b = c; } else if (h < 300) { r = x; b = c; } else if (h <= 360) { r = c; b = x; } r = Math.round((r + m) * 255); g = Math.round((g + m) * 255); b = Math.round((b + m) * 255); return new RGBA(r, g, b, a); } } class Color { static fromHex(hex) { return Color.Format.CSS.parseHex(hex) || Color.red; } static equals(a, b) { if (!a && !b) { return true; } if (!a || !b) { return false; } return a.equals(b); } get hsla() { if (this._hsla) { return this._hsla; } else { return HSLA.fromRGBA(this.rgba); } } get hsva() { if (this._hsva) { return this._hsva; } return HSVA.fromRGBA(this.rgba); } constructor(arg) { if (!arg) { throw new Error('Color needs a value'); } else if (arg instanceof RGBA) { this.rgba = arg; } else if (arg instanceof HSLA) { this._hsla = arg; this.rgba = HSLA.toRGBA(arg); } else if (arg instanceof HSVA) { this._hsva = arg; this.rgba = HSVA.toRGBA(arg); } else { throw new Error('Invalid color ctor argument'); } } equals(other) { return !!other && RGBA.equals(this.rgba, other.rgba) && HSLA.equals(this.hsla, other.hsla) && HSVA.equals(this.hsva, other.hsva); } /** * http://www.w3.org/TR/WCAG20/#relativeluminancedef * Returns the number in the set [0, 1]. O => Darkest Black. 1 => Lightest white. */ getRelativeLuminance() { const R = Color._relativeLuminanceForComponent(this.rgba.r); const G = Color._relativeLuminanceForComponent(this.rgba.g); const B = Color._relativeLuminanceForComponent(this.rgba.b); const luminance = 0.2126 * R + 0.7152 * G + 0.0722 * B; return roundFloat(luminance, 4); } static _relativeLuminanceForComponent(color) { const c = color / 255; return (c <= 0.03928) ? c / 12.92 : Math.pow(((c + 0.055) / 1.055), 2.4); } /** * http://24ways.org/2010/calculating-color-contrast * Return 'true' if lighter color otherwise 'false' */ isLighter() { const yiq = (this.rgba.r * 299 + this.rgba.g * 587 + this.rgba.b * 114) / 1000; return yiq >= 128; } isLighterThan(another) { const lum1 = this.getRelativeLuminance(); const lum2 = another.getRelativeLuminance(); return lum1 > lum2; } isDarkerThan(another) { const lum1 = this.getRelativeLuminance(); const lum2 = another.getRelativeLuminance(); return lum1 < lum2; } lighten(factor) { return new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l + this.hsla.l * factor, this.hsla.a)); } darken(factor) { return new Color(new HSLA(this.hsla.h, this.hsla.s, this.hsla.l - this.hsla.l * factor, this.hsla.a)); } transparent(factor) { const { r, g, b, a } = this.rgba; return new Color(new RGBA(r, g, b, a * factor)); } isTransparent() { return this.rgba.a === 0; } isOpaque() { return this.rgba.a === 1; } opposite() { return new Color(new RGBA(255 - this.rgba.r, 255 - this.rgba.g, 255 - this.rgba.b, this.rgba.a)); } makeOpaque(opaqueBackground) { if (this.isOpaque() || opaqueBackground.rgba.a !== 1) { // only allow to blend onto a non-opaque color onto a opaque color return this; } const { r, g, b, a } = this.rgba; // https://stackoverflow.com/questions/12228548/finding-equivalent-color-with-opacity return new Color(new RGBA(opaqueBackground.rgba.r - a * (opaqueBackground.rgba.r - r), opaqueBackground.rgba.g - a * (opaqueBackground.rgba.g - g), opaqueBackground.rgba.b - a * (opaqueBackground.rgba.b - b), 1)); } toString() { if (!this._toString) { this._toString = Color.Format.CSS.format(this); } return this._toString; } static getLighterColor(of, relative, factor) { if (of.isLighterThan(relative)) { return of; } factor = factor ? factor : 0.5; const lum1 = of.getRelativeLuminance(); const lum2 = relative.getRelativeLuminance(); factor = factor * (lum2 - lum1) / lum2; return of.lighten(factor); } static getDarkerColor(of, relative, factor) { if (of.isDarkerThan(relative)) { return of; } factor = factor ? factor : 0.5; const lum1 = of.getRelativeLuminance(); const lum2 = relative.getRelativeLuminance(); factor = factor * (lum1 - lum2) / lum1; return of.darken(factor); } static { this.white = new Color(new RGBA(255, 255, 255, 1)); } static { this.black = new Color(new RGBA(0, 0, 0, 1)); } static { this.red = new Color(new RGBA(255, 0, 0, 1)); } static { this.blue = new Color(new RGBA(0, 0, 255, 1)); } static { this.green = new Color(new RGBA(0, 255, 0, 1)); } static { this.cyan = new Color(new RGBA(0, 255, 255, 1)); } static { this.lightgrey = new Color(new RGBA(211, 211, 211, 1)); } static { this.transparent = new Color(new RGBA(0, 0, 0, 0)); } } (function (Color) { (function (Format) { (function (CSS) { function formatRGB(color) { if (color.rgba.a === 1) { return `rgb(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b})`; } return Color.Format.CSS.formatRGBA(color); } CSS.formatRGB = formatRGB; function formatRGBA(color) { return `rgba(${color.rgba.r}, ${color.rgba.g}, ${color.rgba.b}, ${+(color.rgba.a).toFixed(2)})`; } CSS.formatRGBA = formatRGBA; function formatHSL(color) { if (color.hsla.a === 1) { return `hsl(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%)`; } return Color.Format.CSS.formatHSLA(color); } CSS.formatHSL = formatHSL; function formatHSLA(color) { return `hsla(${color.hsla.h}, ${(color.hsla.s * 100).toFixed(2)}%, ${(color.hsla.l * 100).toFixed(2)}%, ${color.hsla.a.toFixed(2)})`; } CSS.formatHSLA = formatHSLA; function _toTwoDigitHex(n) { const r = n.toString(16); return r.length !== 2 ? '0' + r : r; } /** * Formats the color as #RRGGBB */ function formatHex(color) { return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}`; } CSS.formatHex = formatHex; /** * Formats the color as #RRGGBBAA * If 'compact' is set, colors without transparancy will be printed as #RRGGBB */ function formatHexA(color, compact = false) { if (compact && color.rgba.a === 1) { return Color.Format.CSS.formatHex(color); } return `#${_toTwoDigitHex(color.rgba.r)}${_toTwoDigitHex(color.rgba.g)}${_toTwoDigitHex(color.rgba.b)}${_toTwoDigitHex(Math.round(color.rgba.a * 255))}`; } CSS.formatHexA = formatHexA; /** * The default format will use HEX if opaque and RGBA otherwise. */ function format(color) { if (color.isOpaque()) { return Color.Format.CSS.formatHex(color); } return Color.Format.CSS.formatRGBA(color); } CSS.format = format; /** * Converts an Hex color value to a Color. * returns r, g, and b are contained in the set [0, 255] * @param hex string (#RGB, #RGBA, #RRGGBB or #RRGGBBAA). */ function parseHex(hex) { const length = hex.length; if (length === 0) { // Invalid color return null; } if (hex.charCodeAt(0) !== 35 /* CharCode.Hash */) { // Does not begin with a # return null; } if (length === 7) { // #RRGGBB format const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2)); const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4)); const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6)); return new Color(new RGBA(r, g, b, 1)); } if (length === 9) { // #RRGGBBAA format const r = 16 * _parseHexDigit(hex.charCodeAt(1)) + _parseHexDigit(hex.charCodeAt(2)); const g = 16 * _parseHexDigit(hex.charCodeAt(3)) + _parseHexDigit(hex.charCodeAt(4)); const b = 16 * _parseHexDigit(hex.charCodeAt(5)) + _parseHexDigit(hex.charCodeAt(6)); const a = 16 * _parseHexDigit(hex.charCodeAt(7)) + _parseHexDigit(hex.charCodeAt(8)); return new Color(new RGBA(r, g, b, a / 255)); } if (length === 4) { // #RGB format const r = _parseHexDigit(hex.charCodeAt(1)); const g = _parseHexDigit(hex.charCodeAt(2)); const b = _parseHexDigit(hex.charCodeAt(3)); return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b)); } if (length === 5) { // #RGBA format const r = _parseHexDigit(hex.charCodeAt(1)); const g = _parseHexDigit(hex.charCodeAt(2)); const b = _parseHexDigit(hex.charCodeAt(3)); const a = _parseHexDigit(hex.charCodeAt(4)); return new Color(new RGBA(16 * r + r, 16 * g + g, 16 * b + b, (16 * a + a) / 255)); } // Invalid color return null; } CSS.parseHex = parseHex; function _parseHexDigit(charCode) { switch (charCode) { case 48 /* CharCode.Digit0 */: return 0; case 49 /* CharCode.Digit1 */: return 1; case 50 /* CharCode.Digit2 */: return 2; case 51 /* CharCode.Digit3 */: return 3; case 52 /* CharCode.Digit4 */: return 4; case 53 /* CharCode.Digit5 */: return 5; case 54 /* CharCode.Digit6 */: return 6; case 55 /* CharCode.Digit7 */: return 7; case 56 /* CharCode.Digit8 */: return 8; case 57 /* CharCode.Digit9 */: return 9; case 97 /* CharCode.a */: return 10; case 65 /* CharCode.A */: return 10; case 98 /* CharCode.b */: return 11; case 66 /* CharCode.B */: return 11; case 99 /* CharCode.c */: return 12; case 67 /* CharCode.C */: return 12; case 100 /* CharCode.d */: return 13; case 68 /* CharCode.D */: return 13; case 101 /* CharCode.e */: return 14; case 69 /* CharCode.E */: return 14; case 102 /* CharCode.f */: return 15; case 70 /* CharCode.F */: return 15; } return 0; } })(Format.CSS || (Format.CSS = {})); })(Color.Format || (Color.Format = {})); })(Color || (Color = {})); /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ function _parseCaptureGroups(captureGroups) { const values = []; for (const captureGroup of captureGroups) { const parsedNumber = Number(captureGroup); if (parsedNumber || parsedNumber === 0 && captureGroup.replace(/\s/g, '') !== '') { values.push(parsedNumber); } } return values; } function _toIColor(r, g, b, a) { return { red: r / 255, blue: b / 255, green: g / 255, alpha: a }; } function _findRange(model, match) { const index = match.index; const length = match[0].length; if (!index) { return; } const startPosition = model.positionAt(index); const range = { startLineNumber: startPosition.lineNumber, startColumn: startPosition.column, endLineNumber: startPosition.lineNumber, endColumn: startPosition.column + length }; return range; } function _findHexColorInformation(range, hexValue) { if (!range) { return; } const parsedHexColor = Color.Format.CSS.parseHex(hexValue); if (!parsedHexColor) { return; } return { range: range, color: _toIColor(parsedHexColor.rgba.r, parsedHexColor.rgba.g, parsedHexColor.rgba.b, parsedHexColor.rgba.a) }; } function _findRGBColorInformation(range, matches, isAlpha) { if (!range || matches.length !== 1) { return; } const match = matches[0]; const captureGroups = match.values(); const parsedRegex = _parseCaptureGroups(captureGroups); return { range: range, color: _toIColor(parsedRegex[0], parsedRegex[1], parsedRegex[2], isAlpha ? parsedRegex[3] : 1) }; } function _findHSLColorInformation(range, matches, isAlpha) { if (!range || matches.length !== 1) { return; } const match = matches[0]; const captureGroups = match.values(); const parsedRegex = _parseCaptureGroups(captureGroups); const colorEquivalent = new Color(new HSLA(parsedRegex[0], parsedRegex[1] / 100, parsedRegex[2] / 100, isAlpha ? parsedRegex[3] : 1)); return { range: range, color: _toIColor(colorEquivalent.rgba.r, colorEquivalent.rgba.g, colorEquivalent.rgba.b, colorEquivalent.rgba.a) }; } function _findMatches(model, regex) { if (typeof model === 'string') { return [...model.matchAll(regex)]; } else { return model.findMatches(regex); } } function computeColors(model) { const result = []; // Early validation for RGB and HSL const initialValidationRegex = /\b(rgb|rgba|hsl|hsla)(\([0-9\s,.\%]*\))|(#)([A-Fa-f0-9]{3})\b|(#)([A-Fa-f0-9]{4})\b|(#)([A-Fa-f0-9]{6})\b|(#)([A-Fa-f0-9]{8})\b/gm; const initialValidationMatches = _findMatches(model, initialValidationRegex); // Potential colors have been found, validate the parameters if (initialValidationMatches.length > 0) { for (const initialMatch of initialValidationMatches) { const initialCaptureGroups = initialMatch.filter(captureGroup => captureGroup !== undefined); const colorScheme = initialCaptureGroups[1]; const colorParameters = initialCaptureGroups[2]; if (!colorParameters) { continue; } let colorInformation; if (colorScheme === 'rgb') { const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*\)$/gm; colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false); } else if (colorScheme === 'rgba') { const regexParameters = /^\(\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(25[0-5]|2[0-4][0-9]|1[0-9]{2}|[1-9][0-9]|[0-9])\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm; colorInformation = _findRGBColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true); } else if (colorScheme === 'hsl') { const regexParameters = /^\(\s*(36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*\)$/gm; colorInformation = _findHSLColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), false); } else if (colorScheme === 'hsla') { const regexParameters = /^\(\s*(36[0]|3[0-5][0-9]|[12][0-9][0-9]|[1-9]?[0-9])\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(100|\d{1,2}[.]\d*|\d{1,2})%\s*,\s*(0[.][0-9]+|[.][0-9]+|[01][.]|[01])\s*\)$/gm; colorInformation = _findHSLColorInformation(_findRange(model, initialMatch), _findMatches(colorParameters, regexParameters), true); } else if (colorScheme === '#') { colorInformation = _findHexColorInformation(_findRange(model, initialMatch), colorScheme + colorParameters); } if (colorInformation) { result.push(colorInformation); } } } return result; } /** * Returns an array of all default document colors in the provided document */ function computeDefaultDocumentColors(model) { if (!model || typeof model.getValue !== 'function' || typeof model.positionAt !== 'function') { // Unknown caller! return []; } return computeColors(model); } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ const markRegex = new RegExp('\\bMARK:\\s*(.*)$', 'd'); const trimDashesRegex = /^-+|-+$/g; /** * Find section headers in the model. * * @param model the text model to search in * @param options options to search with * @returns an array of section headers */ function findSectionHeaders(model, options) { let headers = []; if (options.findRegionSectionHeaders && options.foldingRules?.markers) { const regionHeaders = collectRegionHeaders(model, options); headers = headers.concat(regionHeaders); } if (options.findMarkSectionHeaders) { const markHeaders = collectMarkHeaders(model); headers = headers.concat(markHeaders); } return headers; } function collectRegionHeaders(model, options) { const regionHeaders = []; const endLineNumber = model.getLineCount(); for (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) { const lineContent = model.getLineContent(lineNumber); const match = lineContent.match(options.foldingRules.markers.start); if (match) { const range = { startLineNumber: lineNumber, startColumn: match[0].length + 1, endLineNumber: lineNumber, endColumn: lineContent.length + 1 }; if (range.endColumn > range.startColumn) { const sectionHeader = { range, ...getHeaderText(lineContent.substring(match[0].length)), shouldBeInComments: false }; if (sectionHeader.text || sectionHeader.hasSeparatorLine) { regionHeaders.push(sectionHeader); } } } } return regionHeaders; } function collectMarkHeaders(model) { const markHeaders = []; const endLineNumber = model.getLineCount(); for (let lineNumber = 1; lineNumber <= endLineNumber; lineNumber++) { const lineContent = model.getLineContent(lineNumber); addMarkHeaderIfFound(lineContent, lineNumber, markHeaders); } return markHeaders; } function addMarkHeaderIfFound(lineContent, lineNumber, sectionHeaders) { markRegex.lastIndex = 0; const match = markRegex.exec(lineContent); if (match) { const column = match.indices[1][0] + 1; const endColumn = match.indices[1][1] + 1; const range = { startLineNumber: lineNumber, startColumn: column, endLineNumber: lineNumber, endColumn: endColumn }; if (range.endColumn > range.startColumn) { const sectionHeader = { range, ...getHeaderText(match[1]), shouldBeInComments: true }; if (sectionHeader.text || sectionHeader.hasSeparatorLine) { sectionHeaders.push(sectionHeader); } } } } function getHeaderText(text) { text = text.trim(); const hasSeparatorLine = text.startsWith('-'); text = text.replace(trimDashesRegex, ''); return { text, hasSeparatorLine }; } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ //#endregion //#region Promises var Promises; (function (Promises) { /** * A drop-in replacement for `Promise.all` with the only difference * that the method awaits every promise to either fulfill or reject. * * Similar to `Promise.all`, only the first error will be returned * if any. */ async function settled(promises) { let firstError = undefined; const result = await Promise.all(promises.map(promise => promise.then(value => value, error => { if (!firstError) { firstError = error; } return undefined; // do not rethrow so that other promises can settle }))); if (typeof firstError !== 'undefined') { throw firstError; } return result; // cast is needed and protected by the `throw` above } Promises.settled = settled; /** * A helper to create a new `Promise` with a body that is a promise * itself. By default, an error that raises from the async body will * end up as a unhandled rejection, so this utility properly awaits the * body and rejects the promise as a normal promise does without async * body. * * This method should only be used in rare cases where otherwise `async` * cannot be used (e.g. when callbacks are involved that require this). */ function withAsyncBody(bodyFn) { // eslint-disable-next-line no-async-promise-executor return new Promise(async (resolve, reject) => { try { await bodyFn(resolve, reject); } catch (error) { reject(error); } }); } Promises.withAsyncBody = withAsyncBody; })(Promises || (Promises = {})); /** * A rich implementation for an `AsyncIterable`. */ class AsyncIterableObject { static fromArray(items) { return new AsyncIterableObject((writer) => { writer.emitMany(items); }); } static fromPromise(promise) { return new AsyncIterableObject(async (emitter) => { emitter.emitMany(await promise); }); } static fromPromises(promises) { return new AsyncIterableObject(async (emitter) => { await Promise.all(promises.map(async (p) => emitter.emitOne(await p))); }); } static merge(iterables) { return new AsyncIterableObject(async (emitter) => { await Promise.all(iterables.map(async (iterable) => { for await (const item of iterable) { emitter.emitOne(item); } })); }); } static { this.EMPTY = AsyncIterableObject.fromArray([]); } constructor(executor, onReturn) { this._state = 0 /* AsyncIterableSourceState.Initial */; this._results = []; this._error = null; this._onReturn = onReturn; this._onStateChanged = new Emitter(); queueMicrotask(async () => { const writer = { emitOne: (item) => this.emitOne(item), emitMany: (items) => this.emitMany(items), reject: (error) => this.reject(error) }; try { await Promise.resolve(executor(writer)); this.resolve(); } catch (err) { this.reject(err); } finally { writer.emitOne = undefined; writer.emitMany = undefined; writer.reject = undefined; } }); } [Symbol.asyncIterator]() { let i = 0; return { next: async () => { do { if (this._state === 2 /* AsyncIterableSourceState.DoneError */) { throw this._error; } if (i < this._results.length) { return { done: false, value: this._results[i++] }; } if (this._state === 1 /* AsyncIterableSourceState.DoneOK */) { return { done: true, value: undefined }; } await Event.toPromise(this._onStateChanged.event); } while (true); }, return: async () => { this._onReturn?.(); return { done: true, value: undefined }; } }; } static map(iterable, mapFn) { return new AsyncIterableObject(async (emitter) => { for await (const item of iterable) { emitter.emitOne(mapFn(item)); } }); } map(mapFn) { return AsyncIterableObject.map(this, mapFn); } static filter(iterable, filterFn) { return new AsyncIterableObject(async (emitter) => { for await (const item of iterable) { if (filterFn(item)) { emitter.emitOne(item); } } }); } filter(filterFn) { return AsyncIterableObject.filter(this, filterFn); } static coalesce(iterable) { return AsyncIterableObject.filter(iterable, item => !!item); } coalesce() { return AsyncIterableObject.coalesce(this); } static async toPromise(iterable) { const result = []; for await (const item of iterable) { result.push(item); } return result; } toPromise() { return AsyncIterableObject.toPromise(this); } /** * The value will be appended at the end. * * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ emitOne(value) { if (this._state !== 0 /* AsyncIterableSourceState.Initial */) { return; } // it is important to add new values at the end, // as we may have iterators already running on the array this._results.push(value); this._onStateChanged.fire(); } /** * The values will be appended at the end. * * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ emitMany(values) { if (this._state !== 0 /* AsyncIterableSourceState.Initial */) { return; } // it is important to add new values at the end, // as we may have iterators already running on the array this._results = this._results.concat(values); this._onStateChanged.fire(); } /** * Calling `resolve()` will mark the result array as complete. * * **NOTE** `resolve()` must be called, otherwise all consumers of this iterable will hang indefinitely, similar to a non-resolved promise. * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ resolve() { if (this._state !== 0 /* AsyncIterableSourceState.Initial */) { return; } this._state = 1 /* AsyncIterableSourceState.DoneOK */; this._onStateChanged.fire(); } /** * Writing an error will permanently invalidate this iterable. * The current users will receive an error thrown, as will all future users. * * **NOTE** If `resolve()` or `reject()` have already been called, this method has no effect. */ reject(error) { if (this._state !== 0 /* AsyncIterableSourceState.Initial */) { return; } this._state = 2 /* AsyncIterableSourceState.DoneError */; this._error = error; this._onStateChanged.fire(); } } //#endregion /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class PrefixSumComputer { constructor(values) { this.values = values; this.prefixSum = new Uint32Array(values.length); this.prefixSumValidIndex = new Int32Array(1); this.prefixSumValidIndex[0] = -1; } insertValues(insertIndex, insertValues) { insertIndex = toUint32(insertIndex); const oldValues = this.values; const oldPrefixSum = this.prefixSum; const insertValuesLen = insertValues.length; if (insertValuesLen === 0) { return false; } this.values = new Uint32Array(oldValues.length + insertValuesLen); this.values.set(oldValues.subarray(0, insertIndex), 0); this.values.set(oldValues.subarray(insertIndex), insertIndex + insertValuesLen); this.values.set(insertValues, insertIndex); if (insertIndex - 1 < this.prefixSumValidIndex[0]) { this.prefixSumValidIndex[0] = insertIndex - 1; } this.prefixSum = new Uint32Array(this.values.length); if (this.prefixSumValidIndex[0] >= 0) { this.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1)); } return true; } setValue(index, value) { index = toUint32(index); value = toUint32(value); if (this.values[index] === value) { return false; } this.values[index] = value; if (index - 1 < this.prefixSumValidIndex[0]) { this.prefixSumValidIndex[0] = index - 1; } return true; } removeValues(startIndex, count) { startIndex = toUint32(startIndex); count = toUint32(count); const oldValues = this.values; const oldPrefixSum = this.prefixSum; if (startIndex >= oldValues.length) { return false; } const maxCount = oldValues.length - startIndex; if (count >= maxCount) { count = maxCount; } if (count === 0) { return false; } this.values = new Uint32Array(oldValues.length - count); this.values.set(oldValues.subarray(0, startIndex), 0); this.values.set(oldValues.subarray(startIndex + count), startIndex); this.prefixSum = new Uint32Array(this.values.length); if (startIndex - 1 < this.prefixSumValidIndex[0]) { this.prefixSumValidIndex[0] = startIndex - 1; } if (this.prefixSumValidIndex[0] >= 0) { this.prefixSum.set(oldPrefixSum.subarray(0, this.prefixSumValidIndex[0] + 1)); } return true; } getTotalSum() { if (this.values.length === 0) { return 0; } return this._getPrefixSum(this.values.length - 1); } /** * Returns the sum of the first `index + 1` many items. * @returns `SUM(0 <= j <= index, values[j])`. */ getPrefixSum(index) { if (index < 0) { return 0; } index = toUint32(index); return this._getPrefixSum(index); } _getPrefixSum(index) { if (index <= this.prefixSumValidIndex[0]) { return this.prefixSum[index]; } let startIndex = this.prefixSumValidIndex[0] + 1; if (startIndex === 0) { this.prefixSum[0] = this.values[0]; startIndex++; } if (index >= this.values.length) { index = this.values.length - 1; } for (let i = startIndex; i <= index; i++) { this.prefixSum[i] = this.prefixSum[i - 1] + this.values[i]; } this.prefixSumValidIndex[0] = Math.max(this.prefixSumValidIndex[0], index); return this.prefixSum[index]; } getIndexOf(sum) { sum = Math.floor(sum); // Compute all sums (to get a fully valid prefixSum) this.getTotalSum(); let low = 0; let high = this.values.length - 1; let mid = 0; let midStop = 0; let midStart = 0; while (low <= high) { mid = low + ((high - low) / 2) | 0; midStop = this.prefixSum[mid]; midStart = midStop - this.values[mid]; if (sum < midStart) { high = mid - 1; } else if (sum >= midStop) { low = mid + 1; } else { break; } } return new PrefixSumIndexOfResult(mid, sum - midStart); } } class PrefixSumIndexOfResult { constructor(index, remainder) { this.index = index; this.remainder = remainder; this._prefixSumIndexOfResultBrand = undefined; this.index = index; this.remainder = remainder; } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class MirrorTextModel { constructor(uri, lines, eol, versionId) { this._uri = uri; this._lines = lines; this._eol = eol; this._versionId = versionId; this._lineStarts = null; this._cachedTextValue = null; } dispose() { this._lines.length = 0; } get version() { return this._versionId; } getText() { if (this._cachedTextValue === null) { this._cachedTextValue = this._lines.join(this._eol); } return this._cachedTextValue; } onEvents(e) { if (e.eol && e.eol !== this._eol) { this._eol = e.eol; this._lineStarts = null; } // Update my lines const changes = e.changes; for (const change of changes) { this._acceptDeleteRange(change.range); this._acceptInsertText(new Position(change.range.startLineNumber, change.range.startColumn), change.text); } this._versionId = e.versionId; this._cachedTextValue = null; } _ensureLineStarts() { if (!this._lineStarts) { const eolLength = this._eol.length; const linesLength = this._lines.length; const lineStartValues = new Uint32Array(linesLength); for (let i = 0; i < linesLength; i++) { lineStartValues[i] = this._lines[i].length + eolLength; } this._lineStarts = new PrefixSumComputer(lineStartValues); } } /** * All changes to a line's text go through this method */ _setLineText(lineIndex, newValue) { this._lines[lineIndex] = newValue; if (this._lineStarts) { // update prefix sum this._lineStarts.setValue(lineIndex, this._lines[lineIndex].length + this._eol.length); } } _acceptDeleteRange(range) { if (range.startLineNumber === range.endLineNumber) { if (range.startColumn === range.endColumn) { // Nothing to delete return; } // Delete text on the affected line this._setLineText(range.startLineNumber - 1, this._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1) + this._lines[range.startLineNumber - 1].substring(range.endColumn - 1)); return; } // Take remaining text on last line and append it to remaining text on first line this._setLineText(range.startLineNumber - 1, this._lines[range.startLineNumber - 1].substring(0, range.startColumn - 1) + this._lines[range.endLineNumber - 1].substring(range.endColumn - 1)); // Delete middle lines this._lines.splice(range.startLineNumber, range.endLineNumber - range.startLineNumber); if (this._lineStarts) { // update prefix sum this._lineStarts.removeValues(range.startLineNumber, range.endLineNumber - range.startLineNumber); } } _acceptInsertText(position, insertText) { if (insertText.length === 0) { // Nothing to insert return; } const insertLines = splitLines(insertText); if (insertLines.length === 1) { // Inserting text on one line this._setLineText(position.lineNumber - 1, this._lines[position.lineNumber - 1].substring(0, position.column - 1) + insertLines[0] + this._lines[position.lineNumber - 1].substring(position.column - 1)); return; } // Append overflowing text from first line to the end of text to insert insertLines[insertLines.length - 1] += this._lines[position.lineNumber - 1].substring(position.column - 1); // Delete overflowing text from first line and insert text on first line this._setLineText(position.lineNumber - 1, this._lines[position.lineNumber - 1].substring(0, position.column - 1) + insertLines[0]); // Insert new lines & store lengths const newLengths = new Uint32Array(insertLines.length - 1); for (let i = 1; i < insertLines.length; i++) { this._lines.splice(position.lineNumber + i - 1, 0, insertLines[i]); newLengths[i - 1] = insertLines[i].length + this._eol.length; } if (this._lineStarts) { // update prefix sum this._lineStarts.insertValues(position.lineNumber, newLengths); } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ class WorkerTextModelSyncServer { constructor() { this._models = Object.create(null); } getModel(uri) { return this._models[uri]; } getModels() { const all = []; Object.keys(this._models).forEach((key) => all.push(this._models[key])); return all; } $acceptNewModel(data) { this._models[data.url] = new MirrorModel(URI.parse(data.url), data.lines, data.EOL, data.versionId); } $acceptModelChanged(uri, e) { if (!this._models[uri]) { return; } const model = this._models[uri]; model.onEvents(e); } $acceptRemovedModel(uri) { if (!this._models[uri]) { return; } delete this._models[uri]; } } class MirrorModel extends MirrorTextModel { get uri() { return this._uri; } get eol() { return this._eol; } getValue() { return this.getText(); } findMatches(regex) { const matches = []; for (let i = 0; i < this._lines.length; i++) { const line = this._lines[i]; const offsetToAdd = this.offsetAt(new Position(i + 1, 1)); const iteratorOverMatches = line.matchAll(regex); for (const match of iteratorOverMatches) { if (match.index || match.index === 0) { match.index = match.index + offsetToAdd; } matches.push(match); } } return matches; } getLinesContent() { return this._lines.slice(0); } getLineCount() { return this._lines.length; } getLineContent(lineNumber) { return this._lines[lineNumber - 1]; } getWordAtPosition(position, wordDefinition) { const wordAtText = getWordAtText(position.column, ensureValidWordDefinition(wordDefinition), this._lines[position.lineNumber - 1], 0); if (wordAtText) { return new Range(position.lineNumber, wordAtText.startColumn, position.lineNumber, wordAtText.endColumn); } return null; } words(wordDefinition) { const lines = this._lines; const wordenize = this._wordenize.bind(this); let lineNumber = 0; let lineText = ''; let wordRangesIdx = 0; let wordRanges = []; return { *[Symbol.iterator]() { while (true) { if (wordRangesIdx < wordRanges.length) { const value = lineText.substring(wordRanges[wordRangesIdx].start, wordRanges[wordRangesIdx].end); wordRangesIdx += 1; yield value; } else { if (lineNumber < lines.length) { lineText = lines[lineNumber]; wordRanges = wordenize(lineText, wordDefinition); wordRangesIdx = 0; lineNumber += 1; } else { break; } } } } }; } getLineWords(lineNumber, wordDefinition) { const content = this._lines[lineNumber - 1]; const ranges = this._wordenize(content, wordDefinition); const words = []; for (const range of ranges) { words.push({ word: content.substring(range.start, range.end), startColumn: range.start + 1, endColumn: range.end + 1 }); } return words; } _wordenize(content, wordDefinition) { const result = []; let match; wordDefinition.lastIndex = 0; // reset lastIndex just to be sure while (match = wordDefinition.exec(content)) { if (match[0].length === 0) { // it did match the empty string break; } result.push({ start: match.index, end: match.index + match[0].length }); } return result; } getValueInRange(range) { range = this._validateRange(range); if (range.startLineNumber === range.endLineNumber) { return this._lines[range.startLineNumber - 1].substring(range.startColumn - 1, range.endColumn - 1); } const lineEnding = this._eol; const startLineIndex = range.startLineNumber - 1; const endLineIndex = range.endLineNumber - 1; const resultLines = []; resultLines.push(this._lines[startLineIndex].substring(range.startColumn - 1)); for (let i = startLineIndex + 1; i < endLineIndex; i++) { resultLines.push(this._lines[i]); } resultLines.push(this._lines[endLineIndex].substring(0, range.endColumn - 1)); return resultLines.join(lineEnding); } offsetAt(position) { position = this._validatePosition(position); this._ensureLineStarts(); return this._lineStarts.getPrefixSum(position.lineNumber - 2) + (position.column - 1); } positionAt(offset) { offset = Math.floor(offset); offset = Math.max(0, offset); this._ensureLineStarts(); const out = this._lineStarts.getIndexOf(offset); const lineLength = this._lines[out.index].length; // Ensure we return a valid position return { lineNumber: 1 + out.index, column: 1 + Math.min(out.remainder, lineLength) }; } _validateRange(range) { const start = this._validatePosition({ lineNumber: range.startLineNumber, column: range.startColumn }); const end = this._validatePosition({ lineNumber: range.endLineNumber, column: range.endColumn }); if (start.lineNumber !== range.startLineNumber || start.column !== range.startColumn || end.lineNumber !== range.endLineNumber || end.column !== range.endColumn) { return { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column }; } return range; } _validatePosition(position) { if (!Position.isIPosition(position)) { throw new Error('bad position'); } let { lineNumber, column } = position; let hasChanged = false; if (lineNumber < 1) { lineNumber = 1; column = 1; hasChanged = true; } else if (lineNumber > this._lines.length) { lineNumber = this._lines.length; column = this._lines[lineNumber - 1].length + 1; hasChanged = true; } else { const maxCharacter = this._lines[lineNumber - 1].length + 1; if (column < 1) { column = 1; hasChanged = true; } else if (column > maxCharacter) { column = maxCharacter; hasChanged = true; } } if (!hasChanged) { return position; } else { return { lineNumber, column }; } } } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ /** * @internal */ class BaseEditorSimpleWorker { constructor() { this._workerTextModelSyncServer = new WorkerTextModelSyncServer(); } dispose() { } _getModel(uri) { return this._workerTextModelSyncServer.getModel(uri); } _getModels() { return this._workerTextModelSyncServer.getModels(); } $acceptNewModel(data) { this._workerTextModelSyncServer.$acceptNewModel(data); } $acceptModelChanged(uri, e) { this._workerTextModelSyncServer.$acceptModelChanged(uri, e); } $acceptRemovedModel(uri) { this._workerTextModelSyncServer.$acceptRemovedModel(uri); } async $computeUnicodeHighlights(url, options, range) { const model = this._getModel(url); if (!model) { return { ranges: [], hasMore: false, ambiguousCharacterCount: 0, invisibleCharacterCount: 0, nonBasicAsciiCharacterCount: 0 }; } return UnicodeTextModelHighlighter.computeUnicodeHighlights(model, options, range); } async $findSectionHeaders(url, options) { const model = this._getModel(url); if (!model) { return []; } return findSectionHeaders(model, options); } // ---- BEGIN diff -------------------------------------------------------------------------- async $computeDiff(originalUrl, modifiedUrl, options, algorithm) { const original = this._getModel(originalUrl); const modified = this._getModel(modifiedUrl); if (!original || !modified) { return null; } const result = EditorSimpleWorker.computeDiff(original, modified, options, algorithm); return result; } static computeDiff(originalTextModel, modifiedTextModel, options, algorithm) { const diffAlgorithm = algorithm === 'advanced' ? linesDiffComputers.getDefault() : linesDiffComputers.getLegacy(); const originalLines = originalTextModel.getLinesContent(); const modifiedLines = modifiedTextModel.getLinesContent(); const result = diffAlgorithm.computeDiff(originalLines, modifiedLines, options); const identical = (result.changes.length > 0 ? false : this._modelsAreIdentical(originalTextModel, modifiedTextModel)); function getLineChanges(changes) { return changes.map(m => ([m.original.startLineNumber, m.original.endLineNumberExclusive, m.modified.startLineNumber, m.modified.endLineNumberExclusive, m.innerChanges?.map(m => [ m.originalRange.startLineNumber, m.originalRange.startColumn, m.originalRange.endLineNumber, m.originalRange.endColumn, m.modifiedRange.startLineNumber, m.modifiedRange.startColumn, m.modifiedRange.endLineNumber, m.modifiedRange.endColumn, ])])); } return { identical, quitEarly: result.hitTimeout, changes: getLineChanges(result.changes), moves: result.moves.map(m => ([ m.lineRangeMapping.original.startLineNumber, m.lineRangeMapping.original.endLineNumberExclusive, m.lineRangeMapping.modified.startLineNumber, m.lineRangeMapping.modified.endLineNumberExclusive, getLineChanges(m.changes) ])), }; } static _modelsAreIdentical(original, modified) { const originalLineCount = original.getLineCount(); const modifiedLineCount = modified.getLineCount(); if (originalLineCount !== modifiedLineCount) { return false; } for (let line = 1; line <= originalLineCount; line++) { const originalLine = original.getLineContent(line); const modifiedLine = modified.getLineContent(line); if (originalLine !== modifiedLine) { return false; } } return true; } // ---- END diff -------------------------------------------------------------------------- // ---- BEGIN minimal edits --------------------------------------------------------------- static { this._diffLimit = 100000; } async $computeMoreMinimalEdits(modelUrl, edits, pretty) { const model = this._getModel(modelUrl); if (!model) { return edits; } const result = []; let lastEol = undefined; edits = edits.slice(0).sort((a, b) => { if (a.range && b.range) { return Range.compareRangesUsingStarts(a.range, b.range); } // eol only changes should go to the end const aRng = a.range ? 0 : 1; const bRng = b.range ? 0 : 1; return aRng - bRng; }); // merge adjacent edits let writeIndex = 0; for (let readIndex = 1; readIndex < edits.length; readIndex++) { if (Range.getEndPosition(edits[writeIndex].range).equals(Range.getStartPosition(edits[readIndex].range))) { edits[writeIndex].range = Range.fromPositions(Range.getStartPosition(edits[writeIndex].range), Range.getEndPosition(edits[readIndex].range)); edits[writeIndex].text += edits[readIndex].text; } else { writeIndex++; edits[writeIndex] = edits[readIndex]; } } edits.length = writeIndex + 1; for (let { range, text, eol } of edits) { if (typeof eol === 'number') { lastEol = eol; } if (Range.isEmpty(range) && !text) { // empty change continue; } const original = model.getValueInRange(range); text = text.replace(/\r\n|\n|\r/g, model.eol); if (original === text) { // noop continue; } // make sure diff won't take too long if (Math.max(text.length, original.length) > EditorSimpleWorker._diffLimit) { result.push({ range, text }); continue; } // compute diff between original and edit.text const changes = stringDiff(original, text, pretty); const editOffset = model.offsetAt(Range.lift(range).getStartPosition()); for (const change of changes) { const start = model.positionAt(editOffset + change.originalStart); const end = model.positionAt(editOffset + change.originalStart + change.originalLength); const newEdit = { text: text.substr(change.modifiedStart, change.modifiedLength), range: { startLineNumber: start.lineNumber, startColumn: start.column, endLineNumber: end.lineNumber, endColumn: end.column } }; if (model.getValueInRange(newEdit.range) !== newEdit.text) { result.push(newEdit); } } } if (typeof lastEol === 'number') { result.push({ eol: lastEol, text: '', range: { startLineNumber: 0, startColumn: 0, endLineNumber: 0, endColumn: 0 } }); } return result; } // ---- END minimal edits --------------------------------------------------------------- async $computeLinks(modelUrl) { const model = this._getModel(modelUrl); if (!model) { return null; } return computeLinks(model); } // --- BEGIN default document colors ----------------------------------------------------------- async $computeDefaultDocumentColors(modelUrl) { const model = this._getModel(modelUrl); if (!model) { return null; } return computeDefaultDocumentColors(model); } // ---- BEGIN suggest -------------------------------------------------------------------------- static { this._suggestionsLimit = 10000; } async $textualSuggest(modelUrls, leadingWord, wordDef, wordDefFlags) { const sw = new StopWatch(); const wordDefRegExp = new RegExp(wordDef, wordDefFlags); const seen = new Set(); outer: for (const url of modelUrls) { const model = this._getModel(url); if (!model) { continue; } for (const word of model.words(wordDefRegExp)) { if (word === leadingWord || !isNaN(Number(word))) { continue; } seen.add(word); if (seen.size > EditorSimpleWorker._suggestionsLimit) { break outer; } } } return { words: Array.from(seen), duration: sw.elapsed() }; } // ---- END suggest -------------------------------------------------------------------------- //#region -- word ranges -- async $computeWordRanges(modelUrl, range, wordDef, wordDefFlags) { const model = this._getModel(modelUrl); if (!model) { return Object.create(null); } const wordDefRegExp = new RegExp(wordDef, wordDefFlags); const result = Object.create(null); for (let line = range.startLineNumber; line < range.endLineNumber; line++) { const words = model.getLineWords(line, wordDefRegExp); for (const word of words) { if (!isNaN(Number(word.word))) { continue; } let array = result[word.word]; if (!array) { array = []; result[word.word] = array; } array.push({ startLineNumber: line, startColumn: word.startColumn, endLineNumber: line, endColumn: word.endColumn }); } } return result; } //#endregion async $navigateValueSet(modelUrl, range, up, wordDef, wordDefFlags) { const model = this._getModel(modelUrl); if (!model) { return null; } const wordDefRegExp = new RegExp(wordDef, wordDefFlags); if (range.startColumn === range.endColumn) { range = { startLineNumber: range.startLineNumber, startColumn: range.startColumn, endLineNumber: range.endLineNumber, endColumn: range.endColumn + 1 }; } const selectionText = model.getValueInRange(range); const wordRange = model.getWordAtPosition({ lineNumber: range.startLineNumber, column: range.startColumn }, wordDefRegExp); if (!wordRange) { return null; } const word = model.getValueInRange(wordRange); const result = BasicInplaceReplace.INSTANCE.navigateValueSet(range, selectionText, wordRange, word, up); return result; } } /** * @internal */ class EditorSimpleWorker extends BaseEditorSimpleWorker { constructor(_host, _foreignModuleFactory) { super(); this._host = _host; this._foreignModuleFactory = _foreignModuleFactory; this._foreignModule = null; } async $ping() { return 'pong'; } // ---- BEGIN foreign module support -------------------------------------------------------------------------- $loadForeignModule(moduleId, createData, foreignHostMethods) { const proxyMethodRequest = (method, args) => { return this._host.$fhr(method, args); }; const foreignHost = createProxyObject(foreignHostMethods, proxyMethodRequest); const ctx = { host: foreignHost, getMirrorModels: () => { return this._getModels(); } }; if (this._foreignModuleFactory) { this._foreignModule = this._foreignModuleFactory(ctx, createData); // static foreing module return Promise.resolve(getAllMethodNames(this._foreignModule)); } return new Promise((resolve, reject) => { const onModuleCallback = (foreignModule) => { this._foreignModule = foreignModule.create(ctx, createData); resolve(getAllMethodNames(this._foreignModule)); }; { const url = FileAccess.asBrowserUri(`${moduleId}.js`).toString(true); import(`${url}`).then(onModuleCallback).catch(reject); } }); } // foreign method request $fmr(method, args) { if (!this._foreignModule || typeof this._foreignModule[method] !== 'function') { return Promise.reject(new Error('Missing requestHandler or method: ' + method)); } try { return Promise.resolve(this._foreignModule[method].apply(this._foreignModule, args)); } catch (e) { return Promise.reject(e); } } } if (typeof importScripts === 'function') { // Running in a web worker globalThis.monaco = createMonacoBaseAPI(); } /*--------------------------------------------------------------------------------------------- * Copyright (c) Microsoft Corporation. All rights reserved. * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ let initialized = false; function initialize(foreignModule) { if (initialized) { return; } initialized = true; const simpleWorker = new SimpleWorkerServer((msg) => { globalThis.postMessage(msg); }, (workerServer) => new EditorSimpleWorker(EditorWorkerHost.getChannel(workerServer), foreignModule)); globalThis.onmessage = (e) => { simpleWorker.onmessage(e.data); }; } globalThis.onmessage = (e) => { // Ignore first message in this case and initialize if not yet initialized if (!initialized) { initialize(null); } };