@@ -6,41 +6,56 @@ import { toFileUrl } from "https://deno.land/std@0.217.0/path/mod.ts";
6
6
import { toErrorObject } from "https://deno.land/x/errorutil@v0.1.1/mod.ts" ;
7
7
import { DenopsImpl , Host } from "./denops.ts" ;
8
8
9
+ // We can use `PromiseWithResolvers<void>` but Deno 1.38 doesn't have `PromiseWithResolvers`
10
+ type Waiter = {
11
+ promise : Promise < void > ;
12
+ resolve : ( ) => void ;
13
+ } ;
14
+
9
15
/**
10
16
* Service manage plugins and is visible from the host (Vim/Neovim) through `invoke()` function.
11
17
*/
12
18
export class Service implements Disposable {
13
19
#plugins: Map < string , Plugin > = new Map ( ) ;
20
+ #waiters: Map < string , Waiter > = new Map ( ) ;
14
21
#meta: Meta ;
15
22
#host?: Host ;
16
23
17
24
constructor ( meta : Meta ) {
18
25
this . #meta = meta ;
19
26
}
20
27
28
+ #getWaiter( name : string ) : Waiter {
29
+ if ( ! this . #waiters. has ( name ) ) {
30
+ this . #waiters. set ( name , Promise . withResolvers ( ) ) ;
31
+ }
32
+ return this . #waiters. get ( name ) ! ;
33
+ }
34
+
21
35
bind ( host : Host ) : void {
22
36
this . #host = host ;
23
37
}
24
38
25
- load (
39
+ async load (
26
40
name : string ,
27
41
script : string ,
28
42
suffix = "" ,
29
43
) : Promise < void > {
30
44
if ( ! this . #host) {
31
- return Promise . reject ( new Error ( "No host is bound to the service" ) ) ;
45
+ throw new Error ( "No host is bound to the service" ) ;
32
46
}
33
47
let plugin = this . #plugins. get ( name ) ;
34
48
if ( plugin ) {
35
49
if ( this . #meta. mode === "debug" ) {
36
50
console . log ( `A denops plugin '${ name } ' is already loaded. Skip` ) ;
37
51
}
38
- return Promise . resolve ( ) ;
52
+ return ;
39
53
}
40
54
const denops = new DenopsImpl ( name , this . #meta, this . #host, this ) ;
41
55
plugin = new Plugin ( denops , name , script ) ;
42
56
this . #plugins. set ( name , plugin ) ;
43
- return plugin . load ( suffix ) ;
57
+ await plugin . load ( suffix ) ;
58
+ this . #getWaiter( name ) . resolve ( ) ;
44
59
}
45
60
46
61
reload (
@@ -54,12 +69,17 @@ export class Service implements Disposable {
54
69
return Promise . resolve ( ) ;
55
70
}
56
71
this . #plugins. delete ( name ) ;
72
+ this . #waiters. delete ( name ) ;
57
73
// Import module with fragment so that reload works properly
58
74
// https://github.com/vim-denops/denops.vim/issues/227
59
75
const suffix = `#${ performance . now ( ) } ` ;
60
76
return this . load ( name , plugin . script , suffix ) ;
61
77
}
62
78
79
+ waitLoaded ( name : string ) : Promise < void > {
80
+ return this . #getWaiter( name ) . promise ;
81
+ }
82
+
63
83
async #dispatch( name : string , fn : string , args : unknown [ ] ) : Promise < unknown > {
64
84
const plugin = this . #plugins. get ( name ) ;
65
85
if ( ! plugin ) {
0 commit comments