collabmd 0.1.52 → 0.1.54
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/bin/collabmd.js +3 -2
- package/dist/client/assets/{CodeMirrorEditor-UCMRAMCV-BEz2BKN1.js → CodeMirrorEditor-UCMRAMCV-kJfwukbn.js} +1 -1
- package/dist/client/assets/{browser-BKLM0ThC-IxjwuOIz-C0mP17s1.js → browser-BKLM0ThC-BCLQGPD6-K2seJgRL.js} +1 -1
- package/dist/client/assets/{browser-utils-vlHL9goC.js → browser-utils-S4QYY31r.js} +1 -1
- package/dist/client/assets/{chunk-RUX4WMZV-BGnd3s_C.js → chunk-ISPTBLVO-BMsDq9Ha.js} +2 -2
- package/dist/client/assets/{chunk-4SOEAONT-C3fufoVl.js → chunk-T5WUORNS-DD7KlyY6.js} +9 -9
- package/dist/client/assets/{direct-engine-DdrQKpgq-4QysbH_V.js → direct-engine-DVLMOJWp-C-YL5NFb.js} +1 -1
- package/dist/client/assets/{dist-CXOUa90Q.js → dist-9Eodxf4G.js} +1 -1
- package/dist/client/assets/{dist-jVKfryIL.js → dist-B2ZNQifU.js} +1 -1
- package/dist/client/assets/dist-B6QCMNze.js +1 -0
- package/dist/client/assets/dist-BIAv19LO.js +1 -0
- package/dist/client/assets/{dist-Bog8M5U3.js → dist-BKYp1-dl.js} +4 -4
- package/dist/client/assets/{dist-DI6c02Da.js → dist-BSAZ-Hek.js} +1 -1
- package/dist/client/assets/{dist-DNONgI1P.js → dist-BSTbcioM.js} +1 -1
- package/dist/client/assets/{dist-BfpAc922.js → dist-BT9gJXCb.js} +1 -1
- package/dist/client/assets/{dist-CAG5sIOj.js → dist-BTVg1m-V.js} +1 -1
- package/dist/client/assets/{dist-GTGhtpyW.js → dist-Bi9ZIYXq.js} +1 -1
- package/dist/client/assets/{dist-CvVoyTRF.js → dist-BpAUe9sL.js} +1 -1
- package/dist/client/assets/{dist-B7fBbwrO.js → dist-Bqo-XRVG.js} +1 -1
- package/dist/client/assets/{dist-CUsXdnU4.js → dist-BrKhPlc9.js} +1 -1
- package/dist/client/assets/{dist-CYMCikZo.js → dist-CBsvKPcT.js} +1 -1
- package/dist/client/assets/{dist-W0FoeIxk.js → dist-CJBYh9Wy.js} +1 -1
- package/dist/client/assets/{dist-Ck-B8onw.js → dist-CRwfjtwz.js} +1 -1
- package/dist/client/assets/{dist-Dx37MHWs.js → dist-CX7Kc61C.js} +1 -1
- package/dist/client/assets/{dist-zHDLm1oE.js → dist-CoXN2D3R.js} +1 -1
- package/dist/client/assets/{dist-D4kDR0g8.js → dist-CucpLxUY.js} +1 -1
- package/dist/client/assets/{dist-Cu5Ze2cs.js → dist-DHBMeCxC.js} +1 -1
- package/dist/client/assets/dist-DLEg9d4u.js +1 -0
- package/dist/client/assets/{dist-Y6zYRI-A.js → dist-DOHWxIty.js} +1 -1
- package/dist/client/assets/{dist-DVBYH83t.js → dist-DYFBD-wW.js} +1 -1
- package/dist/client/assets/{dist-CsQTfQFi.js → dist-DeCV9FU4.js} +1 -1
- package/dist/client/assets/dist-DugWGOjQ.js +1 -0
- package/dist/client/assets/{dist-BVCNc-Es.js → dist-KrdpB_GB.js} +1 -1
- package/dist/client/assets/{dist-B_1hMrc6.js → dist-NNrRnB-f.js} +1 -1
- package/dist/client/assets/{dist-Da-jLrCf.js → dist-PUxZqhFe.js} +1 -1
- package/dist/client/assets/dist-cYiJMWHJ.js +1 -0
- package/dist/client/assets/dist-iKC7go4m.js +1 -0
- package/dist/client/assets/{dist-CKf7LlAo.js → dist-lw5TGjI6.js} +1 -1
- package/dist/client/assets/{dist-DGa-2MNX.js → dist-uk11ih8u.js} +1 -1
- package/dist/client/assets/{document-formatter-gO8qM2qY.js → document-formatter-6I63vstk.js} +1 -1
- package/dist/client/assets/{drawioEditor-DCkWweiy.js → drawioEditor-DNTjsjzJ.js} +1 -1
- package/dist/client/assets/{editor-session-DxRyr4EM.js → editor-session-D8GGkJak.js} +3 -3
- package/dist/client/assets/{embedpdf-DyOonRvx.js → embedpdf-TkbBYowM.js} +1 -1
- package/dist/client/assets/{embedpdf-DA4bA119-DsoNiPlQ.js → embedpdf-cl9qiF45-itpgqvGY.js} +2 -2
- package/dist/client/assets/{en-GNC3RJIS-CEy_oGTd.js → en-JTHJ2SIP-DBz9bRq4.js} +1 -1
- package/dist/client/assets/{estree-DCT3Jm65.js → estree-DGmLqopC.js} +17 -17
- package/dist/client/assets/{excalidraw-element-link-CGZ5934B.js → excalidraw-element-link-BRZOTIeI.js} +2 -2
- package/dist/client/assets/{excalidrawEditor-BVfSxjSO.js → excalidrawEditor-D0orhhku.js} +3 -3
- package/dist/client/assets/{export-page-BCo_e15t.js → export-page-CVJNMERq.js} +3 -3
- package/dist/client/assets/{exportDocument-DP6oE_or.js → exportDocument-DSshnmnZ.js} +2 -2
- package/dist/client/assets/{file-search-3hYF4cYa.js → file-search-BA8o_gs0.js} +1 -1
- package/dist/client/assets/{html-CBXMuS97.js → html-BryNQ_yx.js} +6 -6
- package/dist/client/assets/image-I42VHMUI-B2-c_ifV.js +1 -0
- package/dist/client/assets/index-BCgNcVNs.css +1 -0
- package/dist/client/assets/index-BpmR5Qqk.js +1140 -0
- package/dist/client/assets/{lobby-presence-Cz5jGOPg.js → lobby-presence-KJrYhMdN.js} +1 -1
- package/dist/client/assets/{markdown-Bo71X2X2.js → markdown-CZ1tYEW8.js} +17 -17
- package/dist/client/assets/{pdfium-RAgkpwfK.wasm → pdfium-BJ2Yip8Q.wasm} +0 -0
- package/dist/client/assets/{preview-render-compiler-ktU0SXxY.js → preview-render-compiler-BmWQStaL.js} +1 -1
- package/dist/client/assets/{preview-render-worker-BI2bFVqM.js → preview-render-worker-BA4VK_GY.js} +2 -2
- package/dist/client/assets/prod-CA0ie9yD.js +145 -0
- package/dist/client/assets/prod-yKJZ3E4s.js +1 -0
- package/dist/client/assets/{quick-switcher-controller-DSlOwOsU.js → quick-switcher-controller-B5vT9Vj5.js} +1 -1
- package/dist/client/assets/runtime-config-CvrkHb0n.js +1 -0
- package/dist/client/assets/runtime-paths-qQGhzNx4.js +1 -0
- package/dist/client/assets/{standalone-6z5x8CWe.js → standalone-DbyFjvTU.js} +1 -1
- package/dist/client/assets/{vault-api-client-BQxLVPeF.js → vault-api-client-NS_EVHJ3.js} +2 -2
- package/dist/client/assets/{worker-engine-m0rlHn8R-5h66k403.js → worker-engine-BCCrxWYm-CX0qJ_cG.js} +1 -1
- package/dist/client/assets/{workspace-sync-client-C2pdaQUN.js → workspace-sync-client-BrMtf6zN.js} +1 -1
- package/dist/client/drawio-editor.html +5 -5
- package/dist/client/excalidraw-editor.html +9 -9
- package/dist/client/export-document.html +1 -1
- package/dist/client/index.html +13 -2
- package/package.json +14 -14
- package/src/client/app/index.html +11 -0
- package/src/client/app/main-entry.js +30 -4
- package/src/client/bootstrap/collabmd-app-shell.js +3 -1
- package/src/client/browser-utils.js +21 -0
- package/src/client/domain/file-search.js +1 -1
- package/src/client/domain/runtime-paths.js +4 -0
- package/src/client/infrastructure/runtime-config.js +14 -0
- package/src/client/presentation/drawio-embed-controller.js +3 -1
- package/src/client/presentation/excalidraw-embed-controller.js +3 -1
- package/src/client/presentation/file-action-controller.js +21 -1
- package/src/client/presentation/file-explorer-view.js +24 -6
- package/src/client/presentation/vault-dashboard.js +63 -0
- package/src/client/styles/foundation/utilities.css +2 -0
- package/src/client/styles/layout/overlays.css +5 -0
- package/src/client/styles/layout/shell.css +152 -0
- package/src/server/config/env.js +39 -6
- package/src/server/infrastructure/http/create-static-handler.js +3 -1
- package/src/server/infrastructure/http/create-vault-api-query-handler.js +1 -1
- package/dist/client/assets/dist-BYBF4LtZ.js +0 -1
- package/dist/client/assets/dist-BnVaoRgZ.js +0 -1
- package/dist/client/assets/dist-CrkYYcOU.js +0 -1
- package/dist/client/assets/dist-D8LnhZzy.js +0 -1
- package/dist/client/assets/dist-DX6qtdxv.js +0 -1
- package/dist/client/assets/dist-DofvCYzJ.js +0 -1
- package/dist/client/assets/image-EJJKRVD3-BQfi5nWJ.js +0 -1
- package/dist/client/assets/index-BxAuGDoN.css +0 -1
- package/dist/client/assets/index-uw9O0z1c.js +0 -1112
- package/dist/client/assets/prod-DU-0VfI7.js +0 -145
- package/dist/client/assets/prod-cXUNdmYV.js +0 -1
- package/dist/client/assets/runtime-config-BFVdhnJu.js +0 -1
- package/dist/client/assets/runtime-paths-Cn0snt_9.js +0 -1
|
@@ -76,6 +76,10 @@ export function getActiveVaultId(config = getClientRuntimeConfig()) {
|
|
|
76
76
|
if (vaults.length === 0) {
|
|
77
77
|
return null;
|
|
78
78
|
}
|
|
79
|
+
const requested = new URLSearchParams(globalThis.window?.location?.search ?? '').get('vault');
|
|
80
|
+
if (requested && vaults.includes(requested)) {
|
|
81
|
+
return requested;
|
|
82
|
+
}
|
|
79
83
|
try {
|
|
80
84
|
const stored = globalThis.window?.localStorage?.getItem(ACTIVE_VAULT_STORAGE_KEY);
|
|
81
85
|
if (stored && vaults.includes(stored)) {
|
|
@@ -21,6 +21,20 @@ export function getRuntimeConfig() {
|
|
|
21
21
|
export { getActiveVaultId, resolveApiUrl, resolveAppPath, resolveAppUrl, resolveWsBaseUrl, setActiveVaultId };
|
|
22
22
|
export { createFileRouteHash, isCollabMdHashRoute };
|
|
23
23
|
|
|
24
|
+
export function initializeWorkspaceUrl() {
|
|
25
|
+
const url = new URL(window.location.href);
|
|
26
|
+
const vaultId = getActiveVaultId();
|
|
27
|
+
if (vaultId) {
|
|
28
|
+
url.searchParams.set('vault', vaultId);
|
|
29
|
+
}
|
|
30
|
+
const filePath = url.searchParams.get('file');
|
|
31
|
+
if (filePath && !url.hash) {
|
|
32
|
+
url.hash = createFileRouteHash(filePath);
|
|
33
|
+
}
|
|
34
|
+
url.searchParams.delete('file');
|
|
35
|
+
window.history.replaceState(window.history.state, '', url);
|
|
36
|
+
}
|
|
37
|
+
|
|
24
38
|
function getHashParams() {
|
|
25
39
|
return getHashParamsFromRaw(window.location.hash);
|
|
26
40
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createDrawioLeaseRoomName } from '../../domain/drawio-room.js';
|
|
2
2
|
import { setDiagramActionButtonIcon } from '../domain/diagram-action-icons.js';
|
|
3
|
-
import { resolveAppUrl } from '../domain/runtime-paths.js';
|
|
3
|
+
import { getActiveVaultId, resolveAppUrl } from '../domain/runtime-paths.js';
|
|
4
4
|
import { renderDrawioViewer } from './drawio-viewer.js';
|
|
5
5
|
import {
|
|
6
6
|
cancelIdleRender,
|
|
@@ -363,6 +363,8 @@ export class DrawioEmbedController {
|
|
|
363
363
|
buildIframeUrl(entry) {
|
|
364
364
|
const url = new URL(resolveAppUrl('/drawio-editor.html'));
|
|
365
365
|
const localUser = this.getLocalUser?.() ?? {};
|
|
366
|
+
const vaultId = getActiveVaultId();
|
|
367
|
+
if (vaultId) url.searchParams.set('vault', vaultId);
|
|
366
368
|
url.searchParams.set('file', entry.filePath);
|
|
367
369
|
url.searchParams.set('hostMode', entry.mode === 'edit' ? 'file-preview' : 'embed');
|
|
368
370
|
url.searchParams.set('instanceId', entry.instanceId);
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { setDiagramActionButtonIcon } from '../domain/diagram-action-icons.js';
|
|
2
2
|
import { parseExcalidrawElementLink } from '../domain/excalidraw-element-link.js';
|
|
3
3
|
import { reconcileEmbedEntries } from './excalidraw-embed-reconciler.js';
|
|
4
|
-
import { resolveAppPath, resolveAppUrl, resolveWsServerOverride } from '../domain/runtime-paths.js';
|
|
4
|
+
import { getActiveVaultId, resolveAppPath, resolveAppUrl, resolveWsServerOverride } from '../domain/runtime-paths.js';
|
|
5
5
|
import {
|
|
6
6
|
cancelIdleRender,
|
|
7
7
|
isNearViewport,
|
|
@@ -762,6 +762,8 @@ export class ExcalidrawEmbedController {
|
|
|
762
762
|
}
|
|
763
763
|
const theme = this.getTheme?.() || 'dark';
|
|
764
764
|
|
|
765
|
+
const vaultId = getActiveVaultId();
|
|
766
|
+
if (vaultId) iframeUrl.searchParams.set('vault', vaultId);
|
|
765
767
|
iframeUrl.searchParams.set('file', entry.filePath);
|
|
766
768
|
iframeUrl.searchParams.set('theme', theme);
|
|
767
769
|
iframeUrl.searchParams.set('boot', entry.instanceId || '');
|
|
@@ -3,7 +3,7 @@ import {
|
|
|
3
3
|
isVaultFilePath,
|
|
4
4
|
VAULT_FILE_EXTENSIONS,
|
|
5
5
|
} from '../../domain/file-kind.js';
|
|
6
|
-
import { pickFiles } from '../browser-utils.js';
|
|
6
|
+
import { copyTextToClipboard, pickFiles } from '../browser-utils.js';
|
|
7
7
|
import {
|
|
8
8
|
createBaseStarter,
|
|
9
9
|
composeVaultChildPath,
|
|
@@ -17,6 +17,8 @@ import {
|
|
|
17
17
|
getVaultPathParent,
|
|
18
18
|
normalizeVaultPathInput,
|
|
19
19
|
} from '../domain/vault-paths.js';
|
|
20
|
+
import { createFileRouteHash } from '../domain/hash-routes.js';
|
|
21
|
+
import { getActiveVaultId } from '../domain/runtime-paths.js';
|
|
20
22
|
import { buttonClassNames } from './components/ui/button.js';
|
|
21
23
|
import { CreateMenuPresenter } from './create-menu-presenter.js';
|
|
22
24
|
|
|
@@ -258,6 +260,10 @@ export class FileActionController {
|
|
|
258
260
|
|
|
259
261
|
getFileContextMenuItems(filePath) {
|
|
260
262
|
return [
|
|
263
|
+
{
|
|
264
|
+
label: 'Copy as URL',
|
|
265
|
+
onSelect: () => this.copyFileUrl(filePath),
|
|
266
|
+
},
|
|
261
267
|
{
|
|
262
268
|
label: 'Rename / move',
|
|
263
269
|
onSelect: () => this.handleRenameFile(filePath),
|
|
@@ -274,6 +280,20 @@ export class FileActionController {
|
|
|
274
280
|
];
|
|
275
281
|
}
|
|
276
282
|
|
|
283
|
+
async copyFileUrl(filePath) {
|
|
284
|
+
const url = new URL(window.location.href);
|
|
285
|
+
url.search = '';
|
|
286
|
+
const vaultId = getActiveVaultId();
|
|
287
|
+
if (vaultId) url.searchParams.set('vault', vaultId);
|
|
288
|
+
url.hash = createFileRouteHash(filePath);
|
|
289
|
+
try {
|
|
290
|
+
await copyTextToClipboard(url.toString());
|
|
291
|
+
this.showToast('Link copied');
|
|
292
|
+
} catch {
|
|
293
|
+
this.showToast('Failed to copy link');
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
|
|
277
297
|
showToast(message) {
|
|
278
298
|
if (message) {
|
|
279
299
|
this.toastController?.show(String(message));
|
|
@@ -4,6 +4,7 @@ import {
|
|
|
4
4
|
stripVaultFileExtension,
|
|
5
5
|
} from '../../domain/file-kind.js';
|
|
6
6
|
import { escapeHtml } from '../domain/vault-utils.js';
|
|
7
|
+
import { findFuzzyMatch } from '../domain/file-search.js';
|
|
7
8
|
import { getVaultPathLeaf, getVaultPathParent } from '../domain/vault-paths.js';
|
|
8
9
|
import { buttonClassNames } from './components/ui/button.js';
|
|
9
10
|
|
|
@@ -43,9 +44,17 @@ function createMenuFilterInput({ container, itemSelector, placeholder, skipLabel
|
|
|
43
44
|
if (skipLabels.includes(button.textContent)) {
|
|
44
45
|
return;
|
|
45
46
|
}
|
|
46
|
-
|
|
47
|
+
const text = (button.dataset.searchText ?? button.textContent ?? '').toLowerCase();
|
|
48
|
+
button.hidden = query.length > 0 && !text.includes(query) && !findFuzzyMatch(text, query);
|
|
47
49
|
});
|
|
48
50
|
});
|
|
51
|
+
searchInput.addEventListener('keydown', (event) => {
|
|
52
|
+
if (event.key === 'Enter') {
|
|
53
|
+
event.preventDefault();
|
|
54
|
+
Array.from(container.querySelectorAll(itemSelector))
|
|
55
|
+
.find((button) => !button.hidden && !skipLabels.includes(button.textContent))?.click();
|
|
56
|
+
}
|
|
57
|
+
});
|
|
49
58
|
container.appendChild(searchInput);
|
|
50
59
|
return searchInput;
|
|
51
60
|
}
|
|
@@ -117,17 +126,17 @@ export class FileExplorerView {
|
|
|
117
126
|
button.className = 'vault-switcher-button';
|
|
118
127
|
button.id = 'vaultSwitcher';
|
|
119
128
|
button.setAttribute('aria-haspopup', 'menu');
|
|
120
|
-
button.setAttribute('aria-label', `Switch vault (current: ${active.id})`);
|
|
129
|
+
button.setAttribute('aria-label', `Switch vault (current: ${active.name || active.id})`);
|
|
121
130
|
button.title = 'Switch vault';
|
|
122
|
-
button.innerHTML = `<span class="vault-switcher-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg></span><span class="vault-switcher-name">${escapeHtml(active.id)}</span><span class="vault-switcher-chevron" aria-hidden="true"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg></span>`;
|
|
131
|
+
button.innerHTML = `<span class="vault-switcher-icon" aria-hidden="true"><svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg></span><span class="vault-switcher-name">${escapeHtml(active.name || active.id)}</span><span class="vault-switcher-chevron" aria-hidden="true"><svg width="12" height="12" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 9 6 6 6-6"></path></svg></span>`;
|
|
123
132
|
button.addEventListener('click', (event) => {
|
|
124
133
|
this.showContextMenu(event, entries.map((vault) => ({
|
|
125
|
-
label: vault.id,
|
|
134
|
+
label: vault.name || vault.id,
|
|
135
|
+
searchText: `${vault.name || vault.id} ${vault.id}`,
|
|
126
136
|
onSelect: () => (onVaultSelect ?? this.onVaultSelect)?.(vault.id),
|
|
127
137
|
})), {
|
|
128
138
|
alignToAnchor: true,
|
|
129
|
-
|
|
130
|
-
searchPlaceholder: entries.length > 8 ? 'Filter vaults…' : '',
|
|
139
|
+
searchPlaceholder: 'Filter vaults…',
|
|
131
140
|
});
|
|
132
141
|
});
|
|
133
142
|
wrapper.appendChild(button);
|
|
@@ -1093,6 +1102,7 @@ export class FileExplorerView {
|
|
|
1093
1102
|
button.className = `file-context-item${item.danger ? ' file-context-danger' : ''}`;
|
|
1094
1103
|
button.setAttribute('role', 'menuitem');
|
|
1095
1104
|
button.textContent = item.label;
|
|
1105
|
+
if (item.searchText) button.dataset.searchText = item.searchText;
|
|
1096
1106
|
button.addEventListener('click', () => {
|
|
1097
1107
|
this.removeContextMenu();
|
|
1098
1108
|
item.onSelect?.({ anchor: contextAnchor });
|
|
@@ -1184,6 +1194,7 @@ export class FileExplorerView {
|
|
|
1184
1194
|
extra: ['file-action-sheet-item', item.danger ? 'file-context-danger' : ''],
|
|
1185
1195
|
});
|
|
1186
1196
|
button.textContent = item.label;
|
|
1197
|
+
if (item.searchText) button.dataset.searchText = item.searchText;
|
|
1187
1198
|
button.addEventListener('click', () => {
|
|
1188
1199
|
this.removeContextMenu();
|
|
1189
1200
|
item.onSelect?.();
|
|
@@ -1203,6 +1214,13 @@ export class FileExplorerView {
|
|
|
1203
1214
|
});
|
|
1204
1215
|
sheet.appendChild(cancelButton);
|
|
1205
1216
|
|
|
1217
|
+
sheet.addEventListener('keydown', (event) => {
|
|
1218
|
+
if (event.key === 'Escape') {
|
|
1219
|
+
// A search input otherwise consumes Escape before the dialog can cancel.
|
|
1220
|
+
event.preventDefault();
|
|
1221
|
+
this.removeContextMenu();
|
|
1222
|
+
}
|
|
1223
|
+
});
|
|
1206
1224
|
sheet.addEventListener('cancel', (event) => {
|
|
1207
1225
|
event.preventDefault();
|
|
1208
1226
|
this.removeContextMenu();
|
|
@@ -0,0 +1,63 @@
|
|
|
1
|
+
import { findFuzzyMatch } from '../domain/file-search.js';
|
|
2
|
+
|
|
3
|
+
export function renderVaultDashboard({ container, vaults, getVaultUrl, onSelect }) {
|
|
4
|
+
container.removeAttribute('role');
|
|
5
|
+
container.classList.add('vault-dashboard');
|
|
6
|
+
container.innerHTML = `
|
|
7
|
+
<main class="vault-dashboard-card" aria-labelledby="vaultDashboardTitle">
|
|
8
|
+
<header class="vault-dashboard-header">
|
|
9
|
+
<div class="sidebar-brand">
|
|
10
|
+
<svg width="28" height="28" viewBox="0 0 32 32" fill="none" aria-hidden="true">
|
|
11
|
+
<rect x="3" y="4" width="17" height="24" rx="3" stroke="var(--color-primary)" stroke-width="2"></rect>
|
|
12
|
+
<rect x="12" y="4" width="17" height="24" rx="3" fill="var(--color-primary)"></rect>
|
|
13
|
+
<path d="M17 12h7m-7 4h7m-7 4h4" stroke="var(--color-primary-contrast)" stroke-width="1.5"></path>
|
|
14
|
+
</svg>
|
|
15
|
+
<span class="sidebar-title">CollabMD</span>
|
|
16
|
+
</div>
|
|
17
|
+
<h1 id="vaultDashboardTitle">Choose a vault</h1>
|
|
18
|
+
<p>Open a project to start collaborating.</p>
|
|
19
|
+
</header>
|
|
20
|
+
<div class="vault-dashboard-search">
|
|
21
|
+
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" aria-hidden="true"><circle cx="10.5" cy="10.5" r="6.5"></circle><path d="m16 16 4 4"></path></svg>
|
|
22
|
+
<input type="search" class="ui-input" aria-label="Find a vault" placeholder="Find a vault…">
|
|
23
|
+
</div>
|
|
24
|
+
<div class="vault-dashboard-list-heading">
|
|
25
|
+
<h2>Your vaults</h2>
|
|
26
|
+
<span class="ui-pill-badge ui-pill-badge--count ui-pill-badge--muted"></span>
|
|
27
|
+
</div>
|
|
28
|
+
<nav aria-label="Vaults"></nav>
|
|
29
|
+
<p class="ui-empty-state" role="status" hidden>No matching vaults.</p>
|
|
30
|
+
<footer class="vault-dashboard-footer">Press <kbd>Enter</kbd> to open the first match</footer>
|
|
31
|
+
</main>`;
|
|
32
|
+
container.querySelector('.ui-pill-badge').textContent = String(vaults.length);
|
|
33
|
+
const list = container.querySelector('nav');
|
|
34
|
+
const empty = container.querySelector('[role="status"]');
|
|
35
|
+
const entries = vaults.map((vault) => {
|
|
36
|
+
const link = document.createElement('a');
|
|
37
|
+
link.className = 'ui-record-surface vault-dashboard-link';
|
|
38
|
+
link.href = getVaultUrl(vault.id);
|
|
39
|
+
link.innerHTML = `
|
|
40
|
+
<span class="vault-dashboard-icon" aria-hidden="true"><svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round"><path d="M22 19a2 2 0 0 1-2 2H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h5l2 3h9a2 2 0 0 1 2 2z"></path></svg></span>
|
|
41
|
+
<span class="vault-dashboard-name"></span>
|
|
42
|
+
<svg class="vault-dashboard-arrow" width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.75" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true"><path d="M5 12h14m-5-5 5 5-5 5"></path></svg>`;
|
|
43
|
+
link.querySelector('.vault-dashboard-name').textContent = vault.name || vault.id;
|
|
44
|
+
link.addEventListener('click', () => onSelect?.(vault.id));
|
|
45
|
+
list.append(link);
|
|
46
|
+
return { link, text: `${vault.name || vault.id} ${vault.id}`.toLowerCase() };
|
|
47
|
+
});
|
|
48
|
+
const input = container.querySelector('input');
|
|
49
|
+
input.addEventListener('input', () => {
|
|
50
|
+
const query = input.value.trim().toLowerCase();
|
|
51
|
+
entries.forEach(({ link, text }) => {
|
|
52
|
+
link.hidden = Boolean(query && !text.includes(query) && !findFuzzyMatch(text, query));
|
|
53
|
+
});
|
|
54
|
+
empty.hidden = entries.some(({ link }) => !link.hidden);
|
|
55
|
+
});
|
|
56
|
+
input.addEventListener('keydown', (event) => {
|
|
57
|
+
if (event.key === 'Enter') {
|
|
58
|
+
event.preventDefault();
|
|
59
|
+
entries.find(({ link }) => !link.hidden)?.link.click();
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
input.focus();
|
|
63
|
+
}
|
|
@@ -1,5 +1,157 @@
|
|
|
1
1
|
/* ===== APP SHELL ===== */
|
|
2
2
|
|
|
3
|
+
html[data-workspace-loading] .app-shell,
|
|
4
|
+
html[data-workspace-loading] .skip-link {
|
|
5
|
+
visibility: hidden;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
.workspace-loading {
|
|
9
|
+
position: fixed;
|
|
10
|
+
inset: 0;
|
|
11
|
+
display: grid;
|
|
12
|
+
place-content: center;
|
|
13
|
+
padding: var(--space-6);
|
|
14
|
+
overflow: auto;
|
|
15
|
+
background: var(--color-bg);
|
|
16
|
+
color: var(--color-text-muted);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
.vault-dashboard {
|
|
20
|
+
place-items: center;
|
|
21
|
+
place-content: normal;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
.vault-dashboard-card {
|
|
25
|
+
width: min(100%, 520px);
|
|
26
|
+
padding: clamp(var(--space-5), 4vw, var(--space-8));
|
|
27
|
+
border: 1px solid var(--border-accent-soft);
|
|
28
|
+
border-radius: var(--radius-xl);
|
|
29
|
+
background: var(--color-surface);
|
|
30
|
+
color: var(--color-text);
|
|
31
|
+
box-shadow: var(--shadow-card-strong);
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.vault-dashboard-header .sidebar-brand {
|
|
35
|
+
margin-bottom: var(--space-6);
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
.vault-dashboard-header h1 {
|
|
39
|
+
margin: 0 0 var(--space-2);
|
|
40
|
+
font-family: var(--font-display);
|
|
41
|
+
font-size: var(--text-xl);
|
|
42
|
+
line-height: 1.15;
|
|
43
|
+
letter-spacing: -0.035em;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
.vault-dashboard-header p {
|
|
47
|
+
margin: 0 0 var(--space-6);
|
|
48
|
+
color: var(--color-text-muted);
|
|
49
|
+
font-size: var(--text-ui-md);
|
|
50
|
+
line-height: 1.5;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
.vault-dashboard-search {
|
|
54
|
+
position: relative;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
.vault-dashboard-search > svg {
|
|
58
|
+
position: absolute;
|
|
59
|
+
top: 50%;
|
|
60
|
+
left: var(--space-3);
|
|
61
|
+
color: var(--color-text-faint);
|
|
62
|
+
transform: translateY(-50%);
|
|
63
|
+
pointer-events: none;
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
.vault-dashboard-search .ui-input {
|
|
67
|
+
min-height: var(--control-h-lg);
|
|
68
|
+
padding-left: var(--space-10);
|
|
69
|
+
background: var(--color-surface-offset);
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.vault-dashboard-list-heading {
|
|
73
|
+
display: flex;
|
|
74
|
+
align-items: center;
|
|
75
|
+
justify-content: space-between;
|
|
76
|
+
margin: var(--space-6) 0 var(--space-3);
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
.vault-dashboard-list-heading h2 {
|
|
80
|
+
margin: 0;
|
|
81
|
+
color: var(--color-text-muted);
|
|
82
|
+
font-size: var(--text-ui-sm);
|
|
83
|
+
font-weight: 600;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.vault-dashboard-card nav {
|
|
87
|
+
display: grid;
|
|
88
|
+
gap: var(--space-2);
|
|
89
|
+
max-height: 40dvh;
|
|
90
|
+
padding: var(--space-1);
|
|
91
|
+
margin: calc(-1 * var(--space-1));
|
|
92
|
+
overflow: auto;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
.vault-dashboard-link.ui-record-surface {
|
|
96
|
+
--ui-record-gap: var(--space-3);
|
|
97
|
+
--ui-record-border-hover: var(--border-accent-soft);
|
|
98
|
+
flex-direction: row;
|
|
99
|
+
align-items: center;
|
|
100
|
+
color: var(--color-text);
|
|
101
|
+
text-decoration: none;
|
|
102
|
+
}
|
|
103
|
+
|
|
104
|
+
.vault-dashboard-icon {
|
|
105
|
+
display: grid;
|
|
106
|
+
place-items: center;
|
|
107
|
+
flex-shrink: 0;
|
|
108
|
+
width: 40px;
|
|
109
|
+
height: 40px;
|
|
110
|
+
border-radius: var(--radius-md);
|
|
111
|
+
background: var(--color-primary-highlight);
|
|
112
|
+
color: var(--color-primary);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
.vault-dashboard-name {
|
|
116
|
+
flex: 1;
|
|
117
|
+
min-width: 0;
|
|
118
|
+
overflow-wrap: anywhere;
|
|
119
|
+
font-size: var(--text-ui-md);
|
|
120
|
+
font-weight: 600;
|
|
121
|
+
line-height: 1.4;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
.vault-dashboard-arrow {
|
|
125
|
+
flex-shrink: 0;
|
|
126
|
+
color: var(--color-text-faint);
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
.vault-dashboard-footer {
|
|
130
|
+
display: flex;
|
|
131
|
+
flex-wrap: wrap;
|
|
132
|
+
align-items: center;
|
|
133
|
+
justify-content: center;
|
|
134
|
+
gap: var(--space-1);
|
|
135
|
+
margin-top: var(--space-6);
|
|
136
|
+
padding-top: var(--space-4);
|
|
137
|
+
border-top: 1px solid var(--color-divider);
|
|
138
|
+
color: var(--color-text-faint);
|
|
139
|
+
font-size: var(--text-caption);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.vault-dashboard-footer kbd {
|
|
143
|
+
padding: 1px var(--space-1);
|
|
144
|
+
border: 1px solid var(--color-divider);
|
|
145
|
+
border-radius: var(--radius-xs);
|
|
146
|
+
background: var(--color-surface-offset);
|
|
147
|
+
font: inherit;
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
.vault-dashboard-link[hidden],
|
|
151
|
+
.vault-dashboard-card [role='status'][hidden] {
|
|
152
|
+
display: none;
|
|
153
|
+
}
|
|
154
|
+
|
|
3
155
|
.app-shell {
|
|
4
156
|
position: fixed;
|
|
5
157
|
top: var(--app-viewport-offset-top, 0px);
|
package/src/server/config/env.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { basename, isAbsolute, relative, resolve } from 'path';
|
|
2
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
+
import { lstatSync, readdirSync, readFileSync } from 'node:fs';
|
|
3
3
|
import { fileURLToPath } from 'url';
|
|
4
4
|
|
|
5
5
|
import {
|
|
@@ -222,11 +222,11 @@ export function parseVaultList(rawValue) {
|
|
|
222
222
|
|
|
223
223
|
export function resolveConfiguredVaults(overrides = {}, env = process.env) {
|
|
224
224
|
if (Array.isArray(overrides.vaults)) {
|
|
225
|
-
return overrides.vaults.map(({ id, dir, repoUrl }) => {
|
|
225
|
+
return overrides.vaults.map(({ id, dir, name, repoUrl }) => {
|
|
226
226
|
if (!VAULT_ID_PATTERN.test(String(id ?? ''))) {
|
|
227
227
|
throw new Error(`Invalid vault id "${id}". ${VAULT_ID_HINT}`);
|
|
228
228
|
}
|
|
229
|
-
return { id, dir: resolve(dir), repoUrl: normalizeOptionalString(repoUrl) };
|
|
229
|
+
return { id, dir: resolve(dir), ...(name ? { name: normalizeOptionalString(name) } : {}), repoUrl: normalizeOptionalString(repoUrl) };
|
|
230
230
|
});
|
|
231
231
|
}
|
|
232
232
|
// ponytail: explicit directory (CLI positional) wins over the operator list
|
|
@@ -235,13 +235,34 @@ export function resolveConfiguredVaults(overrides = {}, env = process.env) {
|
|
|
235
235
|
return [{ id: basename(dir), dir }];
|
|
236
236
|
}
|
|
237
237
|
const rawList = normalizeOptionalString(env.COLLABMD_VAULTS);
|
|
238
|
-
|
|
238
|
+
const discovery = normalizeOptionalString(env.COLLABMD_VAULT_DISCOVERY);
|
|
239
|
+
if (!rawList && !discovery) {
|
|
239
240
|
const dir = resolveConfiguredVaultDir(overrides, env);
|
|
240
241
|
return [{ id: basename(dir), dir }];
|
|
241
242
|
}
|
|
242
|
-
|
|
243
|
+
let vaults;
|
|
244
|
+
if (rawList) {
|
|
245
|
+
vaults = parseVaultList(rawList);
|
|
246
|
+
} else {
|
|
247
|
+
if (!['all', 'marked'].includes(discovery)) {
|
|
248
|
+
throw new Error('COLLABMD_VAULT_DISCOVERY must be "all" or "marked".');
|
|
249
|
+
}
|
|
250
|
+
const root = resolve(env.COLLABMD_VAULT_DIR || '.');
|
|
251
|
+
// ponytail: discover immediate real directories at startup; restart to pick up additions.
|
|
252
|
+
vaults = readdirSync(root, { withFileTypes: true })
|
|
253
|
+
.filter((entry) => entry.isDirectory() && !entry.name.startsWith('.')
|
|
254
|
+
&& (discovery === 'all' || lstatSync(resolve(root, entry.name, '.collabmd'), { throwIfNoEntry: false })?.isDirectory()))
|
|
255
|
+
.sort((a, b) => a.name.localeCompare(b.name, 'en'))
|
|
256
|
+
.map((entry) => ({ id: entry.name, dir: resolve(root, entry.name) }));
|
|
257
|
+
if (vaults.length === 0) {
|
|
258
|
+
throw new Error('No vaults found. Check COLLABMD_VAULT_DIR and COLLABMD_VAULT_DISCOVERY.');
|
|
259
|
+
}
|
|
260
|
+
}
|
|
243
261
|
const seenIds = new Set();
|
|
244
262
|
for (const vault of vaults) {
|
|
263
|
+
if (!VAULT_ID_PATTERN.test(vault.id)) {
|
|
264
|
+
throw new Error(`Invalid vault id "${vault.id}". ${VAULT_ID_HINT}`);
|
|
265
|
+
}
|
|
245
266
|
if (seenIds.has(vault.id)) {
|
|
246
267
|
throw new Error(`Duplicate vault id "${vault.id}" in COLLABMD_VAULTS.`);
|
|
247
268
|
}
|
|
@@ -262,6 +283,17 @@ export function mangleVaultIdForEnv(vaultId) {
|
|
|
262
283
|
return String(vaultId ?? '').toUpperCase().replace(/[^A-Z0-9]/g, '_');
|
|
263
284
|
}
|
|
264
285
|
|
|
286
|
+
export function resolveVaultNames(vaults, env = process.env) {
|
|
287
|
+
return vaults.map((vault) => {
|
|
288
|
+
const suffix = mangleVaultIdForEnv(vault.id);
|
|
289
|
+
const name = normalizeOptionalString(env[`COLLABMD_VAULT_NAME_${suffix}`]);
|
|
290
|
+
if (name && vaults.filter((entry) => mangleVaultIdForEnv(entry.id) === suffix).length > 1) {
|
|
291
|
+
throw new Error(`Ambiguous vault name: multiple vaults share COLLABMD_VAULT_NAME_${suffix}.`);
|
|
292
|
+
}
|
|
293
|
+
return { ...vault, name: vault.name || name || vault.id };
|
|
294
|
+
});
|
|
295
|
+
}
|
|
296
|
+
|
|
265
297
|
// ponytail: explicit repoUrl wins, then COLLABMD_GIT_REPO_URL_<ID>, then the shared URL for the primary
|
|
266
298
|
export function resolveVaultRepoUrls(vaultDefs = [], overrides = {}, env = process.env) {
|
|
267
299
|
const globalRepoUrl = normalizeOptionalString(overrides.remote?.repoUrl ?? overrides.git?.remote?.repoUrl ?? env.COLLABMD_GIT_REPO_URL);
|
|
@@ -540,7 +572,7 @@ function resolvePublicDir(nodeEnv) {
|
|
|
540
572
|
|
|
541
573
|
export function loadConfig(overrides = {}) {
|
|
542
574
|
const nodeEnv = process.env.NODE_ENV || 'development';
|
|
543
|
-
const vaults = resolveVaultRepoUrls(resolveConfiguredVaults(overrides), overrides);
|
|
575
|
+
const vaults = resolveVaultNames(resolveVaultRepoUrls(resolveConfiguredVaults(overrides), overrides));
|
|
544
576
|
// ponytail: vaultDir stays the primary vault; other vaults resolve through the registry
|
|
545
577
|
const vaultDir = overrides.vaultDir || vaults[0].dir;
|
|
546
578
|
const basePath = normalizeAppBasePath(process.env.BASE_PATH || '');
|
|
@@ -622,6 +654,7 @@ export function loadConfig(overrides = {}) {
|
|
|
622
654
|
publicDir,
|
|
623
655
|
vaultDir,
|
|
624
656
|
vaults,
|
|
657
|
+
vaultDashboard: overrides.vaultDashboard ?? parseBooleanFlag(process.env.COLLABMD_VAULT_DASHBOARD),
|
|
625
658
|
publicWsBaseUrl: process.env.PUBLIC_WS_BASE_URL || '',
|
|
626
659
|
testWsRoomHydrateDelayMs: parsePositiveInt(process.env.TEST_WS_ROOM_HYDRATE_DELAY_MS, 0),
|
|
627
660
|
wikiLinkAutoCreate: process.env.COLLABMD_WIKI_LINK_AUTO_CREATE !== 'false',
|
|
@@ -59,6 +59,7 @@ function buildRuntimeConfig({
|
|
|
59
59
|
wikiLinkAutoCreate,
|
|
60
60
|
wsBasePath,
|
|
61
61
|
vaults,
|
|
62
|
+
vaultDashboard,
|
|
62
63
|
}) {
|
|
63
64
|
return `window.__COLLABMD_CONFIG__ = ${JSON.stringify({
|
|
64
65
|
activeVault: vaults?.[0]?.id ?? '',
|
|
@@ -81,7 +82,8 @@ function buildRuntimeConfig({
|
|
|
81
82
|
structurizrEnabled: Boolean(structurizr?.enabled ?? structurizr?.serverUrl),
|
|
82
83
|
wikiLinkAutoCreate,
|
|
83
84
|
wsBasePath,
|
|
84
|
-
vaults: (vaults ?? []).map(({ id }) => ({ id })),
|
|
85
|
+
vaults: (vaults ?? []).map(({ id, name }) => ({ id, name: name || id })),
|
|
86
|
+
vaultDashboard: Boolean(vaultDashboard && !hosted?.enabled),
|
|
85
87
|
})};\n`;
|
|
86
88
|
}
|
|
87
89
|
|
|
@@ -454,7 +454,7 @@ async function handleSearch(req, res, requestUrl, { searchService }) {
|
|
|
454
454
|
|
|
455
455
|
async function handleVaultList(req, res, _requestUrl, { config }) {
|
|
456
456
|
// ponytail: ids only — absolute vault dirs are operator internals
|
|
457
|
-
const vaults = (config?.vaults ?? []).map(({ id }) => ({ id }));
|
|
457
|
+
const vaults = (config?.vaults ?? []).map(({ id, name }) => ({ id, name: name || id }));
|
|
458
458
|
jsonResponse(req, res, 200, { activeVault: vaults[0]?.id ?? null, vaults });
|
|
459
459
|
}
|
|
460
460
|
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{A as e,At as t,B as n,Ct as r,E as i,F as a,M as o,Ot as s,Pt as c,St as l,T as u,Tt as d,V as f,dt as p,gt as m,k as h,kt as g,lt as ee,mt as _,n as te,ut as ne,wt as v}from"./dist-Bog8M5U3.js";var re=e=>{let{state:t}=e,n=t.doc.lineAt(t.selection.main.from),r=b(e.state,n.from);return r.line?ie(e):r.block?oe(e):!1};function y(e,t){return({state:n,dispatch:r})=>{if(n.readOnly)return!1;let i=e(t,n);return i?(r(n.update(i)),!0):!1}}var ie=y(le,0),ae=y(S,0),oe=y((e,t)=>S(e,t,ce(t)),0);function b(e,t){let n=e.languageDataAt(`commentTokens`,t,1);return n.length?n[0]:{}}var x=50;function se(e,{open:t,close:n},r,i){let a=e.sliceDoc(r-x,r),o=e.sliceDoc(i,i+x),s=/\s*$/.exec(a)[0].length,c=/^\s*/.exec(o)[0].length,l=a.length-s;if(a.slice(l-t.length,l)==t&&o.slice(c,c+n.length)==n)return{open:{pos:r-s,margin:s&&1},close:{pos:i+c,margin:c&&1}};let u,d;i-r<=100?u=d=e.sliceDoc(r,i):(u=e.sliceDoc(r,r+x),d=e.sliceDoc(i-x,i));let f=/^\s*/.exec(u)[0].length,p=/\s*$/.exec(d)[0].length,m=d.length-p-n.length;return u.slice(f,f+t.length)==t&&d.slice(m,m+n.length)==n?{open:{pos:r+f+t.length,margin:+!!/\s/.test(u.charAt(f+t.length))},close:{pos:i-p-n.length,margin:+!!/\s/.test(d.charAt(m-1))}}:null}function ce(e){let t=[];for(let n of e.selection.ranges){let r=e.doc.lineAt(n.from),i=n.to<=r.to?r:e.doc.lineAt(n.to);i.from>r.from&&i.from==n.to&&(i=n.to==r.to+1?r:e.doc.lineAt(n.to-1));let a=t.length-1;a>=0&&t[a].to>r.from?t[a].to=i.to:t.push({from:r.from+/^\s*/.exec(r.text)[0].length,to:i.to})}return t}function S(e,t,n=t.selection.ranges){let r=n.map(e=>b(t,e.from).block);if(!r.every(e=>e))return null;let i=n.map((e,n)=>se(t,r[n],e.from,e.to));if(e!=2&&!i.every(e=>e))return{changes:t.changes(n.map((e,t)=>i[t]?[]:[{from:e.from,insert:r[t].open+` `},{from:e.to,insert:` `+r[t].close}]))};if(e!=1&&i.some(e=>e)){let e=[];for(let t=0,n;t<i.length;t++)if(n=i[t]){let i=r[t],{open:a,close:o}=n;e.push({from:a.pos-i.open.length,to:a.pos+a.margin},{from:o.pos-o.margin,to:o.pos+i.close.length})}return{changes:e}}return null}function le(e,t,n=t.selection.ranges){let r=[],i=-1;ranges:for(let{from:e,to:a}of n){let n=r.length,o=1e9,s;for(let n=e;n<=a;){let c=t.doc.lineAt(n);if(s==null&&(s=b(t,c.from).line,!s))continue ranges;if(c.from>i&&(e==a||a>c.from)){i=c.from;let e=/^\s*/.exec(c.text)[0].length,t=e==c.length,n=c.text.slice(e,e+s.length)==s?e:-1;e<c.text.length&&e<o&&(o=e),r.push({line:c,comment:n,token:s,indent:e,empty:t,single:!1})}n=c.to+1}if(o<1e9)for(let e=n;e<r.length;e++)r[e].indent<r[e].line.text.length&&(r[e].indent=o);r.length==n+1&&(r[n].single=!0)}if(e!=2&&r.some(e=>e.comment<0&&(!e.empty||e.single))){let e=[];for(let{line:t,token:n,indent:i,empty:a,single:o}of r)(o||!a)&&e.push({from:t.from+i,insert:n+` `});let n=t.changes(e);return{changes:n,selection:t.selection.map(n,1)}}if(e!=1&&r.some(e=>e.comment>=0)){let e=[];for(let{line:t,comment:n,token:i}of r)if(n>=0){let r=t.from+n,a=r+i.length;t.text[a-t.from]==` `&&a++,e.push({from:r,to:a})}return{changes:e}}return null}var C=ee.define(),ue=ee.define(),de=m.define(),w=m.define({combine(e){return s(e,{minDepth:100,newGroupDelay:500,joinToEvent:(e,t)=>t},{minDepth:Math.max,newGroupDelay:Math.min,joinToEvent:(e,t)=>(n,r)=>e(n,r)||t(n,r)})}}),fe=r.define({create(){return M.empty},update(e,t){let n=t.state.facet(w),r=t.annotation(C);if(r){let i=O.fromTransaction(t,r.selection),a=r.side,o=a==0?e.undone:e.done;return o=i?k(o,o.length,n.minDepth,i):be(o,t.startState.selection),new M(a==0?r.rest:o,a==0?o:r.rest)}let i=t.annotation(ue);if((i==`full`||i==`before`)&&(e=e.isolate()),t.annotation(d.addToHistory)===!1)return t.changes.empty?e:e.addMapping(t.changes.desc);let a=O.fromTransaction(t),o=t.annotation(d.time),s=t.annotation(d.userEvent);return a?e=e.addChanges(a,o,s,n,t):t.selection&&(e=e.addSelection(t.startState.selection,o,s,n.newGroupDelay)),(i==`full`||i==`after`)&&(e=e.isolate()),e},toJSON(e){return{done:e.done.map(e=>e.toJSON()),undone:e.undone.map(e=>e.toJSON())}},fromJSON(e){return new M(e.done.map(O.fromJSON),e.undone.map(O.fromJSON))}});function pe(e={}){return[fe,w.of(e),f.domEventHandlers({beforeinput(e,t){let n=e.inputType==`historyUndo`?E:e.inputType==`historyRedo`?D:null;return n?(e.preventDefault(),n(t)):!1}})]}function T(e,t){return function({state:n,dispatch:r}){if(!t&&n.readOnly)return!1;let i=n.field(fe,!1);if(!i)return!1;let a=i.pop(e,n,t);return a?(r(a),!0):!1}}var E=T(0,!1),D=T(1,!1),me=T(0,!0),he=T(1,!0),O=class e{constructor(e,t,n,r,i){this.changes=e,this.effects=t,this.mapped=n,this.startSelection=r,this.selectionsAfter=i}setSelAfter(t){return new e(this.changes,this.effects,this.mapped,this.startSelection,t)}toJSON(){return{changes:this.changes?.toJSON(),mapped:this.mapped?.toJSON(),startSelection:this.startSelection?.toJSON(),selectionsAfter:this.selectionsAfter.map(e=>e.toJSON())}}static fromJSON(t){return new e(t.changes&&p.fromJSON(t.changes),[],t.mapped&&ne.fromJSON(t.mapped),t.startSelection&&_.fromJSON(t.startSelection),t.selectionsAfter.map(_.fromJSON))}static fromTransaction(t,n){let r=A;for(let e of t.startState.facet(de)){let n=e(t);n.length&&(r=r.concat(n))}return!r.length&&t.changes.empty?null:new e(t.changes.invert(t.startState.doc),r,void 0,n||t.startState.selection,A)}static selection(t){return new e(void 0,A,void 0,void 0,t)}};function k(e,t,n,r){let i=t+1>n+20?t-n-1:0,a=e.slice(i,t);return a.push(r),a}function ge(e,t){let n=[],r=!1;return e.iterChangedRanges((e,t)=>n.push(e,t)),t.iterChangedRanges((e,t,i,a)=>{for(let e=0;e<n.length;){let t=n[e++],o=n[e++];a>=t&&i<=o&&(r=!0)}}),r}function _e(e,t){return e.ranges.length==t.ranges.length&&e.ranges.filter((e,n)=>e.empty!=t.ranges[n].empty).length===0}function ve(e,t){return e.length?t.length?e.concat(t):e:t}var A=[],ye=200;function be(e,t){if(e.length){let n=e[e.length-1],r=n.selectionsAfter.slice(Math.max(0,n.selectionsAfter.length-ye));return r.length&&r[r.length-1].eq(t)?e:(r.push(t),k(e,e.length-1,1e9,n.setSelAfter(r)))}return[O.selection([t])]}function xe(e){let t=e[e.length-1],n=e.slice();return n[e.length-1]=t.setSelAfter(t.selectionsAfter.slice(0,t.selectionsAfter.length-1)),n}function j(e,t){if(!e.length)return e;let n=e.length,r=A;for(;n;){let i=Se(e[n-1],t,r);if(i.changes&&!i.changes.empty||i.effects.length){let t=e.slice(0,n);return t[n-1]=i,t}t=i.mapped,n--,r=i.selectionsAfter}return r.length?[O.selection(r)]:A}function Se(e,t,n){let r=ve(e.selectionsAfter.length?e.selectionsAfter.map(e=>e.map(t)):A,n);if(!e.changes)return O.selection(r);let i=e.changes.map(t),a=t.mapDesc(e.changes,!0),o=e.mapped?e.mapped.composeDesc(a):a;return new O(i,l.mapEffects(e.effects,t),o,e.startSelection.map(a),r)}var Ce=/^(input\.type|delete)($|\.)/,M=class e{constructor(e,t,n=0,r=void 0){this.done=e,this.undone=t,this.prevTime=n,this.prevUserEvent=r}isolate(){return this.prevTime?new e(this.done,this.undone):this}addChanges(t,n,r,i,a){let o=this.done,s=o[o.length-1];return o=s&&s.changes&&!s.changes.empty&&t.changes&&(!r||Ce.test(r))&&(!s.selectionsAfter.length&&n-this.prevTime<i.newGroupDelay&&i.joinToEvent(a,ge(s.changes,t.changes))||r==`input.type.compose`)?k(o,o.length-1,i.minDepth,new O(t.changes.compose(s.changes),ve(l.mapEffects(t.effects,s.changes),s.effects),s.mapped,s.startSelection,A)):k(o,o.length,i.minDepth,t),new e(o,A,n,r)}addSelection(t,n,r,i){let a=this.done.length?this.done[this.done.length-1].selectionsAfter:A;return a.length>0&&n-this.prevTime<i&&r==this.prevUserEvent&&r&&/^select($|\.)/.test(r)&&_e(a[a.length-1],t)?this:new e(be(this.done,t),this.undone,n,r)}addMapping(t){return new e(j(this.done,t),j(this.undone,t),this.prevTime,this.prevUserEvent)}pop(e,t,n){let r=e==0?this.done:this.undone;if(r.length==0)return null;let i=r[r.length-1],a=i.selectionsAfter[0]||(i.startSelection?i.startSelection.map(i.changes.invertedDesc,1):t.selection);if(n&&i.selectionsAfter.length)return t.update({selection:i.selectionsAfter[i.selectionsAfter.length-1],annotations:C.of({side:e,rest:xe(r),selection:a}),userEvent:e==0?`select.undo`:`select.redo`,scrollIntoView:!0});if(i.changes){let n=r.length==1?A:r.slice(0,r.length-1);return i.mapped&&(n=j(n,i.mapped)),t.update({changes:i.changes,selection:i.startSelection,effects:i.effects,annotations:C.of({side:e,rest:n,selection:a}),filter:!1,userEvent:e==0?`undo`:`redo`,scrollIntoView:!0})}return null}};M.empty=new M(A,A);var we=[{key:`Mod-z`,run:E,preventDefault:!0},{key:`Mod-y`,mac:`Mod-Shift-z`,run:D,preventDefault:!0},{linux:`Ctrl-Shift-z`,run:D,preventDefault:!0},{key:`Mod-u`,run:me,preventDefault:!0},{key:`Alt-u`,mac:`Mod-Shift-u`,run:he,preventDefault:!0}];function N(e,t){return _.create(e.ranges.map(t),e.mainIndex)}function P(e,t){return e.update({selection:t,scrollIntoView:!0,userEvent:`select`})}function F({state:e,dispatch:t},n){let r=N(e.selection,n);return!r.eq(e.selection,!0)&&(t(P(e,r)),!0)}function I(e,t){return _.cursor(t?e.to:e.from)}function L(e,t){return F(e,n=>n.empty?e.moveByChar(n,t):I(n,t))}function R(e){return e.textDirectionAt(e.state.selection.main.head)==n.LTR}var z=e=>L(e,!R(e)),B=e=>L(e,R(e)),Te=e=>L(e,!1);function Ee(e,t){return F(e,n=>n.empty?e.moveByGroup(n,t):I(n,t))}var De=e=>Ee(e,!R(e)),Oe=e=>Ee(e,R(e));typeof Intl<`u`&&Intl.Segmenter;function ke(e,t,n){if(t.type.prop(n))return!0;let r=t.to-t.from;return r&&(r>2||/[^\s,.;:]/.test(e.sliceDoc(t.from,t.to)))||t.firstChild}function V(e,t,n){let r=a(e).resolveInner(t.head),i=n?c.closedBy:c.openedBy;for(let a=t.head;;){let t=n?r.childAfter(a):r.childBefore(a);if(!t)break;ke(e,t,i)?r=t:a=n?t.to:t.from}let s=r.type.prop(i),l,u;return u=s&&(l=n?o(e,r.from,1):o(e,r.to,-1))&&l.matched?n?l.end.to:l.end.from:n?r.to:r.from,_.cursor(u,n?-1:1)}var Ae=e=>F(e,t=>V(e.state,t,!R(e))),je=e=>F(e,t=>V(e.state,t,R(e)));function Me(e,t){return F(e,n=>{if(!n.empty)return I(n,t);let r=e.moveVertically(n,t);return r.head==n.head?e.moveToLineBoundary(n,t):r})}var Ne=e=>Me(e,!1),H=e=>Me(e,!0);function Pe(e){let t=e.scrollDOM.clientHeight<e.scrollDOM.scrollHeight-2,n=0,r=0,i;if(t){for(let t of e.state.facet(f.scrollMargins)){let i=t(e);i?.top&&(n=Math.max(i?.top,n)),i?.bottom&&(r=Math.max(i?.bottom,r))}i=e.scrollDOM.clientHeight-n-r}else i=(e.dom.ownerDocument.defaultView||window).innerHeight;return{marginTop:n,marginBottom:r,selfScroll:t,height:Math.max(e.defaultLineHeight,i-5)}}function Fe(e,t){let n=Pe(e),{state:r}=e,i=N(r.selection,r=>r.empty?e.moveVertically(r,t,n.height):I(r,t));if(i.eq(r.selection))return!1;let a;if(n.selfScroll){let t=e.coordsAtPos(r.selection.main.head),o=e.scrollDOM.getBoundingClientRect(),s=o.top+n.marginTop,c=o.bottom-n.marginBottom;t&&t.top>s&&t.bottom<c&&(a=f.scrollIntoView(i.main.head,{y:`start`,yMargin:t.top-s}))}return e.dispatch(P(r,i),{effects:a}),!0}var Ie=e=>Fe(e,!1),U=e=>Fe(e,!0);function W(e,t,n){let r=e.lineBlockAt(t.head),i=e.moveToLineBoundary(t,n);if(i.head==t.head&&i.head!=(n?r.to:r.from)&&(i=e.moveToLineBoundary(t,n,!1)),!n&&i.head==r.from&&r.length){let n=/^\s*/.exec(e.state.sliceDoc(r.from,Math.min(r.from+100,r.to)))[0].length;n&&t.head!=r.from+n&&(i=_.cursor(r.from+n))}return i}var Le=e=>F(e,t=>W(e,t,!0)),Re=e=>F(e,t=>W(e,t,!1)),ze=e=>F(e,t=>W(e,t,!R(e))),Be=e=>F(e,t=>W(e,t,R(e))),Ve=e=>F(e,t=>_.cursor(e.lineBlockAt(t.head).from,1)),He=e=>F(e,t=>_.cursor(e.lineBlockAt(t.head).to,-1));function Ue(e,t,n){let r=!1,i=N(e.selection,t=>{let i=o(e,t.head,-1)||o(e,t.head,1)||t.head>0&&o(e,t.head-1,1)||t.head<e.doc.length&&o(e,t.head+1,-1);if(!i||!i.end)return t;r=!0;let a=i.start.from==t.head?i.end.to:i.end.from;return n?_.range(t.anchor,a):_.cursor(a)});return r?(t(P(e,i)),!0):!1}var We=({state:e,dispatch:t})=>Ue(e,t,!1);function G(e,t,n){let r=N(e.state.selection,e=>{e.undirectional&&e.head>=e.anchor!=t&&(e=_.range(e.head,e.anchor));let r=n(e);return _.range(e.anchor,r.head,r.goalColumn,r.bidiLevel||void 0,r.assoc)});return!r.eq(e.state.selection)&&(e.dispatch(P(e.state,r)),!0)}function Ge(e,t){return G(e,t,n=>e.moveByChar(n,t))}var Ke=e=>Ge(e,!R(e)),qe=e=>Ge(e,R(e));function Je(e,t){return G(e,t,n=>e.moveByGroup(n,t))}var Ye=e=>Je(e,!R(e)),Xe=e=>Je(e,R(e)),Ze=e=>{let t=!R(e);return G(e,t,n=>V(e.state,n,t))},Qe=e=>{let t=R(e);return G(e,t,n=>V(e.state,n,t))};function $e(e,t){return G(e,t,n=>e.moveVertically(n,t))}var et=e=>$e(e,!1),tt=e=>$e(e,!0);function nt(e,t){return G(e,t,n=>e.moveVertically(n,t,Pe(e).height))}var rt=e=>nt(e,!1),it=e=>nt(e,!0),at=e=>G(e,!0,t=>W(e,t,!0)),ot=e=>G(e,!1,t=>W(e,t,!1)),st=e=>{let t=!R(e);return G(e,t,n=>W(e,n,t))},ct=e=>{let t=R(e);return G(e,t,n=>W(e,n,t))},lt=e=>G(e,!1,t=>_.cursor(e.lineBlockAt(t.head).from)),ut=e=>G(e,!0,t=>_.cursor(e.lineBlockAt(t.head).to)),dt=({state:e,dispatch:t})=>(t(P(e,{anchor:0})),!0),ft=({state:e,dispatch:t})=>(t(P(e,{anchor:e.doc.length})),!0),pt=({state:e,dispatch:t})=>(t(P(e,{anchor:e.selection.main.anchor,head:0})),!0),mt=({state:e,dispatch:t})=>(t(P(e,{anchor:e.selection.main.anchor,head:e.doc.length})),!0),ht=({state:e,dispatch:t})=>(t(e.update({selection:{anchor:0,head:e.doc.length},userEvent:`select`})),!0),gt=({state:e,dispatch:t})=>{let n=Y(e).map(({from:t,to:n})=>_.undirectionalRange(t,Math.min(n+1,e.doc.length)));return t(e.update({selection:_.create(n),userEvent:`select`})),!0},_t=({state:e,dispatch:t})=>{let n=N(e.selection,t=>{let n=a(e),r=n.resolveStack(t.from,1);if(t.empty){let e=n.resolveStack(t.from,-1);e.node.from>=r.node.from&&e.node.to<=r.node.to&&(r=e)}for(let e=r;e;e=e.next){let{node:n}=e;if((n.from<t.from&&n.to>=t.to||n.to>t.to&&n.from<=t.from)&&e.next)return _.undirectionalRange(n.from,n.to)}return t});return!n.eq(e.selection)&&(t(P(e,n)),!0)};function vt(e,t){let{state:n}=e,r=n.selection,i=n.selection.ranges.slice();for(let r of n.selection.ranges){let a=n.doc.lineAt(r.head);if(t?a.to<e.state.doc.length:a.from>0)for(let n=r;;){let r=e.moveVertically(n,t);if(r.head<a.from||r.head>a.to){i.some(e=>e.head==r.head)||i.push(r);break}if(r.head==n.head)break;n=r}}return i.length!=r.ranges.length&&(e.dispatch(P(n,_.create(i,i.length-1))),!0)}var yt=e=>vt(e,!1),bt=e=>vt(e,!0),xt=({state:e,dispatch:t})=>{let n=e.selection,r=null;return n.ranges.length>1?r=_.create([n.main]):n.main.empty||(r=_.create([_.cursor(n.main.head)])),r?(t(P(e,r)),!0):!1};function K(e,t){if(e.state.readOnly)return!1;let n=`delete.selection`,{state:r}=e,i=r.changeByRange(r=>{let{from:i,to:a}=r;if(i==a){let o=t(r);o<i?(n=`delete.backward`,o=q(e,o,!1)):o>i&&(n=`delete.forward`,o=q(e,o,!0)),i=Math.min(i,o),a=Math.max(a,o)}else i=q(e,i,!1),a=q(e,a,!0);return i==a?{range:r}:{changes:{from:i,to:a},range:_.cursor(i,i<r.head?-1:1)}});return!i.changes.empty&&(e.dispatch(r.update(i,{scrollIntoView:!0,userEvent:n,effects:n==`delete.selection`?f.announce.of(r.phrase(`Selection deleted`)):void 0})),!0)}function q(e,t,n){if(e instanceof f)for(let r of e.state.facet(f.atomicRanges).map(t=>t(e)))r.between(t,t,(e,r)=>{e<t&&r>t&&(t=n?r:e)});return t}var St=(e,n,r)=>K(e,i=>{let a=i.from,{state:o}=e,s=o.doc.lineAt(a),c,l;if(r&&!n&&a>s.from&&a<s.from+200&&!/[^ \t]/.test(c=s.text.slice(0,a-s.from))){if(c[c.length-1]==` `)return a-1;let e=g(c,o.tabSize)%u(o)||u(o);for(let t=0;t<e&&c[c.length-1-t]==` `;t++)a--;l=a}else l=t(s.text,a-s.from,n,n)+s.from,l==a&&s.number!=(n?o.doc.lines:1)?l+=n?1:-1:!n&&/[\ufe00-\ufe0f]/.test(s.text.slice(l-s.from,a-s.from))&&(l=t(s.text,l-s.from,!1,!1)+s.from);return l}),J=e=>St(e,!1,!0),Ct=e=>St(e,!0,!1),wt=(e,n)=>K(e,r=>{let i=r.head,{state:a}=e,o=a.doc.lineAt(i),s=a.charCategorizer(i);for(let e=null;;){if(i==(n?o.to:o.from)){i==r.head&&o.number!=(n?a.doc.lines:1)&&(i+=n?1:-1);break}let c=t(o.text,i-o.from,n)+o.from,l=o.text.slice(Math.min(i,c)-o.from,Math.max(i,c)-o.from),u=s(l);if(e!=null&&u!=e)break;(l!=` `||i!=r.head)&&(e=u),i=c}return i}),Tt=e=>wt(e,!1),Et=e=>wt(e,!0),Dt=e=>K(e,t=>{let n=e.lineBlockAt(t.head).to;return t.head<n?n:Math.min(e.state.doc.length,t.head+1)}),Ot=e=>K(e,t=>{let n=e.moveToLineBoundary(t,!1).head;return t.head>n?n:Math.max(0,t.head-1)}),kt=e=>K(e,t=>{let n=e.moveToLineBoundary(t,!0).head;return t.head<n?n:Math.min(e.state.doc.length,t.head+1)}),At=({state:e,dispatch:t})=>{if(e.readOnly)return!1;let n=e.changeByRange(e=>({changes:{from:e.from,to:e.to,insert:v.of([``,``])},range:_.cursor(e.from)}));return t(e.update(n,{scrollIntoView:!0,userEvent:`input`})),!0},jt=({state:e,dispatch:n})=>{if(e.readOnly)return!1;let r=e.changeByRange(n=>{if(!n.empty||n.from==0||n.from==e.doc.length)return{range:n};let r=n.from,i=e.doc.lineAt(r),a=r==i.from?r-1:t(i.text,r-i.from,!1)+i.from,o=r==i.to?r+1:t(i.text,r-i.from,!0)+i.from;return{changes:{from:a,to:o,insert:e.doc.slice(r,o).append(e.doc.slice(a,r))},range:_.cursor(o)}});return!r.changes.empty&&(n(e.update(r,{scrollIntoView:!0,userEvent:`move.character`})),!0)};function Y(e){let t=[],n=-1;for(let r of e.selection.ranges){let i=e.doc.lineAt(r.from),a=e.doc.lineAt(r.to);if(!r.empty&&r.to==a.from&&(a=e.doc.lineAt(r.to-1)),n>=i.number){let e=t[t.length-1];e.to=a.to,e.ranges.push(r)}else t.push({from:i.from,to:a.to,ranges:[r]});n=a.number+1}return t}function Mt(e,t,n){if(e.readOnly)return!1;let r=[],i=[];for(let t of Y(e)){if(n?t.to==e.doc.length:t.from==0)continue;let a=e.doc.lineAt(n?t.to+1:t.from-1),o=a.length+1;if(n){r.push({from:t.to,to:a.to},{from:t.from,insert:a.text+e.lineBreak});for(let n of t.ranges)i.push(_.range(Math.min(e.doc.length,n.anchor+o),Math.min(e.doc.length,n.head+o)))}else{r.push({from:a.from,to:t.from},{from:t.to,insert:e.lineBreak+a.text});for(let e of t.ranges)i.push(_.range(e.anchor-o,e.head-o))}}return r.length?(t(e.update({changes:r,scrollIntoView:!0,selection:_.create(i,e.selection.mainIndex),userEvent:`move.line`})),!0):!1}var Nt=({state:e,dispatch:t})=>Mt(e,t,!1),Pt=({state:e,dispatch:t})=>Mt(e,t,!0);function Ft(e,t,n){if(e.readOnly)return!1;let r=[];for(let t of Y(e))n?r.push({from:t.from,insert:e.doc.slice(t.from,t.to)+e.lineBreak}):r.push({from:t.to,insert:e.lineBreak+e.doc.slice(t.from,t.to)});let i=e.changes(r);return t(e.update({changes:i,selection:e.selection.map(i,n?1:-1),scrollIntoView:!0,userEvent:`input.copyline`})),!0}var It=({state:e,dispatch:t})=>Ft(e,t,!1),Lt=({state:e,dispatch:t})=>Ft(e,t,!0),Rt=e=>{if(e.state.readOnly)return!1;let{state:t}=e,n=t.changes(Y(t).map(({from:e,to:n})=>(e>0?e--:n<t.doc.length&&n++,{from:e,to:n}))),r=N(t.selection,t=>{let n;if(e.lineWrapping){let r=e.lineBlockAt(t.head),i=e.coordsAtPos(t.head,t.assoc||1);i&&(n=r.bottom+e.documentTop-i.bottom+e.defaultLineHeight/2)}return e.moveVertically(t,!0,n)}).map(n);return e.dispatch({changes:n,selection:r,scrollIntoView:!0,userEvent:`delete.line`}),!0};function zt(e,t){if(/\(\)|\[\]|\{\}/.test(e.sliceDoc(t-1,t+1)))return{from:t,to:t};let n=a(e).resolveInner(t),r=n.childBefore(t),i=n.childAfter(t),o;return r&&i&&r.to<=t&&i.from>=t&&(o=r.type.prop(c.closedBy))&&o.indexOf(i.name)>-1&&e.doc.lineAt(r.to).from==e.doc.lineAt(i.from).from&&!/\S/.test(e.sliceDoc(r.to,i.from))?{from:r.to,to:i.from}:null}var X=Vt(!1),Bt=Vt(!0);function Vt(e){return({state:t,dispatch:n})=>{if(t.readOnly)return!1;let r=t.changeByRange(n=>{let{from:r,to:a}=n,o=t.doc.lineAt(r),s=!e&&r==a&&zt(t,r);e&&(r=a=(a<=o.to?o:t.doc.lineAt(a)).to);let c=new te(t,{simulateBreak:r,simulateDoubleBreak:!!s}),l=i(c,r);for(l??=g(/^\s*/.exec(t.doc.lineAt(r).text)[0],t.tabSize);a<o.to&&/\s/.test(o.text[a-o.from]);)a++;s?{from:r,to:a}=s:r>o.from&&r<o.from+100&&!/\S/.test(o.text.slice(0,r))&&(r=o.from);let u=[``,h(t,l)];return s&&u.push(h(t,c.lineIndent(o.from,-1))),{changes:{from:r,to:a,insert:v.of(u)},range:_.cursor(r+1+u[1].length)}});return n(t.update(r,{scrollIntoView:!0,userEvent:`input`})),!0}}function Z(e,t){let n=-1;return e.changeByRange(r=>{let i=[];for(let a=r.from;a<=r.to;){let o=e.doc.lineAt(a);o.number>n&&(r.empty||r.to>o.from)&&(t(o,i,r),n=o.number),a=o.to+1}let a=e.changes(i);return{changes:i,range:_.range(a.mapPos(r.anchor,1),a.mapPos(r.head,1))}})}var Ht=({state:e,dispatch:t})=>{if(e.readOnly)return!1;let n=Object.create(null),r=new te(e,{overrideIndentation:e=>n[e]??-1}),a=Z(e,(t,a,o)=>{let s=i(r,t.from);if(s==null)return;/\S/.test(t.text)||(s=0);let c=/^\s*/.exec(t.text)[0],l=h(e,s);(c!=l||o.from<t.from+c.length)&&(n[t.from]=s,a.push({from:t.from,to:t.from+c.length,insert:l}))});return a.changes.empty||t(e.update(a,{userEvent:`indent`})),!0},Q=({state:t,dispatch:n})=>!t.readOnly&&(n(t.update(Z(t,(n,r)=>{r.push({from:n.from,insert:t.facet(e)})}),{userEvent:`input.indent`})),!0),$=({state:e,dispatch:t})=>!e.readOnly&&(t(e.update(Z(e,(t,n)=>{let r=/^\s*/.exec(t.text)[0];if(!r)return;let i=g(r,e.tabSize),a=0,o=h(e,Math.max(0,i-u(e)));for(;a<r.length&&a<o.length&&r.charCodeAt(a)==o.charCodeAt(a);)a++;n.push({from:t.from+a,to:t.from+r.length,insert:o.slice(a)})}),{userEvent:`delete.dedent`})),!0),Ut=e=>(e.setTabFocusMode(),!0),Wt=[{key:`Ctrl-b`,run:z,shift:Ke,preventDefault:!0},{key:`Ctrl-f`,run:B,shift:qe},{key:`Ctrl-p`,run:Ne,shift:et},{key:`Ctrl-n`,run:H,shift:tt},{key:`Ctrl-a`,run:Ve,shift:lt},{key:`Ctrl-e`,run:He,shift:ut},{key:`Ctrl-d`,run:Ct},{key:`Ctrl-h`,run:J},{key:`Ctrl-k`,run:Dt},{key:`Ctrl-Alt-h`,run:Tt},{key:`Ctrl-o`,run:At},{key:`Ctrl-t`,run:jt},{key:`Ctrl-v`,run:U}],Gt=[{key:`ArrowLeft`,run:z,shift:Ke,preventDefault:!0},{key:`Mod-ArrowLeft`,mac:`Alt-ArrowLeft`,run:De,shift:Ye,preventDefault:!0},{mac:`Cmd-ArrowLeft`,run:ze,shift:st,preventDefault:!0},{key:`ArrowRight`,run:B,shift:qe,preventDefault:!0},{key:`Mod-ArrowRight`,mac:`Alt-ArrowRight`,run:Oe,shift:Xe,preventDefault:!0},{mac:`Cmd-ArrowRight`,run:Be,shift:ct,preventDefault:!0},{key:`ArrowUp`,run:Ne,shift:et,preventDefault:!0},{mac:`Cmd-ArrowUp`,run:dt,shift:pt},{mac:`Ctrl-ArrowUp`,run:Ie,shift:rt},{key:`ArrowDown`,run:H,shift:tt,preventDefault:!0},{mac:`Cmd-ArrowDown`,run:ft,shift:mt},{mac:`Ctrl-ArrowDown`,run:U,shift:it},{key:`PageUp`,run:Ie,shift:rt},{key:`PageDown`,run:U,shift:it},{key:`Home`,run:Re,shift:ot,preventDefault:!0},{key:`Mod-Home`,run:dt,shift:pt},{key:`End`,run:Le,shift:at,preventDefault:!0},{key:`Mod-End`,run:ft,shift:mt},{key:`Enter`,run:X,shift:X},{key:`Mod-a`,run:ht},{key:`Backspace`,run:J,shift:J,preventDefault:!0},{key:`Delete`,run:Ct,preventDefault:!0},{key:`Mod-Backspace`,mac:`Alt-Backspace`,run:Tt,preventDefault:!0},{key:`Mod-Delete`,mac:`Alt-Delete`,run:Et,preventDefault:!0},{mac:`Mod-Backspace`,run:Ot,preventDefault:!0},{mac:`Mod-Delete`,run:kt,preventDefault:!0}].concat(Wt.map(e=>({mac:e.key,run:e.run,shift:e.shift}))),Kt=[{key:`Alt-ArrowLeft`,mac:`Ctrl-ArrowLeft`,run:Ae,shift:Ze},{key:`Alt-ArrowRight`,mac:`Ctrl-ArrowRight`,run:je,shift:Qe},{key:`Alt-ArrowUp`,run:Nt},{key:`Shift-Alt-ArrowUp`,run:It},{key:`Alt-ArrowDown`,run:Pt},{key:`Shift-Alt-ArrowDown`,run:Lt},{key:`Mod-Alt-ArrowUp`,run:yt},{key:`Mod-Alt-ArrowDown`,run:bt},{key:`Escape`,run:xt},{key:`Mod-Enter`,run:Bt},{key:`Alt-l`,mac:`Ctrl-l`,run:gt},{key:`Mod-i`,run:_t,preventDefault:!0},{key:`Mod-[`,run:$},{key:`Mod-]`,run:Q},{key:`Mod-Alt-\\`,run:Ht},{key:`Shift-Mod-k`,run:Rt},{key:`Shift-Mod-\\`,run:We},{key:`Mod-/`,run:re},{key:`Alt-A`,mac:`Ctrl-A`,run:ae},{key:`Ctrl-m`,mac:`Shift-Alt-m`,run:Ut}].concat(Gt),qt={key:`Tab`,run:Q,shift:$};export{Kt as a,$ as c,qt as d,X as f,E as h,Le as i,Q as l,ie as m,z as n,pe as o,D as p,Re as r,we as s,Te as t,Ht as u};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{a as e}from"./dist-Cu5Ze2cs.js";export{e as markdown};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./dist-jVKfryIL.js";export{e as css};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./dist-W0FoeIxk.js";export{e as javascript};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{t as e}from"./dist-zHDLm1oE.js";export{e as yaml};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{n as e}from"./dist-B_1hMrc6.js";export{e as html};
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
import{i as e,y as t}from"./chunk-4SOEAONT-C3fufoVl.js";import"./chunk-SRAX5OIU-KFQikY-4.js";export{t as decodePngMetadata,e as encodePngMetadata};
|