-
Notifications
You must be signed in to change notification settings - Fork 1
Expand file tree
/
Copy pathuse-input.ts
More file actions
66 lines (58 loc) · 1.54 KB
/
Copy pathuse-input.ts
File metadata and controls
66 lines (58 loc) · 1.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
import {
call,
createChannel,
each,
type Operation,
race,
resource,
sleep,
spawn,
type Stream,
suspend,
until,
} from "effection";
import { createInput, type InputEvent, type InputOptions } from "clayterm";
import { useStdin } from "./stdio.ts";
function nothing() {
return suspend() as unknown as Operation<
IteratorResult<Uint8Array, void>
>;
}
export function useInput(
options?: InputOptions,
): Stream<InputEvent, void> {
return resource(function* (provide) {
let input = yield* until(createInput(options));
let stdin = yield* useStdin();
let subscription = yield* stdin;
let pending = nothing();
let events = createChannel<InputEvent, void>();
yield* spawn(function* () {
let next = yield* subscription.next();
while (!next.done) {
let result = input.scan(next.value);
pending = result.pending ? rescan(result.pending.delay) : nothing();
for (let event of result.events) {
yield* events.send(event);
}
next = yield* race([subscription.next(), pending]);
}
yield* events.close();
});
yield* race([provide(yield* events), drain(events)]);
});
}
function rescan(delay: number): ReturnType<typeof nothing> {
return call(function* (): Operation<IteratorResult<Uint8Array, void>> {
yield* sleep(delay);
return {
done: false,
value: new Uint8Array(),
};
});
}
function* drain<T, TClose>(stream: Stream<T, TClose>): Operation<void> {
for (let _ of yield* each(stream)) {
yield* each.next();
}
}