dsh-plugin-workbench 0.0.2 → 0.0.3

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_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{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{background:var(--fe-hover);color:var(--fe-fg)}.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_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{height:100%;min-height:0;position:relative}.Myjg4a_editorHighlight{pointer-events:none;white-space:pre;color:var(--fe-fg);background:0 0;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:hidden}.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_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{font-weight:700}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_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{height:100%;min-height:0;position:relative}.Myjg4a_editorHighlight{pointer-events:none;white-space:pre;tab-size:2;color:var(--fe-fg);background:0 0;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_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{font-weight:700}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");
@@ -50,6 +50,8 @@ window.__ModuleLoader__.load({
50
50
  "editorTextarea": "Myjg4a_editorTextarea",
51
51
  "fe-preview-in": "Myjg4a_fe-preview-in",
52
52
  "fe-preview-out": "Myjg4a_fe-preview-out",
53
+ "fileBadge": "Myjg4a_fileBadge",
54
+ "fileBadgeLong": "Myjg4a_fileBadgeLong",
53
55
  "handle": "Myjg4a_handle",
54
56
  "header": "Myjg4a_header",
55
57
  "headerActions": "Myjg4a_headerActions",
@@ -69,15 +71,465 @@ window.__ModuleLoader__.load({
69
71
  "saveError": "Myjg4a_saveError",
70
72
  "size": "Myjg4a_size",
71
73
  "tab": "Myjg4a_tab",
74
+ "tabAction": "Myjg4a_tabAction",
75
+ "tabActionActive": "Myjg4a_tabActionActive",
72
76
  "tabActive": "Myjg4a_tabActive",
73
77
  "tabBar": "Myjg4a_tabBar",
74
78
  "tabClose": "Myjg4a_tabClose",
75
79
  "tabDot": "Myjg4a_tabDot",
80
+ "tabIcon": "Myjg4a_tabIcon",
76
81
  "tabName": "Myjg4a_tabName",
77
82
  "tabScroller": "Myjg4a_tabScroller",
78
83
  "treeArea": "Myjg4a_treeArea"
79
84
  };
80
85
  //#endregion
86
+ //#region src/client/fileIcons.tsx
87
+ /**
88
+ * File-type icons for the explorer tree rows and the preview tabs.
89
+ *
90
+ * Code/config files render as small colored badges with an extension label
91
+ * (VS Code "Minimal"-theme style); media, archives and installer files use
92
+ * emoji; anything unknown falls back to a generic document glyph. No icon
93
+ * assets are shipped — badges are pure CSS (per-language colors) and emoji
94
+ * come from the platform font.
95
+ */
96
+ /** lowercase extension (no dot) → badge colors. */
97
+ const BADGES = {
98
+ ts: {
99
+ label: "TS",
100
+ bg: "#3178c6",
101
+ fg: "#ffffff"
102
+ },
103
+ mts: {
104
+ label: "TS",
105
+ bg: "#3178c6",
106
+ fg: "#ffffff"
107
+ },
108
+ cts: {
109
+ label: "TS",
110
+ bg: "#3178c6",
111
+ fg: "#ffffff"
112
+ },
113
+ tsx: {
114
+ label: "TSX",
115
+ bg: "#61dafb",
116
+ fg: "#06283d"
117
+ },
118
+ js: {
119
+ label: "JS",
120
+ bg: "#f7df1e",
121
+ fg: "#1e1e1e"
122
+ },
123
+ mjs: {
124
+ label: "JS",
125
+ bg: "#f7df1e",
126
+ fg: "#1e1e1e"
127
+ },
128
+ cjs: {
129
+ label: "JS",
130
+ bg: "#f7df1e",
131
+ fg: "#1e1e1e"
132
+ },
133
+ jsx: {
134
+ label: "JSX",
135
+ bg: "#61dafb",
136
+ fg: "#06283d"
137
+ },
138
+ json: {
139
+ label: "{}",
140
+ bg: "#cbcb41",
141
+ fg: "#1e1e1e"
142
+ },
143
+ jsonc: {
144
+ label: "{}",
145
+ bg: "#cbcb41",
146
+ fg: "#1e1e1e"
147
+ },
148
+ html: {
149
+ label: "HTML",
150
+ bg: "#e44d26",
151
+ fg: "#ffffff"
152
+ },
153
+ htm: {
154
+ label: "HTML",
155
+ bg: "#e44d26",
156
+ fg: "#ffffff"
157
+ },
158
+ css: {
159
+ label: "CSS",
160
+ bg: "#2965f1",
161
+ fg: "#ffffff"
162
+ },
163
+ scss: {
164
+ label: "SCSS",
165
+ bg: "#cc6699",
166
+ fg: "#ffffff"
167
+ },
168
+ less: {
169
+ label: "LESS",
170
+ bg: "#2a4d80",
171
+ fg: "#ffffff"
172
+ },
173
+ md: {
174
+ label: "MD",
175
+ bg: "#519aba",
176
+ fg: "#ffffff"
177
+ },
178
+ markdown: {
179
+ label: "MD",
180
+ bg: "#519aba",
181
+ fg: "#ffffff"
182
+ },
183
+ py: {
184
+ label: "PY",
185
+ bg: "#3572a5",
186
+ fg: "#ffffff"
187
+ },
188
+ pyw: {
189
+ label: "PY",
190
+ bg: "#3572a5",
191
+ fg: "#ffffff"
192
+ },
193
+ go: {
194
+ label: "GO",
195
+ bg: "#00add8",
196
+ fg: "#06283d"
197
+ },
198
+ rs: {
199
+ label: "RS",
200
+ bg: "#dea584",
201
+ fg: "#1e1e1e"
202
+ },
203
+ java: {
204
+ label: "JAVA",
205
+ bg: "#b07219",
206
+ fg: "#ffffff"
207
+ },
208
+ c: {
209
+ label: "C",
210
+ bg: "#6e6e6e",
211
+ fg: "#ffffff"
212
+ },
213
+ h: {
214
+ label: "H",
215
+ bg: "#6e6e6e",
216
+ fg: "#ffffff"
217
+ },
218
+ cpp: {
219
+ label: "CPP",
220
+ bg: "#f34b7d",
221
+ fg: "#ffffff"
222
+ },
223
+ cc: {
224
+ label: "CPP",
225
+ bg: "#f34b7d",
226
+ fg: "#ffffff"
227
+ },
228
+ cxx: {
229
+ label: "CPP",
230
+ bg: "#f34b7d",
231
+ fg: "#ffffff"
232
+ },
233
+ hpp: {
234
+ label: "HPP",
235
+ bg: "#f34b7d",
236
+ fg: "#ffffff"
237
+ },
238
+ hxx: {
239
+ label: "HPP",
240
+ bg: "#f34b7d",
241
+ fg: "#ffffff"
242
+ },
243
+ cs: {
244
+ label: "CS",
245
+ bg: "#178600",
246
+ fg: "#ffffff"
247
+ },
248
+ sh: {
249
+ label: "SH",
250
+ bg: "#89e051",
251
+ fg: "#1e1e1e"
252
+ },
253
+ bash: {
254
+ label: "SH",
255
+ bg: "#89e051",
256
+ fg: "#1e1e1e"
257
+ },
258
+ zsh: {
259
+ label: "SH",
260
+ bg: "#89e051",
261
+ fg: "#1e1e1e"
262
+ },
263
+ ps1: {
264
+ label: "PS1",
265
+ bg: "#012456",
266
+ fg: "#ffffff"
267
+ },
268
+ psm1: {
269
+ label: "PS1",
270
+ bg: "#012456",
271
+ fg: "#ffffff"
272
+ },
273
+ psd1: {
274
+ label: "PS1",
275
+ bg: "#012456",
276
+ fg: "#ffffff"
277
+ },
278
+ bat: {
279
+ label: "BAT",
280
+ bg: "#6e6e6e",
281
+ fg: "#ffffff"
282
+ },
283
+ cmd: {
284
+ label: "BAT",
285
+ bg: "#6e6e6e",
286
+ fg: "#ffffff"
287
+ },
288
+ sql: {
289
+ label: "SQL",
290
+ bg: "#e38c00",
291
+ fg: "#ffffff"
292
+ },
293
+ yml: {
294
+ label: "YML",
295
+ bg: "#cb171e",
296
+ fg: "#ffffff"
297
+ },
298
+ yaml: {
299
+ label: "YML",
300
+ bg: "#cb171e",
301
+ fg: "#ffffff"
302
+ },
303
+ toml: {
304
+ label: "TOML",
305
+ bg: "#8b8b8b",
306
+ fg: "#ffffff"
307
+ },
308
+ ini: {
309
+ label: "INI",
310
+ bg: "#8b8b8b",
311
+ fg: "#ffffff"
312
+ },
313
+ conf: {
314
+ label: "INI",
315
+ bg: "#8b8b8b",
316
+ fg: "#ffffff"
317
+ },
318
+ cfg: {
319
+ label: "INI",
320
+ bg: "#8b8b8b",
321
+ fg: "#ffffff"
322
+ },
323
+ xml: {
324
+ label: "XML",
325
+ bg: "#a074c4",
326
+ fg: "#ffffff"
327
+ },
328
+ xsl: {
329
+ label: "XML",
330
+ bg: "#a074c4",
331
+ fg: "#ffffff"
332
+ },
333
+ svg: {
334
+ label: "SVG",
335
+ bg: "#e37933",
336
+ fg: "#ffffff"
337
+ },
338
+ vue: {
339
+ label: "VUE",
340
+ bg: "#41b883",
341
+ fg: "#06283d"
342
+ },
343
+ lock: {
344
+ label: "LOCK",
345
+ bg: "#9d9d9d",
346
+ fg: "#1e1e1e"
347
+ },
348
+ env: {
349
+ label: "ENV",
350
+ bg: "#f05033",
351
+ fg: "#ffffff"
352
+ },
353
+ gitignore: {
354
+ label: "GIT",
355
+ bg: "#f05033",
356
+ fg: "#ffffff"
357
+ },
358
+ gitattributes: {
359
+ label: "GIT",
360
+ bg: "#f05033",
361
+ fg: "#ffffff"
362
+ },
363
+ gitmodules: {
364
+ label: "GIT",
365
+ bg: "#f05033",
366
+ fg: "#ffffff"
367
+ },
368
+ editorconfig: {
369
+ label: "CFG",
370
+ bg: "#8b8b8b",
371
+ fg: "#ffffff"
372
+ },
373
+ npmrc: {
374
+ label: "CFG",
375
+ bg: "#8b8b8b",
376
+ fg: "#ffffff"
377
+ },
378
+ pnpmrc: {
379
+ label: "CFG",
380
+ bg: "#8b8b8b",
381
+ fg: "#ffffff"
382
+ },
383
+ yarnrc: {
384
+ label: "CFG",
385
+ bg: "#8b8b8b",
386
+ fg: "#ffffff"
387
+ },
388
+ mk: {
389
+ label: "MK",
390
+ bg: "#6d8086",
391
+ fg: "#ffffff"
392
+ },
393
+ makefile: {
394
+ label: "MK",
395
+ bg: "#6d8086",
396
+ fg: "#ffffff"
397
+ },
398
+ txt: {
399
+ label: "TXT",
400
+ bg: "#9d9d9d",
401
+ fg: "#ffffff"
402
+ },
403
+ log: {
404
+ label: "TXT",
405
+ bg: "#9d9d9d",
406
+ fg: "#ffffff"
407
+ },
408
+ pdf: {
409
+ label: "PDF",
410
+ bg: "#e74c3c",
411
+ fg: "#ffffff"
412
+ }
413
+ };
414
+ /** lowercase extension (no dot) → emoji glyph. */
415
+ const EMOJI = {
416
+ png: "🖼️",
417
+ jpg: "🖼️",
418
+ jpeg: "🖼️",
419
+ gif: "🖼️",
420
+ webp: "🖼️",
421
+ bmp: "🖼️",
422
+ ico: "🖼️",
423
+ avif: "🖼️",
424
+ jfif: "🖼️",
425
+ tif: "🖼️",
426
+ tiff: "🖼️",
427
+ mp3: "🎵",
428
+ wav: "🎵",
429
+ flac: "🎵",
430
+ ogg: "🎵",
431
+ oga: "🎵",
432
+ m4a: "🎵",
433
+ aac: "🎵",
434
+ wma: "🎵",
435
+ opus: "🎵",
436
+ mid: "🎵",
437
+ mp4: "🎬",
438
+ mkv: "🎬",
439
+ avi: "🎬",
440
+ mov: "🎬",
441
+ webm: "🎬",
442
+ flv: "🎬",
443
+ wmv: "🎬",
444
+ m4v: "🎬",
445
+ mpg: "🎬",
446
+ mpeg: "🎬",
447
+ zip: "🗜️",
448
+ rar: "🗜️",
449
+ "7z": "🗜️",
450
+ tar: "🗜️",
451
+ gz: "🗜️",
452
+ bz2: "🗜️",
453
+ xz: "🗜️",
454
+ tgz: "🗜️",
455
+ tbz2: "🗜️",
456
+ zst: "🗜️",
457
+ doc: "📘",
458
+ docx: "📘",
459
+ odt: "📘",
460
+ rtf: "📘",
461
+ xls: "📗",
462
+ xlsx: "📗",
463
+ ods: "📗",
464
+ csv: "📗",
465
+ ppt: "📙",
466
+ pptx: "📙",
467
+ odp: "📙",
468
+ epub: "📖",
469
+ mobi: "📖",
470
+ exe: "📦",
471
+ msi: "📦",
472
+ dmg: "📦",
473
+ app: "📦",
474
+ deb: "📦",
475
+ rpm: "📦",
476
+ apk: "📦",
477
+ iso: "📦"
478
+ };
479
+ /** Well-known extension-less names (lowercase) → emoji. */
480
+ const NAMED_EMOJI = { dockerfile: "🐳" };
481
+ /** Resolve a file name to its icon spec (badge colors or an emoji glyph). */
482
+ function fileIconFor(name) {
483
+ const lower = name.trim().toLowerCase();
484
+ if (lower === "") return {
485
+ kind: "emoji",
486
+ char: "📄"
487
+ };
488
+ const namedEmoji = NAMED_EMOJI[lower];
489
+ if (namedEmoji !== void 0) return {
490
+ kind: "emoji",
491
+ char: namedEmoji
492
+ };
493
+ let key;
494
+ if (lower.startsWith(".")) {
495
+ const rest = lower.slice(1);
496
+ key = rest.startsWith("env.") ? "env" : rest;
497
+ } else {
498
+ const dot = lower.lastIndexOf(".");
499
+ key = dot > 0 ? lower.slice(dot + 1) : lower;
500
+ }
501
+ const badge = BADGES[key];
502
+ if (badge !== void 0) return {
503
+ kind: "badge",
504
+ label: badge.label,
505
+ bg: badge.bg,
506
+ fg: badge.fg
507
+ };
508
+ const emoji = EMOJI[key];
509
+ if (emoji !== void 0) return {
510
+ kind: "emoji",
511
+ char: emoji
512
+ };
513
+ return {
514
+ kind: "emoji",
515
+ char: "📄"
516
+ };
517
+ }
518
+ /** Render a file's icon: a colored extension badge or an emoji glyph. */
519
+ function FileIcon({ name }) {
520
+ const icon = fileIconFor(name);
521
+ if (icon.kind === "emoji") return /* @__PURE__ */ (0, react_jsx_runtime.jsx)(react_jsx_runtime.Fragment, { children: icon.char });
522
+ const className = icon.label.length >= 4 ? `${files_module_css_default.fileBadge} ${files_module_css_default.fileBadgeLong}` : files_module_css_default.fileBadge;
523
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
524
+ className,
525
+ style: {
526
+ background: icon.bg,
527
+ color: icon.fg
528
+ },
529
+ children: icon.label
530
+ });
531
+ }
532
+ //#endregion
81
533
  //#region src/client/store.ts
82
534
  /**
83
535
  * Module-local store shared by the explorer tree (FileExplorer) and the split
@@ -93,15 +545,29 @@ window.__ModuleLoader__.load({
93
545
  active: void 0,
94
546
  collapsed: false
95
547
  };
548
+ const WRAP_KEY = "dsh-plugin-workbench:wrap";
549
+ /** Read the persisted wrap preference; defaults to soft wrap ON. */
550
+ function storedWrap() {
551
+ try {
552
+ if (typeof window === "undefined") return true;
553
+ const stored = window.localStorage.getItem(WRAP_KEY);
554
+ return stored === null ? true : stored === "1";
555
+ } catch {
556
+ return true;
557
+ }
558
+ }
559
+ const initialWrap = storedWrap();
96
560
  let state = {
97
561
  currentCwd: void 0,
98
562
  workspaces: {},
99
- theme: "dark"
563
+ theme: "dark",
564
+ wrap: initialWrap
100
565
  };
101
566
  let view = {
102
567
  tabs: EMPTY_TABS,
103
568
  active: void 0,
104
569
  collapsed: false,
570
+ wrap: initialWrap,
105
571
  theme: "dark",
106
572
  cwd: void 0
107
573
  };
@@ -128,10 +594,11 @@ window.__ModuleLoader__.load({
128
594
  tabs: ws.tabs,
129
595
  active: ws.active,
130
596
  collapsed: ws.collapsed,
597
+ wrap: state.wrap,
131
598
  theme: state.theme,
132
599
  cwd: state.currentCwd
133
600
  };
134
- if (nextView.tabs === view.tabs && nextView.active === view.active && nextView.collapsed === view.collapsed && nextView.theme === view.theme && nextView.cwd === view.cwd) return;
601
+ if (nextView.tabs === view.tabs && nextView.active === view.active && nextView.collapsed === view.collapsed && nextView.wrap === view.wrap && nextView.theme === view.theme && nextView.cwd === view.cwd) return;
135
602
  view = nextView;
136
603
  for (const listener of [...listeners]) listener();
137
604
  }
@@ -236,6 +703,17 @@ window.__ModuleLoader__.load({
236
703
  theme: state.theme === "dark" ? "light" : "dark"
237
704
  });
238
705
  }
706
+ /** Toggle display-only soft wrap for the editor (global, persisted). */
707
+ function toggleWrap() {
708
+ const wrap = !state.wrap;
709
+ try {
710
+ window.localStorage.setItem(WRAP_KEY, wrap ? "1" : "0");
711
+ } catch {}
712
+ commit({
713
+ ...state,
714
+ wrap
715
+ });
716
+ }
239
717
  //#endregion
240
718
  //#region src/client/FileExplorer.tsx
241
719
  /**
@@ -488,7 +966,7 @@ window.__ModuleLoader__.load({
488
966
  }),
489
967
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
490
968
  className: files_module_css_default.icon,
491
- children: isDir ? "📁" : entry.kind === "file" ? "📄" : "·"
969
+ children: isDir ? isExpanded ? "📂" : "📁" : entry.kind === "file" ? /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileIcon, { name: entry.name }) : "·"
492
970
  }),
493
971
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
494
972
  className: files_module_css_default.name,
@@ -8261,7 +8739,7 @@ window.__ModuleLoader__.load({
8261
8739
  };
8262
8740
  }
8263
8741
  function FilePreview({ t, readFile, writeFile }) {
8264
- const { tabs, active, theme, collapsed } = useTabsState();
8742
+ const { tabs, active, theme, collapsed, wrap } = useTabsState();
8265
8743
  const [previewWidth, setPreviewWidth] = (0, react.useState)(null);
8266
8744
  const [closing, setClosing] = (0, react.useState)(false);
8267
8745
  const [dragPath, setDragPath] = (0, react.useState)(void 0);
@@ -8432,6 +8910,7 @@ window.__ModuleLoader__.load({
8432
8910
  const highlighted = active !== void 0 ? highlightCode(activeData.draft ?? "", active) : "";
8433
8911
  return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8434
8912
  className: files_module_css_default.editor,
8913
+ "data-wrap": wrap ? "on" : "off",
8435
8914
  children: [
8436
8915
  /* @__PURE__ */ (0, react_jsx_runtime.jsx)("pre", {
8437
8916
  ref: highlightRef,
@@ -8446,7 +8925,7 @@ window.__ModuleLoader__.load({
8446
8925
  onScroll: onTextareaScroll,
8447
8926
  onKeyDown,
8448
8927
  spellCheck: false,
8449
- wrap: "off",
8928
+ wrap: wrap ? "soft" : "off",
8450
8929
  title: t("action.saveHint")
8451
8930
  }),
8452
8931
  saveError !== void 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
@@ -8488,44 +8967,58 @@ window.__ModuleLoader__.load({
8488
8967
  "data-fe-theme": theme,
8489
8968
  children: [tabs.length > 0 && /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8490
8969
  className: files_module_css_default.tabBar,
8491
- children: [/* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8492
- className: files_module_css_default.tabScroller,
8493
- children: tabs.map((path) => {
8494
- const data = cacheRef.current.get(path);
8495
- return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8496
- className: `${files_module_css_default.tab} ${path === active ? files_module_css_default.tabActive : ""}`,
8497
- onClick: () => activateFile(path),
8498
- draggable: true,
8499
- onDragStart: (e) => onTabDragStart(e, path),
8500
- onDragOver: (e) => onTabDragOver(e, path),
8501
- onDragEnd: onTabDragEnd,
8502
- title: path,
8503
- children: [
8504
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8505
- className: files_module_css_default.tabName,
8506
- children: basenameOf(path)
8507
- }),
8508
- data?.dirty === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: files_module_css_default.tabDot }),
8509
- /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8510
- type: "button",
8511
- className: files_module_css_default.tabClose,
8512
- title: t("tab.close"),
8513
- onClick: (e) => {
8514
- e.stopPropagation();
8515
- closeFile(path);
8516
- },
8517
- children: ""
8518
- })
8519
- ]
8520
- }, path);
8970
+ children: [
8971
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8972
+ className: files_module_css_default.tabScroller,
8973
+ children: tabs.map((path) => {
8974
+ const data = cacheRef.current.get(path);
8975
+ return /* @__PURE__ */ (0, react_jsx_runtime.jsxs)("div", {
8976
+ className: `${files_module_css_default.tab} ${path === active ? files_module_css_default.tabActive : ""}`,
8977
+ onClick: () => activateFile(path),
8978
+ draggable: true,
8979
+ onDragStart: (e) => onTabDragStart(e, path),
8980
+ onDragOver: (e) => onTabDragOver(e, path),
8981
+ onDragEnd: onTabDragEnd,
8982
+ title: path,
8983
+ children: [
8984
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8985
+ className: files_module_css_default.tabIcon,
8986
+ children: /* @__PURE__ */ (0, react_jsx_runtime.jsx)(FileIcon, { name: basenameOf(path) })
8987
+ }),
8988
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", {
8989
+ className: files_module_css_default.tabName,
8990
+ children: basenameOf(path)
8991
+ }),
8992
+ data?.dirty === true && /* @__PURE__ */ (0, react_jsx_runtime.jsx)("span", { className: files_module_css_default.tabDot }),
8993
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8994
+ type: "button",
8995
+ className: files_module_css_default.tabClose,
8996
+ title: t("tab.close"),
8997
+ onClick: (e) => {
8998
+ e.stopPropagation();
8999
+ closeFile(path);
9000
+ },
9001
+ children: "✕"
9002
+ })
9003
+ ]
9004
+ }, path);
9005
+ })
9006
+ }),
9007
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9008
+ type: "button",
9009
+ className: `${files_module_css_default.tabAction}${wrap ? ` ${files_module_css_default.tabActionActive}` : ""}`,
9010
+ title: wrap ? t("action.wrapOff") : t("action.wrapOn"),
9011
+ onClick: toggleWrap,
9012
+ children: "⤶"
9013
+ }),
9014
+ /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
9015
+ type: "button",
9016
+ className: files_module_css_default.collapse,
9017
+ title: t("tab.collapse"),
9018
+ onClick: collapsePreview,
9019
+ children: "<"
8521
9020
  })
8522
- }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("button", {
8523
- type: "button",
8524
- className: files_module_css_default.collapse,
8525
- title: t("tab.collapse"),
8526
- onClick: collapsePreview,
8527
- children: "<"
8528
- })]
9021
+ ]
8529
9022
  }), /* @__PURE__ */ (0, react_jsx_runtime.jsx)("div", {
8530
9023
  className: files_module_css_default.previewBody,
8531
9024
  children: renderBody()
@@ -8549,6 +9042,8 @@ window.__ModuleLoader__.load({
8549
9042
  "action.open": "在系统中打开",
8550
9043
  "action.theme": "切换浅色/暗色主题",
8551
9044
  "action.saveHint": "Ctrl+S 保存",
9045
+ "action.wrapOn": "开启自动换行(显示层换行,不改文件)",
9046
+ "action.wrapOff": "关闭自动换行(长行横向滚动)",
8552
9047
  "tab.close": "关闭标签页",
8553
9048
  "tab.collapse": "收起文件详情",
8554
9049
  "tab.expand": "弹出文件详情",
@@ -8565,6 +9060,8 @@ window.__ModuleLoader__.load({
8565
9060
  "action.open": "Open in system",
8566
9061
  "action.theme": "Toggle light/dark theme",
8567
9062
  "action.saveHint": "Ctrl+S to save",
9063
+ "action.wrapOn": "Enable word wrap (display only, file unchanged)",
9064
+ "action.wrapOff": "Disable word wrap (long lines scroll horizontally)",
8568
9065
  "tab.close": "Close tab",
8569
9066
  "tab.collapse": "Collapse file details",
8570
9067
  "tab.expand": "Expand file details",