lean4monaco 1.1.11 → 1.1.14

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -3,3 +3,5 @@ export * from './leanmonaco';
3
3
  export { RpcSessionAtPos } from './vscode-lean4/vscode-lean4/src/infoview';
4
4
  export { DocumentPosition } from './vscode-lean4/lean4-infoview/src/infoview/util';
5
5
  export { LeanClient } from './vscode-lean4/vscode-lean4/src/leanclient';
6
+ export { WithRpcSessions } from './vscode-lean4/lean4-infoview/src/infoview/rpcSessions';
7
+ export { RpcSessions } from './vscode-lean4/lean4-infoview-api/src/rpcSessions';
package/dist/index.js CHANGED
@@ -3,3 +3,5 @@ export * from './leanmonaco';
3
3
  export { RpcSessionAtPos } from './vscode-lean4/vscode-lean4/src/infoview';
4
4
  export { DocumentPosition } from './vscode-lean4/lean4-infoview/src/infoview/util';
5
5
  export { LeanClient } from './vscode-lean4/vscode-lean4/src/leanclient';
6
+ export { WithRpcSessions } from './vscode-lean4/lean4-infoview/src/infoview/rpcSessions';
7
+ export { RpcSessions } from './vscode-lean4/lean4-infoview-api/src/rpcSessions';
@@ -0,0 +1,21 @@
1
+ import { RpcSessionAtPos } from '@leanprover/infoview-api';
2
+ import * as React from 'react';
3
+ import type { TextDocumentPositionParams } from 'vscode-languageserver-protocol';
4
+ import { DocumentPosition } from './util';
5
+ /**
6
+ * Provides a {@link RpcSessionsContext} to the children.
7
+ * The {@link RpcSessions} object stored there manages RPC sessions in the Lean server.
8
+ */
9
+ export declare function WithRpcSessions({ children }: {
10
+ children: React.ReactNode;
11
+ }): import("react/jsx-runtime").JSX.Element;
12
+ export declare function useRpcSessionAtTdpp(pos: TextDocumentPositionParams): RpcSessionAtPos;
13
+ export declare function useRpcSessionAtPos(pos: DocumentPosition): RpcSessionAtPos;
14
+ /** @deprecated use {@link useRpcSession} instead */
15
+ export declare const RpcContext: React.Context<RpcSessionAtPos>;
16
+ /**
17
+ * Retrieve an RPC session at {@link EnvPosContext},
18
+ * if the context is set.
19
+ * Otherwise return a dummy session that throws on any RPC call.
20
+ */
21
+ export declare function useRpcSession(): RpcSessionAtPos;
@@ -0,0 +1,67 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { RpcSessions } from '@leanprover/infoview-api';
3
+ import * as React from 'react';
4
+ import { EditorContext, EnvPosContext } from './contexts';
5
+ import { DocumentPosition, useClientNotificationEffect, useEvent } from './util';
6
+ const RpcSessionsContext = React.createContext(undefined);
7
+ /**
8
+ * Provides a {@link RpcSessionsContext} to the children.
9
+ * The {@link RpcSessions} object stored there manages RPC sessions in the Lean server.
10
+ */
11
+ export function WithRpcSessions({ children }) {
12
+ const ec = React.useContext(EditorContext);
13
+ const [sessions] = React.useState(() => new RpcSessions({
14
+ createRpcSession: (uri) => ec.api.createRpcSession(uri),
15
+ closeRpcSession: (uri) => ec.api.closeRpcSession(uri),
16
+ call: (params) => ec.api.sendClientRequest(params.textDocument.uri, '$/lean/rpc/call', params),
17
+ release: (params) => void ec.api.sendClientNotification(params.uri, '$/lean/rpc/release', params),
18
+ }));
19
+ React.useEffect(() => {
20
+ // Clean up the sessions on unmount
21
+ return () => sessions.dispose();
22
+ }, [sessions]);
23
+ useClientNotificationEffect('textDocument/didClose', (params) => {
24
+ sessions.closeSessionForFile(params.textDocument.uri);
25
+ }, [sessions]);
26
+ // TODO: only restart files for the server that stopped
27
+ useEvent(ec.events.serverRestarted, () => sessions.closeAllSessions());
28
+ return _jsx(RpcSessionsContext.Provider, { value: sessions, children: children });
29
+ }
30
+ const noCtxRpcSession = {
31
+ call: async () => {
32
+ throw new Error('no RPC context set');
33
+ },
34
+ };
35
+ const noPosRpcSession = {
36
+ call: async () => {
37
+ throw new Error('no position context set');
38
+ },
39
+ };
40
+ export function useRpcSessionAtTdpp(pos) {
41
+ return React.useContext(RpcSessionsContext)?.connect(pos) || noCtxRpcSession;
42
+ }
43
+ export function useRpcSessionAtPos(pos) {
44
+ return useRpcSessionAtTdpp(DocumentPosition.toTdpp(pos));
45
+ }
46
+ /** @deprecated use {@link useRpcSession} instead */
47
+ /*
48
+ * NOTE(WN): This context cannot be removed as of 2024-05-27 since existing widgets use it.
49
+ * For backwards compatibility, it must be set to the correct value by infoview code.
50
+ * A future major release of @leanprover/infoview could remove this context
51
+ * after it has been deprecated for a sufficiently long time.
52
+ */
53
+ export const RpcContext = React.createContext(noCtxRpcSession);
54
+ /**
55
+ * Retrieve an RPC session at {@link EnvPosContext},
56
+ * if the context is set.
57
+ * Otherwise return a dummy session that throws on any RPC call.
58
+ */
59
+ export function useRpcSession() {
60
+ const pos = React.useContext(EnvPosContext);
61
+ const rsc = React.useContext(RpcSessionsContext);
62
+ if (!pos)
63
+ return noPosRpcSession;
64
+ if (!rsc)
65
+ return noCtxRpcSession;
66
+ return rsc.connect(DocumentPosition.toTdpp(pos));
67
+ }
@@ -0,0 +1,98 @@
1
+ import type { Diagnostic, DocumentUri, integer, Range, TextDocumentPositionParams, VersionedTextDocumentIdentifier } from 'vscode-languageserver-protocol';
2
+ export declare enum LeanTag {
3
+ UnsolvedGoals = 1,// introduced in 2025-03-05
4
+ GoalsAccomplished = 2
5
+ }
6
+ /** Used in place of {@link Diagnostic} within `textDocument/publishDiagnostics`. */
7
+ export interface LeanDiagnostic extends Diagnostic {
8
+ fullRange?: Range;
9
+ isSilent?: boolean;
10
+ leanTags?: LeanTag[];
11
+ }
12
+ export interface LeanPublishDiagnosticsParams {
13
+ uri: DocumentUri;
14
+ version?: integer;
15
+ diagnostics: LeanDiagnostic[];
16
+ }
17
+ export interface PlainGoal {
18
+ rendered: string;
19
+ goals: string[];
20
+ }
21
+ export interface PlainTermGoal {
22
+ goal: string;
23
+ range: Range;
24
+ }
25
+ export declare enum LeanFileProgressKind {
26
+ Processing = 1,
27
+ FatalError = 2
28
+ }
29
+ export interface LeanFileProgressProcessingInfo {
30
+ /** Range for which the processing info was reported. */
31
+ range: Range;
32
+ /** Kind of progress that was reported. */
33
+ kind?: LeanFileProgressKind;
34
+ }
35
+ export interface LeanFileProgressParams {
36
+ /** The text document to which this progress notification applies. */
37
+ textDocument: VersionedTextDocumentIdentifier;
38
+ /**
39
+ * Array containing the parts of the file which are still being processed.
40
+ * The array should be empty if and only if the server is finished processing.
41
+ */
42
+ processing: LeanFileProgressProcessingInfo[];
43
+ }
44
+ declare const tag: unique symbol;
45
+ /** An RPC pointer is a reference to an object on the lean server.
46
+ * An example where you need this is passing the Environment object,
47
+ * which we need to be able to reference but which would be too large to
48
+ * send over directly.
49
+ */
50
+ export type RpcPtr<T> = {
51
+ readonly [tag]: T;
52
+ p: string;
53
+ };
54
+ export declare namespace RpcPtr {
55
+ function copy<T>(p: RpcPtr<T>): RpcPtr<T>;
56
+ /** Turns a reference into a unique string. Useful for React `key`s. */
57
+ function toKey(p: RpcPtr<any>): string;
58
+ }
59
+ export interface RpcConnectParams {
60
+ uri: DocumentUri;
61
+ }
62
+ export interface RpcConnected {
63
+ sessionId: string;
64
+ }
65
+ export interface RpcKeepAliveParams {
66
+ uri: DocumentUri;
67
+ sessionId: string;
68
+ }
69
+ export interface RpcCallParams extends TextDocumentPositionParams {
70
+ sessionId: string;
71
+ method: string;
72
+ params: any;
73
+ }
74
+ export interface RpcReleaseParams {
75
+ uri: DocumentUri;
76
+ sessionId: string;
77
+ refs: RpcPtr<any>[];
78
+ }
79
+ export declare enum RpcErrorCode {
80
+ ParseError = -32700,
81
+ InvalidRequest = -32600,
82
+ MethodNotFound = -32601,
83
+ InvalidParams = -32602,
84
+ InternalError = -32603,
85
+ ServerNotInitialized = -32002,
86
+ UnknownErrorCode = -32001,
87
+ ContentModified = -32801,
88
+ RequestCancelled = -32800,
89
+ RpcNeedsReconnect = -32900,
90
+ WorkerExited = -32901,
91
+ WorkerCrashed = -32902
92
+ }
93
+ export interface RpcError {
94
+ code: RpcErrorCode;
95
+ message: string;
96
+ }
97
+ export declare function isRpcError(x: any): x is RpcError;
98
+ export {};
@@ -0,0 +1,44 @@
1
+ // Lean 4 extensions to LSP.
2
+ export var LeanTag;
3
+ (function (LeanTag) {
4
+ LeanTag[LeanTag["UnsolvedGoals"] = 1] = "UnsolvedGoals";
5
+ LeanTag[LeanTag["GoalsAccomplished"] = 2] = "GoalsAccomplished";
6
+ })(LeanTag || (LeanTag = {}));
7
+ // Seems to be an eslint bug:
8
+ // eslint-disable-next-line no-shadow
9
+ export var LeanFileProgressKind;
10
+ (function (LeanFileProgressKind) {
11
+ LeanFileProgressKind[LeanFileProgressKind["Processing"] = 1] = "Processing";
12
+ LeanFileProgressKind[LeanFileProgressKind["FatalError"] = 2] = "FatalError";
13
+ })(LeanFileProgressKind || (LeanFileProgressKind = {}));
14
+ // eslint-disable-next-line @typescript-eslint/no-namespace
15
+ export var RpcPtr;
16
+ (function (RpcPtr) {
17
+ function copy(p) {
18
+ return { p: p.p };
19
+ }
20
+ RpcPtr.copy = copy;
21
+ /** Turns a reference into a unique string. Useful for React `key`s. */
22
+ function toKey(p) {
23
+ return p.p;
24
+ }
25
+ RpcPtr.toKey = toKey;
26
+ })(RpcPtr || (RpcPtr = {}));
27
+ export var RpcErrorCode;
28
+ (function (RpcErrorCode) {
29
+ RpcErrorCode[RpcErrorCode["ParseError"] = -32700] = "ParseError";
30
+ RpcErrorCode[RpcErrorCode["InvalidRequest"] = -32600] = "InvalidRequest";
31
+ RpcErrorCode[RpcErrorCode["MethodNotFound"] = -32601] = "MethodNotFound";
32
+ RpcErrorCode[RpcErrorCode["InvalidParams"] = -32602] = "InvalidParams";
33
+ RpcErrorCode[RpcErrorCode["InternalError"] = -32603] = "InternalError";
34
+ RpcErrorCode[RpcErrorCode["ServerNotInitialized"] = -32002] = "ServerNotInitialized";
35
+ RpcErrorCode[RpcErrorCode["UnknownErrorCode"] = -32001] = "UnknownErrorCode";
36
+ RpcErrorCode[RpcErrorCode["ContentModified"] = -32801] = "ContentModified";
37
+ RpcErrorCode[RpcErrorCode["RequestCancelled"] = -32800] = "RequestCancelled";
38
+ RpcErrorCode[RpcErrorCode["RpcNeedsReconnect"] = -32900] = "RpcNeedsReconnect";
39
+ RpcErrorCode[RpcErrorCode["WorkerExited"] = -32901] = "WorkerExited";
40
+ RpcErrorCode[RpcErrorCode["WorkerCrashed"] = -32902] = "WorkerCrashed";
41
+ })(RpcErrorCode || (RpcErrorCode = {}));
42
+ export function isRpcError(x) {
43
+ return !!(x?.code && x?.message);
44
+ }
@@ -0,0 +1,149 @@
1
+ import type { DocumentUri, Position, TextDocumentPositionParams } from 'vscode-languageserver-protocol';
2
+ import { RpcCallParams, RpcPtr, RpcReleaseParams } from './lspTypes';
3
+ /**
4
+ * Abstraction of the functionality needed
5
+ * to establish RPC sessions in the Lean server
6
+ * and to make RPC calls.
7
+ * See the Lean module `Lean.Server.Rpc.Basic`.
8
+ *
9
+ * This interface can be implemented both in the infoview
10
+ * (relaying LSP messages from the webview to the extension),
11
+ * as well as in the extension itself
12
+ * (directly sending LSP messages via the
13
+ * `vscode-languageserver-node` library (TODO)).
14
+ */
15
+ export interface RpcServerIface {
16
+ /**
17
+ * Creates an RPC session for the given URI and returns the session ID.
18
+ * The implementation of {@link RpcServerIface} takes care
19
+ * to send any required keepalive notifications.
20
+ */
21
+ createRpcSession(uri: DocumentUri): Promise<string>;
22
+ /** Closes an RPC session created with {@link createRpcSession}. */
23
+ closeRpcSession(sessionId: string): void;
24
+ /** Sends an RPC call to the Lean server. */
25
+ call(request: RpcCallParams): Promise<any>;
26
+ /** Sends an RPC reference release notification to the server. */
27
+ release(request: RpcReleaseParams): void;
28
+ }
29
+ /**
30
+ * An {@link RpcSessionForFile} with `call` specialized to a specific position `p`.
31
+ *
32
+ * Morally, this bundles an RPC session
33
+ * with the set of RPC methods
34
+ * available at the position `p`.
35
+ *
36
+ * It is okay to mix RPC references
37
+ * between different {@link RpcSessionAtPos} objects
38
+ * created from the same {@link RpcSessionForFile}.
39
+ */
40
+ export interface RpcSessionAtPos {
41
+ /**
42
+ * Invoke an RPC method in the Lean server.
43
+ *
44
+ * @param method fully qualified name of the method to call.
45
+ * @param params arguments to the invoked method.
46
+ * @returns a promise that resolves to the returned value, or an error in case the call fails.
47
+ */
48
+ call<T, S>(method: string, params: T): Promise<S>;
49
+ }
50
+ /**
51
+ * Manages a connection to an RPC session
52
+ * that has been opened for a given file
53
+ * (in the Lean server's worker process for that file).
54
+ *
55
+ * An RPC session keeps track of a set of RPC references
56
+ * that are mutually intelligible,
57
+ * in the sense that any RPC method can be called
58
+ * with any number of references from this set.
59
+ * On the other hand,
60
+ * it is not possible to mix RPC references
61
+ * between different sessions.
62
+ */
63
+ declare class RpcSessionForFile {
64
+ uri: DocumentUri;
65
+ sessions: RpcSessions;
66
+ sessionId: Promise<string>;
67
+ /**
68
+ * If present, stores a fatal exception
69
+ * indicating that the RPC session can no longer be used.
70
+ * For example: the worker crashed
71
+ */
72
+ failed?: any;
73
+ refsToRelease: RpcPtr<any>[];
74
+ finalizers: FinalizationRegistry<RpcPtr<any>>;
75
+ /** Essentially a cache for {@link at}. See {@link at} for why we need this. */
76
+ sessionsAtPos: Map<string, RpcSessionAtPos>;
77
+ constructor(uri: DocumentUri, sessions: RpcSessions);
78
+ releaseNow(): Promise<void>;
79
+ /**
80
+ * Traverses an object received from the RPC server
81
+ * and registers all contained references
82
+ * for future garbage collection.
83
+ *
84
+ * The function implements a form of "conservative garbage collection"
85
+ * where it treats any subobject `{'p': v}` as a potential RPC reference.
86
+ * Therefore `p` should not be used as a field name on the Lean side
87
+ * to prevent false positives.
88
+ *
89
+ * It is unclear if the false positives will become a big issue.
90
+ * Earlier versions of the extension
91
+ * had manually written registration functions for every type,
92
+ * but those are a lot of boilerplate.
93
+ * If we change back to that approach,
94
+ * we should generate them automatically.
95
+ */
96
+ registerRefs(o: any): void;
97
+ private failWithoutClosing;
98
+ fail(reason: any): void;
99
+ /**
100
+ * Invoke an RPC method in the Lean server.
101
+ *
102
+ * To compute the set of RPC methods that can be called,
103
+ * the server finds the environment `e` at the source code location `this.uri:position`.
104
+ * The callable methods are then all the builtin ones,
105
+ * and all constants in `e` marked with `@[server_rpc_method]`
106
+ * (i.e., the `@[server_rpc_method]` declarations made above `this.uri:position`).
107
+ *
108
+ * @param position within the file identified by {@link uri}, used to resolve the set of available RPC methods.
109
+ * @param method fully qualified name of the method to call.
110
+ * @param params arguments to the invoked method.
111
+ * @returns a promise that resolves to the returned value, or to an error in case the call fails.
112
+ */
113
+ call(position: Position, method: string, params: any): Promise<any>;
114
+ /**
115
+ * Returns this session with {@link call} specialized to `position` within the file.
116
+ * This is guaranteed to return the same (by reference) object
117
+ * if called multiple times with the same (by deep comparison) position,
118
+ * on the same {@link RpcSessionForFile}.
119
+ * It can therefore be used as a React dep.
120
+ */
121
+ at(position: Position): RpcSessionAtPos;
122
+ }
123
+ /** Manages RPC sessions for multiple files. */
124
+ export declare class RpcSessions {
125
+ iface: RpcServerIface;
126
+ /**
127
+ * Contains the active {@link RpcSessionForFile} objects.
128
+ * Once an {@link RpcSessionForFile} is set to failed (e.g. due to a server crash),
129
+ * it is removed from this map.
130
+ * The {@link connect} method will then automatically reconnect
131
+ * the next time it is called.
132
+ */
133
+ sessions: Map<DocumentUri, RpcSessionForFile>;
134
+ constructor(iface: RpcServerIface);
135
+ private connectCore;
136
+ /**
137
+ * Returns an {@link RpcSessionAtPos} for the given document and position.
138
+ * Calling {@link connect} multiple times will return the same
139
+ * session (with the same session ID).
140
+ * A new session is only created if a fatal error occurs (the worker crashes)
141
+ * or the session is closed manually (the file is closed).
142
+ */
143
+ connect(pos: TextDocumentPositionParams): RpcSessionAtPos;
144
+ /** Closes the session for the given URI. */
145
+ closeSessionForFile(uri: DocumentUri): void;
146
+ closeAllSessions(): void;
147
+ dispose(): void;
148
+ }
149
+ export {};
@@ -0,0 +1,215 @@
1
+ import { RpcErrorCode, RpcPtr } from './lspTypes';
2
+ /**
3
+ * Manages a connection to an RPC session
4
+ * that has been opened for a given file
5
+ * (in the Lean server's worker process for that file).
6
+ *
7
+ * An RPC session keeps track of a set of RPC references
8
+ * that are mutually intelligible,
9
+ * in the sense that any RPC method can be called
10
+ * with any number of references from this set.
11
+ * On the other hand,
12
+ * it is not possible to mix RPC references
13
+ * between different sessions.
14
+ */
15
+ class RpcSessionForFile {
16
+ uri;
17
+ sessions;
18
+ sessionId;
19
+ /**
20
+ * If present, stores a fatal exception
21
+ * indicating that the RPC session can no longer be used.
22
+ * For example: the worker crashed
23
+ */
24
+ failed;
25
+ refsToRelease = [];
26
+ finalizers;
27
+ /** Essentially a cache for {@link at}. See {@link at} for why we need this. */
28
+ sessionsAtPos = new Map();
29
+ constructor(uri, sessions) {
30
+ this.uri = uri;
31
+ this.sessions = sessions;
32
+ this.sessionId = (async () => {
33
+ try {
34
+ return await sessions.iface.createRpcSession(uri);
35
+ }
36
+ catch (ex) {
37
+ this.failWithoutClosing(ex);
38
+ throw ex;
39
+ }
40
+ })();
41
+ this.sessionId.catch(() => { }); // silence uncaught exception warning
42
+ // Here we hook into the JS GC and send release-reference notifications
43
+ // whenever the GC finalizes a number of `RpcPtr`s. Requires ES2021.
44
+ let releaseTimeout;
45
+ this.finalizers = new FinalizationRegistry(ptr => {
46
+ if (this.failed)
47
+ return;
48
+ this.refsToRelease.push(ptr);
49
+ // We release eagerly instead of delaying when this many refs become garbage
50
+ const maxBatchSize = 100;
51
+ if (this.refsToRelease.length > maxBatchSize) {
52
+ void this.releaseNow();
53
+ clearTimeout(releaseTimeout);
54
+ releaseTimeout = undefined;
55
+ }
56
+ else if (releaseTimeout === undefined) {
57
+ releaseTimeout = window.setTimeout(() => {
58
+ void this.releaseNow();
59
+ releaseTimeout = undefined;
60
+ }, 100);
61
+ }
62
+ });
63
+ }
64
+ async releaseNow() {
65
+ const sessionId = await this.sessionId;
66
+ if (this.failed || this.refsToRelease.length === 0)
67
+ return;
68
+ this.sessions.iface.release({
69
+ uri: this.uri,
70
+ sessionId,
71
+ refs: this.refsToRelease,
72
+ });
73
+ this.refsToRelease = [];
74
+ }
75
+ /**
76
+ * Traverses an object received from the RPC server
77
+ * and registers all contained references
78
+ * for future garbage collection.
79
+ *
80
+ * The function implements a form of "conservative garbage collection"
81
+ * where it treats any subobject `{'p': v}` as a potential RPC reference.
82
+ * Therefore `p` should not be used as a field name on the Lean side
83
+ * to prevent false positives.
84
+ *
85
+ * It is unclear if the false positives will become a big issue.
86
+ * Earlier versions of the extension
87
+ * had manually written registration functions for every type,
88
+ * but those are a lot of boilerplate.
89
+ * If we change back to that approach,
90
+ * we should generate them automatically.
91
+ */
92
+ registerRefs(o) {
93
+ if (o instanceof Object) {
94
+ if (Object.keys(o).length === 1 && 'p' in o && typeof o.p !== 'object') {
95
+ this.finalizers.register(o, RpcPtr.copy(o));
96
+ }
97
+ else {
98
+ for (const v of Object.values(o))
99
+ this.registerRefs(v);
100
+ }
101
+ }
102
+ else if (o instanceof Array) {
103
+ for (const e of o)
104
+ this.registerRefs(e);
105
+ }
106
+ }
107
+ failWithoutClosing(reason) {
108
+ this.failed = reason;
109
+ // NOTE(WN): the sessions map is keyed by URI rather than ID and by the time this
110
+ // function executes, a new session for the same file may already have been added.
111
+ // So we should only delete the stored session if it's still this one.
112
+ if (this.sessions.sessions.get(this.uri) === this) {
113
+ this.sessions.sessions.delete(this.uri);
114
+ }
115
+ }
116
+ fail(reason) {
117
+ this.failWithoutClosing(reason);
118
+ void this.sessionId.then(id => this.sessions.iface.closeRpcSession(id));
119
+ }
120
+ /**
121
+ * Invoke an RPC method in the Lean server.
122
+ *
123
+ * To compute the set of RPC methods that can be called,
124
+ * the server finds the environment `e` at the source code location `this.uri:position`.
125
+ * The callable methods are then all the builtin ones,
126
+ * and all constants in `e` marked with `@[server_rpc_method]`
127
+ * (i.e., the `@[server_rpc_method]` declarations made above `this.uri:position`).
128
+ *
129
+ * @param position within the file identified by {@link uri}, used to resolve the set of available RPC methods.
130
+ * @param method fully qualified name of the method to call.
131
+ * @param params arguments to the invoked method.
132
+ * @returns a promise that resolves to the returned value, or to an error in case the call fails.
133
+ */
134
+ async call(position, method, params) {
135
+ const sessionId = await this.sessionId;
136
+ if (this.failed)
137
+ throw this.failed;
138
+ const tdpp = { position, textDocument: { uri: this.uri } };
139
+ try {
140
+ const result = await this.sessions.iface.call({ method, params, sessionId, ...tdpp });
141
+ this.registerRefs(result);
142
+ // HACK: most of our types are `T | undefined` so try to return something matching that interface
143
+ if (result === null)
144
+ return undefined;
145
+ return result;
146
+ }
147
+ catch (ex) {
148
+ if (ex?.code === RpcErrorCode.WorkerCrashed ||
149
+ ex?.code === RpcErrorCode.WorkerExited ||
150
+ ex?.code === RpcErrorCode.RpcNeedsReconnect) {
151
+ this.fail(ex);
152
+ }
153
+ throw ex;
154
+ }
155
+ }
156
+ /**
157
+ * Returns this session with {@link call} specialized to `position` within the file.
158
+ * This is guaranteed to return the same (by reference) object
159
+ * if called multiple times with the same (by deep comparison) position,
160
+ * on the same {@link RpcSessionForFile}.
161
+ * It can therefore be used as a React dep.
162
+ */
163
+ at(position) {
164
+ // As JS tradition dictates, we use stringification for deep comparison of `Position`s in a `Map`.
165
+ const posStr = `${position.line}:${position.character}`;
166
+ if (this.sessionsAtPos.has(posStr))
167
+ return this.sessionsAtPos.get(posStr);
168
+ const atPos = { call: (method, params) => this.call(position, method, params) };
169
+ this.sessionsAtPos.set(posStr, atPos);
170
+ return atPos;
171
+ }
172
+ }
173
+ /** Manages RPC sessions for multiple files. */
174
+ export class RpcSessions {
175
+ iface;
176
+ /**
177
+ * Contains the active {@link RpcSessionForFile} objects.
178
+ * Once an {@link RpcSessionForFile} is set to failed (e.g. due to a server crash),
179
+ * it is removed from this map.
180
+ * The {@link connect} method will then automatically reconnect
181
+ * the next time it is called.
182
+ */
183
+ sessions = new Map();
184
+ constructor(iface) {
185
+ this.iface = iface;
186
+ }
187
+ connectCore(uri) {
188
+ if (this.sessions.has(uri))
189
+ return this.sessions.get(uri);
190
+ const sess = new RpcSessionForFile(uri, this);
191
+ this.sessions.set(uri, sess);
192
+ return sess;
193
+ }
194
+ /**
195
+ * Returns an {@link RpcSessionAtPos} for the given document and position.
196
+ * Calling {@link connect} multiple times will return the same
197
+ * session (with the same session ID).
198
+ * A new session is only created if a fatal error occurs (the worker crashes)
199
+ * or the session is closed manually (the file is closed).
200
+ */
201
+ connect(pos) {
202
+ return this.connectCore(pos.textDocument.uri).at(pos.position);
203
+ }
204
+ /** Closes the session for the given URI. */
205
+ closeSessionForFile(uri) {
206
+ void this.sessions.get(uri)?.fail('file closed');
207
+ }
208
+ closeAllSessions() {
209
+ for (const k of [...this.sessions.keys()])
210
+ this.closeSessionForFile(k);
211
+ }
212
+ dispose() {
213
+ this.closeAllSessions();
214
+ }
215
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "lean4monaco",
3
- "version": "1.1.11",
3
+ "version": "1.1.14",
4
4
  "description": "Monaco Editor support for the Lean 4 theorem prover.",
5
5
  "keywords": [
6
6
  "lean",