Skip to content

Commit 775d819

Browse files
committed
👍 Add lambda module and deprecate anonymous
1 parent ed6e0ae commit 775d819

File tree

3 files changed

+216
-0
lines changed

3 files changed

+216
-0
lines changed

denops_std/anonymous/mod.ts

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22
* A module to provide anonymous function which is callable from
33
* outside of the plugin (Vim or other plugins.)
44
*
5+
* @deprecated Use `lambda` module instead.
56
* @module
67
*/
78
import type { Denops } from "https://deno.land/x/denops_core@v3.4.1/mod.ts";
@@ -55,6 +56,8 @@ export type Callback = (...args: unknown[]) => Promise<unknown> | unknown;
5556
* });
5657
* }
5758
* ```
59+
*
60+
* @deprecated Use `lambda.register()` function instead.
5861
*/
5962
export function add<N extends number>(
6063
denops: Denops,
@@ -98,6 +101,8 @@ export function add<N extends number>(
98101
* await denops.dispatch(denops.name, ids[0]);
99102
* }
100103
* ```
104+
*
105+
* @deprecated Use `lambda.register()` function instead.
101106
*/
102107
export function once<N extends number>(
103108
denops: Denops,
@@ -147,6 +152,8 @@ export function once<N extends number>(
147152
* await denops.dispatch(denops.name, ids[1]);
148153
* }
149154
* ```
155+
*
156+
* @deprecated Use `lambda.unregister()` function instead.
150157
*/
151158
export function remove<N extends number>(
152159
denops: Denops,

denops_std/lambda/mod.ts

Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
/**
2+
* A module to provide lambda function that is callable from the outside of the plugin.
3+
*
4+
* Use `denops#callback#register()` and `denops#callback#call()` functions instead if you'd like
5+
* to create a lambda function of Vim script that is callable from Deno.
6+
*
7+
* ```typescript
8+
* import { Denops } from "../mod.ts";
9+
* import * as lambda from "./mod.ts";
10+
*
11+
* export async function main(denops: Denops): Promise<void> {
12+
* // Add lambda function
13+
* const id = lambda.register(
14+
* denops,
15+
* () => {
16+
* // Do what ever you want.
17+
* },
18+
* );
19+
*
20+
* // Use id to dispatch added function from Deno
21+
* await denops.dispatch(denops.name, id);
22+
*
23+
* // Or from Vim
24+
* await denops.cmd("call denops#notify(name, id, [])", {
25+
* name: denops.name,
26+
* id,
27+
* });
28+
* }
29+
* ```
30+
*
31+
* @module
32+
*/
33+
34+
import type { Denops } from "https://deno.land/x/denops_core@v3.4.1/mod.ts";
35+
36+
/**
37+
* Lambda function identifier
38+
*/
39+
export type Identifier = string;
40+
41+
/**
42+
* Lambda function
43+
*/
44+
export type Fn = (...args: unknown[]) => unknown;
45+
46+
/**
47+
* Register options
48+
*/
49+
export interface Options {
50+
/** Register the function as a one-time lambda function that will be removed when the function has called */
51+
once?: boolean;
52+
}
53+
54+
/**
55+
* Register a lambda function as a denops API and return the identifier.
56+
*
57+
* ```typescript
58+
* import { Denops } from "../mod.ts";
59+
* import * as lambda from "./mod.ts";
60+
*
61+
* export async function main(denops: Denops): Promise<void> {
62+
* // Add lambda function
63+
* const id = lambda.register(
64+
* denops,
65+
* () => {
66+
* // Do what ever you want.
67+
* },
68+
* );
69+
*
70+
* // Use id to dispatch added function from Deno
71+
* await denops.dispatch(denops.name, id);
72+
*
73+
* // Or from Vim
74+
* await denops.cmd("call denops#notify(name, id, [])", {
75+
* name: denops.name,
76+
* id,
77+
* });
78+
* }
79+
* ```
80+
*
81+
* If you need an one-time lambda function, use `once` option like
82+
*
83+
* ```typescript
84+
* import { Denops } from "../mod.ts";
85+
* import * as lambda from "./mod.ts";
86+
*
87+
* export async function main(denops: Denops): Promise<void> {
88+
* // Add lambda function
89+
* const id = lambda.register(
90+
* denops,
91+
* () => {
92+
* // Do what ever you want.
93+
* },
94+
* {
95+
* once: true,
96+
* },
97+
* );
98+
*
99+
* // Use id to dispatch added function from Deno
100+
* await denops.dispatch(denops.name, id);
101+
*
102+
* // Second call would throw error
103+
* await denops.dispatch(denops.name, id);
104+
* }
105+
* ```
106+
*/
107+
export function register(
108+
denops: Denops,
109+
fn: Fn,
110+
options: Options = {},
111+
): Identifier {
112+
const uuid = crypto.randomUUID();
113+
const id = `lambda:${denops.name}:${uuid}`;
114+
if (options.once) {
115+
denops.dispatcher[id] = async (...args: unknown[]) => {
116+
try {
117+
return await fn(...args);
118+
} finally {
119+
unregister(denops, id);
120+
}
121+
};
122+
} else {
123+
denops.dispatcher[id] = async (...args: unknown[]) => {
124+
return await fn(...args);
125+
};
126+
}
127+
return id;
128+
}
129+
130+
/**
131+
* Unregister a lambda function from a denops API identified by the identifier
132+
*
133+
* It returns `true` if the lambda function is unregistered. Otherwise it returns `false`.
134+
*/
135+
export function unregister(
136+
denops: Denops,
137+
id: Identifier,
138+
): boolean {
139+
if (id in denops.dispatcher) {
140+
delete denops.dispatcher[id];
141+
return true;
142+
}
143+
return false;
144+
}

denops_std/lambda/mod_test.ts

Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
import {
2+
assertEquals,
3+
assertRejects,
4+
} from "https://deno.land/std@0.170.0/testing/asserts.ts";
5+
import { test } from "https://deno.land/x/denops_test@v1.0.1/mod.ts";
6+
import * as lambda from "./mod.ts";
7+
8+
test({
9+
mode: "all",
10+
name: "lambda",
11+
fn: async (denops, t) => {
12+
await t.step({
13+
name: "register() registers a lambda function",
14+
fn: async () => {
15+
const id = lambda.register(
16+
denops,
17+
() => Promise.resolve("0"),
18+
);
19+
assertEquals(await denops.dispatch(denops.name, id), "0");
20+
assertEquals(await denops.dispatch(denops.name, id), "0");
21+
},
22+
});
23+
24+
await t.step({
25+
name:
26+
"register() registers an oneshot lambda functions when 'once' option is specified",
27+
fn: async () => {
28+
const id = lambda.register(
29+
denops,
30+
() => Promise.resolve("0"),
31+
{ once: true },
32+
);
33+
assertEquals(await denops.dispatch(denops.name, id), "0");
34+
35+
// The method will be removed
36+
await assertRejects(
37+
async () => {
38+
await denops.dispatch(denops.name, id);
39+
},
40+
`No method '${id}' exists`,
41+
);
42+
},
43+
});
44+
45+
await t.step({
46+
name:
47+
"unregister() unregisters a lambda function identified by the identifier",
48+
fn: async () => {
49+
const id = lambda.register(
50+
denops,
51+
() => Promise.resolve("0"),
52+
);
53+
assertEquals(lambda.unregister(denops, id), true);
54+
55+
// The method is removed
56+
await assertRejects(
57+
async () => {
58+
await denops.dispatch(denops.name, id);
59+
},
60+
`No method '${id}' exists`,
61+
);
62+
},
63+
});
64+
},
65+
});

0 commit comments

Comments
 (0)