Skip to content

Commit b052e7a

Browse files
hyperpolymathclaude
andcommitted
feat(stdlib): async-extern binding surface — Thenable + withProgress/sendRequest
#103 slice 1 (Promise-returning extern, per owner decision). The AffineScript extern-call shape is synchronous, so Thenable-returning vscode APIs could not be bound at all; the rsr-certifier vscode port fell back to shelling out to the CLI. Adds the binding surface only (smallest root-cause slice): - stdlib/Vscode.affine: `extern type Thenable;` + `withProgressNotification(title, work_thunk) -> Thenable / Async`. - stdlib/VscodeLanguageClient.affine: `languageClientSendRequest(c, method, params_json) -> Thenable / Async`. No backend change needed: the Deno/Node source-to-source backend already lowers an unlisted extern to a plain host call, so a Thenable-returning extern emits a real JS Promise and a consumer's `await` is valid source JS. The `Async` effect (v1 registry, PR-1 #196) tracks it in signatures. Verified: both files typecheck standalone; dune test 253/253 (incl. the AOT Vscode smoke); a consumer compiled with --deno-esm emits `return languageClientSendRequest("rsr/getCompliance", "{}")` — a plain awaitable host call. Deferred to follow-up slices (per scope): vscode-host JS impl in packages/affine-vscode/mod.js, and the rsr-certifier pilot restore. Refs #103 Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent e1c1591 commit b052e7a

2 files changed

Lines changed: 32 additions & 0 deletions

File tree

stdlib/Vscode.affine

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -283,3 +283,22 @@ pub extern fn processPlatform() -> String;
283283
/// `context.asAbsolutePath(rel_path)` — resolves a path relative to the
284284
/// extension's install location.
285285
pub extern fn extensionAbsolutePath(ctx: ExtensionContext, rel_path: String) -> String;
286+
287+
// ── Async-extern ABI (issue #103) ────────────────────────────────────
288+
//
289+
// AffineScript's extern-call shape is synchronous, but most of vscode's
290+
// interactive surface returns a JS Thenable. `Thenable` is an opaque
291+
// host handle; the Deno/Node source-to-source backend lowers a
292+
// Thenable-returning extern to a plain host call, so the emitted JS is a
293+
// real Promise and a consumer's `await` is valid source JS. The `Async`
294+
// effect (v1 registry, #59) tracks this in signatures. The vscode-host
295+
// JS implementation lives in packages/affine-vscode/mod.js (follow-up
296+
// slice); these declarations are the binding surface + effect tracking.
297+
298+
pub extern type Thenable;
299+
300+
/// `vscode.window.withProgress({ location: Notification, title }, task)`.
301+
/// `work_thunk` is a wasm/host table index of the `() -> Thenable` task
302+
/// (same thunk-handle convention as `onDidSaveTextDocument`). Returns the
303+
/// progress Thenable.
304+
pub extern fn withProgressNotification(title: String, work_thunk: Int) -> Thenable / Async;

stdlib/VscodeLanguageClient.affine

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,3 +31,16 @@ pub extern fn newLanguageClient(id: String,
3131

3232
pub extern fn languageClientStart(c: LanguageClient) -> Int;
3333
pub extern fn languageClientStop(c: LanguageClient) -> Int;
34+
35+
// ── Async-extern ABI (issue #103) ────────────────────────────────────
36+
// Opaque host handle, declared per-module (these binding modules are
37+
// self-contained; the host erases the type). See stdlib/Vscode.affine.
38+
39+
pub extern type Thenable;
40+
41+
/// `LanguageClient.sendRequest(method, params)` — returns a Thenable of
42+
/// the JSON-encoded response. `params_json` is the request params encoded
43+
/// as a JSON string; the host shim parses it before the LSP call.
44+
pub extern fn languageClientSendRequest(c: LanguageClient,
45+
method: String,
46+
params_json: String) -> Thenable / Async;

0 commit comments

Comments
 (0)