Skip to content

Commit 369dff2

Browse files
authored
Merge pull request #6 from thefrontside/middleware
✨Middleware
2 parents 5df9fa6 + d6e3503 commit 369dff2

File tree

11 files changed

+483
-137
lines changed

11 files changed

+483
-137
lines changed

deno.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
"imports": {
1111
"@effection-contrib/test-adapter": "jsr:@effection-contrib/test-adapter@^0.1.0",
1212
"@std/expect": "jsr:@std/expect@^1.0.13",
13+
"@std/streams": "jsr:@std/streams@^1.0.9",
1314
"@std/testing": "jsr:@std/testing@^1.0.9",
1415
"deepmerge": "npm:deepmerge@^4.3.1",
1516
"effection": "jsr:@effection/effection@^4.0.0-alpha.7",

deno.lock

Lines changed: 32 additions & 1 deletion
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

lib/debug.ts

Lines changed: 72 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
import type { LSPXMiddleware } from "./types.ts";
2+
import { createLSPXMiddleware } from "./middleware.ts";
3+
4+
/**
5+
* This debug middleware prints handy diagnostics to stderr with
6+
* every request/notification in both directions
7+
*/
8+
export function debug(): LSPXMiddleware {
9+
return createLSPXMiddleware({
10+
client2server: {
11+
*request(req, next) {
12+
let [method, ...params] = req.params;
13+
console.error(
14+
`--> [client2server.request]`,
15+
req.agents.map((a) => a.name),
16+
method,
17+
params,
18+
);
19+
let result = yield* next(req);
20+
console.error(
21+
`<-- [client2server.request]`,
22+
req.agents.map((a) => a.name),
23+
method,
24+
result,
25+
);
26+
return result;
27+
},
28+
*notify(req, next) {
29+
let [method, ...params] = req.params;
30+
console.error(
31+
`--> [client2server.notify]`,
32+
req.agents.map((a) => a.name),
33+
method,
34+
params,
35+
);
36+
let result = yield* next(req);
37+
return result;
38+
},
39+
},
40+
server2client: {
41+
*request(req, next) {
42+
let [method, ...params] = req.params;
43+
console.error(
44+
`--> [server2client.request]`,
45+
req.agent.name,
46+
method,
47+
params,
48+
);
49+
let result = yield* next(req);
50+
console.error(
51+
`<-- [server2client.request]`,
52+
req.agent.name,
53+
method,
54+
result,
55+
);
56+
return result;
57+
},
58+
59+
*notify(req, next) {
60+
let [method, ...params] = req.params;
61+
console.error(
62+
`--> [server2client.notify]`,
63+
req.agent.name,
64+
method,
65+
params,
66+
);
67+
let result = yield* next(req);
68+
return result;
69+
},
70+
},
71+
});
72+
}

lib/dispatch.ts

Lines changed: 29 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,11 @@
11
import { all, type Operation } from "effection";
2-
import type { LSPAgent, NotificationParams, RequestParams } from "./types.ts";
2+
import type {
3+
LSPAgent,
4+
LSPXMiddleware,
5+
RequestParams,
6+
XClientNotification,
7+
XClientRequest,
8+
} from "./types.ts";
39
import deepmerge from "deepmerge";
410
import { get, optic } from "optics-ts";
511
import { method2capability } from "./capabilities.ts";
@@ -8,21 +14,23 @@ import {
814
type CompletionParams,
915
ErrorCodes,
1016
} from "vscode-languageserver-protocol";
17+
import { createLSPXMiddleware } from "./middleware.ts";
1118

12-
/**
13-
* An incomping request that should be delegated to some group of server
14-
*/
15-
export interface RequestOptions {
16-
agents: LSPAgent[];
17-
params: RequestParams;
19+
export function defaultHandler(): LSPXMiddleware {
20+
return createLSPXMiddleware({
21+
client2server: {
22+
request: defaultRequest,
23+
notify: defaultNotify,
24+
},
25+
});
1826
}
1927

2028
/**
2129
* Dispatch an incoming request from the client to a set of matching
2230
* agents, and then merge the responses from each one into a single
2331
* response
2432
*/
25-
export function* request(options: RequestOptions): Operation<unknown> {
33+
export function* defaultRequest(options: XClientRequest): Operation<unknown> {
2634
let { agents, params } = options;
2735
let handler = match(agents, params);
2836

@@ -42,18 +50,24 @@ export function* request(options: RequestOptions): Operation<unknown> {
4250
return merge(responses);
4351
}
4452

45-
export interface NotificationOptions {
46-
agents: LSPAgent[];
47-
params: NotificationParams;
48-
}
49-
5053
/**
5154
* Dispatch an incoming notification from the client to a set of
5255
* matching agents.
5356
*/
54-
export function* notification(options: NotificationOptions): Operation<void> {
57+
export function* defaultNotify(options: XClientNotification): Operation<void> {
5558
let [method] = options.params;
5659
let handler = defaultMatch(options.agents, method);
60+
if (handler.agents.length === 0) {
61+
console.error(
62+
`no matching agents found for notification '${
63+
options.params[0]
64+
}. candidates are`,
65+
options.agents.map((a) => ({
66+
name: a.name,
67+
capabilities: a.capabilities,
68+
})),
69+
);
70+
}
5771

5872
yield* all(
5973
handler.agents.map((agent) => agent.notify(options.params)),
@@ -75,7 +89,7 @@ export function match(agents: LSPAgent[], params: RequestParams): Match {
7589
* If the completion trigger is not specified as one of the triggers
7690
* that an agent is providing, then it will not be sent the request.
7791
*/
78-
function completion(options: RequestOptions): Match {
92+
function completion(options: XClientRequest): Match {
7993
let { context } = options.params[1] as CompletionParams;
8094
let agents = options.agents.filter((agent) => {
8195
let capability = agent.capabilities.completionProvider;

lib/json-rpc-connection.ts

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ import {
1313
} from "effection";
1414
import * as rpc from "vscode-jsonrpc/node.js";
1515
import type {
16+
LSPServerNotification,
1617
LSPServerRequest,
17-
NotificationParams,
1818
RPCEndpoint,
1919
} from "./types.ts";
2020
import { disposable, disposableScope } from "./disposable.ts";
@@ -50,11 +50,13 @@ export function useConnection(
5050
rpc.createMessageConnection(readable, writable),
5151
);
5252

53-
let notifications = createSignal<NotificationParams>();
53+
let notifications = createSignal<LSPServerNotification>();
5454
let requests = createSignal<LSPServerRequest>();
5555

5656
yield* disposable(
57-
connection.onNotification((...params) => notifications.send(params)),
57+
connection.onNotification((...params) => {
58+
notifications.send((execute) => execute(params));
59+
}),
5860
);
5961

6062
yield* disposable(connection.onRequest((...params) => {

0 commit comments

Comments
 (0)