@pstdio/workbench 0.6.0 → 0.7.1

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.
@@ -1,432 +0,0 @@
1
- import { jsx as g, jsxs as $ } from "react/jsx-runtime";
2
- import { c as ue } from "react/compiler-runtime";
3
- import { Image as Ne, Center as ne, Text as fe, Flex as re, Box as ve, Button as ye, Spinner as we } from "@chakra-ui/react";
4
- import { useState as de, useRef as O, useEffect as te, useLayoutEffect as _e } from "react";
5
- import { g as xe, r as Ue, s as Le } from "./file-section-navigation-CfYqVObc.js";
6
- import { CodeEditor as je } from "@pstdio/ui/diff";
7
- import { MarkdownEditor as Fe } from "@pstdio/ui/rich-text";
8
- const Te = /* @__PURE__ */ new Set(["png", "jpg", "jpeg", "gif", "webp", "svg", "avif", "bmp", "ico"]), Se = {
9
- ts: "typescript",
10
- tsx: "typescript",
11
- js: "javascript",
12
- jsx: "javascript",
13
- mjs: "javascript",
14
- cjs: "javascript",
15
- json: "json",
16
- jsonc: "json",
17
- py: "python",
18
- rb: "ruby",
19
- rs: "rust",
20
- go: "go",
21
- java: "java",
22
- kt: "kotlin",
23
- c: "c",
24
- h: "c",
25
- cpp: "cpp",
26
- cc: "cpp",
27
- hpp: "cpp",
28
- cs: "csharp",
29
- php: "php",
30
- swift: "swift",
31
- sh: "shell",
32
- bash: "shell",
33
- zsh: "shell",
34
- sql: "sql",
35
- css: "css",
36
- scss: "scss",
37
- less: "less",
38
- html: "html",
39
- xml: "xml",
40
- yml: "yaml",
41
- yaml: "yaml",
42
- toml: "ini",
43
- ini: "ini",
44
- dockerfile: "dockerfile",
45
- graphql: "graphql",
46
- gql: "graphql"
47
- }, me = (t) => {
48
- if (!t) return "";
49
- const e = t.lastIndexOf(".");
50
- return e < 0 || e === t.length - 1 ? "" : t.slice(e + 1).toLowerCase();
51
- }, ke = (t, e) => e?.startsWith("image/") ? !0 : Te.has(me(t)), He = (t, e) => ke(t, e) ? "image" : me(t) in Se ? "code" : "markdown", Be = (t) => Se[me(t)] ?? "plaintext", Oe = (t) => {
52
- const e = ue(33), {
53
- content: r,
54
- editorKey: o,
55
- errorNotice: i,
56
- isEditable: n,
57
- onActiveSectionChange: f,
58
- onChange: E,
59
- rendererRef: h,
60
- sectionNavigation: x,
61
- title: U
62
- } = t, c = He(r.fileName, r.mimeType);
63
- if (c === "image") {
64
- if (!r.dataUrl) {
65
- let y;
66
- return e[0] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (y = /* @__PURE__ */ g(ne, { h: "full", minH: "0", bg: "bg", p: "md", children: /* @__PURE__ */ g(fe, { color: "fg.muted", children: "This image preview is unavailable." }) }), e[0] = y) : y = e[0], y;
67
- }
68
- const m = r.fileName ?? U;
69
- let p;
70
- e[1] !== r.dataUrl || e[2] !== m ? (p = /* @__PURE__ */ g(Ne, { src: r.dataUrl, alt: m, maxW: "100%", maxH: "100%", objectFit: "contain" }), e[1] = r.dataUrl, e[2] = m, e[3] = p) : p = e[3];
71
- let a;
72
- e[4] !== h || e[5] !== p ? (a = /* @__PURE__ */ g(ne, { ref: h, flex: "1", minH: "0", p: "md", overflow: "auto", children: p }), e[4] = h, e[5] = p, e[6] = a) : a = e[6];
73
- let I;
74
- return e[7] !== i || e[8] !== a ? (I = /* @__PURE__ */ $(re, { direction: "column", h: "full", minH: "0", bg: "bg", children: [
75
- i,
76
- a
77
- ] }), e[7] = i, e[8] = a, e[9] = I) : I = e[9], I;
78
- }
79
- if (c === "code") {
80
- let m;
81
- e[10] !== r.fileName ? (m = Be(r.fileName), e[10] = r.fileName, e[11] = m) : m = e[11];
82
- const p = r.content ?? "", a = n ? E : void 0;
83
- let I;
84
- e[12] !== o || e[13] !== n || e[14] !== m || e[15] !== p || e[16] !== a ? (I = /* @__PURE__ */ g(ve, { flex: "1", minH: "0", children: /* @__PURE__ */ g(je, { language: m, defaultCode: p, isEditable: n, showLineNumbers: !0, onChange: a }, o) }), e[12] = o, e[13] = n, e[14] = m, e[15] = p, e[16] = a, e[17] = I) : I = e[17];
85
- let y;
86
- return e[18] !== i || e[19] !== I ? (y = /* @__PURE__ */ $(re, { direction: "column", h: "full", minH: "0", bg: "bg", children: [
87
- i,
88
- I
89
- ] }), e[18] = i, e[19] = I, e[20] = y) : y = e[20], y;
90
- }
91
- const N = r.content ?? "", L = n ? r.placeholder ?? "Write…" : void 0, v = n ? E : void 0;
92
- let b;
93
- e[21] !== o || e[22] !== n || e[23] !== f || e[24] !== x || e[25] !== N || e[26] !== L || e[27] !== v ? (b = /* @__PURE__ */ g(ve, { flex: "1", minH: "0", overflowY: "auto", children: /* @__PURE__ */ g(Fe, { defaultState: N, isEditable: n, sectionNavigation: x, placeholder: L, onActiveSectionChange: f, onChange: v }, o) }), e[21] = o, e[22] = n, e[23] = f, e[24] = x, e[25] = N, e[26] = L, e[27] = v, e[28] = b) : b = e[28];
94
- let C;
95
- return e[29] !== i || e[30] !== h || e[31] !== b ? (C = /* @__PURE__ */ $(re, { ref: h, direction: "column", h: "full", minH: "0", overflow: "hidden", bg: "bg", children: [
96
- i,
97
- b
98
- ] }), e[29] = i, e[30] = h, e[31] = b, e[32] = C) : C = e[32], C;
99
- }, $e = (t) => {
100
- let e, r, o = null, i = null, n, f, E = !1, h = null, x = 0;
101
- const U = /* @__PURE__ */ new Set(), c = /* @__PURE__ */ new Set(), N = (s) => s instanceof Error ? s.message : "Failed to save file.", L = () => ({
102
- dirty: o !== null || i !== null && i.value !== e,
103
- saving: i !== null,
104
- ...n ? {
105
- saveError: n
106
- } : {}
107
- }), v = () => t.onStateChange?.(L()), b = () => {
108
- h !== null && (clearTimeout(h), h = null);
109
- }, C = () => t.createOperationId?.() ?? `file-save-${Date.now()}-${++x}`, m = () => o !== null || i !== null || h !== null || !!n, p = (s) => {
110
- s.revision && (!f || s.revision.localeCompare(f) > 0) && (f = s.revision), s.revision || (E = !0);
111
- }, a = (s) => {
112
- const d = s.origin?.operationId;
113
- return !d || s.origin?.rendererId !== t.binding.rendererId || s.origin.instanceId !== t.binding.instanceId ? !1 : i?.origin.operationId === d || c.has(d);
114
- }, I = (s) => {
115
- if (o !== null || i) return;
116
- const d = f, w = E;
117
- if (f = void 0, E = !1, d && (!s || d.localeCompare(s) > 0)) {
118
- t.load({
119
- resourceUri: t.binding.resourceUri,
120
- revision: d
121
- });
122
- return;
123
- }
124
- w && t.load({
125
- resourceUri: t.binding.resourceUri
126
- });
127
- }, y = () => {
128
- if (o === null || i || n) return;
129
- const s = o;
130
- o = null;
131
- const d = {
132
- rendererId: t.binding.rendererId,
133
- instanceId: t.binding.instanceId,
134
- operationId: C()
135
- };
136
- i = {
137
- value: s,
138
- origin: d
139
- }, v(), Promise.resolve(t.save(s, d)).then((w) => {
140
- if (i?.origin.operationId === d.operationId) {
141
- if (i = null, c.add(d.operationId), c.size > 20 && c.delete(c.values().next().value), e = s, r = w?.revision ?? r, o === e && (o = null, b()), v(), o !== null) {
142
- T();
143
- return;
144
- }
145
- I(w?.revision);
146
- }
147
- }).catch((w) => {
148
- i?.origin.operationId === d.operationId && (i = null, o === null && (o = s), n = N(w), v());
149
- });
150
- }, T = () => {
151
- b(), h = setTimeout(() => {
152
- h = null, y();
153
- }, t.debounceMs);
154
- };
155
- return {
156
- getBaseline() {
157
- return e;
158
- },
159
- getState: L,
160
- setBaseline(s, d) {
161
- e = s, r = d, v();
162
- },
163
- acceptLoaded(s, d) {
164
- return m() ? (p(d ? {
165
- revision: d
166
- } : {}), !1) : (e = s, r = d, v(), !0);
167
- },
168
- handleChange(s) {
169
- if (!(n && s === o)) {
170
- if (n = void 0, s === e && !i) {
171
- o = null, b(), v();
172
- return;
173
- }
174
- if (i?.value === s) {
175
- o = null, b(), v();
176
- return;
177
- }
178
- o = s, T(), v();
179
- }
180
- },
181
- handleRefreshEvent(s = {}) {
182
- if (!(s.resourceUri && s.resourceUri !== t.binding.resourceUri) && !a(s) && !(s.revision && U.has(s.revision))) {
183
- if (s.revision && U.add(s.revision), m()) {
184
- p(s);
185
- return;
186
- }
187
- s.revision && r && s.revision.localeCompare(r) <= 0 || t.load(s);
188
- }
189
- },
190
- retry() {
191
- !n || o === null || i || (n = void 0, v(), y());
192
- },
193
- retryLoad() {
194
- t.load({
195
- resourceUri: t.binding.resourceUri
196
- });
197
- },
198
- flush() {
199
- b(), y();
200
- }
201
- };
202
- }, Ae = (t, e, r, o) => !t || t.loadKey !== r ? 1 : (o ?? t.content) === e.content && t.dataUrl === e.dataUrl ? t.editorRevision : t.editorRevision + 1, Ke = 30, B = /* @__PURE__ */ new Map(), be = (t) => B.get(t), pe = (t, e) => {
203
- if (B.delete(t), B.set(t, e), B.size <= Ke) return;
204
- const r = B.keys().next().value;
205
- r !== void 0 && B.delete(r);
206
- }, Ie = (t) => {
207
- const e = ue(7), {
208
- message: r,
209
- onRetry: o
210
- } = t;
211
- let i;
212
- e[0] !== r ? (i = /* @__PURE__ */ g(fe, { color: "fg.muted", textStyle: "label/S/regular", children: r }), e[0] = r, e[1] = i) : i = e[1];
213
- let n;
214
- e[2] !== o ? (n = /* @__PURE__ */ g(ye, { size: "2xs", variant: "subtle", onClick: o, children: "Retry" }), e[2] = o, e[3] = n) : n = e[3];
215
- let f;
216
- return e[4] !== i || e[5] !== n ? (f = /* @__PURE__ */ $(re, { flex: "none", alignItems: "center", justifyContent: "space-between", gap: "sm", borderBottomWidth: "1px", borderColor: "border.muted", bg: "bg.muted", px: "sm", py: "xs", children: [
217
- i,
218
- n
219
- ] }), e[4] = i, e[5] = n, e[6] = f) : f = e[6], f;
220
- }, Me = (t) => {
221
- if (!t) return "";
222
- const e = Object.entries(t).sort(([r], [o]) => r.localeCompare(o));
223
- return JSON.stringify(e);
224
- }, qe = (t) => {
225
- const {
226
- fileRendererId: e,
227
- resourceUri: r,
228
- resourceMetadata: o
229
- } = t;
230
- return `${e}:${r ?? ""}:${Me(o)}`;
231
- }, ze = (t, e) => t?.loadKey === e, De = 600, Ve = (t) => t instanceof Error ? t.message : "Failed to load file.", We = (t) => {
232
- const {
233
- workbench: e,
234
- navigation: r,
235
- sectionId: o
236
- } = t;
237
- if (!r || !e.renderers.getTreeRenderer(r.treeId)) return;
238
- if (o && r.anchors.some((n) => n.id === o)) {
239
- e.renderers.setSelectedNode(r.treeId, o);
240
- return;
241
- }
242
- const i = e.renderers.getTreeState(r.treeId).selectedNodeId;
243
- i && r.anchors.some((n) => n.id === i) && e.renderers.setSelectedNode(r.treeId, void 0);
244
- }, Pe = (t, e) => {
245
- if (!e) return;
246
- const r = t.renderers.getTreeRenderer(e.treeId) ? t.renderers.getTreeState(e.treeId).selectedNodeId : void 0;
247
- return {
248
- anchors: e.anchors,
249
- targetId: Ue(e, r)
250
- };
251
- }, nt = (t) => {
252
- const e = ue(64), {
253
- workbench: r,
254
- contribution: o
255
- } = t, i = t.placement?.resource;
256
- let n, f;
257
- e[0] !== i || e[1] !== r ? (n = xe(i), f = Pe(r, n), e[0] = i, e[1] = r, e[2] = n, e[3] = f) : (n = e[2], f = e[3]);
258
- const E = f, h = i?.uri, x = i?.metadata;
259
- let U;
260
- e[4] !== o.id || e[5] !== h || e[6] !== x ? (U = qe({
261
- fileRendererId: o.id,
262
- resourceUri: h,
263
- resourceMetadata: x
264
- }), e[4] = o.id, e[5] = h, e[6] = x, e[7] = U) : U = e[7];
265
- const c = U, [N, L] = de(null), [v, b] = de(null);
266
- let C;
267
- e[8] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (C = {
268
- dirty: !1,
269
- saving: !1
270
- }, e[8] = C) : C = e[8];
271
- const [m, p] = de(C), a = O(null), I = O(null), y = O(null);
272
- let T;
273
- e[9] !== i?.uri || e[10] !== n || e[11] !== r.renderers ? (T = () => {
274
- const l = y.current, u = l && r.renderers.getTreeRenderer(l.treeId) ? r.renderers.getTreeState(l.treeId).selectedNodeId : void 0;
275
- Le({
276
- previous: l,
277
- current: n,
278
- currentResourceUri: i?.uri,
279
- selectedNodeId: u
280
- }) && l && r.renderers.setSelectedNode(l.treeId, void 0), y.current = n ? {
281
- resourceUri: i?.uri,
282
- treeId: n.treeId,
283
- anchorIds: n.anchors.map(Ye)
284
- } : null;
285
- }, e[9] = i?.uri, e[10] = n, e[11] = r.renderers, e[12] = T) : T = e[12];
286
- const s = i?.uri;
287
- let d;
288
- e[13] !== n || e[14] !== s || e[15] !== r ? (d = [s, n, r], e[13] = n, e[14] = s, e[15] = r, e[16] = d) : d = e[16], te(T, d);
289
- const w = O(o), A = O(i);
290
- let K;
291
- e[17] !== o || e[18] !== i ? (K = () => {
292
- w.current = o, A.current = i;
293
- }, e[17] = o, e[18] = i, e[19] = K) : K = e[19], te(K);
294
- const j = o.id, k = !!o.save;
295
- let M;
296
- e[20] !== j || e[21] !== k || e[22] !== c || e[23] !== t.placement?.instanceId || e[24] !== r.renderers ? (M = () => {
297
- let l = !1;
298
- b(null);
299
- const u = be(c);
300
- L(u ? {
301
- ...u,
302
- editorRevision: 1,
303
- loadKey: c
304
- } : null);
305
- const _ = () => {
306
- Promise.resolve(w.current.load(A.current)).then((S) => {
307
- if (l || a.current && !a.current.acceptLoaded(S.content, S.revision))
308
- return;
309
- b(null), pe(c, S);
310
- const H = a.current?.getBaseline();
311
- L((ae) => ({
312
- ...S,
313
- editorRevision: Ae(ae, S, c, H),
314
- loadKey: c
315
- }));
316
- }).catch((S) => {
317
- l || b({
318
- loadKey: c,
319
- message: Ve(S)
320
- });
321
- });
322
- };
323
- a.current = k ? $e({
324
- binding: {
325
- rendererId: j,
326
- instanceId: t.placement?.instanceId ?? j,
327
- resourceUri: A.current?.uri
328
- },
329
- debounceMs: De,
330
- load: _,
331
- onStateChange: (S) => {
332
- l || p(S);
333
- },
334
- save: (S, H) => Promise.resolve(w.current.save?.(A.current, S, H)).then((ae) => {
335
- const ge = be(c);
336
- return ge && pe(c, {
337
- ...ge,
338
- content: S
339
- }), ae ?? void 0;
340
- })
341
- }) : null, u && a.current?.setBaseline(u.content, u.revision), p({
342
- dirty: !1,
343
- saving: !1
344
- }), _();
345
- const Ee = r.renderers.onDidRefreshFileRenderer((S) => {
346
- if (S.fileRendererId !== j)
347
- return;
348
- const H = a.current;
349
- H ? H.handleRefreshEvent(S) : _();
350
- });
351
- return () => {
352
- l = !0, Ee.dispose(), a.current?.flush(), a.current = null;
353
- };
354
- }, e[20] = j, e[21] = k, e[22] = c, e[23] = t.placement?.instanceId, e[24] = r.renderers, e[25] = M) : M = e[25];
355
- const oe = t.placement?.instanceId;
356
- let q;
357
- e[26] !== j || e[27] !== k || e[28] !== c || e[29] !== oe || e[30] !== r ? (q = [j, k, r, c, oe], e[26] = j, e[27] = k, e[28] = c, e[29] = oe, e[30] = r, e[31] = q) : q = e[31], te(M, q);
358
- let z, D;
359
- e[32] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (z = () => {
360
- const l = () => a.current?.flush(), u = () => {
361
- document.visibilityState === "hidden" && l();
362
- };
363
- return window.addEventListener("beforeunload", l), document.addEventListener("visibilitychange", u), () => {
364
- window.removeEventListener("beforeunload", l), document.removeEventListener("visibilitychange", u);
365
- };
366
- }, D = [], e[32] = z, e[33] = D) : (z = e[32], D = e[33]), te(z, D);
367
- let V;
368
- e[34] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (V = (l) => {
369
- a.current?.handleChange(l);
370
- }, e[34] = V) : V = e[34];
371
- const Ce = V;
372
- let W;
373
- e[35] !== c || e[36] !== N ? (W = ze(N, c) ? N : null, e[35] = c, e[36] = N, e[37] = W) : W = e[37];
374
- const R = W, P = R ? `${R.loadKey}:${R.editorRevision}` : "";
375
- let Y, G;
376
- e[38] !== P || e[39] !== n ? (Y = () => {
377
- if (!P || n)
378
- return;
379
- const l = I.current;
380
- l && requestAnimationFrame(() => {
381
- let u = l.parentElement;
382
- for (; u; ) {
383
- const _ = getComputedStyle(u).overflowY;
384
- ["auto", "scroll", "overlay"].includes(_) && u.scrollHeight > u.clientHeight && (u.scrollTop = 0), u = u.parentElement;
385
- }
386
- });
387
- }, G = [P, n], e[38] = P, e[39] = n, e[40] = Y, e[41] = G) : (Y = e[40], G = e[41]), _e(Y, G);
388
- const F = v?.loadKey === c ? v.message : void 0;
389
- let X;
390
- e[42] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (X = () => a.current?.retryLoad(), e[42] = X) : X = e[42];
391
- const he = X;
392
- let J;
393
- e[43] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (J = () => a.current?.retry(), e[43] = J) : J = e[43];
394
- const Re = J;
395
- if (F && !R) {
396
- let l;
397
- e[44] !== F ? (l = /* @__PURE__ */ g(fe, { color: "fg.muted", children: F }), e[44] = F, e[45] = l) : l = e[45];
398
- let u;
399
- e[46] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (u = /* @__PURE__ */ g(ye, { size: "xs", variant: "subtle", onClick: he, children: "Retry" }), e[46] = u) : u = e[46];
400
- let _;
401
- return e[47] !== l ? (_ = /* @__PURE__ */ $(ne, { h: "full", minH: "0", bg: "bg", p: "md", flexDirection: "column", gap: "sm", children: [
402
- l,
403
- u
404
- ] }), e[47] = l, e[48] = _) : _ = e[48], _;
405
- }
406
- if (!R) {
407
- let l;
408
- return e[49] === /* @__PURE__ */ Symbol.for("react.memo_cache_sentinel") ? (l = /* @__PURE__ */ g(ne, { h: "full", minH: "0", bg: "bg", children: /* @__PURE__ */ g(we, { size: "sm" }) }), e[49] = l) : l = e[49], l;
409
- }
410
- const ie = !!o.save && !R.dataUrl, se = `${R.loadKey}:${R.editorRevision}`;
411
- let Q;
412
- e[50] !== m || e[51] !== F ? (Q = F ? /* @__PURE__ */ g(Ie, { message: F, onRetry: he }) : m.saveError ? /* @__PURE__ */ g(Ie, { message: m.saveError, onRetry: Re }) : null, e[50] = m, e[51] = F, e[52] = Q) : Q = e[52];
413
- const le = Q;
414
- let Z;
415
- e[53] !== n || e[54] !== r ? (Z = (l) => {
416
- We({
417
- workbench: r,
418
- navigation: n,
419
- sectionId: l
420
- });
421
- }, e[53] = n, e[54] = r, e[55] = Z) : Z = e[55];
422
- const ce = n ? Z : void 0;
423
- let ee;
424
- return e[56] !== o.title || e[57] !== R || e[58] !== se || e[59] !== E || e[60] !== le || e[61] !== ie || e[62] !== ce ? (ee = /* @__PURE__ */ g(Oe, { content: R, editorKey: se, errorNotice: le, isEditable: ie, onActiveSectionChange: ce, onChange: Ce, rendererRef: I, sectionNavigation: E, title: o.title }), e[56] = o.title, e[57] = R, e[58] = se, e[59] = E, e[60] = le, e[61] = ie, e[62] = ce, e[63] = ee) : ee = e[63], ee;
425
- };
426
- function Ye(t) {
427
- return t.id;
428
- }
429
- export {
430
- nt as WorkbenchFileRendererView
431
- };
432
- //# sourceMappingURL=file-renderer-view-zpunbE4I.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"file-renderer-view-zpunbE4I.js","sources":["../src/react/renderers/file/file-kind.ts","../src/react/renderers/file/file-renderer-content.tsx","../src/react/renderers/file/file-renderer-edit-state.ts","../src/react/renderers/file/file-renderer-error-notice.tsx","../src/react/renderers/file/file-renderer-load-key.ts","../src/react/renderers/file/file-renderer-view.tsx"],"sourcesContent":["// Generic file-type dispatch for the file renderer. Markdown is the default so\n// `.md` / `.txt` / extension-less files open in the prose editor; recognised code\n// extensions open in Monaco; images render read-only. This is deliberately\n// domain-agnostic — it knows about file types, not about tickets.\n\nexport type FileKind = \"markdown\" | \"code\" | \"image\";\n\nconst IMAGE_EXTENSIONS = new Set([\"png\", \"jpg\", \"jpeg\", \"gif\", \"webp\", \"svg\", \"avif\", \"bmp\", \"ico\"]);\n\n// Extension → Monaco language id. Markdown/plain text intentionally absent so\n// they fall through to the prose editor.\nconst CODE_LANGUAGE_BY_EXTENSION: Record<string, string> = {\n ts: \"typescript\",\n tsx: \"typescript\",\n js: \"javascript\",\n jsx: \"javascript\",\n mjs: \"javascript\",\n cjs: \"javascript\",\n json: \"json\",\n jsonc: \"json\",\n py: \"python\",\n rb: \"ruby\",\n rs: \"rust\",\n go: \"go\",\n java: \"java\",\n kt: \"kotlin\",\n c: \"c\",\n h: \"c\",\n cpp: \"cpp\",\n cc: \"cpp\",\n hpp: \"cpp\",\n cs: \"csharp\",\n php: \"php\",\n swift: \"swift\",\n sh: \"shell\",\n bash: \"shell\",\n zsh: \"shell\",\n sql: \"sql\",\n css: \"css\",\n scss: \"scss\",\n less: \"less\",\n html: \"html\",\n xml: \"xml\",\n yml: \"yaml\",\n yaml: \"yaml\",\n toml: \"ini\",\n ini: \"ini\",\n dockerfile: \"dockerfile\",\n graphql: \"graphql\",\n gql: \"graphql\",\n};\n\nconst extensionOf = (fileName: string | undefined) => {\n if (!fileName) return \"\";\n const dot = fileName.lastIndexOf(\".\");\n if (dot < 0 || dot === fileName.length - 1) return \"\";\n return fileName.slice(dot + 1).toLowerCase();\n};\n\nconst isImage = (fileName: string | undefined, mimeType: string | undefined) => {\n if (mimeType?.startsWith(\"image/\")) return true;\n return IMAGE_EXTENSIONS.has(extensionOf(fileName));\n};\n\nexport const pickFileKind = (fileName: string | undefined, mimeType: string | undefined): FileKind => {\n if (isImage(fileName, mimeType)) return \"image\";\n if (extensionOf(fileName) in CODE_LANGUAGE_BY_EXTENSION) return \"code\";\n return \"markdown\";\n};\n\n// Monaco language for a code file; falls back to plaintext for unknown extensions.\nexport const codeLanguageFor = (fileName: string | undefined) =>\n CODE_LANGUAGE_BY_EXTENSION[extensionOf(fileName)] ?? \"plaintext\";\n","import { Box, Center, Flex, Image, Text } from \"@chakra-ui/react\";\nimport { CodeEditor } from \"@pstdio/ui/diff\";\nimport { MarkdownEditor } from \"@pstdio/ui/rich-text\";\nimport type { ReactNode, RefObject } from \"react\";\nimport type { FileRendererContent } from \"../../../core\";\nimport { codeLanguageFor, pickFileKind } from \"./file-kind\";\n\ninterface FileRendererContentViewProps {\n content: FileRendererContent;\n editorKey: string;\n errorNotice: ReactNode;\n isEditable: boolean;\n onActiveSectionChange?: (sectionId: string | null) => void;\n onChange: (value: string) => void;\n rendererRef: RefObject<HTMLDivElement | null>;\n sectionNavigation?: {\n anchors: Array<{ id: string; heading: string; occurrence?: number }>;\n targetId: string;\n };\n title: string;\n}\n\nexport const FileRendererContentView = (props: FileRendererContentViewProps) => {\n const {\n content,\n editorKey,\n errorNotice,\n isEditable,\n onActiveSectionChange,\n onChange,\n rendererRef,\n sectionNavigation,\n title,\n } = props;\n const kind = pickFileKind(content.fileName, content.mimeType);\n\n if (kind === \"image\") {\n if (!content.dataUrl) {\n return (\n <Center h=\"full\" minH=\"0\" bg=\"bg\" p=\"md\">\n <Text color=\"fg.muted\">This image preview is unavailable.</Text>\n </Center>\n );\n }\n return (\n <Flex direction=\"column\" h=\"full\" minH=\"0\" bg=\"bg\">\n {errorNotice}\n <Center ref={rendererRef} flex=\"1\" minH=\"0\" p=\"md\" overflow=\"auto\">\n <Image src={content.dataUrl} alt={content.fileName ?? title} maxW=\"100%\" maxH=\"100%\" objectFit=\"contain\" />\n </Center>\n </Flex>\n );\n }\n\n if (kind === \"code\") {\n return (\n <Flex direction=\"column\" h=\"full\" minH=\"0\" bg=\"bg\">\n {errorNotice}\n <Box flex=\"1\" minH=\"0\">\n <CodeEditor\n key={editorKey}\n language={codeLanguageFor(content.fileName)}\n defaultCode={content.content ?? \"\"}\n isEditable={isEditable}\n showLineNumbers\n onChange={isEditable ? onChange : undefined}\n />\n </Box>\n </Flex>\n );\n }\n\n return (\n <Flex ref={rendererRef} direction=\"column\" h=\"full\" minH=\"0\" overflow=\"hidden\" bg=\"bg\">\n {errorNotice}\n <Box flex=\"1\" minH=\"0\" overflowY=\"auto\">\n <MarkdownEditor\n key={editorKey}\n defaultState={content.content ?? \"\"}\n isEditable={isEditable}\n sectionNavigation={sectionNavigation}\n placeholder={isEditable ? (content.placeholder ?? \"Write…\") : undefined}\n onActiveSectionChange={onActiveSectionChange}\n onChange={isEditable ? onChange : undefined}\n />\n </Box>\n </Flex>\n );\n};\n","// Owns the editable file renderer's save lifecycle: the last loaded or saved\n// value (the baseline), the debounced draft, the one in-flight save, and\n// refresh events that arrive while a draft or save exists.\n//\n// Invariants (from the renderer edit/refresh lifecycle PRD):\n// - a change equal to the baseline never schedules a save\n// - at most one save runs at a time; the baseline advances when it succeeds\n// - a failed save keeps the draft so a later change or flush retries it\n// - refresh events are deferred while a draft or save exists and coalesce\n// into one reload after the last save settles\n\nimport type {\n FileRendererRefreshEnvelope,\n FileRendererRefreshOrigin,\n FileRendererSaveResult,\n} from \"../../../core/registries/renderers/file-renderer-registry\";\n\nexport interface FileEditControllerState {\n dirty: boolean;\n saving: boolean;\n saveError?: string;\n}\n\nexport interface FileEditControllerInput {\n binding: Omit<FileRendererRefreshOrigin, \"operationId\"> & { resourceUri?: string };\n debounceMs: number;\n load: (event?: FileRendererRefreshEnvelope) => void;\n save: (value: string, origin: FileRendererRefreshOrigin) => Promise<FileRendererSaveResult | undefined>;\n createOperationId?: () => string;\n onStateChange?: (state: FileEditControllerState) => void;\n}\n\nexport type FileEditController = ReturnType<typeof createFileEditController>;\n\nexport const createFileEditController = (input: FileEditControllerInput) => {\n let baseline: string | undefined;\n let baselineRevision: string | undefined;\n let draft: string | null = null;\n let activeSave: { value: string; origin: FileRendererRefreshOrigin } | null = null;\n let saveError: string | undefined;\n let deferredRevision: string | undefined;\n let genericRefreshDeferred = false;\n let timer: ReturnType<typeof setTimeout> | null = null;\n let operationSequence = 0;\n const seenRefreshRevisions = new Set<string>();\n const completedOperationIds = new Set<string>();\n\n const describeError = (error: unknown) => (error instanceof Error ? error.message : \"Failed to save file.\");\n const getState = (): FileEditControllerState => ({\n dirty: draft !== null || (activeSave !== null && activeSave.value !== baseline),\n saving: activeSave !== null,\n ...(saveError ? { saveError } : {}),\n });\n const notify = () => input.onStateChange?.(getState());\n\n const clearTimer = () => {\n if (timer === null) return;\n clearTimeout(timer);\n timer = null;\n };\n\n const nextOperationId = () => input.createOperationId?.() ?? `file-save-${Date.now()}-${++operationSequence}`;\n\n const hasPendingLocalState = () => draft !== null || activeSave !== null || timer !== null || Boolean(saveError);\n\n const deferRefresh = (event: FileRendererRefreshEnvelope) => {\n if (event.revision && (!deferredRevision || event.revision.localeCompare(deferredRevision) > 0)) {\n deferredRevision = event.revision;\n }\n if (!event.revision) genericRefreshDeferred = true;\n };\n\n const isSelfRefresh = (event: FileRendererRefreshEnvelope) => {\n const operationId = event.origin?.operationId;\n if (!operationId) return false;\n if (event.origin?.rendererId !== input.binding.rendererId) return false;\n if (event.origin.instanceId !== input.binding.instanceId) return false;\n return activeSave?.origin.operationId === operationId || completedOperationIds.has(operationId);\n };\n\n const takeDeferredRefresh = (savedRevision?: string) => {\n if (draft !== null || activeSave) return;\n const revision = deferredRevision;\n const generic = genericRefreshDeferred;\n deferredRevision = undefined;\n genericRefreshDeferred = false;\n if (revision && (!savedRevision || revision.localeCompare(savedRevision) > 0)) {\n input.load({ resourceUri: input.binding.resourceUri, revision });\n return;\n }\n if (generic) input.load({ resourceUri: input.binding.resourceUri });\n };\n\n const runSave = () => {\n if (draft === null || activeSave || saveError) return;\n const value = draft;\n draft = null;\n const origin = {\n rendererId: input.binding.rendererId,\n instanceId: input.binding.instanceId,\n operationId: nextOperationId(),\n };\n activeSave = { value, origin };\n notify();\n void Promise.resolve(input.save(value, origin))\n .then((result) => {\n if (activeSave?.origin.operationId !== origin.operationId) return;\n activeSave = null;\n completedOperationIds.add(origin.operationId);\n if (completedOperationIds.size > 20) completedOperationIds.delete(completedOperationIds.values().next().value!);\n baseline = value;\n baselineRevision = result?.revision ?? baselineRevision;\n if (draft === baseline) {\n draft = null;\n clearTimer();\n }\n notify();\n if (draft !== null) {\n schedule();\n return;\n }\n takeDeferredRefresh(result?.revision);\n })\n .catch((error) => {\n if (activeSave?.origin.operationId !== origin.operationId) return;\n activeSave = null;\n if (draft === null) draft = value;\n saveError = describeError(error);\n notify();\n });\n };\n\n const schedule = () => {\n clearTimer();\n timer = setTimeout(() => {\n timer = null;\n runSave();\n }, input.debounceMs);\n };\n\n return {\n getBaseline() {\n return baseline;\n },\n getState,\n setBaseline(value: string | undefined, revision?: string) {\n baseline = value;\n baselineRevision = revision;\n notify();\n },\n acceptLoaded(value: string | undefined, revision?: string) {\n if (hasPendingLocalState()) {\n deferRefresh(revision ? { revision } : {});\n return false;\n }\n baseline = value;\n baselineRevision = revision;\n notify();\n return true;\n },\n handleChange(value: string) {\n if (saveError && value === draft) return;\n saveError = undefined;\n if (value === baseline && !activeSave) {\n draft = null;\n clearTimer();\n notify();\n return;\n }\n if (activeSave?.value === value) {\n draft = null;\n clearTimer();\n notify();\n return;\n }\n draft = value;\n schedule();\n notify();\n },\n handleRefreshEvent(event: FileRendererRefreshEnvelope = {}) {\n if (event.resourceUri && event.resourceUri !== input.binding.resourceUri) return;\n if (isSelfRefresh(event)) return;\n if (event.revision && seenRefreshRevisions.has(event.revision)) return;\n if (event.revision) seenRefreshRevisions.add(event.revision);\n if (hasPendingLocalState()) {\n deferRefresh(event);\n return;\n }\n if (event.revision && baselineRevision && event.revision.localeCompare(baselineRevision) <= 0) return;\n input.load(event);\n },\n retry() {\n if (!saveError || draft === null || activeSave) return;\n saveError = undefined;\n notify();\n runSave();\n },\n retryLoad() {\n input.load({ resourceUri: input.binding.resourceUri });\n },\n flush() {\n clearTimer();\n runSave();\n },\n };\n};\n\n// A reload that returns what the editor already shows must not remount it: the\n// revision feeds the editor's React key, and a new key destroys focus and\n// selection. `editorValue` is the current baseline for an editable renderer —\n// after a save, a reload returns the saved value, which matches the baseline\n// even though it differs from the previously loaded state.\nexport const nextLoadedRevision = (\n previous: { content?: string; dataUrl?: string; loadKey: string; editorRevision: number } | null,\n next: { content?: string; dataUrl?: string },\n loadKey: string,\n editorValue?: string,\n) => {\n if (!previous || previous.loadKey !== loadKey) return 1;\n const shownContent = editorValue ?? previous.content;\n if (shownContent === next.content && previous.dataUrl === next.dataUrl) return previous.editorRevision;\n return previous.editorRevision + 1;\n};\n\n// Last loaded document per binding, so reopening a recently viewed file mounts\n// the editor immediately instead of a spinner. The follow-up load reconciles:\n// unchanged content keeps the revision (no remount), changed content remounts.\nconst FILE_CONTENT_CACHE_LIMIT = 30;\nconst fileContentCache = new Map<\n string,\n { content?: string; dataUrl?: string; fileName?: string; mimeType?: string; placeholder?: string; revision?: string }\n>();\n\nexport const readCachedFileContent = (loadKey: string) => fileContentCache.get(loadKey);\n\nexport const storeCachedFileContent = (\n loadKey: string,\n content: NonNullable<ReturnType<typeof readCachedFileContent>>,\n) => {\n fileContentCache.delete(loadKey);\n fileContentCache.set(loadKey, content);\n if (fileContentCache.size <= FILE_CONTENT_CACHE_LIMIT) return;\n const oldest = fileContentCache.keys().next().value;\n if (oldest !== undefined) fileContentCache.delete(oldest);\n};\n","import { Button, Flex, Text } from \"@chakra-ui/react\";\n\nexport const FileRendererErrorNotice = (props: { message: string; onRetry: () => void }) => {\n const { message, onRetry } = props;\n return (\n <Flex\n flex=\"none\"\n alignItems=\"center\"\n justifyContent=\"space-between\"\n gap=\"sm\"\n borderBottomWidth=\"1px\"\n borderColor=\"border.muted\"\n bg=\"bg.muted\"\n px=\"sm\"\n py=\"xs\"\n >\n <Text color=\"fg.muted\" textStyle=\"label/S/regular\">\n {message}\n </Text>\n <Button size=\"2xs\" variant=\"subtle\" onClick={onRetry}>\n Retry\n </Button>\n </Flex>\n );\n};\n","interface FileRendererLoadKeyInput {\n fileRendererId: string;\n resourceUri: string | undefined;\n resourceMetadata?: Record<string, unknown>;\n}\n\n// Metadata selects which document a resource shows (e.g. one ticket resource\n// carrying the file the tree picked), so it belongs to the document's identity.\n// Sorted keys keep the key stable when a caller rebuilds metadata in another order.\nconst serializeResourceMetadata = (metadata: Record<string, unknown> | undefined) => {\n if (!metadata) return \"\";\n const entries = Object.entries(metadata).sort(([a], [b]) => a.localeCompare(b));\n return JSON.stringify(entries);\n};\n\nexport const createFileRendererLoadKey = (input: FileRendererLoadKeyInput) => {\n const { fileRendererId, resourceUri, resourceMetadata } = input;\n return `${fileRendererId}:${resourceUri ?? \"\"}:${serializeResourceMetadata(resourceMetadata)}`;\n};\n\nexport const isCurrentLoadedFile = (loaded: { loadKey: string } | null, loadKey: string) => loaded?.loadKey === loadKey;\n","import { Button, Center, Spinner, Text } from \"@chakra-ui/react\";\nimport { useEffect, useLayoutEffect, useRef, useState } from \"react\";\nimport type {\n FileRendererContent,\n RegisteredFileRendererContribution,\n WorkbenchCore,\n WorkbenchPanelInstance,\n} from \"../../../core\";\nimport {\n getFileSectionNavigation,\n resolveFileSectionTargetId,\n shouldClearFileSectionSelection,\n} from \"../../../core/registries/renderers/file-section-navigation\";\nimport { FileRendererContentView } from \"./file-renderer-content\";\nimport {\n createFileEditController,\n type FileEditController,\n type FileEditControllerState,\n nextLoadedRevision,\n readCachedFileContent,\n storeCachedFileContent,\n} from \"./file-renderer-edit-state\";\nimport { FileRendererErrorNotice } from \"./file-renderer-error-notice\";\nimport { createFileRendererLoadKey, isCurrentLoadedFile } from \"./file-renderer-load-key\";\n\ninterface WorkbenchFileRendererViewProps {\n workbench: WorkbenchCore;\n contribution: RegisteredFileRendererContribution;\n // The bound resource (e.g. the open ticket / ticket-file) the load/save\n // commands operate on.\n placement?: WorkbenchPanelInstance;\n}\n\ninterface LoadedFile extends FileRendererContent {\n // Bumped on every (re)load so the uncontrolled editors remount with fresh\n // content on a refresh, but never mid-edit (load only runs on mount/refresh).\n editorRevision: number;\n loadKey: string;\n}\n\nconst SAVE_DEBOUNCE_MS = 600;\n\nconst describeError = (error: unknown) => (error instanceof Error ? error.message : \"Failed to load file.\");\n\nconst syncActiveFileSection = (input: {\n workbench: WorkbenchCore;\n navigation: ReturnType<typeof getFileSectionNavigation>;\n sectionId: string | null;\n}) => {\n const { workbench, navigation, sectionId } = input;\n if (!navigation || !workbench.renderers.getTreeRenderer(navigation.treeId)) return;\n\n if (sectionId && navigation.anchors.some((anchor) => anchor.id === sectionId)) {\n workbench.renderers.setSelectedNode(navigation.treeId, sectionId);\n return;\n }\n\n const selectedNodeId = workbench.renderers.getTreeState(navigation.treeId).selectedNodeId;\n if (selectedNodeId && navigation.anchors.some((anchor) => anchor.id === selectedNodeId)) {\n workbench.renderers.setSelectedNode(navigation.treeId, undefined);\n }\n};\n\nconst getEditorSectionNavigation = (\n workbench: WorkbenchCore,\n navigation: ReturnType<typeof getFileSectionNavigation>,\n) => {\n if (!navigation) return undefined;\n const selectedNodeId = workbench.renderers.getTreeRenderer(navigation.treeId)\n ? workbench.renderers.getTreeState(navigation.treeId).selectedNodeId\n : undefined;\n\n return {\n anchors: navigation.anchors,\n targetId: resolveFileSectionTargetId(navigation, selectedNodeId),\n };\n};\n\nexport const WorkbenchFileRendererView = (props: WorkbenchFileRendererViewProps) => {\n const { workbench, contribution } = props;\n const resource = props.placement?.resource;\n const sectionNavigation = getFileSectionNavigation(resource);\n const editorSectionNavigation = getEditorSectionNavigation(workbench, sectionNavigation);\n const loadKey = createFileRendererLoadKey({\n fileRendererId: contribution.id,\n resourceUri: resource?.uri,\n resourceMetadata: resource?.metadata,\n });\n const [loaded, setLoaded] = useState<LoadedFile | null>(null);\n const [error, setError] = useState<{ loadKey: string; message: string } | null>(null);\n const [editState, setEditState] = useState<FileEditControllerState>({ dirty: false, saving: false });\n const controllerRef = useRef<FileEditController | null>(null);\n const rendererRef = useRef<HTMLDivElement>(null);\n const previousSectionNavigationRef = useRef<{\n resourceUri?: string;\n treeId: string;\n anchorIds: string[];\n } | null>(null);\n\n useEffect(() => {\n const previous = previousSectionNavigationRef.current;\n const selectedNodeId =\n previous && workbench.renderers.getTreeRenderer(previous.treeId)\n ? workbench.renderers.getTreeState(previous.treeId).selectedNodeId\n : undefined;\n\n if (\n shouldClearFileSectionSelection({\n previous,\n current: sectionNavigation,\n currentResourceUri: resource?.uri,\n selectedNodeId,\n }) &&\n previous\n ) {\n workbench.renderers.setSelectedNode(previous.treeId, undefined);\n }\n\n previousSectionNavigationRef.current = sectionNavigation\n ? {\n resourceUri: resource?.uri,\n treeId: sectionNavigation.treeId,\n anchorIds: sectionNavigation.anchors.map((anchor) => anchor.id),\n }\n : null;\n }, [resource?.uri, sectionNavigation, workbench]);\n\n // Contribution refresh re-registers an identical contribution as a new\n // object, and a save that changes the document title produces a new resource\n // object with a fresh label. Identity is the contribution id plus the\n // resource URI (both inside loadKey); callbacks read the latest objects\n // through refs so neither replacement resets an open editor.\n const contributionRef = useRef(contribution);\n const resourceRef = useRef(resource);\n useEffect(() => {\n contributionRef.current = contribution;\n resourceRef.current = resource;\n });\n\n const contributionId = contribution.id;\n const hasSave = Boolean(contribution.save);\n\n // Re-binding a singleton widget to another resource changes `resource` and reloads.\n useEffect(() => {\n let cancelled = false;\n setError(null);\n // A recently viewed document mounts immediately from the cache; the load\n // below reconciles it (unchanged content keeps the editor mounted).\n const cached = readCachedFileContent(loadKey);\n setLoaded(cached ? { ...cached, editorRevision: 1, loadKey } : null);\n const load = () => {\n Promise.resolve(contributionRef.current.load(resourceRef.current))\n .then((next) => {\n if (cancelled) return;\n if (controllerRef.current && !controllerRef.current.acceptLoaded(next.content, next.revision)) return;\n setError(null);\n storeCachedFileContent(loadKey, next);\n // Compare against the editor's current value so a reload that returns\n // what is already shown (e.g. after a save) keeps the editor mounted.\n const editorValue = controllerRef.current?.getBaseline();\n setLoaded((previous) => ({\n ...next,\n editorRevision: nextLoadedRevision(previous, next, loadKey, editorValue),\n loadKey,\n }));\n })\n .catch((loadError) => {\n if (cancelled) return;\n setError({ loadKey, message: describeError(loadError) });\n });\n };\n controllerRef.current = hasSave\n ? createFileEditController({\n binding: {\n rendererId: contributionId,\n instanceId: props.placement?.instanceId ?? contributionId,\n resourceUri: resourceRef.current?.uri,\n },\n debounceMs: SAVE_DEBOUNCE_MS,\n load,\n onStateChange: (state) => {\n if (!cancelled) setEditState(state);\n },\n save: (value, origin) =>\n Promise.resolve(contributionRef.current.save?.(resourceRef.current, value, origin)).then((result) => {\n const current = readCachedFileContent(loadKey);\n if (current) storeCachedFileContent(loadKey, { ...current, content: value });\n return result ?? undefined;\n }),\n })\n : null;\n if (cached) controllerRef.current?.setBaseline(cached.content, cached.revision);\n setEditState({ dirty: false, saving: false });\n load();\n const refreshSubscription = workbench.renderers.onDidRefreshFileRenderer((event) => {\n if (event.fileRendererId !== contributionId) return;\n const controller = controllerRef.current;\n if (controller) controller.handleRefreshEvent(event);\n else load();\n });\n return () => {\n cancelled = true;\n refreshSubscription.dispose();\n // Flush the last keystrokes on unbind; the load callback above is\n // cancelled, so a deferred refresh cannot resurrect the old binding.\n controllerRef.current?.flush();\n controllerRef.current = null;\n };\n }, [contributionId, hasSave, workbench, loadKey, props.placement?.instanceId]);\n\n // The last keystrokes are also flushed when the tab is hidden or closed.\n useEffect(() => {\n const flush = () => controllerRef.current?.flush();\n const onVisibility = () => {\n if (document.visibilityState === \"hidden\") flush();\n };\n window.addEventListener(\"beforeunload\", flush);\n document.addEventListener(\"visibilitychange\", onVisibility);\n return () => {\n window.removeEventListener(\"beforeunload\", flush);\n document.removeEventListener(\"visibilitychange\", onVisibility);\n };\n }, []);\n\n const handleChange = (value: string) => {\n controllerRef.current?.handleChange(value);\n };\n\n const currentLoaded = isCurrentLoadedFile(loaded, loadKey) ? loaded : null;\n const scrollResetKey = currentLoaded ? `${currentLoaded.loadKey}:${currentLoaded.editorRevision}` : \"\";\n\n useLayoutEffect(() => {\n if (!scrollResetKey || sectionNavigation) return;\n const node = rendererRef.current;\n if (!node) return;\n\n requestAnimationFrame(() => {\n let current = node.parentElement;\n while (current) {\n const overflowY = getComputedStyle(current).overflowY;\n if ([\"auto\", \"scroll\", \"overlay\"].includes(overflowY) && current.scrollHeight > current.clientHeight) {\n current.scrollTop = 0;\n }\n current = current.parentElement;\n }\n });\n }, [scrollResetKey, sectionNavigation]);\n\n const loadError = error?.loadKey === loadKey ? error.message : undefined;\n const retryLoad = () => controllerRef.current?.retryLoad();\n const retrySave = () => controllerRef.current?.retry();\n\n if (loadError && !currentLoaded) {\n return (\n <Center h=\"full\" minH=\"0\" bg=\"bg\" p=\"md\" flexDirection=\"column\" gap=\"sm\">\n <Text color=\"fg.muted\">{loadError}</Text>\n <Button size=\"xs\" variant=\"subtle\" onClick={retryLoad}>\n Retry\n </Button>\n </Center>\n );\n }\n\n if (!currentLoaded) {\n return (\n <Center h=\"full\" minH=\"0\" bg=\"bg\">\n <Spinner size=\"sm\" />\n </Center>\n );\n }\n\n const isEditable = Boolean(contribution.save) && !currentLoaded.dataUrl;\n // The key must carry the document identity, not just the contribution: two\n // documents from the same renderer both start at revision 1, so keying on the\n // contribution alone reuses the editor and keeps showing the previous file.\n const editorKey = `${currentLoaded.loadKey}:${currentLoaded.editorRevision}`;\n const errorNotice = loadError ? (\n <FileRendererErrorNotice message={loadError} onRetry={retryLoad} />\n ) : editState.saveError ? (\n <FileRendererErrorNotice message={editState.saveError} onRetry={retrySave} />\n ) : null;\n\n const handleActiveSectionChange = (sectionId: string | null) => {\n syncActiveFileSection({ workbench, navigation: sectionNavigation, sectionId });\n };\n\n return (\n <FileRendererContentView\n content={currentLoaded}\n editorKey={editorKey}\n errorNotice={errorNotice}\n isEditable={isEditable}\n onActiveSectionChange={sectionNavigation ? handleActiveSectionChange : undefined}\n onChange={handleChange}\n rendererRef={rendererRef}\n sectionNavigation={editorSectionNavigation}\n title={contribution.title}\n />\n );\n};\n"],"names":["IMAGE_EXTENSIONS","Set","CODE_LANGUAGE_BY_EXTENSION","ts","tsx","js","jsx","mjs","cjs","json","jsonc","py","rb","rs","go","java","kt","c","h","cpp","cc","hpp","cs","php","swift","sh","bash","zsh","sql","css","scss","less","html","xml","yml","yaml","toml","ini","dockerfile","graphql","gql","extensionOf","fileName","dot","lastIndexOf","length","slice","toLowerCase","isImage","mimeType","startsWith","has","pickFileKind","codeLanguageFor","FileRendererContentView","props","$","_c","content","editorKey","errorNotice","isEditable","onActiveSectionChange","onChange","rendererRef","sectionNavigation","title","kind","dataUrl","t0","Symbol","for","Center","Text","t1","Image","t2","t3","jsxs","Flex","undefined","Box","CodeEditor","t4","placeholder","MarkdownEditor","createFileEditController","input","baseline","baselineRevision","draft","activeSave","saveError","deferredRevision","genericRefreshDeferred","timer","operationSequence","seenRefreshRevisions","completedOperationIds","describeError","error","Error","message","getState","dirty","value","saving","notify","onStateChange","clearTimer","clearTimeout","nextOperationId","createOperationId","Date","now","hasPendingLocalState","Boolean","deferRefresh","event","revision","localeCompare","isSelfRefresh","operationId","origin","rendererId","binding","instanceId","takeDeferredRefresh","savedRevision","generic","load","resourceUri","runSave","Promise","resolve","save","then","result","add","size","delete","values","next","schedule","catch","setTimeout","debounceMs","getBaseline","setBaseline","acceptLoaded","handleChange","handleRefreshEvent","retry","retryLoad","flush","nextLoadedRevision","previous","loadKey","editorValue","editorRevision","FILE_CONTENT_CACHE_LIMIT","fileContentCache","Map","readCachedFileContent","get","storeCachedFileContent","set","oldest","keys","FileRendererErrorNotice","onRetry","Button","serializeResourceMetadata","metadata","entries","Object","sort","a","b","JSON","stringify","createFileRendererLoadKey","fileRendererId","resourceMetadata","isCurrentLoadedFile","loaded","SAVE_DEBOUNCE_MS","syncActiveFileSection","workbench","navigation","sectionId","renderers","getTreeRenderer","treeId","anchors","some","anchor","id","setSelectedNode","selectedNodeId","getTreeState","getEditorSectionNavigation","targetId","resolveFileSectionTargetId","WorkbenchFileRendererView","contribution","resource","placement","getFileSectionNavigation","editorSectionNavigation","uri","setLoaded","useState","setError","editState","setEditState","controllerRef","useRef","previousSectionNavigationRef","t5","current","shouldClearFileSectionSelection","currentResourceUri","anchorIds","map","_temp","t6","t7","useEffect","contributionRef","resourceRef","t8","contributionId","hasSave","t9","cancelled","cached","previous_0","loadError","state","refreshSubscription","onDidRefreshFileRenderer","controller","dispose","t10","t11","t12","t13","onVisibility","document","visibilityState","window","addEventListener","removeEventListener","t14","value_0","t15","currentLoaded","scrollResetKey","t16","t17","node","requestAnimationFrame","current_0","parentElement","overflowY","getComputedStyle","includes","scrollHeight","clientHeight","scrollTop","useLayoutEffect","loadError_0","t18","t19","retrySave","t20","t21","t22","Spinner","t23"],"mappings":"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"}