Cancellation can be challenging to implement, so we aim to provide a method for denops plugins to handle interruptions.
The proposed API could be:
Promise version
import type { Denops as DenopsOrigin } from "https://deno.land/x/denops_core@v6.0.4/mod.ts";
import { delay } from "https://deno.land/std@0.211.0/async/mod.ts";
export function main(denops: Denops): void {
denops.dispatcher = {
start: async () => {
const { interrupted, done } = denops.interrupted();
try {
for (let i = 0; i < 100; i++) {
await Promise.race([interrupted, denops.cmd(`echo 'Hello ${i}'`)]);
await Promise.race([interrupted, delay(100)]);
}
} catch (e) {
if (e instanceof Interrupted) {
await denops.cmd("echo 'Interrupted'");
return;
}
throw e;
} finally {
// Clean up interrupted promise
done();
}
},
};
}
// Assume that this error is thrown from the `signal` when the user invoke `denops#interrupt()`
class Interrupted extends Error {}
// Assume that Denops v6.1 add `interrupted()` method to Denops
type Denops = DenopsOrigin & {
interrupted: () => { interrupted: Promise<never>; done: () => void };
};
The implementation on denops.vim is easier when we use Promise<never> as a signal but it's not clear for users while users must call done() or whatever to clean up promises for wait.
AbortSignal version
import type { Denops as DenopsOrigin } from "https://deno.land/x/denops_core@v6.0.4/mod.ts";
import { abortable, delay } from "https://deno.land/std@0.211.0/async/mod.ts";
export function main(denops: Denops): void {
denops.dispatcher = {
start: async () => {
const { signal } = denops.interrupted();
try {
for (let i = 0; i < 100; i++) {
signal.throwIfAborted();
await abortable(denops.cmd(`echo 'Hello ${i}'`), signal);
await delay(100, { signal });
}
} catch (e) {
if (e instanceof Interrupted) {
await denops.cmd("echo 'Interrupted'");
return;
}
throw e;
}
},
};
}
// Assume that this error is thrown from the `signal` when the user invoke `denops#interrupt()`
class Interrupted extends Error {}
// Assume that Denops v6.1 add `interrupted()` method to Denops
type Denops = DenopsOrigin & {
interrupted: () => { signal: AbortSignal };
};
The implementation on denops.vim is a bit tough when we use AbortSignal as a signal but it seems this version is more Deno native friendly and users don't need to care about resource management.
Cancellation can be challenging to implement, so we aim to provide a method for denops plugins to handle interruptions.
The proposed API could be:
Promise
versionThe implementation on denops.vim is easier when we use
Promise<never>
as a signal but it's not clear for users while users must calldone()
or whatever to clean up promises for wait.AbortSignal
versionThe implementation on denops.vim is a bit tough when we use
AbortSignal
as a signal but it seems this version is more Deno native friendly and users don't need to care about resource management.