-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy pathscope.ts
More file actions
74 lines (69 loc) · 2.63 KB
/
Copy pathscope.ts
File metadata and controls
74 lines (69 loc) · 2.63 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
/**
* Where a call came from, decided by the kernel (#7617 R2.2).
*
* The wire lets a page name the window it called from and nothing else: the process and the
* workspace are looked up here, so a page cannot address another process by putting an id on the
* wire. A spell that legitimately targets another process takes that id as an argument of its own
* `params` and is answerable for it.
*
* The kernel has no window noun (#7632 R1.2), so `WindowIndex` is an interface this slice declares
* and the shell implements: `shellWindowIndexKernel` (`../shell/commands/kernel.ts`) reads the live
* desk, and boot provides it (#7894). `WindowIndex.scripted` answers from a fixture, for a test
* that wants a fixed table rather than a running desk.
*/
import {Context, Effect, Layer} from "effect";
import type {ProcessId} from "../process/process.ts";
import {NoSuchWindow} from "./errors.ts";
import type {ClientId, Scope, WindowId, WorkspaceId} from "./spell.ts";
/** Where one window is: the process it shows, when it shows one, and the workspace holding it. */
export interface WindowPlacement {
readonly process?: ProcessId;
readonly workspace: WorkspaceId;
}
/** The caller as the kernel knows it: who it is, and which workspace it is looking at. */
export interface Client {
readonly id: ClientId;
readonly workspace: WorkspaceId;
}
export class WindowIndex extends Context.Service<
WindowIndex,
{
readonly resolve: (window: WindowId) => Effect.Effect<WindowPlacement, NoSuchWindow>;
}
>()("tuval/WindowIndex") {
/** The index over a fixed table — the deterministic layer tests and the shell-less kernel use. */
static readonly scripted = (
table: Readonly<Record<string, WindowPlacement>>,
): Layer.Layer<WindowIndex> =>
Layer.succeed(
WindowIndex,
WindowIndex.of({
resolve: (window) => {
const placement = table[window];
return placement === undefined
? Effect.fail(new NoSuchWindow({window}))
: Effect.succeed(placement);
},
}),
);
}
/**
* The scope for one call. With a window, every field comes from the index; without one, the call is
* workspace-wide and names no process.
*/
export const resolveScope = Effect.fn("Tuval.Commands.resolveScope")(function* (
call: {readonly window?: WindowId},
client: Client,
) {
if (call.window === undefined) {
return {workspace: client.workspace, client: client.id} satisfies Scope;
}
const index = yield* WindowIndex;
const placement = yield* index.resolve(call.window);
return {
window: call.window,
...(placement.process === undefined ? {} : {process: placement.process}),
workspace: placement.workspace,
client: client.id,
} satisfies Scope;
});