dsh-plugin-workbench 0.0.4 → 0.0.5

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/lib/client.js CHANGED
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
30
30
  let react = require("react");
31
31
  let react_jsx_runtime = require("react/jsx-runtime");
32
32
  //#region \0dsh-css:src/client/files.module.css.mjs
33
- const css$1 = "[data-fe-theme=light]{--fe-bg:#fff;--fe-sidebar-bg:#f3f3f3;--fe-fg:#1f1f1f;--fe-muted:#6e6e6e;--fe-faint:#9d9d9d;--fe-border:#e5e5e5;--fe-border-strong:#c8c8c8;--fe-accent:#005fb8;--fe-hover:#e8e8e8;--fe-selection:#add6ff;--fe-token-keyword:#00f;--fe-token-string:#a31515;--fe-token-comment:green;--fe-token-number:#098658;--fe-token-function:#795e26;--fe-token-type:#267f99;--fe-token-variable:#001080;--fe-token-tag:maroon;--fe-token-meta:#6e6e6e}[data-fe-theme=dark]{--fe-bg:#1e1e1e;--fe-sidebar-bg:#252526;--fe-fg:#d4d4d4;--fe-muted:#ccc;--fe-faint:#9d9d9d;--fe-border:#3c3c3c;--fe-border-strong:#454545;--fe-accent:#007acc;--fe-hover:#2a2d2e;--fe-selection:#264f78;--fe-token-keyword:#569cd6;--fe-token-string:#ce9178;--fe-token-comment:#6a9955;--fe-token-number:#b5cea8;--fe-token-function:#dcdcaa;--fe-token-type:#4ec9b0;--fe-token-variable:#9cdcfe;--fe-token-tag:#569cd6;--fe-token-meta:#9b9b9b}.Myjg4a_column{box-sizing:border-box;background:var(--fe-sidebar-bg);min-width:0;height:100%;color:var(--fe-fg);flex-direction:column;font-size:13px;display:flex;overflow:hidden}.Myjg4a_header{box-sizing:border-box;border-bottom:1px solid var(--fe-border);flex:none;align-items:center;gap:6px;height:34px;padding:0 8px;display:flex}.Myjg4a_headerTitle{text-overflow:ellipsis;white-space:nowrap;text-transform:uppercase;letter-spacing:.04em;min-width:0;color:var(--fe-muted);flex:1;font-size:11px;font-weight:600;overflow:hidden}.Myjg4a_headerActions{flex:none;align-items:center;gap:2px;display:flex}.Myjg4a_action{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:5px;justify-content:center;align-items:center;width:22px;height:22px;padding:0;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_action:hover:not(:disabled){background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_action:disabled{opacity:.5;cursor:default}.Myjg4a_treeArea{flex:1;min-height:0;padding:4px;overflow-y:auto}.Myjg4a_row{cursor:pointer;user-select:none;white-space:nowrap;height:22px;color:var(--fe-fg);border-radius:3px;align-items:center;gap:6px;font-size:13px;display:flex}.Myjg4a_row:hover{background:var(--fe-hover)}.Myjg4a_rowSelected{background:var(--fe-selection)}.Myjg4a_rowSelected .Myjg4a_name{color:var(--fe-fg)}.Myjg4a_chevron{text-align:center;width:12px;color:var(--fe-muted);flex:none;font-size:10px;line-height:22px}.Myjg4a_icon{text-align:center;flex:none;width:16px;font-size:13px;line-height:22px}.Myjg4a_fileBadge{letter-spacing:-.3px;box-sizing:border-box;vertical-align:middle;user-select:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:15px;padding:0 1px;font-size:8px;font-weight:700;line-height:1;display:inline-flex}.Myjg4a_fileBadgeLong{letter-spacing:-.4px;font-size:6.5px}.Myjg4a_name{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_size{color:var(--fe-faint);flex:none;font-size:11px}.Myjg4a_actions{opacity:0;flex:none;align-items:center;gap:2px;transition:opacity .12s;display:flex}.Myjg4a_row:hover .Myjg4a_actions,.Myjg4a_row:focus-within .Myjg4a_actions{opacity:1}.Myjg4a_rowHint{color:var(--fe-faint);padding:2px 8px 2px 0;font-size:12px;line-height:20px}.Myjg4a_rowError{color:#f48771;padding:2px 8px 2px 0;font-size:12px;line-height:18px}.Myjg4a_preview{border-right:1px solid var(--fe-border);background:var(--fe-bg);flex-direction:column;flex:0 0 55%;min-width:240px;min-height:0;animation:.18s Myjg4a_fe-preview-in;display:flex;overflow:hidden}.Myjg4a_previewClosing{animation:.2s forwards Myjg4a_fe-preview-out}@keyframes Myjg4a_fe-preview-in{0%{opacity:0}to{opacity:1}}@keyframes Myjg4a_fe-preview-out{0%{opacity:1}to{opacity:0}}.Myjg4a_handle{cursor:col-resize;touch-action:none;z-index:2;background:0 0;flex:none;width:6px;margin-left:-4px;margin-right:-2px}.Myjg4a_handle:hover,.Myjg4a_handle:active{background:var(--fe-accent);opacity:.35}.Myjg4a_tabBar{border-bottom:1px solid var(--fe-border);background:var(--fe-sidebar-bg);flex:none;align-items:stretch;height:34px;display:flex}.Myjg4a_tabScroller{scrollbar-width:thin;flex:1;align-items:stretch;min-width:0;display:flex;overflow-x:auto}.Myjg4a_collapse,.Myjg4a_tabAction{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;margin:auto 4px;padding:0;font-size:14px;line-height:1;display:inline-flex}.Myjg4a_collapse:hover,.Myjg4a_tabAction:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabActionActive{background:var(--fe-hover);color:var(--fe-accent)}.Myjg4a_tab{max-width:180px;color:var(--fe-muted);border-right:1px solid var(--fe-border);cursor:pointer;user-select:none;white-space:nowrap;flex:none;align-items:center;gap:6px;padding:0 8px 0 12px;font-size:13px;display:flex}.Myjg4a_tab:hover{background:var(--fe-hover)}.Myjg4a_tabActive{background:var(--fe-bg);color:var(--fe-fg);box-shadow:inset 0 -1px 0 var(--fe-accent)}.Myjg4a_tabName{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_tabIcon{flex:none;justify-content:center;align-items:center;width:16px;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_tabClose{appearance:none;color:var(--fe-faint);cursor:pointer;background:0 0;border:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:11px;display:inline-flex}.Myjg4a_tabClose:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabDot{background:var(--fe-fg);opacity:.85;border-radius:50%;flex:none;width:8px;height:8px}.Myjg4a_previewBody{flex:1;min-height:0;overflow:auto}.Myjg4a_editor{contain:layout paint;height:100%;min-height:0;position:relative}.Myjg4a_editorPlain .Myjg4a_editorTextarea{color:var(--fe-fg)}.Myjg4a_editorHint{background:var(--fe-hover);color:var(--fe-muted);pointer-events:none;border-radius:4px;padding:4px 10px;font-size:11px;position:absolute;bottom:8px;left:8px}.Myjg4a_editorHighlight{pointer-events:none;white-space:pre;tab-size:2;color:var(--fe-fg);background:0 0;margin:0;padding:12px 12px calc(12px + 1.5em);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;inset:0;overflow:auto}.Myjg4a_editorHighlight code{font-family:inherit;font-size:inherit;line-height:inherit;white-space:inherit}.Myjg4a_editorTextarea{box-sizing:border-box;resize:none;color:#0000;caret-color:var(--fe-fg);white-space:pre;tab-size:2;background:0 0;border:none;outline:none;margin:0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;inset:0;overflow:auto}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorHighlight,.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{white-space:pre-wrap;overflow-wrap:anywhere}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{overflow-x:hidden}.Myjg4a_saveError{color:#1e1e1e;background:#f48771;border-radius:4px;padding:4px 10px;font-size:12px;position:absolute;bottom:8px;right:8px}.Myjg4a_previewHint{color:var(--fe-faint);padding:12px;font-size:12px;line-height:18px}.Myjg4a_previewMeta{color:var(--fe-faint);font-size:11px}.Myjg4a_placeholder{text-align:center;color:var(--fe-faint);flex:1;justify-content:center;align-items:center;padding:16px;font-size:12px;line-height:18px;display:flex}.Myjg4a_editorHighlight .hljs-keyword,.Myjg4a_editorHighlight .hljs-selector-tag,.Myjg4a_editorHighlight .hljs-literal{color:var(--fe-token-keyword)}.Myjg4a_editorHighlight .hljs-string,.Myjg4a_editorHighlight .hljs-regexp,.Myjg4a_editorHighlight .hljs-addition{color:var(--fe-token-string)}.Myjg4a_editorHighlight .hljs-comment,.Myjg4a_editorHighlight .hljs-quote{color:var(--fe-token-comment);font-style:italic}.Myjg4a_editorHighlight .hljs-number,.Myjg4a_editorHighlight .hljs-symbol,.Myjg4a_editorHighlight .hljs-bullet{color:var(--fe-token-number)}.Myjg4a_editorHighlight .hljs-title,.Myjg4a_editorHighlight .hljs-section,.Myjg4a_editorHighlight .hljs-title.function_{color:var(--fe-token-function)}.Myjg4a_editorHighlight .hljs-type,.Myjg4a_editorHighlight .hljs-built_in,.Myjg4a_editorHighlight .hljs-class .hljs-title{color:var(--fe-token-type)}.Myjg4a_editorHighlight .hljs-attr,.Myjg4a_editorHighlight .hljs-attribute,.Myjg4a_editorHighlight .hljs-variable,.Myjg4a_editorHighlight .hljs-template-variable,.Myjg4a_editorHighlight .hljs-params{color:var(--fe-token-variable)}.Myjg4a_editorHighlight .hljs-tag,.Myjg4a_editorHighlight .hljs-name{color:var(--fe-token-tag)}.Myjg4a_editorHighlight .hljs-meta{color:var(--fe-token-meta)}.Myjg4a_editorHighlight .hljs-emphasis{font-style:italic}.Myjg4a_editorHighlight .hljs-strong{color:var(--fe-accent);font-weight:inherit}body[data-dsh-maid-atelier] [data-skin-chrome=top-trim],body[data-dsh-maid-atelier] [data-skin-chrome=bottom-trim]{translate:calc(var(--maid-sidebar-width,0px) + var(--dsh-explorer-width,0px) + var(--dsh-preview-width,0px)) 0!important}[class*=explorerCol]{border-right:1px solid var(--fe-border)!important}";
33
+ const css$1 = "[data-fe-theme=light]{--fe-bg:#fff;--fe-sidebar-bg:#f3f3f3;--fe-fg:#1f1f1f;--fe-muted:#6e6e6e;--fe-faint:#9d9d9d;--fe-border:#e5e5e5;--fe-border-strong:#c8c8c8;--fe-accent:#005fb8;--fe-hover:#e8e8e8;--fe-selection:#add6ff;--fe-token-keyword:#00f;--fe-token-string:#a31515;--fe-token-comment:green;--fe-token-number:#098658;--fe-token-function:#795e26;--fe-token-type:#267f99;--fe-token-variable:#001080;--fe-token-tag:maroon;--fe-token-meta:#6e6e6e}[data-fe-theme=dark]{--fe-bg:#1e1e1e;--fe-sidebar-bg:#252526;--fe-fg:#d4d4d4;--fe-muted:#ccc;--fe-faint:#9d9d9d;--fe-border:#3c3c3c;--fe-border-strong:#454545;--fe-accent:#007acc;--fe-hover:#2a2d2e;--fe-selection:#264f78;--fe-token-keyword:#569cd6;--fe-token-string:#ce9178;--fe-token-comment:#6a9955;--fe-token-number:#b5cea8;--fe-token-function:#dcdcaa;--fe-token-type:#4ec9b0;--fe-token-variable:#9cdcfe;--fe-token-tag:#569cd6;--fe-token-meta:#9b9b9b}.Myjg4a_column{box-sizing:border-box;background:var(--fe-sidebar-bg);min-width:0;height:100%;color:var(--fe-fg);flex-direction:column;font-size:13px;display:flex;overflow:hidden}.Myjg4a_header{box-sizing:border-box;border-bottom:1px solid var(--fe-border);flex:none;align-items:center;gap:6px;height:34px;padding:0 8px;display:flex}.Myjg4a_headerTitle{text-overflow:ellipsis;white-space:nowrap;text-transform:uppercase;letter-spacing:.04em;min-width:0;color:var(--fe-muted);flex:1;font-size:11px;font-weight:600;overflow:hidden}.Myjg4a_headerActions{flex:none;align-items:center;gap:2px;display:flex}.Myjg4a_action{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:5px;justify-content:center;align-items:center;width:22px;height:22px;padding:0;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_action:hover:not(:disabled){background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_action:disabled{opacity:.5;cursor:default}.Myjg4a_treeArea{flex:1;min-height:0;padding:4px;overflow-y:auto}.Myjg4a_row{cursor:pointer;user-select:none;white-space:nowrap;height:22px;color:var(--fe-fg);border-radius:3px;align-items:center;gap:6px;font-size:13px;display:flex}.Myjg4a_row:hover{background:var(--fe-hover)}.Myjg4a_rowSelected{background:var(--fe-selection)}.Myjg4a_rowSelected .Myjg4a_name{color:var(--fe-fg)}.Myjg4a_chevron{text-align:center;width:12px;color:var(--fe-muted);flex:none;font-size:10px;line-height:22px}.Myjg4a_icon{text-align:center;flex:none;width:16px;font-size:13px;line-height:22px}.Myjg4a_fileBadge{letter-spacing:-.3px;box-sizing:border-box;vertical-align:middle;user-select:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:15px;padding:0 1px;font-size:8px;font-weight:700;line-height:1;display:inline-flex}.Myjg4a_fileBadgeLong{letter-spacing:-.4px;font-size:6.5px}.Myjg4a_name{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_size{color:var(--fe-faint);flex:none;font-size:11px}.Myjg4a_actions{opacity:0;flex:none;align-items:center;gap:2px;transition:opacity .12s;display:flex}.Myjg4a_row:hover .Myjg4a_actions,.Myjg4a_row:focus-within .Myjg4a_actions{opacity:1}.Myjg4a_rowHint{color:var(--fe-faint);padding:2px 8px 2px 0;font-size:12px;line-height:20px}.Myjg4a_rowError{color:#f48771;padding:2px 8px 2px 0;font-size:12px;line-height:18px}.Myjg4a_contextMenu{z-index:10000;box-sizing:border-box;border:1px solid var(--fe-border-strong);user-select:none;border-radius:6px;min-width:180px;padding:4px;font-size:13px;position:fixed;box-shadow:0 6px 24px #00000047;background:var(--fe-bg)!important;color:var(--fe-fg)!important}.Myjg4a_contextMenuItem{cursor:pointer;white-space:nowrap;color:inherit;border-radius:4px;align-items:center;gap:8px;padding:5px 10px;display:flex}.Myjg4a_contextMenuItem:hover{background:var(--fe-selection)!important;color:var(--fe-fg)!important}.Myjg4a_contextMenuItemDanger{color:#f48771!important}.Myjg4a_contextMenuDivider{background:var(--fe-border);height:1px;margin:4px 6px}.Myjg4a_preview{border-right:1px solid var(--fe-border);background:var(--fe-bg);flex-direction:column;flex:0 0 55%;min-width:240px;min-height:0;animation:.18s Myjg4a_fe-preview-in;display:flex;overflow:hidden}.Myjg4a_previewClosing{animation:.2s forwards Myjg4a_fe-preview-out}@keyframes Myjg4a_fe-preview-in{0%{opacity:0}to{opacity:1}}@keyframes Myjg4a_fe-preview-out{0%{opacity:1}to{opacity:0}}.Myjg4a_handle{cursor:col-resize;touch-action:none;z-index:2;background:0 0;flex:none;width:6px;margin-left:-4px;margin-right:-2px}.Myjg4a_handle:hover,.Myjg4a_handle:active{background:var(--fe-accent);opacity:.35}.Myjg4a_tabBar{border-bottom:1px solid var(--fe-border);background:var(--fe-sidebar-bg);flex:none;align-items:stretch;height:34px;display:flex}.Myjg4a_tabScroller{scrollbar-width:thin;flex:1;align-items:stretch;min-width:0;display:flex;overflow-x:auto}.Myjg4a_collapse,.Myjg4a_tabAction{appearance:none;color:var(--fe-muted);cursor:pointer;background:0 0;border:none;border-radius:4px;flex:none;justify-content:center;align-items:center;width:26px;height:26px;margin:auto 4px;padding:0;font-size:14px;line-height:1;display:inline-flex}.Myjg4a_collapse:hover,.Myjg4a_tabAction:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabActionActive{background:var(--fe-hover);color:var(--fe-accent)}.Myjg4a_tab{max-width:180px;color:var(--fe-muted);border-right:1px solid var(--fe-border);cursor:pointer;user-select:none;white-space:nowrap;flex:none;align-items:center;gap:6px;padding:0 8px 0 12px;font-size:13px;display:flex}.Myjg4a_tab:hover{background:var(--fe-hover)}.Myjg4a_tabActive{background:var(--fe-bg);color:var(--fe-fg);box-shadow:inset 0 -1px 0 var(--fe-accent)}.Myjg4a_tabName{text-overflow:ellipsis;flex:1;min-width:0;overflow:hidden}.Myjg4a_tabIcon{flex:none;justify-content:center;align-items:center;width:16px;font-size:13px;line-height:1;display:inline-flex}.Myjg4a_tabClose{appearance:none;color:var(--fe-faint);cursor:pointer;background:0 0;border:none;border-radius:3px;justify-content:center;align-items:center;width:16px;height:16px;padding:0;font-size:11px;display:inline-flex}.Myjg4a_tabClose:hover{background:var(--fe-hover);color:var(--fe-fg)}.Myjg4a_tabDot{background:var(--fe-fg);opacity:.85;border-radius:50%;flex:none;width:8px;height:8px}.Myjg4a_previewBody{flex:1;min-height:0;overflow:auto}.Myjg4a_editor{--fe-gutter:44px;contain:layout paint;height:100%;min-height:0;position:relative}.Myjg4a_gutter{width:var(--fe-gutter);box-sizing:border-box;border-right:1px solid var(--fe-border);background:var(--fe-sidebar-bg);color:var(--fe-faint);user-select:none;pointer-events:none;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;top:0;bottom:0;left:0;overflow:hidden}.Myjg4a_gutterNumbers{white-space:pre;text-align:right;padding:12px 8px}.Myjg4a_editorPlain .Myjg4a_editorTextarea{color:var(--fe-fg)}.Myjg4a_editorHint{left:calc(var(--fe-gutter) + 8px);background:var(--fe-hover);color:var(--fe-muted);pointer-events:none;border-radius:4px;padding:4px 10px;font-size:11px;position:absolute;bottom:8px}.Myjg4a_editorHighlight{top:0;bottom:0;left:var(--fe-gutter);pointer-events:none;white-space:pre;tab-size:2;color:var(--fe-fg);background:0 0;margin:0;padding:12px 12px calc(12px + 1.5em);font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;right:0;overflow:auto}.Myjg4a_editorHighlight code{font-family:inherit;font-size:inherit;line-height:inherit;white-space:inherit}.Myjg4a_editorTextarea{top:0;bottom:0;left:var(--fe-gutter);box-sizing:border-box;resize:none;color:#0000;caret-color:var(--fe-fg);white-space:pre;tab-size:2;background:0 0;border:none;outline:none;margin:0;padding:12px;font-family:ui-monospace,SFMono-Regular,Menlo,Consolas,monospace;font-size:13px;line-height:1.5;position:absolute;right:0;overflow:auto}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorHighlight,.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{white-space:pre-wrap;overflow-wrap:anywhere}.Myjg4a_editor[data-wrap=on] .Myjg4a_editorTextarea{overflow-x:hidden}.Myjg4a_saveError{color:#1e1e1e;background:#f48771;border-radius:4px;padding:4px 10px;font-size:12px;position:absolute;bottom:8px;right:8px}.Myjg4a_previewHint{color:var(--fe-faint);padding:12px;font-size:12px;line-height:18px}.Myjg4a_imageView{box-sizing:border-box;background:var(--fe-bg);flex-direction:column;justify-content:center;align-items:center;gap:8px;height:100%;min-height:0;padding:12px;display:flex;overflow:auto}.Myjg4a_image{object-fit:contain;max-width:100%;max-height:100%;box-shadow:0 0 0 1px var(--fe-border);border-radius:4px}.Myjg4a_previewMeta{color:var(--fe-faint);font-size:11px}.Myjg4a_placeholder{text-align:center;color:var(--fe-faint);flex:1;justify-content:center;align-items:center;padding:16px;font-size:12px;line-height:18px;display:flex}.Myjg4a_editorHighlight .hljs-keyword,.Myjg4a_editorHighlight .hljs-selector-tag,.Myjg4a_editorHighlight .hljs-literal{color:var(--fe-token-keyword)}.Myjg4a_editorHighlight .hljs-string,.Myjg4a_editorHighlight .hljs-regexp,.Myjg4a_editorHighlight .hljs-addition{color:var(--fe-token-string)}.Myjg4a_editorHighlight .hljs-comment,.Myjg4a_editorHighlight .hljs-quote{color:var(--fe-token-comment);font-style:italic}.Myjg4a_editorHighlight .hljs-number,.Myjg4a_editorHighlight .hljs-symbol,.Myjg4a_editorHighlight .hljs-bullet{color:var(--fe-token-number)}.Myjg4a_editorHighlight .hljs-title,.Myjg4a_editorHighlight .hljs-section,.Myjg4a_editorHighlight .hljs-title.function_{color:var(--fe-token-function)}.Myjg4a_editorHighlight .hljs-type,.Myjg4a_editorHighlight .hljs-built_in,.Myjg4a_editorHighlight .hljs-class .hljs-title{color:var(--fe-token-type)}.Myjg4a_editorHighlight .hljs-attr,.Myjg4a_editorHighlight .hljs-attribute,.Myjg4a_editorHighlight .hljs-variable,.Myjg4a_editorHighlight .hljs-template-variable,.Myjg4a_editorHighlight .hljs-params{color:var(--fe-token-variable)}.Myjg4a_editorHighlight .hljs-tag,.Myjg4a_editorHighlight .hljs-name{color:var(--fe-token-tag)}.Myjg4a_editorHighlight .hljs-meta{color:var(--fe-token-meta)}.Myjg4a_editorHighlight .hljs-emphasis{font-style:italic}.Myjg4a_editorHighlight .hljs-strong{color:var(--fe-accent);font-weight:inherit}body[data-dsh-maid-atelier] [data-skin-chrome=top-trim],body[data-dsh-maid-atelier] [data-skin-chrome=bottom-trim]{translate:calc(var(--maid-sidebar-width,0px) + var(--dsh-explorer-width,0px) + var(--dsh-preview-width,0px)) 0!important}[class*=explorerCol]{border-right:1px solid var(--fe-border)!important}";
34
34
  const tagId = "dsh-plugin-workbench/files.module.css";
35
35
  if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
36
36
  const tag = document.createElement("style");
@@ -45,6 +45,10 @@ window.__ModuleLoader__.load({
45
45
  "chevron": "Myjg4a_chevron",
46
46
  "collapse": "Myjg4a_collapse",
47
47
  "column": "Myjg4a_column",
48
+ "contextMenu": "Myjg4a_contextMenu",
49
+ "contextMenuDivider": "Myjg4a_contextMenuDivider",
50
+ "contextMenuItem": "Myjg4a_contextMenuItem",
51
+ "contextMenuItemDanger": "Myjg4a_contextMenuItemDanger",
48
52
  "editor": "Myjg4a_editor",
49
53
  "editorHighlight": "Myjg4a_editorHighlight",
50
54
  "editorHint": "Myjg4a_editorHint",
@@ -54,11 +58,15 @@ window.__ModuleLoader__.load({
54
58
  "fe-preview-out": "Myjg4a_fe-preview-out",
55
59
  "fileBadge": "Myjg4a_fileBadge",
56
60
  "fileBadgeLong": "Myjg4a_fileBadgeLong",
61
+ "gutter": "Myjg4a_gutter",
62
+ "gutterNumbers": "Myjg4a_gutterNumbers",
57
63
  "handle": "Myjg4a_handle",
58
64
  "header": "Myjg4a_header",
59
65
  "headerActions": "Myjg4a_headerActions",
60
66
  "headerTitle": "Myjg4a_headerTitle",
61
67
  "icon": "Myjg4a_icon",
68
+ "image": "Myjg4a_image",
69
+ "imageView": "Myjg4a_imageView",
62
70
  "name": "Myjg4a_name",
63
71
  "placeholder": "Myjg4a_placeholder",
64
72
  "preview": "Myjg4a_preview",
@@ -668,6 +676,37 @@ window.__ModuleLoader__.load({
668
676
  active: path
669
677
  });
670
678
  }
679
+ /** Point any open tab at a new path after a rename (the disk path changed). */
680
+ function retargetFile(oldPath, newPath) {
681
+ updateCurrent((ws) => {
682
+ if (!ws.tabs.includes(oldPath)) return ws;
683
+ const tabs = ws.tabs.map((t) => t === oldPath ? newPath : t);
684
+ return {
685
+ ...ws,
686
+ tabs,
687
+ active: ws.active === oldPath ? newPath : ws.active
688
+ };
689
+ });
690
+ }
691
+ /** Close every open tab at or under a path (used after deleting it). */
692
+ function closeFilesUnder(path) {
693
+ updateCurrent((ws) => {
694
+ const sep = path.includes("\\") ? "\\" : "/";
695
+ const prefix = path.endsWith("\\") || path.endsWith("/") ? path : path + sep;
696
+ const kept = ws.tabs.filter((t) => t !== path && !t.startsWith(prefix));
697
+ if (kept.length === ws.tabs.length) return ws;
698
+ let active = ws.active;
699
+ if (active !== void 0 && (active === path || active.startsWith(prefix))) {
700
+ const index = ws.tabs.indexOf(active);
701
+ active = kept[Math.min(index, kept.length - 1)];
702
+ }
703
+ return {
704
+ ...ws,
705
+ tabs: kept,
706
+ active
707
+ };
708
+ });
709
+ }
671
710
  /** Move a tab before another tab (drag-to-reorder). */
672
711
  function moveTab(dragged, target) {
673
712
  updateCurrent((ws) => {
@@ -728,6 +767,16 @@ window.__ModuleLoader__.load({
728
767
  const idx = Math.max(trimmed.lastIndexOf("/"), trimmed.lastIndexOf("\\"));
729
768
  return idx >= 0 ? trimmed.slice(idx + 1) : trimmed;
730
769
  }
770
+ /** Parent directory of a path ('' for a bare drive root — never used for such). */
771
+ function parentOf(path) {
772
+ const idx = Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\"));
773
+ return idx > 0 ? path.slice(0, idx) : path;
774
+ }
775
+ /** Append a child name to a directory path, honoring its separator style. */
776
+ function joinPath(dir, name) {
777
+ const sep = dir.includes("\\") ? "\\" : "/";
778
+ return dir.endsWith("\\") || dir.endsWith("/") ? dir + name : dir + sep + name;
779
+ }
731
780
  function formatSize$1(bytes) {
732
781
  if (!Number.isFinite(bytes) || bytes < 0) return "";
733
782
  if (bytes < 1024) return `${bytes} B`;
@@ -754,13 +803,14 @@ window.__ModuleLoader__.load({
754
803
  * full of files, re-rendering the whole tree on every click is what made
755
804
  * opening files feel laggy.
756
805
  */
757
- const TreeRow = (0, react.memo)(function TreeRow({ entry, depth, isActive, isExpanded, onToggleDir, onRefreshDir, onSelect, onDoubleClick, onOpenExternal, t }) {
806
+ const TreeRow = (0, react.memo)(function TreeRow({ entry, depth, isActive, isExpanded, onToggleDir, onRefreshDir, onSelect, onDoubleClick, onOpenExternal, onContextMenu, t }) {
758
807
  const isDir = entry.kind === "dir";
759
808
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
760
809
  className: `${files_module_css_default.row} ${isActive ? files_module_css_default.rowSelected : ""}`,
761
810
  style: { paddingLeft: 8 + depth * 14 },
762
811
  onClick: () => onSelect(entry),
763
812
  onDoubleClick: () => onDoubleClick(entry),
813
+ onContextMenu: (e) => onContextMenu(e, entry),
764
814
  role: "treeitem",
765
815
  "aria-selected": isActive,
766
816
  "aria-expanded": isDir ? isExpanded : void 0,
@@ -811,7 +861,7 @@ window.__ModuleLoader__.load({
811
861
  ]
812
862
  });
813
863
  });
814
- function FileExplorer({ width, useSessions, t, listDir, openPath }) {
864
+ function FileExplorer({ width, useSessions, t, listDir, openPath, createFile, createDir, renameFile, removePath }) {
815
865
  const sessionList = useSessions((s) => s);
816
866
  const currentId = sessionList.current;
817
867
  const cwd = currentId !== void 0 ? sessionList.byId[currentId]?.cwd : void 0;
@@ -826,6 +876,42 @@ window.__ModuleLoader__.load({
826
876
  const [children, setChildren] = (0, react.useState)({});
827
877
  const [loadingDirs, setLoadingDirs] = (0, react.useState)(/* @__PURE__ */ new Set());
828
878
  const [dirErrors, setDirErrors] = (0, react.useState)({});
879
+ const [menu, setMenu] = (0, react.useState)(void 0);
880
+ const [menuPos, setMenuPos] = (0, react.useState)(void 0);
881
+ const menuRef = (0, react.useRef)(null);
882
+ (0, react.useLayoutEffect)(() => {
883
+ if (menu === void 0) {
884
+ setMenuPos(void 0);
885
+ return;
886
+ }
887
+ const el = menuRef.current;
888
+ if (el === null) return;
889
+ const rect = el.getBoundingClientRect();
890
+ setMenuPos({
891
+ x: Math.max(4, Math.min(menu.x, window.innerWidth - rect.width - 4)),
892
+ y: Math.max(4, Math.min(menu.y, window.innerHeight - rect.height - 4))
893
+ });
894
+ }, [menu]);
895
+ (0, react.useEffect)(() => {
896
+ if (menu === void 0) return void 0;
897
+ const onKeyDown = (e) => {
898
+ if (e.key === "Escape") setMenu(void 0);
899
+ };
900
+ const onMouseDown = (e) => {
901
+ const el = menuRef.current;
902
+ if (el !== null && e.target instanceof Node && el.contains(e.target)) return;
903
+ setMenu(void 0);
904
+ };
905
+ const onBlur = () => setMenu(void 0);
906
+ document.addEventListener("keydown", onKeyDown);
907
+ document.addEventListener("mousedown", onMouseDown);
908
+ window.addEventListener("blur", onBlur);
909
+ return () => {
910
+ document.removeEventListener("keydown", onKeyDown);
911
+ document.removeEventListener("mousedown", onMouseDown);
912
+ window.removeEventListener("blur", onBlur);
913
+ };
914
+ }, [menu]);
829
915
  const treeRef = (0, react.useRef)({
830
916
  root,
831
917
  children,
@@ -992,6 +1078,88 @@ window.__ModuleLoader__.load({
992
1078
  });
993
1079
  loadDir(dirPath);
994
1080
  }, [loadDir]);
1081
+ const openContextMenu = (0, react.useCallback)((e, entry) => {
1082
+ e.preventDefault();
1083
+ e.stopPropagation();
1084
+ setMenu({
1085
+ kind: entry.kind === "dir" ? "dir" : "file",
1086
+ path: entry.path,
1087
+ x: e.clientX,
1088
+ y: e.clientY
1089
+ });
1090
+ }, []);
1091
+ const runAction = (0, react.useCallback)((action) => {
1092
+ setMenu(void 0);
1093
+ action();
1094
+ }, []);
1095
+ const applyMutation = (0, react.useCallback)(async (op, refreshPath) => {
1096
+ try {
1097
+ await op();
1098
+ refreshDir(refreshPath);
1099
+ } catch (error) {
1100
+ const message = error instanceof Error ? error.message : String(error);
1101
+ if (refreshPath === root) setRootError(message);
1102
+ else setDirErrors((prev) => ({
1103
+ ...prev,
1104
+ [refreshPath]: message
1105
+ }));
1106
+ }
1107
+ }, [refreshDir, root]);
1108
+ const onNewFile = (0, react.useCallback)((dirPath) => {
1109
+ const name = window.prompt(`${t("prompt.newFileName")}:`, "");
1110
+ if (name === null) return;
1111
+ const trimmed = name.trim();
1112
+ if (trimmed === "") return;
1113
+ applyMutation(() => createFile(joinPath(dirPath, trimmed)), dirPath);
1114
+ }, [
1115
+ applyMutation,
1116
+ createFile,
1117
+ t
1118
+ ]);
1119
+ const onNewFolder = (0, react.useCallback)((dirPath) => {
1120
+ const name = window.prompt(`${t("prompt.newFolderName")}:`, "");
1121
+ if (name === null) return;
1122
+ const trimmed = name.trim();
1123
+ if (trimmed === "") return;
1124
+ applyMutation(() => createDir(joinPath(dirPath, trimmed)), dirPath);
1125
+ }, [
1126
+ applyMutation,
1127
+ createDir,
1128
+ t
1129
+ ]);
1130
+ const onRename = (0, react.useCallback)((path) => {
1131
+ const current = basenameOf$1(path);
1132
+ const name = window.prompt(`${t("prompt.renameTo")}:`, current);
1133
+ if (name === null) return;
1134
+ const trimmed = name.trim();
1135
+ if (trimmed === "" || trimmed === current) return;
1136
+ const parent = parentOf(path);
1137
+ const to = joinPath(parent, trimmed);
1138
+ applyMutation(async () => {
1139
+ await renameFile(path, to);
1140
+ retargetFile(path, to);
1141
+ }, parent);
1142
+ }, [
1143
+ applyMutation,
1144
+ renameFile,
1145
+ t
1146
+ ]);
1147
+ const onDelete = (0, react.useCallback)((path, kind) => {
1148
+ const name = basenameOf$1(path);
1149
+ const message = kind === "dir" ? t("confirm.deleteDir", { name }) : t("confirm.deleteFile", { name });
1150
+ if (!window.confirm(message)) return;
1151
+ applyMutation(async () => {
1152
+ await removePath(path);
1153
+ closeFilesUnder(path);
1154
+ }, parentOf(path));
1155
+ }, [
1156
+ applyMutation,
1157
+ removePath,
1158
+ t
1159
+ ]);
1160
+ const onCopyPath = (0, react.useCallback)((path) => {
1161
+ navigator.clipboard.writeText(path).catch(() => {});
1162
+ }, []);
995
1163
  const onRowClick = (0, react.useCallback)((entry) => {
996
1164
  if (entry.kind === "dir") {
997
1165
  toggleDir(entry.path);
@@ -1029,6 +1197,7 @@ window.__ModuleLoader__.load({
1029
1197
  onSelect: onRowClick,
1030
1198
  onDoubleClick: onRowDoubleClick,
1031
1199
  onOpenExternal: openPath,
1200
+ onContextMenu: openContextMenu,
1032
1201
  t
1033
1202
  }), isDir && isExpanded && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", { children: [
1034
1203
  isLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -1049,61 +1218,173 @@ window.__ModuleLoader__.load({
1049
1218
  childEntries !== void 0 && renderEntries(childEntries, depth + 1)
1050
1219
  ] })] }, entry.path);
1051
1220
  });
1221
+ const menuItems = (m) => {
1222
+ if (m.kind === "file") return [
1223
+ {
1224
+ label: t("menu.open"),
1225
+ onClick: () => openFile(m.path)
1226
+ },
1227
+ "divider",
1228
+ {
1229
+ label: t("menu.copyPath"),
1230
+ onClick: () => onCopyPath(m.path)
1231
+ },
1232
+ {
1233
+ label: t("menu.openSystem"),
1234
+ onClick: () => void openPath(m.path)
1235
+ },
1236
+ "divider",
1237
+ {
1238
+ label: t("menu.rename"),
1239
+ onClick: () => onRename(m.path)
1240
+ },
1241
+ {
1242
+ label: t("menu.delete"),
1243
+ danger: true,
1244
+ onClick: () => onDelete(m.path, "file")
1245
+ }
1246
+ ];
1247
+ if (m.kind === "dir") return [
1248
+ {
1249
+ label: t("menu.newFile"),
1250
+ onClick: () => onNewFile(m.path)
1251
+ },
1252
+ {
1253
+ label: t("menu.newFolder"),
1254
+ onClick: () => onNewFolder(m.path)
1255
+ },
1256
+ "divider",
1257
+ {
1258
+ label: t("menu.copyPath"),
1259
+ onClick: () => onCopyPath(m.path)
1260
+ },
1261
+ {
1262
+ label: t("menu.openSystem"),
1263
+ onClick: () => void openPath(m.path)
1264
+ },
1265
+ {
1266
+ label: t("menu.refresh"),
1267
+ onClick: () => refreshDir(m.path)
1268
+ },
1269
+ "divider",
1270
+ {
1271
+ label: t("menu.rename"),
1272
+ onClick: () => onRename(m.path)
1273
+ },
1274
+ {
1275
+ label: t("menu.delete"),
1276
+ danger: true,
1277
+ onClick: () => onDelete(m.path, "dir")
1278
+ }
1279
+ ];
1280
+ return [
1281
+ {
1282
+ label: t("menu.newFile"),
1283
+ onClick: () => onNewFile(m.path)
1284
+ },
1285
+ {
1286
+ label: t("menu.newFolder"),
1287
+ onClick: () => onNewFolder(m.path)
1288
+ },
1289
+ "divider",
1290
+ {
1291
+ label: t("menu.copyPath"),
1292
+ onClick: () => onCopyPath(m.path)
1293
+ },
1294
+ {
1295
+ label: t("menu.refresh"),
1296
+ onClick: () => refreshDir(m.path)
1297
+ }
1298
+ ];
1299
+ };
1052
1300
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1053
1301
  className: files_module_css_default.column,
1054
1302
  style: { width: width > 0 ? width : void 0 },
1055
1303
  "data-pane": "explorer",
1056
1304
  "data-fe-theme": theme,
1057
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1058
- className: files_module_css_default.header,
1059
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1060
- className: files_module_css_default.headerTitle,
1061
- title: root ?? cwd,
1062
- children: basenameOf$1(root ?? cwd)
1063
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1064
- className: files_module_css_default.headerActions,
1305
+ children: [
1306
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1307
+ className: files_module_css_default.header,
1308
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
1309
+ className: files_module_css_default.headerTitle,
1310
+ title: root ?? cwd,
1311
+ children: basenameOf$1(root ?? cwd)
1312
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("span", {
1313
+ className: files_module_css_default.headerActions,
1314
+ children: [
1315
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1316
+ type: "button",
1317
+ className: files_module_css_default.action,
1318
+ title: t("action.theme"),
1319
+ onClick: toggleTheme,
1320
+ children: theme === "dark" ? "☀" : "🌙"
1321
+ }),
1322
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1323
+ type: "button",
1324
+ className: files_module_css_default.action,
1325
+ title: t("action.open"),
1326
+ onClick: () => void openPath(cwd),
1327
+ children: "↗"
1328
+ }),
1329
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1330
+ type: "button",
1331
+ className: files_module_css_default.action,
1332
+ title: t("tab.expand"),
1333
+ onClick: expandPreview,
1334
+ children: ">"
1335
+ })
1336
+ ]
1337
+ })]
1338
+ }),
1339
+ /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1340
+ className: files_module_css_default.treeArea,
1341
+ onContextMenu: (e) => {
1342
+ e.preventDefault();
1343
+ const target = root ?? cwd;
1344
+ if (target === void 0) return;
1345
+ setMenu({
1346
+ kind: "root",
1347
+ path: target,
1348
+ x: e.clientX,
1349
+ y: e.clientY
1350
+ });
1351
+ },
1065
1352
  children: [
1066
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1067
- type: "button",
1068
- className: files_module_css_default.action,
1069
- title: t("action.theme"),
1070
- onClick: toggleTheme,
1071
- children: theme === "dark" ? "☀" : "🌙"
1353
+ rootLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1354
+ className: files_module_css_default.rowHint,
1355
+ children: t("preview.loading")
1072
1356
  }),
1073
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1074
- type: "button",
1075
- className: files_module_css_default.action,
1076
- title: t("action.open"),
1077
- onClick: () => void openPath(cwd),
1078
- children: "↗"
1357
+ rootError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1358
+ className: files_module_css_default.rowError,
1359
+ children: rootError
1079
1360
  }),
1080
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
1081
- type: "button",
1082
- className: files_module_css_default.action,
1083
- title: t("tab.expand"),
1084
- onClick: expandPreview,
1085
- children: ">"
1086
- })
1361
+ !rootLoading && rootError === void 0 && root !== void 0 && children[root] !== void 0 && children[root].length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1362
+ className: files_module_css_default.rowHint,
1363
+ children: t("preview.emptyDir")
1364
+ }),
1365
+ root !== void 0 && children[root] !== void 0 && renderEntries(children[root], 0)
1087
1366
  ]
1088
- })]
1089
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
1090
- className: files_module_css_default.treeArea,
1091
- children: [
1092
- rootLoading && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1093
- className: files_module_css_default.rowHint,
1094
- children: t("preview.loading")
1095
- }),
1096
- rootError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1097
- className: files_module_css_default.rowError,
1098
- children: rootError
1099
- }),
1100
- !rootLoading && rootError === void 0 && root !== void 0 && children[root] !== void 0 && children[root].length === 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1101
- className: files_module_css_default.rowHint,
1102
- children: t("preview.emptyDir")
1103
- }),
1104
- root !== void 0 && children[root] !== void 0 && renderEntries(children[root], 0)
1105
- ]
1106
- })]
1367
+ }),
1368
+ menu !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1369
+ ref: menuRef,
1370
+ className: files_module_css_default.contextMenu,
1371
+ role: "menu",
1372
+ style: menuPos !== void 0 ? {
1373
+ left: menuPos.x,
1374
+ top: menuPos.y
1375
+ } : {
1376
+ left: menu.x,
1377
+ top: menu.y,
1378
+ visibility: "hidden"
1379
+ },
1380
+ children: menuItems(menu).map((item, index) => item === "divider" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { className: files_module_css_default.contextMenuDivider }, index) : /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
1381
+ role: "menuitem",
1382
+ className: `${files_module_css_default.contextMenuItem}${item.danger ? ` ${files_module_css_default.contextMenuItemDanger}` : ""}`,
1383
+ onClick: () => runAction(item.onClick),
1384
+ children: item.label
1385
+ }, index))
1386
+ })
1387
+ ]
1107
1388
  });
1108
1389
  }
1109
1390
  var core_default = (/* @__PURE__ */ __toESM((/* @__PURE__ */ __commonJSMin(((exports, module) => {
@@ -8736,6 +9017,30 @@ window.__ModuleLoader__.load({
8736
9017
  const PREVIEW_MIN = 240;
8737
9018
  const CHAT_MIN = 240;
8738
9019
  const PREVIEW_TOO_LARGE_LABEL = "512KB";
9020
+ /** Same-origin raw-bytes route registered by the host half (see src/index.ts). */
9021
+ const RAW_PREFIX = "/dsh-plugin-files/raw";
9022
+ const IMAGE_EXTENSIONS = /* @__PURE__ */ new Set([
9023
+ "png",
9024
+ "jpg",
9025
+ "jpeg",
9026
+ "gif",
9027
+ "webp",
9028
+ "avif",
9029
+ "bmp",
9030
+ "ico",
9031
+ "svg"
9032
+ ]);
9033
+ /**
9034
+ * Same-origin URL serving the file's bytes when it is a previewable image;
9035
+ * undefined otherwise. Image tabs never go through the text RPC read — the
9036
+ * host route resolves the path through the sandboxed fs service itself.
9037
+ */
9038
+ function imageSrcOf(path) {
9039
+ const idx = path.lastIndexOf(".");
9040
+ if (idx < 0 || idx === path.length - 1) return void 0;
9041
+ const ext = path.slice(idx + 1).toLowerCase();
9042
+ return IMAGE_EXTENSIONS.has(ext) ? `${RAW_PREFIX}/${encodeURIComponent(path)}` : void 0;
9043
+ }
8739
9044
  /**
8740
9045
  * Above this size the overlay editor (syntax-highlight layer + transparent
8741
9046
  * textarea) falls back to a plain textarea: re-injecting and re-laying out
@@ -8783,6 +9088,18 @@ window.__ModuleLoader__.load({
8783
9088
  size: result.size
8784
9089
  };
8785
9090
  }
9091
+ /**
9092
+ * Gutter text for an editor: one logical line number per source line, as a
9093
+ * single pre-formatted block (VS Code shows logical numbers even when soft
9094
+ * wrap makes a line occupy several visual rows).
9095
+ */
9096
+ function lineNumbersOf(content) {
9097
+ const count = content.split("\n").length;
9098
+ if (count <= 1) return "1";
9099
+ const parts = new Array(count);
9100
+ for (let i = 0; i < count; i += 1) parts[i] = String(i + 1);
9101
+ return parts.join("\n");
9102
+ }
8786
9103
  function FilePreview({ t, readFile, writeFile }) {
8787
9104
  const { tabs, active, theme, collapsed, wrap } = useTabsState();
8788
9105
  const [previewWidth, setPreviewWidth] = (0, react.useState)(null);
@@ -8792,10 +9109,12 @@ window.__ModuleLoader__.load({
8792
9109
  const cacheRef = (0, react.useRef)(/* @__PURE__ */ new Map());
8793
9110
  const hasOpenedRef = (0, react.useRef)(false);
8794
9111
  const [, bump] = (0, react.useState)(0);
9112
+ const [imageFailed, setImageFailed] = (0, react.useState)(void 0);
8795
9113
  const previewRef = (0, react.useRef)(null);
8796
9114
  const handleRef = (0, react.useRef)(null);
8797
9115
  const highlightRef = (0, react.useRef)(null);
8798
9116
  const textareaRef = (0, react.useRef)(null);
9117
+ const gutterRef = (0, react.useRef)(null);
8799
9118
  const refresh = (0, react.useCallback)(() => bump((v) => v + 1), []);
8800
9119
  (0, react.useEffect)(() => {
8801
9120
  const cache = cacheRef.current;
@@ -8806,6 +9125,11 @@ window.__ModuleLoader__.load({
8806
9125
  return;
8807
9126
  }
8808
9127
  const controller = new AbortController();
9128
+ if (imageSrcOf(target) !== void 0) {
9129
+ cache.set(target, { status: "image" });
9130
+ refresh();
9131
+ return () => controller.abort();
9132
+ }
8809
9133
  cache.set(target, { status: "loading" });
8810
9134
  readFile(target, controller.signal).then((result) => {
8811
9135
  if (!controller.signal.aborted) {
@@ -8830,6 +9154,9 @@ window.__ModuleLoader__.load({
8830
9154
  readFile,
8831
9155
  refresh
8832
9156
  ]);
9157
+ (0, react.useEffect)(() => {
9158
+ setImageFailed(void 0);
9159
+ }, [active]);
8833
9160
  if (tabs.length > 0) hasOpenedRef.current = true;
8834
9161
  (0, react.useEffect)(() => {
8835
9162
  if (tabs.length > 0) {
@@ -8850,14 +9177,19 @@ window.__ModuleLoader__.load({
8850
9177
  const language = active !== void 0 ? detectLanguage(active) : void 0;
8851
9178
  const tooBig = (activeData?.size ?? 0) > HIGHLIGHT_MAX_BYTES;
8852
9179
  const plain = language === void 0 || tooBig || language !== void 0 && PLAIN_LANGUAGES.has(language);
9180
+ const gutterNumbers = (0, react.useMemo)(() => activeData?.status === "loaded" ? lineNumbersOf(activeData.draft ?? "") : "", [activeData?.status, activeData?.draft]);
8853
9181
  (0, react.useEffect)(() => {
8854
9182
  const pre = highlightRef.current;
8855
9183
  const ta = textareaRef.current;
8856
- if (pre === null || ta === null || plain) return void 0;
9184
+ const gutter = gutterRef.current;
9185
+ if (ta === null || gutter === null) return void 0;
8857
9186
  let raf = 0;
8858
9187
  const tick = () => {
8859
- pre.scrollTop = ta.scrollTop;
8860
- pre.scrollLeft = ta.scrollLeft;
9188
+ if (pre !== null) {
9189
+ pre.scrollTop = ta.scrollTop;
9190
+ pre.scrollLeft = ta.scrollLeft;
9191
+ }
9192
+ gutter.scrollTop = ta.scrollTop;
8861
9193
  raf = requestAnimationFrame(tick);
8862
9194
  };
8863
9195
  raf = requestAnimationFrame(tick);
@@ -8943,11 +9275,13 @@ window.__ModuleLoader__.load({
8943
9275
  }, [onSave]);
8944
9276
  const onTextareaScroll = (0, react.useCallback)((e) => {
8945
9277
  const pre = highlightRef.current;
9278
+ const gutter = gutterRef.current;
8946
9279
  const ta = e.currentTarget;
8947
9280
  if (pre !== null) {
8948
9281
  pre.scrollTop = ta.scrollTop;
8949
9282
  pre.scrollLeft = ta.scrollLeft;
8950
9283
  }
9284
+ if (gutter !== null) gutter.scrollTop = ta.scrollTop;
8951
9285
  }, []);
8952
9286
  const onTabDragStart = (0, react.useCallback)((e, path) => {
8953
9287
  setDragPath(path);
@@ -8979,6 +9313,15 @@ window.__ModuleLoader__.load({
8979
9313
  className: `${files_module_css_default.editor}${plain ? ` ${files_module_css_default.editorPlain}` : ""}`,
8980
9314
  "data-wrap": wrap ? "on" : "off",
8981
9315
  children: [
9316
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9317
+ ref: gutterRef,
9318
+ className: files_module_css_default.gutter,
9319
+ "aria-hidden": "true",
9320
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9321
+ className: files_module_css_default.gutterNumbers,
9322
+ children: gutterNumbers
9323
+ })
9324
+ }),
8982
9325
  !plain && active !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
8983
9326
  ref: highlightRef,
8984
9327
  className: files_module_css_default.editorHighlight,
@@ -9005,6 +9348,33 @@ window.__ModuleLoader__.load({
9005
9348
  })
9006
9349
  ]
9007
9350
  });
9351
+ case "image": {
9352
+ const src = active !== void 0 ? imageSrcOf(active) : void 0;
9353
+ const name = active !== void 0 ? basenameOf(active) : "";
9354
+ if (src === void 0) return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9355
+ className: files_module_css_default.previewHint,
9356
+ children: t("preview.binary")
9357
+ });
9358
+ if (imageFailed === active) return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9359
+ className: files_module_css_default.previewHint,
9360
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("preview.imageFailed") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9361
+ className: files_module_css_default.previewMeta,
9362
+ children: name
9363
+ })]
9364
+ });
9365
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9366
+ className: files_module_css_default.imageView,
9367
+ children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("img", {
9368
+ className: files_module_css_default.image,
9369
+ src,
9370
+ alt: name,
9371
+ onError: () => setImageFailed(active)
9372
+ }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
9373
+ className: files_module_css_default.previewMeta,
9374
+ children: name
9375
+ })]
9376
+ });
9377
+ }
9008
9378
  case "binary": return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
9009
9379
  className: files_module_css_default.previewHint,
9010
9380
  children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", { children: t("preview.binary") }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -9117,8 +9487,22 @@ window.__ModuleLoader__.load({
9117
9487
  "tab.close": "关闭标签页",
9118
9488
  "tab.collapse": "收起文件详情",
9119
9489
  "tab.expand": "弹出文件详情",
9490
+ "menu.open": "打开预览",
9491
+ "menu.newFile": "新建文件",
9492
+ "menu.newFolder": "新建文件夹",
9493
+ "menu.rename": "重命名",
9494
+ "menu.delete": "删除",
9495
+ "menu.copyPath": "复制路径",
9496
+ "menu.refresh": "刷新",
9497
+ "menu.openSystem": "在系统中打开",
9498
+ "prompt.newFileName": "新文件名",
9499
+ "prompt.newFolderName": "新文件夹名",
9500
+ "prompt.renameTo": "重命名为",
9501
+ "confirm.deleteFile": "确定删除文件「{name}」吗?",
9502
+ "confirm.deleteDir": "确定删除文件夹「{name}」及其全部内容吗?",
9120
9503
  "preview.loading": "加载中…",
9121
9504
  "preview.binary": "二进制文件,无法预览",
9505
+ "preview.imageFailed": "图片加载失败",
9122
9506
  "preview.tooLarge": "文件过大,仅支持预览不超过 {limit}",
9123
9507
  "preview.emptyDir": "空目录",
9124
9508
  "preview.error": "加载失败",
@@ -9136,8 +9520,22 @@ window.__ModuleLoader__.load({
9136
9520
  "tab.close": "Close tab",
9137
9521
  "tab.collapse": "Collapse file details",
9138
9522
  "tab.expand": "Expand file details",
9523
+ "menu.open": "Open preview",
9524
+ "menu.newFile": "New File",
9525
+ "menu.newFolder": "New Folder",
9526
+ "menu.rename": "Rename",
9527
+ "menu.delete": "Delete",
9528
+ "menu.copyPath": "Copy Path",
9529
+ "menu.refresh": "Refresh",
9530
+ "menu.openSystem": "Open in System",
9531
+ "prompt.newFileName": "New file name",
9532
+ "prompt.newFolderName": "New folder name",
9533
+ "prompt.renameTo": "Rename to",
9534
+ "confirm.deleteFile": "Delete file \"{name}\"?",
9535
+ "confirm.deleteDir": "Delete folder \"{name}\" and all its contents?",
9139
9536
  "preview.loading": "Loading…",
9140
9537
  "preview.binary": "Binary file, cannot preview",
9538
+ "preview.imageFailed": "Failed to load image",
9141
9539
  "preview.tooLarge": "File too large to preview (limit {limit})",
9142
9540
  "preview.emptyDir": "Empty directory",
9143
9541
  "preview.error": "Load failed",
@@ -9165,13 +9563,24 @@ window.__ModuleLoader__.load({
9165
9563
  path,
9166
9564
  content
9167
9565
  }, signal));
9566
+ const createFile = (path, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "createFile", { path }, signal));
9567
+ const createDir = (path, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "createDir", { path }, signal));
9568
+ const renameFile = (path, to, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "rename", {
9569
+ path,
9570
+ to
9571
+ }, signal));
9572
+ const removePath = (path, signal) => unwrap(ctx.connection.rpc.call(CHANNEL, "delete", { path }, signal));
9168
9573
  const openPath = (path) => ctx.workspaces.openPath(path);
9169
9574
  ctx.slots.inject("explorer", () => ctx.slots.register({
9170
9575
  name: "explorer",
9171
9576
  locale: NS,
9172
9577
  inject: () => ({
9173
9578
  listDir,
9174
- openPath
9579
+ openPath,
9580
+ createFile,
9581
+ createDir,
9582
+ renameFile,
9583
+ removePath
9175
9584
  })
9176
9585
  }, FileExplorer));
9177
9586
  ctx.slots.inject("explorer.preview", () => ctx.slots.register({