Skip to content

Commit 897bda7

Browse files
committed
👍 Automatically wait plugin load on denops.dispatch()
Note that wait only happens on `denops.dispatch()` but `service.dispatch()` so this change only affects plugin-plugin communication (not denops-plugin communication)
1 parent d17dd0b commit 897bda7

File tree

2 files changed

+37
-6
lines changed

2 files changed

+37
-6
lines changed

denops/@denops-private/denops.ts

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ const isBatchReturn = is.TupleOf([is.Array, is.String] as const);
1313

1414
export type Host = Pick<HostOrigin, "redraw" | "call" | "batch">;
1515

16-
export type Service = Pick<ServiceOrigin, "dispatch">;
16+
export type Service = Pick<ServiceOrigin, "dispatch" | "waitLoaded">;
1717

1818
export class DenopsImpl implements Denops {
1919
readonly name: string;
@@ -67,12 +67,13 @@ export class DenopsImpl implements Denops {
6767
return this.#host.call("denops#api#eval", expr, ctx);
6868
}
6969

70-
dispatch(
70+
async dispatch(
7171
name: string,
7272
fn: string,
7373
...args: unknown[]
7474
): Promise<unknown> {
75-
return this.#service.dispatch(name, fn, args);
75+
await this.#service.waitLoaded(name);
76+
return await this.#service.dispatch(name, fn, args);
7677
}
7778
}
7879

denops/@denops-private/denops_test.ts

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
import type { Meta } from "https://deno.land/x/denops_core@v6.0.5/mod.ts";
2+
import { assertEquals } from "https://deno.land/std@0.217.0/assert/mod.ts";
23
import {
34
assertSpyCall,
45
stub,
56
} from "https://deno.land/std@0.217.0/testing/mock.ts";
67
import { DenopsImpl, Host, Service } from "./denops.ts";
8+
import { promiseState } from "https://deno.land/x/async@v2.1.0/mod.ts";
79
import { unimplemented } from "https://deno.land/x/errorutil@v0.1.1/mod.ts";
810

911
Deno.test("DenopsImpl", async (t) => {
@@ -20,6 +22,7 @@ Deno.test("DenopsImpl", async (t) => {
2022
};
2123
const service: Service = {
2224
dispatch: () => unimplemented(),
25+
waitLoaded: () => unimplemented(),
2326
};
2427
const denops = new DenopsImpl("dummy", meta, host, service);
2528

@@ -93,14 +96,41 @@ Deno.test("DenopsImpl", async (t) => {
9396
});
9497

9598
await t.step("dispatch() calls service.dispatch()", async () => {
96-
const s = stub(service, "dispatch");
99+
const s1 = stub(service, "waitLoaded", () => Promise.resolve());
100+
const s2 = stub(service, "dispatch", () => Promise.resolve());
97101
try {
98102
await denops.dispatch("dummy", "fn", "args");
99-
assertSpyCall(s, 0, {
103+
assertSpyCall(s1, 0, {
104+
args: ["dummy"],
105+
});
106+
assertSpyCall(s2, 0, {
100107
args: ["dummy", "fn", ["args"]],
101108
});
102109
} finally {
103-
s.restore();
110+
s1.restore();
111+
s2.restore();
104112
}
105113
});
114+
115+
await t.step(
116+
"dispatch() internally waits 'service.waitLoaded()' before 'service.dispatch()'",
117+
async () => {
118+
const { promise, resolve } = Promise.withResolvers<void>();
119+
const s1 = stub(service, "waitLoaded", () => promise);
120+
const s2 = stub(service, "dispatch", () => Promise.resolve());
121+
try {
122+
const p = denops.dispatch("dummy", "fn", "args");
123+
assertEquals(await promiseState(p), "pending");
124+
assertEquals(s1.calls.length, 1);
125+
assertEquals(s2.calls.length, 0);
126+
resolve();
127+
assertEquals(await promiseState(p), "fulfilled");
128+
assertEquals(s1.calls.length, 1);
129+
assertEquals(s2.calls.length, 1);
130+
} finally {
131+
s1.restore();
132+
s2.restore();
133+
}
134+
},
135+
);
106136
});

0 commit comments

Comments
 (0)