mirror of
https://github.com/enso-org/enso.git
synced 2024-12-23 05:41:32 +03:00
c811a5ae8b
- Fix the UI problems with our CodeMirror integration (Fixed view stability; Fixed a focus bug; Fixed errors caused by diagnostics range exceptions; Fixed linter invalidation--see https://discuss.codemirror.net/t/problem-trying-to-force-linting/5823; Implemented edit-coalescing for performance). - Introduce an algorithm for applying text edits to an AST. Compared to the GUI1 approach, the new algorithm supports deeper identity-stability for expressions (which is important for subexpression metadata and Y.Js sync), as well as reordered-subtree identification. - Enable the code editor.
99 lines
2.9 KiB
TypeScript
99 lines
2.9 KiB
TypeScript
/** @file Functions for manipulating {@link Iterable}s. */
|
|
|
|
export function* empty(): Generator<never> {}
|
|
|
|
export function* range(start: number, stop: number, step = start <= stop ? 1 : -1) {
|
|
if ((step > 0 && start > stop) || (step < 0 && start < stop)) {
|
|
throw new Error(
|
|
"The range's step is in the wrong direction - please use Infinity or -Infinity as the endpoint for an infinite range.",
|
|
)
|
|
}
|
|
if (start <= stop) {
|
|
while (start < stop) {
|
|
yield start
|
|
start += step
|
|
}
|
|
} else {
|
|
while (start > stop) {
|
|
yield start
|
|
start += step
|
|
}
|
|
}
|
|
}
|
|
|
|
export function* map<T, U>(iter: Iterable<T>, map: (value: T) => U) {
|
|
for (const value of iter) {
|
|
yield map(value)
|
|
}
|
|
}
|
|
|
|
export function* chain<T>(...iters: Iterable<T>[]) {
|
|
for (const iter of iters) {
|
|
yield* iter
|
|
}
|
|
}
|
|
|
|
export function* zip<T, U>(left: Iterable<T>, right: Iterable<U>): Generator<[T, U]> {
|
|
const leftIterator = left[Symbol.iterator]()
|
|
const rightIterator = right[Symbol.iterator]()
|
|
while (true) {
|
|
const leftResult = leftIterator.next()
|
|
const rightResult = rightIterator.next()
|
|
if (leftResult.done || rightResult.done) break
|
|
yield [leftResult.value, rightResult.value]
|
|
}
|
|
}
|
|
|
|
export function* zipLongest<T, U>(
|
|
left: Iterable<T>,
|
|
right: Iterable<U>,
|
|
): Generator<[T | undefined, U | undefined]> {
|
|
const leftIterator = left[Symbol.iterator]()
|
|
const rightIterator = right[Symbol.iterator]()
|
|
while (true) {
|
|
const leftResult = leftIterator.next()
|
|
const rightResult = rightIterator.next()
|
|
if (leftResult.done && rightResult.done) break
|
|
yield [
|
|
leftResult.done ? undefined : leftResult.value,
|
|
rightResult.done ? undefined : rightResult.value,
|
|
]
|
|
}
|
|
}
|
|
|
|
export function tryGetSoleValue<T>(iter: Iterable<T>): T | undefined {
|
|
const iterator = iter[Symbol.iterator]()
|
|
const result = iterator.next()
|
|
if (result.done) return
|
|
const excessResult = iterator.next()
|
|
if (!excessResult.done) return
|
|
return result.value
|
|
}
|
|
|
|
/** Utility to simplify consuming an iterator a part at a time. */
|
|
export class Resumable<T> {
|
|
private readonly iterator: Iterator<T>
|
|
private current: IteratorResult<T>
|
|
constructor(iterable: Iterable<T>) {
|
|
this.iterator = iterable[Symbol.iterator]()
|
|
this.current = this.iterator.next()
|
|
}
|
|
|
|
/** The given function peeks at the current value. If the function returns `true`, the current value will be advanced
|
|
* and the function called again; if it returns `false`, the peeked value remains current and `advanceWhile` returns.
|
|
*/
|
|
advanceWhile(f: (value: T) => boolean) {
|
|
while (!this.current.done && f(this.current.value)) {
|
|
this.current = this.iterator.next()
|
|
}
|
|
}
|
|
|
|
/** Apply the given function to all values remaining in the iterator. */
|
|
forEach(f: (value: T) => void) {
|
|
while (!this.current.done) {
|
|
f(this.current.value)
|
|
this.current = this.iterator.next()
|
|
}
|
|
}
|
|
}
|