dsh-vscode-mode 0.1.48 → 0.1.50
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/README.md +13 -1
- package/lib/client.js +885 -32
- package/lib/client.js.map +1 -1
- package/lib/index.js +562 -3
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/compat.ts +1 -1
- package/src/client/index.ts +9 -2
- package/src/client/paths.ts +2 -0
- package/src/client/rulesMdc.ts +141 -0
- package/src/client/sidebar/SidebarView.ts +83 -16
- package/src/client/sidebar/panels/RulesPanel.ts +445 -0
- package/src/client/sidebar/panels/index.ts +18 -2
- package/src/client/sidebar/types.ts +2 -0
- package/src/client/sidebarMin.ts +48 -0
- package/src/client/styles/editor.css +53 -1
- package/src/client/ui/EditorView.ts +22 -4
- package/src/client/ui/McpSettings.ts +37 -2
- package/src/client/ui/SideEditorTab.ts +1 -0
- package/src/fileOpenSettings.ts +2 -0
- package/src/index.ts +5 -1
- package/src/rpc.ts +37 -0
- package/src/rules.ts +528 -0
- package/src/shared/rpc.ts +11 -0
- package/src/shared/rules.ts +60 -0
package/lib/client.js
CHANGED
|
@@ -30,7 +30,7 @@ window.__ModuleLoader__.load({
|
|
|
30
30
|
react = __toESM(react, 1);
|
|
31
31
|
let react_dom = require("react-dom");
|
|
32
32
|
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
|
|
33
|
-
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 0; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n\n\n";
|
|
33
|
+
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\n\n[data-edrv-view] .edrv-tabs { display: flex; align-items: center; gap: 2px; padding: 2px 8px 0; background: var(--dsw-alias-bg-layer-1, transparent); overflow-x: auto; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\n[data-edrv-view] .edrv-tab .edrv-tab-x { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: rgba(255,255,255,.12); color: var(--dsw-alias-label-primary, #eee); }\n[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: #fff; font-weight: 600; white-space: nowrap; }\n[data-edrv-view] .edrv-btn-keep { background: var(--dsw-alias-state-success-primary, #2e9e44); }\n[data-edrv-view] .edrv-btn-undo { background: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-btn-mini:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-statusbar { display: flex; align-items: center; gap: 10px; padding: 3px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #333); background: var(--dsw-alias-bg-layer-1, transparent); font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); flex-shrink: 0; white-space: nowrap; overflow: hidden; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-path { flex: 1; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-lsp { flex: 0 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress-message { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-statusbar .edrv-sp-progress { flex: 0 0 auto; min-width: 36px; text-align: right; font-variant-numeric: tabular-nums; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-lsp-status-dot { width: 7px; height: 7px; border-radius: 50%; flex: 0 0 auto; background: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-lsp-status-dot.ready { background: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-lsp-status-dot.busy { background: var(--dsw-alias-state-warn-primary, #d97706); animation: edrv-lsp-pulse 1.2s ease-in-out infinite; }\n@keyframes edrv-lsp-pulse { 50% { opacity: .45; } }\n/* Ctrl+hover 可导航标识符下划线提示(绑定 Monaco inlineClassName 装饰) */\n[data-edrv-view] .edrv-nav-underline { text-decoration: underline; text-decoration-color: var(--dsw-alias-interactive-primary, #4fc1ff); text-underline-offset: 1px; cursor: pointer; }\n[data-edrv-view] .edrv-diffchip { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-state-warn-primary, #b7791f); cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn { font-size: 12px; padding: 2px 6px; border: none; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; border-radius: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-chip-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-chip-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-chip-btn:disabled:hover { background: transparent; }\n[data-edrv-view] .edrv-mn-add-line { background: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #0f9d58 !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px rgba(217,83,79,.12); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: #c0392b; }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: #d9534f; }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-empty { display: flex; flex-direction: column; align-items: center; justify-content: center; gap: 10px; height: 100%; color: var(--dsw-alias-label-tertiary, #777); font-size: 13px; }\n[data-edrv-view] .edrv-diffbar { position: absolute; left: 0; right: 0; bottom: 10px; margin: 0 auto; z-index: 25; width: fit-content; max-width: calc(100% - 20px); border-radius: 12px; background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); box-shadow: none; overflow: visible; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-editor-area > .edrv-diffbar { max-height: calc(100% - 20px); }\n[data-edrv-view] .edrv-diffbar-row { display: flex; align-items: center; gap: 6px; height: 36px; padding: 4px 5px 4px 12px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-diffbar-count { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); min-width: 42px; text-align: center; white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-diffbar-count.edrv-count-file { min-width: 64px; cursor: default; }\n[data-edrv-view] .edrv-diffbar-file { flex: 1; min-width: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-pill { font-size: 11px; padding: 3px 10px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-weight: 600; }\n[data-edrv-view] .edrv-pill-keep { background: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #ffffff; color: var(--dsw-alias-label-secondary, #52606d); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-diffbar-menu { position: absolute; right: 8px; bottom: calc(100% + 6px); z-index: 45; min-width: 160px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 6px 20px rgba(31,41,51,.16); padding: 4px; display: flex; flex-direction: column; gap: 2px; }\n[data-edrv-view] .edrv-diffmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; padding: 6px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; }\n[data-edrv-view] .edrv-diffmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n/* 编辑区 / Tab 右键菜单(添加文件/选中内容到对话) */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: rgba(217,119,6,.5); cursor: default; }\n[data-edrv-view] .edrv-diffbox-others { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; padding: 4px 2px 0; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); margin-top: 2px; }\n[data-edrv-view] .edrv-diffrow-file { font-size: 11px; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; white-space: nowrap; max-width: 200px; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n/* 编辑区 hover 差异块的 Keep/Undo 浮层 */\n[data-edrv-view] .edrv-hoveract { position: absolute; z-index: 30; display: flex; align-items: center; gap: 4px; padding: 2px 6px; border-radius: 8px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 4px 14px rgba(31,41,51,.14); }\n[data-edrv-view] .edrv-launch { position: absolute; left: 12px; right: 12px; bottom: 12px; z-index: 40; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); box-shadow: 0 6px 24px rgba(0,0,0,.5); display: flex; flex-direction: column; max-height: 60%; overflow: hidden; }\n[data-edrv-view] .edrv-launch-head { display: flex; align-items: center; gap: 6px; padding: 6px 8px; border-bottom: 1px solid var(--dsw-alias-border-l1, #333); }\n[data-edrv-view] .edrv-launch-tab { font-size: 12px; padding: 3px 12px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); cursor: pointer; }\n[data-edrv-view] .edrv-launch-tab.on { background: var(--dsw-alias-bg-layer-2, transparent); color: var(--dsw-alias-label-primary, #eee); font-weight: 600; }\n[data-edrv-view] .edrv-launch-body { flex: 1; min-height: 0; overflow: auto; padding: 6px 8px; display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-launch-row { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #333); border-radius: 6px; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-launch-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-launch-path { flex: 1; min-width: 0; font-size: 12px; color: var(--dsw-alias-label-primary, #eee); word-break: break-all; }\n[data-edrv-view] .edrv-launch-cnt { font-size: 11px; color: var(--dsw-alias-label-tertiary, #888); white-space: nowrap; }\n[data-edrv-view] .edrv-launch-arch { display: flex; flex-direction: column; gap: 6px; }\n[data-edrv-view] .monaco-editor { overflow: hidden !important; }\n[data-edrv-view] .monaco-editor .sticky-widget { z-index: 30 !important; background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-content,\n[data-edrv-view] .monaco-editor .sticky-widget .sticky-line-number { background: var(--dsw-alias-bg-base, #f8f8f8) !important; }\n[data-edrv-view] .monaco-editor, [data-edrv-view] .monaco-editor .margin, [data-edrv-view] .monaco-editor-background { background: transparent !important; }\n[data-edrv-view] .monaco-editor .scrollbar .slider { background: rgba(128,128,128,.3) !important; }\n[data-edrv-view] .edrv-loading { gap: 8px; padding: 20px; }\n[data-edrv-view] .edrv-loading-title { color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; }\n[data-edrv-view] .edrv-progress { width: min(360px, 72%); height: 6px; overflow: hidden; border-radius: 999px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-progress-value { height: 100%; border-radius: inherit; background: var(--dsw-alias-brand-primary, #0f9d58); transition: width .24s ease; }\n[data-edrv-view] .edrv-loading-percent { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; font-variant-numeric: tabular-nums; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-progress-value { transition: none; }\n}\n\n/* ===== 唯一会话级差异 dock(遵循 DSH todo/queue 原生布局) ===== */\n[data-edrv-diff-dock-shell] {\n box-sizing: border-box;\n width: calc(100% - var(--dsh-composer-side-clearance) - var(--dsh-composer-side-clearance) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n max-width: calc(var(--dsh-composer-card-max-width) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset) - var(--dsh-composer-dock-inset));\n margin: 0 auto;\n padding: 0;\n flex: none;\n border: 1px solid var(--dsw-alias-border-l1, #e0e6e8);\n border-radius: 12px;\n background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, transparent));\n box-shadow: none;\n overflow: hidden;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock {\n box-sizing: border-box;\n position: relative;\n left: auto;\n right: auto;\n bottom: auto;\n z-index: auto;\n width: 100%;\n max-width: none;\n margin: 0;\n display: flex;\n flex-direction: column;\n border: none;\n border-radius: 0;\n background: transparent;\n box-shadow: none;\n overflow: visible;\n}\n[data-edrv-diff-dock-shell] .edrv-diffbar-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-row { min-height: 36px; padding: 6px 12px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-body { max-height: 180px; overflow: auto; padding: 6px 12px 10px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button { box-sizing: border-box; display: flex; align-items: center; justify-content: center; width: 100%; height: 24px; border: none; border-radius: 8px; padding: 0 12px; background: transparent; color: var(--dsw-alias-label-primary); font-size: 13px; font-weight: 500; line-height: 24px; text-align: center; cursor: pointer; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-dock-button:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffbar-count { display: inline-flex; align-items: center; color: var(--dsw-alias-label-primary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 500; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-file { display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-row { display: flex; align-items: center; height: 36px; min-height: 36px; padding: 4px 12px; overflow-x: auto; scrollbar-width: thin; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { display: flex; align-items: center; gap: 10px; width: 100%; min-width: max-content; min-height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-nav,\n[data-edrv-diff-dock-shell] .edrv-diffbar-files,\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { display: flex; align-items: center; gap: 6px; flex: none; height: 28px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-actions { margin-left: auto; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle { display: inline-flex; align-items: center; justify-content: center; width: 28px; min-width: 28px; padding: 0; font-size: 13px; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-details-toggle svg { width: 14px; height: 14px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files { min-width: 0; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { min-width: 72px; max-width: 240px; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-progress { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; font-variant-numeric: tabular-nums; }\n[data-edrv-diff-dock-shell] .edrv-diffbar-summary { min-width: 0; color: var(--dsw-alias-label-tertiary); font-family: Inter, var(--dsw-font-family); font-size: 13px; font-weight: 400; line-height: 24px; }\n[data-edrv-diff-dock-shell] .edrv-pill { box-sizing: border-box; height: 28px; padding: 0 9px; border: none; border-radius: 999px; cursor: pointer; white-space: nowrap; font-size: 11px; line-height: 26px; font-weight: 600; }\n[data-edrv-diff-dock-shell] .edrv-pill-keep { background: var(--dsw-alias-state-success-tertiary); color: var(--dsw-alias-state-success-primary); border: 1px solid var(--dsw-alias-state-success-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-undo { background: var(--dsw-alias-state-error-tertiary); color: var(--dsw-alias-state-error-primary); border: 1px solid var(--dsw-alias-state-error-secondary); }\n[data-edrv-diff-dock-shell] .edrv-pill-ghost { background: transparent; color: var(--dsw-alias-label-secondary); border: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-pill:hover:not(:disabled) { background-color: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-pill:focus-visible { outline: 2px solid var(--dsw-alias-label-tertiary); outline-offset: -2px; }\n[data-edrv-diff-dock-shell] .edrv-pill:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1); border-radius: 6px; background: transparent; cursor: pointer; flex-wrap: wrap; }\n[data-edrv-diff-dock-shell] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-l { color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-o { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-n { color: var(--dsw-alias-state-success-primary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-tag { color: var(--dsw-alias-label-tertiary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-stale { border-color: var(--dsw-alias-state-warn-secondary); cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diffbox-others { border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file { border-color: var(--dsw-alias-border-l1); background: transparent; color: var(--dsw-alias-label-secondary); }\n[data-edrv-diff-dock-shell] .edrv-diffrow-file:hover { background: var(--dsw-alias-interactive-bg-hover); color: var(--dsw-alias-label-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details { display: flex; flex-direction: column; gap: 2px; padding: 6px 12px 8px; border-top: 1px solid var(--dsw-alias-border-l1); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item { display: flex; align-items: center; width: 100%; min-height: 28px; gap: 8px; padding: 4px 8px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary); cursor: pointer; text-align: left; font-size: 12px; line-height: 20px; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item.danger { color: var(--dsw-alias-state-error-primary); }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-item:disabled { opacity: .45; cursor: default; }\n[data-edrv-diff-dock-shell] .edrv-diff-details .edrv-diffmenu-sep { height: 1px; margin: 2px 4px; background: var(--dsw-alias-border-l1); }\n@media (max-width: 620px) {\n [data-edrv-diff-dock-shell] .edrv-diffbar-editor-content { width: max-content; }\n [data-edrv-diff-dock-shell] .edrv-diffbar-files .edrv-diffbar-file { max-width: 160px; }\n}\n\n/* ===== 侧边栏(活动栏 + 面板区 + 文件树) ===== */\n[data-edrv-view] .edrv-editor-row { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col { box-sizing: border-box; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-main-col > .edrv-pathbar,\n[data-edrv-view] .edrv-main-col > .edrv-tabs { flex: 0 0 auto; }\n[data-edrv-view] .edrv-editor-area { position: relative; display: flex; flex: 1 1 auto; flex-direction: column; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-sidebar { display: flex; flex-direction: row; flex-shrink: 1; min-width: 0; height: 100%; background: var(--dsw-alias-bg-layer-1, #ffffff); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; }\n[data-edrv-view] .edrv-rail { display: flex; flex-direction: column; align-items: center; width: 44px; flex-shrink: 0; padding: 6px 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); border-right: 1px solid var(--dsw-alias-border-l1, #e0e6e8); gap: 4px; }\n[data-edrv-view] .edrv-rail-btn { position: relative; display: inline-flex; align-items: center; justify-content: center; width: 32px; height: 32px; border: none; border-radius: 8px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rail-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rail-btn.edrv-rail-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-rail-icon { font-size: 15px; line-height: 1; }\n[data-edrv-view] .edrv-rail-badge { position: absolute; top: 2px; right: 2px; min-width: 14px; height: 14px; padding: 0 3px; border-radius: 999px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; }\n[data-edrv-view] .edrv-side-body { flex: 1; min-width: 0; min-height: 0; display: flex; overflow: hidden; }\n[data-edrv-view] .edrv-side-panel { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; position: relative; }\n[data-edrv-view] .edrv-side-head { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px 0 12px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-side-title { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-root { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-side-btn { display: inline-flex; align-items: center; justify-content: center; width: 22px; height: 22px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-btn:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree { flex: 1; min-height: 0; overflow: auto; padding: 4px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-tree-row { display: flex; align-items: center; gap: 4px; height: 22px; padding-right: 6px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-tree-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-context { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); }\n[data-edrv-view] .edrv-tree-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-tree-name { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-tree-name.edrv-tree-dim { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-badge { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-state-warn-primary, #d97706); color: #fff; font-size: 9px; font-weight: 600; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; }\n[data-edrv-view] .edrv-tree-loading { height: 22px; line-height: 22px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-tree-error { display: flex; align-items: center; gap: 8px; margin: 4px 2px 6px; padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* 大纲面板:kind 字形 / detail / 行号 */\n[data-edrv-view] .edrv-outline-kind { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-size: 12px; font-weight: 600; text-align: center; }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-func { color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-type { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-data { color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-ns { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-outline-kind.edrv-ol-key { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-outline-detail { flex-shrink: 0; max-width: 40%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-outline-ln { flex-shrink: 0; padding-right: 2px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-side-resize { width: 5px; flex-shrink: 0; cursor: col-resize; background: transparent; }\n[data-edrv-view] .edrv-side-resize:hover { background: var(--dsw-alias-brand-primary, #0f9d58); opacity: .35; }\n[data-edrv-view] .edrv-chip-btn.edrv-chip-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== 侧栏形态(betterSidebar 面板内编辑区) ===== */\n[data-edrv-view][data-edrv-layout='side'] { box-sizing: border-box; height: 100%; }\n\n/* ===== 侧边栏引导条(旧页签形态、未装 betterSidebar 时) ===== */\n[data-edrv-view] .edrv-side-hint { display: flex; align-items: center; gap: 8px; flex: 0 0 auto; flex-wrap: wrap; padding: 6px 12px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-specific-tip, var(--dsw-alias-bg-layer-2, #f0f4f4)); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-side-hint-text { white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-cmd { font-size: 11px; padding: 2px 6px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #ffffff); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-side-hint-close { margin-left: auto; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 14px; line-height: 1; padding: 2px 6px; border-radius: 6px; flex-shrink: 0; }\n[data-edrv-view] .edrv-side-hint-close:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n\n/* ===== search panel (sidebar, VSCode search view) ===== */\n[data-edrv-view] .edrv-search-panel { display: flex; flex-direction: column; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-search-qrow { display: flex; gap: 4px; }\n[data-edrv-view] .edrv-search-input { flex: 1; min-width: 0; height: 26px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-opts { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-search-opt { min-width: 24px; height: 22px; padding: 0 6px; border: 1px solid transparent; border-radius: 5px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); cursor: pointer; }\n[data-edrv-view] .edrv-search-opt:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-opt.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-border-l2, #d5dde3); }\n[data-edrv-view] .edrv-search-spacer { flex: 1; }\n[data-edrv-view] .edrv-search-summary { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 2px 4px; }\n[data-edrv-view] .edrv-search-results { flex: 1; min-height: 0; overflow: auto; font-size: 12px; }\n[data-edrv-view] .edrv-search-group { margin-bottom: 2px; }\n[data-edrv-view] .edrv-search-file { display: flex; align-items: center; gap: 4px; height: 22px; padding: 0 4px; border-radius: 5px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-search-file:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-chev { width: 12px; flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; text-align: center; }\n[data-edrv-view] .edrv-search-fname { font-weight: 600; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-search-fdir { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; }\n[data-edrv-view] .edrv-search-fcount { flex-shrink: 0; min-width: 16px; height: 15px; padding: 0 4px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 15px; text-align: center; }\n[data-edrv-view] .edrv-search-line { display: flex; gap: 6px; padding: 1px 4px 1px 16px; border-radius: 4px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-search-line.alt { background: var(--dsw-alias-bg-layer-1, #ffffff); }\n[data-edrv-view] .edrv-search-line:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-ln { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; min-width: 26px; text-align: right; user-select: none; }\n[data-edrv-view] .edrv-search-text { overflow: hidden; text-overflow: ellipsis; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-search-hit { background: var(--dsw-alias-state-warn-primary, #e5b93f); color: #1f2933; border-radius: 2px; padding: 0 1px; }\n[data-edrv-view] .edrv-search-empty { padding: 8px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-error { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #b8860b; font-size: 11px; word-break: break-all; }\n\n/* include/exclude filter rows (collapsible) */\n[data-edrv-view] .edrv-search-rows { display: flex; flex-direction: column; gap: 4px; padding: 2px 0 4px; }\n[data-edrv-view] .edrv-search-row { display: flex; align-items: center; gap: 4px; }\n[data-edrv-view] .edrv-search-field { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; }\n[data-edrv-view] .edrv-search-field:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-field.dim { opacity: .45; }\n[data-edrv-view] .edrv-search-field::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-search-toggle { min-width: 24px; height: 24px; padding: 0 5px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 1; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-search-toggle:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-search-toggle.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-search-toggle:disabled { opacity: .4; cursor: default; }\n\n/* ===== rules panel (sidebar, Codebuddy rules view) ===== */\n[data-edrv-view] .edrv-rules-panel { display: flex; flex-direction: column; min-width: 0; min-height: 0; flex: 1; padding: 6px; gap: 4px; }\n[data-edrv-view] .edrv-rules-tabs { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-tab { height: 24px; padding: 0 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-tab.on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-rules-new { margin-left: auto; height: 24px; padding: 0 10px; border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-new:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-ws-line { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); padding: 0 2px; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; flex: 0 0 auto; user-select: none; }\n[data-edrv-view] .edrv-rules-hint { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 0 2px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-list { flex: 1; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-rules-row { display: flex; align-items: center; gap: 4px; padding: 6px 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; }\n[data-edrv-view] .edrv-rules-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-row.off .edrv-rules-main { opacity: .5; }\n[data-edrv-view] .edrv-rules-main { flex: 1; min-width: 0; cursor: pointer; overflow: hidden; }\n[data-edrv-view] .edrv-rules-line1 { display: flex; align-items: center; gap: 6px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sub { display: flex; align-items: center; gap: 5px; margin-top: 3px; min-width: 0; }\n[data-edrv-view] .edrv-rules-sublabel { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-file { font-weight: 600; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-path { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-type { flex-shrink: 0; height: 15px; padding: 0 5px; border-radius: 999px; font-size: 10px; line-height: 15px; }\n[data-edrv-view] .edrv-rules-type-always { background: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #3367c9; }\n[data-edrv-view] .edrv-rules-type-manual { background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-rules-offtag { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-desc { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; flex: 0 1 auto; }\n[data-edrv-view] .edrv-rules-actions { display: flex; align-items: center; gap: 2px; flex-shrink: 0; margin-left: auto; }\n[data-edrv-view] .edrv-rules-act { min-width: 22px; height: 22px; padding: 0 4px; border: none; border-radius: 5px; background: transparent; font-size: 12px; line-height: 1; cursor: pointer; color: var(--dsw-alias-label-secondary, #52606d); display: inline-flex; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-rules-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-rules-switch { position: relative; width: 30px; height: 16px; border-radius: 999px; border: none; background: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #fff; transition: left .15s; }\n[data-edrv-view] .edrv-rules-switch.on .edrv-rules-knob { left: 16px; }\n[data-edrv-view] .edrv-rules-empty { padding: 10px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n[data-edrv-view] .edrv-rules-err { padding: 6px 8px; border: 1px solid rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; word-break: break-all; }\n[data-edrv-view] .edrv-rules-editor { display: flex; flex-direction: column; min-height: 0; flex: 1; gap: 6px; }\n[data-edrv-view] .edrv-rules-editor-head { display: flex; align-items: center; justify-content: space-between; gap: 6px; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-crumb { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-rules-editor-ctl { display: flex; align-items: center; gap: 6px; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-ctl-label { font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select { height: 24px; padding: 0 4px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-rules-select:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-desc-input { flex: 1; min-width: 0; }\n[data-edrv-view] .edrv-rules-input { flex: 1; min-width: 0; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 11px; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-input:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-body { flex: 1; min-height: 0; resize: none; padding: 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; line-height: 1.5; outline: none; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-rules-body:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-rules-editor-hint { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.5; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-editor-foot { display: flex; justify-content: flex-end; flex: 0 0 auto; }\n[data-edrv-view] .edrv-rules-save { height: 24px; padding: 0 14px; border: none; border-radius: 6px; background: var(--dsw-alias-brand-primary, #0f9d58); color: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
|
|
34
34
|
const tagId$1 = "dsh-vscode-mode/editor.css";
|
|
35
35
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
36
36
|
const tag = document.createElement("style");
|
|
@@ -2166,44 +2166,87 @@ window.__ModuleLoader__.load({
|
|
|
2166
2166
|
//#endregion
|
|
2167
2167
|
//#region src/client/sidebar/SidebarView.ts
|
|
2168
2168
|
/**
|
|
2169
|
-
* dsh-vscode-mode client —
|
|
2170
|
-
*
|
|
2171
|
-
*
|
|
2172
|
-
*
|
|
2169
|
+
* dsh-vscode-mode client — 侧边栏容器(活动栏常显 + 可隐藏面板区 + 拖拽调宽)。
|
|
2170
|
+
* 面板列表来自注册表(活动栏图标/徽标/激活态);最左侧图标列(活动栏)常显,
|
|
2171
|
+
* 右侧详情面板区可拖拽调宽/隐藏:visible=false 时仅保留图标列(宽 = 图标列宽),
|
|
2172
|
+
* 点击任一图标重新展开面板(onShow),底部按钮在 ◀ 收起 / ▶ 展开间切换。
|
|
2173
|
+
* 拖拽调宽下限 = minWidth prop(通用设置 sidebarMinWidth,默认 300),低于下限直接收起面板区。
|
|
2174
|
+
* 作者 ddj 2026-08-26 / 2026-09-04
|
|
2173
2175
|
*/
|
|
2174
|
-
const W_MIN = 180;
|
|
2175
2176
|
const W_MAX = 560;
|
|
2177
|
+
/** 隐藏态拖出面板区的触发阈值(px,拖过即展开并继续实时调宽)。 */
|
|
2178
|
+
const PULL_OUT_THRESHOLD = 12;
|
|
2176
2179
|
/**
|
|
2177
2180
|
* 侧边栏容器。
|
|
2178
2181
|
* @param props.registry 面板注册表(list() 提供面板顺序)
|
|
2179
2182
|
* @param props.ctx 面板共享上下文
|
|
2180
2183
|
* @param props.activePanel 当前激活面板 id
|
|
2181
2184
|
* @param props.onActive 激活面板变化回调
|
|
2185
|
+
* @param props.visible 面板区是否可见(false = 只显示活动栏)
|
|
2186
|
+
* @param props.onShow 重新展开面板区回调(活动栏图标点击/底部按钮)
|
|
2182
2187
|
* @param props.width 面板区宽度
|
|
2183
2188
|
* @param props.onWidth 宽度变化回调
|
|
2184
|
-
* @param props.onHide
|
|
2189
|
+
* @param props.onHide 收起面板区回调
|
|
2190
|
+
* @param props.minWidth 最小宽度(通用设置 sidebarMinWidth;拖拽低于它触发隐藏)
|
|
2185
2191
|
*/
|
|
2186
2192
|
function SidebarView(props) {
|
|
2187
2193
|
const panels = props.registry?.list?.() ?? [];
|
|
2188
2194
|
const ctx = props.ctx;
|
|
2189
2195
|
const activePanel = props.activePanel;
|
|
2190
2196
|
const onActive = props.onActive;
|
|
2197
|
+
const visible = props.visible !== false;
|
|
2198
|
+
const onShow = props.onShow;
|
|
2191
2199
|
const width = props.width;
|
|
2192
2200
|
const onWidth = props.onWidth;
|
|
2193
2201
|
const onHide = props.onHide;
|
|
2202
|
+
const wMin = Math.max(120, Math.min(W_MAX, Math.round(Number(props.minWidth) || 300)));
|
|
2194
2203
|
const active = panels.find((p) => p.id === activePanel) || panels[0];
|
|
2195
2204
|
const onPointerDown = (e) => {
|
|
2196
2205
|
e.preventDefault();
|
|
2197
2206
|
const startX = e.clientX;
|
|
2198
2207
|
const startW = width;
|
|
2208
|
+
const cleanup = () => {
|
|
2209
|
+
window.removeEventListener("pointermove", onMove);
|
|
2210
|
+
window.removeEventListener("pointerup", onUp);
|
|
2211
|
+
};
|
|
2212
|
+
const onUp = () => cleanup();
|
|
2199
2213
|
const onMove = (ev) => {
|
|
2200
|
-
const
|
|
2201
|
-
|
|
2214
|
+
const raw = startW + (ev.clientX - startX);
|
|
2215
|
+
if (raw < wMin) {
|
|
2216
|
+
cleanup();
|
|
2217
|
+
onHide();
|
|
2218
|
+
return;
|
|
2219
|
+
}
|
|
2220
|
+
onWidth(Math.min(W_MAX, raw));
|
|
2202
2221
|
};
|
|
2203
|
-
|
|
2222
|
+
window.addEventListener("pointermove", onMove);
|
|
2223
|
+
window.addEventListener("pointerup", onUp);
|
|
2224
|
+
};
|
|
2225
|
+
/**
|
|
2226
|
+
* 隐藏态接缝拖拽:向右拖过阈值把面板区拉出来(以记忆宽度展开),继续拖动实时调宽。
|
|
2227
|
+
* @param e pointerdown 事件
|
|
2228
|
+
*/
|
|
2229
|
+
const onSeamPointerDown = (e) => {
|
|
2230
|
+
e.preventDefault();
|
|
2231
|
+
const startX = e.clientX;
|
|
2232
|
+
const baseW = Math.max(wMin, Math.min(W_MAX, Math.round(Number(width) || wMin)));
|
|
2233
|
+
let expanded = false;
|
|
2234
|
+
let expandStartX = 0;
|
|
2235
|
+
const cleanup = () => {
|
|
2204
2236
|
window.removeEventListener("pointermove", onMove);
|
|
2205
2237
|
window.removeEventListener("pointerup", onUp);
|
|
2206
2238
|
};
|
|
2239
|
+
const onUp = () => cleanup();
|
|
2240
|
+
const onMove = (ev) => {
|
|
2241
|
+
if (!expanded) {
|
|
2242
|
+
if (ev.clientX - startX < PULL_OUT_THRESHOLD) return;
|
|
2243
|
+
expanded = true;
|
|
2244
|
+
expandStartX = ev.clientX;
|
|
2245
|
+
onShow();
|
|
2246
|
+
return;
|
|
2247
|
+
}
|
|
2248
|
+
onWidth(Math.max(wMin, Math.min(W_MAX, baseW + (ev.clientX - expandStartX))));
|
|
2249
|
+
};
|
|
2207
2250
|
window.addEventListener("pointermove", onMove);
|
|
2208
2251
|
window.addEventListener("pointerup", onUp);
|
|
2209
2252
|
};
|
|
@@ -2216,21 +2259,31 @@ window.__ModuleLoader__.load({
|
|
|
2216
2259
|
const count = typeof p.badge === "function" ? p.badge(ctx) : null;
|
|
2217
2260
|
return react.default.createElement("button", {
|
|
2218
2261
|
key: p.id,
|
|
2219
|
-
className: "edrv-rail-btn" + (active && p.id === active.id ? " edrv-rail-on" : ""),
|
|
2262
|
+
className: "edrv-rail-btn" + (visible && active && p.id === active.id ? " edrv-rail-on" : ""),
|
|
2220
2263
|
title: p.title,
|
|
2221
|
-
onClick: () =>
|
|
2264
|
+
onClick: () => {
|
|
2265
|
+
onActive(p.id);
|
|
2266
|
+
if (!visible && typeof onShow === "function") onShow();
|
|
2267
|
+
}
|
|
2222
2268
|
}, react.default.createElement("span", { className: "edrv-rail-icon" }, p.icon), count > 0 ? react.default.createElement("span", { className: "edrv-rail-badge" }, String(count)) : null);
|
|
2223
2269
|
})), react.default.createElement("button", {
|
|
2224
2270
|
className: "edrv-rail-btn",
|
|
2225
|
-
title: "
|
|
2226
|
-
onClick: onHide
|
|
2227
|
-
}, "◀"));
|
|
2271
|
+
title: (visible ? "隐藏面板区" : "展开面板区") + " (Ctrl+B)",
|
|
2272
|
+
onClick: () => visible ? onHide() : onShow?.()
|
|
2273
|
+
}, visible ? "◀" : "▶"));
|
|
2228
2274
|
return react.default.createElement("div", {
|
|
2229
|
-
className: "edrv-sidebar",
|
|
2230
|
-
style: {
|
|
2231
|
-
|
|
2275
|
+
className: "edrv-sidebar" + (visible ? "" : " edrv-sidebar-rail-only"),
|
|
2276
|
+
style: {
|
|
2277
|
+
width: visible ? width : 49,
|
|
2278
|
+
maxWidth: "100%"
|
|
2279
|
+
}
|
|
2280
|
+
}, rail, visible ? react.default.createElement("div", { className: "edrv-side-body" }, active ? active.render(ctx) : null) : null, visible ? react.default.createElement("div", {
|
|
2232
2281
|
className: "edrv-side-resize",
|
|
2233
2282
|
onPointerDown
|
|
2283
|
+
}) : react.default.createElement("div", {
|
|
2284
|
+
className: "edrv-side-resize",
|
|
2285
|
+
title: "拖拽展开面板区",
|
|
2286
|
+
onPointerDown: onSeamPointerDown
|
|
2234
2287
|
}));
|
|
2235
2288
|
}
|
|
2236
2289
|
//#endregion
|
|
@@ -2431,7 +2484,9 @@ window.__ModuleLoader__.load({
|
|
|
2431
2484
|
/** 侧边栏提示已关闭标记(全局,无会话)。 */
|
|
2432
2485
|
sideHint: "edrv.side-hint-dismissed",
|
|
2433
2486
|
/** 「性能优化」页工作区栏目展开状态(workspaceFoldCache v1,全局不按会话)。 */
|
|
2434
|
-
workspaceFold: "edrv.ws-fold.v1."
|
|
2487
|
+
workspaceFold: "edrv.ws-fold.v1.",
|
|
2488
|
+
/** 规则面板 UI 状态(RulesPanel v1:Tab 与项目工作区选择,全局不按会话)。 */
|
|
2489
|
+
rules: "edrv.rules.v1."
|
|
2435
2490
|
};
|
|
2436
2491
|
//#endregion
|
|
2437
2492
|
//#region src/client/state/viewStateCache.ts
|
|
@@ -2537,6 +2592,36 @@ window.__ModuleLoader__.load({
|
|
|
2537
2592
|
window.localStorage.setItem(KEY_PREFIX$2 + String(sessionId), serializeViewStates(states));
|
|
2538
2593
|
} catch (error) {}
|
|
2539
2594
|
}
|
|
2595
|
+
let currentMin = 300;
|
|
2596
|
+
/**
|
|
2597
|
+
* 归一化最小宽度:非法(NaN/非有限/负数)回退默认,越界夹取到 [180, 560]。
|
|
2598
|
+
* @author ddj 2026年09月04号
|
|
2599
|
+
* @param value 原始值(设置文档来的任意 JSON 值)
|
|
2600
|
+
* @returns 合法最小宽度
|
|
2601
|
+
*/
|
|
2602
|
+
function normalizeSidebarMinWidth(value) {
|
|
2603
|
+
const n = typeof value === "number" ? value : Number(value);
|
|
2604
|
+
if (!Number.isFinite(n) || n <= 0) return 300;
|
|
2605
|
+
return Math.max(180, Math.min(560, Math.round(n)));
|
|
2606
|
+
}
|
|
2607
|
+
/**
|
|
2608
|
+
* 应用设置值(client/index.ts 设置订阅同步调用)。
|
|
2609
|
+
* @author ddj 2026年09月04号
|
|
2610
|
+
* @param value 设置文档中的 sidebarMinWidth
|
|
2611
|
+
* @returns 归一化后的生效值
|
|
2612
|
+
*/
|
|
2613
|
+
function sidebarMinApply(value) {
|
|
2614
|
+
currentMin = normalizeSidebarMinWidth(value);
|
|
2615
|
+
return currentMin;
|
|
2616
|
+
}
|
|
2617
|
+
/**
|
|
2618
|
+
* 读取当前生效的最小宽度(编辑器初始/恢复/拖拽夹取共用)。
|
|
2619
|
+
* @author ddj 2026年09月04号
|
|
2620
|
+
* @returns 当前最小宽度
|
|
2621
|
+
*/
|
|
2622
|
+
function getSidebarMinWidth() {
|
|
2623
|
+
return currentMin;
|
|
2624
|
+
}
|
|
2540
2625
|
/** 路径一致(容忍相对路径大小写差异,对齐既有 sameFile 语义常用写法)。 */
|
|
2541
2626
|
function samePath(a, b) {
|
|
2542
2627
|
if (a === b) return true;
|
|
@@ -3534,7 +3619,7 @@ window.__ModuleLoader__.load({
|
|
|
3534
3619
|
const [fileIdx, setFileIdx] = react.default.useState(0);
|
|
3535
3620
|
const [tabMenu, setTabMenu] = react.default.useState(null);
|
|
3536
3621
|
const [sidebarOn, setSidebarOn] = react.default.useState(layout !== "side");
|
|
3537
|
-
const [sidebarW, setSidebarW] = react.default.useState(
|
|
3622
|
+
const [sidebarW, setSidebarW] = react.default.useState(() => getSidebarMinWidth());
|
|
3538
3623
|
const [activePanel, setActivePanel] = react.default.useState("explorer");
|
|
3539
3624
|
const [focusRequest, setFocusRequest] = react.default.useState(0);
|
|
3540
3625
|
useKeybindingsVersion();
|
|
@@ -4005,11 +4090,20 @@ window.__ModuleLoader__.load({
|
|
|
4005
4090
|
if (raw) {
|
|
4006
4091
|
const saved = JSON.parse(raw);
|
|
4007
4092
|
if (typeof saved.on === "boolean") setSidebarOn(saved.on);
|
|
4008
|
-
if (typeof saved.width === "number") setSidebarW(Math.max(
|
|
4093
|
+
if (typeof saved.width === "number") setSidebarW(Math.max(getSidebarMinWidth(), Math.min(560, saved.width)));
|
|
4009
4094
|
if (typeof saved.panel === "string") setActivePanel(saved.panel);
|
|
4010
4095
|
}
|
|
4011
4096
|
} catch (e) {}
|
|
4012
4097
|
}, [sessionId, sidebarKey]);
|
|
4098
|
+
const [sidebarMinW, setSidebarMinW] = react.default.useState(() => getSidebarMinWidth());
|
|
4099
|
+
react.default.useEffect(() => {
|
|
4100
|
+
const onMinChange = () => {
|
|
4101
|
+
setSidebarMinW(getSidebarMinWidth());
|
|
4102
|
+
setSidebarW((w) => Math.max(getSidebarMinWidth(), w));
|
|
4103
|
+
};
|
|
4104
|
+
window.addEventListener("edrv:sidebar-min-width", onMinChange);
|
|
4105
|
+
return () => window.removeEventListener("edrv:sidebar-min-width", onMinChange);
|
|
4106
|
+
}, []);
|
|
4013
4107
|
react.default.useEffect(() => {
|
|
4014
4108
|
if (!sessionId) return;
|
|
4015
4109
|
try {
|
|
@@ -4888,7 +4982,7 @@ window.__ModuleLoader__.load({
|
|
|
4888
4982
|
onClick: navForward
|
|
4889
4983
|
}, "→"), react.default.createElement("button", {
|
|
4890
4984
|
className: "edrv-chip-btn" + (sidebarOn ? " edrv-chip-on" : ""),
|
|
4891
|
-
title: "
|
|
4985
|
+
title: "切换面板区 (" + (chordOf("edrv.toggleSidebar") ?? "Ctrl+B") + "),图标列常显",
|
|
4892
4986
|
onClick: () => setSidebarOn((v) => !v)
|
|
4893
4987
|
}, "☰"), react.default.createElement("button", {
|
|
4894
4988
|
className: "edrv-chip-btn",
|
|
@@ -5086,6 +5180,7 @@ window.__ModuleLoader__.load({
|
|
|
5086
5180
|
const sidebarPanels = props.sidebarPanels;
|
|
5087
5181
|
const sidebarCtx = {
|
|
5088
5182
|
sessionId,
|
|
5183
|
+
cwd: props.sessions?.list?.getSnapshot?.()?.byId?.[sessionId]?.cwd ?? null,
|
|
5089
5184
|
openFile: (p) => openFile(p, false),
|
|
5090
5185
|
openFileAt,
|
|
5091
5186
|
activePath: active,
|
|
@@ -5132,14 +5227,17 @@ window.__ModuleLoader__.load({
|
|
|
5132
5227
|
overflow: "hidden"
|
|
5133
5228
|
}
|
|
5134
5229
|
}, pathBar, tabRow, sideHintEl, editorArea, lspFooter);
|
|
5135
|
-
const editorRow = react.default.createElement("div", { className: "edrv-editor-row" },
|
|
5230
|
+
const editorRow = react.default.createElement("div", { className: "edrv-editor-row" }, sidebarPanels ? react.default.createElement(SidebarView, {
|
|
5136
5231
|
registry: sidebarPanels,
|
|
5137
5232
|
ctx: sidebarCtx,
|
|
5138
5233
|
activePanel,
|
|
5139
5234
|
onActive: setActivePanel,
|
|
5235
|
+
visible: sidebarOn,
|
|
5236
|
+
onShow: () => setSidebarOn(true),
|
|
5140
5237
|
width: sidebarW,
|
|
5141
5238
|
onWidth: setSidebarW,
|
|
5142
|
-
onHide: () => setSidebarOn(false)
|
|
5239
|
+
onHide: () => setSidebarOn(false),
|
|
5240
|
+
minWidth: sidebarMinW
|
|
5143
5241
|
}) : null, mainCol);
|
|
5144
5242
|
const baseStyle = {
|
|
5145
5243
|
minHeight: 0,
|
|
@@ -6909,7 +7007,7 @@ window.__ModuleLoader__.load({
|
|
|
6909
7007
|
}));
|
|
6910
7008
|
return react.default.createElement("section", { className: "vsm-project" }, head, body);
|
|
6911
7009
|
}
|
|
6912
|
-
/** 通用设置:选择当前对话文件链接的打开器 +
|
|
7010
|
+
/** 通用设置:选择当前对话文件链接的打开器 + 开发形态开关 + 编辑器布局(侧边栏最小宽度)。 */
|
|
6913
7011
|
function GeneralSettings({ registry }) {
|
|
6914
7012
|
const [tool, setTool] = react.default.useState(AUTO_OPEN_TOOL);
|
|
6915
7013
|
const [busy, setBusy] = react.default.useState(false);
|
|
@@ -6917,6 +7015,8 @@ window.__ModuleLoader__.load({
|
|
|
6917
7015
|
const [devForm, setDevForm] = react.default.useState(null);
|
|
6918
7016
|
const [devBusy, setDevBusy] = react.default.useState(false);
|
|
6919
7017
|
const [devMessage, setDevMessage] = react.default.useState("");
|
|
7018
|
+
const [minW, setMinW] = react.default.useState(300);
|
|
7019
|
+
const [minDraft, setMinDraft] = react.default.useState(null);
|
|
6920
7020
|
const settings = react.default.useContext(SettingsContext);
|
|
6921
7021
|
const snapshot = settings?.getSnapshot?.();
|
|
6922
7022
|
const loading = !snapshot || snapshot.status === "loading";
|
|
@@ -6924,8 +7024,10 @@ window.__ModuleLoader__.load({
|
|
|
6924
7024
|
const notReady = snapshot?.status !== "ready";
|
|
6925
7025
|
react.default.useEffect(() => {
|
|
6926
7026
|
const onChange = () => {
|
|
6927
|
-
const
|
|
7027
|
+
const snap = settings?.getSnapshot?.();
|
|
7028
|
+
const next = snap?.value?.fileOpenTool;
|
|
6928
7029
|
if (typeof next === "string") setTool(next);
|
|
7030
|
+
setMinW(normalizeSidebarMinWidth(snap?.value?.sidebarMinWidth));
|
|
6929
7031
|
};
|
|
6930
7032
|
onChange();
|
|
6931
7033
|
return settings?.subscribe?.(onChange);
|
|
@@ -6946,6 +7048,25 @@ window.__ModuleLoader__.load({
|
|
|
6946
7048
|
}
|
|
6947
7049
|
settings.set("fileOpenTool", value).catch((e) => setError(String(e))).finally(() => setBusy(false));
|
|
6948
7050
|
};
|
|
7051
|
+
/** 提交侧边栏最小宽度(归一化夹取 180–560 后持久化)。 */
|
|
7052
|
+
const saveMinW = (raw) => {
|
|
7053
|
+
const next = normalizeSidebarMinWidth(raw);
|
|
7054
|
+
setMinW(next);
|
|
7055
|
+
setBusy(true);
|
|
7056
|
+
setError("");
|
|
7057
|
+
if (!settings?.set) {
|
|
7058
|
+
setError("设置服务不可用");
|
|
7059
|
+
setBusy(false);
|
|
7060
|
+
return;
|
|
7061
|
+
}
|
|
7062
|
+
settings.set("sidebarMinWidth", next).catch((e) => setError(String(e))).finally(() => setBusy(false));
|
|
7063
|
+
};
|
|
7064
|
+
/** 结束输入(blur/Enter)时提交草稿。 */
|
|
7065
|
+
const commitMinW = () => {
|
|
7066
|
+
if (minDraft === null) return;
|
|
7067
|
+
setMinDraft(null);
|
|
7068
|
+
saveMinW(minDraft);
|
|
7069
|
+
};
|
|
6949
7070
|
const closeDevForm = () => {
|
|
6950
7071
|
if (!window.confirm("关闭开发形态:插件将切换为正式版安装(版本依赖 + 删除工作区链接),pnpm 装配后需重启 DSH 生效。确认关闭?")) return;
|
|
6951
7072
|
setDevBusy(true);
|
|
@@ -6981,7 +7102,20 @@ window.__ModuleLoader__.load({
|
|
|
6981
7102
|
}, options.map((item) => react.default.createElement("option", {
|
|
6982
7103
|
key: item.id,
|
|
6983
7104
|
value: item.id
|
|
6984
|
-
}, item.label))), loading && react.default.createElement("small", null, "读取中…")), devFormRow)))
|
|
7105
|
+
}, item.label))), loading && react.default.createElement("small", null, "读取中…")), devFormRow)), react.default.createElement("section", { className: "vsm-panel" }, react.default.createElement("h3", { className: "vsm-panel-title" }, "编辑器"), react.default.createElement("div", { className: "vsm-panel-body" }, react.default.createElement("label", { className: "vsm-general-row" }, react.default.createElement("span", null, "侧边栏最小宽度"), react.default.createElement("input", {
|
|
7106
|
+
type: "number",
|
|
7107
|
+
min: 180,
|
|
7108
|
+
max: 560,
|
|
7109
|
+
step: 10,
|
|
7110
|
+
value: minDraft ?? minW,
|
|
7111
|
+
disabled: loading || unavailable || notReady || busy || snapshot?.writable === false,
|
|
7112
|
+
title: "180–560 px;拖拽侧边栏低于该宽度时自动隐藏",
|
|
7113
|
+
onChange: (event) => setMinDraft(event.target.value),
|
|
7114
|
+
onBlur: commitMinW,
|
|
7115
|
+
onKeyDown: (event) => {
|
|
7116
|
+
if (event.key === "Enter") commitMinW();
|
|
7117
|
+
}
|
|
7118
|
+
}), react.default.createElement("small", null, "180–560 px;拖拽低于该宽度自动隐藏")))));
|
|
6985
7119
|
}
|
|
6986
7120
|
/** 兼容性小节:host 报告(RPC compat)+ 客户端本地适配项。 */
|
|
6987
7121
|
function CompatSection({ getSummary }) {
|
|
@@ -7368,7 +7502,8 @@ window.__ModuleLoader__.load({
|
|
|
7368
7502
|
addToConversation: props?.addToConversation,
|
|
7369
7503
|
sidebarPanels: props?.sidebarPanels,
|
|
7370
7504
|
outlineSources: props?.outlineSources,
|
|
7371
|
-
fileMenuItems: props?.fileMenuItems
|
|
7505
|
+
fileMenuItems: props?.fileMenuItems,
|
|
7506
|
+
sessions: props?.sessions
|
|
7372
7507
|
});
|
|
7373
7508
|
}
|
|
7374
7509
|
//#endregion
|
|
@@ -8439,10 +8574,709 @@ window.__ModuleLoader__.load({
|
|
|
8439
8574
|
})), optsBar, filterRows, summary, warnBanner, body);
|
|
8440
8575
|
}
|
|
8441
8576
|
//#endregion
|
|
8577
|
+
//#region src/client/rulesMdc.ts
|
|
8578
|
+
/**
|
|
8579
|
+
* 去除值两侧成对引号(与 host stripQuotes 一致)。
|
|
8580
|
+
* @author ddj 2026年09月07号
|
|
8581
|
+
* @param raw 原始值
|
|
8582
|
+
* @returns 去引号后的值
|
|
8583
|
+
*/
|
|
8584
|
+
function stripQuotes(raw) {
|
|
8585
|
+
const value = raw.trim();
|
|
8586
|
+
if (value.length >= 2 && (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'"))) return value.slice(1, -1);
|
|
8587
|
+
return value;
|
|
8588
|
+
}
|
|
8589
|
+
/**
|
|
8590
|
+
* 解析 .mdc 全文:首行 --- 且 100 行内有闭合 --- 才视为 frontmatter;
|
|
8591
|
+
* 已知键 description/alwaysApply/globs/enabled,其余原行进 fmExtra;永不抛错。
|
|
8592
|
+
* @author ddj 2026年09月07号
|
|
8593
|
+
* @param text 文件全文
|
|
8594
|
+
* @returns 解析结果
|
|
8595
|
+
*/
|
|
8596
|
+
function parseRuleFm(text) {
|
|
8597
|
+
const bom = text.startsWith("");
|
|
8598
|
+
const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
|
|
8599
|
+
const none = {
|
|
8600
|
+
type: "manual",
|
|
8601
|
+
description: "",
|
|
8602
|
+
alwaysApply: false,
|
|
8603
|
+
globs: [],
|
|
8604
|
+
enabled: true,
|
|
8605
|
+
hasFm: false,
|
|
8606
|
+
body: text.replace(/^\uFEFF/, ""),
|
|
8607
|
+
fmExtra: [],
|
|
8608
|
+
bom,
|
|
8609
|
+
hasEnabledLine: false
|
|
8610
|
+
};
|
|
8611
|
+
if (lines[0]?.trim() !== "---") return none;
|
|
8612
|
+
let close = -1;
|
|
8613
|
+
for (let i = 1; i < lines.length && i <= 101; i++) if (lines[i].trim() === "---") {
|
|
8614
|
+
close = i;
|
|
8615
|
+
break;
|
|
8616
|
+
}
|
|
8617
|
+
if (close < 0) return none;
|
|
8618
|
+
const parsed = {
|
|
8619
|
+
type: "manual",
|
|
8620
|
+
description: "",
|
|
8621
|
+
alwaysApply: false,
|
|
8622
|
+
globs: [],
|
|
8623
|
+
enabled: true,
|
|
8624
|
+
hasFm: true,
|
|
8625
|
+
body: lines.slice(close + 1).join("\n"),
|
|
8626
|
+
fmExtra: [],
|
|
8627
|
+
bom,
|
|
8628
|
+
hasEnabledLine: false
|
|
8629
|
+
};
|
|
8630
|
+
for (let i = 1; i < close; i++) {
|
|
8631
|
+
const match = /^([A-Za-z_-]+)[ \t]*:[ \t]?(.*)$/.exec(lines[i]);
|
|
8632
|
+
if (!match) {
|
|
8633
|
+
parsed.fmExtra.push(lines[i]);
|
|
8634
|
+
continue;
|
|
8635
|
+
}
|
|
8636
|
+
const [, key, raw] = match;
|
|
8637
|
+
if (key === "description") parsed.description = stripQuotes(raw);
|
|
8638
|
+
else if (key === "alwaysApply") parsed.alwaysApply = stripQuotes(raw).toLowerCase() === "true";
|
|
8639
|
+
else if (key === "enabled") {
|
|
8640
|
+
parsed.enabled = stripQuotes(raw).toLowerCase() !== "false";
|
|
8641
|
+
parsed.hasEnabledLine = true;
|
|
8642
|
+
} else if (key === "globs") parsed.globs = parseGlobsValue(raw, lines, i, close);
|
|
8643
|
+
else parsed.fmExtra.push(lines[i]);
|
|
8644
|
+
}
|
|
8645
|
+
parsed.type = fmTypeOf(parsed);
|
|
8646
|
+
return parsed;
|
|
8647
|
+
}
|
|
8648
|
+
/**
|
|
8649
|
+
* 解析 globs 值:内联逗号分隔串,或空值后接 YAML 短横列表(与 host parseGlobs 一致)。
|
|
8650
|
+
* @author ddj 2026年09月07号
|
|
8651
|
+
* @param value 内联值
|
|
8652
|
+
* @param lines 全文行
|
|
8653
|
+
* @param start globs 行下标
|
|
8654
|
+
* @param close 闭合 --- 下标
|
|
8655
|
+
* @returns glob 数组
|
|
8656
|
+
*/
|
|
8657
|
+
function parseGlobsValue(value, lines, start, close) {
|
|
8658
|
+
const inline = stripQuotes(value);
|
|
8659
|
+
if (inline) return inline.split(",").map((item) => stripQuotes(item)).filter(Boolean);
|
|
8660
|
+
const list = [];
|
|
8661
|
+
for (let j = start + 1; j < close; j++) {
|
|
8662
|
+
const item = /^[ \t]*-[ \t]*(.+)$/.exec(lines[j]);
|
|
8663
|
+
if (!item) break;
|
|
8664
|
+
list.push(stripQuotes(item[1]));
|
|
8665
|
+
}
|
|
8666
|
+
return list;
|
|
8667
|
+
}
|
|
8668
|
+
/**
|
|
8669
|
+
* 由 frontmatter 推导类型:alwaysApply=true → 总是;有 globs → 自动;否则手动。
|
|
8670
|
+
* @author ddj 2026年09月07号
|
|
8671
|
+
* @param parsed 解析结果
|
|
8672
|
+
* @returns 规则类型
|
|
8673
|
+
*/
|
|
8674
|
+
function fmTypeOf(parsed) {
|
|
8675
|
+
if (parsed.alwaysApply) return "always";
|
|
8676
|
+
if (parsed.globs.length) return "auto";
|
|
8677
|
+
return "manual";
|
|
8678
|
+
}
|
|
8679
|
+
/**
|
|
8680
|
+
* 按最新控件值重写 frontmatter:known 键固定顺序 + fmExtra + 闭合 --- + 原 body;
|
|
8681
|
+
* 无 frontmatter 且目标为手动时:有描述则新建仅含描述的 frontmatter,否则原文返回。
|
|
8682
|
+
* @author ddj 2026年09月07号
|
|
8683
|
+
* @param parsed parseRuleFm 的结果(必须来自同一文本)
|
|
8684
|
+
* @param next 控件最新值
|
|
8685
|
+
* @returns 重写后的全文
|
|
8686
|
+
*/
|
|
8687
|
+
function applyRuleMeta(parsed, next) {
|
|
8688
|
+
if (!parsed.hasFm && next.type === "manual") {
|
|
8689
|
+
if (!next.description.trim()) return (parsed.bom ? "" : "") + parsed.body;
|
|
8690
|
+
return (parsed.bom ? "" : "") + [
|
|
8691
|
+
"---",
|
|
8692
|
+
"description: " + next.description.trim(),
|
|
8693
|
+
"---"
|
|
8694
|
+
].join("\n") + "\n" + parsed.body;
|
|
8695
|
+
}
|
|
8696
|
+
const lines = ["---"];
|
|
8697
|
+
lines.push("description: " + next.description.trim());
|
|
8698
|
+
if (next.type === "always") lines.push("alwaysApply: true");
|
|
8699
|
+
if (next.type === "auto") lines.push("globs: " + next.globs.join(", "));
|
|
8700
|
+
if (parsed.hasEnabledLine) lines.push("enabled: " + (parsed.enabled ? "true" : "false"));
|
|
8701
|
+
lines.push(...parsed.fmExtra);
|
|
8702
|
+
lines.push("---");
|
|
8703
|
+
return (parsed.bom ? "" : "") + lines.join("\n") + "\n" + parsed.body;
|
|
8704
|
+
}
|
|
8705
|
+
//#endregion
|
|
8706
|
+
//#region src/client/sidebar/panels/RulesPanel.ts
|
|
8707
|
+
/**
|
|
8708
|
+
* dsh-vscode-mode client — 侧边栏「规则」面板(Codebuddy 规则管理形态)。
|
|
8709
|
+
* 双 Tab:用户规则(~/.dsh/rules/)与项目规则(<工作区>/.dsh/rules/);
|
|
8710
|
+
* 列表行 = 文件名 + 相对提示,第二行类型徽标与描述,右侧 编辑/删除 图标 + 滑动启用开关;
|
|
8711
|
+
* 新建/编辑 = 顶部面包屑 + 规则类型下拉(总是/自动/手动)+ 描述/globs 控件,与原始 .mdc
|
|
8712
|
+
* 文本域双向同步(控件改写 frontmatter,文本域回读控件),保存走 rules.save。
|
|
8713
|
+
* 作者 ddj 2026年09月03号(2026年09月07号 交互性调整)
|
|
8714
|
+
*/
|
|
8715
|
+
/** 新建规则模板(frontmatter 字段与 host parseRuleMdc 对齐)。 */
|
|
8716
|
+
const NEW_TEMPLATE = "---\ndescription: \nalwaysApply: true\n---\n\n";
|
|
8717
|
+
const TYPE_LABEL = {
|
|
8718
|
+
always: "总是",
|
|
8719
|
+
auto: "自动",
|
|
8720
|
+
manual: "手动"
|
|
8721
|
+
};
|
|
8722
|
+
/** 列表行描述的基础显示上限(字符数;宽面板下的封顶值,超出省略号)。 */
|
|
8723
|
+
const DESC_MAX = 24;
|
|
8724
|
+
/** 动态字数下限(极窄面板的保底可见字符数)。 */
|
|
8725
|
+
const DESC_CAP_MIN = 8;
|
|
8726
|
+
/** 动态字数估算:描述之外的行内固定占用 px(动作区/类型标签/徽标/间距/省略余量)。 */
|
|
8727
|
+
const DESC_RESERVE_PX = 210;
|
|
8728
|
+
/** 动态字数估算:单字符平均宽度 px(11px 字号,中英混排)。 */
|
|
8729
|
+
const DESC_CHAR_PX = 10;
|
|
8730
|
+
/** 窄面板阈值:低于此宽度隐藏路径提示(编辑界面面包屑与悬停仍有完整路径)。 */
|
|
8731
|
+
const NARROW_W = 420;
|
|
8732
|
+
/**
|
|
8733
|
+
* 读 localStorage(损坏/不可用安全)。
|
|
8734
|
+
* @author ddj 2026年09月03号
|
|
8735
|
+
* @param key 键
|
|
8736
|
+
* @returns 值或 null
|
|
8737
|
+
*/
|
|
8738
|
+
function readLocal(key) {
|
|
8739
|
+
try {
|
|
8740
|
+
return localStorage.getItem(key);
|
|
8741
|
+
} catch (e) {
|
|
8742
|
+
return null;
|
|
8743
|
+
}
|
|
8744
|
+
}
|
|
8745
|
+
/**
|
|
8746
|
+
* 写 localStorage(不可用安全)。
|
|
8747
|
+
* @author ddj 2026年09月03号
|
|
8748
|
+
* @param key 键
|
|
8749
|
+
* @param value 值
|
|
8750
|
+
*/
|
|
8751
|
+
function writeLocal(key, value) {
|
|
8752
|
+
try {
|
|
8753
|
+
localStorage.setItem(key, value);
|
|
8754
|
+
} catch (e) {}
|
|
8755
|
+
}
|
|
8756
|
+
/**
|
|
8757
|
+
* 类型徽标(总是=绿 / 自动=蓝 / 手动=灰)。
|
|
8758
|
+
* @author ddj 2026年09月03号
|
|
8759
|
+
* @param type 规则类型
|
|
8760
|
+
* @returns 徽标元素
|
|
8761
|
+
*/
|
|
8762
|
+
function typeBadge(type) {
|
|
8763
|
+
return react.default.createElement("span", { className: "edrv-rules-type edrv-rules-type-" + type }, TYPE_LABEL[type] ?? type);
|
|
8764
|
+
}
|
|
8765
|
+
/**
|
|
8766
|
+
* 按字符上限截断列表行描述,超出以省略号收尾(上限随面板宽度动态变化;
|
|
8767
|
+
* 窄面板下 CSS 省略号仍会按像素提前截断,二者取更小)。
|
|
8768
|
+
* @author ddj 2026年09月07号
|
|
8769
|
+
* @param text 完整描述
|
|
8770
|
+
* @param cap 本帧字符上限
|
|
8771
|
+
* @returns 截断后的展示文本
|
|
8772
|
+
*/
|
|
8773
|
+
function clampDesc(text, cap) {
|
|
8774
|
+
const chars = Array.from(String(text ?? ""));
|
|
8775
|
+
const limit = Math.max(4, Number(cap) || DESC_MAX);
|
|
8776
|
+
return chars.length > limit ? chars.slice(0, limit).join("") + "…" : chars.join("");
|
|
8777
|
+
}
|
|
8778
|
+
/**
|
|
8779
|
+
* 由面板宽度估算描述可用字符数:随宽度动态变化,并与基础上限取小、极窄时保底。
|
|
8780
|
+
* @author ddj 2026年09月07号
|
|
8781
|
+
* @param panelWidth 面板内容宽度(px)
|
|
8782
|
+
* @returns 本帧描述字符上限
|
|
8783
|
+
*/
|
|
8784
|
+
function descCapOf(panelWidth) {
|
|
8785
|
+
const byWidth = Math.floor((Number(panelWidth) - DESC_RESERVE_PX) / DESC_CHAR_PX);
|
|
8786
|
+
return Math.max(DESC_CAP_MIN, Math.min(DESC_MAX, byWidth));
|
|
8787
|
+
}
|
|
8788
|
+
/**
|
|
8789
|
+
* 编辑图标(线性铅笔,与 DiffBox chevron 同风格:currentColor 描边装饰图)。
|
|
8790
|
+
* @author ddj 2026年09月07号
|
|
8791
|
+
* @returns 13×13 装饰性 SVG
|
|
8792
|
+
*/
|
|
8793
|
+
function pencilIcon() {
|
|
8794
|
+
return react.default.createElement("svg", {
|
|
8795
|
+
width: 13,
|
|
8796
|
+
height: 13,
|
|
8797
|
+
viewBox: "0 0 24 24",
|
|
8798
|
+
fill: "none",
|
|
8799
|
+
"aria-hidden": true,
|
|
8800
|
+
focusable: false
|
|
8801
|
+
}, react.default.createElement("path", {
|
|
8802
|
+
d: "M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z",
|
|
8803
|
+
stroke: "currentColor",
|
|
8804
|
+
strokeWidth: 2,
|
|
8805
|
+
strokeLinecap: "round",
|
|
8806
|
+
strokeLinejoin: "round"
|
|
8807
|
+
}));
|
|
8808
|
+
}
|
|
8809
|
+
/**
|
|
8810
|
+
* 删除图标(线性垃圾桶,风格同 pencilIcon)。
|
|
8811
|
+
* @author ddj 2026年09月07号
|
|
8812
|
+
* @returns 13×13 装饰性 SVG
|
|
8813
|
+
*/
|
|
8814
|
+
function trashIcon() {
|
|
8815
|
+
return react.default.createElement("svg", {
|
|
8816
|
+
width: 13,
|
|
8817
|
+
height: 13,
|
|
8818
|
+
viewBox: "0 0 24 24",
|
|
8819
|
+
fill: "none",
|
|
8820
|
+
"aria-hidden": true,
|
|
8821
|
+
focusable: false
|
|
8822
|
+
}, react.default.createElement("path", {
|
|
8823
|
+
d: "M3 6h18M8 6V4a2 2 0 0 1 2-2h4a2 2 0 0 1 2 2v2m3 0v14a2 2 0 0 1-2 2H7a2 2 0 0 1-2-2V6h14zM10 11v6M14 11v6",
|
|
8824
|
+
stroke: "currentColor",
|
|
8825
|
+
strokeWidth: 2,
|
|
8826
|
+
strokeLinecap: "round",
|
|
8827
|
+
strokeLinejoin: "round"
|
|
8828
|
+
}));
|
|
8829
|
+
}
|
|
8830
|
+
/**
|
|
8831
|
+
* 逗号分隔的 globs 输入串 → 数组(去空项)。
|
|
8832
|
+
* @author ddj 2026年09月07号
|
|
8833
|
+
* @param text 输入串
|
|
8834
|
+
* @returns glob 数组
|
|
8835
|
+
*/
|
|
8836
|
+
function globList(text) {
|
|
8837
|
+
return String(text ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
8838
|
+
}
|
|
8839
|
+
/**
|
|
8840
|
+
* 由控件值重建 .mdc 全文:frontmatter 按类型/描述/globs 重写,正文与其余键不动。
|
|
8841
|
+
* @author ddj 2026年09月07号
|
|
8842
|
+
* @param base 当前全文
|
|
8843
|
+
* @param fmType 目标类型(always/auto/manual)
|
|
8844
|
+
* @param desc 描述文本
|
|
8845
|
+
* @param globsText globs 输入串
|
|
8846
|
+
* @returns 重写后的全文
|
|
8847
|
+
*/
|
|
8848
|
+
function rebuildContent(base, fmType, desc, globsText) {
|
|
8849
|
+
return applyRuleMeta(parseRuleFm(base), {
|
|
8850
|
+
type: fmType,
|
|
8851
|
+
description: desc,
|
|
8852
|
+
globs: globList(globsText)
|
|
8853
|
+
});
|
|
8854
|
+
}
|
|
8855
|
+
/**
|
|
8856
|
+
* 渲染一条规则行:左侧两行(文件名+相对提示 / 类型徽标+描述),右侧 编辑/删除 图标 + 滑动开关。
|
|
8857
|
+
* @author ddj 2026年09月03号
|
|
8858
|
+
* @param props.rule 规则元信息
|
|
8859
|
+
* @param props.onEdit 编辑回调
|
|
8860
|
+
* @param props.onRemove 删除回调
|
|
8861
|
+
* @param props.onToggle 开关回调
|
|
8862
|
+
* @returns 行元素
|
|
8863
|
+
*/
|
|
8864
|
+
function RuleRow(props) {
|
|
8865
|
+
const rule = props.rule;
|
|
8866
|
+
const desc = [rule.error ? "解析失败:" + rule.error : null, rule.description || (rule.type === "auto" ? "globs: " + rule.globs.join(", ") : "")].filter(Boolean).join(" · ");
|
|
8867
|
+
return react.default.createElement("div", { className: "edrv-rules-row" + (rule.enabled ? "" : " off") }, react.default.createElement("div", {
|
|
8868
|
+
className: "edrv-rules-main",
|
|
8869
|
+
onClick: () => props.onEdit(rule),
|
|
8870
|
+
title: rule.absPath
|
|
8871
|
+
}, react.default.createElement("div", { className: "edrv-rules-line1" }, react.default.createElement("span", { className: "edrv-rules-file" }, rule.file), !props.narrow ? react.default.createElement("span", { className: "edrv-rules-path" }, "[" + rule.relHint + rule.file + "]") : null, !rule.enabled ? react.default.createElement("span", { className: "edrv-rules-offtag" }, "已停用") : null), react.default.createElement("div", { className: "edrv-rules-sub" }, react.default.createElement("span", { className: "edrv-rules-sublabel" }, "类型:"), typeBadge(rule.type), desc ? react.default.createElement("span", {
|
|
8872
|
+
className: "edrv-rules-desc",
|
|
8873
|
+
title: desc
|
|
8874
|
+
}, clampDesc(desc, props.descCap)) : null)), react.default.createElement("div", { className: "edrv-rules-actions" }, react.default.createElement("button", {
|
|
8875
|
+
className: "edrv-rules-act",
|
|
8876
|
+
title: "编辑",
|
|
8877
|
+
onClick: () => props.onEdit(rule)
|
|
8878
|
+
}, pencilIcon()), react.default.createElement("button", {
|
|
8879
|
+
className: "edrv-rules-act",
|
|
8880
|
+
title: "删除",
|
|
8881
|
+
onClick: () => props.onRemove(rule)
|
|
8882
|
+
}, trashIcon()), react.default.createElement("button", {
|
|
8883
|
+
className: "edrv-rules-switch" + (rule.enabled ? " on" : ""),
|
|
8884
|
+
role: "switch",
|
|
8885
|
+
"aria-checked": rule.enabled,
|
|
8886
|
+
title: rule.enabled ? "已启用(点击停用)" : "已停用(点击启用)",
|
|
8887
|
+
onClick: () => props.onToggle(rule)
|
|
8888
|
+
}, react.default.createElement("span", { className: "edrv-rules-knob" }))));
|
|
8889
|
+
}
|
|
8890
|
+
/**
|
|
8891
|
+
* 新建/编辑表单:面包屑头部 + 规则类型下拉/描述/globs 控件行 + 原始 .mdc 文本域 + 保存/取消。
|
|
8892
|
+
* @author ddj 2026年09月03号
|
|
8893
|
+
* @param props.form 表单状态(mode/scope/workspacePath/relHint/file/content/fmType/desc/globs/error/saving)
|
|
8894
|
+
* @param props.onType 类型下拉变更回调
|
|
8895
|
+
* @param props.onDesc 描述输入回调
|
|
8896
|
+
* @param props.onGlobs globs 输入回调
|
|
8897
|
+
* @param props.onBody 文本域编辑回调
|
|
8898
|
+
* @param props.onSave 保存回调
|
|
8899
|
+
* @param props.onCancel 取消回调
|
|
8900
|
+
* @returns 表单元素
|
|
8901
|
+
*/
|
|
8902
|
+
function RuleEditor(props) {
|
|
8903
|
+
const form = props.form;
|
|
8904
|
+
const isNew = form.mode === "new";
|
|
8905
|
+
const crumb = (form.scope === "project" ? "项目规则" : "用户规则") + " > " + form.relHint + " > " + (form.file || "新建规则.mdc");
|
|
8906
|
+
return react.default.createElement("div", { className: "edrv-rules-editor" }, react.default.createElement("div", { className: "edrv-rules-editor-head" }, react.default.createElement("span", {
|
|
8907
|
+
className: "edrv-rules-crumb",
|
|
8908
|
+
title: crumb
|
|
8909
|
+
}, crumb), react.default.createElement("button", {
|
|
8910
|
+
className: "edrv-rules-act",
|
|
8911
|
+
title: "取消",
|
|
8912
|
+
onClick: props.onCancel
|
|
8913
|
+
}, "✕")), react.default.createElement("div", { className: "edrv-rules-editor-ctl" }, react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "规则类型"), react.default.createElement("select", {
|
|
8914
|
+
className: "edrv-rules-select",
|
|
8915
|
+
value: form.fmType,
|
|
8916
|
+
onChange: props.onType
|
|
8917
|
+
}, Object.keys(TYPE_LABEL).map((key) => react.default.createElement("option", {
|
|
8918
|
+
key,
|
|
8919
|
+
value: key
|
|
8920
|
+
}, TYPE_LABEL[key]))), react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "描述"), react.default.createElement("input", {
|
|
8921
|
+
className: "edrv-rules-input edrv-rules-desc-input",
|
|
8922
|
+
value: form.desc,
|
|
8923
|
+
spellCheck: false,
|
|
8924
|
+
placeholder: isNew ? "规则用途说明(写入 frontmatter description)" : "规则用途说明",
|
|
8925
|
+
onChange: props.onDesc
|
|
8926
|
+
})), form.fmType === "auto" ? react.default.createElement("div", { className: "edrv-rules-editor-ctl" }, react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "globs"), react.default.createElement("input", {
|
|
8927
|
+
className: "edrv-rules-input",
|
|
8928
|
+
value: form.globs,
|
|
8929
|
+
spellCheck: false,
|
|
8930
|
+
placeholder: "src/**/*.ts, *.md(逗号分隔,命中才注入)",
|
|
8931
|
+
onChange: props.onGlobs
|
|
8932
|
+
})) : null, react.default.createElement("textarea", {
|
|
8933
|
+
className: "edrv-rules-body",
|
|
8934
|
+
spellCheck: false,
|
|
8935
|
+
value: form.content,
|
|
8936
|
+
onChange: props.onBody
|
|
8937
|
+
}), react.default.createElement("div", { className: "edrv-rules-editor-hint" }, "类型/描述/globs 与 frontmatter 双向同步;enabled 与其余键原样保留;无 frontmatter 的纯 markdown 视为「手动」规则"), form.error ? react.default.createElement("div", { className: "edrv-rules-err" }, form.error) : null, react.default.createElement("div", { className: "edrv-rules-editor-foot" }, react.default.createElement("button", {
|
|
8938
|
+
className: "edrv-rules-save",
|
|
8939
|
+
disabled: form.saving,
|
|
8940
|
+
onClick: props.onSave
|
|
8941
|
+
}, form.saving ? "保存中…" : "保存")));
|
|
8942
|
+
}
|
|
8943
|
+
/**
|
|
8944
|
+
* 规则面板主体。
|
|
8945
|
+
* @param props.ctx 面板共享上下文(notify 可选)
|
|
8946
|
+
*/
|
|
8947
|
+
function RulesPanel(props) {
|
|
8948
|
+
const ctx = props?.ctx;
|
|
8949
|
+
const notify = ctx?.notify ?? ((message) => {});
|
|
8950
|
+
const cwd = ctx?.cwd ?? null;
|
|
8951
|
+
const [tab, setTab] = react.default.useState(() => readLocal(CACHE_KEY.rules + "tab") === "project" ? "project" : "user");
|
|
8952
|
+
const [data, setData] = react.default.useState(null);
|
|
8953
|
+
const [error, setError] = react.default.useState("");
|
|
8954
|
+
const panelRef = react.default.useRef(null);
|
|
8955
|
+
const [panelW, setPanelW] = react.default.useState(0);
|
|
8956
|
+
const [form, setForm] = react.default.useState(null);
|
|
8957
|
+
const mountedRef = react.default.useRef(true);
|
|
8958
|
+
/**
|
|
8959
|
+
* 当前工作区对应的项目聚合(按 ctx.cwd 自动匹配;无会话/未注册返回 null)。
|
|
8960
|
+
* @returns RuleProject 或 null
|
|
8961
|
+
*/
|
|
8962
|
+
const activeProject = () => {
|
|
8963
|
+
if (!cwd) return null;
|
|
8964
|
+
return (data?.projects ?? []).find((p) => p.workspacePath === cwd) ?? null;
|
|
8965
|
+
};
|
|
8966
|
+
/** 拉取规则总列表(rules.list)。 */
|
|
8967
|
+
const load = () => {
|
|
8968
|
+
rpc("rules.list", {}).then((res) => {
|
|
8969
|
+
if (!mountedRef.current) return;
|
|
8970
|
+
if (res && res.ok) {
|
|
8971
|
+
setData(res);
|
|
8972
|
+
setError("");
|
|
8973
|
+
} else setError(res?.error ?? "读取规则失败");
|
|
8974
|
+
}).catch((e) => {
|
|
8975
|
+
if (mountedRef.current) setError("读取规则异常: " + String(e));
|
|
8976
|
+
});
|
|
8977
|
+
};
|
|
8978
|
+
react.default.useEffect(() => {
|
|
8979
|
+
mountedRef.current = true;
|
|
8980
|
+
load();
|
|
8981
|
+
return () => {
|
|
8982
|
+
mountedRef.current = false;
|
|
8983
|
+
};
|
|
8984
|
+
}, []);
|
|
8985
|
+
react.default.useEffect(() => {
|
|
8986
|
+
const el = panelRef.current;
|
|
8987
|
+
if (!el || typeof ResizeObserver === "undefined") return void 0;
|
|
8988
|
+
const observer = new ResizeObserver(() => setPanelW(el.clientWidth));
|
|
8989
|
+
observer.observe(el);
|
|
8990
|
+
setPanelW(el.clientWidth);
|
|
8991
|
+
return () => observer.disconnect();
|
|
8992
|
+
}, []);
|
|
8993
|
+
const descCap = panelW > 0 ? descCapOf(panelW) : DESC_MAX;
|
|
8994
|
+
const narrow = panelW > 0 && panelW < NARROW_W;
|
|
8995
|
+
/**
|
|
8996
|
+
* 切换 Tab(记忆到 localStorage)。
|
|
8997
|
+
* @param next 目标 Tab
|
|
8998
|
+
*/
|
|
8999
|
+
const switchTab = (next) => {
|
|
9000
|
+
setTab(next);
|
|
9001
|
+
writeLocal(CACHE_KEY.rules + "tab", next);
|
|
9002
|
+
};
|
|
9003
|
+
/**
|
|
9004
|
+
* 打开新建表单(按当前 Tab 决定作用域;项目规则跟随当前会话工作区)。
|
|
9005
|
+
*/
|
|
9006
|
+
const openNew = () => {
|
|
9007
|
+
const scope = tab === "project" ? "project" : "user";
|
|
9008
|
+
if (scope === "project" && !cwd) {
|
|
9009
|
+
notify("当前会话没有工作区,无法新建项目规则");
|
|
9010
|
+
return;
|
|
9011
|
+
}
|
|
9012
|
+
const parsed = parseRuleFm(NEW_TEMPLATE);
|
|
9013
|
+
setForm({
|
|
9014
|
+
mode: "new",
|
|
9015
|
+
scope,
|
|
9016
|
+
workspacePath: scope === "project" ? cwd : void 0,
|
|
9017
|
+
relHint: scope === "project" ? ".dsh/rules/" : "rules/",
|
|
9018
|
+
file: "",
|
|
9019
|
+
content: NEW_TEMPLATE,
|
|
9020
|
+
fmType: parsed.type,
|
|
9021
|
+
desc: parsed.description,
|
|
9022
|
+
globs: parsed.globs.join(", "),
|
|
9023
|
+
error: "",
|
|
9024
|
+
saving: false
|
|
9025
|
+
});
|
|
9026
|
+
};
|
|
9027
|
+
/**
|
|
9028
|
+
* 打开编辑表单:先拉全文,再解析 frontmatter 回填类型/描述/globs 控件。
|
|
9029
|
+
* @param rule 目标规则
|
|
9030
|
+
*/
|
|
9031
|
+
const openEdit = (rule) => {
|
|
9032
|
+
rpc("rules.read", {
|
|
9033
|
+
scope: rule.scope,
|
|
9034
|
+
workspacePath: rule.scope === "project" ? rule.workspacePath : void 0,
|
|
9035
|
+
file: rule.file
|
|
9036
|
+
}).then((res) => {
|
|
9037
|
+
if (!res || !res.ok) {
|
|
9038
|
+
notify(res?.error ?? "读取规则失败");
|
|
9039
|
+
return;
|
|
9040
|
+
}
|
|
9041
|
+
const parsed = parseRuleFm(res.content);
|
|
9042
|
+
setForm({
|
|
9043
|
+
mode: "edit",
|
|
9044
|
+
scope: rule.scope,
|
|
9045
|
+
workspacePath: rule.workspacePath,
|
|
9046
|
+
relHint: rule.relHint,
|
|
9047
|
+
file: rule.file,
|
|
9048
|
+
content: res.content,
|
|
9049
|
+
fmType: parsed.type,
|
|
9050
|
+
desc: parsed.description,
|
|
9051
|
+
globs: parsed.globs.join(", "),
|
|
9052
|
+
error: "",
|
|
9053
|
+
saving: false
|
|
9054
|
+
});
|
|
9055
|
+
}).catch((e) => notify("读取规则异常: " + String(e)));
|
|
9056
|
+
};
|
|
9057
|
+
/** 类型下拉变更:frontmatter 按新类型重写,控件同步。 */
|
|
9058
|
+
const onTypeChange = (e) => {
|
|
9059
|
+
const nextType = e.target.value;
|
|
9060
|
+
setForm((prev) => ({
|
|
9061
|
+
...prev,
|
|
9062
|
+
fmType: nextType,
|
|
9063
|
+
content: rebuildContent(prev.content, nextType, prev.desc, prev.globs),
|
|
9064
|
+
error: ""
|
|
9065
|
+
}));
|
|
9066
|
+
};
|
|
9067
|
+
/** 描述输入变更:同步 frontmatter description 行。 */
|
|
9068
|
+
const onDescChange = (e) => {
|
|
9069
|
+
const nextDesc = e.target.value;
|
|
9070
|
+
setForm((prev) => ({
|
|
9071
|
+
...prev,
|
|
9072
|
+
desc: nextDesc,
|
|
9073
|
+
content: rebuildContent(prev.content, prev.fmType, nextDesc, prev.globs),
|
|
9074
|
+
error: ""
|
|
9075
|
+
}));
|
|
9076
|
+
};
|
|
9077
|
+
/** globs 输入变更(自动规则):同步 frontmatter globs 行。 */
|
|
9078
|
+
const onGlobsChange = (e) => {
|
|
9079
|
+
const nextGlobs = e.target.value;
|
|
9080
|
+
setForm((prev) => ({
|
|
9081
|
+
...prev,
|
|
9082
|
+
globs: nextGlobs,
|
|
9083
|
+
content: rebuildContent(prev.content, prev.fmType, prev.desc, nextGlobs),
|
|
9084
|
+
error: ""
|
|
9085
|
+
}));
|
|
9086
|
+
};
|
|
9087
|
+
/** 文本域直接编辑:回读 frontmatter,同步类型/描述/globs 控件(文本域是唯一真源)。 */
|
|
9088
|
+
const onBodyChange = (e) => {
|
|
9089
|
+
const parsed = parseRuleFm(e.target.value);
|
|
9090
|
+
setForm((prev) => ({
|
|
9091
|
+
...prev,
|
|
9092
|
+
content: e.target.value,
|
|
9093
|
+
fmType: parsed.type,
|
|
9094
|
+
desc: parsed.description,
|
|
9095
|
+
globs: parsed.globs.join(", ")
|
|
9096
|
+
}));
|
|
9097
|
+
};
|
|
9098
|
+
/** 保存表单(rules.save;文件名非空 + 自动规则必须有 globs)。 */
|
|
9099
|
+
const saveForm = () => {
|
|
9100
|
+
const next = {
|
|
9101
|
+
...form,
|
|
9102
|
+
saving: true,
|
|
9103
|
+
error: ""
|
|
9104
|
+
};
|
|
9105
|
+
const file = String(form.file ?? "").trim();
|
|
9106
|
+
if (!file) {
|
|
9107
|
+
setForm({
|
|
9108
|
+
...next,
|
|
9109
|
+
saving: false,
|
|
9110
|
+
error: "文件名不能为空"
|
|
9111
|
+
});
|
|
9112
|
+
return;
|
|
9113
|
+
}
|
|
9114
|
+
if (form.fmType === "auto" && globList(form.globs).length === 0) {
|
|
9115
|
+
setForm({
|
|
9116
|
+
...next,
|
|
9117
|
+
saving: false,
|
|
9118
|
+
error: "自动规则需要至少一个 glob(逗号分隔)"
|
|
9119
|
+
});
|
|
9120
|
+
return;
|
|
9121
|
+
}
|
|
9122
|
+
setForm(next);
|
|
9123
|
+
rpc("rules.save", {
|
|
9124
|
+
scope: form.scope,
|
|
9125
|
+
workspacePath: form.workspacePath,
|
|
9126
|
+
file,
|
|
9127
|
+
content: form.content
|
|
9128
|
+
}).then((res) => {
|
|
9129
|
+
if (res && res.ok) {
|
|
9130
|
+
setForm(null);
|
|
9131
|
+
notify("规则已保存:" + file);
|
|
9132
|
+
load();
|
|
9133
|
+
} else setForm((prev) => ({
|
|
9134
|
+
...prev,
|
|
9135
|
+
saving: false,
|
|
9136
|
+
error: res?.error ?? "保存失败"
|
|
9137
|
+
}));
|
|
9138
|
+
}).catch((e) => setForm((prev) => ({
|
|
9139
|
+
...prev,
|
|
9140
|
+
saving: false,
|
|
9141
|
+
error: "保存异常: " + String(e)
|
|
9142
|
+
})));
|
|
9143
|
+
};
|
|
9144
|
+
/**
|
|
9145
|
+
* 删除规则(confirm 后走 rules.remove)。
|
|
9146
|
+
* @param rule 目标规则
|
|
9147
|
+
*/
|
|
9148
|
+
const removeRule = (rule) => {
|
|
9149
|
+
if (!window.confirm("删除规则 " + rule.file + "?(不可恢复)")) return;
|
|
9150
|
+
rpc("rules.remove", {
|
|
9151
|
+
scope: rule.scope,
|
|
9152
|
+
workspacePath: rule.workspacePath,
|
|
9153
|
+
file: rule.file
|
|
9154
|
+
}).then((res) => {
|
|
9155
|
+
if (res && res.ok) {
|
|
9156
|
+
notify("已删除:" + rule.file);
|
|
9157
|
+
load();
|
|
9158
|
+
} else notify(res?.error ?? "删除失败");
|
|
9159
|
+
}).catch((e) => notify("删除异常: " + String(e)));
|
|
9160
|
+
};
|
|
9161
|
+
/**
|
|
9162
|
+
* 切换启用开关:本地乐观翻转(按 workspacePath+file 定位,失败回滚)。
|
|
9163
|
+
* @param rule 目标规则(project 已注入 workspacePath)
|
|
9164
|
+
*/
|
|
9165
|
+
const toggleRule = (rule) => {
|
|
9166
|
+
const enabled = !rule.enabled;
|
|
9167
|
+
const applyLocal = (on) => setData((prev) => prev ? {
|
|
9168
|
+
...prev,
|
|
9169
|
+
user: prev.user.map((r) => r.scope === "user" && r.file === rule.file ? {
|
|
9170
|
+
...r,
|
|
9171
|
+
enabled: on
|
|
9172
|
+
} : r),
|
|
9173
|
+
projects: prev.projects.map((p) => p.workspacePath === rule.workspacePath ? {
|
|
9174
|
+
...p,
|
|
9175
|
+
rules: p.rules.map((r) => r.file === rule.file ? {
|
|
9176
|
+
...r,
|
|
9177
|
+
enabled: on
|
|
9178
|
+
} : r)
|
|
9179
|
+
} : p)
|
|
9180
|
+
} : prev);
|
|
9181
|
+
applyLocal(enabled);
|
|
9182
|
+
rpc("rules.toggle", {
|
|
9183
|
+
scope: rule.scope,
|
|
9184
|
+
workspacePath: rule.workspacePath,
|
|
9185
|
+
file: rule.file,
|
|
9186
|
+
enabled
|
|
9187
|
+
}).then((res) => {
|
|
9188
|
+
if (res && res.ok) {
|
|
9189
|
+
applyLocal(res.rule?.enabled === true);
|
|
9190
|
+
notify(res.rule?.enabled === false ? "已停用:" + rule.file : "已启用:" + rule.file);
|
|
9191
|
+
} else {
|
|
9192
|
+
applyLocal(!enabled);
|
|
9193
|
+
notify(res?.error ?? "切换失败");
|
|
9194
|
+
}
|
|
9195
|
+
}).catch((e) => {
|
|
9196
|
+
applyLocal(!enabled);
|
|
9197
|
+
notify("切换异常: " + String(e));
|
|
9198
|
+
});
|
|
9199
|
+
};
|
|
9200
|
+
/** 当前列表数据(按 Tab 取用户规则或当前工作区的项目规则)。 */
|
|
9201
|
+
const rowsOf = () => {
|
|
9202
|
+
if (!data) return [];
|
|
9203
|
+
if (tab === "user") return data.user;
|
|
9204
|
+
return activeProject()?.rules ?? [];
|
|
9205
|
+
};
|
|
9206
|
+
const renderTabs = () => react.default.createElement("div", { className: "edrv-rules-tabs" }, react.default.createElement("button", {
|
|
9207
|
+
className: "edrv-rules-tab" + (tab === "user" ? " on" : ""),
|
|
9208
|
+
onClick: () => switchTab("user")
|
|
9209
|
+
}, "用户规则"), react.default.createElement("button", {
|
|
9210
|
+
className: "edrv-rules-tab" + (tab === "project" ? " on" : ""),
|
|
9211
|
+
onClick: () => switchTab("project")
|
|
9212
|
+
}, "项目规则"), react.default.createElement("button", {
|
|
9213
|
+
className: "edrv-rules-new",
|
|
9214
|
+
title: "新建规则",
|
|
9215
|
+
onClick: openNew
|
|
9216
|
+
}, "+ 新建规则"));
|
|
9217
|
+
/** 项目 Tab 的工作区展示(不可编辑,自动跟随当前会话)。 */
|
|
9218
|
+
const renderWsLine = () => {
|
|
9219
|
+
if (tab !== "project") return null;
|
|
9220
|
+
return react.default.createElement("div", {
|
|
9221
|
+
className: "edrv-rules-ws-line",
|
|
9222
|
+
title: cwd ?? ""
|
|
9223
|
+
}, "工作区:" + (cwd ?? "当前会话未打开工作区"));
|
|
9224
|
+
};
|
|
9225
|
+
const renderEmpty = () => {
|
|
9226
|
+
if (tab === "project") {
|
|
9227
|
+
if (!cwd) return "当前会话没有工作区,项目规则不可用(项目规则跟随会话所在工作区)";
|
|
9228
|
+
if (!data?.projects?.length) return "当前 DSH 没有已注册的工作区;在目标工作区打开一次会话后再来管理";
|
|
9229
|
+
if (!activeProject()) return "当前工作区未注册为 DSH workspace,暂不能管理其项目规则";
|
|
9230
|
+
return "<工作区>/.dsh/rules/ 还没有规则,点击「+ 新建规则」创建";
|
|
9231
|
+
}
|
|
9232
|
+
return "还没有用户规则(~/.dsh/rules/),点击「+ 新建规则」创建";
|
|
9233
|
+
};
|
|
9234
|
+
const renderBody = () => {
|
|
9235
|
+
if (form) return react.default.createElement(RuleEditor, {
|
|
9236
|
+
form,
|
|
9237
|
+
onType: onTypeChange,
|
|
9238
|
+
onDesc: onDescChange,
|
|
9239
|
+
onGlobs: onGlobsChange,
|
|
9240
|
+
onBody: onBodyChange,
|
|
9241
|
+
onSave: saveForm,
|
|
9242
|
+
onCancel: () => setForm(null)
|
|
9243
|
+
});
|
|
9244
|
+
if (!data) return react.default.createElement("div", { className: "edrv-rules-empty" }, "加载中…");
|
|
9245
|
+
if (error) return react.default.createElement("div", { className: "edrv-rules-err" }, error);
|
|
9246
|
+
const rows = rowsOf();
|
|
9247
|
+
if (!rows.length) return react.default.createElement("div", { className: "edrv-rules-empty" }, renderEmpty());
|
|
9248
|
+
const common = {
|
|
9249
|
+
descCap,
|
|
9250
|
+
narrow,
|
|
9251
|
+
onEdit: (rule) => openEdit({
|
|
9252
|
+
...rule,
|
|
9253
|
+
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
9254
|
+
}),
|
|
9255
|
+
onRemove: (rule) => removeRule({
|
|
9256
|
+
...rule,
|
|
9257
|
+
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
9258
|
+
}),
|
|
9259
|
+
onToggle: (rule) => toggleRule({
|
|
9260
|
+
...rule,
|
|
9261
|
+
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
9262
|
+
})
|
|
9263
|
+
};
|
|
9264
|
+
return react.default.createElement("div", { className: "edrv-rules-list" }, rows.map((rule) => react.default.createElement(RuleRow, {
|
|
9265
|
+
key: rule.scope + ":" + rule.file,
|
|
9266
|
+
rule,
|
|
9267
|
+
...common
|
|
9268
|
+
})));
|
|
9269
|
+
};
|
|
9270
|
+
return react.default.createElement("div", {
|
|
9271
|
+
className: "edrv-rules-panel",
|
|
9272
|
+
ref: panelRef
|
|
9273
|
+
}, renderTabs(), renderWsLine(), react.default.createElement("div", { className: "edrv-rules-hint" }, tab === "user" ? "用户规则对所有会话生效(存放于 ~/.dsh/rules/)" : "项目规则仅对所在工作区的会话生效(存放于 <工作区>/.dsh/rules/)"), renderBody());
|
|
9274
|
+
}
|
|
9275
|
+
//#endregion
|
|
8442
9276
|
//#region src/client/sidebar/panels/index.ts
|
|
8443
9277
|
/**
|
|
8444
|
-
* dsh-vscode-mode client — 侧边栏面板定义(文件管理 +
|
|
8445
|
-
* 作者 ddj 2026-08-26 / 2026-
|
|
9278
|
+
* dsh-vscode-mode client — 侧边栏面板定义(文件管理 + 搜索 + 规则)。
|
|
9279
|
+
* 作者 ddj 2026-08-26 / 2026-09-03
|
|
8446
9280
|
*/
|
|
8447
9281
|
/**
|
|
8448
9282
|
* 构造文件管理面板定义。
|
|
@@ -8473,6 +9307,20 @@ window.__ModuleLoader__.load({
|
|
|
8473
9307
|
render: (ctx) => react.default.createElement(SearchPanel, { ctx })
|
|
8474
9308
|
};
|
|
8475
9309
|
}
|
|
9310
|
+
/**
|
|
9311
|
+
* 构造规则管理面板定义(Codebuddy 规则形态:用户规则/项目规则双 Tab + 开关)。
|
|
9312
|
+
* @author ddj 2026年09月03号
|
|
9313
|
+
* @returns 面板定义(无徽标;活动栏图标 📏,与大纲 📜 区分)
|
|
9314
|
+
*/
|
|
9315
|
+
function createRulesPanel() {
|
|
9316
|
+
return {
|
|
9317
|
+
id: "rules",
|
|
9318
|
+
title: "规则",
|
|
9319
|
+
icon: "📏",
|
|
9320
|
+
order: 20,
|
|
9321
|
+
render: (ctx) => react.default.createElement(RulesPanel, { ctx })
|
|
9322
|
+
};
|
|
9323
|
+
}
|
|
8476
9324
|
//#endregion
|
|
8477
9325
|
//#region src/client/sidebar/menuItems.ts
|
|
8478
9326
|
/**
|
|
@@ -9407,6 +10255,7 @@ window.__ModuleLoader__.load({
|
|
|
9407
10255
|
ctx.provide("edrvSidebarPanels", sidebarPanels);
|
|
9408
10256
|
ctx.effect(() => sidebarPanels.register(createFilePanel()), "vscode-mode: sidebar panel");
|
|
9409
10257
|
ctx.effect(() => sidebarPanels.register(createSearchPanel()), "vscode-mode: sidebar panel search");
|
|
10258
|
+
ctx.effect(() => sidebarPanels.register(createRulesPanel()), "vscode-mode: sidebar panel rules");
|
|
9410
10259
|
const fileMenuItems = createTreeMenuRegistry();
|
|
9411
10260
|
ctx.provide("edrvFileContextMenuItems", fileMenuItems);
|
|
9412
10261
|
for (const item of createDefaultFileMenuItems()) ctx.effect(() => fileMenuItems.register(item), "vscode-mode: file context menu item " + item.id);
|
|
@@ -9442,6 +10291,8 @@ window.__ModuleLoader__.load({
|
|
|
9442
10291
|
const snapshot = settings.getSnapshot();
|
|
9443
10292
|
if (snapshot.status === "loading") return;
|
|
9444
10293
|
keybindingsApply(snapshot.value?.keybindings);
|
|
10294
|
+
const minW = sidebarMinApply(snapshot.value?.sidebarMinWidth);
|
|
10295
|
+
window.dispatchEvent(new CustomEvent("edrv:sidebar-min-width", { detail: { value: minW } }));
|
|
9445
10296
|
};
|
|
9446
10297
|
sync();
|
|
9447
10298
|
return settings.subscribe(sync);
|
|
@@ -9474,7 +10325,8 @@ window.__ModuleLoader__.load({
|
|
|
9474
10325
|
addToConversation,
|
|
9475
10326
|
sidebarPanels,
|
|
9476
10327
|
outlineSources,
|
|
9477
|
-
fileMenuItems
|
|
10328
|
+
fileMenuItems,
|
|
10329
|
+
sessions
|
|
9478
10330
|
})));
|
|
9479
10331
|
};
|
|
9480
10332
|
let sideDisposer = null;
|
|
@@ -9493,7 +10345,8 @@ window.__ModuleLoader__.load({
|
|
|
9493
10345
|
addToConversation,
|
|
9494
10346
|
sidebarPanels,
|
|
9495
10347
|
outlineSources,
|
|
9496
|
-
fileMenuItems
|
|
10348
|
+
fileMenuItems,
|
|
10349
|
+
sessions
|
|
9497
10350
|
})),
|
|
9498
10351
|
activeSession: () => {
|
|
9499
10352
|
const snapshot = sessions?.list?.getSnapshot?.();
|