@joinezco/codeblock 0.0.8 → 0.0.9
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/assets/fs.worker-DfanUHpQ.js +21 -0
- package/dist/assets/{index-MGle_v2x.js → index-BAnLzvMk.js} +1 -1
- package/dist/assets/{index-as7ELo0J.js → index-BBC9WDX6.js} +1 -1
- package/dist/assets/{index-Dx_VuNNd.js → index-BEXYxRro.js} +1 -1
- package/dist/assets/{index-pGm0qkrJ.js → index-BfYmUKH9.js} +1 -1
- package/dist/assets/{index-CXFONXS8.js → index-BhaTNAWE.js} +1 -1
- package/dist/assets/{index-D5Z27j1C.js → index-CCbYDSng.js} +1 -1
- package/dist/assets/{index-Dvu-FFzd.js → index-CIi8tLT6.js} +1 -1
- package/dist/assets/{index-C-QhPFHP.js → index-CaANcgI2.js} +1 -1
- package/dist/assets/index-CkWzFNzm.js +208 -0
- package/dist/assets/{index-N-GE7HTU.js → index-D_XGv9QZ.js} +1 -1
- package/dist/assets/{index-DWOBdRjn.js → index-DkmiPfkD.js} +1 -1
- package/dist/assets/{index-CGx5MZO7.js → index-DmNlLMQ4.js} +1 -1
- package/dist/assets/{index-I0dlv-r3.js → index-DmX_vI7D.js} +1 -1
- package/dist/assets/{index-9HdhmM_Y.js → index-DogEEevD.js} +1 -1
- package/dist/assets/{index-aEsF5o-7.js → index-DsDl5qZV.js} +1 -1
- package/dist/assets/{index-gUUzXNuP.js → index-gAy5mDg-.js} +1 -1
- package/dist/assets/{index-CIuq3uTk.js → index-i5qJLB2h.js} +1 -1
- package/dist/assets/javascript.worker-ClsyHOLi.js +552 -0
- package/dist/e2e/editor.spec.d.ts +1 -0
- package/dist/e2e/editor.spec.js +309 -0
- package/dist/editor.d.ts +9 -3
- package/dist/editor.js +83 -15
- package/dist/index.d.ts +3 -0
- package/dist/index.html +2 -3
- package/dist/index.js +3 -0
- package/dist/lsps/typescript.d.ts +3 -1
- package/dist/lsps/typescript.js +8 -17
- package/dist/panels/footer.d.ts +16 -0
- package/dist/panels/footer.js +258 -0
- package/dist/panels/toolbar.d.ts +15 -2
- package/dist/panels/toolbar.js +528 -115
- package/dist/panels/toolbar.test.js +20 -14
- package/dist/rpc/transport.d.ts +2 -11
- package/dist/rpc/transport.js +19 -35
- package/dist/themes/index.js +181 -14
- package/dist/themes/vscode.js +3 -2
- package/dist/utils/fs.d.ts +15 -3
- package/dist/utils/fs.js +85 -6
- package/dist/utils/lsp.d.ts +26 -15
- package/dist/utils/lsp.js +79 -44
- package/dist/utils/search.d.ts +2 -0
- package/dist/utils/search.js +13 -4
- package/dist/utils/typescript-defaults.d.ts +57 -0
- package/dist/utils/typescript-defaults.js +208 -0
- package/dist/utils/typescript-defaults.test.d.ts +1 -0
- package/dist/utils/typescript-defaults.test.js +197 -0
- package/dist/workers/fs.worker.js +14 -18
- package/dist/workers/javascript.worker.js +11 -9
- package/package.json +4 -3
- package/dist/assets/fs.worker-BwEqZcql.ts +0 -109
- package/dist/assets/index-C3BnE2cG.js +0 -222
- package/dist/assets/javascript.worker-C1zGArKk.js +0 -527
- package/dist/snapshot.bin +0 -0
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
// @vitest-environment jsdom
|
|
1
2
|
import { describe, it, expect, beforeEach, vi } from 'vitest';
|
|
2
3
|
import { EditorState } from '@codemirror/state';
|
|
3
4
|
import { EditorView } from '@codemirror/view';
|
|
@@ -13,19 +14,25 @@ vi.mock('../lsps', () => ({
|
|
|
13
14
|
'go': 'go'
|
|
14
15
|
}
|
|
15
16
|
}));
|
|
16
|
-
vi.mock('../editor', () =>
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
17
|
+
vi.mock('../editor', async () => {
|
|
18
|
+
const { Facet, StateField, StateEffect } = await import('@codemirror/state');
|
|
19
|
+
return {
|
|
20
|
+
CodeblockFacet: Facet.define({
|
|
21
|
+
combine: (values) => values[0],
|
|
22
|
+
}),
|
|
23
|
+
currentFileField: StateField.define({
|
|
24
|
+
create() {
|
|
25
|
+
return { path: null, content: '', language: null, loading: false };
|
|
26
|
+
},
|
|
27
|
+
update(value) {
|
|
28
|
+
return value;
|
|
29
|
+
},
|
|
30
|
+
}),
|
|
31
|
+
openFileEffect: StateEffect.define(),
|
|
32
|
+
};
|
|
33
|
+
});
|
|
27
34
|
describe('Toolbar Panel', () => {
|
|
28
|
-
|
|
35
|
+
const ctx = { view: null };
|
|
29
36
|
let mockFs;
|
|
30
37
|
beforeEach(() => {
|
|
31
38
|
mockFs = {
|
|
@@ -49,11 +56,10 @@ describe('Toolbar Panel', () => {
|
|
|
49
56
|
currentFileField
|
|
50
57
|
]
|
|
51
58
|
});
|
|
52
|
-
view = new EditorView({
|
|
59
|
+
ctx.view = new EditorView({
|
|
53
60
|
state,
|
|
54
61
|
parent: document.createElement('div')
|
|
55
62
|
});
|
|
56
|
-
console.log(view);
|
|
57
63
|
});
|
|
58
64
|
describe('Command Results Generation', () => {
|
|
59
65
|
it('should generate create file command for any query', () => {
|
package/dist/rpc/transport.d.ts
CHANGED
|
@@ -1,11 +1,2 @@
|
|
|
1
|
-
import { Transport } from "@
|
|
2
|
-
|
|
3
|
-
export default class MessagePortTransport extends Transport {
|
|
4
|
-
port: MessagePort;
|
|
5
|
-
postMessageID: string;
|
|
6
|
-
constructor(port: MessagePort);
|
|
7
|
-
private messageHandler;
|
|
8
|
-
connect(): Promise<void>;
|
|
9
|
-
sendData(data: JSONRPCRequestData): Promise<any>;
|
|
10
|
-
close(): void;
|
|
11
|
-
}
|
|
1
|
+
import type { Transport } from "@codemirror/lsp-client";
|
|
2
|
+
export declare function messagePortTransport(port: MessagePort): Transport;
|
package/dist/rpc/transport.js
CHANGED
|
@@ -1,38 +1,22 @@
|
|
|
1
|
-
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
1
|
+
/// Creates a Transport adapter that bridges a MessagePort (which
|
|
2
|
+
/// sends/receives JSON objects) to lsp-client's Transport interface
|
|
3
|
+
/// (which sends/receives JSON strings).
|
|
4
|
+
export function messagePortTransport(port) {
|
|
5
|
+
let handlers = [];
|
|
6
|
+
port.addEventListener("message", (ev) => {
|
|
7
|
+
let msg = typeof ev.data === "string" ? ev.data : JSON.stringify(ev.data);
|
|
8
|
+
for (let handler of handlers)
|
|
9
|
+
handler(msg);
|
|
10
|
+
});
|
|
11
|
+
return {
|
|
12
|
+
send(message) {
|
|
13
|
+
port.postMessage(JSON.parse(message));
|
|
14
|
+
},
|
|
15
|
+
subscribe(handler) {
|
|
16
|
+
handlers.push(handler);
|
|
17
|
+
},
|
|
18
|
+
unsubscribe(handler) {
|
|
19
|
+
handlers = handlers.filter(h => h !== handler);
|
|
19
20
|
}
|
|
20
21
|
};
|
|
21
|
-
connect() {
|
|
22
|
-
return new Promise(async (resolve) => {
|
|
23
|
-
this.port.addEventListener("message", this.messageHandler);
|
|
24
|
-
resolve();
|
|
25
|
-
});
|
|
26
|
-
}
|
|
27
|
-
async sendData(data) {
|
|
28
|
-
console.debug("LSP ->>", data);
|
|
29
|
-
const prom = this.transportRequestManager.addRequest(data, null);
|
|
30
|
-
const notifications = getNotifications(data);
|
|
31
|
-
if (this.port) {
|
|
32
|
-
this.port.postMessage(data.request);
|
|
33
|
-
this.transportRequestManager.settlePendingRequest(notifications);
|
|
34
|
-
}
|
|
35
|
-
return prom;
|
|
36
|
-
}
|
|
37
|
-
close() { }
|
|
38
22
|
}
|
package/dist/themes/index.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
import { EditorView } from '@codemirror/view';
|
|
2
|
+
// Font size helpers — all relative to --cm-font-size so changing the
|
|
3
|
+
// base font size in settings automatically scales the entire UI.
|
|
4
|
+
const FS = 'var(--cm-font-size, 16px)';
|
|
5
|
+
const FS_75 = `calc(${FS} * 0.75)`; // 12px at base 16
|
|
6
|
+
const FS_85 = `calc(${FS} * 0.85)`; // ~14px at base 16
|
|
7
|
+
const FS_875 = `calc(${FS} * 0.875)`; // 14px at base 16
|
|
2
8
|
export const codeblockTheme = EditorView.theme({
|
|
3
9
|
"&:not(.cm-focused)": {
|
|
4
10
|
'& .cm-activeLine, & .cm-activeLineGutter': {
|
|
@@ -12,7 +18,7 @@ export const codeblockTheme = EditorView.theme({
|
|
|
12
18
|
border: 'none',
|
|
13
19
|
background: 'transparent',
|
|
14
20
|
outline: 'none',
|
|
15
|
-
fontSize:
|
|
21
|
+
fontSize: FS,
|
|
16
22
|
color: 'var(--cm-toolbar-color)',
|
|
17
23
|
padding: '0 2px 0 6px',
|
|
18
24
|
width: '100%',
|
|
@@ -43,10 +49,9 @@ export const codeblockTheme = EditorView.theme({
|
|
|
43
49
|
'& > .cm-search-result-icon-container': {
|
|
44
50
|
width: 'var(--cm-gutter-width)',
|
|
45
51
|
'& > .cm-search-result-icon': {
|
|
46
|
-
fontSize:
|
|
47
|
-
textAlign: '
|
|
52
|
+
fontSize: FS,
|
|
53
|
+
textAlign: 'center',
|
|
48
54
|
boxSizing: 'border-box',
|
|
49
|
-
padding: '0 3px 0 5px',
|
|
50
55
|
width: 'var(--cm-gutter-lineno-width)',
|
|
51
56
|
}
|
|
52
57
|
},
|
|
@@ -69,14 +74,23 @@ export const codeblockTheme = EditorView.theme({
|
|
|
69
74
|
},
|
|
70
75
|
'.cm-toolbar-state-icon-container': {
|
|
71
76
|
width: 'var(--cm-gutter-width)',
|
|
77
|
+
display: 'flex',
|
|
72
78
|
},
|
|
79
|
+
// Nerd Font icon glyphs have visual widths (700-920 units) that far exceed
|
|
80
|
+
// their monospace advance width (500 units), overflowing to the right.
|
|
81
|
+
// text-align operates on the advance width, not the visual bounds, so
|
|
82
|
+
// 'right' misaligns the icon. 'center' partially compensates for the
|
|
83
|
+
// rightward overflow and visually aligns with gutter line numbers.
|
|
73
84
|
'.cm-toolbar-state-icon': {
|
|
74
|
-
fontSize:
|
|
75
|
-
textAlign: 'right',
|
|
76
|
-
boxSizing: 'border-box',
|
|
77
|
-
padding: '0 3px 0 5px',
|
|
85
|
+
fontSize: FS,
|
|
78
86
|
color: 'var(--cm-foreground)',
|
|
79
|
-
|
|
87
|
+
fontFamily: 'var(--cm-icon-font-family)',
|
|
88
|
+
textAlign: 'center',
|
|
89
|
+
boxSizing: 'border-box',
|
|
90
|
+
width: 'var(--cm-gutter-lineno-width)',
|
|
91
|
+
},
|
|
92
|
+
'&': {
|
|
93
|
+
fontSize: FS,
|
|
80
94
|
},
|
|
81
95
|
'.cm-content': {
|
|
82
96
|
padding: 0,
|
|
@@ -86,7 +100,7 @@ export const codeblockTheme = EditorView.theme({
|
|
|
86
100
|
flexDirection: 'column',
|
|
87
101
|
fontFamily: 'var(--cm-font-family)',
|
|
88
102
|
boxShadow: '-12px 12px 1px rgba(0,0,0,0.3)',
|
|
89
|
-
fontSize:
|
|
103
|
+
fontSize: FS,
|
|
90
104
|
maxWidth: 'min(calc(100% - 2rem), 62ch)',
|
|
91
105
|
border: '2px solid var(--cm-tooltip-border)',
|
|
92
106
|
overflow: 'auto',
|
|
@@ -126,7 +140,7 @@ export const codeblockTheme = EditorView.theme({
|
|
|
126
140
|
'.documentation > *': {
|
|
127
141
|
margin: 0,
|
|
128
142
|
padding: '0.25rem 6px',
|
|
129
|
-
fontSize:
|
|
143
|
+
fontSize: FS,
|
|
130
144
|
},
|
|
131
145
|
'.documentation > p > code': {
|
|
132
146
|
backgroundColor: 'var(--cm-comment-bg)',
|
|
@@ -154,16 +168,169 @@ export const codeblockTheme = EditorView.theme({
|
|
|
154
168
|
padding: 0,
|
|
155
169
|
background: 'var(--cm-toolbar-background)',
|
|
156
170
|
fontFamily: 'var(--cm-font-family)',
|
|
157
|
-
fontSize:
|
|
171
|
+
fontSize: FS,
|
|
158
172
|
listStyleType: 'none',
|
|
159
173
|
width: '100%',
|
|
160
174
|
maxHeight: '25vh',
|
|
161
175
|
overflowY: 'auto',
|
|
176
|
+
zIndex: 200,
|
|
162
177
|
},
|
|
163
178
|
'.cm-gutters': {
|
|
164
179
|
borderRight: 'none',
|
|
165
180
|
},
|
|
166
181
|
'.cm-panels-top': {
|
|
167
|
-
borderBottom: 'none'
|
|
168
|
-
|
|
182
|
+
borderBottom: 'none',
|
|
183
|
+
zIndex: 301,
|
|
184
|
+
},
|
|
185
|
+
// CSS border spinner for file loading indicator
|
|
186
|
+
'.cm-loading': {
|
|
187
|
+
display: 'inline-block',
|
|
188
|
+
width: FS,
|
|
189
|
+
height: FS,
|
|
190
|
+
border: '2px solid currentColor',
|
|
191
|
+
borderTopColor: 'transparent',
|
|
192
|
+
borderRadius: '50%',
|
|
193
|
+
boxSizing: 'border-box',
|
|
194
|
+
animation: 'cm-spin 0.8s linear infinite',
|
|
195
|
+
marginLeft: '4px'
|
|
196
|
+
},
|
|
197
|
+
'@keyframes cm-spin': {
|
|
198
|
+
'0%': { transform: 'rotate(0deg)' },
|
|
199
|
+
'100%': { transform: 'rotate(360deg)' },
|
|
200
|
+
},
|
|
201
|
+
// Settings cog + LSP log button in toolbar (far right)
|
|
202
|
+
'.cm-toolbar-settings-cog, .cm-toolbar-lsp-log': {
|
|
203
|
+
border: 'none',
|
|
204
|
+
background: 'transparent',
|
|
205
|
+
color: 'var(--cm-toolbar-color)',
|
|
206
|
+
cursor: 'pointer',
|
|
207
|
+
padding: '0 6px',
|
|
208
|
+
fontSize: FS_875,
|
|
209
|
+
lineHeight: 'inherit',
|
|
210
|
+
flexShrink: '0',
|
|
211
|
+
transition: 'transform 0.25s ease',
|
|
212
|
+
},
|
|
213
|
+
'.cm-toolbar-settings-cog.cm-cog-active': {
|
|
214
|
+
transform: 'rotate(90deg)',
|
|
215
|
+
},
|
|
216
|
+
// Settings / log overlay — anchored at top, grows downward
|
|
217
|
+
'.cm-settings-overlay': {
|
|
218
|
+
position: 'absolute',
|
|
219
|
+
top: 0,
|
|
220
|
+
left: 0,
|
|
221
|
+
right: 0,
|
|
222
|
+
overflowY: 'auto',
|
|
223
|
+
background: 'var(--cm-background)',
|
|
224
|
+
color: 'var(--cm-toolbar-color)',
|
|
225
|
+
zIndex: 1000,
|
|
226
|
+
fontFamily: 'var(--cm-font-family)',
|
|
227
|
+
fontSize: FS,
|
|
228
|
+
},
|
|
229
|
+
'.cm-settings-section': {
|
|
230
|
+
padding: '8px 6px',
|
|
231
|
+
},
|
|
232
|
+
'.cm-settings-section-title': {
|
|
233
|
+
fontWeight: 'bold',
|
|
234
|
+
marginBottom: '6px',
|
|
235
|
+
fontSize: FS_85,
|
|
236
|
+
opacity: '0.7',
|
|
237
|
+
},
|
|
238
|
+
'.cm-settings-row': {
|
|
239
|
+
display: 'flex',
|
|
240
|
+
alignItems: 'center',
|
|
241
|
+
marginBottom: '6px',
|
|
242
|
+
gap: '8px',
|
|
243
|
+
},
|
|
244
|
+
'.cm-settings-row > label': {
|
|
245
|
+
flex: '0 0 auto',
|
|
246
|
+
whiteSpace: 'nowrap',
|
|
247
|
+
},
|
|
248
|
+
'.cm-settings-control': {
|
|
249
|
+
display: 'flex',
|
|
250
|
+
alignItems: 'center',
|
|
251
|
+
gap: '4px',
|
|
252
|
+
},
|
|
253
|
+
// Fixed pixel width so font-size changes don't relayout the slider
|
|
254
|
+
'.cm-settings-font-size-range': {
|
|
255
|
+
width: '120px',
|
|
256
|
+
flexShrink: '0',
|
|
257
|
+
},
|
|
258
|
+
'.cm-settings-font-size-input': {
|
|
259
|
+
background: 'var(--cm-background)',
|
|
260
|
+
color: 'inherit',
|
|
261
|
+
border: '1px solid var(--cm-tooltip-border)',
|
|
262
|
+
borderRadius: '2px',
|
|
263
|
+
padding: '2px 4px',
|
|
264
|
+
fontSize: 'inherit',
|
|
265
|
+
fontFamily: 'var(--cm-font-family)',
|
|
266
|
+
width: '3em',
|
|
267
|
+
textAlign: 'right',
|
|
268
|
+
},
|
|
269
|
+
'.cm-settings-select': {
|
|
270
|
+
background: 'var(--cm-background)',
|
|
271
|
+
color: 'inherit',
|
|
272
|
+
border: '1px solid var(--cm-tooltip-border)',
|
|
273
|
+
borderRadius: '2px',
|
|
274
|
+
padding: '2px 4px',
|
|
275
|
+
fontSize: 'inherit',
|
|
276
|
+
fontFamily: 'var(--cm-font-family)',
|
|
277
|
+
},
|
|
278
|
+
'.cm-settings-radio-group': {
|
|
279
|
+
display: 'flex',
|
|
280
|
+
gap: '4px',
|
|
281
|
+
alignItems: 'center',
|
|
282
|
+
},
|
|
283
|
+
'.cm-settings-radio-group label': {
|
|
284
|
+
marginRight: '6px',
|
|
285
|
+
},
|
|
286
|
+
'.cm-settings-input': {
|
|
287
|
+
background: 'var(--cm-background)',
|
|
288
|
+
color: 'inherit',
|
|
289
|
+
border: '1px solid var(--cm-tooltip-border)',
|
|
290
|
+
borderRadius: '2px',
|
|
291
|
+
padding: '2px 6px',
|
|
292
|
+
fontSize: 'inherit',
|
|
293
|
+
fontFamily: 'var(--cm-font-family)',
|
|
294
|
+
flex: 1,
|
|
295
|
+
minWidth: 0,
|
|
296
|
+
},
|
|
297
|
+
'.cm-settings-button': {
|
|
298
|
+
background: 'var(--cm-background)',
|
|
299
|
+
color: 'inherit',
|
|
300
|
+
border: '1px solid var(--cm-tooltip-border)',
|
|
301
|
+
borderRadius: '2px',
|
|
302
|
+
padding: '4px 8px',
|
|
303
|
+
fontSize: 'inherit',
|
|
304
|
+
cursor: 'pointer',
|
|
305
|
+
},
|
|
306
|
+
'.cm-settings-button-disabled': {
|
|
307
|
+
opacity: '0.5',
|
|
308
|
+
cursor: 'not-allowed',
|
|
309
|
+
},
|
|
310
|
+
// LSP log content
|
|
311
|
+
'.cm-lsp-log-content': {
|
|
312
|
+
padding: '8px 12px',
|
|
313
|
+
fontFamily: 'var(--cm-font-family)',
|
|
314
|
+
fontSize: FS_75,
|
|
315
|
+
lineHeight: 1.5,
|
|
316
|
+
whiteSpace: 'pre-wrap',
|
|
317
|
+
wordBreak: 'break-all',
|
|
318
|
+
overflowY: 'auto',
|
|
319
|
+
flex: 1,
|
|
320
|
+
},
|
|
321
|
+
'.cm-lsp-log-entry': {
|
|
322
|
+
padding: '1px 0',
|
|
323
|
+
},
|
|
324
|
+
'.cm-lsp-log-error': {
|
|
325
|
+
color: 'var(--cm-diagnostic-error-bg)',
|
|
326
|
+
},
|
|
327
|
+
'.cm-lsp-log-warn': {
|
|
328
|
+
color: '#e5a100',
|
|
329
|
+
},
|
|
330
|
+
'.cm-lsp-log-info': {
|
|
331
|
+
opacity: '0.8',
|
|
332
|
+
},
|
|
333
|
+
'.cm-lsp-log-log': {
|
|
334
|
+
opacity: '0.6',
|
|
335
|
+
},
|
|
169
336
|
});
|
package/dist/themes/vscode.js
CHANGED
|
@@ -113,7 +113,7 @@ const darkModeStyles = {
|
|
|
113
113
|
"--cm-comment": "#6a9955",
|
|
114
114
|
"--cm-link": "#4078f2",
|
|
115
115
|
"--cm-invalid": "#ff0000",
|
|
116
|
-
"--cm-search-result-color": "var(--cm-
|
|
116
|
+
"--cm-search-result-color": "var(--cm-foreground)",
|
|
117
117
|
"--cm-search-result-color-hover": "#ffffff",
|
|
118
118
|
"--cm-command-result-color": "var(--cm-search-result-color-hover)",
|
|
119
119
|
"--cm-toolbar-background": "var(--cm-toolbar-bg-dark)",
|
|
@@ -129,6 +129,7 @@ export const vscodeStyleMod = new StyleModule({
|
|
|
129
129
|
":root, .cm-editor[data-theme='light'], [data-theme='light'] .cm-editor": {
|
|
130
130
|
/* Shared */
|
|
131
131
|
"--cm-font-family": 'Menlo, Monaco, Consolas, "Andale Mono", "Ubuntu Mono", "Courier New", monospace',
|
|
132
|
+
"--cm-icon-font-family": '"UbuntuMono NF", var(--cm-font-family)',
|
|
132
133
|
/* Defaults to light theme */
|
|
133
134
|
"--cm-background": "#ffffff",
|
|
134
135
|
"--cm-foreground": "#383a42",
|
|
@@ -155,7 +156,7 @@ export const vscodeStyleMod = new StyleModule({
|
|
|
155
156
|
"--cm-link": "#4078f2",
|
|
156
157
|
"--cm-invalid": "#e45649",
|
|
157
158
|
/* Additional UI colors */
|
|
158
|
-
"--cm-search-result-color": "
|
|
159
|
+
"--cm-search-result-color": "var(--cm-foreground)",
|
|
159
160
|
"--cm-search-result-color-hover": "var(--cm-toolbar-color)",
|
|
160
161
|
"--cm-search-result-bg-hover": "#2490e94f",
|
|
161
162
|
"--cm-search-result-color-selected": "#ffffff",
|
package/dist/utils/fs.d.ts
CHANGED
|
@@ -23,7 +23,19 @@ export declare namespace Vfs {
|
|
|
23
23
|
export declare class VolarFs implements FileSystem {
|
|
24
24
|
#private;
|
|
25
25
|
constructor(fs: VfsInterface);
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
26
|
+
/**
|
|
27
|
+
* Synchronously populate the cache from a pre-resolved map of path → content.
|
|
28
|
+
* This bypasses async VFS reads entirely, ensuring TypeScript gets lib files
|
|
29
|
+
* immediately on first program creation.
|
|
30
|
+
*/
|
|
31
|
+
preloadFromMap(files: Record<string, string>): void;
|
|
32
|
+
stat(uri: URI): Promise<any> | {
|
|
33
|
+
type: FileType;
|
|
34
|
+
ctime: number;
|
|
35
|
+
mtime: number;
|
|
36
|
+
size: number;
|
|
37
|
+
};
|
|
38
|
+
readDirectory(uri: URI): [string, FileType][] | Promise<[string, FileType][]>;
|
|
39
|
+
readFile(uri: URI): string | Promise<string>;
|
|
40
|
+
getCacheSize(): number;
|
|
29
41
|
}
|
package/dist/utils/fs.js
CHANGED
|
@@ -58,7 +58,6 @@ export var Vfs;
|
|
|
58
58
|
let cur = "/";
|
|
59
59
|
for (const part of parts) {
|
|
60
60
|
cur = cur === "/" ? `/${part}` : `${cur}/${part}`;
|
|
61
|
-
console.log('creating', { cur, abs });
|
|
62
61
|
const exists = await this.exists(cur);
|
|
63
62
|
if (exists)
|
|
64
63
|
continue;
|
|
@@ -257,8 +256,8 @@ export var Vfs;
|
|
|
257
256
|
* for better performance with large files.
|
|
258
257
|
*/
|
|
259
258
|
Vfs.worker = async (bufferOrUrl) => {
|
|
260
|
-
|
|
261
|
-
const worker = new SharedWorker(url, { type: 'module' });
|
|
259
|
+
// TODO: fix this for non-Vite consumers
|
|
260
|
+
const worker = new SharedWorker(new URL('../workers/fs.worker.js', import.meta.url), { type: 'module' });
|
|
262
261
|
worker.port.start();
|
|
263
262
|
const proxy = Comlink.wrap(worker.port);
|
|
264
263
|
let fs;
|
|
@@ -277,6 +276,7 @@ export var Vfs;
|
|
|
277
276
|
// Buffer provided - use traditional mount method
|
|
278
277
|
({ fs } = await proxy.mount(Comlink.transfer({ buffer: bufferOrUrl, mountPoint: "/" }, [bufferOrUrl])));
|
|
279
278
|
}
|
|
279
|
+
console.debug('Filesystem worker mounted');
|
|
280
280
|
return Comlink.proxy(Vfs.fromMemfs(fs));
|
|
281
281
|
};
|
|
282
282
|
async function* walk(fs, path) {
|
|
@@ -295,16 +295,95 @@ export var Vfs;
|
|
|
295
295
|
})(Vfs || (Vfs = {}));
|
|
296
296
|
export class VolarFs {
|
|
297
297
|
#fs;
|
|
298
|
+
#fileCache = new Map();
|
|
299
|
+
#statCache = new Map();
|
|
300
|
+
#dirCache = new Map();
|
|
298
301
|
constructor(fs) {
|
|
299
302
|
this.#fs = fs;
|
|
300
303
|
}
|
|
301
|
-
|
|
304
|
+
/**
|
|
305
|
+
* Synchronously populate the cache from a pre-resolved map of path → content.
|
|
306
|
+
* This bypasses async VFS reads entirely, ensuring TypeScript gets lib files
|
|
307
|
+
* immediately on first program creation.
|
|
308
|
+
*/
|
|
309
|
+
preloadFromMap(files) {
|
|
310
|
+
const now = Date.now();
|
|
311
|
+
for (const [path, content] of Object.entries(files)) {
|
|
312
|
+
this.#fileCache.set(path, content);
|
|
313
|
+
this.#statCache.set(path, {
|
|
314
|
+
type: FileType.File,
|
|
315
|
+
ctime: now,
|
|
316
|
+
mtime: now,
|
|
317
|
+
size: content.length,
|
|
318
|
+
});
|
|
319
|
+
}
|
|
320
|
+
// Build directory tree from file paths
|
|
321
|
+
const dirChildren = new Map();
|
|
322
|
+
for (const path of Object.keys(files)) {
|
|
323
|
+
let dir = path;
|
|
324
|
+
let child = '';
|
|
325
|
+
while (true) {
|
|
326
|
+
const lastSlash = dir.lastIndexOf('/');
|
|
327
|
+
if (lastSlash < 0)
|
|
328
|
+
break;
|
|
329
|
+
child = dir.substring(lastSlash + 1);
|
|
330
|
+
dir = dir.substring(0, lastSlash) || '/';
|
|
331
|
+
if (!dirChildren.has(dir)) {
|
|
332
|
+
dirChildren.set(dir, new Map());
|
|
333
|
+
}
|
|
334
|
+
const children = dirChildren.get(dir);
|
|
335
|
+
// First encounter of this child — it's the file itself
|
|
336
|
+
if (!children.has(child)) {
|
|
337
|
+
// If we've already seen this as a parent dir, it's a Directory
|
|
338
|
+
children.set(child, dirChildren.has(dir === '/' ? `/${child}` : `${dir}/${child}`) ? FileType.Directory : FileType.File);
|
|
339
|
+
}
|
|
340
|
+
if (dir === '/')
|
|
341
|
+
break;
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
// Update directory type for children that are actually directories
|
|
345
|
+
for (const [dirPath, children] of dirChildren) {
|
|
346
|
+
for (const [name] of children) {
|
|
347
|
+
const fullPath = dirPath === '/' ? `/${name}` : `${dirPath}/${name}`;
|
|
348
|
+
if (dirChildren.has(fullPath)) {
|
|
349
|
+
children.set(name, FileType.Directory);
|
|
350
|
+
}
|
|
351
|
+
}
|
|
352
|
+
}
|
|
353
|
+
// Cache directory listings and stats
|
|
354
|
+
for (const [dirPath, children] of dirChildren) {
|
|
355
|
+
this.#dirCache.set(dirPath, [...children.entries()]);
|
|
356
|
+
this.#statCache.set(dirPath, {
|
|
357
|
+
type: FileType.Directory,
|
|
358
|
+
ctime: now,
|
|
359
|
+
mtime: now,
|
|
360
|
+
size: 0,
|
|
361
|
+
});
|
|
362
|
+
}
|
|
363
|
+
}
|
|
364
|
+
stat(uri) {
|
|
365
|
+
const cached = this.#statCache.get(uri.path);
|
|
366
|
+
if (cached)
|
|
367
|
+
return cached;
|
|
302
368
|
return this.#fs.stat(uri.path);
|
|
303
369
|
}
|
|
304
|
-
|
|
370
|
+
readDirectory(uri) {
|
|
371
|
+
// Only use dirCache for node_modules subtree (stable, preloaded).
|
|
372
|
+
// Root and user directories must go through live VFS to pick up new files.
|
|
373
|
+
if (uri.path.startsWith('/node_modules/')) {
|
|
374
|
+
const cached = this.#dirCache.get(uri.path);
|
|
375
|
+
if (cached)
|
|
376
|
+
return cached;
|
|
377
|
+
}
|
|
305
378
|
return this.#fs.readDir(uri.path);
|
|
306
379
|
}
|
|
307
|
-
|
|
380
|
+
readFile(uri) {
|
|
381
|
+
const cached = this.#fileCache.get(uri.path);
|
|
382
|
+
if (cached !== undefined)
|
|
383
|
+
return cached;
|
|
308
384
|
return this.#fs.readFile(uri.path);
|
|
309
385
|
}
|
|
386
|
+
getCacheSize() {
|
|
387
|
+
return this.#fileCache.size;
|
|
388
|
+
}
|
|
310
389
|
}
|
package/dist/utils/lsp.d.ts
CHANGED
|
@@ -1,26 +1,37 @@
|
|
|
1
1
|
import { VfsInterface } from "../types";
|
|
2
|
-
import { LanguageServerClient } from "@marimo-team/codemirror-languageserver";
|
|
3
2
|
import { Extension } from "@codemirror/state";
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
3
|
+
export declare const FileChangeType: {
|
|
4
|
+
readonly Created: 1;
|
|
5
|
+
readonly Changed: 2;
|
|
6
|
+
readonly Deleted: 3;
|
|
7
|
+
};
|
|
8
|
+
export interface LspLogEntry {
|
|
9
|
+
timestamp: number;
|
|
10
|
+
level: 'error' | 'warn' | 'info' | 'log';
|
|
11
|
+
message: string;
|
|
12
|
+
}
|
|
13
|
+
export declare namespace LspLog {
|
|
14
|
+
function entries(): readonly LspLogEntry[];
|
|
15
|
+
function push(level: LspLogEntry['level'], message: string): void;
|
|
16
|
+
function clear(): void;
|
|
17
|
+
function subscribe(fn: () => void): () => void;
|
|
18
|
+
}
|
|
9
19
|
export type ClientOptions = {
|
|
10
|
-
view: EditorView;
|
|
11
20
|
language: string;
|
|
12
21
|
path: string;
|
|
13
22
|
fs: VfsInterface;
|
|
23
|
+
libFiles?: Record<string, string>;
|
|
14
24
|
};
|
|
15
|
-
export declare const languageServerFactory: Map<string, (args: {
|
|
16
|
-
fs: VfsInterface;
|
|
17
|
-
}) => Promise<{
|
|
18
|
-
server: LanguageServer;
|
|
19
|
-
}>>;
|
|
20
25
|
export declare const lspWorkers: Map<string, SharedWorker>;
|
|
21
26
|
export declare namespace LSP {
|
|
22
|
-
function worker(language: string, fs: VfsInterface): Promise<{
|
|
27
|
+
function worker(language: string, fs: VfsInterface, libFiles?: Record<string, string>): Promise<{
|
|
23
28
|
worker: SharedWorker;
|
|
24
|
-
|
|
25
|
-
|
|
29
|
+
lspPort: MessagePort;
|
|
30
|
+
} | null>;
|
|
31
|
+
function client({ fs, language, path, libFiles }: ClientOptions): Promise<Extension | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Notify all connected LSP clients that a file was created, changed, or deleted.
|
|
34
|
+
* This sends workspace/didChangeWatchedFiles so the server re-evaluates the project.
|
|
35
|
+
*/
|
|
36
|
+
function notifyFileChanged(path: string, type?: number): void;
|
|
26
37
|
}
|