lean4monaco 1.0.2 → 1.0.4
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/monaco-lean4/lean4-infoview/src/index.d.ts +16 -0
- package/dist/monaco-lean4/lean4-infoview/src/index.js +29 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/collapsing.d.ts +12 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/collapsing.js +37 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/contexts.d.ts +40 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/contexts.js +44 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/editorConnection.d.ts +22 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/editorConnection.js +41 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/errors.d.ts +14 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/errors.js +24 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/event.d.ts +33 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/event.js +57 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/goalLocation.d.ts +61 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/goalLocation.js +87 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/goals.d.ts +11 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/goals.js +141 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/info.d.ts +18 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/info.js +278 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/infos.d.ts +2 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/infos.js +113 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/interactiveCode.d.ts +18 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/interactiveCode.js +164 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/main.d.ts +13 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/main.js +97 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/messages.d.ts +16 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/messages.js +151 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/rpcSessions.d.ts +21 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/rpcSessions.js +67 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/serverVersion.d.ts +10 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/serverVersion.js +25 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/tooltips.d.ts +23 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/tooltips.js +231 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/traceExplorer.d.ts +11 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/traceExplorer.js +115 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/userWidget.d.ts +48 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/userWidget.js +54 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/util.d.ts +144 -0
- package/dist/monaco-lean4/lean4-infoview/src/infoview/util.js +366 -0
- package/dist/monaco-lean4/vscode-lean4/src/utils/batch.d.ts +0 -1
- package/dist/monaco-lean4/vscode-lean4/src/utils/envPath.d.ts +0 -1
- package/dist/monaco-lean4/vscode-lean4/src/utils/fsHelper.d.ts +0 -1
- package/package.json +3 -4
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-namespace */
|
|
2
|
+
/* eslint-disable react-hooks/exhaustive-deps */
|
|
3
|
+
import * as React from 'react';
|
|
4
|
+
import { isRpcError, RpcErrorCode } from '@leanprover/infoview-api';
|
|
5
|
+
import { EditorContext } from './contexts';
|
|
6
|
+
export var DocumentPosition;
|
|
7
|
+
(function (DocumentPosition) {
|
|
8
|
+
function isEqual(p1, p2) {
|
|
9
|
+
return p1.uri === p2.uri && p1.line === p2.line && p1.character === p2.character;
|
|
10
|
+
}
|
|
11
|
+
DocumentPosition.isEqual = isEqual;
|
|
12
|
+
function toTdpp(p) {
|
|
13
|
+
return { textDocument: { uri: p.uri }, position: { line: p.line, character: p.character } };
|
|
14
|
+
}
|
|
15
|
+
DocumentPosition.toTdpp = toTdpp;
|
|
16
|
+
function toString(p) {
|
|
17
|
+
return `${p.uri}:${p.line + 1}:${p.character}`;
|
|
18
|
+
}
|
|
19
|
+
DocumentPosition.toString = toString;
|
|
20
|
+
})(DocumentPosition || (DocumentPosition = {}));
|
|
21
|
+
export var PositionHelpers;
|
|
22
|
+
(function (PositionHelpers) {
|
|
23
|
+
function isLessThanOrEqual(p1, p2) {
|
|
24
|
+
return p1.line < p2.line || (p1.line === p2.line && p1.character <= p2.character);
|
|
25
|
+
}
|
|
26
|
+
PositionHelpers.isLessThanOrEqual = isLessThanOrEqual;
|
|
27
|
+
})(PositionHelpers || (PositionHelpers = {}));
|
|
28
|
+
export var RangeHelpers;
|
|
29
|
+
(function (RangeHelpers) {
|
|
30
|
+
function contains(range, pos, ignoreCharacter) {
|
|
31
|
+
if (!ignoreCharacter) {
|
|
32
|
+
if (pos.line === range.start.line && pos.character < range.start.character)
|
|
33
|
+
return false;
|
|
34
|
+
if (pos.line === range.end.line && pos.character > range.end.character)
|
|
35
|
+
return false;
|
|
36
|
+
}
|
|
37
|
+
return range.start.line <= pos.line && pos.line <= range.end.line;
|
|
38
|
+
}
|
|
39
|
+
RangeHelpers.contains = contains;
|
|
40
|
+
})(RangeHelpers || (RangeHelpers = {}));
|
|
41
|
+
// https://stackoverflow.com/questions/6234773/can-i-escape-html-special-chars-in-javascript
|
|
42
|
+
export function escapeHtml(s) {
|
|
43
|
+
return s
|
|
44
|
+
.replace(/&/g, '&')
|
|
45
|
+
.replace(/</g, '<')
|
|
46
|
+
.replace(/>/g, '>')
|
|
47
|
+
.replace(/"/g, '"')
|
|
48
|
+
.replace(/'/g, ''');
|
|
49
|
+
}
|
|
50
|
+
/** @deprecated (unused) */
|
|
51
|
+
export function colorizeMessage(goal) {
|
|
52
|
+
return goal
|
|
53
|
+
.replace(/^([|⊢]) /gm, '<strong class="goal-vdash">$1</strong> ')
|
|
54
|
+
.replace(/^(\d+ goals|1 goal)/gm, '<strong class="goal-goals">$1</strong>')
|
|
55
|
+
.replace(/^(context|state):/gm, '<strong class="goal-goals">$1</strong>:')
|
|
56
|
+
.replace(/^(case) /gm, '<strong class="goal-case">$1</strong> ')
|
|
57
|
+
.replace(/^([^:\n< ][^:\n⊢{[(⦃]*) :/gm, '<strong class="goal-hyp">$1</strong> :');
|
|
58
|
+
}
|
|
59
|
+
export function basename(path) {
|
|
60
|
+
const bn = path.split(/[\\/]/).pop();
|
|
61
|
+
if (bn)
|
|
62
|
+
return bn;
|
|
63
|
+
else
|
|
64
|
+
return '';
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* A specialization of {@link React.useEffect} which executes `f` with the event data
|
|
68
|
+
* whenever `ev` fires.
|
|
69
|
+
* If `key` is provided, `f` is only invoked on events fired with that key.
|
|
70
|
+
*/
|
|
71
|
+
export function useEvent(ev, f, dependencies, key) {
|
|
72
|
+
React.useEffect(() => {
|
|
73
|
+
const h = ev.on(f, key);
|
|
74
|
+
return () => h.dispose();
|
|
75
|
+
}, dependencies);
|
|
76
|
+
}
|
|
77
|
+
export function useEventResult(ev, f) {
|
|
78
|
+
const fn = f ?? (x => x);
|
|
79
|
+
const [s, setS] = React.useState(ev.current ? fn(ev.current) : undefined);
|
|
80
|
+
useEvent(ev, newV => setS(newV ? fn(newV) : undefined));
|
|
81
|
+
return s;
|
|
82
|
+
}
|
|
83
|
+
export function useServerNotificationEffect(method, f, deps) {
|
|
84
|
+
const ec = React.useContext(EditorContext);
|
|
85
|
+
React.useEffect(() => {
|
|
86
|
+
void ec.api.subscribeServerNotifications(method).catch(ex => {
|
|
87
|
+
console.error(`Failed subscribing to server notification '${method}': ${ex}`);
|
|
88
|
+
});
|
|
89
|
+
const h = ec.events.gotServerNotification.on(([thisMethod, params]) => {
|
|
90
|
+
if (thisMethod !== method)
|
|
91
|
+
return;
|
|
92
|
+
f(params);
|
|
93
|
+
});
|
|
94
|
+
return () => {
|
|
95
|
+
h.dispose();
|
|
96
|
+
void ec.api.unsubscribeServerNotifications(method);
|
|
97
|
+
};
|
|
98
|
+
}, deps);
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Returns the same tuple as `setState` such that whenever a server notification with `method`
|
|
102
|
+
* arrives at the editor, the state will be updated according to `f`.
|
|
103
|
+
*/
|
|
104
|
+
export function useServerNotificationState(method, initial, f, deps) {
|
|
105
|
+
const [s, setS] = React.useState(initial);
|
|
106
|
+
useServerNotificationEffect(method, (params) => void f(params).then(g => setS(g)), deps);
|
|
107
|
+
return [s, setS];
|
|
108
|
+
}
|
|
109
|
+
export function useClientNotificationEffect(method, f, deps) {
|
|
110
|
+
const ec = React.useContext(EditorContext);
|
|
111
|
+
React.useEffect(() => {
|
|
112
|
+
void ec.api.subscribeClientNotifications(method).catch(ex => {
|
|
113
|
+
console.error(`Failed subscribing to client notification '${method}': ${ex}`);
|
|
114
|
+
});
|
|
115
|
+
const h = ec.events.sentClientNotification.on(([thisMethod, params]) => {
|
|
116
|
+
if (thisMethod !== method)
|
|
117
|
+
return;
|
|
118
|
+
f(params);
|
|
119
|
+
});
|
|
120
|
+
return () => {
|
|
121
|
+
h.dispose();
|
|
122
|
+
void ec.api.unsubscribeClientNotifications(method);
|
|
123
|
+
};
|
|
124
|
+
}, deps);
|
|
125
|
+
}
|
|
126
|
+
/**
|
|
127
|
+
* Like {@link useServerNotificationState} but for client->server notifications sent by the editor.
|
|
128
|
+
*/
|
|
129
|
+
export function useClientNotificationState(method, initial, f, deps) {
|
|
130
|
+
const [s, setS] = React.useState(initial);
|
|
131
|
+
useClientNotificationEffect(method, (params) => {
|
|
132
|
+
setS(state => f(state, params));
|
|
133
|
+
}, deps);
|
|
134
|
+
return [s, setS];
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Returns `[{ isPaused, setPaused }, tPausable, tRef]` s.t.
|
|
138
|
+
* - `[isPaused, setPaused]` are the paused status state
|
|
139
|
+
* - for as long as `isPaused` is set, `tPausable` holds its initial value (the `t` passed before pausing)
|
|
140
|
+
* rather than updates with changes to `t`.
|
|
141
|
+
* - `tRef` can be used to overwrite the paused state
|
|
142
|
+
*
|
|
143
|
+
* To pause child components, `startPaused` can be passed in their props.
|
|
144
|
+
*/
|
|
145
|
+
export function usePausableState(startPaused, t) {
|
|
146
|
+
const [isPaused, setPaused] = React.useState(startPaused);
|
|
147
|
+
const old = React.useRef(t);
|
|
148
|
+
if (!isPaused)
|
|
149
|
+
old.current = t;
|
|
150
|
+
return [{ isPaused, setPaused }, old.current, old];
|
|
151
|
+
}
|
|
152
|
+
/**
|
|
153
|
+
* Adds a unique `key` property to each element in `elems` using
|
|
154
|
+
* the values of (possibly non-injective) `getId`.
|
|
155
|
+
*/
|
|
156
|
+
export function addUniqueKeys(elems, getId) {
|
|
157
|
+
const keys = {};
|
|
158
|
+
return elems.map(el => {
|
|
159
|
+
const id = getId(el);
|
|
160
|
+
keys[id] = (keys[id] || 0) + 1;
|
|
161
|
+
return { key: `${id}:${keys[id]}`, ...el };
|
|
162
|
+
});
|
|
163
|
+
}
|
|
164
|
+
/** Like `React.forwardRef`, but also allows reading the ref inside the forwarding component.
|
|
165
|
+
* Adapted from https://itnext.io/reusing-the-ref-from-forwardref-with-react-hooks-4ce9df693dd */
|
|
166
|
+
export function forwardAndUseRef(render) {
|
|
167
|
+
return React.forwardRef((props, ref) => {
|
|
168
|
+
const thisRef = React.useRef(null);
|
|
169
|
+
return render(props, thisRef, v => {
|
|
170
|
+
thisRef.current = v;
|
|
171
|
+
if (!ref)
|
|
172
|
+
return;
|
|
173
|
+
if (typeof ref === 'function') {
|
|
174
|
+
ref(v);
|
|
175
|
+
}
|
|
176
|
+
else {
|
|
177
|
+
ref.current = v;
|
|
178
|
+
}
|
|
179
|
+
});
|
|
180
|
+
});
|
|
181
|
+
}
|
|
182
|
+
/** Like `forwardAndUseRef`, but the ref is stored in state so that setting it triggers a render.
|
|
183
|
+
* Should only be used if re-rendering is necessary. */
|
|
184
|
+
export function forwardAndUseStateRef(render) {
|
|
185
|
+
return React.forwardRef((props, ref) => {
|
|
186
|
+
const [thisRef, setThisRef] = React.useState(null);
|
|
187
|
+
return render(props, thisRef, v => {
|
|
188
|
+
setThisRef(v);
|
|
189
|
+
if (!ref)
|
|
190
|
+
return;
|
|
191
|
+
if (typeof ref === 'function') {
|
|
192
|
+
ref(v);
|
|
193
|
+
}
|
|
194
|
+
else {
|
|
195
|
+
ref.current = v;
|
|
196
|
+
}
|
|
197
|
+
});
|
|
198
|
+
});
|
|
199
|
+
}
|
|
200
|
+
export const LogicalDomContext = React.createContext({ registerDescendant: () => () => { } });
|
|
201
|
+
/** Suppose a component B appears as a React descendant of the component A. For layout reasons,
|
|
202
|
+
* we sometimes don't want B to appear as a descendant of A in the DOM, so we use `createPortal`.
|
|
203
|
+
* We may still however want to carry out `contains` checks as if B were there, i.e. according to
|
|
204
|
+
* the React tree structure rather than the DOM structure. While React already correctly propagates
|
|
205
|
+
* DOM events up the React tree, other functionality such as `contains` is not provided. We provide
|
|
206
|
+
* it in this hook.
|
|
207
|
+
*
|
|
208
|
+
* Accepts a ref to the observed {@link HTMLElement} (A in the example). Returns:
|
|
209
|
+
* - a {@link LogicalDomElement} which provides `contains` checks for that {@link HTMLElement}; and
|
|
210
|
+
* - a {@link LogicalDomStorage} which MUST be passed to a {@link LogicalDomContext} enclosing
|
|
211
|
+
* the observed {@link HTMLElement}.
|
|
212
|
+
*
|
|
213
|
+
* Additionally, any component which introduces a portal MUST call `registerDescendant` in the
|
|
214
|
+
* {@link LogicalDomContext} with a ref to the portalled component (B in the example). */
|
|
215
|
+
export function useLogicalDomObserver(elt) {
|
|
216
|
+
const parentCtx = React.useContext(LogicalDomContext);
|
|
217
|
+
const descendants = React.useRef(new Set());
|
|
218
|
+
// Provides a `contains` check for the children only, but not the observed element.
|
|
219
|
+
// We pass this to the parent context under the assumption that its own DOM-based
|
|
220
|
+
// `contains` check already includes the observed element.
|
|
221
|
+
const logicalChildrenElt = React.useMemo(() => ({
|
|
222
|
+
contains: (e) => {
|
|
223
|
+
for (const d of descendants.current) {
|
|
224
|
+
if (d.contains(e))
|
|
225
|
+
return true;
|
|
226
|
+
}
|
|
227
|
+
return false;
|
|
228
|
+
},
|
|
229
|
+
}), []);
|
|
230
|
+
React.useEffect(() => parentCtx.registerDescendant(logicalChildrenElt), [parentCtx, logicalChildrenElt]);
|
|
231
|
+
const logicalElt = React.useMemo(() => ({
|
|
232
|
+
contains: (e) => {
|
|
233
|
+
if (!elt.current)
|
|
234
|
+
return false;
|
|
235
|
+
if (elt.current.contains(e))
|
|
236
|
+
return true;
|
|
237
|
+
return logicalChildrenElt.contains(e);
|
|
238
|
+
},
|
|
239
|
+
}), [elt, logicalChildrenElt]);
|
|
240
|
+
const registerDescendant = React.useCallback((el) => {
|
|
241
|
+
descendants.current.add(el);
|
|
242
|
+
return () => {
|
|
243
|
+
descendants.current.delete(el);
|
|
244
|
+
};
|
|
245
|
+
}, []);
|
|
246
|
+
return [logicalElt, React.useMemo(() => ({ registerDescendant }), [registerDescendant])];
|
|
247
|
+
}
|
|
248
|
+
/**
|
|
249
|
+
* An effect which calls `onClickOutside` whenever an element not logically descending from `ld`
|
|
250
|
+
* (see {@link useLogicalDomObserver}) is clicked. Note that `onClickOutside` is not called on clicks
|
|
251
|
+
* on the scrollbar since these should usually not impact the app's state. */
|
|
252
|
+
export function useOnClickOutside(ld, onClickOutside) {
|
|
253
|
+
React.useEffect(() => {
|
|
254
|
+
const onClickAnywhere = (e) => {
|
|
255
|
+
if (e.target instanceof Node && !ld.contains(e.target)) {
|
|
256
|
+
if (e.target instanceof Element && e.target.tagName === 'HTML') {
|
|
257
|
+
// then user might be clicking in a scrollbar, otherwise
|
|
258
|
+
// e.target would be a tag other than 'HTML'
|
|
259
|
+
}
|
|
260
|
+
else
|
|
261
|
+
onClickOutside(e);
|
|
262
|
+
}
|
|
263
|
+
};
|
|
264
|
+
document.addEventListener('pointerdown', onClickAnywhere);
|
|
265
|
+
return () => document.removeEventListener('pointerdown', onClickAnywhere);
|
|
266
|
+
}, [ld, onClickOutside]);
|
|
267
|
+
}
|
|
268
|
+
/** Sends an exception object to a throwable error.
|
|
269
|
+
* Maps JSON Rpc errors to throwable errors.
|
|
270
|
+
*/
|
|
271
|
+
export function mapRpcError(err) {
|
|
272
|
+
if (isRpcError(err)) {
|
|
273
|
+
return new Error(`Rpc error: ${RpcErrorCode[err.code]}: ${err.message}`);
|
|
274
|
+
}
|
|
275
|
+
else if (!(err instanceof Error)) {
|
|
276
|
+
return new Error(`Unrecognised error ${JSON.stringify(err)}`);
|
|
277
|
+
}
|
|
278
|
+
else {
|
|
279
|
+
return err;
|
|
280
|
+
}
|
|
281
|
+
}
|
|
282
|
+
/** Catch handler for RPC methods that just returns undefined if the method is not found.
|
|
283
|
+
* This is useful for compatibility with versions of Lean that do not yet have the given RPC method.
|
|
284
|
+
*/
|
|
285
|
+
export function discardMethodNotFound(e) {
|
|
286
|
+
if (isRpcError(e) && e.code === RpcErrorCode.MethodNotFound) {
|
|
287
|
+
return undefined;
|
|
288
|
+
}
|
|
289
|
+
else {
|
|
290
|
+
throw mapRpcError(e);
|
|
291
|
+
}
|
|
292
|
+
}
|
|
293
|
+
export function useAsyncWithTrigger(fn, deps = []) {
|
|
294
|
+
const asyncState = React.useRef({ state: 'notStarted' });
|
|
295
|
+
const asyncStateDeps = React.useRef([]);
|
|
296
|
+
// A monotonically increasing counter.
|
|
297
|
+
const tick = React.useRef(0);
|
|
298
|
+
// This is bumped up to the current `tick` whenever `asyncState.current` is assigned,
|
|
299
|
+
// in order to trigger a React update.
|
|
300
|
+
const [_, setUpdate] = React.useState(0);
|
|
301
|
+
const trigger = React.useCallback(async () => {
|
|
302
|
+
if (asyncState.current.state === 'loading' || asyncState.current.state === 'resolved')
|
|
303
|
+
return;
|
|
304
|
+
tick.current += 1;
|
|
305
|
+
asyncState.current = { state: 'loading' };
|
|
306
|
+
setUpdate(tick.current);
|
|
307
|
+
tick.current += 1;
|
|
308
|
+
const startTick = tick.current;
|
|
309
|
+
const set = (state) => {
|
|
310
|
+
if (tick.current === startTick) {
|
|
311
|
+
asyncState.current = state;
|
|
312
|
+
setUpdate(tick.current);
|
|
313
|
+
}
|
|
314
|
+
};
|
|
315
|
+
return fn().then(value => set({ state: 'resolved', value }), error => set({ state: 'rejected', error }));
|
|
316
|
+
}, deps);
|
|
317
|
+
const depsTheSame = asyncStateDeps.current.length === deps.length && asyncStateDeps.current.every((d, i) => Object.is(d, deps[i]));
|
|
318
|
+
if (!depsTheSame) {
|
|
319
|
+
tick.current += 1;
|
|
320
|
+
asyncState.current = { state: 'notStarted' };
|
|
321
|
+
asyncStateDeps.current = deps;
|
|
322
|
+
setUpdate(tick.current);
|
|
323
|
+
}
|
|
324
|
+
return [asyncState.current, trigger];
|
|
325
|
+
}
|
|
326
|
+
/** This React hook will run the given promise function `fn` whenever the deps change
|
|
327
|
+
* and use it to update the status and result when the promise resolves.
|
|
328
|
+
*
|
|
329
|
+
* This function prevents race conditions if the requests resolve in a
|
|
330
|
+
* different order to that which they were requested in:
|
|
331
|
+
*
|
|
332
|
+
* - Request 1 is sent with, say, line=42.
|
|
333
|
+
* - Request 2 is sent with line=90.
|
|
334
|
+
* - Request 2 returns with diags=[].
|
|
335
|
+
* - Request 1 returns with diags=['error'].
|
|
336
|
+
*
|
|
337
|
+
* Without `useAsync` we would now return the diagnostics for line 42 even though we're at line 90.
|
|
338
|
+
*
|
|
339
|
+
* When the deps change, the function immediately returns `{ state: 'loading' }`.
|
|
340
|
+
*/
|
|
341
|
+
export function useAsync(fn, deps = []) {
|
|
342
|
+
const [state, trigger] = useAsyncWithTrigger(fn, deps);
|
|
343
|
+
if (state.state === 'notStarted') {
|
|
344
|
+
void trigger();
|
|
345
|
+
return { state: 'loading' };
|
|
346
|
+
}
|
|
347
|
+
else {
|
|
348
|
+
return state;
|
|
349
|
+
}
|
|
350
|
+
}
|
|
351
|
+
/** Like {@link useAsync} but never transitions from `resolved` to `loading` by internally storing
|
|
352
|
+
* the latest `resolved` state and continuing to return it while an update is in flight. The lower
|
|
353
|
+
* amount of re-renders tends to be less visually jarring.
|
|
354
|
+
*/
|
|
355
|
+
export function useAsyncPersistent(fn, deps = []) {
|
|
356
|
+
const [latestState, setLatestState] = React.useState(undefined);
|
|
357
|
+
const state = useAsync(async () => {
|
|
358
|
+
const newState = await fn();
|
|
359
|
+
setLatestState(newState);
|
|
360
|
+
return newState;
|
|
361
|
+
}, deps);
|
|
362
|
+
if (state.state === 'loading' && latestState !== undefined) {
|
|
363
|
+
return { state: 'resolved', value: latestState };
|
|
364
|
+
}
|
|
365
|
+
return state;
|
|
366
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "lean4monaco",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"files": ["dist"],
|
|
@@ -30,15 +30,14 @@
|
|
|
30
30
|
"dependencies": {
|
|
31
31
|
"@codingame/monaco-vscode-views-service-override": "^6.0.1",
|
|
32
32
|
"@leanprover/infoview": "=0.7.0",
|
|
33
|
-
"@leanprover/infoview-api": "
|
|
34
|
-
"@leanprover/unicode-input": "
|
|
33
|
+
"@leanprover/infoview-api": "=0.4.0",
|
|
34
|
+
"@leanprover/unicode-input": "=0.1.0",
|
|
35
35
|
"axios": "^1.7.2",
|
|
36
36
|
"cheerio": "^1.0.0-rc.12",
|
|
37
37
|
"concurrently": "^8.2.2",
|
|
38
38
|
"memfs": "^4.9.3",
|
|
39
39
|
"mobx": "5.15.7",
|
|
40
40
|
"monaco-editor-wrapper": "^5.3.1",
|
|
41
|
-
"react-dom": "^18.3.1",
|
|
42
41
|
"semver": "^7.6.2",
|
|
43
42
|
"zod": "^3.23.8"
|
|
44
43
|
}
|