Skip to content

Commit 6ab89a5

Browse files
committed
👍 Improve stability on unexpected errors
1 parent 184566f commit 6ab89a5

File tree

6 files changed

+36
-17
lines changed

6 files changed

+36
-17
lines changed

autoload/fall/internal.vim

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,5 +2,5 @@ function! fall#internal#dispatch(event) abort
22
if denops#plugin#wait('fall') isnot# 0
33
return
44
endif
5-
call denops#request('fall', 'event:dispatch', [a:event])
5+
call denops#notify('fall', 'event:dispatch', [a:event])
66
endfunction

denops/fall/event.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,15 +7,15 @@ export function dispatch(event: Readonly<Event>): void {
77
}
88

99
export function consume(consumer: Consumer): void {
10-
for (const event of eventQueue) {
11-
consumer(event);
12-
}
10+
const events = eventQueue;
1311
eventQueue = [];
12+
events.forEach(consumer);
1413
}
1514

1615
type SelectMethod = "on" | "off" | "toggle";
1716

1817
export type Event =
18+
| { type: "debug-error"; message: string }
1919
| { type: "vim-resized"; width: number; height: number }
2020
| { type: "vim-cmdline-changed"; cmdline: string }
2121
| { type: "vim-cmdpos-changed"; cmdpos: number }

denops/fall/lib/scheduler.ts

Lines changed: 11 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,30 +8,33 @@ export class Scheduler implements Disposable {
88

99
#tick(
1010
callback: () => void | Promise<void>,
11-
{ signal }: { signal?: AbortSignal } = {},
11+
{ reject, signal }: {
12+
reject: (reason: unknown) => void;
13+
signal?: AbortSignal;
14+
},
1215
): void {
1316
this.#timer = setTimeout(async () => {
1417
if (!this.#timer || signal?.aborted) return;
1518
try {
1619
await callback();
1720
if (!this.#timer || signal?.aborted) return;
18-
this.#tick(callback, { signal });
21+
this.#tick(callback, { reject, signal });
1922
} catch (err) {
20-
if (err instanceof DOMException && err.name === "AbortError") return;
21-
const m = err instanceof Error ? err.message : String(err);
22-
console.error(`[fall] Unexpected error in Scheduler: ${m}`);
23+
reject(err);
2324
}
2425
}, this.#interval);
2526
}
2627

2728
start(
2829
callback: () => void | Promise<void>,
2930
{ signal }: { signal?: AbortSignal } = {},
30-
): void {
31+
): Promise<never> {
3132
if (this.#timer !== undefined) {
32-
throw new Error("Scheduler is already started");
33+
return Promise.reject(new Error("Scheduler is already started"));
3334
}
34-
this.#tick(callback, { signal });
35+
return new Promise((_, reject) => {
36+
this.#tick(callback, { reject, signal });
37+
});
3538
}
3639

3740
stop(): void {

denops/fall/main/event.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,10 @@ function eventDispatch(event: unknown): void {
2121
// Only event that is dispatched from Vim requires predicate function.
2222
// So this is NOT a full list of event types.
2323
const isEventComplement = is.UnionOf([
24+
is.ObjectOf({
25+
type: is.LiteralOf("debug-error"),
26+
message: is.String,
27+
}),
2428
// Vim
2529
is.ObjectOf({
2630
type: is.LiteralOf("vim-resized"),

denops/fall/picker.ts

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -143,7 +143,7 @@ export class Picker<T> implements AsyncDisposable {
143143
{ args }: { args: string[] },
144144
{ signal }: { signal?: AbortSignal } = {},
145145
): Promise<PickerResult<T> | undefined> {
146-
using stack = new DisposableStack();
146+
await using stack = new AsyncDisposableStack();
147147

148148
this.#collectProcessor.start(denops, { args });
149149
stack.defer(() => this.#collectProcessor.pause());
@@ -158,8 +158,8 @@ export class Picker<T> implements AsyncDisposable {
158158
cmdline: this.#inputComponent.cmdline,
159159
cmdpos: this.#inputComponent.cmdpos,
160160
});
161-
using scheduler = new Scheduler(this.#schedulerInterval);
162-
scheduler.start(async () => {
161+
const scheduler = stack.use(new Scheduler(this.#schedulerInterval));
162+
const waiter = scheduler.start(async () => {
163163
// Check cmdline/cmdpos
164164
await cmdliner.check(denops);
165165

@@ -197,7 +197,11 @@ export class Picker<T> implements AsyncDisposable {
197197
}
198198
}, { signal });
199199

200-
const query = await cmdliner.input(denops, { signal });
200+
stack.defer(() => Cmdliner.cancel(denops));
201+
const query = await Promise.race([
202+
cmdliner.input(denops, { signal }),
203+
waiter,
204+
]);
201205
if (query == null) {
202206
return;
203207
}
@@ -278,6 +282,11 @@ export class Picker<T> implements AsyncDisposable {
278282
accept: (name: string) => Promise<void>;
279283
}): void {
280284
switch (event.type) {
285+
case "debug-error":
286+
console.log(
287+
`[fall] 'debug-error' event has received: ${event.message}`,
288+
);
289+
throw new Error(event.message);
281290
case "vim-resized": {
282291
this.#resized = {
283292
width: event.width,

denops/fall/util/cmdliner.ts

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,9 @@ export class Cmdliner {
1818

1919
static async #feedkeys(denops: Denops, key: string): Promise<void> {
2020
try {
21+
if (!(await fn.mode(denops)).startsWith("c")) {
22+
return;
23+
}
2124
await useEval(denops, async (denops) => {
2225
await fn.feedkeys(denops, key, "n");
2326
});
@@ -65,7 +68,7 @@ export class Cmdliner {
6568
fn.getcmdline(denops),
6669
fn.getcmdpos(denops),
6770
]);
68-
if (mode !== "c") {
71+
if (!mode.startsWith("c")) {
6972
// Not in command-line mode
7073
return;
7174
}

0 commit comments

Comments
 (0)