dsh-vscode-mode 0.18.0 → 0.19.0
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 +6 -4
- package/lib/client.debug.js +934 -0
- package/lib/client.debug.js.map +1 -0
- package/lib/client.js +848 -1676
- package/lib/client.js.map +1 -1
- package/lib/client.rules.js +793 -0
- package/lib/client.rules.js.map +1 -0
- package/lib/index.js +236 -42
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/index.ts +9 -0
- package/src/client/lazyPanel.ts +68 -0
- package/src/client/sidebar/PanelBoundary.ts +57 -0
- package/src/client/sidebar/SidebarView.ts +58 -21
- package/src/client/sidebar/panels/FileExplorer.ts +80 -27
- package/src/client/sidebar/panels/SvnPanel.ts +24 -8
- package/src/client/sidebar/panels/index.ts +3 -4
- package/src/client/sidebar/panels/treeWindow.ts +106 -0
- package/src/client/sidebar/panels/useExplorerReveal.ts +5 -2
- package/src/client/sidebar/registry.ts +4 -1
- package/src/client/styles/editor.css +8 -0
- package/src/client/textPages.ts +135 -0
- package/src/client/ui/EditorView.ts +71 -11
- package/src/client/ui/LargeTextView.ts +94 -0
- package/src/rpc.ts +29 -7
- package/src/shared/rpc.ts +3 -1
- package/src/shared/textPages.ts +28 -0
- package/src/textPages.ts +149 -0
- package/src/treeIndex.ts +62 -37
package/lib/client.js
CHANGED
|
@@ -29,11 +29,11 @@ window.__ModuleLoader__.load({
|
|
|
29
29
|
let react = require("react");
|
|
30
30
|
react = __toESM(react, 1);
|
|
31
31
|
let react_dom = require("react-dom");
|
|
32
|
+
let react_dom_client = require("react-dom/client");
|
|
32
33
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
34
|
_deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
|
|
34
|
-
let react_dom_client = require("react-dom/client");
|
|
35
35
|
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
|
|
36
|
-
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 主题:跟随官方 --dsw-alias-* 令牌(DSH 明暗与第三方皮肤生效)。\n 本作用域不再重定义官方令牌(旧实现曾在此硬覆盖浅色盘,导致插件不跟随 DSH 主题);\n 旧环境/缺令牌场景由每条声明的 var(--dsw-alias-*, 回落值) 兜底。\n @author ddj 2026-09-10 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; }\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; overflow-y: hidden; scrollbar-width: thin; flex-shrink: 0; overscroll-behavior-x: contain; } /* overscroll-behavior-x: 横滚到边界不把滚动链传给页面(滚轮横滚接管更可控)@author ddj 2026年09月18号 */\n[data-edrv-view] .edrv-tab { user-select: none; -webkit-user-select: none; 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-star { color: var(--dsw-alias-brand-primary, #4f8cff); font-size: 13px; font-weight: 700; line-height: 1; flex-shrink: 0; } /* 未保存修改星号 @author ddj 2026年09月09号 */\n[data-edrv-view] .edrv-tab .edrv-tab-x { appearance: none; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 16px; width: 16px; height: 16px; padding: 0; border: 0; border-radius: 4px; background: transparent; box-shadow: none; color: var(--dsw-alias-label-tertiary, #888); font-family: inherit; font-size: 11px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:focus-visible { outline: 1px solid var(--dsw-alias-state-info-primary, #4d6bfe); outline-offset: 1px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.12)); color: var(--dsw-alias-label-primary, #eee); }\n/* 固定页签:📌 标记 + 免关闭按钮(固定页签不渲染 ×,仅可经右键菜单取消固定) */\n[data-edrv-view] .edrv-tab .edrv-tab-pin { flex-shrink: 0; font-size: 10px; line-height: 1; opacity: .85; }\n[data-edrv-view] .edrv-tab.edrv-tab-pinned { background: var(--dsw-alias-bg-layer-2, rgba(255,255,255,.04)); }\n/* 页签行 = 可横滚的页签区 + 行尾固定工具列(计划预览页签与磁盘页签同处这一行的滚动区)@author ddj 2026年10月20号 */\n[data-edrv-view] .edrv-tabs-row { display: flex; align-items: center; min-width: 0; flex: 0 0 auto; background: var(--dsw-alias-bg-layer-1, transparent); }\n/* 特异性需盖过下面 .edrv-group .edrv-tabs 的 flex: 0 0 auto,页签区才能吃掉行走宽、把工具列压到行尾 */\n[data-edrv-view] .edrv-group .edrv-tabs-row > .edrv-tabs { flex: 1 1 auto; min-width: 0; background: transparent; }\n[data-edrv-view] .edrv-tabs-tools { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; padding: 0 6px 0 2px; }\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/* 非焦点分组的静态路径条(GroupPathbar):可点击聚焦所属组,悬停给反馈 @author ddj 2026-10-16 */\n[data-edrv-view] .edrv-pathbar[data-edrv-pb-static] { cursor: pointer; }\n[data-edrv-view] .edrv-pathbar[data-edrv-pb-static]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-pb-update { display: inline-flex; align-items: center; gap: 4px; height: 20px; flex: none; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l1, #d9e0e4); border-radius: 4px; background: var(--dsw-alias-bg-layer-2, #f1f4f5); color: var(--dsw-alias-label-secondary, #485762); font-size: 11px; cursor: pointer; }\n[data-edrv-view] .edrv-pb-update:hover { background: var(--dsw-alias-interactive-bg-hover, #e7edf0); }\n[data-edrv-view] .edrv-pb-update:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2869b4); outline-offset: 1px; }\n@media (max-width: 620px) { [data-edrv-view] .edrv-pb-update { width: 24px; padding: 0 4px; overflow: hidden; font-size: 0; } }\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/* 键盘高亮项(↑↓ 选择):与 hover 同特异性但声明在后,故选中态稳定可辨 @author ddj 2026年09月11号 */\n[data-edrv-view] .edrv-search-item.edrv-search-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.14)); }\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: var(--dsw-alias-label-primary-inverted, #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/* 跳转目标区域高亮(LSP 定义/引用、搜索命中落点):落点一眼可见,约 1.2s 后由 EditorView 自动清除。\n 用官方令牌并带回落值,不在插件作用域重定义 --dsw-* (否则永久脱离官方主题)。 */\n[data-edrv-view] .edrv-nav-target { background: var(--dsw-alias-interactive-bg-hover, rgba(79,193,255,.28)); border-radius: 2px; box-shadow: 0 0 0 1px var(--dsw-alias-interactive-primary, rgba(79,193,255,.55)); }\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/* 行内和原生 Monaco diff 共用主题色盘;不再借用普通 hover 的灰底。 */\n[data-edrv-view] .edrv-mn-add-line { background: var(--edrv-diff-add, #e6f4e8); }\n[data-edrv-view] .edrv-mn-gutter-add { background: var(--edrv-diff-add, #e6f4e8); color: var(--dsw-alias-state-success-primary, #0f9d58) !important; 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, [data-edrv-view] .edrv-del-margin { background: var(--edrv-diff-del, #fbe7e3); color: var(--edrv-diff-fg, #1e1e1e); }\n[data-edrv-view] .edrv-del-row { white-space: pre; height: var(--edrv-line-height, 20px); line-height: var(--edrv-line-height, 20px); }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-del-margin-row { position: relative; height: var(--edrv-line-height, 20px); line-height: var(--edrv-line-height, 20px); }\n[data-edrv-view] .edrv-del-number { position: absolute; left: var(--edrv-number-left); width: var(--edrv-number-width); color: var(--edrv-diff-number, #6c6c6c); text-align: right; }\n[data-edrv-view] .edrv-del-marker { position: absolute; left: var(--edrv-marker-left); width: var(--edrv-marker-width); color: var(--dsw-alias-state-error-primary, #d9534f); text-align: center; }\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-imgview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-imgview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-imgview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 图片预览:居中交给子项 margin:auto(auto 外边距优先吃正向空闲空间;溢出时空闲为负 → 外边距归 0、\n flex-start 起点对齐 → 放大后四边均可滚动到达,规避 justify-content:center 双侧溢出不可达问题) */\n[data-edrv-view] .edrv-imgview-stage { flex: 1 1 auto; min-height: 0; display: flex; overflow: auto; padding: 14px; background-color: var(--dsw-alias-bg-layer-1, #f0f4f4); background-image: conic-gradient(rgba(128,128,128,.14) 25%, transparent 0 50%, rgba(128,128,128,.14) 0 75%, transparent 0); background-size: 16px 16px; }\n[data-edrv-view] .edrv-imgview-img { max-width: 100%; max-height: 100%; flex-shrink: 0; margin: auto; align-self: flex-start; object-fit: contain; border-radius: 4px; box-shadow: 0 2px 12px rgba(31,41,51,.18); }\n[data-edrv-view] .edrv-imgview-broken { display: flex; flex-direction: column; align-items: center; gap: 10px; font-size: 13px; color: var(--dsw-alias-label-tertiary, #777); margin: auto; }\n[data-edrv-view] .edrv-pdf-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-host > .edrv-pdf { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-pdf { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-pdf-page { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; min-width: 52px; text-align: center; }\n[data-edrv-view] .edrv-pdf-zoom { min-width: 26px; text-align: center; padding: 3px 7px; }\n[data-edrv-view] .edrv-pdf-sep { width: 1px; height: 16px; background: var(--dsw-alias-border-l1, #e0e6e8); margin: 0 2px; }\n[data-edrv-view] .edrv-pdf-mode-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-brand-primary, #0f9d58); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-pdf-dirty { color: var(--dsw-alias-state-warn-primary, #d97706); border-color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-pdf-stage { position: absolute; top: 34px; left: 0; right: 0; bottom: 0; overflow: auto; }\n/* Markdown 预览(需求 4):工具条 + 居中阅读栏;正文排版由官方 MarkdownText 自带的 --dsw-* 样式负责 */\n[data-edrv-view] .edrv-mdview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-mdview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-mdview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n[data-edrv-view] .edrv-mdview-stage { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 20px 28px; }\n[data-edrv-view] .edrv-mdview-doc { max-width: 880px; margin: 0 auto; width: 100%; }\n[data-edrv-view] .edrv-mdview-fallback { font-size: 12px; line-height: 1.7; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-mdview-pre { margin: 8px 0 0; padding: 10px 12px; border-radius: 8px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }\n[data-edrv-view] .edrv-pb-mdbtn { height: 20px; padding: 0 8px; font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-pdf-stage .edrv-pdf-viewer { margin: 0 auto; }\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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-state-success-primary, #0f7a45); border: 1px solid var(--dsw-alias-state-success-primary, rgba(15,157,88,.4)); }\n[data-edrv-view] .edrv-pill-undo { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); color: var(--dsw-alias-state-error-primary, #c0392b); border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-pill-ghost { background: var(--dsw-alias-bg-layer-1, #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 页签菜单 11 条 + 键位提示,故限高可滚(ContextMenu 以实测尺寸做 viewport clamp)。\n ⚠️ z-index 71 在既有浮层阶梯内(见文件末尾命令栏注释),不得上调越过命令栏/片段浮窗。 */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 220px; max-width: 360px; max-height: min(70vh, 520px); overflow-y: auto; 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/* 菜单项文案(弹性占宽,超出省略)与右侧键位提示(不缩放,等宽字体) */\n[data-edrv-view] .edrv-ctxmenu-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-hint { flex: 0 0 auto; padding-left: 18px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-ctxmenu-item:disabled .edrv-ctxmenu-hint,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled .edrv-ctxmenu-hint { color: var(--dsw-alias-label-disabled, #b0b7c0); }\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: var(--dsw-alias-state-warn-primary, 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/* 侧栏差异栏在编辑内容底部居中悬浮,按内容宽度收缩;窄栏只在工具条内横滚。@author ddj 2026年09月29号 */\n[data-edrv-view] .edrv-side-diff-dock[data-edrv-diff-dock-shell] { position: absolute; left: 50%; bottom: 28px; z-index: 25; width: max-content; max-width: calc(100% - 20px); max-height: min(300px, calc(100% - 38px)); margin: 0; transform: translateX(-50%); border-radius: 12px; background: var(--dsw-alias-bg-overlay, #fff); box-shadow: 0 6px 20px rgba(0,0,0,.18); overflow-x: hidden; overflow-y: auto; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-editor-row { padding-inline: 8px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-editor-content { gap: 5px; width: max-content; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-nav,\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-files,\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-actions { gap: 3px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-pill { padding-inline: 5px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-files .edrv-diffbar-file { min-width: 0; max-width: 72px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-details-toggle { width: 26px; min-width: 26px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-body { max-height: min(180px, 25vh); max-width: 100%; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diff-details { max-height: min(260px, 35vh); overflow-y: auto; }\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; display: inline-flex; align-items: center; justify-content: center; }\n/* 树行图标:官方原语(文件夹/文件类型),尺寸与行高对齐 @author ddj 2026-09-10 */\n[data-edrv-view] .edrv-tree-icon { flex-shrink: 0; display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active .edrv-tree-icon { color: var(--dsw-alias-label-secondary, #52606d); }\n/* SVN overlays: official file icon remains visible, independent local/remote signs. ddj 2026-10-09 */\n[data-edrv-view] .edrv-tree-iconbox { position: relative; display: inline-flex; width: 20px; height: 20px; align-items: center; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-overlay { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-svn-local { position: absolute; right: -1px; bottom: -2px; display: flex; border-radius: 50%; box-shadow: 0 0 0 1px var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-svn-icon-clean { color: #16853b; }\n[data-edrv-view] .edrv-svn-icon-modified, [data-edrv-view] .edrv-svn-icon-deleted { color: #d12e35; }\n[data-edrv-view] .edrv-svn-icon-conflict { color: #c27300; }\n[data-edrv-view] .edrv-svn-icon-added { color: #2465c9; }\n[data-edrv-view] .edrv-svn-icon-unversioned, [data-edrv-view] .edrv-svn-icon-ignored, [data-edrv-view] .edrv-svn-icon-external { color: #75808c; }\n[data-edrv-view] .edrv-svn-remote { position: absolute; right: -3px; top: -4px; color: #2465c9; background: var(--dsw-alias-bg-layer-1, #fff); border-radius: 3px; font-size: 11px; font-weight: 900; line-height: 12px; }\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: var(--dsw-alias-label-primary-inverted, #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/* 「在资源管理器视图中显示」的定位高亮(短时淡出,区别于常驻的 active 态) */\n[data-edrv-view] .edrv-tree-row.edrv-tree-reveal { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); animation: edrv-tree-reveal-fade 2s ease-out; }\n@keyframes edrv-tree-reveal-fade { from { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.32)); } to { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); } }\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: var(--dsw-alias-label-primary-inverted, #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/* SVN 状态独立占位:换行不覆盖文件树,长错误在栏内滚动。@author ddj 2026-10-12 */\n[data-edrv-view] .edrv-tree-status { flex: 0 0 auto; min-width: 0; max-height: 96px; overflow: auto; padding: 4px 8px; box-sizing: border-box; line-height: 18px; white-space: normal; overflow-wrap: anywhere; 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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); 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/* ===== SVN 变更面板(工作副本状态列表;颜色分级对齐 TortoiseSVN 口径) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svn-toolbar { display: flex; align-items: center; gap: 12px; padding: 4px 10px 6px 12px; flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svn-check { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-check input { margin: 0; cursor: pointer; }\n[data-edrv-view] .edrv-svn-bulk { display: flex; align-items: center; gap: 6px; padding: 0 10px 6px 12px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-count { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* AI 助手 dock(12-panel-ai-bar 设计定稿):manifest 分带之 assistant 带,accent 左竖轨为唯一记忆点。\n AI 线程色三处同轨:竖轨 / dock 按钮描边 / 弹窗进度条(--dsw-alias-state-info-primary)。 @author ddj 2026-09-23 */\n[data-edrv-view] .edrv-svn-ai-bar { position: relative; display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px 14px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-ai-rail { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-ai-label { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svn-ai-btn { border-color: var(--dsw-alias-state-info-primary, #2f6fed); color: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-ai-btn:disabled { border-color: var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 状态位定宽右对齐(就绪/分析中…/等待助手投递…互换不跳版) */\n[data-edrv-view] .edrv-svn-ai-status { flex-shrink: 0; min-width: 88px; text-align: right; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 批量条语义分隔(导出簇 ┊ 动作簇之间 1px 竖线) */\n[data-edrv-view] .edrv-svn-sep { width: 1px; height: 14px; background: var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n/* 头部图标组(检查远端/刷新成组,gap 收紧) */\n[data-edrv-view] .edrv-svn-head-icons { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-list { flex: 1; min-height: 0; overflow: auto; padding: 2px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-svn-group { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; margin: 2px 0; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; font-weight: 600; cursor: pointer; user-select: none; }\n[data-edrv-view] .edrv-svn-group:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-fold-ch { width: 10px; flex-shrink: 0; text-align: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svn-group-n { margin-left: auto; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-weight: 400; }\n[data-edrv-view] .edrv-svn-row { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-path { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-row:hover .edrv-svn-acts { display: inline-flex; }\n[data-edrv-view] .edrv-svn-act { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 14px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-act:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-svn-act-danger { color: var(--dsw-alias-state-error-primary, #d9534f); border-color: var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-svn-ch { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-weight: 700; }\n[data-edrv-view] .edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svn-ch-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* .edrv-svn-ch-* 动作词表补全:replaced(替换)= 琥珀;侧栏状态分级(SVN_STATUS_TONE)不受影响 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svn-ch-replaced { color: var(--dsw-alias-state-warn-primary, #d97706); }\n/* 文件树行尾 SVN 状态徽标(与差异角标并列;方形字母,区别圆形差异计数) */\n[data-edrv-view] .edrv-tree-svn { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 4px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* ===== SVN 基线差异视图(BASE 左 / 工作区右,只读并排) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svndiff { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-svndiff-bar { display: flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svndiff-title { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svndiff-tag { padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svndiff-host { flex: 1 1 auto; min-height: 0; }\n[data-edrv-view] .edrv-svndiff-empty { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; padding: 24px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 12px; text-align: center; }\n/* 差异整行色块与行首 +/- 指示符:vendored Monaco(diffEditorWidget2)静态 CSS 无\n .line-insert/.line-delete 背景规则,整行色块靠主题键 + 此处固定色兜底保证可见。\n 注意不要用 --dsw-alias-interactive-bg-hover 类 token:实测为 92% 透明中性色,肉眼不可见。\n 固定色取自研差异 UI 同色相(绿 #0f9d58 / 红 #d9534f),alpha 提到肉眼可辨。 */\n[data-edrv-view] .monaco-editor .line-insert { background: rgba(15, 157, 88, 0.18); }\n[data-edrv-view] .monaco-editor .line-delete { background: rgba(217, 83, 79, 0.16); }\n[data-edrv-view] .monaco-editor .gutter-insert { background: rgba(15, 157, 88, 0.35); }\n[data-edrv-view] .monaco-editor .gutter-delete { background: rgba(217, 83, 79, 0.35); }\n[data-edrv-view] .monaco-editor .insert-sign { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .monaco-editor .delete-sign { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* 差异条快速跳转簇(对齐自研审查条 ↑ i/N ↓ 的形态) */\n[data-edrv-view] .edrv-svndiff-nav { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svndiff-nav-count { min-width: 36px; text-align: center; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n/* W1-3 差异统计徽标(+新增/修改 −删除/修改;色相与行块绿红一致) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svndiff-stat { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svndiff-stat-add { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-svndiff-stat-del { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W1-1 差异视图选项条(右端开关组;复用 .edrv-svn-check 的 label 形态) */\n[data-edrv-view] .edrv-svndiff-opts { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n/* W1-2 变更面板名称过滤输入框(工具条行内,紧凑) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-name-filter { width: 168px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 14px; }\n[data-edrv-view] .edrv-svn-name-filter:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-svn-name-filter::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* W2-3 远端更新提示条(工具条上方;warn = 失败降级) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-hintbar { display: flex; align-items: center; gap: 6px; margin: 0 10px 4px 12px; padding: 3px 8px; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-hintbar-warn { background: rgba(217, 83, 79, 0.12); color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W2-5 疑似改名标记(行内 ⇄;hover 见 tooltip) */\n[data-edrv-view] .edrv-svn-pair-mark { flex-shrink: 0; color: var(--dsw-alias-state-warn-primary, #7c3aed); font-size: 11px; cursor: help; }\n/* W2-1 补丁对话框 / W2-2 目录对比对话框 @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-patch-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svn-patch-head { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-patch-notes { display: flex; flex-direction: column; gap: 4px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svn-patch-warn { color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-svn-patch-pre { max-height: 46vh; overflow: auto; margin: 0 0 8px; padding: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.5; white-space: pre; user-select: text; }\n[data-edrv-view] .edrv-svn-patch-foot { display: flex; align-items: center; gap: 8px; }\n/* AI 智能整理弹窗(11-ai-changelist-triage):预览三分组卡 + 执行进度 @author ddj 2026-09-23 */\n[data-edrv-view] .edrv-svnplan-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svnplan-head { display: flex; align-items: center; gap: 8px; padding-bottom: 4px; }\n[data-edrv-view] .edrv-svnplan-meta { display: flex; gap: 10px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svnplan-note { color: var(--dsw-alias-state-warn-primary, #b7791f); font-size: 10px; }\n[data-edrv-view] .edrv-svnplan-sec { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 6px 8px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnplan-sechead { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnplan-sectitle { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-list { max-height: 26vh; overflow: auto; padding-left: 18px; }\n[data-edrv-view] .edrv-svnplan-card { border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); padding: 3px 0; }\n[data-edrv-view] .edrv-svnplan-row { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnplan-item { display: flex; align-items: center; gap: 6px; padding-left: 18px; }\n[data-edrv-view] .edrv-svnplan-groupname { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46ch; }\n[data-edrv-view] .edrv-svnplan-reason { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 30ch; }\n[data-edrv-view] .edrv-svnplan-stage { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svnplan-badge { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 8px; font-size: 10px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-alias-bg-layer-2, #f7f9f9); white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-badge-cur { font-family: var(--ds-font-family-code, ui-monospace, monospace); overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnplan-bar { height: 6px; border-radius: 3px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnplan-bar-in { height: 100%; background: var(--dsw-alias-state-info-primary, #2f6fed); transition: width .2s; }\n[data-edrv-view] .edrv-svnplan-logwrap { max-height: 40vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 6px 8px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); }\n[data-edrv-view] .edrv-svnplan-log { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; color: var(--dsw-alias-label-secondary, #52606d); user-select: text; }\n[data-edrv-view] .edrv-svnplan-log-bad { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svnplan-foot { display: flex; align-items: center; gap: 8px; }\n[data-edrv-view] .edrv-svnplan-primary { font-weight: 600; border-color: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-sum-form { display: flex; align-items: center; gap: 10px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-sum-list { max-height: 44vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 2px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnlog-path-kind { flex-shrink: 0; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; }\n\n/* ===== 通用弹窗外壳(ModalShell)+ SVN 日志弹窗 @author ddj 2026-09-16 ===== */\n/* z-index 190:落在既有阶梯内(命令栏 200 > 片段二级 197 > 片段一级 195 > 190),\n 不遮挡命令栏;既有浮层数值不受影响(见 tests/overlayZOrder.test.ts)。 */\n[data-edrv-view] .edrv-modal-mask { position: fixed; inset: 0; z-index: 190; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, #000000aa); }\n[data-edrv-view] .edrv-svnlog-dialog { position: relative; display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-head { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-title { margin: 0; font-size: 16px; font-weight: 650; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n/* 头部目标路径 = 代码 chip(mono + 底色 + 全圆角;补丁/目录对比弹窗共用同视觉) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-target { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n/* 关闭按钮图标化(透明底,hover 显形;dialog 前缀提高特异性,压过底部按钮统一尺寸) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svnlog-head .edrv-svn-act { border-color: transparent; background: transparent; width: 24px; height: 24px; padding: 0; font-size: 12px; line-height: 1; }\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svnlog-head .edrv-svn-act:hover { border-color: var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n/* 过滤栏:浅色表面条 + 统一 24px 控件 + 焦点边框变色 + 日期组靠右 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-filter { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; padding: 6px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-field { flex: 0 0 auto; height: 24px; box-sizing: border-box; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-search { min-width: 160px; flex: 1 1 220px; height: 24px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-field:focus, [data-edrv-view] .edrv-svnlog-search:focus, [data-edrv-view] .edrv-svnlog-date:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-dates { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }\n[data-edrv-view] .edrv-svnlog-date { height: 24px; box-sizing: border-box; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-check { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-check input[type=\"checkbox\"] { margin: 0; cursor: pointer; accent-color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* P0-14 上中下三段全宽:body 纵向铺满弹窗(外框高度由拖拽受控) */\n[data-edrv-view] .edrv-svnlog-body { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-height: 0; }\n/* 上段修订列表(13-log-ui-polish 变更台账):\n 1px 发丝边框 + 底色面 + 左侧时间脊线(每行 ::before 画节点圆点、行盒左缘 ::after 连线段,\n 行行相接即整列脊线;选中行节点实心着色 + 2px 左强调条)。列宽由 cell 类与 nth-child 对齐(P0-12/D30)。 */\n[data-edrv-view] .edrv-svnlog-list { position: relative; flex: 0 0 auto; display: flex; flex-direction: column; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 0 4px 4px; background: var(--dsw-alias-bg-layer-1, #fff); }\n/* 列头 sticky:滚动常驻 + 实底防透;z-index 20 低于一切浮层(190 起),仅在列表滚动容器内生效 */\n[data-edrv-view] .edrv-svnlog-cols { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 16px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 10px; font-weight: 600; letter-spacing: .04em; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(1) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(2) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(3) { width: 88px; flex: none; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(4) { width: 82px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(5) { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-col-sortable { cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-col-sortable:hover { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-col-on { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-sort-reset { flex: none; }\n/* 行:position:relative 承载脊线节点(::before)与连线段(::after);选中 = 强调条 + 节点实心 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-item { position: relative; display: flex; align-items: center; gap: 6px; padding: 3px 6px 3px 16px; border-radius: 6px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-item::before { content: ''; position: absolute; left: 6px; top: 50%; transform: translateY(-50%); width: 7px; height: 7px; box-sizing: border-box; border-radius: 50%; border: 1.5px solid var(--dsw-alias-border-l2, #cbd2d9); background: var(--dsw-alias-bg-layer-1, #fff); z-index: 1; }\n[data-edrv-view] .edrv-svnlog-item::after { content: ''; position: absolute; left: 9px; top: 0; bottom: 0; width: 1px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-item:last-child::after { bottom: 50%; }\n[data-edrv-view] .edrv-svnlog-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-item.edrv-svnlog-item-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-item.edrv-svnlog-item-on::before { border-color: var(--dsw-alias-brand-primary, #2563eb); background: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-cell-msg,\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-rev { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-cell { overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svnlog-cell-rev { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-act { width: 52px; flex: none; display: inline-flex; gap: 3px; }\n[data-edrv-view] .edrv-svnlog-cell-author { width: 88px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-date { width: 82px; flex: none; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-cell-msg { flex: 1 1 auto; }\n[data-edrv-view] .edrv-svnlog-rev { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-weight: 700; color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-badge { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 4px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; }\n/* 动作语义色(13-log-ui-polish 归位):A=success 绿 · D=error 红 · M=brand 蓝 · R=warn 琥珀 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-badge-modified { color: var(--dsw-alias-state-info-primary, #2f6fed); background: rgba(47,111,237,.14); }\n[data-edrv-view] .edrv-svnlog-badge-added { color: var(--dsw-alias-state-success-primary, #0f9d58); background: rgba(15,157,88,.14); }\n[data-edrv-view] .edrv-svnlog-badge-deleted { color: var(--dsw-alias-state-error-primary, #d9534f); background: rgba(217,83,79,.14); }\n[data-edrv-view] .edrv-svnlog-badge-replaced { color: var(--dsw-alias-state-warn-primary, #d97706); background: rgba(217,119,6,.16); }\n[data-edrv-view] .edrv-svnlog-badge-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-more { padding: 6px 4px 2px; text-align: center; }\n/* P0-14 三段 pane 公共外观(13-log-ui-polish:2px 粗框 → 1px 发丝线 + 面板底色) */\n[data-edrv-view] .edrv-svnlog-pane { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 8px 10px; overflow: hidden; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-svnlog-msgpane { flex: 0 0 auto; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-svnlog-pathspane { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n/* P0-13/P0-14:分段横向拖拽分隔条 + 变更路径独立滚动容器 */\n[data-edrv-view] .edrv-svnlog-hsplit { flex: 0 0 6px; cursor: row-resize; margin: 2px 0; border-radius: 3px; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-hsplit:hover, [data-edrv-view] .edrv-svnlog-hsplit:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.28)); }\n[data-edrv-view] .edrv-svnlog-paths-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }\n/* 提交信息 meta 行:rev/日期 chip 化,author 常规字重(13-log-ui-polish) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-meta { display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-meta .edrv-svnlog-rev { padding: 1px 8px; border-radius: 999px; background: var(--dsw-alias-state-info-primary, #2f6fed); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 11px; font-weight: 700; }\n[data-edrv-view] .edrv-svnlog-meta .edrv-svnlog-date { height: auto; padding: 1px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svnlog-date { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 正文块:左侧品牌强调线 +1.7 行高(长提交信息可读性) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-msgpane pre.edrv-svnlog-body { margin: 8px 0 0; padding: 8px 10px; border-radius: 0 6px 6px 0; border-left: 2px solid var(--dsw-alias-state-info-primary, #2f6fed); background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11.5px; line-height: 1.7; white-space: pre-wrap; word-break: break-word; overflow: auto; flex: 1 1 auto; min-height: 0; }\n/* P0-14 外框尺寸手柄(13-log-ui-polish 增量3 八向:n/s/w/e 四边 + nw/ne/sw/se 四角);\n 热区避开内边距带(边8px/角14px 落在卡片22/24px padding 内不遮内容),角手柄后渲染盖过相邻边2px overlap。\n chevron 角标四向各自朝向,hover 显形。 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-grip { position: absolute; z-index: 2; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-grip-n { top: 0; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-s { bottom: 0; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-w { left: 0; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-e { right: 0; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-nw { left: 0; top: 0; width: 14px; height: 14px; cursor: nwse-resize; }\n[data-edrv-view] .edrv-svnlog-grip-ne { right: 0; top: 0; width: 14px; height: 14px; cursor: nesw-resize; }\n[data-edrv-view] .edrv-svnlog-grip-sw { left: 0; bottom: 0; width: 14px; height: 14px; cursor: nesw-resize; }\n[data-edrv-view] .edrv-svnlog-grip-se { right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; background: transparent; }\n[data-edrv-view] .edrv-svnlog-grip-nw::after,\n[data-edrv-view] .edrv-svnlog-grip-ne::after,\n[data-edrv-view] .edrv-svnlog-grip-sw::after,\n[data-edrv-view] .edrv-svnlog-grip-se::after { content: ''; position: absolute; width: 6px; height: 6px; opacity: .5; border-color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-grip-se::after { right: 3px; bottom: 3px; border-right: 1.5px solid; border-bottom: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip-sw::after { left: 3px; bottom: 3px; border-left: 1.5px solid; border-bottom: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip-ne::after { right: 3px; top: 3px; border-right: 1.5px solid; border-top: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip-nw::after { left: 3px; top: 3px; border-left: 1.5px solid; border-top: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip:hover, [data-edrv-view] .edrv-svnlog-grip:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.35)); }\n[data-edrv-view] .edrv-svnlog-grip:hover::after, [data-edrv-view] .edrv-svnlog-grip:active::after { opacity: 1; border-color: var(--dsw-alias-label-primary, #1f2933); }\n/* 行反馈微动效(仅 hover/选中背景过渡;用户要求减少动效时关闭) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-item { transition: background-color .12s ease, box-shadow .12s ease; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-svnlog-item { transition: none; }\n}\n/*13-log-ui-polish 增量:行容器可滚动(pane 仍 overflow:hidden 裁圆角),列头不被压缩 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-paths-head { display: flex; align-items: center; gap: 6px; flex: none; font-size: 10px; font-weight: 600; letter-spacing: .04em; color: var(--dsw-alias-label-tertiary, #9aa5b1); margin-bottom: 4px; padding-bottom: 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-hint { font-weight: 400; letter-spacing: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-paths { display: flex; flex-direction: column; gap: 1px; flex: 1 1 auto; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-svnlog-path { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: default; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-path:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-pathtext,\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-copyfrom { opacity: .45; }\n[data-edrv-view] .edrv-svnlog-pathtext { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\n/* 路径两段着色:目录段弱化 + 文件名加重(13-log-ui-polish) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-pdir { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-pbase { color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-svnlog-copyfrom { flex: 0 1 160px; overflow: hidden; text-overflow: ellipsis; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-svnlog-kind { font-size: 10px; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-path:hover .edrv-svnlog-acts { display: inline-flex; }\n/* 底部:状态行与按钮组分层 + 组间发丝线(13-log-ui-polish) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-footwrap { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; padding-top: 6px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svnlog-btns { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnlog-btngroup { display: inline-flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnlog-btngroup + .edrv-svnlog-btngroup { margin-left: 6px; padding-left: 10px; border-left: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svn-act,\n[data-edrv-view] .edrv-svnlog-range .edrv-svn-act,\n[data-edrv-view] .edrv-svnlog-stats .edrv-svn-act { font-size: 11px; padding: 2px 9px; }\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svn-act:focus-visible,\n[data-edrv-view] .edrv-svnlog-range .edrv-svn-act:focus-visible,\n[data-edrv-view] .edrv-svnlog-stats .edrv-svn-act:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2563eb); outline-offset: 1px; }\n/* ===== SVN 日志统计窗(P1-10)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-stats { display: flex; flex-direction: column; max-height: 82vh; }\n[data-edrv-view] .edrv-svnlog-stats-head { display: flex; align-items: center; gap: 8px; padding: 12px 16px 0; }\n[data-edrv-view] .edrv-svnlog-stats-body { display: flex; flex-direction: column; gap: 14px; padding: 10px 16px 16px; overflow: auto; }\n[data-edrv-view] .edrv-svnlog-stat-line { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-block { display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-stat-label { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-duo { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-stat-hist { flex: 1 1 260px; display: flex; flex-direction: column; gap: 4px; min-width: 220px; }\n[data-edrv-view] .edrv-svnlog-stat-row { display: flex; align-items: center; gap: 8px; font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-stat-name { width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-barwrap { flex: 1; height: 12px; border-radius: 6px; background: rgba(127,127,127,.15); overflow: hidden; }\n[data-edrv-view] .edrv-svnlog-stat-bar { display: block; height: 100%; border-radius: 6px; }\n[data-edrv-view] .edrv-svnlog-stat-count { width: 36px; text-align: right; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-pie { width: 120px; height: 120px; flex-shrink: 0; border-radius: 50%; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-stat-days { display: flex; align-items: flex-end; gap: 2px; height: 120px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow-x: auto; }\n[data-edrv-view] .edrv-svnlog-stat-day { flex: 1 0 6px; min-width: 6px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; }\n[data-edrv-view] .edrv-svnlog-stat-seg { display: block; width: 100%; }\n/* ===== SVN 日志区间弹窗(P1-6)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-range-body { display: flex; flex-direction: column; gap: 12px; padding: 14px 16px 16px; }\n[data-edrv-view] .edrv-svnlog-range-row { display: flex; gap: 14px; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-range-input { width: 110px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-range-btns { display: flex; gap: 8px; justify-content: flex-end; }\n/* SVN 日志 WC 版号行加粗(P1-9) */\n[data-edrv-view] .edrv-svnlog-item-wc { font-weight: 700; }\n/* SVN 日志 merged 行(P1-5):灰字 + 缩进(缩进量按层级内联),前置「↳」标记 */\n[data-edrv-view] .edrv-svnlog-item-merged { color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-merge-mark { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-cell-msg { font-style: italic; }\n/* ===== 诊断日志弹窗(LogDialog)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-dlog-dialog { display: flex; flex-direction: column; gap: 8px; max-height: 88vh; }\n[data-edrv-view] .edrv-dlog-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-dlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-file { max-width: 200px; padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-level { padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-search { min-width: 120px; flex: 0 1 200px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-auto { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-dlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-scroll { flex: 1 1 auto; min-height: 240px; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px 0; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-dlog-row { display: flex; align-items: baseline; gap: 8px; padding: 1px 8px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.55; }\n[data-edrv-view] .edrv-dlog-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-dlog-at { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-lvl { flex-shrink: 0; width: 26px; text-align: center; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-text { flex: 1; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dlog-row-error .edrv-dlog-text { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-dlog-row-warn .edrv-dlog-text { color: var(--dsw-alias-state-warning-primary, #b45309); }\n[data-edrv-view] .edrv-dlog-row-debug .edrv-dlog-text { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-dlog-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-stat { white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-switch { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; flex-shrink: 0; }\n/* 原生 SVN 更新窗口:逐条状态与路径是主信息;跟随 DSH 主题令牌。 */\n[data-edrv-view] .edrv-update-dialog { display: flex; flex-direction: column; padding: 0; border-radius: 8px; overflow: hidden; background: var(--dsw-alias-bg-overlay, #fff); }\n[data-edrv-view] .edrv-update-head { display: flex; align-items: center; gap: 12px; min-height: 48px; padding: 0 16px; border-bottom: 1px solid var(--dsw-alias-border-l1, #d9e0e4); }\n[data-edrv-view] .edrv-update-heading { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1; }\n[data-edrv-view] .edrv-update-heading h3 { margin: 0; flex: none; font-size: 15px; }\n[data-edrv-view] .edrv-update-target { min-width: 0; color: var(--dsw-alias-label-tertiary, #65737c); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }\n[data-edrv-view] .edrv-update-phase { flex: none; font-size: 12px; color: var(--dsw-alias-label-secondary, #485762); }\n[data-edrv-view] .edrv-update-close { display: grid; place-items: center; flex: none; width: 28px; height: 28px; border: 0; border-radius: 4px; background: none; color: var(--dsw-alias-label-secondary, #485762); cursor: pointer; }\n[data-edrv-view] .edrv-update-close:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-update-close:not(:disabled):hover { background: var(--dsw-alias-interactive-bg-hover, #e7edf0); }\n[data-edrv-view] .edrv-update-table { display: flex; flex-direction: column; flex: 1; min-height: 0; margin: 12px 14px 0; border: 1px solid var(--dsw-alias-border-l1, #d9e0e4); border-radius: 5px; overflow: hidden; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-update-cols, [data-edrv-view] .edrv-update-row { display: grid; grid-template-columns: 110px minmax(0, 1fr) 160px; align-items: center; }\n[data-edrv-view] .edrv-update-sort { width: 100%; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }\n[data-edrv-view] .edrv-update-sort:hover { color: var(--dsw-alias-brand-primary, #2869b4); }\n[data-edrv-view] .edrv-update-sort:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2869b4); outline-offset: 2px; }\n[data-edrv-view] .edrv-update-jump { color: var(--dsw-alias-state-error-primary, #b93b43); }\n[data-edrv-view] .edrv-update-cols { flex: none; height: 30px; background: var(--dsw-alias-bg-layer-2, #f1f4f5); border-bottom: 1px solid var(--dsw-alias-border-l1, #d9e0e4); color: var(--dsw-alias-label-secondary, #485762); font-size: 11px; font-weight: 600; }\n[data-edrv-view] .edrv-update-cols > span, [data-edrv-view] .edrv-update-row > span { min-width: 0; padding: 0 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-update-cols > span + span, [data-edrv-view] .edrv-update-row > span + span { border-left: 1px solid var(--dsw-alias-border-l1, #d9e0e4); }\n[data-edrv-view] .edrv-update-list { position: relative; flex: 1; min-height: 0; overflow: auto; scrollbar-width: thin; }\n[data-edrv-view] .edrv-update-space { position: relative; }\n[data-edrv-view] .edrv-update-pos { position: absolute; left: 0; right: 0; }\n[data-edrv-view] .edrv-update-row { height: 100%; font-size: 11px; cursor: default; color: var(--dsw-alias-label-primary, #202932); }\n[data-edrv-view] .edrv-update-row:hover { background: var(--dsw-alias-interactive-bg-hover, #ecf3f9); }\n[data-edrv-view] .edrv-update-row.is-selected { background: var(--dsw-alias-interactive-bg-hover, #dceaf9); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #2869b4); }\n[data-edrv-view] .edrv-update-action { font-weight: 600; }\n[data-edrv-view] .edrv-update-action.tone-added { color: var(--dsw-alias-state-success-primary, #23704e); }\n[data-edrv-view] .edrv-update-action.tone-deleted, [data-edrv-view] .edrv-update-action.tone-conflict { color: var(--dsw-alias-state-error-primary, #b93b43); }\n[data-edrv-view] .edrv-update-action.tone-merged { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-action.tone-updated { color: var(--dsw-alias-state-info-primary, #2869b4); }\n[data-edrv-view] .edrv-update-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-update-type { color: var(--dsw-alias-label-tertiary, #65737c); }\n[data-edrv-view] .edrv-update-empty { position: absolute; top: 50%; left: 0; right: 0; transform: translateY(-50%); text-align: center; font-size: 12px; color: var(--dsw-alias-label-tertiary, #65737c); pointer-events: none; }\n[data-edrv-view] .edrv-update-telemetry { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 18px; padding: 10px 15px; min-height: 43px; box-sizing: border-box; font-size: 11px; color: var(--dsw-alias-label-secondary, #485762); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-update-error { color: var(--dsw-alias-state-error-primary, #b93b43); overflow-wrap: anywhere; }\n[data-edrv-view] .edrv-update-warning { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-locked { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-foot .edrv-update-cleanup:not(:disabled) { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-foot { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-top: 1px solid var(--dsw-alias-border-l1, #d9e0e4); font-size: 11px; }\n[data-edrv-view] .edrv-update-counts { flex: 1; min-width: 0; color: var(--dsw-alias-label-secondary, #485762); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-update-foot .edrv-svn-act { flex: none; min-width: 74px; }\n[data-edrv-view] .edrv-update-foot .edrv-svn-act:focus-visible, [data-edrv-view] .edrv-update-close:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2869b4); outline-offset: 2px; }\n[data-edrv-view] .edrv-update-foot .edrv-svn-act:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-update-raw { max-height: 120px; overflow: auto; padding: 0 14px 10px; font-size: 11px; }\n[data-edrv-view] .edrv-update-raw pre { white-space: pre-wrap; overflow-wrap: anywhere; margin: 5px 0; }\n@media (max-width: 620px) {\n [data-edrv-view] .edrv-update-head { gap: 6px; padding: 0 10px; }\n [data-edrv-view] .edrv-update-table { margin: 8px 8px 0; }\n [data-edrv-view] .edrv-update-cols, [data-edrv-view] .edrv-update-row { grid-template-columns: 76px minmax(0, 1fr); }\n [data-edrv-view] .edrv-update-cols > span:nth-child(3), [data-edrv-view] .edrv-update-row > span:nth-child(3) { display: none; }\n [data-edrv-view] .edrv-update-path { white-space: normal !important; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }\n [data-edrv-view] .edrv-update-foot { flex-wrap: wrap; padding: 8px; }\n [data-edrv-view] .edrv-update-counts { flex-basis: 100%; }\n}\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: var(--dsw-alias-label-primary-inverted, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-warn-primary, rgba(240,173,78,.45)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover, rgba(240,173,78,.12)); color: var(--dsw-alias-state-warn-primary, #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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.15)); color: var(--dsw-alias-state-success-primary, #0b7c46); }\n[data-edrv-view] .edrv-rules-type-auto { background: var(--dsw-alias-interactive-bg-hover-accent, rgba(79,140,255,.16)); color: var(--dsw-alias-link, #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: var(--dsw-alias-border-l2, #b9c4cc); cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: var(--dsw-alias-brand-primary, #7c5cff); }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--dsw-alias-bg-layer-1, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); 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: var(--dsw-alias-label-primary-inverted, #fff); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n/* 命令栏(Ctrl+Shift+P / F1):body 级 portal 浮层,故不依赖编辑区几何。\n ⚠️ 浮层 z-index 阶梯(自下而上;改动务必保持顺序,tests/overlayZOrder.test.ts 守约):\n 编辑器内浮层 60(.edrv-search-pop) / 71(.edrv-ctxmenu)\n < 190 命令栏遮罩 < 200 命令栏\n < 195 片段浮窗遮罩 < 197 片段二级弹窗遮罩\n 命令栏必须**高于**片段浮窗:曾因片段遮罩(192) 压过命令栏(191),导致片段浮窗打开时\n 命令栏被整体盖住,按 Ctrl+Shift+P 因「已打开即早退」而毫无反应(表现为快捷键失效)。 */\n[data-edrv-view] .edrv-palette-mask { position: fixed; inset: 0; z-index: 190; background: rgba(0, 0, 0, .28); }\n[data-edrv-view] .edrv-palette { position: fixed; top: 12vh; left: 50%; transform: translateX(-50%); z-index: 200; width: min(580px, calc(100vw - 32px)); max-height: 64vh; display: flex; flex-direction: column; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 12px 34px rgba(31, 41, 51, .24); overflow: hidden; }\n[data-edrv-view] .edrv-palette-input { height: 38px; flex: 0 0 auto; padding: 0 12px; border: none; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: transparent; color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; outline: none; }\n[data-edrv-view] .edrv-palette-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px; }\n[data-edrv-view] .edrv-palette-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; }\n[data-edrv-view] .edrv-palette-row.edrv-palette-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 157, 88, .10)); }\n[data-edrv-view] .edrv-palette-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-palette-cat { flex: 0 0 auto; font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-palette-key { flex: 0 0 auto; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 10px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-palette-empty { padding: 14px 10px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #7b8794); text-align: center; }\n[data-edrv-view] .edrv-palette-notice { flex: 0 0 auto; padding: 6px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-state-warn-primary, #b7791f); }\n\n/* 代码片段选择器(配置 / 插入):居中浮窗 + 新建二级弹窗。\n 卡片复用 mcp.css 的 .vsm-mcp-dialog(与「添加 MCP」「工作区选择」同一视觉语言),\n 此处只补遮罩、尺寸与列表布局。⚠️ 根节点须带 data-edrv-view,否则这些规则全部失配。 */\n[data-edrv-view] .edrv-snip-mask { position: fixed; inset: 0; z-index: 195; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, rgba(0, 0, 0, .55)); }\n/* 二级弹窗叠在一级浮窗之上(仍在命令栏之下,见上方阶梯说明) */\n[data-edrv-view] .edrv-snip-mask-top { z-index: 197; }\n[data-edrv-view] .edrv-snip-dialog { display: flex; flex-direction: column; overflow: hidden; width: min(620px, calc(100vw - 48px)); }\n[data-edrv-view] .edrv-snip-hint { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-list { display: flex; flex-direction: column; gap: 1px; min-height: 0; max-height: 46vh; overflow: auto; }\n[data-edrv-view] .edrv-snip-group { padding: 12px 2px 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-row { display: flex; align-items: center; gap: 4px; width: 100%; box-sizing: border-box; padding: 2px; border: none; border-radius: 8px; background: transparent; text-align: left; color: var(--dsw-alias-label-primary, #e6e6e6); font: inherit; }\n[data-edrv-view] .edrv-snip-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, .06)); }\n[data-edrv-view] button.edrv-snip-row { cursor: pointer; }\n[data-edrv-view] .edrv-snip-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border: none; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; color: inherit; font: inherit; }\n[data-edrv-view] .edrv-snip-label { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary, #e6e6e6); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-desc { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-src { flex: 0 0 auto; padding-right: 6px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-warn { flex: 0 0 auto; font-size: 11px; padding: 2px 7px; border-radius: 999px; background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .16)); color: var(--dsw-alias-state-warn-primary, #e5b93f); white-space: nowrap; }\n[data-edrv-view] .edrv-snip-act { flex: 0 0 auto; width: 26px; height: 26px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-snip-act:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n[data-edrv-view] .edrv-snip-empty { padding: 12px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n/* 当前文件语言提示条(片段按语言绑定,明确告知生效范围) */\n[data-edrv-view] .edrv-snip-langbar { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #2b2b2b); font-size: 12px; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-langbar b { color: var(--dsw-alias-label-primary, #e6e6e6); }\n/* 二级弹窗的动作按钮(原生 .vsm-mcp-dialog-actions 已提供排版与按钮样式) */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-dialog-actions { flex-wrap: wrap; }\n/* 删除图标按钮:.vsm-danger 的规则全部限定在 .vsm-mcp-actions button 之下,裸用无样式,此处补自有类 */\n[data-edrv-view] .edrv-snip-act.edrv-snip-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n/* 浮窗内的原生空态(.vsm-mcp-empty 默认为整页尺寸)压缩为对话框尺寸 */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-empty { padding: 26px 16px; border: 0; }\n\n\n\n\n\n/* 调试(DAP):断点圆点 / 停帧行 / 浮动调试工具条。\n 圆点挂在 Monaco glyphMargin(glyphMarginClassName),行背景为 isWholeLine className;\n 工具条绝对定位于编辑区右上(editorArea relative 由 .edrv-editor-area 自身定位)。 */\n/* 断点圆点:装饰类占满整行,圆点经 ::before 在本行盒子内居中(行归属明确、不跨行界) */\n[data-edrv-view] .edrv-dap-bp { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dap-bp-off { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-off::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n/* 未验证断点(适配器真实回执 verified:false):空心红圈,对齐 VS Code 空心圆语义 */\n[data-edrv-view] .edrv-dap-bp-unverified { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-unverified::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n[data-edrv-view] .edrv-dap-paused-line { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .22)); }\n[data-edrv-view] .edrv-dap-paused-glyph { cursor: pointer; }\n[data-edrv-view] .edrv-dap-paused-glyph::before { content: ''; display: block; width: 5px; height: 12px; margin: 4px auto 0; border-radius: 2px; background: var(--dsw-alias-state-warn-primary, #e5b93f); }\n[data-edrv-view] .edrv-editor-area { position: relative; }\n/* launch.json 右下角「添加配置」按钮(VSCode 同款形态):仅 launch.json 打开时渲染 */\n[data-edrv-view] .edrv-addcfg { position: absolute; right: 14px; bottom: 10px; z-index: 13; padding: 4px 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 18px; cursor: pointer; box-shadow: 0 1px 4px rgba(0, 0, 0, .1); }\n[data-edrv-view] .edrv-addcfg:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dapbar { position: absolute; top: 6px; right: 14px; z-index: 12; display: none; align-items: center; gap: 3px; padding: 3px 5px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #f7f9fa); box-shadow: 0 2px 8px rgba(0, 0, 0, .12); }\n[data-edrv-view] .edrv-dapbar.on { display: flex; border-color: var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapbar-grip { flex: 0 0 auto; width: 16px; height: 22px; display: inline-flex; align-items: center; justify-content: center; cursor: grab; user-select: none; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 12px; }\n[data-edrv-view] .edrv-dapbar-grip:active, [data-edrv-view] .edrv-dapbar.dragging .edrv-dapbar-grip { cursor: grabbing; }\n[data-edrv-view] .edrv-dapbar.dragging { user-select: none; }\n[data-edrv-view] .edrv-dapbar-cfg { max-width: 220px; height: 22px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapbar-btn { min-width: 24px; height: 22px; padding: 0 6px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 12px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dapbar-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dapbar-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-dapbar-phase { padding: 0 4px; font-size: 11px; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbar-phase.paused { color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dapbar-err { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--dsw-alias-state-error-primary, #e05252); }\n\n/* 调试面板(活动栏「调试」页签):四段折叠区 + 断点列表 + REPL。 */\n[data-edrv-view] .edrv-dappanel { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 0; overflow: auto; padding: 2px 2px 8px; }\n[data-edrv-view] .edrv-dappanel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; row-gap: 4px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dappanel-phase { padding: 2px 8px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dappanel-phase.paused { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .18)); color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dappanel-cfg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dappanel-pid { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-dappanel-err { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapseg { display: flex; flex-direction: column; gap: 2px; min-height: 0; }\n[data-edrv-view] .edrv-dapseg-body { min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; }\n/* 段间分隔条(splitview sash):拖动调整相邻两段高度占比;各段高度由 DebugPanel 内联接管。 */\n[data-edrv-view] .edrv-dapseg-sash { flex: 0 0 auto; height: 4px; margin: 2px 0; border-radius: 2px; background: transparent; cursor: row-resize; }\n[data-edrv-view] .edrv-dapseg-sash:hover, [data-edrv-view] .edrv-dapseg-sash.dragging { background: var(--dsw-alias-border-l2, #cdd6da); }\n/* 折叠段头:chevron + 标题 + 悬浮动作区(动作 hover 显隐;REPL 头不参与折叠)。 */\n[data-edrv-view] .edrv-dapseg-head { display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-tertiary, #7b8794); padding: 2px 2px; cursor: pointer; border-radius: 4px; }\n[data-edrv-view] .edrv-dapseg-head:hover { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-daprepl .edrv-dapseg-head { cursor: default; padding: 2px 0; }\n[data-edrv-view] .edrv-dapseg-chevron { flex: 0 0 auto; width: 14px; text-align: center; font-size: 10px; }\n[data-edrv-view] .edrv-dapseg-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapseg-act { flex: 0 0 auto; min-width: 20px; height: 18px; padding: 0 4px; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 11px; line-height: 1; cursor: pointer; opacity: 0; }\n[data-edrv-view] .edrv-dapseg-head:hover .edrv-dapseg-act { opacity: 1; }\n[data-edrv-view] .edrv-dapseg-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapempty { font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 4px 2px; }\n[data-edrv-view] .edrv-dapframe { display: flex; align-items: baseline; gap: 8px; padding: 3px 4px; border-radius: 6px; cursor: pointer; font-size: 12px; }\n[data-edrv-view] .edrv-dapframe:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapframe-name { color: var(--dsw-alias-label-primary, inherit); font-weight: 600; }\n[data-edrv-view] .edrv-dapframe-loc { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapscope { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); padding: 4px 2px 1px; }\n[data-edrv-view] .edrv-dapvar { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; font-size: 12px; padding: 1px 2px; min-width: 0; }\n[data-edrv-view] .edrv-dapvar-tw { flex: 0 0 auto; width: 14px; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 10px; padding: 0; }\n[data-edrv-view] span.edrv-dapvar-tw { cursor: default; }\n[data-edrv-view] .edrv-dapvar-name { flex: 0 1 34%; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, inherit); font-family: var(--ds-font-family-code, ui-monospace, monospace); white-space: nowrap; }\n[data-edrv-view] .edrv-dapvar-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapvar-type { flex: 0 0 auto; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapframe.selected { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .16)); outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapwatch { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; min-width: 0; font-size: 12px; padding: 1px 2px; }\n[data-edrv-view] .edrv-dapwatch-x { border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapwatch-x:hover { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapwatch-add { padding: 2px 0; }\n[data-edrv-view] .edrv-dapbp { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 2px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-dapbp:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapbp:active { background: var(--dsw-alias-interactive-bg-pressed, rgba(127, 127, 127, .2)); }\n[data-edrv-view] .edrv-dapbp-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dapbp-dot.off { background: transparent; border: 1.5px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n[data-edrv-view] .edrv-dapbp-file { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: none; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; padding: 0; font-size: 12px; }\n[data-edrv-view] .edrv-dapbp-dir { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; text-align: right; }\n[data-edrv-view] .edrv-dapbp-line { flex: 0 0 auto; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbp-x { flex: 0 0 auto; border: none; background: transparent; color: transparent; cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapbp:hover .edrv-dapbp-x { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapbp-x:hover { color: var(--dsw-alias-state-error-primary, #e05252) !important; }\n[data-edrv-view] .edrv-daprepl { display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-daprepl-log { display: flex; flex-direction: column; gap: 1px; max-height: 180px; overflow: auto; }\n[data-edrv-view] .edrv-daprepl-line { font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); white-space: pre-wrap; word-break: break-all; display: flex; gap: 6px; }\n[data-edrv-view] .edrv-daprepl-line.out { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-daprepl-in { width: 100%; box-sizing: border-box; height: 26px; padding: 0 8px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dappanel-run { flex: 0 0 auto; width: 24px; height: 24px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dappanel-run:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dappanel-run:disabled { opacity: .35; cursor: default; background: transparent; }\n/* 面板顶部配置下拉(与编辑器浮动条 .edrv-dapbar-cfg 同视觉)。 */\n[data-edrv-view] .edrv-dappanel-cfg-select { max-width: 190px; height: 24px; padding: 0 4px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n/* 断点行内编辑行(面板内展开编辑,控件复用 .edrv-bpwidget-* 视觉;左缩进对齐断点行文字列)。 */\n[data-edrv-view] .edrv-dapbp-edit { display: flex; align-items: center; gap: 6px; padding: 3px 2px 3px 20px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-mode { height: 20px; }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-input { height: 20px; }\n/* 断点回执:未验证空心红圈(须排在 .off 之后,禁用态优先展示灰圈语义)。 */\n[data-edrv-view] .edrv-dapbp-dot.unverified { background: transparent; border: 1.5px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n/* 断点行内编辑浮层(Monaco content widget,锚定断点行上方;对齐 VS Code breakpointWidget 形态)。 */\n/* View Zone 浮层:宽度/左移由 BpWidget.syncWidth 按 layout 内联设置\n (Monaco .view-zones 仅内容区宽,需补偿 contentLeft 与滚动条),此处只管视觉。 */\n[data-edrv-view] .edrv-bpwidget { position: relative; box-sizing: border-box; display: flex; align-items: center; gap: 6px; padding: 3px 8px; border-top: 1px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-layer-1, #f7f9fa); }\n/* 断点编辑中的目标行高亮(浮层打开期间) */\n[data-edrv-view] .edrv-dap-editing-line { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-bpwidget-mode { flex: 0 0 auto; height: 22px; padding: 0 4px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); cursor: pointer; }\n[data-edrv-view] .edrv-bpwidget-input { flex: 1 1 auto !important; min-width: 0; width: auto !important; box-sizing: border-box; height: 22px; padding: 0 6px; font-size: 12px; font-family: var(--ds-font-family-code, ui-monospace, monospace); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-bpwidget-input:focus { outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n\n/* 断点 hover 预览(glyph 区):半透明小红点 + pointer 光标(对齐 VS Code .codicon-debug-hint)。 */\n[data-edrv-view] .edrv-dap-bp-hint { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-hint::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); opacity: .4; }\n/* 行号区也给出可点提示(与 VS Code 一致:glyph 区与行号区都可点/可 hover);\n 不拦截折叠箭头等自有控件的光标。 */\n[data-edrv-view] .edrv-editor-row .monaco-editor .margin-view-overlays .line-numbers:hover { cursor: pointer; }\n\n/* 暂停态 hover 调试块 + 变量树(成员全量直显 + table 成员折叠展开)。\n ⚠️ 选择器一律用 data-*:本仓 vendored Monaco 的 markdown→DOM 管线会剥掉我们 HTML 里的\n class(supportHtml/isTrusted 都不豁免),只有 data-* 存活;用 class 会静默失效。 */\n[data-edrv-view] [data-edrv-dap] { display: block; min-width: 0; }\n[data-edrv-view] [data-edrv-head] { display: flex; align-items: baseline; gap: 2px; }\n[data-edrv-view] [data-edrv-head] [data-edrv-expr] { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-head] [data-edrv-val] { font-family: var(--ds-font-family-code, ui-monospace, monospace); word-break: break-all; }\n[data-edrv-view] [data-edrv-type] { margin-top: 2px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-tree] { margin: 2px 0 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }\n[data-edrv-view] [data-edrv-line] { display: flex; align-items: baseline; gap: 4px; padding: 1px 2px; border-radius: 3px; white-space: nowrap; }\n[data-edrv-view] [data-edrv-line]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n/* 折叠按钮(对齐 CodeBuddy 调试浮窗变量树的 twist):热区 14px + hover 反馈,未可展开时留空占位 */\n[data-edrv-view] [data-edrv-twist] { flex: 0 0 auto; box-sizing: border-box; width: 14px; height: 14px; line-height: 13px; text-align: center; border-radius: 3px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-twist]:not(:empty) { cursor: pointer; user-select: none; }\n[data-edrv-view] [data-edrv-twist]:not(:empty):hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .2)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-name] { flex: 0 0 auto; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-line] [data-edrv-eq] { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-line] [data-edrv-val] { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] [data-edrv-note] { color: var(--dsw-alias-label-tertiary, #8a949b); font-style: italic; }\n/* Alt 提示层:由 hoverTree 注入到 .monaco-hover(滚动区之外)贴底常驻;容器预留同高内边距避免遮挡末行。\n 不再用 sticky / `:has()`:滚动链在 .monaco-hover-content 上,sticky 会被滚走。 */\n[data-edrv-view] .monaco-hover[data-edrv-hint-host=\"1\"] { padding-bottom: 22px; }\n[data-edrv-view] [data-edrv-hint=\"1\"] { position: absolute; left: 0; right: 0; bottom: 0; box-sizing: border-box; height: 22px; padding: 2px 8px; font-size: 11px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8a949b); background: var(--dsw-alias-bg-overlay, #ffffff); border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n\n/* Workbench panes: existing theme, action-driven drop previews. ddj 2026年10月14号 */\n[data-edrv-view] .edrv-group, [data-edrv-view] .edrv-group-body,\n[data-edrv-view] .edrv-full-slot, [data-edrv-view] .edrv-full-view,\n[data-edrv-view] .edrv-passive-view { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-group { border: 0; }\n[data-edrv-view] .edrv-group .edrv-tabs { flex: 0 0 auto; touch-action: none; }\n[data-edrv-view] .edrv-group-tab-name { overflow: hidden; text-overflow: ellipsis; max-width: 180px; }\n[data-edrv-view] .edrv-split { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-split-vertical { flex-direction: column; }\n[data-edrv-view] .edrv-split-child { display: flex; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-split-handle { flex: 0 0 5px; background: var(--dsw-alias-border-l1, #e0e6e8); cursor: col-resize; touch-action: none; }\n[data-edrv-view] .edrv-split-vertical > .edrv-split-handle { cursor: row-resize; }\n[data-edrv-view] .edrv-split-handle:hover, [data-edrv-view] .edrv-split-handle:focus-visible { background: var(--dsw-alias-state-info-primary, #4d6bfe); }\n[data-edrv-view].edrv-floating { position: fixed; display: flex; flex-direction: column; overflow: hidden; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-base, #fff); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: 0 8px 28px rgba(0,0,0,.22); }\n[data-edrv-view] .edrv-floating-title { display: flex; align-items: center; gap: 8px; flex: 0 0 32px; padding: 0 8px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); cursor: move; touch-action: none; user-select: none; }\n[data-edrv-view] .edrv-floating-title > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-floating-content { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; overflow: auto; box-sizing: border-box; }\n[data-edrv-view] .edrv-floating-content.edrv-svnlog-dialog { padding: 12px; overflow: auto; }\n[data-edrv-view] .edrv-floating-content.edrv-svn-patch-dialog,\n[data-edrv-view] .edrv-floating-content.edrv-svn-sum-dialog,\n[data-edrv-view] .edrv-floating-content.edrv-svnplan-dialog { padding: 12px; max-width: none; gap: 8px; }\n[data-edrv-view] .edrv-floating-content.edrv-svnlog-stats { max-height: none; }\n[data-edrv-view] .edrv-floating-content .edrv-svn-patch-pre,\n[data-edrv-view] .edrv-floating-content .edrv-svn-sum-list { flex: 1; min-height: 0; max-height: none; }\n[data-edrv-view] .edrv-floating-content .edrv-svnlog-filter,\n[data-edrv-view] .edrv-floating-content .edrv-svn-sum-form { flex-wrap: wrap; }\n[data-edrv-view] .edrv-floating-content > .edrv-svnlog-head,\n[data-edrv-view] .edrv-floating-content > .edrv-svnlog-filter,\n[data-edrv-view] .edrv-floating-content > .edrv-svnlog-foot { flex-shrink: 0; }\n[data-edrv-view] .edrv-floating-title > button { border: 0; background: transparent; color: inherit; cursor: pointer; }\n[data-edrv-view] .edrv-floating-grip { position: absolute; width: 16px; height: 16px; bottom: 0; right: 0; cursor: nwse-resize; touch-action: none; border-right: 3px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 3px solid var(--dsw-alias-border-l2, #cdd6da); }\n.edrv-drag-overlay { position: fixed; z-index: 150; pointer-events: none; box-sizing: border-box; border: 0; background: color-mix(in srgb, var(--dsw-alias-state-info-primary, #4d6bfe) 25%, transparent); }\n.edrv-drop-label, .edrv-drag-ghost { position: fixed; z-index: 151; pointer-events: none; padding: 4px 8px; background: var(--dsw-alias-bg-overlay, #fff); color: var(--dsw-alias-label-primary, #1f2933); border: 1px solid var(--dsw-alias-border-l2, #cdd6da); font-size: 12px; white-space: nowrap; }\n.edrv-drop-label { position: absolute; left: 4px; top: 4px; }\n[data-edrv-view] .edrv-tab:focus-visible { outline: 2px solid var(--dsw-alias-state-info-primary, #4d6bfe); outline-offset: -2px; }\n@media (prefers-reduced-motion: reduce) { .edrv-drag-overlay { transition: none; } }\n";
|
|
36
|
+
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 主题:跟随官方 --dsw-alias-* 令牌(DSH 明暗与第三方皮肤生效)。\n 本作用域不再重定义官方令牌(旧实现曾在此硬覆盖浅色盘,导致插件不跟随 DSH 主题);\n 旧环境/缺令牌场景由每条声明的 var(--dsw-alias-*, 回落值) 兜底。\n @author ddj 2026-09-10 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; }\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; overflow-y: hidden; scrollbar-width: thin; flex-shrink: 0; overscroll-behavior-x: contain; } /* overscroll-behavior-x: 横滚到边界不把滚动链传给页面(滚轮横滚接管更可控)@author ddj 2026年09月18号 */\n[data-edrv-view] .edrv-tab { user-select: none; -webkit-user-select: none; 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-star { color: var(--dsw-alias-brand-primary, #4f8cff); font-size: 13px; font-weight: 700; line-height: 1; flex-shrink: 0; } /* 未保存修改星号 @author ddj 2026年09月09号 */\n[data-edrv-view] .edrv-tab .edrv-tab-x { appearance: none; display: inline-flex; align-items: center; justify-content: center; flex: 0 0 16px; width: 16px; height: 16px; padding: 0; border: 0; border-radius: 4px; background: transparent; box-shadow: none; color: var(--dsw-alias-label-tertiary, #888); font-family: inherit; font-size: 11px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:focus-visible { outline: 1px solid var(--dsw-alias-state-info-primary, #4d6bfe); outline-offset: 1px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.12)); color: var(--dsw-alias-label-primary, #eee); }\n/* 固定页签:📌 标记 + 免关闭按钮(固定页签不渲染 ×,仅可经右键菜单取消固定) */\n[data-edrv-view] .edrv-tab .edrv-tab-pin { flex-shrink: 0; font-size: 10px; line-height: 1; opacity: .85; }\n[data-edrv-view] .edrv-tab.edrv-tab-pinned { background: var(--dsw-alias-bg-layer-2, rgba(255,255,255,.04)); }\n/* 页签行 = 可横滚的页签区 + 行尾固定工具列(计划预览页签与磁盘页签同处这一行的滚动区)@author ddj 2026年10月20号 */\n[data-edrv-view] .edrv-tabs-row { display: flex; align-items: center; min-width: 0; flex: 0 0 auto; background: var(--dsw-alias-bg-layer-1, transparent); }\n/* 特异性需盖过下面 .edrv-group .edrv-tabs 的 flex: 0 0 auto,页签区才能吃掉行走宽、把工具列压到行尾 */\n[data-edrv-view] .edrv-group .edrv-tabs-row > .edrv-tabs { flex: 1 1 auto; min-width: 0; background: transparent; }\n[data-edrv-view] .edrv-tabs-tools { display: flex; align-items: center; gap: 2px; flex: 0 0 auto; padding: 0 6px 0 2px; }\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/* 非焦点分组的静态路径条(GroupPathbar):可点击聚焦所属组,悬停给反馈 @author ddj 2026-10-16 */\n[data-edrv-view] .edrv-pathbar[data-edrv-pb-static] { cursor: pointer; }\n[data-edrv-view] .edrv-pathbar[data-edrv-pb-static]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-pb-update { display: inline-flex; align-items: center; gap: 4px; height: 20px; flex: none; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l1, #d9e0e4); border-radius: 4px; background: var(--dsw-alias-bg-layer-2, #f1f4f5); color: var(--dsw-alias-label-secondary, #485762); font-size: 11px; cursor: pointer; }\n[data-edrv-view] .edrv-pb-update:hover { background: var(--dsw-alias-interactive-bg-hover, #e7edf0); }\n[data-edrv-view] .edrv-pb-update:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2869b4); outline-offset: 1px; }\n@media (max-width: 620px) { [data-edrv-view] .edrv-pb-update { width: 24px; padding: 0 4px; overflow: hidden; font-size: 0; } }\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/* 键盘高亮项(↑↓ 选择):与 hover 同特异性但声明在后,故选中态稳定可辨 @author ddj 2026年09月11号 */\n[data-edrv-view] .edrv-search-item.edrv-search-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.14)); }\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: var(--dsw-alias-label-primary-inverted, #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/* 跳转目标区域高亮(LSP 定义/引用、搜索命中落点):落点一眼可见,约 1.2s 后由 EditorView 自动清除。\n 用官方令牌并带回落值,不在插件作用域重定义 --dsw-* (否则永久脱离官方主题)。 */\n[data-edrv-view] .edrv-nav-target { background: var(--dsw-alias-interactive-bg-hover, rgba(79,193,255,.28)); border-radius: 2px; box-shadow: 0 0 0 1px var(--dsw-alias-interactive-primary, rgba(79,193,255,.55)); }\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/* 行内和原生 Monaco diff 共用主题色盘;不再借用普通 hover 的灰底。 */\n[data-edrv-view] .edrv-mn-add-line { background: var(--edrv-diff-add, #e6f4e8); }\n[data-edrv-view] .edrv-mn-gutter-add { background: var(--edrv-diff-add, #e6f4e8); color: var(--dsw-alias-state-success-primary, #0f9d58) !important; 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, [data-edrv-view] .edrv-del-margin { background: var(--edrv-diff-del, #fbe7e3); color: var(--edrv-diff-fg, #1e1e1e); }\n[data-edrv-view] .edrv-del-row { white-space: pre; height: var(--edrv-line-height, 20px); line-height: var(--edrv-line-height, 20px); }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-del-margin-row { position: relative; height: var(--edrv-line-height, 20px); line-height: var(--edrv-line-height, 20px); }\n[data-edrv-view] .edrv-del-number { position: absolute; left: var(--edrv-number-left); width: var(--edrv-number-width); color: var(--edrv-diff-number, #6c6c6c); text-align: right; }\n[data-edrv-view] .edrv-del-marker { position: absolute; left: var(--edrv-marker-left); width: var(--edrv-marker-width); color: var(--dsw-alias-state-error-primary, #d9534f); text-align: center; }\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-imgview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-imgview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-imgview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 图片预览:居中交给子项 margin:auto(auto 外边距优先吃正向空闲空间;溢出时空闲为负 → 外边距归 0、\n flex-start 起点对齐 → 放大后四边均可滚动到达,规避 justify-content:center 双侧溢出不可达问题) */\n[data-edrv-view] .edrv-imgview-stage { flex: 1 1 auto; min-height: 0; display: flex; overflow: auto; padding: 14px; background-color: var(--dsw-alias-bg-layer-1, #f0f4f4); background-image: conic-gradient(rgba(128,128,128,.14) 25%, transparent 0 50%, rgba(128,128,128,.14) 0 75%, transparent 0); background-size: 16px 16px; }\n[data-edrv-view] .edrv-imgview-img { max-width: 100%; max-height: 100%; flex-shrink: 0; margin: auto; align-self: flex-start; object-fit: contain; border-radius: 4px; box-shadow: 0 2px 12px rgba(31,41,51,.18); }\n[data-edrv-view] .edrv-imgview-broken { display: flex; flex-direction: column; align-items: center; gap: 10px; font-size: 13px; color: var(--dsw-alias-label-tertiary, #777); margin: auto; }\n[data-edrv-view] .edrv-pdf-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-host > .edrv-pdf { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-pdf { min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-pdf-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-pdf-page { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; min-width: 52px; text-align: center; }\n[data-edrv-view] .edrv-pdf-zoom { min-width: 26px; text-align: center; padding: 3px 7px; }\n[data-edrv-view] .edrv-pdf-sep { width: 1px; height: 16px; background: var(--dsw-alias-border-l1, #e0e6e8); margin: 0 2px; }\n[data-edrv-view] .edrv-pdf-mode-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.12)); color: var(--dsw-alias-brand-primary, #0f9d58); border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-pdf-dirty { color: var(--dsw-alias-state-warn-primary, #d97706); border-color: var(--dsw-alias-state-warn-primary, #d97706); }\n[data-edrv-view] .edrv-pdf-stage { position: absolute; top: 34px; left: 0; right: 0; bottom: 0; overflow: auto; }\n/* Markdown 预览(需求 4):工具条 + 居中阅读栏;正文排版由官方 MarkdownText 自带的 --dsw-* 样式负责 */\n[data-edrv-view] .edrv-mdview { flex: 1 1 auto; min-width: 0; min-height: 0; display: flex; flex-direction: column; overflow: hidden; }\n[data-edrv-view] .edrv-mdview-bar { display: flex; align-items: center; gap: 8px; height: 34px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, transparent); }\n[data-edrv-view] .edrv-mdview-meta { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n[data-edrv-view] .edrv-mdview-stage { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 14px 20px 28px; }\n[data-edrv-view] .edrv-mdview-doc { max-width: 880px; margin: 0 auto; width: 100%; }\n[data-edrv-view] .edrv-mdview-fallback { font-size: 12px; line-height: 1.7; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-mdview-pre { margin: 8px 0 0; padding: 10px 12px; border-radius: 8px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; }\n[data-edrv-view] .edrv-pb-mdbtn { height: 20px; padding: 0 8px; font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-pdf-stage .edrv-pdf-viewer { margin: 0 auto; }\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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); color: var(--dsw-alias-state-success-primary, #0f7a45); border: 1px solid var(--dsw-alias-state-success-primary, rgba(15,157,88,.4)); }\n[data-edrv-view] .edrv-pill-undo { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); color: var(--dsw-alias-state-error-primary, #c0392b); border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-pill-ghost { background: var(--dsw-alias-bg-layer-1, #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 页签菜单 11 条 + 键位提示,故限高可滚(ContextMenu 以实测尺寸做 viewport clamp)。\n ⚠️ z-index 71 在既有浮层阶梯内(见文件末尾命令栏注释),不得上调越过命令栏/片段浮窗。 */\n[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 220px; max-width: 360px; max-height: min(70vh, 520px); overflow-y: auto; 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/* 菜单项文案(弹性占宽,超出省略)与右侧键位提示(不缩放,等宽字体) */\n[data-edrv-view] .edrv-ctxmenu-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-hint { flex: 0 0 auto; padding-left: 18px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-ctxmenu-item:disabled .edrv-ctxmenu-hint,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled .edrv-ctxmenu-hint { color: var(--dsw-alias-label-disabled, #b0b7c0); }\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: var(--dsw-alias-state-warn-primary, 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/* 侧栏差异栏在编辑内容底部居中悬浮,按内容宽度收缩;窄栏只在工具条内横滚。@author ddj 2026年09月29号 */\n[data-edrv-view] .edrv-side-diff-dock[data-edrv-diff-dock-shell] { position: absolute; left: 50%; bottom: 28px; z-index: 25; width: max-content; max-width: calc(100% - 20px); max-height: min(300px, calc(100% - 38px)); margin: 0; transform: translateX(-50%); border-radius: 12px; background: var(--dsw-alias-bg-overlay, #fff); box-shadow: 0 6px 20px rgba(0,0,0,.18); overflow-x: hidden; overflow-y: auto; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-editor-row { padding-inline: 8px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-editor-content { gap: 5px; width: max-content; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-nav,\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-files,\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-actions { gap: 3px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-pill { padding-inline: 5px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-files .edrv-diffbar-file { min-width: 0; max-width: 72px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-details-toggle { width: 26px; min-width: 26px; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diffbar-body { max-height: min(180px, 25vh); max-width: 100%; }\n[data-edrv-view] .edrv-side-diff-dock .edrv-diff-details { max-height: min(260px, 35vh); overflow-y: auto; }\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; display: inline-flex; align-items: center; justify-content: center; }\n/* 树行图标:官方原语(文件夹/文件类型),尺寸与行高对齐 @author ddj 2026-09-10 */\n[data-edrv-view] .edrv-tree-icon { flex-shrink: 0; display: inline-flex; align-items: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-tree-row.edrv-tree-active .edrv-tree-icon { color: var(--dsw-alias-label-secondary, #52606d); }\n/* SVN overlays: official file icon remains visible, independent local/remote signs. ddj 2026-10-09 */\n[data-edrv-view] .edrv-tree-iconbox { position: relative; display: inline-flex; width: 20px; height: 20px; align-items: center; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-overlay { position: absolute; inset: 0; }\n[data-edrv-view] .edrv-svn-local { position: absolute; right: -1px; bottom: -2px; display: flex; border-radius: 50%; box-shadow: 0 0 0 1px var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-svn-icon-clean { color: #16853b; }\n[data-edrv-view] .edrv-svn-icon-modified, [data-edrv-view] .edrv-svn-icon-deleted { color: #d12e35; }\n[data-edrv-view] .edrv-svn-icon-conflict { color: #c27300; }\n[data-edrv-view] .edrv-svn-icon-added { color: #2465c9; }\n[data-edrv-view] .edrv-svn-icon-unversioned, [data-edrv-view] .edrv-svn-icon-ignored, [data-edrv-view] .edrv-svn-icon-external { color: #75808c; }\n[data-edrv-view] .edrv-svn-remote { position: absolute; right: -3px; top: -4px; color: #2465c9; background: var(--dsw-alias-bg-layer-1, #fff); border-radius: 3px; font-size: 11px; font-weight: 900; line-height: 12px; }\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: var(--dsw-alias-label-primary-inverted, #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/* Virtual rows and placeholders share the same geometry as treeWindow.ts. @author ddj 2026年10月22号 */\n[data-edrv-view] .edrv-tree.edrv-tree-virtual { padding-top: 0; padding-bottom: 0; }\n[data-edrv-view] .edrv-tree-virtual .edrv-tree-row,\n[data-edrv-view] .edrv-tree-virtual .edrv-tree-loading { height: 24px; min-height: 24px; box-sizing: border-box; }\n[data-edrv-view] .edrv-tree-virtual .edrv-tree-loading { line-height: 24px; }\n[data-edrv-view] .edrv-large-text { flex: 1; min-width: 0; min-height: 0; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-large-text-toolbar { display: flex; flex-wrap: wrap; gap: 8px; align-items: center; }\n[data-edrv-view] .edrv-large-text-content { margin: 0; flex: 1; min-height: 0; overflow: auto; white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); user-select: text; }\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/* 「在资源管理器视图中显示」的定位高亮(短时淡出,区别于常驻的 active 态) */\n[data-edrv-view] .edrv-tree-row.edrv-tree-reveal { box-shadow: inset 0 0 0 1px var(--dsw-alias-brand-primary, #0f9d58); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); animation: edrv-tree-reveal-fade 2s ease-out; }\n@keyframes edrv-tree-reveal-fade { from { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.32)); } to { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.18)); } }\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: var(--dsw-alias-label-primary-inverted, #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/* SVN 状态独立占位:换行不覆盖文件树,长错误在栏内滚动。@author ddj 2026-10-12 */\n[data-edrv-view] .edrv-tree-status { flex: 0 0 auto; min-width: 0; max-height: 96px; overflow: auto; padding: 4px 8px; box-sizing: border-box; line-height: 18px; white-space: normal; overflow-wrap: anywhere; 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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); 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/* ===== SVN 变更面板(工作副本状态列表;颜色分级对齐 TortoiseSVN 口径) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svn-toolbar { display: flex; align-items: center; gap: 12px; padding: 4px 10px 6px 12px; flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svn-check { display: inline-flex; align-items: center; gap: 4px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-check input { margin: 0; cursor: pointer; }\n[data-edrv-view] .edrv-svn-bulk { display: flex; align-items: center; gap: 6px; padding: 0 10px 6px 12px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-count { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* AI 助手 dock(12-panel-ai-bar 设计定稿):manifest 分带之 assistant 带,accent 左竖轨为唯一记忆点。\n AI 线程色三处同轨:竖轨 / dock 按钮描边 / 弹窗进度条(--dsw-alias-state-info-primary)。 @author ddj 2026-09-23 */\n[data-edrv-view] .edrv-svn-ai-bar { position: relative; display: flex; align-items: center; gap: 8px; padding: 6px 10px 6px 14px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-ai-rail { position: absolute; left: 0; top: 0; bottom: 0; width: 3px; background: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-ai-label { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svn-ai-btn { border-color: var(--dsw-alias-state-info-primary, #2f6fed); color: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-ai-btn:disabled { border-color: var(--dsw-alias-border-l1, #e0e6e8); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 状态位定宽右对齐(就绪/分析中…/等待助手投递…互换不跳版) */\n[data-edrv-view] .edrv-svn-ai-status { flex-shrink: 0; min-width: 88px; text-align: right; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; }\n/* 批量条语义分隔(导出簇 ┊ 动作簇之间 1px 竖线) */\n[data-edrv-view] .edrv-svn-sep { width: 1px; height: 14px; background: var(--dsw-alias-border-l1, #e0e6e8); flex-shrink: 0; }\n/* 头部图标组(检查远端/刷新成组,gap 收紧) */\n[data-edrv-view] .edrv-svn-head-icons { display: inline-flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-list { flex: 1; min-height: 0; overflow: auto; padding: 2px 6px 12px; font-size: 12px; }\n[data-edrv-view] .edrv-svn-group { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; margin: 2px 0; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; font-weight: 600; cursor: pointer; user-select: none; }\n[data-edrv-view] .edrv-svn-group:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-fold-ch { width: 10px; flex-shrink: 0; text-align: center; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svn-group-n { margin-left: auto; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-weight: 400; }\n[data-edrv-view] .edrv-svn-row { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svn-path { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-row:hover .edrv-svn-acts { display: inline-flex; }\n[data-edrv-view] .edrv-svn-act { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-secondary, #52606d); font-size: 10px; line-height: 14px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svn-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svn-act:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-svn-act-danger { color: var(--dsw-alias-state-error-primary, #d9534f); border-color: var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); }\n[data-edrv-view] .edrv-svn-ch { display: inline-flex; align-items: center; justify-content: center; width: 14px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-weight: 700; }\n[data-edrv-view] .edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svn-ch-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* .edrv-svn-ch-* 动作词表补全:replaced(替换)= 琥珀;侧栏状态分级(SVN_STATUS_TONE)不受影响 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svn-ch-replaced { color: var(--dsw-alias-state-warn-primary, #d97706); }\n/* 文件树行尾 SVN 状态徽标(与差异角标并列;方形字母,区别圆形差异计数) */\n[data-edrv-view] .edrv-tree-svn { min-width: 14px; height: 14px; padding: 0 4px; border-radius: 4px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; line-height: 14px; text-align: center; box-sizing: border-box; flex-shrink: 0; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-modified { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-deleted { color: var(--dsw-alias-label-secondary, #b91c1c); }\n[data-edrv-view] .edrv-tree-svn.edrv-svn-ch-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* ===== SVN 基线差异视图(BASE 左 / 工作区右,只读并排) @author ddj 2026-09-16 ===== */\n[data-edrv-view] .edrv-svndiff { display: flex; flex-direction: column; flex: 1 1 auto; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-svndiff-bar { display: flex; align-items: center; gap: 8px; height: 30px; padding: 0 10px; flex-shrink: 0; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svndiff-title { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svndiff-tag { padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svndiff-host { flex: 1 1 auto; min-height: 0; }\n[data-edrv-view] .edrv-svndiff-empty { display: flex; flex: 1 1 auto; align-items: center; justify-content: center; padding: 24px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 12px; text-align: center; }\n/* 差异整行色块与行首 +/- 指示符:vendored Monaco(diffEditorWidget2)静态 CSS 无\n .line-insert/.line-delete 背景规则,整行色块靠主题键 + 此处固定色兜底保证可见。\n 注意不要用 --dsw-alias-interactive-bg-hover 类 token:实测为 92% 透明中性色,肉眼不可见。\n 固定色取自研差异 UI 同色相(绿 #0f9d58 / 红 #d9534f),alpha 提到肉眼可辨。 */\n[data-edrv-view] .monaco-editor .line-insert { background: rgba(15, 157, 88, 0.18); }\n[data-edrv-view] .monaco-editor .line-delete { background: rgba(217, 83, 79, 0.16); }\n[data-edrv-view] .monaco-editor .gutter-insert { background: rgba(15, 157, 88, 0.35); }\n[data-edrv-view] .monaco-editor .gutter-delete { background: rgba(217, 83, 79, 0.35); }\n[data-edrv-view] .monaco-editor .insert-sign { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .monaco-editor .delete-sign { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* 差异条快速跳转簇(对齐自研审查条 ↑ i/N ↓ 的形态) */\n[data-edrv-view] .edrv-svndiff-nav { display: flex; align-items: center; gap: 2px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svndiff-nav-count { min-width: 36px; text-align: center; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); }\n/* W1-3 差异统计徽标(+新增/修改 −删除/修改;色相与行块绿红一致) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svndiff-stat { display: inline-flex; align-items: center; gap: 4px; flex-shrink: 0; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svndiff-stat-add { color: var(--dsw-alias-state-success-primary, #0f9d58); }\n[data-edrv-view] .edrv-svndiff-stat-del { color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W1-1 差异视图选项条(右端开关组;复用 .edrv-svn-check 的 label 形态) */\n[data-edrv-view] .edrv-svndiff-opts { display: flex; align-items: center; gap: 8px; flex-shrink: 0; }\n/* W1-2 变更面板名称过滤输入框(工具条行内,紧凑) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-name-filter { width: 168px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 14px; }\n[data-edrv-view] .edrv-svn-name-filter:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #0f9d58); }\n[data-edrv-view] .edrv-svn-name-filter::placeholder { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* W2-3 远端更新提示条(工具条上方;warn = 失败降级) @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-hintbar { display: flex; align-items: center; gap: 6px; margin: 0 10px 4px 12px; padding: 3px 8px; border-radius: 5px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); font-size: 11px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svn-hintbar-warn { background: rgba(217, 83, 79, 0.12); color: var(--dsw-alias-state-error-primary, #d9534f); }\n/* W2-5 疑似改名标记(行内 ⇄;hover 见 tooltip) */\n[data-edrv-view] .edrv-svn-pair-mark { flex-shrink: 0; color: var(--dsw-alias-state-warn-primary, #7c3aed); font-size: 11px; cursor: help; }\n/* W2-1 补丁对话框 / W2-2 目录对比对话框 @author ddj 2026-09-20 */\n[data-edrv-view] .edrv-svn-patch-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svn-patch-head { display: flex; align-items: center; gap: 8px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-patch-notes { display: flex; flex-direction: column; gap: 4px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svn-patch-warn { color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-svn-patch-pre { max-height: 46vh; overflow: auto; margin: 0 0 8px; padding: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); color: var(--dsw-alias-label-primary, #1f2933); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.5; white-space: pre; user-select: text; }\n[data-edrv-view] .edrv-svn-patch-foot { display: flex; align-items: center; gap: 8px; }\n/* AI 智能整理弹窗(11-ai-changelist-triage):预览三分组卡 + 执行进度 @author ddj 2026-09-23 */\n[data-edrv-view] .edrv-svnplan-dialog { max-width: calc(100vw - 48px); }\n[data-edrv-view] .edrv-svnplan-head { display: flex; align-items: center; gap: 8px; padding-bottom: 4px; }\n[data-edrv-view] .edrv-svnplan-meta { display: flex; gap: 10px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svnplan-note { color: var(--dsw-alias-state-warn-primary, #b7791f); font-size: 10px; }\n[data-edrv-view] .edrv-svnplan-sec { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 6px 8px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnplan-sechead { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnplan-sectitle { font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-list { max-height: 26vh; overflow: auto; padding-left: 18px; }\n[data-edrv-view] .edrv-svnplan-card { border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); padding: 3px 0; }\n[data-edrv-view] .edrv-svnplan-row { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnplan-item { display: flex; align-items: center; gap: 6px; padding-left: 18px; }\n[data-edrv-view] .edrv-svnplan-groupname { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 46ch; }\n[data-edrv-view] .edrv-svnplan-reason { font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; max-width: 30ch; }\n[data-edrv-view] .edrv-svnplan-stage { display: flex; align-items: center; gap: 8px; padding-bottom: 6px; }\n[data-edrv-view] .edrv-svnplan-badge { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; padding: 1px 8px; font-size: 10px; color: var(--dsw-alias-label-secondary, #52606d); background: var(--dsw-alias-bg-layer-2, #f7f9f9); white-space: nowrap; }\n[data-edrv-view] .edrv-svnplan-badge-cur { font-family: var(--ds-font-family-code, ui-monospace, monospace); overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnplan-bar { height: 6px; border-radius: 3px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow: hidden; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnplan-bar-in { height: 100%; background: var(--dsw-alias-state-info-primary, #2f6fed); transition: width .2s; }\n[data-edrv-view] .edrv-svnplan-logwrap { max-height: 40vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 6px 8px; background: var(--dsw-alias-bg-layer-2, #f7f9f9); }\n[data-edrv-view] .edrv-svnplan-log { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.6; color: var(--dsw-alias-label-secondary, #52606d); user-select: text; }\n[data-edrv-view] .edrv-svnplan-log-bad { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-svnplan-foot { display: flex; align-items: center; gap: 8px; }\n[data-edrv-view] .edrv-svnplan-primary { font-weight: 600; border-color: var(--dsw-alias-state-info-primary, #2f6fed); }\n[data-edrv-view] .edrv-svn-sum-form { display: flex; align-items: center; gap: 10px; padding-bottom: 8px; }\n[data-edrv-view] .edrv-svn-sum-list { max-height: 44vh; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; padding: 2px; margin-bottom: 8px; }\n[data-edrv-view] .edrv-svnlog-path-kind { flex-shrink: 0; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 10px; }\n\n/* ===== 通用弹窗外壳(ModalShell)+ SVN 日志弹窗 @author ddj 2026-09-16 ===== */\n/* z-index 190:落在既有阶梯内(命令栏 200 > 片段二级 197 > 片段一级 195 > 190),\n 不遮挡命令栏;既有浮层数值不受影响(见 tests/overlayZOrder.test.ts)。 */\n[data-edrv-view] .edrv-modal-mask { position: fixed; inset: 0; z-index: 190; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, #000000aa); }\n[data-edrv-view] .edrv-svnlog-dialog { position: relative; display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-head { display: flex; align-items: center; gap: 10px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-title { margin: 0; font-size: 16px; font-weight: 650; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n/* 头部目标路径 = 代码 chip(mono + 底色 + 全圆角;补丁/目录对比弹窗共用同视觉) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-target { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); max-width: 320px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; padding: 2px 10px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n/* 关闭按钮图标化(透明底,hover 显形;dialog 前缀提高特异性,压过底部按钮统一尺寸) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svnlog-head .edrv-svn-act { border-color: transparent; background: transparent; width: 24px; height: 24px; padding: 0; font-size: 12px; line-height: 1; }\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svnlog-head .edrv-svn-act:hover { border-color: var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n/* 过滤栏:浅色表面条 + 统一 24px 控件 + 焦点边框变色 + 日期组靠右 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-filter { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; padding: 6px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-field { flex: 0 0 auto; height: 24px; box-sizing: border-box; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-search { min-width: 160px; flex: 1 1 220px; height: 24px; box-sizing: border-box; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-field:focus, [data-edrv-view] .edrv-svnlog-search:focus, [data-edrv-view] .edrv-svnlog-date:focus { outline: none; border-color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-dates { display: inline-flex; align-items: center; gap: 8px; margin-left: auto; }\n[data-edrv-view] .edrv-svnlog-date { height: 24px; box-sizing: border-box; padding: 0 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-check { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-check input[type=\"checkbox\"] { margin: 0; cursor: pointer; accent-color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n/* P0-14 上中下三段全宽:body 纵向铺满弹窗(外框高度由拖拽受控) */\n[data-edrv-view] .edrv-svnlog-body { display: flex; flex-direction: column; gap: 6px; flex: 1 1 auto; min-height: 0; }\n/* 上段修订列表(13-log-ui-polish 变更台账):\n 1px 发丝边框 + 底色面 + 左侧时间脊线(每行 ::before 画节点圆点、行盒左缘 ::after 连线段,\n 行行相接即整列脊线;选中行节点实心着色 + 2px 左强调条)。列宽由 cell 类与 nth-child 对齐(P0-12/D30)。 */\n[data-edrv-view] .edrv-svnlog-list { position: relative; flex: 0 0 auto; display: flex; flex-direction: column; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 0 4px 4px; background: var(--dsw-alias-bg-layer-1, #fff); }\n/* 列头 sticky:滚动常驻 + 实底防透;z-index 20 低于一切浮层(190 起),仅在列表滚动容器内生效 */\n[data-edrv-view] .edrv-svnlog-cols { position: sticky; top: 0; z-index: 20; display: flex; align-items: center; gap: 6px; padding: 6px 6px 6px 16px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #fff); font-size: 10px; font-weight: 600; letter-spacing: .04em; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(1) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(2) { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(3) { width: 88px; flex: none; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(4) { width: 82px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cols .edrv-svnlog-col:nth-child(5) { flex: 1 1 auto; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-svnlog-col-sortable { cursor: pointer; }\n[data-edrv-view] .edrv-svnlog-col-sortable:hover { color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-col-on { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-sort-reset { flex: none; }\n/* 行:position:relative 承载脊线节点(::before)与连线段(::after);选中 = 强调条 + 节点实心 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-item { position: relative; display: flex; align-items: center; gap: 6px; padding: 3px 6px 3px 16px; border-radius: 6px; cursor: pointer; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-item::before { content: ''; position: absolute; left: 6px; top: 50%; transform: translateY(-50%); width: 7px; height: 7px; box-sizing: border-box; border-radius: 50%; border: 1.5px solid var(--dsw-alias-border-l2, #cbd2d9); background: var(--dsw-alias-bg-layer-1, #fff); z-index: 1; }\n[data-edrv-view] .edrv-svnlog-item::after { content: ''; position: absolute; left: 9px; top: 0; bottom: 0; width: 1px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-item:last-child::after { bottom: 50%; }\n[data-edrv-view] .edrv-svnlog-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-item.edrv-svnlog-item-on { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.14)); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-item.edrv-svnlog-item-on::before { border-color: var(--dsw-alias-brand-primary, #2563eb); background: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-cell-msg,\n[data-edrv-view] .edrv-svnlog-item-copied .edrv-svnlog-rev { color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-cell { overflow: hidden; text-overflow: ellipsis; font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svnlog-cell-rev { width: 52px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-act { width: 52px; flex: none; display: inline-flex; gap: 3px; }\n[data-edrv-view] .edrv-svnlog-cell-author { width: 88px; flex: none; }\n[data-edrv-view] .edrv-svnlog-cell-date { width: 82px; flex: none; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-cell-msg { flex: 1 1 auto; }\n[data-edrv-view] .edrv-svnlog-rev { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-weight: 700; color: var(--dsw-alias-brand-primary, #2563eb); }\n[data-edrv-view] .edrv-svnlog-badge { display: inline-flex; align-items: center; justify-content: center; width: 14px; height: 14px; border-radius: 4px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; }\n/* 动作语义色(13-log-ui-polish 归位):A=success 绿 · D=error 红 · M=brand 蓝 · R=warn 琥珀 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-badge-modified { color: var(--dsw-alias-state-info-primary, #2f6fed); background: rgba(47,111,237,.14); }\n[data-edrv-view] .edrv-svnlog-badge-added { color: var(--dsw-alias-state-success-primary, #0f9d58); background: rgba(15,157,88,.14); }\n[data-edrv-view] .edrv-svnlog-badge-deleted { color: var(--dsw-alias-state-error-primary, #d9534f); background: rgba(217,83,79,.14); }\n[data-edrv-view] .edrv-svnlog-badge-replaced { color: var(--dsw-alias-state-warn-primary, #d97706); background: rgba(217,119,6,.16); }\n[data-edrv-view] .edrv-svnlog-badge-plain { color: var(--dsw-alias-label-tertiary, #9aa5b1); background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-svnlog-more { padding: 6px 4px 2px; text-align: center; }\n/* P0-14 三段 pane 公共外观(13-log-ui-polish:2px 粗框 → 1px 发丝线 + 面板底色) */\n[data-edrv-view] .edrv-svnlog-pane { border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 8px 10px; overflow: hidden; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-svnlog-msgpane { flex: 0 0 auto; display: flex; flex-direction: column; }\n[data-edrv-view] .edrv-svnlog-pathspane { flex: 1 1 auto; min-height: 0; display: flex; flex-direction: column; }\n/* P0-13/P0-14:分段横向拖拽分隔条 + 变更路径独立滚动容器 */\n[data-edrv-view] .edrv-svnlog-hsplit { flex: 0 0 6px; cursor: row-resize; margin: 2px 0; border-radius: 3px; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-hsplit:hover, [data-edrv-view] .edrv-svnlog-hsplit:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.28)); }\n[data-edrv-view] .edrv-svnlog-paths-wrap { flex: 1 1 auto; min-height: 0; overflow: auto; display: flex; flex-direction: column; }\n/* 提交信息 meta 行:rev/日期 chip 化,author 常规字重(13-log-ui-polish) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-meta { display: flex; align-items: center; gap: 8px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-meta .edrv-svnlog-rev { padding: 1px 8px; border-radius: 999px; background: var(--dsw-alias-state-info-primary, #2f6fed); color: var(--dsw-alias-label-primary-inverted, #fff); font-size: 11px; font-weight: 700; }\n[data-edrv-view] .edrv-svnlog-meta .edrv-svnlog-date { height: auto; padding: 1px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svnlog-date { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n/* 正文块:左侧品牌强调线 +1.7 行高(长提交信息可读性) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-msgpane pre.edrv-svnlog-body { margin: 8px 0 0; padding: 8px 10px; border-radius: 0 6px 6px 0; border-left: 2px solid var(--dsw-alias-state-info-primary, #2f6fed); background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11.5px; line-height: 1.7; white-space: pre-wrap; word-break: break-word; overflow: auto; flex: 1 1 auto; min-height: 0; }\n/* P0-14 外框尺寸手柄(13-log-ui-polish 增量3 八向:n/s/w/e 四边 + nw/ne/sw/se 四角);\n 热区避开内边距带(边8px/角14px 落在卡片22/24px padding 内不遮内容),角手柄后渲染盖过相邻边2px overlap。\n chevron 角标四向各自朝向,hover 显形。 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-grip { position: absolute; z-index: 2; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-grip-n { top: 0; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-s { bottom: 0; left: 12px; right: 12px; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-w { left: 0; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-e { right: 0; top: 12px; bottom: 12px; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-nw { left: 0; top: 0; width: 14px; height: 14px; cursor: nwse-resize; }\n[data-edrv-view] .edrv-svnlog-grip-ne { right: 0; top: 0; width: 14px; height: 14px; cursor: nesw-resize; }\n[data-edrv-view] .edrv-svnlog-grip-sw { left: 0; bottom: 0; width: 14px; height: 14px; cursor: nesw-resize; }\n[data-edrv-view] .edrv-svnlog-grip-se { right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; background: transparent; }\n[data-edrv-view] .edrv-svnlog-grip-nw::after,\n[data-edrv-view] .edrv-svnlog-grip-ne::after,\n[data-edrv-view] .edrv-svnlog-grip-sw::after,\n[data-edrv-view] .edrv-svnlog-grip-se::after { content: ''; position: absolute; width: 6px; height: 6px; opacity: .5; border-color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-grip-se::after { right: 3px; bottom: 3px; border-right: 1.5px solid; border-bottom: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip-sw::after { left: 3px; bottom: 3px; border-left: 1.5px solid; border-bottom: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip-ne::after { right: 3px; top: 3px; border-right: 1.5px solid; border-top: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip-nw::after { left: 3px; top: 3px; border-left: 1.5px solid; border-top: 1.5px solid; }\n[data-edrv-view] .edrv-svnlog-grip:hover, [data-edrv-view] .edrv-svnlog-grip:active { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.35)); }\n[data-edrv-view] .edrv-svnlog-grip:hover::after, [data-edrv-view] .edrv-svnlog-grip:active::after { opacity: 1; border-color: var(--dsw-alias-label-primary, #1f2933); }\n/* 行反馈微动效(仅 hover/选中背景过渡;用户要求减少动效时关闭) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-item { transition: background-color .12s ease, box-shadow .12s ease; }\n@media (prefers-reduced-motion: reduce) {\n [data-edrv-view] .edrv-svnlog-item { transition: none; }\n}\n/*13-log-ui-polish 增量:行容器可滚动(pane 仍 overflow:hidden 裁圆角),列头不被压缩 @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-paths-head { display: flex; align-items: center; gap: 6px; flex: none; font-size: 10px; font-weight: 600; letter-spacing: .04em; color: var(--dsw-alias-label-tertiary, #9aa5b1); margin-bottom: 4px; padding-bottom: 4px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-hint { font-weight: 400; letter-spacing: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-paths { display: flex; flex-direction: column; gap: 1px; flex: 1 1 auto; min-height: 0; overflow: auto; }\n[data-edrv-view] .edrv-svnlog-path { display: flex; align-items: center; gap: 6px; height: 22px; padding: 0 6px; border-radius: 5px; cursor: default; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-path:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-pathtext,\n[data-edrv-view] .edrv-svnlog-path-dim .edrv-svnlog-copyfrom { opacity: .45; }\n[data-edrv-view] .edrv-svnlog-pathtext { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\n/* 路径两段着色:目录段弱化 + 文件名加重(13-log-ui-polish) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-pdir { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-pbase { color: var(--dsw-alias-label-primary, #1f2933); font-weight: 600; }\n[data-edrv-view] .edrv-svnlog-copyfrom { flex: 0 1 160px; overflow: hidden; text-overflow: ellipsis; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-svnlog-kind { font-size: 10px; padding: 0 5px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-acts { display: none; align-items: center; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-path:hover .edrv-svnlog-acts { display: inline-flex; }\n/* 底部:状态行与按钮组分层 + 组间发丝线(13-log-ui-polish) @author ddj 2026年09月24号 */\n[data-edrv-view] .edrv-svnlog-footwrap { display: flex; flex-direction: column; gap: 6px; flex-shrink: 0; padding-top: 6px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-svnlog-btns { display: flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnlog-btngroup { display: inline-flex; align-items: center; gap: 6px; }\n[data-edrv-view] .edrv-svnlog-btngroup + .edrv-svnlog-btngroup { margin-left: 6px; padding-left: 10px; border-left: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svn-act,\n[data-edrv-view] .edrv-svnlog-range .edrv-svn-act,\n[data-edrv-view] .edrv-svnlog-stats .edrv-svn-act { font-size: 11px; padding: 2px 9px; }\n[data-edrv-view] .edrv-svnlog-dialog .edrv-svn-act:focus-visible,\n[data-edrv-view] .edrv-svnlog-range .edrv-svn-act:focus-visible,\n[data-edrv-view] .edrv-svnlog-stats .edrv-svn-act:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2563eb); outline-offset: 1px; }\n/* ===== SVN 日志统计窗(P1-10)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-stats { display: flex; flex-direction: column; max-height: 82vh; }\n[data-edrv-view] .edrv-svnlog-stats-head { display: flex; align-items: center; gap: 8px; padding: 12px 16px 0; }\n[data-edrv-view] .edrv-svnlog-stats-body { display: flex; flex-direction: column; gap: 14px; padding: 10px 16px 16px; overflow: auto; }\n[data-edrv-view] .edrv-svnlog-stat-line { display: flex; gap: 16px; flex-wrap: wrap; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-block { display: flex; flex-direction: column; gap: 8px; }\n[data-edrv-view] .edrv-svnlog-stat-label { display: flex; align-items: center; gap: 12px; flex-wrap: wrap; font-size: 12px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-svnlog-stat-duo { display: flex; gap: 18px; align-items: flex-start; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-stat-hist { flex: 1 1 260px; display: flex; flex-direction: column; gap: 4px; min-width: 220px; }\n[data-edrv-view] .edrv-svnlog-stat-row { display: flex; align-items: center; gap: 8px; font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-stat-name { width: 110px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-barwrap { flex: 1; height: 12px; border-radius: 6px; background: rgba(127,127,127,.15); overflow: hidden; }\n[data-edrv-view] .edrv-svnlog-stat-bar { display: block; height: 100%; border-radius: 6px; }\n[data-edrv-view] .edrv-svnlog-stat-count { width: 36px; text-align: right; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnlog-stat-pie { width: 120px; height: 120px; flex-shrink: 0; border-radius: 50%; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-svnlog-stat-days { display: flex; align-items: flex-end; gap: 2px; height: 120px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); overflow-x: auto; }\n[data-edrv-view] .edrv-svnlog-stat-day { flex: 1 0 6px; min-width: 6px; height: 100%; display: flex; flex-direction: column; justify-content: flex-end; }\n[data-edrv-view] .edrv-svnlog-stat-seg { display: block; width: 100%; }\n/* ===== SVN 日志区间弹窗(P1-6)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-svnlog-range-body { display: flex; flex-direction: column; gap: 12px; padding: 14px 16px 16px; }\n[data-edrv-view] .edrv-svnlog-range-row { display: flex; gap: 14px; flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-range-input { width: 110px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-svnlog-range-btns { display: flex; gap: 8px; justify-content: flex-end; }\n/* SVN 日志 WC 版号行加粗(P1-9) */\n[data-edrv-view] .edrv-svnlog-item-wc { font-weight: 700; }\n/* SVN 日志 merged 行(P1-5):灰字 + 缩进(缩进量按层级内联),前置「↳」标记 */\n[data-edrv-view] .edrv-svnlog-item-merged { color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-merge-mark { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-svnlog-item-merged .edrv-svnlog-cell-msg { font-style: italic; }\n/* ===== 诊断日志弹窗(LogDialog)@author ddj 2026-09-17 ===== */\n[data-edrv-view] .edrv-dlog-dialog { display: flex; flex-direction: column; gap: 8px; max-height: 88vh; }\n[data-edrv-view] .edrv-dlog-head { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-dlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-file { max-width: 200px; padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-level { padding: 4px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-search { min-width: 120px; flex: 0 1 200px; padding: 4px 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #fff); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-auto { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; }\n[data-edrv-view] .edrv-dlog-error { padding: 4px 8px; border: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-dlog-scroll { flex: 1 1 auto; min-height: 240px; overflow: auto; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px 0; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-dlog-row { display: flex; align-items: baseline; gap: 8px; padding: 1px 8px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; line-height: 1.55; }\n[data-edrv-view] .edrv-dlog-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-dlog-at { flex-shrink: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-lvl { flex-shrink: 0; width: 26px; text-align: center; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dlog-text { flex: 1; min-width: 0; white-space: pre-wrap; word-break: break-word; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dlog-row-error .edrv-dlog-text { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-dlog-row-warn .edrv-dlog-text { color: var(--dsw-alias-state-warning-primary, #b45309); }\n[data-edrv-view] .edrv-dlog-row-debug .edrv-dlog-text { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); flex-shrink: 0; }\n[data-edrv-view] .edrv-dlog-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); max-width: 46%; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-stat { white-space: nowrap; }\n[data-edrv-view] .edrv-dlog-switch { display: inline-flex; align-items: center; gap: 4px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); white-space: nowrap; cursor: pointer; flex-shrink: 0; }\n/* 原生 SVN 更新窗口:逐条状态与路径是主信息;跟随 DSH 主题令牌。 */\n[data-edrv-view] .edrv-update-dialog { display: flex; flex-direction: column; padding: 0; border-radius: 8px; overflow: hidden; background: var(--dsw-alias-bg-overlay, #fff); }\n[data-edrv-view] .edrv-update-head { display: flex; align-items: center; gap: 12px; min-height: 48px; padding: 0 16px; border-bottom: 1px solid var(--dsw-alias-border-l1, #d9e0e4); }\n[data-edrv-view] .edrv-update-heading { display: flex; align-items: center; gap: 12px; min-width: 0; flex: 1; }\n[data-edrv-view] .edrv-update-heading h3 { margin: 0; flex: none; font-size: 15px; }\n[data-edrv-view] .edrv-update-target { min-width: 0; color: var(--dsw-alias-label-tertiary, #65737c); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; }\n[data-edrv-view] .edrv-update-phase { flex: none; font-size: 12px; color: var(--dsw-alias-label-secondary, #485762); }\n[data-edrv-view] .edrv-update-close { display: grid; place-items: center; flex: none; width: 28px; height: 28px; border: 0; border-radius: 4px; background: none; color: var(--dsw-alias-label-secondary, #485762); cursor: pointer; }\n[data-edrv-view] .edrv-update-close:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-update-close:not(:disabled):hover { background: var(--dsw-alias-interactive-bg-hover, #e7edf0); }\n[data-edrv-view] .edrv-update-table { display: flex; flex-direction: column; flex: 1; min-height: 0; margin: 12px 14px 0; border: 1px solid var(--dsw-alias-border-l1, #d9e0e4); border-radius: 5px; overflow: hidden; background: var(--dsw-alias-bg-layer-1, #fff); }\n[data-edrv-view] .edrv-update-cols, [data-edrv-view] .edrv-update-row { display: grid; grid-template-columns: 110px minmax(0, 1fr) 160px; align-items: center; }\n[data-edrv-view] .edrv-update-sort { width: 100%; padding: 0; border: 0; background: transparent; color: inherit; font: inherit; text-align: left; cursor: pointer; }\n[data-edrv-view] .edrv-update-sort:hover { color: var(--dsw-alias-brand-primary, #2869b4); }\n[data-edrv-view] .edrv-update-sort:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2869b4); outline-offset: 2px; }\n[data-edrv-view] .edrv-update-jump { color: var(--dsw-alias-state-error-primary, #b93b43); }\n[data-edrv-view] .edrv-update-cols { flex: none; height: 30px; background: var(--dsw-alias-bg-layer-2, #f1f4f5); border-bottom: 1px solid var(--dsw-alias-border-l1, #d9e0e4); color: var(--dsw-alias-label-secondary, #485762); font-size: 11px; font-weight: 600; }\n[data-edrv-view] .edrv-update-cols > span, [data-edrv-view] .edrv-update-row > span { min-width: 0; padding: 0 10px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-update-cols > span + span, [data-edrv-view] .edrv-update-row > span + span { border-left: 1px solid var(--dsw-alias-border-l1, #d9e0e4); }\n[data-edrv-view] .edrv-update-list { position: relative; flex: 1; min-height: 0; overflow: auto; scrollbar-width: thin; }\n[data-edrv-view] .edrv-update-space { position: relative; }\n[data-edrv-view] .edrv-update-pos { position: absolute; left: 0; right: 0; }\n[data-edrv-view] .edrv-update-row { height: 100%; font-size: 11px; cursor: default; color: var(--dsw-alias-label-primary, #202932); }\n[data-edrv-view] .edrv-update-row:hover { background: var(--dsw-alias-interactive-bg-hover, #ecf3f9); }\n[data-edrv-view] .edrv-update-row.is-selected { background: var(--dsw-alias-interactive-bg-hover, #dceaf9); box-shadow: inset 2px 0 0 var(--dsw-alias-brand-primary, #2869b4); }\n[data-edrv-view] .edrv-update-action { font-weight: 600; }\n[data-edrv-view] .edrv-update-action.tone-added { color: var(--dsw-alias-state-success-primary, #23704e); }\n[data-edrv-view] .edrv-update-action.tone-deleted, [data-edrv-view] .edrv-update-action.tone-conflict { color: var(--dsw-alias-state-error-primary, #b93b43); }\n[data-edrv-view] .edrv-update-action.tone-merged { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-action.tone-updated { color: var(--dsw-alias-state-info-primary, #2869b4); }\n[data-edrv-view] .edrv-update-path { font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-update-type { color: var(--dsw-alias-label-tertiary, #65737c); }\n[data-edrv-view] .edrv-update-empty { position: absolute; top: 50%; left: 0; right: 0; transform: translateY(-50%); text-align: center; font-size: 12px; color: var(--dsw-alias-label-tertiary, #65737c); pointer-events: none; }\n[data-edrv-view] .edrv-update-telemetry { display: flex; align-items: center; flex-wrap: wrap; gap: 8px 18px; padding: 10px 15px; min-height: 43px; box-sizing: border-box; font-size: 11px; color: var(--dsw-alias-label-secondary, #485762); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-update-error { color: var(--dsw-alias-state-error-primary, #b93b43); overflow-wrap: anywhere; }\n[data-edrv-view] .edrv-update-warning { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-locked { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-foot .edrv-update-cleanup:not(:disabled) { color: var(--dsw-alias-state-warn-primary, #a05d22); }\n[data-edrv-view] .edrv-update-foot { display: flex; align-items: center; gap: 8px; padding: 10px 14px; border-top: 1px solid var(--dsw-alias-border-l1, #d9e0e4); font-size: 11px; }\n[data-edrv-view] .edrv-update-counts { flex: 1; min-width: 0; color: var(--dsw-alias-label-secondary, #485762); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-update-foot .edrv-svn-act { flex: none; min-width: 74px; }\n[data-edrv-view] .edrv-update-foot .edrv-svn-act:focus-visible, [data-edrv-view] .edrv-update-close:focus-visible { outline: 2px solid var(--dsw-alias-brand-primary, #2869b4); outline-offset: 2px; }\n[data-edrv-view] .edrv-update-foot .edrv-svn-act:disabled { opacity: .45; cursor: default; }\n[data-edrv-view] .edrv-update-raw { max-height: 120px; overflow: auto; padding: 0 14px 10px; font-size: 11px; }\n[data-edrv-view] .edrv-update-raw pre { white-space: pre-wrap; overflow-wrap: anywhere; margin: 5px 0; }\n@media (max-width: 620px) {\n [data-edrv-view] .edrv-update-head { gap: 6px; padding: 0 10px; }\n [data-edrv-view] .edrv-update-table { margin: 8px 8px 0; }\n [data-edrv-view] .edrv-update-cols, [data-edrv-view] .edrv-update-row { grid-template-columns: 76px minmax(0, 1fr); }\n [data-edrv-view] .edrv-update-cols > span:nth-child(3), [data-edrv-view] .edrv-update-row > span:nth-child(3) { display: none; }\n [data-edrv-view] .edrv-update-path { white-space: normal !important; overflow-wrap: anywhere; display: -webkit-box; -webkit-line-clamp: 2; -webkit-box-orient: vertical; }\n [data-edrv-view] .edrv-update-foot { flex-wrap: wrap; padding: 8px; }\n [data-edrv-view] .edrv-update-counts { flex-basis: 100%; }\n}\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: var(--dsw-alias-label-primary-inverted, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid var(--dsw-alias-state-warn-primary, rgba(240,173,78,.45)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover, rgba(240,173,78,.12)); color: var(--dsw-alias-state-warn-primary, #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: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.15)); color: var(--dsw-alias-state-success-primary, #0b7c46); }\n[data-edrv-view] .edrv-rules-type-auto { background: var(--dsw-alias-interactive-bg-hover-accent, rgba(79,140,255,.16)); color: var(--dsw-alias-link, #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: var(--dsw-alias-border-l2, #b9c4cc); cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: var(--dsw-alias-brand-primary, #7c5cff); }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: var(--dsw-alias-bg-layer-1, #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 var(--dsw-alias-state-error-primary, rgba(217,83,79,.4)); border-radius: 6px; background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); 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: var(--dsw-alias-label-primary-inverted, #fff); font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n/* 命令栏(Ctrl+Shift+P / F1):body 级 portal 浮层,故不依赖编辑区几何。\n ⚠️ 浮层 z-index 阶梯(自下而上;改动务必保持顺序,tests/overlayZOrder.test.ts 守约):\n 编辑器内浮层 60(.edrv-search-pop) / 71(.edrv-ctxmenu)\n < 190 命令栏遮罩 < 200 命令栏\n < 195 片段浮窗遮罩 < 197 片段二级弹窗遮罩\n 命令栏必须**高于**片段浮窗:曾因片段遮罩(192) 压过命令栏(191),导致片段浮窗打开时\n 命令栏被整体盖住,按 Ctrl+Shift+P 因「已打开即早退」而毫无反应(表现为快捷键失效)。 */\n[data-edrv-view] .edrv-palette-mask { position: fixed; inset: 0; z-index: 190; background: rgba(0, 0, 0, .28); }\n[data-edrv-view] .edrv-palette { position: fixed; top: 12vh; left: 50%; transform: translateX(-50%); z-index: 200; width: min(580px, calc(100vw - 32px)); max-height: 64vh; display: flex; flex-direction: column; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 12px 34px rgba(31, 41, 51, .24); overflow: hidden; }\n[data-edrv-view] .edrv-palette-input { height: 38px; flex: 0 0 auto; padding: 0 12px; border: none; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: transparent; color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; outline: none; }\n[data-edrv-view] .edrv-palette-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px; }\n[data-edrv-view] .edrv-palette-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; }\n[data-edrv-view] .edrv-palette-row.edrv-palette-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 157, 88, .10)); }\n[data-edrv-view] .edrv-palette-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-palette-cat { flex: 0 0 auto; font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-palette-key { flex: 0 0 auto; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 10px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-palette-empty { padding: 14px 10px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #7b8794); text-align: center; }\n[data-edrv-view] .edrv-palette-notice { flex: 0 0 auto; padding: 6px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-state-warn-primary, #b7791f); }\n\n/* 代码片段选择器(配置 / 插入):居中浮窗 + 新建二级弹窗。\n 卡片复用 mcp.css 的 .vsm-mcp-dialog(与「添加 MCP」「工作区选择」同一视觉语言),\n 此处只补遮罩、尺寸与列表布局。⚠️ 根节点须带 data-edrv-view,否则这些规则全部失配。 */\n[data-edrv-view] .edrv-snip-mask { position: fixed; inset: 0; z-index: 195; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, rgba(0, 0, 0, .55)); }\n/* 二级弹窗叠在一级浮窗之上(仍在命令栏之下,见上方阶梯说明) */\n[data-edrv-view] .edrv-snip-mask-top { z-index: 197; }\n[data-edrv-view] .edrv-snip-dialog { display: flex; flex-direction: column; overflow: hidden; width: min(620px, calc(100vw - 48px)); }\n[data-edrv-view] .edrv-snip-hint { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-list { display: flex; flex-direction: column; gap: 1px; min-height: 0; max-height: 46vh; overflow: auto; }\n[data-edrv-view] .edrv-snip-group { padding: 12px 2px 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-row { display: flex; align-items: center; gap: 4px; width: 100%; box-sizing: border-box; padding: 2px; border: none; border-radius: 8px; background: transparent; text-align: left; color: var(--dsw-alias-label-primary, #e6e6e6); font: inherit; }\n[data-edrv-view] .edrv-snip-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, .06)); }\n[data-edrv-view] button.edrv-snip-row { cursor: pointer; }\n[data-edrv-view] .edrv-snip-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border: none; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; color: inherit; font: inherit; }\n[data-edrv-view] .edrv-snip-label { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary, #e6e6e6); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-desc { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-src { flex: 0 0 auto; padding-right: 6px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-warn { flex: 0 0 auto; font-size: 11px; padding: 2px 7px; border-radius: 999px; background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .16)); color: var(--dsw-alias-state-warn-primary, #e5b93f); white-space: nowrap; }\n[data-edrv-view] .edrv-snip-act { flex: 0 0 auto; width: 26px; height: 26px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-snip-act:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n[data-edrv-view] .edrv-snip-empty { padding: 12px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n/* 当前文件语言提示条(片段按语言绑定,明确告知生效范围) */\n[data-edrv-view] .edrv-snip-langbar { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #2b2b2b); font-size: 12px; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-langbar b { color: var(--dsw-alias-label-primary, #e6e6e6); }\n/* 二级弹窗的动作按钮(原生 .vsm-mcp-dialog-actions 已提供排版与按钮样式) */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-dialog-actions { flex-wrap: wrap; }\n/* 删除图标按钮:.vsm-danger 的规则全部限定在 .vsm-mcp-actions button 之下,裸用无样式,此处补自有类 */\n[data-edrv-view] .edrv-snip-act.edrv-snip-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n/* 浮窗内的原生空态(.vsm-mcp-empty 默认为整页尺寸)压缩为对话框尺寸 */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-empty { padding: 26px 16px; border: 0; }\n\n\n\n\n\n/* 调试(DAP):断点圆点 / 停帧行 / 浮动调试工具条。\n 圆点挂在 Monaco glyphMargin(glyphMarginClassName),行背景为 isWholeLine className;\n 工具条绝对定位于编辑区右上(editorArea relative 由 .edrv-editor-area 自身定位)。 */\n/* 断点圆点:装饰类占满整行,圆点经 ::before 在本行盒子内居中(行归属明确、不跨行界) */\n[data-edrv-view] .edrv-dap-bp { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dap-bp-off { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-off::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n/* 未验证断点(适配器真实回执 verified:false):空心红圈,对齐 VS Code 空心圆语义 */\n[data-edrv-view] .edrv-dap-bp-unverified { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-unverified::before { content: ''; display: block; box-sizing: border-box; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; border: 1px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n[data-edrv-view] .edrv-dap-paused-line { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .22)); }\n[data-edrv-view] .edrv-dap-paused-glyph { cursor: pointer; }\n[data-edrv-view] .edrv-dap-paused-glyph::before { content: ''; display: block; width: 5px; height: 12px; margin: 4px auto 0; border-radius: 2px; background: var(--dsw-alias-state-warn-primary, #e5b93f); }\n[data-edrv-view] .edrv-editor-area { position: relative; }\n/* launch.json 右下角「添加配置」按钮(VSCode 同款形态):仅 launch.json 打开时渲染 */\n[data-edrv-view] .edrv-addcfg { position: absolute; right: 14px; bottom: 10px; z-index: 13; padding: 4px 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); font-size: 12px; line-height: 18px; cursor: pointer; box-shadow: 0 1px 4px rgba(0, 0, 0, .1); }\n[data-edrv-view] .edrv-addcfg:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] .edrv-dapbar { position: absolute; top: 6px; right: 14px; z-index: 12; display: none; align-items: center; gap: 3px; padding: 3px 5px; border-radius: 8px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, #f7f9fa); box-shadow: 0 2px 8px rgba(0, 0, 0, .12); }\n[data-edrv-view] .edrv-dapbar.on { display: flex; border-color: var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapbar-grip { flex: 0 0 auto; width: 16px; height: 22px; display: inline-flex; align-items: center; justify-content: center; cursor: grab; user-select: none; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 12px; }\n[data-edrv-view] .edrv-dapbar-grip:active, [data-edrv-view] .edrv-dapbar.dragging .edrv-dapbar-grip { cursor: grabbing; }\n[data-edrv-view] .edrv-dapbar.dragging { user-select: none; }\n[data-edrv-view] .edrv-dapbar-cfg { max-width: 220px; height: 22px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapbar-btn { min-width: 24px; height: 22px; padding: 0 6px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 12px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dapbar-btn:hover:not(:disabled) { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dapbar-btn:disabled { opacity: .35; cursor: default; }\n[data-edrv-view] .edrv-dapbar-phase { padding: 0 4px; font-size: 11px; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbar-phase.paused { color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dapbar-err { max-width: 260px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; font-size: 11px; color: var(--dsw-alias-state-error-primary, #e05252); }\n\n/* 调试面板(活动栏「调试」页签):四段折叠区 + 断点列表 + REPL。 */\n[data-edrv-view] .edrv-dappanel { display: flex; flex-direction: column; gap: 10px; height: 100%; min-height: 0; overflow: auto; padding: 2px 2px 8px; }\n[data-edrv-view] .edrv-dappanel-head { display: flex; flex-wrap: wrap; align-items: center; gap: 6px; row-gap: 4px; font-size: 12px; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dappanel-phase { padding: 2px 8px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dappanel-phase.paused { background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .18)); color: var(--dsw-alias-state-warn-primary, #b7791f); font-weight: 600; }\n[data-edrv-view] .edrv-dappanel-cfg { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dappanel-pid { font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; }\n[data-edrv-view] .edrv-dappanel-err { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapseg { display: flex; flex-direction: column; gap: 2px; min-height: 0; }\n[data-edrv-view] .edrv-dapseg-body { min-height: 0; overflow-y: auto; overflow-x: hidden; overscroll-behavior: contain; }\n/* 段间分隔条(splitview sash):拖动调整相邻两段高度占比;各段高度由 DebugPanel 内联接管。 */\n[data-edrv-view] .edrv-dapseg-sash { flex: 0 0 auto; height: 4px; margin: 2px 0; border-radius: 2px; background: transparent; cursor: row-resize; }\n[data-edrv-view] .edrv-dapseg-sash:hover, [data-edrv-view] .edrv-dapseg-sash.dragging { background: var(--dsw-alias-border-l2, #cdd6da); }\n/* 折叠段头:chevron + 标题 + 悬浮动作区(动作 hover 显隐;REPL 头不参与折叠)。 */\n[data-edrv-view] .edrv-dapseg-head { display: flex; align-items: center; gap: 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-tertiary, #7b8794); padding: 2px 2px; cursor: pointer; border-radius: 4px; }\n[data-edrv-view] .edrv-dapseg-head:hover { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-daprepl .edrv-dapseg-head { cursor: default; padding: 2px 0; }\n[data-edrv-view] .edrv-dapseg-chevron { flex: 0 0 auto; width: 14px; text-align: center; font-size: 10px; }\n[data-edrv-view] .edrv-dapseg-title { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapseg-act { flex: 0 0 auto; min-width: 20px; height: 18px; padding: 0 4px; border: none; border-radius: 4px; background: transparent; color: var(--dsw-alias-label-tertiary, #7b8794); font-size: 11px; line-height: 1; cursor: pointer; opacity: 0; }\n[data-edrv-view] .edrv-dapseg-head:hover .edrv-dapseg-act { opacity: 1; }\n[data-edrv-view] .edrv-dapseg-act:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dapempty { font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); padding: 4px 2px; }\n[data-edrv-view] .edrv-dapframe { display: flex; align-items: baseline; gap: 8px; padding: 3px 4px; border-radius: 6px; cursor: pointer; font-size: 12px; }\n[data-edrv-view] .edrv-dapframe:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapframe-name { color: var(--dsw-alias-label-primary, inherit); font-weight: 600; }\n[data-edrv-view] .edrv-dapframe-loc { color: var(--dsw-alias-label-tertiary, #9aa5b1); font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-dapscope { font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); padding: 4px 2px 1px; }\n[data-edrv-view] .edrv-dapvar { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; font-size: 12px; padding: 1px 2px; min-width: 0; }\n[data-edrv-view] .edrv-dapvar-tw { flex: 0 0 auto; width: 14px; border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; font-size: 10px; padding: 0; }\n[data-edrv-view] span.edrv-dapvar-tw { cursor: default; }\n[data-edrv-view] .edrv-dapvar-name { flex: 0 1 34%; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-primary, inherit); font-family: var(--ds-font-family-code, ui-monospace, monospace); white-space: nowrap; }\n[data-edrv-view] .edrv-dapvar-val { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapvar-type { flex: 0 0 auto; font-size: 10px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapframe.selected { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .16)); outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n[data-edrv-view] .edrv-dapwatch { display: flex; align-items: baseline; gap: 6px; width: 100%; box-sizing: border-box; min-width: 0; font-size: 12px; padding: 1px 2px; }\n[data-edrv-view] .edrv-dapwatch-x { border: none; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapwatch-x:hover { color: var(--dsw-alias-state-error-primary, #e05252); }\n[data-edrv-view] .edrv-dapwatch-add { padding: 2px 0; }\n[data-edrv-view] .edrv-dapbp { display: flex; align-items: center; gap: 6px; font-size: 12px; padding: 2px 2px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-dapbp:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-dapbp:active { background: var(--dsw-alias-interactive-bg-pressed, rgba(127, 127, 127, .2)); }\n[data-edrv-view] .edrv-dapbp-dot { flex: 0 0 auto; width: 9px; height: 9px; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); }\n[data-edrv-view] .edrv-dapbp-dot.off { background: transparent; border: 1.5px solid var(--dsw-alias-label-tertiary, #9aa5b1); opacity: .6; }\n[data-edrv-view] .edrv-dapbp-file { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; border: none; background: transparent; color: var(--dsw-alias-label-primary, inherit); cursor: pointer; padding: 0; font-size: 12px; }\n[data-edrv-view] .edrv-dapbp-dir { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 11px; text-align: right; }\n[data-edrv-view] .edrv-dapbp-line { flex: 0 0 auto; font-size: 10px; padding: 1px 6px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-dapbp-x { flex: 0 0 auto; border: none; background: transparent; color: transparent; cursor: pointer; width: 14px; }\n[data-edrv-view] .edrv-dapbp:hover .edrv-dapbp-x { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-dapbp-x:hover { color: var(--dsw-alias-state-error-primary, #e05252) !important; }\n[data-edrv-view] .edrv-daprepl { display: flex; flex-direction: column; gap: 4px; }\n[data-edrv-view] .edrv-daprepl-log { display: flex; flex-direction: column; gap: 1px; max-height: 180px; overflow: auto; }\n[data-edrv-view] .edrv-daprepl-line { font-size: 11px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); white-space: pre-wrap; word-break: break-all; display: flex; gap: 6px; }\n[data-edrv-view] .edrv-daprepl-line.out { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-daprepl-in { width: 100%; box-sizing: border-box; height: 26px; padding: 0 8px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-dappanel-run { flex: 0 0 auto; width: 24px; height: 24px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, inherit); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-dappanel-run:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .15)); }\n[data-edrv-view] .edrv-dappanel-run:disabled { opacity: .35; cursor: default; background: transparent; }\n/* 面板顶部配置下拉(与编辑器浮动条 .edrv-dapbar-cfg 同视觉)。 */\n[data-edrv-view] .edrv-dappanel-cfg-select { max-width: 190px; height: 24px; padding: 0 4px; font-size: 11px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n/* 断点行内编辑行(面板内展开编辑,控件复用 .edrv-bpwidget-* 视觉;左缩进对齐断点行文字列)。 */\n[data-edrv-view] .edrv-dapbp-edit { display: flex; align-items: center; gap: 6px; padding: 3px 2px 3px 20px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-mode { height: 20px; }\n[data-edrv-view] .edrv-dapbp-edit .edrv-bpwidget-input { height: 20px; }\n/* 断点回执:未验证空心红圈(须排在 .off 之后,禁用态优先展示灰圈语义)。 */\n[data-edrv-view] .edrv-dapbp-dot.unverified { background: transparent; border: 1.5px solid var(--dsw-alias-state-error-primary, #e51400); opacity: .75; }\n/* 断点行内编辑浮层(Monaco content widget,锚定断点行上方;对齐 VS Code breakpointWidget 形态)。 */\n/* View Zone 浮层:宽度/左移由 BpWidget.syncWidth 按 layout 内联设置\n (Monaco .view-zones 仅内容区宽,需补偿 contentLeft 与滚动条),此处只管视觉。 */\n[data-edrv-view] .edrv-bpwidget { position: relative; box-sizing: border-box; display: flex; align-items: center; gap: 6px; padding: 3px 8px; border-top: 1px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-layer-1, #f7f9fa); }\n/* 断点编辑中的目标行高亮(浮层打开期间) */\n[data-edrv-view] .edrv-dap-editing-line { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n[data-edrv-view] .edrv-bpwidget-mode { flex: 0 0 auto; height: 22px; padding: 0 4px; font-size: 12px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); cursor: pointer; }\n[data-edrv-view] .edrv-bpwidget-input { flex: 1 1 auto !important; min-width: 0; width: auto !important; box-sizing: border-box; height: 22px; padding: 0 6px; font-size: 12px; font-family: var(--ds-font-family-code, ui-monospace, monospace); border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 3px; background: var(--dsw-alias-bg-base, transparent); color: var(--dsw-alias-label-primary, inherit); }\n[data-edrv-view] .edrv-bpwidget-input:focus { outline: 1px solid var(--dsw-alias-border-l2, #cdd6da); }\n\n/* 断点 hover 预览(glyph 区):半透明小红点 + pointer 光标(对齐 VS Code .codicon-debug-hint)。 */\n[data-edrv-view] .edrv-dap-bp-hint { cursor: pointer; }\n[data-edrv-view] .edrv-dap-bp-hint::before { content: ''; display: block; width: 7px; height: 7px; margin: 6px auto 0; border-radius: 50%; background: var(--dsw-alias-state-error-primary, #e51400); opacity: .4; }\n/* 行号区也给出可点提示(与 VS Code 一致:glyph 区与行号区都可点/可 hover);\n 不拦截折叠箭头等自有控件的光标。 */\n[data-edrv-view] .edrv-editor-row .monaco-editor .margin-view-overlays .line-numbers:hover { cursor: pointer; }\n\n/* 暂停态 hover 调试块 + 变量树(成员全量直显 + table 成员折叠展开)。\n ⚠️ 选择器一律用 data-*:本仓 vendored Monaco 的 markdown→DOM 管线会剥掉我们 HTML 里的\n class(supportHtml/isTrusted 都不豁免),只有 data-* 存活;用 class 会静默失效。 */\n[data-edrv-view] [data-edrv-dap] { display: block; min-width: 0; }\n[data-edrv-view] [data-edrv-head] { display: flex; align-items: baseline; gap: 2px; }\n[data-edrv-view] [data-edrv-head] [data-edrv-expr] { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-head] [data-edrv-val] { font-family: var(--ds-font-family-code, ui-monospace, monospace); word-break: break-all; }\n[data-edrv-view] [data-edrv-type] { margin-top: 2px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-tree] { margin: 2px 0 0; padding: 0; list-style: none; font-variant-numeric: tabular-nums; }\n[data-edrv-view] [data-edrv-line] { display: flex; align-items: baseline; gap: 4px; padding: 1px 2px; border-radius: 3px; white-space: nowrap; }\n[data-edrv-view] [data-edrv-line]:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .12)); }\n/* 折叠按钮(对齐 CodeBuddy 调试浮窗变量树的 twist):热区 14px + hover 反馈,未可展开时留空占位 */\n[data-edrv-view] [data-edrv-twist] { flex: 0 0 auto; box-sizing: border-box; width: 14px; height: 14px; line-height: 13px; text-align: center; border-radius: 3px; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-twist]:not(:empty) { cursor: pointer; user-select: none; }\n[data-edrv-view] [data-edrv-twist]:not(:empty):hover { background: var(--dsw-alias-interactive-bg-hover, rgba(127, 127, 127, .2)); color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-name] { flex: 0 0 auto; color: var(--dsw-alias-label-primary, #1f2933); }\n[data-edrv-view] [data-edrv-line] [data-edrv-eq] { flex: 0 0 auto; color: var(--dsw-alias-label-tertiary, #8a949b); }\n[data-edrv-view] [data-edrv-line] [data-edrv-val] { flex: 0 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] [data-edrv-note] { color: var(--dsw-alias-label-tertiary, #8a949b); font-style: italic; }\n/* Alt 提示层:由 hoverTree 注入到 .monaco-hover(滚动区之外)贴底常驻;容器预留同高内边距避免遮挡末行。\n 不再用 sticky / `:has()`:滚动链在 .monaco-hover-content 上,sticky 会被滚走。 */\n[data-edrv-view] .monaco-hover[data-edrv-hint-host=\"1\"] { padding-bottom: 22px; }\n[data-edrv-view] [data-edrv-hint=\"1\"] { position: absolute; left: 0; right: 0; bottom: 0; box-sizing: border-box; height: 22px; padding: 2px 8px; font-size: 11px; line-height: 18px; color: var(--dsw-alias-label-tertiary, #8a949b); background: var(--dsw-alias-bg-overlay, #ffffff); border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n\n/* Workbench panes: existing theme, action-driven drop previews. ddj 2026年10月14号 */\n[data-edrv-view] .edrv-group, [data-edrv-view] .edrv-group-body,\n[data-edrv-view] .edrv-full-slot, [data-edrv-view] .edrv-full-view,\n[data-edrv-view] .edrv-passive-view { display: flex; flex-direction: column; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-group { border: 0; }\n[data-edrv-view] .edrv-group .edrv-tabs { flex: 0 0 auto; touch-action: none; }\n[data-edrv-view] .edrv-group-tab-name { overflow: hidden; text-overflow: ellipsis; max-width: 180px; }\n[data-edrv-view] .edrv-split { display: flex; flex: 1 1 auto; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-split-vertical { flex-direction: column; }\n[data-edrv-view] .edrv-split-child { display: flex; min-width: 0; min-height: 0; overflow: hidden; }\n[data-edrv-view] .edrv-split-handle { flex: 0 0 5px; background: var(--dsw-alias-border-l1, #e0e6e8); cursor: col-resize; touch-action: none; }\n[data-edrv-view] .edrv-split-vertical > .edrv-split-handle { cursor: row-resize; }\n[data-edrv-view] .edrv-split-handle:hover, [data-edrv-view] .edrv-split-handle:focus-visible { background: var(--dsw-alias-state-info-primary, #4d6bfe); }\n[data-edrv-view].edrv-floating { position: fixed; display: flex; flex-direction: column; overflow: hidden; box-sizing: border-box; border: 1px solid var(--dsw-alias-border-l2, #cdd6da); background: var(--dsw-alias-bg-base, #fff); color: var(--dsw-alias-label-primary, #1f2933); box-shadow: 0 8px 28px rgba(0,0,0,.22); }\n[data-edrv-view] .edrv-floating-title { display: flex; align-items: center; gap: 8px; flex: 0 0 32px; padding: 0 8px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); cursor: move; touch-action: none; user-select: none; }\n[data-edrv-view] .edrv-floating-title > span { flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-floating-content { display: flex; flex-direction: column; flex: 1; min-width: 0; min-height: 0; overflow: auto; box-sizing: border-box; }\n[data-edrv-view] .edrv-floating-content.edrv-svnlog-dialog { padding: 12px; overflow: auto; }\n[data-edrv-view] .edrv-floating-content.edrv-svn-patch-dialog,\n[data-edrv-view] .edrv-floating-content.edrv-svn-sum-dialog,\n[data-edrv-view] .edrv-floating-content.edrv-svnplan-dialog { padding: 12px; max-width: none; gap: 8px; }\n[data-edrv-view] .edrv-floating-content.edrv-svnlog-stats { max-height: none; }\n[data-edrv-view] .edrv-floating-content .edrv-svn-patch-pre,\n[data-edrv-view] .edrv-floating-content .edrv-svn-sum-list { flex: 1; min-height: 0; max-height: none; }\n[data-edrv-view] .edrv-floating-content .edrv-svnlog-filter,\n[data-edrv-view] .edrv-floating-content .edrv-svn-sum-form { flex-wrap: wrap; }\n[data-edrv-view] .edrv-floating-content > .edrv-svnlog-head,\n[data-edrv-view] .edrv-floating-content > .edrv-svnlog-filter,\n[data-edrv-view] .edrv-floating-content > .edrv-svnlog-foot { flex-shrink: 0; }\n[data-edrv-view] .edrv-floating-title > button { border: 0; background: transparent; color: inherit; cursor: pointer; }\n[data-edrv-view] .edrv-floating-grip { position: absolute; width: 16px; height: 16px; bottom: 0; right: 0; cursor: nwse-resize; touch-action: none; border-right: 3px solid var(--dsw-alias-border-l2, #cdd6da); border-bottom: 3px solid var(--dsw-alias-border-l2, #cdd6da); }\n.edrv-drag-overlay { position: fixed; z-index: 150; pointer-events: none; box-sizing: border-box; border: 0; background: color-mix(in srgb, var(--dsw-alias-state-info-primary, #4d6bfe) 25%, transparent); }\n.edrv-drop-label, .edrv-drag-ghost { position: fixed; z-index: 151; pointer-events: none; padding: 4px 8px; background: var(--dsw-alias-bg-overlay, #fff); color: var(--dsw-alias-label-primary, #1f2933); border: 1px solid var(--dsw-alias-border-l2, #cdd6da); font-size: 12px; white-space: nowrap; }\n.edrv-drop-label { position: absolute; left: 4px; top: 4px; }\n[data-edrv-view] .edrv-tab:focus-visible { outline: 2px solid var(--dsw-alias-state-info-primary, #4d6bfe); outline-offset: -2px; }\n@media (prefers-reduced-motion: reduce) { .edrv-drag-overlay { transition: none; } }\n";
|
|
37
37
|
const tagId$1 = "dsh-vscode-mode/editor.css";
|
|
38
38
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
39
39
|
const tag = document.createElement("style");
|
|
@@ -199,7 +199,7 @@ window.__ModuleLoader__.load({
|
|
|
199
199
|
* 作者 ddj 2026-08-28
|
|
200
200
|
*/
|
|
201
201
|
/** localStorage 键前缀(按工作区作用域隔离,无 cwd 会话回退会话键)。 */
|
|
202
|
-
const KEY_PREFIX$
|
|
202
|
+
const KEY_PREFIX$4 = CACHE_KEY.viewstate;
|
|
203
203
|
/**
|
|
204
204
|
* 判断对象是否为合法的 Monaco view state(保守形状校验,非深校验)。
|
|
205
205
|
* @author ddj 2026年08月28号
|
|
@@ -277,7 +277,7 @@ window.__ModuleLoader__.load({
|
|
|
277
277
|
*/
|
|
278
278
|
function viewStatesLoad(scope) {
|
|
279
279
|
try {
|
|
280
|
-
return parseViewStates(window.localStorage.getItem(KEY_PREFIX$
|
|
280
|
+
return parseViewStates(window.localStorage.getItem(KEY_PREFIX$4 + String(scope))) ?? {};
|
|
281
281
|
} catch (error) {
|
|
282
282
|
return {};
|
|
283
283
|
}
|
|
@@ -290,7 +290,7 @@ window.__ModuleLoader__.load({
|
|
|
290
290
|
*/
|
|
291
291
|
function viewStatesSave(scope, states) {
|
|
292
292
|
try {
|
|
293
|
-
window.localStorage.setItem(KEY_PREFIX$
|
|
293
|
+
window.localStorage.setItem(KEY_PREFIX$4 + String(scope), serializeViewStates(states));
|
|
294
294
|
} catch (error) {}
|
|
295
295
|
}
|
|
296
296
|
//#endregion
|
|
@@ -1505,6 +1505,236 @@ window.__ModuleLoader__.load({
|
|
|
1505
1505
|
actions
|
|
1506
1506
|
}, props.children);
|
|
1507
1507
|
}
|
|
1508
|
+
const TEXT_VIEW_BYTES = 8388608;
|
|
1509
|
+
//#endregion
|
|
1510
|
+
//#region src/client/textPages.ts
|
|
1511
|
+
/**
|
|
1512
|
+
* Own one preview identity and one in-flight request; no polling or automatic continuation.
|
|
1513
|
+
* @public @author ddj 2026年10月22号
|
|
1514
|
+
* @param load Authorized RPC loader. @param changed Snapshot observer.
|
|
1515
|
+
* @returns Pager lifecycle and explicit load controls.
|
|
1516
|
+
*/
|
|
1517
|
+
function createTextPager(load, changed) {
|
|
1518
|
+
let generation = 0;
|
|
1519
|
+
let disposed = false;
|
|
1520
|
+
let target = null;
|
|
1521
|
+
let cursor;
|
|
1522
|
+
let version;
|
|
1523
|
+
let inFlight = false;
|
|
1524
|
+
let retainedBytes = 0;
|
|
1525
|
+
let state = emptyState();
|
|
1526
|
+
/** @private @author ddj 2026年10月22号 @returns Publish immutable snapshot. */
|
|
1527
|
+
function publish() {
|
|
1528
|
+
changed({ ...state });
|
|
1529
|
+
}
|
|
1530
|
+
/** @public @author ddj 2026年10月22号 @param args New file/session identity. @returns Reset state; old responses are ignored. */
|
|
1531
|
+
function reset(args) {
|
|
1532
|
+
generation++;
|
|
1533
|
+
target = {
|
|
1534
|
+
sessionId: args.sessionId,
|
|
1535
|
+
path: args.path
|
|
1536
|
+
};
|
|
1537
|
+
cursor = void 0;
|
|
1538
|
+
version = void 0;
|
|
1539
|
+
retainedBytes = 0;
|
|
1540
|
+
state = emptyState();
|
|
1541
|
+
state.loading = inFlight;
|
|
1542
|
+
if (!disposed) publish();
|
|
1543
|
+
}
|
|
1544
|
+
/** @public @author ddj 2026年10月22号 @returns Explicitly load one page, or no-op when busy/finished. */
|
|
1545
|
+
async function loadNext() {
|
|
1546
|
+
if (disposed || !target || inFlight || state.eof || state.capped) return;
|
|
1547
|
+
state.error = null;
|
|
1548
|
+
const requestGeneration = generation;
|
|
1549
|
+
const request = {
|
|
1550
|
+
...target,
|
|
1551
|
+
cursor
|
|
1552
|
+
};
|
|
1553
|
+
inFlight = true;
|
|
1554
|
+
state.loading = true;
|
|
1555
|
+
publish();
|
|
1556
|
+
try {
|
|
1557
|
+
const page = await load(request);
|
|
1558
|
+
if (disposed || requestGeneration !== generation) return;
|
|
1559
|
+
if (!page.ok) {
|
|
1560
|
+
state.error = page.error;
|
|
1561
|
+
return;
|
|
1562
|
+
}
|
|
1563
|
+
if (!validPage(page, state.offset, version)) {
|
|
1564
|
+
state.error = "Invalid or stale text page";
|
|
1565
|
+
return;
|
|
1566
|
+
}
|
|
1567
|
+
appendPage(page);
|
|
1568
|
+
} catch (error) {
|
|
1569
|
+
if (!disposed && requestGeneration === generation) state.error = String(error);
|
|
1570
|
+
} finally {
|
|
1571
|
+
inFlight = false;
|
|
1572
|
+
if (!disposed) {
|
|
1573
|
+
state.loading = false;
|
|
1574
|
+
publish();
|
|
1575
|
+
}
|
|
1576
|
+
}
|
|
1577
|
+
}
|
|
1578
|
+
/** @private @author ddj 2026年10月22号 @param page Verified page. @returns Append only within byte/line limits. */
|
|
1579
|
+
function appendPage(page) {
|
|
1580
|
+
let text = page.text;
|
|
1581
|
+
const encoded = new TextEncoder().encode(text);
|
|
1582
|
+
const remaining = TEXT_VIEW_BYTES - retainedBytes;
|
|
1583
|
+
if (encoded.length > remaining) {
|
|
1584
|
+
let end = remaining;
|
|
1585
|
+
while (end > 0 && (encoded[end] & 192) === 128) end--;
|
|
1586
|
+
text = new TextDecoder("utf-8", { fatal: true }).decode(encoded.subarray(0, end));
|
|
1587
|
+
state.capped = true;
|
|
1588
|
+
}
|
|
1589
|
+
let lines = state.lines;
|
|
1590
|
+
for (let index = 0; index < text.length; index++) {
|
|
1591
|
+
if (text[index] !== "\n" && (text[index] !== "\r" || text[index + 1] === "\n")) continue;
|
|
1592
|
+
if (lines >= 5e4) {
|
|
1593
|
+
const end = text[index] === "\n" && text[index - 1] === "\r" ? index - 1 : index;
|
|
1594
|
+
text = text.slice(0, end);
|
|
1595
|
+
state.capped = true;
|
|
1596
|
+
break;
|
|
1597
|
+
}
|
|
1598
|
+
lines++;
|
|
1599
|
+
}
|
|
1600
|
+
retainedBytes += new TextEncoder().encode(text).length;
|
|
1601
|
+
state.text += text;
|
|
1602
|
+
state.lines = lines;
|
|
1603
|
+
state.offset = page.offset;
|
|
1604
|
+
state.size = page.size;
|
|
1605
|
+
state.eof = page.eof;
|
|
1606
|
+
state.partialLine = page.partialLine || state.capped;
|
|
1607
|
+
state.capped ||= page.offset >= 8388608 || retainedBytes >= 8388608 || lines >= 5e4;
|
|
1608
|
+
version = page.version;
|
|
1609
|
+
cursor = page.nextCursor ?? void 0;
|
|
1610
|
+
}
|
|
1611
|
+
/** @public @author ddj 2026年10月22号 @returns Invalidate identity while retaining the transport lock. */
|
|
1612
|
+
function invalidate() {
|
|
1613
|
+
generation++;
|
|
1614
|
+
target = null;
|
|
1615
|
+
state = emptyState();
|
|
1616
|
+
}
|
|
1617
|
+
/** @public @author ddj 2026年10月22号 @returns Invalidate pending responses and release preview content. */
|
|
1618
|
+
function dispose() {
|
|
1619
|
+
disposed = true;
|
|
1620
|
+
invalidate();
|
|
1621
|
+
}
|
|
1622
|
+
return {
|
|
1623
|
+
reset,
|
|
1624
|
+
loadNext,
|
|
1625
|
+
invalidate,
|
|
1626
|
+
dispose,
|
|
1627
|
+
getState: () => ({ ...state })
|
|
1628
|
+
};
|
|
1629
|
+
}
|
|
1630
|
+
/** @private @author ddj 2026年10月22号 @returns Empty bounded preview state. */
|
|
1631
|
+
function emptyState() {
|
|
1632
|
+
return {
|
|
1633
|
+
text: "",
|
|
1634
|
+
loading: false,
|
|
1635
|
+
eof: false,
|
|
1636
|
+
capped: false,
|
|
1637
|
+
error: null,
|
|
1638
|
+
offset: 0,
|
|
1639
|
+
size: 0,
|
|
1640
|
+
lines: 1,
|
|
1641
|
+
partialLine: false
|
|
1642
|
+
};
|
|
1643
|
+
}
|
|
1644
|
+
/**
|
|
1645
|
+
* Validate the RPC envelope before retaining any content.
|
|
1646
|
+
* @private @author ddj 2026年10月22号
|
|
1647
|
+
* @param page Server page. @param offset Previous byte position. @param version Bound version.
|
|
1648
|
+
* @returns Whether bounds and continuation invariants hold.
|
|
1649
|
+
*/
|
|
1650
|
+
function validPage(page, offset, version) {
|
|
1651
|
+
return typeof page.text === "string" && typeof page.version === "string" && (version === void 0 || version === page.version) && Number.isSafeInteger(page.offset) && Number.isSafeInteger(page.size) && page.size >= 0 && page.offset >= offset && page.offset <= page.size && (page.offset > offset || page.eof) && page.offset - offset <= 262144 && new TextEncoder().encode(page.text).length <= 262145 && page.encoding === "utf-8" && typeof page.partialLine === "boolean" && typeof page.eof === "boolean" && (page.eof ? page.nextCursor === null : typeof page.nextCursor === "string" && page.nextCursor.length > 0) && page.eof === (page.offset === page.size);
|
|
1652
|
+
}
|
|
1653
|
+
//#endregion
|
|
1654
|
+
//#region src/client/ui/LargeTextView.ts
|
|
1655
|
+
const Button$1 = _deepseek_ai_dsh_client_ui_primitives.Button;
|
|
1656
|
+
/**
|
|
1657
|
+
* Read-only paged text surface: never creates a Monaco model or exposes a save action.
|
|
1658
|
+
* @public @author ddj 2026年10月22号
|
|
1659
|
+
* @param props Exact session/file identity and authorized page loader.
|
|
1660
|
+
* @returns Bounded selectable text with explicit continuation and status.
|
|
1661
|
+
*/
|
|
1662
|
+
function LargeTextView(props) {
|
|
1663
|
+
const [snapshot, setSnapshot] = react.default.useState(null);
|
|
1664
|
+
const [identity, setIdentity] = react.default.useState("");
|
|
1665
|
+
const pagerRef = react.default.useRef(null);
|
|
1666
|
+
const loaderRef = react.default.useRef(props.loadPage);
|
|
1667
|
+
const mountedRef = react.default.useRef(false);
|
|
1668
|
+
const firstPending = react.default.useRef(false);
|
|
1669
|
+
loaderRef.current = props.loadPage;
|
|
1670
|
+
const currentIdentity = JSON.stringify([props.sessionId, props.path]);
|
|
1671
|
+
/** @private @author ddj 2026年10月22号 @param args Request identity. @returns Current injected loader response. */
|
|
1672
|
+
function loadPage(args) {
|
|
1673
|
+
return loaderRef.current(args);
|
|
1674
|
+
}
|
|
1675
|
+
/** @private @author ddj 2026年10月22号 @param state Latest pager snapshot. @returns Publish only while mounted. */
|
|
1676
|
+
function onSnapshot(state) {
|
|
1677
|
+
if (!mountedRef.current) return;
|
|
1678
|
+
setSnapshot(state);
|
|
1679
|
+
if (!state.loading && firstPending.current) queueMicrotask(loadFirst);
|
|
1680
|
+
}
|
|
1681
|
+
/** @private @author ddj 2026年10月22号 @description Start only the new identity's deferred first page, never automatic continuation. */
|
|
1682
|
+
function loadFirst() {
|
|
1683
|
+
const pager = pagerRef.current;
|
|
1684
|
+
if (!mountedRef.current || !firstPending.current || !pager || pager.getState().loading || typeof document !== "undefined" && document.hidden) return;
|
|
1685
|
+
firstPending.current = false;
|
|
1686
|
+
pager.loadNext();
|
|
1687
|
+
}
|
|
1688
|
+
/** @private @author ddj 2026年10月22号 @returns Bind identity without replacing the single transport lock. */
|
|
1689
|
+
function mountPager() {
|
|
1690
|
+
mountedRef.current = true;
|
|
1691
|
+
if (!pagerRef.current) pagerRef.current = createTextPager(loadPage, onSnapshot);
|
|
1692
|
+
const pager = pagerRef.current;
|
|
1693
|
+
setIdentity(currentIdentity);
|
|
1694
|
+
firstPending.current = true;
|
|
1695
|
+
pager.reset({
|
|
1696
|
+
sessionId: props.sessionId,
|
|
1697
|
+
path: props.path
|
|
1698
|
+
});
|
|
1699
|
+
loadFirst();
|
|
1700
|
+
if (typeof document !== "undefined") document.addEventListener("visibilitychange", loadFirst);
|
|
1701
|
+
/** @private @author ddj 2026年10月22号 @returns Release retained text and ignore pending responses. */
|
|
1702
|
+
function unmountPager() {
|
|
1703
|
+
mountedRef.current = false;
|
|
1704
|
+
firstPending.current = false;
|
|
1705
|
+
if (typeof document !== "undefined") document.removeEventListener("visibilitychange", loadFirst);
|
|
1706
|
+
pager.invalidate();
|
|
1707
|
+
}
|
|
1708
|
+
return unmountPager;
|
|
1709
|
+
}
|
|
1710
|
+
react.default.useEffect(mountPager, [props.sessionId, props.path]);
|
|
1711
|
+
/** @private @author ddj 2026年10月22号 @returns Load exactly one additional page on user intent. */
|
|
1712
|
+
function loadNext() {
|
|
1713
|
+
if (typeof document !== "undefined" && document.hidden) return;
|
|
1714
|
+
if (firstPending.current) {
|
|
1715
|
+
loadFirst();
|
|
1716
|
+
return;
|
|
1717
|
+
}
|
|
1718
|
+
pagerRef.current?.loadNext();
|
|
1719
|
+
}
|
|
1720
|
+
const state = identity === currentIdentity ? snapshot : null;
|
|
1721
|
+
let status = "正在加载只读文本…";
|
|
1722
|
+
if (state?.error) status = state.error;
|
|
1723
|
+
else if (state?.capped) status = "已达预览上限(8 MiB / 50,000 行),请使用外部编辑器查看完整文件";
|
|
1724
|
+
else if (state?.eof) status = "文件末尾 · 只读";
|
|
1725
|
+
else if (state) status = `已读取 ${state.offset.toLocaleString()} / ${state.size.toLocaleString()} 字节 · 只读`;
|
|
1726
|
+
if (state?.partialLine) status += " · 末行尚未完整";
|
|
1727
|
+
return react.default.createElement("section", {
|
|
1728
|
+
className: "edrv-large-text",
|
|
1729
|
+
"aria-label": "大文件只读预览"
|
|
1730
|
+
}, react.default.createElement("div", { className: "edrv-large-text-toolbar" }, react.default.createElement("span", { role: "status" }, status), react.default.createElement(Button$1, {
|
|
1731
|
+
onClick: loadNext,
|
|
1732
|
+
disabled: !state || state.loading || state.eof || state.capped
|
|
1733
|
+
}, state?.loading ? "加载中…" : state?.error ? "重试本段" : "加载下一段")), react.default.createElement("pre", {
|
|
1734
|
+
className: "edrv-large-text-content",
|
|
1735
|
+
tabIndex: 0
|
|
1736
|
+
}, state?.text ?? ""));
|
|
1737
|
+
}
|
|
1508
1738
|
//#endregion
|
|
1509
1739
|
//#region src/client/tabDrag.ts
|
|
1510
1740
|
/** Internal pointer drag: never converts external text into file paths. @author ddj 2026年10月14号 */
|
|
@@ -8433,7 +8663,7 @@ window.__ModuleLoader__.load({
|
|
|
8433
8663
|
//#endregion
|
|
8434
8664
|
//#region src/client/dap/breakpoints.ts
|
|
8435
8665
|
/** localStorage key 前缀。 */
|
|
8436
|
-
const KEY_PREFIX$
|
|
8666
|
+
const KEY_PREFIX$3 = "edrv.dap.bp.";
|
|
8437
8667
|
/**
|
|
8438
8668
|
* 读断点表(缺失/损坏返回空表)。
|
|
8439
8669
|
* @author ddj 2026年09月29号
|
|
@@ -8441,7 +8671,7 @@ window.__ModuleLoader__.load({
|
|
|
8441
8671
|
*/
|
|
8442
8672
|
function loadBpMap(scope) {
|
|
8443
8673
|
try {
|
|
8444
|
-
const raw = localStorage.getItem(KEY_PREFIX$
|
|
8674
|
+
const raw = localStorage.getItem(KEY_PREFIX$3 + scope);
|
|
8445
8675
|
if (!raw) return {};
|
|
8446
8676
|
const data = JSON.parse(raw);
|
|
8447
8677
|
if (!data || typeof data !== "object" || Array.isArray(data)) return {};
|
|
@@ -8477,8 +8707,8 @@ window.__ModuleLoader__.load({
|
|
|
8477
8707
|
*/
|
|
8478
8708
|
function saveBpMap(scope, map) {
|
|
8479
8709
|
try {
|
|
8480
|
-
if (!Object.keys(map).length) localStorage.removeItem(KEY_PREFIX$
|
|
8481
|
-
else localStorage.setItem(KEY_PREFIX$
|
|
8710
|
+
if (!Object.keys(map).length) localStorage.removeItem(KEY_PREFIX$3 + scope);
|
|
8711
|
+
else localStorage.setItem(KEY_PREFIX$3 + scope, JSON.stringify(map));
|
|
8482
8712
|
} catch {}
|
|
8483
8713
|
}
|
|
8484
8714
|
/**
|
|
@@ -8585,23 +8815,6 @@ window.__ModuleLoader__.load({
|
|
|
8585
8815
|
[path]: list
|
|
8586
8816
|
};
|
|
8587
8817
|
}
|
|
8588
|
-
/**
|
|
8589
|
-
* 推导断点行的跳转目标(调试面板点击断点项 → 打开文件并定位到断点行)。
|
|
8590
|
-
* 路径缺失或行号非 ≥1 的有限数时返回 null(提前返回,不发起无效导航)。
|
|
8591
|
-
* @author ddj 2026年09月21号
|
|
8592
|
-
* @param row 面板行视图(文件路径 + 断点条目)
|
|
8593
|
-
* @returns 跳转目标;入参不合法时返回 null
|
|
8594
|
-
*/
|
|
8595
|
-
function bpJumpTargetOf(row) {
|
|
8596
|
-
const path = typeof row?.path === "string" ? row.path : "";
|
|
8597
|
-
const line = row?.entry?.line;
|
|
8598
|
-
if (!path || typeof line !== "number" || !Number.isFinite(line) || line < 1) return null;
|
|
8599
|
-
return {
|
|
8600
|
-
path,
|
|
8601
|
-
line: Math.floor(line),
|
|
8602
|
-
column: 1
|
|
8603
|
-
};
|
|
8604
|
-
}
|
|
8605
8818
|
//#endregion
|
|
8606
8819
|
//#region src/client/dap/pidPick.ts
|
|
8607
8820
|
/**
|
|
@@ -10913,6 +11126,82 @@ window.__ModuleLoader__.load({
|
|
|
10913
11126
|
}, "✕ 关闭")), react.default.createElement("div", { className: "edrv-launch-body" }, body));
|
|
10914
11127
|
}
|
|
10915
11128
|
//#endregion
|
|
11129
|
+
//#region src/client/sidebar/PanelBoundary.ts
|
|
11130
|
+
/** Panel-local callback and React subtree isolation, not a security sandbox. @author ddj 2026年10月22号 */
|
|
11131
|
+
const panelIds = /* @__PURE__ */ new WeakMap();
|
|
11132
|
+
let nextPanelId = 0;
|
|
11133
|
+
/** @private @author ddj 2026年10月22号 @param props Subtree ownership. @returns Stable identity that changes on registration, scope or session replacement. */
|
|
11134
|
+
function ownerKey(props) {
|
|
11135
|
+
if (!panelIds.has(props.panel)) panelIds.set(props.panel, ++nextPanelId);
|
|
11136
|
+
return JSON.stringify([
|
|
11137
|
+
panelIds.get(props.panel),
|
|
11138
|
+
props.scope,
|
|
11139
|
+
props.sessionId
|
|
11140
|
+
]);
|
|
11141
|
+
}
|
|
11142
|
+
/** @public @author ddj 2026年10月22号 @param panel Registered definition. @param ctx Current scope. @returns Hidden marker or isolated visible/badge result; failed guards stay reachable for retry. */
|
|
11143
|
+
function inspectPanel(panel, ctx) {
|
|
11144
|
+
try {
|
|
11145
|
+
if (panel.visible && panel.visible(ctx) !== true) return null;
|
|
11146
|
+
return {
|
|
11147
|
+
panel,
|
|
11148
|
+
badge: panel.badge?.(ctx) ?? null
|
|
11149
|
+
};
|
|
11150
|
+
} catch (error) {
|
|
11151
|
+
return {
|
|
11152
|
+
panel,
|
|
11153
|
+
badge: null,
|
|
11154
|
+
error: error instanceof Error ? error : new Error(String(error))
|
|
11155
|
+
};
|
|
11156
|
+
}
|
|
11157
|
+
}
|
|
11158
|
+
/** @public @author ddj 2026年10月22号 @description Reset a failed subtree when registration or scope ownership changes. */
|
|
11159
|
+
var PanelBoundary = class extends react.default.Component {
|
|
11160
|
+
state = {
|
|
11161
|
+
panel: this.props.panel,
|
|
11162
|
+
scope: this.props.scope,
|
|
11163
|
+
sessionId: this.props.sessionId,
|
|
11164
|
+
error: null
|
|
11165
|
+
};
|
|
11166
|
+
/** @public @author ddj 2026年10月22号 @param props Current ownership. @param state Previous ownership/error. @returns Reset only when the owner changes. */
|
|
11167
|
+
static getDerivedStateFromProps(props, state) {
|
|
11168
|
+
if (state.panel === props.panel && state.scope === props.scope && state.sessionId === props.sessionId) return null;
|
|
11169
|
+
return {
|
|
11170
|
+
panel: props.panel,
|
|
11171
|
+
scope: props.scope,
|
|
11172
|
+
sessionId: props.sessionId,
|
|
11173
|
+
error: null
|
|
11174
|
+
};
|
|
11175
|
+
}
|
|
11176
|
+
/** @public @author ddj 2026年10月22号 @param error React render/lifecycle error. @returns Local fallback state. */
|
|
11177
|
+
static getDerivedStateFromError(error) {
|
|
11178
|
+
return { error };
|
|
11179
|
+
}
|
|
11180
|
+
/** @private @author ddj 2026年10月22号 @description Remount only this failed subtree and reevaluate its callbacks. */
|
|
11181
|
+
retry = () => {
|
|
11182
|
+
this.setState({ error: null });
|
|
11183
|
+
};
|
|
11184
|
+
/** @public @author ddj 2026年10月22号 @returns Original subtree or panel-local retry UI. */
|
|
11185
|
+
render() {
|
|
11186
|
+
if (!this.state.error) return react.default.createElement(react.default.Fragment, { key: ownerKey(this.props) }, this.props.children);
|
|
11187
|
+
if (this.props.compact) return react.default.createElement("span", {
|
|
11188
|
+
role: "img",
|
|
11189
|
+
title: "图标加载失败",
|
|
11190
|
+
"aria-label": "图标加载失败"
|
|
11191
|
+
}, "!");
|
|
11192
|
+
return react.default.createElement("div", {
|
|
11193
|
+
className: "edrv-empty",
|
|
11194
|
+
role: "alert"
|
|
11195
|
+
}, this.props.panel.title + ":" + String(this.state.error.message), react.default.createElement("button", { onClick: this.retry }, "重试"));
|
|
11196
|
+
}
|
|
11197
|
+
};
|
|
11198
|
+
/** @public @author ddj 2026年10月22号 @param props Isolated panel invocation below the boundary. @returns Panel subtree. @throws Extension callback error for the nearest boundary. */
|
|
11199
|
+
function PanelContent(props) {
|
|
11200
|
+
const checked = inspectPanel(props.panel, props.ctx);
|
|
11201
|
+
if (checked?.error) throw checked.error;
|
|
11202
|
+
return checked ? props.panel.render(props.ctx) : null;
|
|
11203
|
+
}
|
|
11204
|
+
//#endregion
|
|
10916
11205
|
//#region src/client/sidebar/SidebarView.ts
|
|
10917
11206
|
/**
|
|
10918
11207
|
* dsh-vscode-mode client — 侧边栏容器(活动栏常显 + 可隐藏面板区 + 拖拽调宽)。
|
|
@@ -10955,7 +11244,8 @@ window.__ModuleLoader__.load({
|
|
|
10955
11244
|
*/
|
|
10956
11245
|
function SidebarView(props) {
|
|
10957
11246
|
const ctx = props.ctx;
|
|
10958
|
-
const
|
|
11247
|
+
const checked = (props.registry?.list?.() ?? []).map((panel) => inspectPanel(panel, ctx)).filter(Boolean);
|
|
11248
|
+
const panels = checked.map((entry) => entry.panel);
|
|
10959
11249
|
const activePanel = props.activePanel;
|
|
10960
11250
|
const onActive = props.onActive;
|
|
10961
11251
|
const visible = props.visible !== false;
|
|
@@ -10965,26 +11255,71 @@ window.__ModuleLoader__.load({
|
|
|
10965
11255
|
const onHide = props.onHide;
|
|
10966
11256
|
const wMin = Math.max(120, Math.min(W_MAX, Math.round(Number(props.minWidth) || 300)));
|
|
10967
11257
|
const active = panels.find((p) => p.id === activePanel) || panels[0];
|
|
11258
|
+
const dragCleanup = react.default.useRef(null);
|
|
11259
|
+
/** @private @author ddj 2026年10月22号 @description End the active drag; safe on repeated teardown. */
|
|
11260
|
+
function stopDrag() {
|
|
11261
|
+
dragCleanup.current?.();
|
|
11262
|
+
}
|
|
11263
|
+
const seamOpening = react.default.useRef(false);
|
|
11264
|
+
const lastVisible = react.default.useRef(visible);
|
|
11265
|
+
/** @private @author ddj 2026年10月22号 @description Always release listeners on unmount, including a pending seam expansion. */
|
|
11266
|
+
function dragEffect() {
|
|
11267
|
+
return stopDrag;
|
|
11268
|
+
}
|
|
11269
|
+
react.default.useEffect(dragEffect, []);
|
|
11270
|
+
/** @private @author ddj 2026年10月22号 @description Preserve only the seam's own expansion; external visibility changes cancel ownership. */
|
|
11271
|
+
function visibilityEffect() {
|
|
11272
|
+
if (lastVisible.current !== visible) {
|
|
11273
|
+
if (!(visible && seamOpening.current)) stopDrag();
|
|
11274
|
+
seamOpening.current = false;
|
|
11275
|
+
lastVisible.current = visible;
|
|
11276
|
+
}
|
|
11277
|
+
}
|
|
11278
|
+
react.default.useEffect(visibilityEffect, [visible]);
|
|
11279
|
+
/** @private @author ddj 2026年10月22号 @param pointerId Owning pointer. @param move Pointer movement callback. @description Replace the previous drag and own every exit path. */
|
|
11280
|
+
function bindDrag(pointerId, move) {
|
|
11281
|
+
stopDrag();
|
|
11282
|
+
/** @author ddj 2026年10月22号 @param event Pointer event. @description Ignore another pointer's movement. */
|
|
11283
|
+
function onMove(event) {
|
|
11284
|
+
if (event.pointerId === pointerId) move(event);
|
|
11285
|
+
}
|
|
11286
|
+
/** @author ddj 2026年10月22号 @param event Pointer completion. @description Only the owning pointer ends the drag. */
|
|
11287
|
+
function onEnd(event) {
|
|
11288
|
+
if (event.pointerId === pointerId) cleanup();
|
|
11289
|
+
}
|
|
11290
|
+
/** @author ddj 2026年10月22号 @description Remove all drag listeners and release ownership. */
|
|
11291
|
+
function cleanup() {
|
|
11292
|
+
window.removeEventListener("pointermove", onMove);
|
|
11293
|
+
window.removeEventListener("pointerup", onEnd);
|
|
11294
|
+
window.removeEventListener("pointercancel", onEnd);
|
|
11295
|
+
window.removeEventListener("blur", cleanup);
|
|
11296
|
+
if (dragCleanup.current === cleanup) {
|
|
11297
|
+
dragCleanup.current = null;
|
|
11298
|
+
seamOpening.current = false;
|
|
11299
|
+
}
|
|
11300
|
+
}
|
|
11301
|
+
dragCleanup.current = cleanup;
|
|
11302
|
+
window.addEventListener("pointermove", onMove);
|
|
11303
|
+
window.addEventListener("pointerup", onEnd);
|
|
11304
|
+
window.addEventListener("pointercancel", onEnd);
|
|
11305
|
+
window.addEventListener("blur", cleanup);
|
|
11306
|
+
}
|
|
11307
|
+
/** @private @author ddj 2026年10月22号 @param e Starting pointer. @description Resize the visible panel until completion or collapse. */
|
|
10968
11308
|
const onPointerDown = (e) => {
|
|
10969
11309
|
e.preventDefault();
|
|
10970
11310
|
const startX = e.clientX;
|
|
10971
11311
|
const startW = width;
|
|
10972
|
-
|
|
10973
|
-
window.removeEventListener("pointermove", onMove);
|
|
10974
|
-
window.removeEventListener("pointerup", onUp);
|
|
10975
|
-
};
|
|
10976
|
-
const onUp = () => cleanup();
|
|
11312
|
+
/** @author ddj 2026年10月22号 @param ev Owning pointer movement. @description Apply this drag's width calculation. */
|
|
10977
11313
|
const onMove = (ev) => {
|
|
10978
11314
|
const raw = startW + (ev.clientX - startX);
|
|
10979
11315
|
if (raw < wMin) {
|
|
10980
|
-
|
|
11316
|
+
stopDrag();
|
|
10981
11317
|
onHide();
|
|
10982
11318
|
return;
|
|
10983
11319
|
}
|
|
10984
11320
|
onWidth(Math.min(W_MAX, raw));
|
|
10985
11321
|
};
|
|
10986
|
-
|
|
10987
|
-
window.addEventListener("pointerup", onUp);
|
|
11322
|
+
bindDrag(e.pointerId, onMove);
|
|
10988
11323
|
};
|
|
10989
11324
|
/**
|
|
10990
11325
|
* 隐藏态接缝拖拽:向右拖过阈值把面板区拉出来(以记忆宽度展开),继续拖动实时调宽。
|
|
@@ -10996,23 +11331,19 @@ window.__ModuleLoader__.load({
|
|
|
10996
11331
|
const baseW = Math.max(wMin, Math.min(W_MAX, Math.round(Number(width) || wMin)));
|
|
10997
11332
|
let expanded = false;
|
|
10998
11333
|
let expandStartX = 0;
|
|
10999
|
-
|
|
11000
|
-
window.removeEventListener("pointermove", onMove);
|
|
11001
|
-
window.removeEventListener("pointerup", onUp);
|
|
11002
|
-
};
|
|
11003
|
-
const onUp = () => cleanup();
|
|
11334
|
+
/** @author ddj 2026年10月22号 @param ev Owning pointer movement. @description Apply this drag's width calculation. */
|
|
11004
11335
|
const onMove = (ev) => {
|
|
11005
11336
|
if (!expanded) {
|
|
11006
11337
|
if (ev.clientX - startX < PULL_OUT_THRESHOLD) return;
|
|
11007
11338
|
expanded = true;
|
|
11008
11339
|
expandStartX = ev.clientX;
|
|
11340
|
+
seamOpening.current = true;
|
|
11009
11341
|
onShow();
|
|
11010
11342
|
return;
|
|
11011
11343
|
}
|
|
11012
11344
|
onWidth(Math.max(wMin, Math.min(W_MAX, baseW + (ev.clientX - expandStartX))));
|
|
11013
11345
|
};
|
|
11014
|
-
|
|
11015
|
-
window.addEventListener("pointerup", onUp);
|
|
11346
|
+
bindDrag(e.pointerId, onMove);
|
|
11016
11347
|
};
|
|
11017
11348
|
const rail = react.default.createElement("div", { className: "edrv-rail" }, react.default.createElement("div", { style: {
|
|
11018
11349
|
flex: 1,
|
|
@@ -11020,7 +11351,7 @@ window.__ModuleLoader__.load({
|
|
|
11020
11351
|
flexDirection: "column",
|
|
11021
11352
|
gap: 2
|
|
11022
11353
|
} }, panels.map((p) => {
|
|
11023
|
-
const count =
|
|
11354
|
+
const count = checked.find((entry) => entry.panel === p)?.badge;
|
|
11024
11355
|
return react.default.createElement("button", {
|
|
11025
11356
|
key: p.id,
|
|
11026
11357
|
className: "edrv-rail-btn" + (visible && active && p.id === active.id ? " edrv-rail-on" : ""),
|
|
@@ -11029,7 +11360,12 @@ window.__ModuleLoader__.load({
|
|
|
11029
11360
|
onActive(p.id);
|
|
11030
11361
|
if (!visible && typeof onShow === "function") onShow();
|
|
11031
11362
|
}
|
|
11032
|
-
}, react.default.createElement("span", { className: "edrv-rail-icon" },
|
|
11363
|
+
}, react.default.createElement("span", { className: "edrv-rail-icon" }, react.default.createElement(PanelBoundary, {
|
|
11364
|
+
panel: p,
|
|
11365
|
+
scope: ctx?.scope,
|
|
11366
|
+
sessionId: ctx?.sessionId,
|
|
11367
|
+
compact: true
|
|
11368
|
+
}, railIconEl(p.icon))), count > 0 ? react.default.createElement("span", { className: "edrv-rail-badge" }, String(count)) : null);
|
|
11033
11369
|
})), react.default.createElement("button", {
|
|
11034
11370
|
className: "edrv-rail-btn",
|
|
11035
11371
|
title: (visible ? "隐藏面板区" : "展开面板区") + " (Ctrl+B)",
|
|
@@ -11041,7 +11377,14 @@ window.__ModuleLoader__.load({
|
|
|
11041
11377
|
width: visible ? width : 49,
|
|
11042
11378
|
maxWidth: "100%"
|
|
11043
11379
|
}
|
|
11044
|
-
}, rail, visible ? react.default.createElement("div", { className: "edrv-side-body" }, active ?
|
|
11380
|
+
}, rail, visible ? react.default.createElement("div", { className: "edrv-side-body" }, active ? react.default.createElement(PanelBoundary, {
|
|
11381
|
+
panel: active,
|
|
11382
|
+
scope: ctx?.scope,
|
|
11383
|
+
sessionId: ctx?.sessionId
|
|
11384
|
+
}, react.default.createElement(PanelContent, {
|
|
11385
|
+
panel: active,
|
|
11386
|
+
ctx
|
|
11387
|
+
})) : null) : null, visible ? react.default.createElement("div", {
|
|
11045
11388
|
className: "edrv-side-resize",
|
|
11046
11389
|
onPointerDown
|
|
11047
11390
|
}) : react.default.createElement("div", {
|
|
@@ -22346,7 +22689,7 @@ window.__ModuleLoader__.load({
|
|
|
22346
22689
|
}
|
|
22347
22690
|
//#endregion
|
|
22348
22691
|
//#region src/client/dap/toolbarDrag.ts
|
|
22349
|
-
const KEY_PREFIX$
|
|
22692
|
+
const KEY_PREFIX$2 = "edrv.dap.toolbar.";
|
|
22350
22693
|
/** 将工具条位置限制在编辑区内。 */
|
|
22351
22694
|
function clampToolbarPosition(point, bounds) {
|
|
22352
22695
|
const margin = bounds.margin ?? 6;
|
|
@@ -22361,7 +22704,7 @@ window.__ModuleLoader__.load({
|
|
|
22361
22704
|
function loadToolbarPosition(scope) {
|
|
22362
22705
|
if (!scope) return null;
|
|
22363
22706
|
try {
|
|
22364
|
-
const raw = localStorage.getItem(KEY_PREFIX$
|
|
22707
|
+
const raw = localStorage.getItem(KEY_PREFIX$2 + scope);
|
|
22365
22708
|
if (!raw) return null;
|
|
22366
22709
|
const value = JSON.parse(raw);
|
|
22367
22710
|
if (!value || !Number.isFinite(value.left) || !Number.isFinite(value.top)) return null;
|
|
@@ -22377,7 +22720,7 @@ window.__ModuleLoader__.load({
|
|
|
22377
22720
|
function saveToolbarPosition(scope, point) {
|
|
22378
22721
|
if (!scope) return;
|
|
22379
22722
|
try {
|
|
22380
|
-
localStorage.setItem(KEY_PREFIX$
|
|
22723
|
+
localStorage.setItem(KEY_PREFIX$2 + scope, JSON.stringify(point));
|
|
22381
22724
|
} catch {}
|
|
22382
22725
|
}
|
|
22383
22726
|
//#endregion
|
|
@@ -22627,6 +22970,15 @@ window.__ModuleLoader__.load({
|
|
|
22627
22970
|
const aiStatusTimer = react.default.useRef(null);
|
|
22628
22971
|
const [error, setError] = react.default.useState(null);
|
|
22629
22972
|
const [loadError, setLoadError] = react.default.useState(null);
|
|
22973
|
+
const [largeCandidate, setLargeCandidate] = react.default.useState(null);
|
|
22974
|
+
const [pagedFile, setPagedFile] = react.default.useState(null);
|
|
22975
|
+
const [pageChanged, setPageChanged] = react.default.useState(null);
|
|
22976
|
+
const pageIdentity = JSON.stringify([
|
|
22977
|
+
scope,
|
|
22978
|
+
sessionId,
|
|
22979
|
+
active
|
|
22980
|
+
]);
|
|
22981
|
+
const paging = pagedFile === pageIdentity;
|
|
22630
22982
|
const [loadStage, setLoadStage] = react.default.useState({
|
|
22631
22983
|
progress: 0,
|
|
22632
22984
|
message: "准备加载编辑器…"
|
|
@@ -23339,6 +23691,9 @@ window.__ModuleLoader__.load({
|
|
|
23339
23691
|
status: "loading"
|
|
23340
23692
|
});
|
|
23341
23693
|
setLoadError(null);
|
|
23694
|
+
setLargeCandidate(null);
|
|
23695
|
+
setPagedFile(null);
|
|
23696
|
+
setPageChanged(null);
|
|
23342
23697
|
/**
|
|
23343
23698
|
* 记下磁盘版本基线;markRead=true 表示本次真的从磁盘读了内容
|
|
23344
23699
|
* (已读版本台账随之失效,下一轮轮询按新版本重新比对)。
|
|
@@ -23395,6 +23750,11 @@ window.__ModuleLoader__.load({
|
|
|
23395
23750
|
}));
|
|
23396
23751
|
setStatus("已加载");
|
|
23397
23752
|
} else {
|
|
23753
|
+
if (res?.code === "file-too-large") setLargeCandidate(JSON.stringify([
|
|
23754
|
+
scope,
|
|
23755
|
+
sid,
|
|
23756
|
+
path
|
|
23757
|
+
]));
|
|
23398
23758
|
const base = res?.error ? String(res.error) : "读取失败";
|
|
23399
23759
|
dapTrace("read-failed", {
|
|
23400
23760
|
path,
|
|
@@ -23575,7 +23935,7 @@ window.__ModuleLoader__.load({
|
|
|
23575
23935
|
* @author ddj 2026年09月15号
|
|
23576
23936
|
* @param change 轮询判定出的外部变更
|
|
23577
23937
|
*/
|
|
23578
|
-
|
|
23938
|
+
function onDiskChange(change) {
|
|
23579
23939
|
if (!change || !change.path) return;
|
|
23580
23940
|
const eventId = emitFileChanged(change.path, {
|
|
23581
23941
|
scope,
|
|
@@ -23604,6 +23964,18 @@ window.__ModuleLoader__.load({
|
|
|
23604
23964
|
}).catch(() => {});
|
|
23605
23965
|
return;
|
|
23606
23966
|
}
|
|
23967
|
+
if (change.kind === "modified" && (paging || pageChanged === pageIdentity) && change.path === activeRef.current) {
|
|
23968
|
+
loadContent(change.path, sessionId, true);
|
|
23969
|
+
setPageChanged(pageIdentity);
|
|
23970
|
+
setStatus("文件已变化,请重新读取");
|
|
23971
|
+
emitRefresh({
|
|
23972
|
+
scope,
|
|
23973
|
+
paths: [change.path],
|
|
23974
|
+
kind: "text",
|
|
23975
|
+
eventId
|
|
23976
|
+
});
|
|
23977
|
+
return;
|
|
23978
|
+
}
|
|
23607
23979
|
if (change.kind === "modified") {
|
|
23608
23980
|
loadContent(change.path, sessionId, true);
|
|
23609
23981
|
clearSync(scope, change.path);
|
|
@@ -23624,7 +23996,7 @@ window.__ModuleLoader__.load({
|
|
|
23624
23996
|
at: Date.now()
|
|
23625
23997
|
});
|
|
23626
23998
|
setStatus(kind === "deleted" ? "文件已被外部删除" : "外部已修改(未保存的编辑保留)");
|
|
23627
|
-
}
|
|
23999
|
+
}
|
|
23628
24000
|
diskChangeRef.current = onDiskChange;
|
|
23629
24001
|
/**
|
|
23630
24002
|
* 版本变化时读磁盘并与缓冲比对:内容相同 → 只推进基线(不做无意义重载);
|
|
@@ -23633,7 +24005,8 @@ window.__ModuleLoader__.load({
|
|
|
23633
24005
|
* @param path 文件路径
|
|
23634
24006
|
* @returns 比对结果;模型不可用/读失败 → null(按「需要重载」处理)
|
|
23635
24007
|
*/
|
|
23636
|
-
|
|
24008
|
+
function readDiskCompare(path) {
|
|
24009
|
+
if (path === activeRef.current && (paging || pageChanged === pageIdentity)) return Promise.resolve({ equal: false });
|
|
23637
24010
|
const model = modelsRef.current?.get(path);
|
|
23638
24011
|
if (!model || typeof model.getValue !== "function") return Promise.resolve(null);
|
|
23639
24012
|
return rpc("edrv.read", {
|
|
@@ -23643,7 +24016,7 @@ window.__ModuleLoader__.load({
|
|
|
23643
24016
|
if (!res || !res.ok) return null;
|
|
23644
24017
|
return { equal: res.content === model.getValue() };
|
|
23645
24018
|
}).catch(() => null);
|
|
23646
|
-
}
|
|
24019
|
+
}
|
|
23647
24020
|
useFileWatch({
|
|
23648
24021
|
sessionId,
|
|
23649
24022
|
scope,
|
|
@@ -26353,7 +26726,8 @@ window.__ModuleLoader__.load({
|
|
|
26353
26726
|
window.removeEventListener("edrv.command.debugStop", onStop);
|
|
26354
26727
|
};
|
|
26355
26728
|
}, []);
|
|
26356
|
-
|
|
26729
|
+
/** @private @author ddj 2026年10月22号 @description Probe a typed path; let oversized files enter the existing read-only paging flow. @returns Probe completion. */
|
|
26730
|
+
function openPath() {
|
|
26357
26731
|
const p = (pathDraft || "").trim();
|
|
26358
26732
|
if (!p) return;
|
|
26359
26733
|
if (isImagePath(p) || isPdfPath(p)) {
|
|
@@ -26365,11 +26739,11 @@ window.__ModuleLoader__.load({
|
|
|
26365
26739
|
return;
|
|
26366
26740
|
}
|
|
26367
26741
|
setStatus("打开中…");
|
|
26368
|
-
rpc("edrv.read", {
|
|
26742
|
+
return rpc("edrv.read", {
|
|
26369
26743
|
sessionId,
|
|
26370
26744
|
path: p
|
|
26371
26745
|
}).then((res) => {
|
|
26372
|
-
if (res && res.ok) {
|
|
26746
|
+
if (res && (res.ok || res.code === "file-too-large")) {
|
|
26373
26747
|
openFile(p, false);
|
|
26374
26748
|
setOpenInput(false);
|
|
26375
26749
|
setPathDraft("");
|
|
@@ -26383,7 +26757,7 @@ window.__ModuleLoader__.load({
|
|
|
26383
26757
|
setStatus("打开失败");
|
|
26384
26758
|
setError("打开异常:" + String(e));
|
|
26385
26759
|
});
|
|
26386
|
-
}
|
|
26760
|
+
}
|
|
26387
26761
|
/** @private @author ddj 2026年10月14号 @param group Group id. @param path Optional selection. Route global actions only to this group. */
|
|
26388
26762
|
function selectGroup(group, path) {
|
|
26389
26763
|
saveViewState();
|
|
@@ -26565,9 +26939,21 @@ window.__ModuleLoader__.load({
|
|
|
26565
26939
|
host.removeEventListener("contextmenu", onCtx);
|
|
26566
26940
|
};
|
|
26567
26941
|
}
|
|
26942
|
+
/** @private @author ddj 2026年10月22号 @param args Read-only page request. @returns Current Host capability result. */
|
|
26943
|
+
function loadTextPage(args) {
|
|
26944
|
+
return rpc("edrv.textPage", args);
|
|
26945
|
+
}
|
|
26946
|
+
/** @private @author ddj 2026年10月22号 @description Never replace a dirty or saving document with partial text. */
|
|
26947
|
+
function openTextPages() {
|
|
26948
|
+
if (largeCandidate !== pageIdentity || dirtyRef.current[active] || savingRef.current.has(active)) return;
|
|
26949
|
+
flushSave();
|
|
26950
|
+
if (dirtyRef.current[active] || savingRef.current.has(active)) return;
|
|
26951
|
+
setPageChanged(null);
|
|
26952
|
+
setPagedFile(pageIdentity);
|
|
26953
|
+
}
|
|
26568
26954
|
/** @private @author ddj 2026年10月16号 @param host Passive body. @param path Canonical file. @param groupId Owning group id(find 快照按组隔离). @returns View-only cleanup, models remain workbench-owned. */
|
|
26569
26955
|
function mountPassive(host, path, groupId) {
|
|
26570
|
-
let disposed = false, keeper = null, subscription = null, observer = null;
|
|
26956
|
+
let disposed = false, keeper = null, subscription = null, observer = null, pageRoot = null;
|
|
26571
26957
|
const focus = () => {
|
|
26572
26958
|
const owner = ownerOf(benchRef.current, path);
|
|
26573
26959
|
if (owner) selectGroup(owner.id, path);
|
|
@@ -26594,6 +26980,27 @@ window.__ModuleLoader__.load({
|
|
|
26594
26980
|
host.textContent = "";
|
|
26595
26981
|
if (!result?.ok) {
|
|
26596
26982
|
host.textContent = result?.error || "文件加载失败";
|
|
26983
|
+
if (result?.code === "file-too-large" && !binary) {
|
|
26984
|
+
const button = document.createElement("button");
|
|
26985
|
+
button.textContent = "只读分段查看";
|
|
26986
|
+
/** @author ddj 2026年10月22号 @param event Pointer event. @description Do not focus and unmount the passive group before click. */
|
|
26987
|
+
button.onpointerdown = (event) => event.stopPropagation();
|
|
26988
|
+
/** @author ddj 2026年10月22号 @description Keep partial text out of passive models, autosave and editing commands. */
|
|
26989
|
+
button.onclick = () => {
|
|
26990
|
+
if (disposed || dirtyRef.current[path] || savingRef.current.has(path)) return;
|
|
26991
|
+
flushSave();
|
|
26992
|
+
if (dirtyRef.current[path] || savingRef.current.has(path)) return;
|
|
26993
|
+
host.textContent = "";
|
|
26994
|
+
host.removeEventListener("pointerdown", focus);
|
|
26995
|
+
pageRoot = (0, react_dom_client.createRoot)(host);
|
|
26996
|
+
pageRoot.render(react.default.createElement(LargeTextView, {
|
|
26997
|
+
sessionId,
|
|
26998
|
+
path,
|
|
26999
|
+
loadPage: loadTextPage
|
|
27000
|
+
}));
|
|
27001
|
+
};
|
|
27002
|
+
host.appendChild(button);
|
|
27003
|
+
}
|
|
26597
27004
|
return;
|
|
26598
27005
|
}
|
|
26599
27006
|
if (binary) {
|
|
@@ -26644,6 +27051,7 @@ window.__ModuleLoader__.load({
|
|
|
26644
27051
|
});
|
|
26645
27052
|
return () => {
|
|
26646
27053
|
disposed = true;
|
|
27054
|
+
pageRoot?.unmount();
|
|
26647
27055
|
host.removeEventListener("pointerdown", focus);
|
|
26648
27056
|
observer?.disconnect();
|
|
26649
27057
|
subscription?.dispose();
|
|
@@ -26705,7 +27113,11 @@ window.__ModuleLoader__.load({
|
|
|
26705
27113
|
path: group.active,
|
|
26706
27114
|
onFocus: () => selectGroup(id)
|
|
26707
27115
|
}), react.default.createElement(PassiveEditor, {
|
|
26708
|
-
key:
|
|
27116
|
+
key: JSON.stringify([
|
|
27117
|
+
scope,
|
|
27118
|
+
sessionId,
|
|
27119
|
+
group.active
|
|
27120
|
+
]),
|
|
26709
27121
|
path: group.active,
|
|
26710
27122
|
groupId: id,
|
|
26711
27123
|
mount: passiveMount
|
|
@@ -26931,7 +27343,20 @@ window.__ModuleLoader__.load({
|
|
|
26931
27343
|
ref: planHostRef,
|
|
26932
27344
|
"data-plan-address": activePlan.address
|
|
26933
27345
|
}, react.default.createElement("div", { className: "edrv-mdview-stage" }, react.default.createElement("div", { className: "edrv-mdview-doc" }, render)));
|
|
26934
|
-
} else if (
|
|
27346
|
+
} else if (pageChanged === pageIdentity && largeCandidate === pageIdentity) body = react.default.createElement("div", {
|
|
27347
|
+
className: "edrv-empty",
|
|
27348
|
+
role: "status"
|
|
27349
|
+
}, react.default.createElement("div", null, "文件已变化,请重新读取"), react.default.createElement("button", {
|
|
27350
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
27351
|
+
onClick: openTextPages
|
|
27352
|
+
}, "重新读取首段"));
|
|
27353
|
+
else if (paging) body = react.default.createElement(LargeTextView, {
|
|
27354
|
+
key: pageIdentity,
|
|
27355
|
+
sessionId,
|
|
27356
|
+
path: active,
|
|
27357
|
+
loadPage: loadTextPage
|
|
27358
|
+
});
|
|
27359
|
+
else if (!monaco && !monacoErr) body = loadingBody(loadStage.message, loadStage.progress);
|
|
26935
27360
|
else if (monacoErr) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "Monaco 编辑器加载失败:" + String(monacoErr)), react.default.createElement("div", { style: { fontSize: 11 } }, "请确认插件包 assets/vendor/monaco 完整(/edrv/vendor 路由可达)"), react.default.createElement("button", {
|
|
26936
27361
|
className: "edrv-pill edrv-pill-ghost",
|
|
26937
27362
|
onClick: () => {
|
|
@@ -26963,7 +27388,7 @@ window.__ModuleLoader__.load({
|
|
|
26963
27388
|
loadContent(active, sessionId);
|
|
26964
27389
|
}
|
|
26965
27390
|
}, "重试"));
|
|
26966
|
-
else if (content === null && loadError) body = loadingBody("文件加载失败:" + loadError, 0, () => {
|
|
27391
|
+
else if (content === null && loadError) body = react.default.createElement(react.default.Fragment, null, loadingBody("文件加载失败:" + loadError, 0, () => {
|
|
26967
27392
|
setLoadError(null);
|
|
26968
27393
|
setContent(null);
|
|
26969
27394
|
setContentPath(null);
|
|
@@ -26972,7 +27397,10 @@ window.__ModuleLoader__.load({
|
|
|
26972
27397
|
message: "重新读取文件…"
|
|
26973
27398
|
});
|
|
26974
27399
|
loadContent(active, sessionId);
|
|
26975
|
-
})
|
|
27400
|
+
}), largeCandidate === pageIdentity && react.default.createElement("button", {
|
|
27401
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
27402
|
+
onClick: openTextPages
|
|
27403
|
+
}, "只读分段查看"));
|
|
26976
27404
|
else if (isImageActive && imageSrc) body = imagePanel();
|
|
26977
27405
|
else if (isImageActive) body = loadingBody(loadStage.message || "读取图片…", loadStage.progress);
|
|
26978
27406
|
else if (isPdfActive && pdfBytes) body = react.default.createElement("div", {
|
|
@@ -28927,7 +29355,7 @@ window.__ModuleLoader__.load({
|
|
|
28927
29355
|
if (hasStoredConfig(config[status.languageId])) return true;
|
|
28928
29356
|
return Array.isArray(status.missingEnv) && status.missingEnv.length > 0;
|
|
28929
29357
|
}
|
|
28930
|
-
const PHASE_LABEL
|
|
29358
|
+
const PHASE_LABEL = {
|
|
28931
29359
|
idle: "未启动",
|
|
28932
29360
|
starting: "启动中",
|
|
28933
29361
|
ready: "就绪",
|
|
@@ -28981,7 +29409,7 @@ window.__ModuleLoader__.load({
|
|
|
28981
29409
|
className: "vsm-switch " + (config?.enabled !== false ? "on" : ""),
|
|
28982
29410
|
onClick: () => onToggle(lang.id, config?.enabled !== false ? false : true),
|
|
28983
29411
|
"aria-label": "启用/禁用"
|
|
28984
|
-
}, config?.enabled !== false ? "●" : "○"))), react.default.createElement("div", { className: "vsm-mcp-meta" }, PHASE_LABEL
|
|
29412
|
+
}, config?.enabled !== false ? "●" : "○"))), react.default.createElement("div", { className: "vsm-mcp-meta" }, PHASE_LABEL[phase] ?? phase, " · ", SOURCE_LABEL[status?.source] ?? status?.source, status?.providerName ? " · " + status.providerName : "", status?.version ? " · v" + status.version : "", phase === "ready" && status?.root ? " · " + String(status.root).split(/[\\/]/).pop() : ""), status?.reason ? react.default.createElement("div", { className: "vsm-mcp-error" }, status.reason) : null, Array.isArray(status?.candidates) && status.candidates.length > 1 ? react.default.createElement("div", { className: "vsm-lsp-hint" }, "候选(" + status.candidates.length + "):" + status.candidates.map((c) => c.name + (c.version ? " v" + c.version : "") + (c.chosen ? "(当前)" : "")).join(" · ")) : null, Array.isArray(status?.missingEnv) && status.missingEnv.length ? react.default.createElement("div", { className: "vsm-lsp-hint" }, "缺少运行环境(一键安装后自动生效):", status.missingEnv.map((req) => react.default.createElement("div", {
|
|
28985
29413
|
key: req.id,
|
|
28986
29414
|
className: "vsm-mcp-actions"
|
|
28987
29415
|
}, react.default.createElement("span", null, req.label, req.detail ? "(" + req.detail + ")" : ""), req.installable ? react.default.createElement("button", {
|
|
@@ -32315,8 +32743,11 @@ window.__ModuleLoader__.load({
|
|
|
32315
32743
|
function createSidebarPanelRegistry() {
|
|
32316
32744
|
const entries = /* @__PURE__ */ new Map();
|
|
32317
32745
|
const listeners = /* @__PURE__ */ new Set();
|
|
32746
|
+
/** @private @author ddj 2026年10月22号 @description Isolate subscribers and snapshot notification membership against reentrant changes. */
|
|
32318
32747
|
const notify = () => {
|
|
32319
|
-
for (const listener of listeners)
|
|
32748
|
+
for (const listener of [...listeners]) try {
|
|
32749
|
+
listener();
|
|
32750
|
+
} catch {}
|
|
32320
32751
|
};
|
|
32321
32752
|
const list = () => [...entries.values()].sort((a, b) => (a.order ?? 100) - (b.order ?? 100));
|
|
32322
32753
|
return {
|
|
@@ -32432,7 +32863,7 @@ window.__ModuleLoader__.load({
|
|
|
32432
32863
|
* 作者 ddj 2026-08-28
|
|
32433
32864
|
*/
|
|
32434
32865
|
/** localStorage 键前缀(按工作区作用域隔离,无 cwd 会话回退会话键)。 */
|
|
32435
|
-
const KEY_PREFIX$
|
|
32866
|
+
const KEY_PREFIX$1 = CACHE_KEY.expanded;
|
|
32436
32867
|
/**
|
|
32437
32868
|
* 归一化展开路径:去空白、反斜杠→斜杠、去首尾斜杠,`..` 段拒绝。
|
|
32438
32869
|
* @author ddj 2026年08月28号
|
|
@@ -32510,7 +32941,7 @@ window.__ModuleLoader__.load({
|
|
|
32510
32941
|
*/
|
|
32511
32942
|
function explorerLoad(scope) {
|
|
32512
32943
|
try {
|
|
32513
|
-
return parseExplorer(window.localStorage.getItem(KEY_PREFIX$
|
|
32944
|
+
return parseExplorer(window.localStorage.getItem(KEY_PREFIX$1 + String(scope)));
|
|
32514
32945
|
} catch (error) {
|
|
32515
32946
|
return null;
|
|
32516
32947
|
}
|
|
@@ -32523,12 +32954,12 @@ window.__ModuleLoader__.load({
|
|
|
32523
32954
|
*/
|
|
32524
32955
|
function explorerSave(scope, data) {
|
|
32525
32956
|
try {
|
|
32526
|
-
window.localStorage.setItem(KEY_PREFIX$
|
|
32957
|
+
window.localStorage.setItem(KEY_PREFIX$1 + String(scope), serializeExplorer(data));
|
|
32527
32958
|
} catch (error) {}
|
|
32528
32959
|
}
|
|
32529
32960
|
//#endregion
|
|
32530
32961
|
//#region src/client/state/explorerEntriesCache.ts
|
|
32531
|
-
const KEY_PREFIX
|
|
32962
|
+
const KEY_PREFIX = CACHE_KEY.entries;
|
|
32532
32963
|
/** 裁剪到上限(目录按 ts 逐出最旧;单目录条目截断)。 */
|
|
32533
32964
|
function entriesTrim(data, maxDirs = 300, maxEntries = 500) {
|
|
32534
32965
|
const dirs = {};
|
|
@@ -32602,7 +33033,7 @@ window.__ModuleLoader__.load({
|
|
|
32602
33033
|
/** localStorage 读取(不可用 → null)。 */
|
|
32603
33034
|
function readRaw(scope) {
|
|
32604
33035
|
try {
|
|
32605
|
-
return window.localStorage.getItem(KEY_PREFIX
|
|
33036
|
+
return window.localStorage.getItem(KEY_PREFIX + scope);
|
|
32606
33037
|
} catch (error) {
|
|
32607
33038
|
return null;
|
|
32608
33039
|
}
|
|
@@ -32610,7 +33041,7 @@ window.__ModuleLoader__.load({
|
|
|
32610
33041
|
/** localStorage 写入(配额/隐私模式失败静默)。 */
|
|
32611
33042
|
function writeRaw(scope, text) {
|
|
32612
33043
|
try {
|
|
32613
|
-
window.localStorage.setItem(KEY_PREFIX
|
|
33044
|
+
window.localStorage.setItem(KEY_PREFIX + scope, text);
|
|
32614
33045
|
} catch (error) {}
|
|
32615
33046
|
}
|
|
32616
33047
|
/** 取(或建)作用域缓存镜像。 */
|
|
@@ -33230,12 +33661,12 @@ window.__ModuleLoader__.load({
|
|
|
33230
33661
|
setTarget(next);
|
|
33231
33662
|
if (next) current.prepare(next.path);
|
|
33232
33663
|
}
|
|
33233
|
-
/** @private @author ddj 2026年10月
|
|
33664
|
+
/** @private @author ddj 2026年10月22号 Attempts virtual data-index location or the original mounted-row fallback after commit/resize; consumes only a successful current request. */
|
|
33234
33665
|
function tryReveal() {
|
|
33235
33666
|
const next = pending.current;
|
|
33236
33667
|
const current = latest.current;
|
|
33237
33668
|
if (!next || next.scope !== current.scope || next.active !== current.activePath) return;
|
|
33238
|
-
if (!revealTreeRow(current.treeRef.current, next.path)) return;
|
|
33669
|
+
if (!(current.locate ? current.locate(next.path) : revealTreeRow(current.treeRef.current, next.path))) return;
|
|
33239
33670
|
pending.current = null;
|
|
33240
33671
|
setRevealPath(next.path);
|
|
33241
33672
|
clearHighlight();
|
|
@@ -33278,6 +33709,106 @@ window.__ModuleLoader__.load({
|
|
|
33278
33709
|
requestReveal
|
|
33279
33710
|
};
|
|
33280
33711
|
}
|
|
33712
|
+
/**
|
|
33713
|
+
* @public @author ddj 2026年10月22号
|
|
33714
|
+
* @description Preserve the first visible path when rows above it expand or collapse.
|
|
33715
|
+
* @param previous Previous complete model.
|
|
33716
|
+
* @param rows New complete model.
|
|
33717
|
+
* @param top Previous scroll offset.
|
|
33718
|
+
* @returns Anchored offset, or original offset for subsequent clamping if path disappeared.
|
|
33719
|
+
*/
|
|
33720
|
+
function treeAnchorTop(previous, rows, top) {
|
|
33721
|
+
const anchor = previous[Math.floor(Math.max(0, top) / 24)]?.key;
|
|
33722
|
+
if (!anchor) return top;
|
|
33723
|
+
const nextIndex = rows.findIndex((row) => row.key === anchor);
|
|
33724
|
+
if (nextIndex < 0) return top;
|
|
33725
|
+
return nextIndex * 24 + top % 24;
|
|
33726
|
+
}
|
|
33727
|
+
/**
|
|
33728
|
+
* @public @author ddj 2026年10月22号
|
|
33729
|
+
* @description Flatten all expanded entries in their supplied order, including metadata files.
|
|
33730
|
+
* @param entriesOf Directory snapshot lookup; null means unavailable.
|
|
33731
|
+
* @param expanded Current directory expansion flags.
|
|
33732
|
+
* @param loading Current loading flags.
|
|
33733
|
+
* @returns Complete row model, independent of viewport mounting.
|
|
33734
|
+
*/
|
|
33735
|
+
function flattenTree(entriesOf, expanded, loading) {
|
|
33736
|
+
const rows = [];
|
|
33737
|
+
const pending = [{
|
|
33738
|
+
rel: "",
|
|
33739
|
+
depth: 0
|
|
33740
|
+
}];
|
|
33741
|
+
while (pending.length) {
|
|
33742
|
+
const current = pending.pop();
|
|
33743
|
+
const entry = current.entry;
|
|
33744
|
+
if (entry) {
|
|
33745
|
+
const isDir = entry.type === "directory";
|
|
33746
|
+
const isOpen = expanded[entry.path] === true;
|
|
33747
|
+
rows.push({
|
|
33748
|
+
key: entry.path,
|
|
33749
|
+
e: entry,
|
|
33750
|
+
depth: current.depth,
|
|
33751
|
+
isDir,
|
|
33752
|
+
isOpen
|
|
33753
|
+
});
|
|
33754
|
+
if (isDir && isOpen) pending.push({
|
|
33755
|
+
rel: entry.path,
|
|
33756
|
+
depth: current.depth + 1
|
|
33757
|
+
});
|
|
33758
|
+
continue;
|
|
33759
|
+
}
|
|
33760
|
+
const entries = entriesOf(current.rel);
|
|
33761
|
+
if (!entries) {
|
|
33762
|
+
rows.push({
|
|
33763
|
+
key: current.rel + ":loading",
|
|
33764
|
+
depth: current.depth,
|
|
33765
|
+
text: loading[current.rel] ? "加载中…" : "无法加载"
|
|
33766
|
+
});
|
|
33767
|
+
continue;
|
|
33768
|
+
}
|
|
33769
|
+
for (let index = entries.length - 1; index >= 0; index--) pending.push({
|
|
33770
|
+
rel: current.rel,
|
|
33771
|
+
depth: current.depth,
|
|
33772
|
+
entry: entries[index]
|
|
33773
|
+
});
|
|
33774
|
+
}
|
|
33775
|
+
return rows;
|
|
33776
|
+
}
|
|
33777
|
+
/**
|
|
33778
|
+
* @public @author ddj 2026年10月22号
|
|
33779
|
+
* @description Clamp scroll state before reusing the existing fixed-height range calculation.
|
|
33780
|
+
* @param count Complete row count.
|
|
33781
|
+
* @param viewport Latest scroll position and measured viewport height.
|
|
33782
|
+
* @returns Clamped scroll offset and overscanned exclusive row range.
|
|
33783
|
+
*/
|
|
33784
|
+
function treeWindow(count, viewport) {
|
|
33785
|
+
const height = Math.max(0, viewport.height);
|
|
33786
|
+
const top = Math.min(Math.max(0, viewport.top), Math.max(0, count * 24 - height));
|
|
33787
|
+
return {
|
|
33788
|
+
top,
|
|
33789
|
+
...updateRange(count, top, height, 24)
|
|
33790
|
+
};
|
|
33791
|
+
}
|
|
33792
|
+
/**
|
|
33793
|
+
* @public @author ddj 2026年10月22号
|
|
33794
|
+
* @description Locate an unmounted row using model indices, without querying row DOM.
|
|
33795
|
+
* @param rows Complete flattened model.
|
|
33796
|
+
* @param path Requested relative file path.
|
|
33797
|
+
* @param viewport Current viewport geometry.
|
|
33798
|
+
* @returns New scroll offset, or null while ancestors/viewport are unavailable.
|
|
33799
|
+
*/
|
|
33800
|
+
function treeRevealTop(rows, path, viewport) {
|
|
33801
|
+
if (viewport.height <= 0) return null;
|
|
33802
|
+
const index = rows.findIndex((row) => row.e?.path === path);
|
|
33803
|
+
if (index < 0) return null;
|
|
33804
|
+
const current = treeWindow(rows.length, viewport).top;
|
|
33805
|
+
const rowTop = index * 24;
|
|
33806
|
+
if (rowTop >= current && rowTop + 24 <= current + viewport.height) return current;
|
|
33807
|
+
return treeWindow(rows.length, {
|
|
33808
|
+
top: rowTop - (viewport.height - 24) / 2,
|
|
33809
|
+
height: viewport.height
|
|
33810
|
+
}).top;
|
|
33811
|
+
}
|
|
33281
33812
|
//#endregion
|
|
33282
33813
|
//#region src/client/sidebar/panels/FileExplorer.ts
|
|
33283
33814
|
/**
|
|
@@ -33291,7 +33822,6 @@ window.__ModuleLoader__.load({
|
|
|
33291
33822
|
* 远端更新箭头由显式只读检查提供,与本地状态并存,不执行更新。
|
|
33292
33823
|
* 作者 ddj 2026-08-26 / 2026-08-27 / 2026-08-31 / 2026-09-10 / 2026-09-16 / 2026-10-09
|
|
33293
33824
|
*/
|
|
33294
|
-
const DIR_CAP = 4e3;
|
|
33295
33825
|
const SAVE_DEBOUNCE_MS = 300;
|
|
33296
33826
|
const FOLLOW_INTERVAL_MS = 1e4;
|
|
33297
33827
|
const PREFETCH_MAX = 4;
|
|
@@ -33390,6 +33920,11 @@ window.__ModuleLoader__.load({
|
|
|
33390
33920
|
const loadDirRef = react.default.useRef(null);
|
|
33391
33921
|
const refreshRef = react.default.useRef(null);
|
|
33392
33922
|
const treeRef = react.default.useRef(null);
|
|
33923
|
+
const [viewport, setViewport] = react.default.useState({
|
|
33924
|
+
scope,
|
|
33925
|
+
top: 0,
|
|
33926
|
+
height: 0
|
|
33927
|
+
});
|
|
33393
33928
|
const reloadDirRef = react.default.useRef(null);
|
|
33394
33929
|
const changedTimerRef = react.default.useRef(null);
|
|
33395
33930
|
const changedRelRef = react.default.useRef(/* @__PURE__ */ new Set());
|
|
@@ -33596,12 +34131,6 @@ window.__ModuleLoader__.load({
|
|
|
33596
34131
|
window.addEventListener("edrv:refresh", onRefresh);
|
|
33597
34132
|
return () => window.removeEventListener("edrv:refresh", onRefresh);
|
|
33598
34133
|
}, []);
|
|
33599
|
-
const { revealPath } = useExplorerReveal({
|
|
33600
|
-
scope,
|
|
33601
|
-
activePath,
|
|
33602
|
-
treeRef,
|
|
33603
|
-
prepare: prepareReveal
|
|
33604
|
-
});
|
|
33605
34134
|
const activeTreePath = treeRevealPath(activePath);
|
|
33606
34135
|
react.default.useEffect(() => {
|
|
33607
34136
|
if (!scope) return;
|
|
@@ -33613,39 +34142,9 @@ window.__ModuleLoader__.load({
|
|
|
33613
34142
|
}, FOLLOW_INTERVAL_MS);
|
|
33614
34143
|
return () => clearInterval(timer);
|
|
33615
34144
|
}, [scope]);
|
|
33616
|
-
/** @private @author ddj 2026年10月
|
|
34145
|
+
/** @private @author ddj 2026年10月22号 @returns Complete expanded model; icon-only updates do not flatten again. */
|
|
33617
34146
|
function flatten() {
|
|
33618
|
-
|
|
33619
|
-
/** @private @author ddj 2026年10月10号 @param rel Directory. @param depth Indent level. Appends only expanded rows and placeholders. */
|
|
33620
|
-
function visit(rel, depth) {
|
|
33621
|
-
const entries = dirs[rel] ?? entriesCacheGet(scope, rel);
|
|
33622
|
-
if (!entries) {
|
|
33623
|
-
result.push({
|
|
33624
|
-
key: rel + ":loading",
|
|
33625
|
-
depth,
|
|
33626
|
-
text: loading[rel] ? "加载中…" : "无法加载"
|
|
33627
|
-
});
|
|
33628
|
-
return;
|
|
33629
|
-
}
|
|
33630
|
-
for (const e of entries) {
|
|
33631
|
-
const isDir = e.type === "directory", isOpen = expanded[e.path] === true;
|
|
33632
|
-
result.push({
|
|
33633
|
-
key: e.path,
|
|
33634
|
-
e,
|
|
33635
|
-
depth,
|
|
33636
|
-
isDir,
|
|
33637
|
-
isOpen
|
|
33638
|
-
});
|
|
33639
|
-
if (isDir && isOpen) visit(e.path, depth + 1);
|
|
33640
|
-
}
|
|
33641
|
-
if (entries.length >= DIR_CAP) result.push({
|
|
33642
|
-
key: rel + ":cap",
|
|
33643
|
-
depth,
|
|
33644
|
-
text: "目录条目过多,仅显示前 4000 项"
|
|
33645
|
-
});
|
|
33646
|
-
}
|
|
33647
|
-
visit("", 0);
|
|
33648
|
-
return result;
|
|
34147
|
+
return flattenTree(entriesOf, expanded, loading);
|
|
33649
34148
|
}
|
|
33650
34149
|
const treeRows = react.default.useMemo(flatten, [
|
|
33651
34150
|
dirs,
|
|
@@ -33653,6 +34152,99 @@ window.__ModuleLoader__.load({
|
|
|
33653
34152
|
loading,
|
|
33654
34153
|
scope
|
|
33655
34154
|
]);
|
|
34155
|
+
const previousRows = react.default.useRef({
|
|
34156
|
+
scope,
|
|
34157
|
+
rows: treeRows
|
|
34158
|
+
});
|
|
34159
|
+
let anchoredTop = 0;
|
|
34160
|
+
if (viewport.scope === scope) {
|
|
34161
|
+
anchoredTop = viewport.top;
|
|
34162
|
+
if (previousRows.current.scope === scope && previousRows.current.rows !== treeRows) anchoredTop = treeAnchorTop(previousRows.current.rows, treeRows, viewport.top);
|
|
34163
|
+
}
|
|
34164
|
+
const currentViewport = {
|
|
34165
|
+
top: anchoredTop,
|
|
34166
|
+
height: viewport.height
|
|
34167
|
+
};
|
|
34168
|
+
const windowRows = treeWindow(treeRows.length, currentViewport);
|
|
34169
|
+
/** @private @author ddj 2026年10月22号 Read current geometry after scroll, resize or scope restoration. */
|
|
34170
|
+
function measureTree() {
|
|
34171
|
+
const host = treeRef.current;
|
|
34172
|
+
if (!host || host.clientHeight <= 0) return;
|
|
34173
|
+
setViewport({
|
|
34174
|
+
scope,
|
|
34175
|
+
top: host.scrollTop,
|
|
34176
|
+
height: host.clientHeight
|
|
34177
|
+
});
|
|
34178
|
+
}
|
|
34179
|
+
const scrollFrame = react.default.useRef(null);
|
|
34180
|
+
/** @private @author ddj 2026年10月22号 Coalesce high-frequency scrolling into one measured render per frame. */
|
|
34181
|
+
function scrollTree() {
|
|
34182
|
+
if (scrollFrame.current !== null) return;
|
|
34183
|
+
scrollFrame.current = requestAnimationFrame(readScroll);
|
|
34184
|
+
}
|
|
34185
|
+
/** @private @author ddj 2026年10月22号 Read only after the pending animation frame fires. */
|
|
34186
|
+
function readScroll() {
|
|
34187
|
+
scrollFrame.current = null;
|
|
34188
|
+
measureTree();
|
|
34189
|
+
}
|
|
34190
|
+
/** @private @author ddj 2026年10月22号 @returns Resize observer and pending frame cleanup. Keep hidden trees measurable when shown. */
|
|
34191
|
+
function watchTree() {
|
|
34192
|
+
const observer = typeof ResizeObserver === "function" ? new ResizeObserver(measureTree) : null;
|
|
34193
|
+
if (treeRef.current) observer?.observe(treeRef.current);
|
|
34194
|
+
measureTree();
|
|
34195
|
+
/** @private @author ddj 2026年10月22号 Stop all viewport callbacks owned by this scope. */
|
|
34196
|
+
function cleanup() {
|
|
34197
|
+
observer?.disconnect();
|
|
34198
|
+
if (scrollFrame.current !== null) cancelAnimationFrame(scrollFrame.current);
|
|
34199
|
+
scrollFrame.current = null;
|
|
34200
|
+
}
|
|
34201
|
+
return cleanup;
|
|
34202
|
+
}
|
|
34203
|
+
react.default.useLayoutEffect(watchTree, [scope]);
|
|
34204
|
+
/** @private @author ddj 2026年10月22号 Clamp actual scroll after collapse, filtering, or workspace switch. */
|
|
34205
|
+
function clampTree() {
|
|
34206
|
+
const host = treeRef.current;
|
|
34207
|
+
previousRows.current = {
|
|
34208
|
+
scope,
|
|
34209
|
+
rows: treeRows
|
|
34210
|
+
};
|
|
34211
|
+
if (!host || host.clientHeight <= 0) return;
|
|
34212
|
+
if (host.scrollTop !== windowRows.top) host.scrollTop = windowRows.top;
|
|
34213
|
+
if (viewport.scope !== scope || viewport.top !== windowRows.top) setViewport({
|
|
34214
|
+
scope,
|
|
34215
|
+
top: windowRows.top,
|
|
34216
|
+
height: host.clientHeight
|
|
34217
|
+
});
|
|
34218
|
+
}
|
|
34219
|
+
react.default.useLayoutEffect(clampTree, [
|
|
34220
|
+
scope,
|
|
34221
|
+
windowRows.top,
|
|
34222
|
+
treeRows
|
|
34223
|
+
]);
|
|
34224
|
+
/** @private @author ddj 2026年10月22号 @param path Requested file. @returns Whether its complete model row is available. */
|
|
34225
|
+
function locateTree(path) {
|
|
34226
|
+
const host = treeRef.current;
|
|
34227
|
+
if (!host) return false;
|
|
34228
|
+
const top = treeRevealTop(treeRows, path, {
|
|
34229
|
+
top: host.scrollTop,
|
|
34230
|
+
height: host.clientHeight
|
|
34231
|
+
});
|
|
34232
|
+
if (top === null) return false;
|
|
34233
|
+
host.scrollTop = top;
|
|
34234
|
+
setViewport({
|
|
34235
|
+
scope,
|
|
34236
|
+
top,
|
|
34237
|
+
height: host.clientHeight
|
|
34238
|
+
});
|
|
34239
|
+
return true;
|
|
34240
|
+
}
|
|
34241
|
+
const { revealPath } = useExplorerReveal({
|
|
34242
|
+
scope,
|
|
34243
|
+
activePath,
|
|
34244
|
+
treeRef,
|
|
34245
|
+
prepare: prepareReveal,
|
|
34246
|
+
locate: locateTree
|
|
34247
|
+
});
|
|
33656
34248
|
/** @private @author ddj 2026年10月10号 @returns Stable RPC row projection, independent of icon-only renders. */
|
|
33657
34249
|
function projectRows() {
|
|
33658
34250
|
return treeRows.filter((row) => row.e).map((row) => ({
|
|
@@ -33673,6 +34265,7 @@ window.__ModuleLoader__.load({
|
|
|
33673
34265
|
event.preventDefault();
|
|
33674
34266
|
event.stopPropagation();
|
|
33675
34267
|
setMenu({
|
|
34268
|
+
scope,
|
|
33676
34269
|
x: event.clientX,
|
|
33677
34270
|
y: event.clientY,
|
|
33678
34271
|
target: {
|
|
@@ -33682,7 +34275,7 @@ window.__ModuleLoader__.load({
|
|
|
33682
34275
|
});
|
|
33683
34276
|
}
|
|
33684
34277
|
const onSelect = react.default.useCallback((path, isDir) => selectRef.current(path, isDir), []);
|
|
33685
|
-
const onContext = react.default.useCallback(contextRow, []);
|
|
34278
|
+
const onContext = react.default.useCallback(contextRow, [scope]);
|
|
33686
34279
|
const rootName = root ? String(root).split(/[\\/]/).pop() || root : "";
|
|
33687
34280
|
/** @private @author ddj 2026年10月10号 @param row Flat descriptor. @returns Memo row; unaffected status objects retain identity. */
|
|
33688
34281
|
function renderRow(row) {
|
|
@@ -33715,6 +34308,7 @@ window.__ModuleLoader__.load({
|
|
|
33715
34308
|
ev.stopPropagation();
|
|
33716
34309
|
if (!ev.currentTarget.contains(ev.target)) return;
|
|
33717
34310
|
setMenu({
|
|
34311
|
+
scope,
|
|
33718
34312
|
x: ev.clientX,
|
|
33719
34313
|
y: ev.clientY,
|
|
33720
34314
|
target: {
|
|
@@ -33723,7 +34317,13 @@ window.__ModuleLoader__.load({
|
|
|
33723
34317
|
}
|
|
33724
34318
|
});
|
|
33725
34319
|
};
|
|
33726
|
-
const
|
|
34320
|
+
const menuValid = menu?.scope === scope && (menu.target.path === "" || treeRows.some((row) => row.e?.path === menu.target.path));
|
|
34321
|
+
/** @private @author ddj 2026年10月22号 Close stale path menus instead of rebinding recycled rows. */
|
|
34322
|
+
function closeLostMenu() {
|
|
34323
|
+
if (menu && !menuValid) setMenu(null);
|
|
34324
|
+
}
|
|
34325
|
+
react.default.useEffect(closeLostMenu, [menu, menuValid]);
|
|
34326
|
+
const menuEntries = menuValid ? buildTreeMenu(ctx?.fileMenuItems, menu.target, ctx).map((item) => ({
|
|
33727
34327
|
id: item.id,
|
|
33728
34328
|
label: item.label,
|
|
33729
34329
|
danger: item.danger,
|
|
@@ -33763,16 +34363,23 @@ window.__ModuleLoader__.load({
|
|
|
33763
34363
|
}, refreshIconEl$1())), svn.message ? react.default.createElement("div", {
|
|
33764
34364
|
className: "edrv-tree-status",
|
|
33765
34365
|
role: "status"
|
|
33766
|
-
}, svn.message) : null, react.default.createElement("div", {
|
|
33767
|
-
className: "edrv-tree",
|
|
33768
|
-
ref: treeRef
|
|
33769
|
-
}, errorText ? react.default.createElement("div", { className: "edrv-tree-error" }, react.default.createElement("span", null, String(errorText)), react.default.createElement("button", {
|
|
34366
|
+
}, svn.message) : null, errorText ? react.default.createElement("div", { className: "edrv-tree-error" }, react.default.createElement("span", null, String(errorText)), react.default.createElement("button", {
|
|
33770
34367
|
className: "edrv-side-btn",
|
|
33771
34368
|
onClick: () => emitRefresh({
|
|
33772
34369
|
scope,
|
|
33773
34370
|
kind: "unknown"
|
|
33774
34371
|
})
|
|
33775
|
-
}, "重试")) : null,
|
|
34372
|
+
}, "重试")) : null, react.default.createElement("div", {
|
|
34373
|
+
className: "edrv-tree edrv-tree-virtual",
|
|
34374
|
+
ref: treeRef,
|
|
34375
|
+
onScroll: scrollTree
|
|
34376
|
+
}, react.default.createElement("div", {
|
|
34377
|
+
"aria-hidden": true,
|
|
34378
|
+
style: { height: windowRows.start * 24 }
|
|
34379
|
+
}), treeRows.slice(windowRows.start, windowRows.end).map(renderRow), react.default.createElement("div", {
|
|
34380
|
+
"aria-hidden": true,
|
|
34381
|
+
style: { height: (treeRows.length - windowRows.end) * 24 }
|
|
34382
|
+
})), menu && menuEntries.length ? react.default.createElement(ContextMenu, {
|
|
33776
34383
|
x: menu.x,
|
|
33777
34384
|
y: menu.y,
|
|
33778
34385
|
entries: menuEntries,
|
|
@@ -34267,713 +34874,79 @@ window.__ModuleLoader__.load({
|
|
|
34267
34874
|
})), optsBar, filterRows, summary, warnBanner, body);
|
|
34268
34875
|
}
|
|
34269
34876
|
//#endregion
|
|
34270
|
-
//#region src/client/
|
|
34271
|
-
/**
|
|
34272
|
-
|
|
34273
|
-
|
|
34274
|
-
|
|
34275
|
-
* @returns 去引号后的值
|
|
34276
|
-
*/
|
|
34277
|
-
function stripQuotes(raw) {
|
|
34278
|
-
const value = raw.trim();
|
|
34279
|
-
if (value.length >= 2 && (value.startsWith("\"") && value.endsWith("\"") || value.startsWith("'") && value.endsWith("'"))) return value.slice(1, -1);
|
|
34280
|
-
return value;
|
|
34281
|
-
}
|
|
34282
|
-
/**
|
|
34283
|
-
* 解析 .mdc 全文:首行 --- 且 100 行内有闭合 --- 才视为 frontmatter;
|
|
34284
|
-
* 已知键 description/alwaysApply/globs/enabled,其余原行进 fmExtra;永不抛错。
|
|
34285
|
-
* @author ddj 2026年09月07号
|
|
34286
|
-
* @param text 文件全文
|
|
34287
|
-
* @returns 解析结果
|
|
34288
|
-
*/
|
|
34289
|
-
function parseRuleFm(text) {
|
|
34290
|
-
const bom = text.startsWith("");
|
|
34291
|
-
const lines = text.replace(/^\uFEFF/, "").split(/\r?\n/);
|
|
34292
|
-
const none = {
|
|
34293
|
-
type: "manual",
|
|
34294
|
-
description: "",
|
|
34295
|
-
alwaysApply: false,
|
|
34296
|
-
globs: [],
|
|
34297
|
-
enabled: true,
|
|
34298
|
-
hasFm: false,
|
|
34299
|
-
body: text.replace(/^\uFEFF/, ""),
|
|
34300
|
-
fmExtra: [],
|
|
34301
|
-
bom,
|
|
34302
|
-
hasEnabledLine: false
|
|
34303
|
-
};
|
|
34304
|
-
if (lines[0]?.trim() !== "---") return none;
|
|
34305
|
-
let close = -1;
|
|
34306
|
-
for (let i = 1; i < lines.length && i <= 101; i++) if (lines[i].trim() === "---") {
|
|
34307
|
-
close = i;
|
|
34308
|
-
break;
|
|
34309
|
-
}
|
|
34310
|
-
if (close < 0) return none;
|
|
34311
|
-
const parsed = {
|
|
34312
|
-
type: "manual",
|
|
34313
|
-
description: "",
|
|
34314
|
-
alwaysApply: false,
|
|
34315
|
-
globs: [],
|
|
34316
|
-
enabled: true,
|
|
34317
|
-
hasFm: true,
|
|
34318
|
-
body: lines.slice(close + 1).join("\n"),
|
|
34319
|
-
fmExtra: [],
|
|
34320
|
-
bom,
|
|
34321
|
-
hasEnabledLine: false
|
|
34322
|
-
};
|
|
34323
|
-
for (let i = 1; i < close; i++) {
|
|
34324
|
-
const match = /^([A-Za-z_-]+)[ \t]*:[ \t]?(.*)$/.exec(lines[i]);
|
|
34325
|
-
if (!match) {
|
|
34326
|
-
parsed.fmExtra.push(lines[i]);
|
|
34327
|
-
continue;
|
|
34328
|
-
}
|
|
34329
|
-
const [, key, raw] = match;
|
|
34330
|
-
if (key === "description") parsed.description = stripQuotes(raw);
|
|
34331
|
-
else if (key === "alwaysApply") parsed.alwaysApply = stripQuotes(raw).toLowerCase() === "true";
|
|
34332
|
-
else if (key === "enabled") {
|
|
34333
|
-
parsed.enabled = stripQuotes(raw).toLowerCase() !== "false";
|
|
34334
|
-
parsed.hasEnabledLine = true;
|
|
34335
|
-
} else if (key === "globs") parsed.globs = parseGlobsValue(raw, lines, i, close);
|
|
34336
|
-
else parsed.fmExtra.push(lines[i]);
|
|
34337
|
-
}
|
|
34338
|
-
parsed.type = fmTypeOf(parsed);
|
|
34339
|
-
return parsed;
|
|
34340
|
-
}
|
|
34341
|
-
/**
|
|
34342
|
-
* 解析 globs 值:内联逗号分隔串,或空值后接 YAML 短横列表(与 host parseGlobs 一致)。
|
|
34343
|
-
* @author ddj 2026年09月07号
|
|
34344
|
-
* @param value 内联值
|
|
34345
|
-
* @param lines 全文行
|
|
34346
|
-
* @param start globs 行下标
|
|
34347
|
-
* @param close 闭合 --- 下标
|
|
34348
|
-
* @returns glob 数组
|
|
34349
|
-
*/
|
|
34350
|
-
function parseGlobsValue(value, lines, start, close) {
|
|
34351
|
-
const inline = stripQuotes(value);
|
|
34352
|
-
if (inline) return inline.split(",").map((item) => stripQuotes(item)).filter(Boolean);
|
|
34353
|
-
const list = [];
|
|
34354
|
-
for (let j = start + 1; j < close; j++) {
|
|
34355
|
-
const item = /^[ \t]*-[ \t]*(.+)$/.exec(lines[j]);
|
|
34356
|
-
if (!item) break;
|
|
34357
|
-
list.push(stripQuotes(item[1]));
|
|
34358
|
-
}
|
|
34359
|
-
return list;
|
|
34360
|
-
}
|
|
34361
|
-
/**
|
|
34362
|
-
* 由 frontmatter 推导类型:alwaysApply=true → 总是;有 globs → 自动;否则手动。
|
|
34363
|
-
* @author ddj 2026年09月07号
|
|
34364
|
-
* @param parsed 解析结果
|
|
34365
|
-
* @returns 规则类型
|
|
34366
|
-
*/
|
|
34367
|
-
function fmTypeOf(parsed) {
|
|
34368
|
-
if (parsed.alwaysApply) return "always";
|
|
34369
|
-
if (parsed.globs.length) return "auto";
|
|
34370
|
-
return "manual";
|
|
34371
|
-
}
|
|
34372
|
-
/**
|
|
34373
|
-
* 按最新控件值重写 frontmatter:known 键固定顺序 + fmExtra + 闭合 --- + 原 body;
|
|
34374
|
-
* 无 frontmatter 且目标为手动时:有描述则新建仅含描述的 frontmatter,否则原文返回。
|
|
34375
|
-
* @author ddj 2026年09月07号
|
|
34376
|
-
* @param parsed parseRuleFm 的结果(必须来自同一文本)
|
|
34377
|
-
* @param next 控件最新值
|
|
34378
|
-
* @returns 重写后的全文
|
|
34379
|
-
*/
|
|
34380
|
-
function applyRuleMeta(parsed, next) {
|
|
34381
|
-
if (!parsed.hasFm && next.type === "manual") {
|
|
34382
|
-
if (!next.description.trim()) return (parsed.bom ? "" : "") + parsed.body;
|
|
34383
|
-
return (parsed.bom ? "" : "") + [
|
|
34384
|
-
"---",
|
|
34385
|
-
"description: " + next.description.trim(),
|
|
34386
|
-
"---"
|
|
34387
|
-
].join("\n") + "\n" + parsed.body;
|
|
34388
|
-
}
|
|
34389
|
-
const lines = ["---"];
|
|
34390
|
-
lines.push("description: " + next.description.trim());
|
|
34391
|
-
if (next.type === "always") lines.push("alwaysApply: true");
|
|
34392
|
-
if (next.type === "auto") lines.push("globs: " + next.globs.join(", "));
|
|
34393
|
-
if (parsed.hasEnabledLine) lines.push("enabled: " + (parsed.enabled ? "true" : "false"));
|
|
34394
|
-
lines.push(...parsed.fmExtra);
|
|
34395
|
-
lines.push("---");
|
|
34396
|
-
return (parsed.bom ? "" : "") + lines.join("\n") + "\n" + parsed.body;
|
|
34397
|
-
}
|
|
34398
|
-
//#endregion
|
|
34399
|
-
//#region src/client/sidebar/panels/RulesPanel.ts
|
|
34400
|
-
/**
|
|
34401
|
-
* dsh-vscode-mode client — 侧边栏「规则」面板(Codebuddy 规则管理形态)。
|
|
34402
|
-
* 双 Tab:用户规则(~/.dsh/rules/)与项目规则(<工作区>/.dsh/rules/);
|
|
34403
|
-
* 列表行 = 文件名 + 相对提示,第二行类型徽标与描述,右侧 编辑/删除 图标 + 滑动启用开关;
|
|
34404
|
-
* 新建/编辑 = 顶部面包屑 + 规则类型下拉(总是/自动/手动)+ 描述/globs 控件,与原始 .mdc
|
|
34405
|
-
* 文本域双向同步(控件改写 frontmatter,文本域回读控件),保存走 rules.save。
|
|
34406
|
-
* 作者 ddj 2026年09月03号(2026年09月07号 交互性调整)
|
|
34407
|
-
*/
|
|
34408
|
-
/** 新建规则模板(frontmatter 字段与 host parseRuleMdc 对齐)。 */
|
|
34409
|
-
const NEW_TEMPLATE = "---\ndescription: \nalwaysApply: true\n---\n\n";
|
|
34410
|
-
const TYPE_LABEL = {
|
|
34411
|
-
always: "总是",
|
|
34412
|
-
auto: "自动",
|
|
34413
|
-
manual: "手动"
|
|
34877
|
+
//#region src/client/lazyPanel.ts
|
|
34878
|
+
/** Package-local CJS panel loading; transport, revision URLs and HMR belong to DSH. @author ddj 2026年10月22号 */
|
|
34879
|
+
const FILES = {
|
|
34880
|
+
rules: "./client.rules.js",
|
|
34881
|
+
debug: "./client.debug.js"
|
|
34414
34882
|
};
|
|
34415
|
-
|
|
34416
|
-
|
|
34417
|
-
|
|
34418
|
-
|
|
34419
|
-
|
|
34420
|
-
|
|
34421
|
-
|
|
34422
|
-
|
|
34423
|
-
|
|
34424
|
-
|
|
34425
|
-
|
|
34426
|
-
|
|
34427
|
-
|
|
34428
|
-
|
|
34429
|
-
|
|
34430
|
-
|
|
34431
|
-
|
|
34432
|
-
|
|
34433
|
-
|
|
34434
|
-
|
|
34435
|
-
|
|
34436
|
-
}
|
|
34437
|
-
|
|
34438
|
-
|
|
34439
|
-
|
|
34440
|
-
|
|
34441
|
-
|
|
34442
|
-
|
|
34443
|
-
|
|
34444
|
-
|
|
34445
|
-
|
|
34446
|
-
localStorage.setItem(key, value);
|
|
34447
|
-
} catch (e) {}
|
|
34448
|
-
}
|
|
34449
|
-
/**
|
|
34450
|
-
* 类型徽标(总是=绿 / 自动=蓝 / 手动=灰)。
|
|
34451
|
-
* @author ddj 2026年09月03号
|
|
34452
|
-
* @param type 规则类型
|
|
34453
|
-
* @returns 徽标元素
|
|
34454
|
-
*/
|
|
34455
|
-
function typeBadge(type) {
|
|
34456
|
-
return react.default.createElement("span", { className: "edrv-rules-type edrv-rules-type-" + type }, TYPE_LABEL[type] ?? type);
|
|
34457
|
-
}
|
|
34458
|
-
/**
|
|
34459
|
-
* 按字符上限截断列表行描述,超出以省略号收尾(上限随面板宽度动态变化;
|
|
34460
|
-
* 窄面板下 CSS 省略号仍会按像素提前截断,二者取更小)。
|
|
34461
|
-
* @author ddj 2026年09月07号
|
|
34462
|
-
* @param text 完整描述
|
|
34463
|
-
* @param cap 本帧字符上限
|
|
34464
|
-
* @returns 截断后的展示文本
|
|
34465
|
-
*/
|
|
34466
|
-
function clampDesc(text, cap) {
|
|
34467
|
-
const chars = Array.from(String(text ?? ""));
|
|
34468
|
-
const limit = Math.max(4, Number(cap) || DESC_MAX);
|
|
34469
|
-
return chars.length > limit ? chars.slice(0, limit).join("") + "…" : chars.join("");
|
|
34470
|
-
}
|
|
34471
|
-
/**
|
|
34472
|
-
* 由面板宽度估算描述可用字符数:随宽度动态变化,并与基础上限取小、极窄时保底。
|
|
34473
|
-
* @author ddj 2026年09月07号
|
|
34474
|
-
* @param panelWidth 面板内容宽度(px)
|
|
34475
|
-
* @returns 本帧描述字符上限
|
|
34476
|
-
*/
|
|
34477
|
-
function descCapOf(panelWidth) {
|
|
34478
|
-
const byWidth = Math.floor((Number(panelWidth) - DESC_RESERVE_PX) / DESC_CHAR_PX);
|
|
34479
|
-
return Math.max(DESC_CAP_MIN, Math.min(DESC_MAX, byWidth));
|
|
34480
|
-
}
|
|
34481
|
-
/**
|
|
34482
|
-
* 编辑图标(线性铅笔,与 DiffBox chevron 同风格:currentColor 描边装饰图)。
|
|
34483
|
-
* @author ddj 2026年09月07号
|
|
34484
|
-
* @returns 13×13 装饰性 SVG
|
|
34485
|
-
*/
|
|
34486
|
-
function pencilIcon() {
|
|
34487
|
-
return react.default.createElement("svg", {
|
|
34488
|
-
width: 13,
|
|
34489
|
-
height: 13,
|
|
34490
|
-
viewBox: "0 0 24 24",
|
|
34491
|
-
fill: "none",
|
|
34492
|
-
"aria-hidden": true,
|
|
34493
|
-
focusable: false
|
|
34494
|
-
}, react.default.createElement("path", {
|
|
34495
|
-
d: "M17 3a2.828 2.828 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5L17 3z",
|
|
34496
|
-
stroke: "currentColor",
|
|
34497
|
-
strokeWidth: 2,
|
|
34498
|
-
strokeLinecap: "round",
|
|
34499
|
-
strokeLinejoin: "round"
|
|
34500
|
-
}));
|
|
34501
|
-
}
|
|
34502
|
-
/**
|
|
34503
|
-
* 删除图标(线性垃圾桶,风格同 pencilIcon)。
|
|
34504
|
-
* @author ddj 2026年09月07号
|
|
34505
|
-
* @returns 13×13 装饰性 SVG
|
|
34506
|
-
*/
|
|
34507
|
-
function trashIcon() {
|
|
34508
|
-
return react.default.createElement("svg", {
|
|
34509
|
-
width: 13,
|
|
34510
|
-
height: 13,
|
|
34511
|
-
viewBox: "0 0 24 24",
|
|
34512
|
-
fill: "none",
|
|
34513
|
-
"aria-hidden": true,
|
|
34514
|
-
focusable: false
|
|
34515
|
-
}, react.default.createElement("path", {
|
|
34516
|
-
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",
|
|
34517
|
-
stroke: "currentColor",
|
|
34518
|
-
strokeWidth: 2,
|
|
34519
|
-
strokeLinecap: "round",
|
|
34520
|
-
strokeLinejoin: "round"
|
|
34521
|
-
}));
|
|
34522
|
-
}
|
|
34523
|
-
/**
|
|
34524
|
-
* 逗号分隔的 globs 输入串 → 数组(去空项)。
|
|
34525
|
-
* @author ddj 2026年09月07号
|
|
34526
|
-
* @param text 输入串
|
|
34527
|
-
* @returns glob 数组
|
|
34528
|
-
*/
|
|
34529
|
-
function globList(text) {
|
|
34530
|
-
return String(text ?? "").split(",").map((item) => item.trim()).filter(Boolean);
|
|
34531
|
-
}
|
|
34532
|
-
/**
|
|
34533
|
-
* 由控件值重建 .mdc 全文:frontmatter 按类型/描述/globs 重写,正文与其余键不动。
|
|
34534
|
-
* @author ddj 2026年09月07号
|
|
34535
|
-
* @param base 当前全文
|
|
34536
|
-
* @param fmType 目标类型(always/auto/manual)
|
|
34537
|
-
* @param desc 描述文本
|
|
34538
|
-
* @param globsText globs 输入串
|
|
34539
|
-
* @returns 重写后的全文
|
|
34540
|
-
*/
|
|
34541
|
-
function rebuildContent(base, fmType, desc, globsText) {
|
|
34542
|
-
return applyRuleMeta(parseRuleFm(base), {
|
|
34543
|
-
type: fmType,
|
|
34544
|
-
description: desc,
|
|
34545
|
-
globs: globList(globsText)
|
|
34883
|
+
const EXPORTS = {
|
|
34884
|
+
rules: "RulesPanel",
|
|
34885
|
+
debug: "DebugPanel"
|
|
34886
|
+
};
|
|
34887
|
+
const loads = /* @__PURE__ */ new Map();
|
|
34888
|
+
let generation = 0;
|
|
34889
|
+
let importer;
|
|
34890
|
+
/** @public @author ddj 2026年10月22号 @param transport Injected ModuleLoader require.async, never a global require. @description Start a new plugin generation and discard older results. */
|
|
34891
|
+
function setPanelImport(transport) {
|
|
34892
|
+
generation++;
|
|
34893
|
+
loads.clear();
|
|
34894
|
+
importer = transport;
|
|
34895
|
+
}
|
|
34896
|
+
/** @public @author ddj 2026年10月22号 @param key Fixed built-in panel key. @returns Shared pending load or cached component. @throws Unsupported loader or invalid chunk export. */
|
|
34897
|
+
function loadPanel(key) {
|
|
34898
|
+
const cached = loads.get(key);
|
|
34899
|
+
if (cached?.component) return Promise.resolve(cached.component);
|
|
34900
|
+
if (cached?.pending) return cached.pending;
|
|
34901
|
+
if (!importer) return Promise.reject(/* @__PURE__ */ new Error("当前 DSH 不支持包内面板加载,请升级宿主"));
|
|
34902
|
+
const epoch = generation;
|
|
34903
|
+
const transport = importer;
|
|
34904
|
+
const state = {};
|
|
34905
|
+
const pending = Promise.resolve().then(() => transport(FILES[key])).then((exports) => {
|
|
34906
|
+
const component = exports[EXPORTS[key]];
|
|
34907
|
+
if (typeof component !== "function") throw new Error("面板脚本缺少组件导出");
|
|
34908
|
+
if (epoch !== generation) throw new Error("面板加载已失效,请重试");
|
|
34909
|
+
state.component = component;
|
|
34910
|
+
return state.component;
|
|
34911
|
+
}).catch((error) => {
|
|
34912
|
+
if (loads.get(key) === state) loads.delete(key);
|
|
34913
|
+
throw error;
|
|
34546
34914
|
});
|
|
34915
|
+
state.pending = pending;
|
|
34916
|
+
loads.set(key, state);
|
|
34917
|
+
return pending;
|
|
34547
34918
|
}
|
|
34548
|
-
/**
|
|
34549
|
-
|
|
34550
|
-
|
|
34551
|
-
|
|
34552
|
-
|
|
34553
|
-
|
|
34554
|
-
|
|
34555
|
-
|
|
34556
|
-
|
|
34557
|
-
|
|
34558
|
-
|
|
34559
|
-
|
|
34560
|
-
|
|
34561
|
-
|
|
34562
|
-
|
|
34563
|
-
|
|
34564
|
-
|
|
34565
|
-
className: "edrv-rules-path",
|
|
34566
|
-
title: rule.absPath
|
|
34567
|
-
}, "旧目录") : 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", {
|
|
34568
|
-
className: "edrv-rules-desc",
|
|
34569
|
-
title: desc
|
|
34570
|
-
}, clampDesc(desc, props.descCap)) : null)), react.default.createElement("div", { className: "edrv-rules-actions" }, react.default.createElement("button", {
|
|
34571
|
-
className: "edrv-rules-act",
|
|
34572
|
-
title: "编辑",
|
|
34573
|
-
onClick: () => props.onEdit(rule)
|
|
34574
|
-
}, pencilIcon()), react.default.createElement("button", {
|
|
34575
|
-
className: "edrv-rules-act",
|
|
34576
|
-
title: "删除",
|
|
34577
|
-
onClick: () => props.onRemove(rule)
|
|
34578
|
-
}, trashIcon()), react.default.createElement("button", {
|
|
34579
|
-
className: "edrv-rules-switch" + (rule.enabled ? " on" : ""),
|
|
34580
|
-
role: "switch",
|
|
34581
|
-
"aria-checked": rule.enabled,
|
|
34582
|
-
title: rule.enabled ? "已启用(点击停用)" : "已停用(点击启用)",
|
|
34583
|
-
onClick: () => props.onToggle(rule)
|
|
34584
|
-
}, react.default.createElement("span", { className: "edrv-rules-knob" }))));
|
|
34585
|
-
}
|
|
34586
|
-
/**
|
|
34587
|
-
* 新建/编辑表单:面包屑头部 + 规则类型下拉/描述/globs 控件行 + 原始 .mdc 文本域 + 保存/取消。
|
|
34588
|
-
* @author ddj 2026年09月03号
|
|
34589
|
-
* @param props.form 表单状态(mode/scope/workspacePath/relHint/file/content/fmType/desc/globs/error/saving)
|
|
34590
|
-
* @param props.onType 类型下拉变更回调
|
|
34591
|
-
* @param props.onDesc 描述输入回调
|
|
34592
|
-
* @param props.onGlobs globs 输入回调
|
|
34593
|
-
* @param props.onBody 文本域编辑回调
|
|
34594
|
-
* @param props.onSave 保存回调
|
|
34595
|
-
* @param props.onCancel 取消回调
|
|
34596
|
-
* @returns 表单元素
|
|
34597
|
-
*/
|
|
34598
|
-
function RuleEditor(props) {
|
|
34599
|
-
const form = props.form;
|
|
34600
|
-
const isNew = form.mode === "new";
|
|
34601
|
-
const crumb = (form.scope === "project" ? "项目规则" : "用户规则") + " > " + form.relHint + " > " + (form.file || "新建规则.mdc");
|
|
34602
|
-
return react.default.createElement("div", { className: "edrv-rules-editor" }, react.default.createElement("div", { className: "edrv-rules-editor-head" }, react.default.createElement("span", {
|
|
34603
|
-
className: "edrv-rules-crumb",
|
|
34604
|
-
title: crumb
|
|
34605
|
-
}, crumb), react.default.createElement("button", {
|
|
34606
|
-
className: "edrv-rules-act",
|
|
34607
|
-
title: "取消",
|
|
34608
|
-
onClick: props.onCancel
|
|
34609
|
-
}, "✕")), react.default.createElement("div", { className: "edrv-rules-editor-ctl" }, react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "规则类型"), react.default.createElement("select", {
|
|
34610
|
-
className: "edrv-rules-select",
|
|
34611
|
-
value: form.fmType,
|
|
34612
|
-
onChange: props.onType
|
|
34613
|
-
}, Object.keys(TYPE_LABEL).map((key) => react.default.createElement("option", {
|
|
34614
|
-
key,
|
|
34615
|
-
value: key
|
|
34616
|
-
}, TYPE_LABEL[key]))), react.default.createElement("label", { className: "edrv-rules-ctl-label" }, "描述"), react.default.createElement("input", {
|
|
34617
|
-
className: "edrv-rules-input edrv-rules-desc-input",
|
|
34618
|
-
value: form.desc,
|
|
34619
|
-
spellCheck: false,
|
|
34620
|
-
placeholder: isNew ? "规则用途说明(写入 frontmatter description)" : "规则用途说明",
|
|
34621
|
-
onChange: props.onDesc
|
|
34622
|
-
})), 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", {
|
|
34623
|
-
className: "edrv-rules-input",
|
|
34624
|
-
value: form.globs,
|
|
34625
|
-
spellCheck: false,
|
|
34626
|
-
placeholder: "src/**/*.ts, *.md(逗号分隔,命中才注入)",
|
|
34627
|
-
onChange: props.onGlobs
|
|
34628
|
-
})) : null, react.default.createElement("textarea", {
|
|
34629
|
-
className: "edrv-rules-body",
|
|
34630
|
-
spellCheck: false,
|
|
34631
|
-
value: form.content,
|
|
34632
|
-
onChange: props.onBody
|
|
34633
|
-
}), 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", {
|
|
34634
|
-
className: "edrv-rules-save",
|
|
34635
|
-
disabled: form.saving,
|
|
34636
|
-
onClick: props.onSave
|
|
34637
|
-
}, form.saving ? "保存中…" : "保存")));
|
|
34638
|
-
}
|
|
34639
|
-
/**
|
|
34640
|
-
* 规则面板主体。
|
|
34641
|
-
* @param props.ctx 面板共享上下文(notify 可选)
|
|
34642
|
-
*/
|
|
34643
|
-
function RulesPanel(props) {
|
|
34644
|
-
const ctx = props?.ctx;
|
|
34645
|
-
const notify = ctx?.notify ?? ((message) => {});
|
|
34646
|
-
const cwd = ctx?.cwd ?? null;
|
|
34647
|
-
const [tab, setTab] = react.default.useState(() => readLocal(CACHE_KEY.rules + "tab") === "project" ? "project" : "user");
|
|
34648
|
-
const [data, setData] = react.default.useState(null);
|
|
34649
|
-
const [error, setError] = react.default.useState("");
|
|
34650
|
-
const panelRef = react.default.useRef(null);
|
|
34651
|
-
const [panelW, setPanelW] = react.default.useState(0);
|
|
34652
|
-
const [form, setForm] = react.default.useState(null);
|
|
34653
|
-
const mountedRef = react.default.useRef(true);
|
|
34654
|
-
/**
|
|
34655
|
-
* 当前工作区对应的项目聚合(按 ctx.cwd 自动匹配;无会话/未注册返回 null)。
|
|
34656
|
-
* @returns RuleProject 或 null
|
|
34657
|
-
*/
|
|
34658
|
-
const activeProject = () => {
|
|
34659
|
-
if (!cwd) return null;
|
|
34660
|
-
return (data?.projects ?? []).find((p) => p.workspacePath === cwd) ?? null;
|
|
34661
|
-
};
|
|
34662
|
-
/** 拉取规则总列表(rules.list)。 */
|
|
34663
|
-
const load = () => {
|
|
34664
|
-
rpc("rules.list", {}).then((res) => {
|
|
34665
|
-
if (!mountedRef.current) return;
|
|
34666
|
-
if (res && res.ok) {
|
|
34667
|
-
setData(res);
|
|
34668
|
-
setError("");
|
|
34669
|
-
} else setError(res?.error ?? "读取规则失败");
|
|
34670
|
-
}).catch((e) => {
|
|
34671
|
-
if (mountedRef.current) setError("读取规则异常: " + String(e));
|
|
34672
|
-
});
|
|
34673
|
-
};
|
|
34674
|
-
react.default.useEffect(() => {
|
|
34675
|
-
mountedRef.current = true;
|
|
34676
|
-
load();
|
|
34919
|
+
/** @public @author ddj 2026年10月22号 @param props Fixed panel and current context. @returns Loading, explicit retry, or the loaded panel subtree. */
|
|
34920
|
+
function LazyPanel(props) {
|
|
34921
|
+
const [attempt, retry] = react.default.useState(0);
|
|
34922
|
+
const [view, setView] = react.default.useState({});
|
|
34923
|
+
/** @private @author ddj 2026年10月22号 @returns Cleanup invalidating callbacks after switch or unmount. */
|
|
34924
|
+
function loadEffect() {
|
|
34925
|
+
let active = true;
|
|
34926
|
+
setView({});
|
|
34927
|
+
/** @author ddj 2026年10月22号 @param component Loaded panel. */
|
|
34928
|
+
function ready(component) {
|
|
34929
|
+
if (active) setView({ component });
|
|
34930
|
+
}
|
|
34931
|
+
/** @author ddj 2026年10月22号 @param error Loader failure. */
|
|
34932
|
+
function failed(error) {
|
|
34933
|
+
if (active) setView({ error: String(error) });
|
|
34934
|
+
}
|
|
34935
|
+
loadPanel(props.panel).then(ready, failed);
|
|
34677
34936
|
return () => {
|
|
34678
|
-
|
|
34679
|
-
};
|
|
34680
|
-
}, []);
|
|
34681
|
-
react.default.useEffect(() => {
|
|
34682
|
-
const el = panelRef.current;
|
|
34683
|
-
if (!el || typeof ResizeObserver === "undefined") return void 0;
|
|
34684
|
-
const observer = new ResizeObserver(() => setPanelW(el.clientWidth));
|
|
34685
|
-
observer.observe(el);
|
|
34686
|
-
setPanelW(el.clientWidth);
|
|
34687
|
-
return () => observer.disconnect();
|
|
34688
|
-
}, []);
|
|
34689
|
-
const descCap = panelW > 0 ? descCapOf(panelW) : DESC_MAX;
|
|
34690
|
-
const narrow = panelW > 0 && panelW < NARROW_W;
|
|
34691
|
-
/**
|
|
34692
|
-
* 切换 Tab(记忆到 localStorage)。
|
|
34693
|
-
* @param next 目标 Tab
|
|
34694
|
-
*/
|
|
34695
|
-
const switchTab = (next) => {
|
|
34696
|
-
setTab(next);
|
|
34697
|
-
writeLocal(CACHE_KEY.rules + "tab", next);
|
|
34698
|
-
};
|
|
34699
|
-
/**
|
|
34700
|
-
* 打开新建表单(按当前 Tab 决定作用域;项目规则跟随当前会话工作区)。
|
|
34701
|
-
*/
|
|
34702
|
-
const openNew = () => {
|
|
34703
|
-
const scope = tab === "project" ? "project" : "user";
|
|
34704
|
-
if (scope === "project" && !cwd) {
|
|
34705
|
-
notify("当前会话没有工作区,无法新建项目规则");
|
|
34706
|
-
return;
|
|
34707
|
-
}
|
|
34708
|
-
const parsed = parseRuleFm(NEW_TEMPLATE);
|
|
34709
|
-
setForm({
|
|
34710
|
-
mode: "new",
|
|
34711
|
-
scope,
|
|
34712
|
-
origin: scope === "user" ? "current" : void 0,
|
|
34713
|
-
workspacePath: scope === "project" ? cwd : void 0,
|
|
34714
|
-
relHint: scope === "project" ? ".dsh/rules/" : "rules/",
|
|
34715
|
-
file: "",
|
|
34716
|
-
content: NEW_TEMPLATE,
|
|
34717
|
-
fmType: parsed.type,
|
|
34718
|
-
desc: parsed.description,
|
|
34719
|
-
globs: parsed.globs.join(", "),
|
|
34720
|
-
error: "",
|
|
34721
|
-
saving: false
|
|
34722
|
-
});
|
|
34723
|
-
};
|
|
34724
|
-
/**
|
|
34725
|
-
* 打开编辑表单:先拉全文,再解析 frontmatter 回填类型/描述/globs 控件。
|
|
34726
|
-
* @param rule 目标规则
|
|
34727
|
-
*/
|
|
34728
|
-
const openEdit = (rule) => {
|
|
34729
|
-
rpc("rules.read", {
|
|
34730
|
-
scope: rule.scope,
|
|
34731
|
-
origin: rule.origin,
|
|
34732
|
-
workspacePath: rule.scope === "project" ? rule.workspacePath : void 0,
|
|
34733
|
-
file: rule.file
|
|
34734
|
-
}).then((res) => {
|
|
34735
|
-
if (!res || !res.ok) {
|
|
34736
|
-
notify(res?.error ?? "读取规则失败");
|
|
34737
|
-
return;
|
|
34738
|
-
}
|
|
34739
|
-
const parsed = parseRuleFm(res.content);
|
|
34740
|
-
setForm({
|
|
34741
|
-
mode: "edit",
|
|
34742
|
-
scope: rule.scope,
|
|
34743
|
-
origin: rule.origin,
|
|
34744
|
-
workspacePath: rule.workspacePath,
|
|
34745
|
-
relHint: rule.relHint,
|
|
34746
|
-
file: rule.file,
|
|
34747
|
-
content: res.content,
|
|
34748
|
-
fmType: parsed.type,
|
|
34749
|
-
desc: parsed.description,
|
|
34750
|
-
globs: parsed.globs.join(", "),
|
|
34751
|
-
error: "",
|
|
34752
|
-
saving: false
|
|
34753
|
-
});
|
|
34754
|
-
}).catch((e) => notify("读取规则异常: " + String(e)));
|
|
34755
|
-
};
|
|
34756
|
-
/** 类型下拉变更:frontmatter 按新类型重写,控件同步。 */
|
|
34757
|
-
const onTypeChange = (e) => {
|
|
34758
|
-
const nextType = e.target.value;
|
|
34759
|
-
setForm((prev) => ({
|
|
34760
|
-
...prev,
|
|
34761
|
-
fmType: nextType,
|
|
34762
|
-
content: rebuildContent(prev.content, nextType, prev.desc, prev.globs),
|
|
34763
|
-
error: ""
|
|
34764
|
-
}));
|
|
34765
|
-
};
|
|
34766
|
-
/** 描述输入变更:同步 frontmatter description 行。 */
|
|
34767
|
-
const onDescChange = (e) => {
|
|
34768
|
-
const nextDesc = e.target.value;
|
|
34769
|
-
setForm((prev) => ({
|
|
34770
|
-
...prev,
|
|
34771
|
-
desc: nextDesc,
|
|
34772
|
-
content: rebuildContent(prev.content, prev.fmType, nextDesc, prev.globs),
|
|
34773
|
-
error: ""
|
|
34774
|
-
}));
|
|
34775
|
-
};
|
|
34776
|
-
/** globs 输入变更(自动规则):同步 frontmatter globs 行。 */
|
|
34777
|
-
const onGlobsChange = (e) => {
|
|
34778
|
-
const nextGlobs = e.target.value;
|
|
34779
|
-
setForm((prev) => ({
|
|
34780
|
-
...prev,
|
|
34781
|
-
globs: nextGlobs,
|
|
34782
|
-
content: rebuildContent(prev.content, prev.fmType, prev.desc, nextGlobs),
|
|
34783
|
-
error: ""
|
|
34784
|
-
}));
|
|
34785
|
-
};
|
|
34786
|
-
/** 文本域直接编辑:回读 frontmatter,同步类型/描述/globs 控件(文本域是唯一真源)。 */
|
|
34787
|
-
const onBodyChange = (e) => {
|
|
34788
|
-
const parsed = parseRuleFm(e.target.value);
|
|
34789
|
-
setForm((prev) => ({
|
|
34790
|
-
...prev,
|
|
34791
|
-
content: e.target.value,
|
|
34792
|
-
fmType: parsed.type,
|
|
34793
|
-
desc: parsed.description,
|
|
34794
|
-
globs: parsed.globs.join(", ")
|
|
34795
|
-
}));
|
|
34796
|
-
};
|
|
34797
|
-
/** 保存表单(rules.save;文件名非空 + 自动规则必须有 globs)。 */
|
|
34798
|
-
const saveForm = () => {
|
|
34799
|
-
const next = {
|
|
34800
|
-
...form,
|
|
34801
|
-
saving: true,
|
|
34802
|
-
error: ""
|
|
34803
|
-
};
|
|
34804
|
-
const file = String(form.file ?? "").trim();
|
|
34805
|
-
if (!file) {
|
|
34806
|
-
setForm({
|
|
34807
|
-
...next,
|
|
34808
|
-
saving: false,
|
|
34809
|
-
error: "文件名不能为空"
|
|
34810
|
-
});
|
|
34811
|
-
return;
|
|
34812
|
-
}
|
|
34813
|
-
if (form.fmType === "auto" && globList(form.globs).length === 0) {
|
|
34814
|
-
setForm({
|
|
34815
|
-
...next,
|
|
34816
|
-
saving: false,
|
|
34817
|
-
error: "自动规则需要至少一个 glob(逗号分隔)"
|
|
34818
|
-
});
|
|
34819
|
-
return;
|
|
34820
|
-
}
|
|
34821
|
-
setForm(next);
|
|
34822
|
-
rpc("rules.save", {
|
|
34823
|
-
scope: form.scope,
|
|
34824
|
-
origin: form.origin,
|
|
34825
|
-
workspacePath: form.workspacePath,
|
|
34826
|
-
file,
|
|
34827
|
-
content: form.content
|
|
34828
|
-
}).then((res) => {
|
|
34829
|
-
if (res && res.ok) {
|
|
34830
|
-
setForm(null);
|
|
34831
|
-
notify("规则已保存:" + file);
|
|
34832
|
-
load();
|
|
34833
|
-
} else setForm((prev) => ({
|
|
34834
|
-
...prev,
|
|
34835
|
-
saving: false,
|
|
34836
|
-
error: res?.error ?? "保存失败"
|
|
34837
|
-
}));
|
|
34838
|
-
}).catch((e) => setForm((prev) => ({
|
|
34839
|
-
...prev,
|
|
34840
|
-
saving: false,
|
|
34841
|
-
error: "保存异常: " + String(e)
|
|
34842
|
-
})));
|
|
34843
|
-
};
|
|
34844
|
-
/**
|
|
34845
|
-
* 删除规则(confirm 后走 rules.remove)。
|
|
34846
|
-
* @param rule 目标规则
|
|
34847
|
-
*/
|
|
34848
|
-
const removeRule = (rule) => {
|
|
34849
|
-
const reveal = rule.scope === "user" && rule.origin !== "legacy" ? "\n若旧目录有同名规则,删除后它将重新生效。" : "";
|
|
34850
|
-
if (!window.confirm("删除规则 " + rule.absPath + "?(不可恢复)" + reveal)) return;
|
|
34851
|
-
rpc("rules.remove", {
|
|
34852
|
-
scope: rule.scope,
|
|
34853
|
-
origin: rule.origin,
|
|
34854
|
-
workspacePath: rule.workspacePath,
|
|
34855
|
-
file: rule.file
|
|
34856
|
-
}).then((res) => {
|
|
34857
|
-
if (res && res.ok) {
|
|
34858
|
-
notify("已删除:" + rule.file);
|
|
34859
|
-
load();
|
|
34860
|
-
} else notify(res?.error ?? "删除失败");
|
|
34861
|
-
}).catch((e) => notify("删除异常: " + String(e)));
|
|
34862
|
-
};
|
|
34863
|
-
/**
|
|
34864
|
-
* 切换启用开关:本地乐观翻转(按 workspacePath+file 定位,失败回滚)。
|
|
34865
|
-
* @param rule 目标规则(project 已注入 workspacePath)
|
|
34866
|
-
*/
|
|
34867
|
-
const toggleRule = (rule) => {
|
|
34868
|
-
const enabled = !rule.enabled;
|
|
34869
|
-
const applyLocal = (on) => setData((prev) => prev ? {
|
|
34870
|
-
...prev,
|
|
34871
|
-
user: prev.user.map((r) => rule.scope === "user" && r.file === rule.file && (r.origin ?? "current") === (rule.origin ?? "current") ? {
|
|
34872
|
-
...r,
|
|
34873
|
-
enabled: on
|
|
34874
|
-
} : r),
|
|
34875
|
-
projects: prev.projects.map((p) => p.workspacePath === rule.workspacePath ? {
|
|
34876
|
-
...p,
|
|
34877
|
-
rules: p.rules.map((r) => r.file === rule.file ? {
|
|
34878
|
-
...r,
|
|
34879
|
-
enabled: on
|
|
34880
|
-
} : r)
|
|
34881
|
-
} : p)
|
|
34882
|
-
} : prev);
|
|
34883
|
-
applyLocal(enabled);
|
|
34884
|
-
rpc("rules.toggle", {
|
|
34885
|
-
scope: rule.scope,
|
|
34886
|
-
origin: rule.origin,
|
|
34887
|
-
workspacePath: rule.workspacePath,
|
|
34888
|
-
file: rule.file,
|
|
34889
|
-
enabled
|
|
34890
|
-
}).then((res) => {
|
|
34891
|
-
if (res && res.ok) {
|
|
34892
|
-
applyLocal(res.rule?.enabled === true);
|
|
34893
|
-
notify(res.rule?.enabled === false ? "已停用:" + rule.file : "已启用:" + rule.file);
|
|
34894
|
-
} else {
|
|
34895
|
-
applyLocal(!enabled);
|
|
34896
|
-
notify(res?.error ?? "切换失败");
|
|
34897
|
-
}
|
|
34898
|
-
}).catch((e) => {
|
|
34899
|
-
applyLocal(!enabled);
|
|
34900
|
-
notify("切换异常: " + String(e));
|
|
34901
|
-
});
|
|
34902
|
-
};
|
|
34903
|
-
/** 当前列表数据(按 Tab 取用户规则或当前工作区的项目规则)。 */
|
|
34904
|
-
const rowsOf = () => {
|
|
34905
|
-
if (!data) return [];
|
|
34906
|
-
if (tab === "user") return data.user;
|
|
34907
|
-
return activeProject()?.rules ?? [];
|
|
34908
|
-
};
|
|
34909
|
-
const renderTabs = () => react.default.createElement("div", { className: "edrv-rules-tabs" }, react.default.createElement("button", {
|
|
34910
|
-
className: "edrv-rules-tab" + (tab === "user" ? " on" : ""),
|
|
34911
|
-
onClick: () => switchTab("user")
|
|
34912
|
-
}, "用户规则"), react.default.createElement("button", {
|
|
34913
|
-
className: "edrv-rules-tab" + (tab === "project" ? " on" : ""),
|
|
34914
|
-
onClick: () => switchTab("project")
|
|
34915
|
-
}, "项目规则"), react.default.createElement("button", {
|
|
34916
|
-
className: "edrv-rules-new",
|
|
34917
|
-
title: "新建规则",
|
|
34918
|
-
onClick: openNew
|
|
34919
|
-
}, "+ 新建规则"));
|
|
34920
|
-
/** 项目 Tab 的工作区展示(不可编辑,自动跟随当前会话)。 */
|
|
34921
|
-
const renderWsLine = () => {
|
|
34922
|
-
if (tab !== "project") return null;
|
|
34923
|
-
return react.default.createElement("div", {
|
|
34924
|
-
className: "edrv-rules-ws-line",
|
|
34925
|
-
title: cwd ?? ""
|
|
34926
|
-
}, "工作区:" + (cwd ?? "当前会话未打开工作区"));
|
|
34927
|
-
};
|
|
34928
|
-
const renderEmpty = () => {
|
|
34929
|
-
if (tab === "project") {
|
|
34930
|
-
if (!cwd) return "当前会话没有工作区,项目规则不可用(项目规则跟随会话所在工作区)";
|
|
34931
|
-
if (!data?.projects?.length) return "当前 DSH 没有已注册的工作区;在目标工作区打开一次会话后再来管理";
|
|
34932
|
-
if (!activeProject()) return "当前工作区未注册为 DSH workspace,暂不能管理其项目规则";
|
|
34933
|
-
return "<工作区>/.dsh/rules/ 还没有规则,点击「+ 新建规则」创建";
|
|
34934
|
-
}
|
|
34935
|
-
return "还没有用户规则(当前 DSH_HOME/rules/ 或旧目录 ~/.dsh/rules/),点击「+ 新建规则」创建";
|
|
34936
|
-
};
|
|
34937
|
-
const renderBody = () => {
|
|
34938
|
-
if (form) return react.default.createElement(RuleEditor, {
|
|
34939
|
-
form,
|
|
34940
|
-
onType: onTypeChange,
|
|
34941
|
-
onDesc: onDescChange,
|
|
34942
|
-
onGlobs: onGlobsChange,
|
|
34943
|
-
onBody: onBodyChange,
|
|
34944
|
-
onSave: saveForm,
|
|
34945
|
-
onCancel: () => setForm(null)
|
|
34946
|
-
});
|
|
34947
|
-
if (!data) return react.default.createElement("div", { className: "edrv-rules-empty" }, "加载中…");
|
|
34948
|
-
if (error) return react.default.createElement("div", { className: "edrv-rules-err" }, error);
|
|
34949
|
-
const rows = rowsOf();
|
|
34950
|
-
if (!rows.length) return react.default.createElement("div", { className: "edrv-rules-empty" }, renderEmpty());
|
|
34951
|
-
const common = {
|
|
34952
|
-
descCap,
|
|
34953
|
-
narrow,
|
|
34954
|
-
onEdit: (rule) => openEdit({
|
|
34955
|
-
...rule,
|
|
34956
|
-
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
34957
|
-
}),
|
|
34958
|
-
onRemove: (rule) => removeRule({
|
|
34959
|
-
...rule,
|
|
34960
|
-
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
34961
|
-
}),
|
|
34962
|
-
onToggle: (rule) => toggleRule({
|
|
34963
|
-
...rule,
|
|
34964
|
-
workspacePath: rule.scope === "project" ? cwd : void 0
|
|
34965
|
-
})
|
|
34937
|
+
active = false;
|
|
34966
34938
|
};
|
|
34967
|
-
|
|
34968
|
-
|
|
34969
|
-
|
|
34970
|
-
|
|
34971
|
-
|
|
34972
|
-
}
|
|
34939
|
+
}
|
|
34940
|
+
react.default.useEffect(loadEffect, [props.panel, attempt]);
|
|
34941
|
+
/** @private @author ddj 2026年10月22号 @description Explicit retry; failures never loop automatically. */
|
|
34942
|
+
function onRetry() {
|
|
34943
|
+
retry(attempt + 1);
|
|
34944
|
+
}
|
|
34945
|
+
if (view.component) return react.default.createElement(view.component, { ctx: props.ctx });
|
|
34973
34946
|
return react.default.createElement("div", {
|
|
34974
|
-
className: "edrv-
|
|
34975
|
-
|
|
34976
|
-
},
|
|
34947
|
+
className: "edrv-empty",
|
|
34948
|
+
role: view.error ? "alert" : "status"
|
|
34949
|
+
}, view.error ?? "正在加载面板…", view.error && react.default.createElement("button", { onClick: onRetry }, "重试"));
|
|
34977
34950
|
}
|
|
34978
34951
|
//#endregion
|
|
34979
34952
|
//#region src/client/ui/SvnAiPlanDialog.ts
|
|
@@ -35703,7 +35676,7 @@ window.__ModuleLoader__.load({
|
|
|
35703
35676
|
const [busy, setBusy] = react.default.useState(false);
|
|
35704
35677
|
const [remote, setRemote] = react.default.useState(null);
|
|
35705
35678
|
const [remoteBusy, setRemoteBusy] = react.default.useState(false);
|
|
35706
|
-
const [
|
|
35679
|
+
const [sizeSnapshot, setSizes] = react.default.useState(null);
|
|
35707
35680
|
const [renderLimit, setRenderLimit] = react.default.useState(RENDER_STEP);
|
|
35708
35681
|
const ctxRef = react.default.useRef(ctx);
|
|
35709
35682
|
ctxRef.current = ctx;
|
|
@@ -35804,17 +35777,39 @@ window.__ModuleLoader__.load({
|
|
|
35804
35777
|
const missingEntries = react.default.useMemo(() => (entries ?? []).filter((entry) => entry.status === "missing"), [entries]);
|
|
35805
35778
|
const unversionedEntries = react.default.useMemo(() => (entries ?? []).filter((entry) => entry.status === "unversioned"), [entries]);
|
|
35806
35779
|
const requested = react.default.useMemo(() => [...missingEntries, ...unversionedEntries].slice(0, 200).map((entry) => entry.path), [missingEntries, unversionedEntries]);
|
|
35807
|
-
const candidateKey =
|
|
35808
|
-
const
|
|
35809
|
-
|
|
35810
|
-
|
|
35811
|
-
if (pairsKnown || !requested.length) return;
|
|
35812
|
-
svnFileSizes(sessionId, requested).then((table) => setSizes(table));
|
|
35813
|
-
}, [
|
|
35814
|
-
pairsKnown,
|
|
35780
|
+
const candidateKey = JSON.stringify(requested);
|
|
35781
|
+
const sizeOwner = JSON.stringify([
|
|
35782
|
+
scope,
|
|
35783
|
+
sessionId,
|
|
35815
35784
|
candidateKey,
|
|
35816
|
-
|
|
35785
|
+
managed
|
|
35817
35786
|
]);
|
|
35787
|
+
const sizeOwnerRef = react.default.useRef(sizeOwner);
|
|
35788
|
+
sizeOwnerRef.current = sizeOwner;
|
|
35789
|
+
const sizes = sizeSnapshot?.owner === sizeOwner ? sizeSnapshot.table : {};
|
|
35790
|
+
const pairsNeeded = managed && missingEntries.length > 0 && unversionedEntries.length > 0;
|
|
35791
|
+
const pairsKnown = pairsNeeded && requested.every((path) => path in sizes);
|
|
35792
|
+
/** @private @author ddj 2026年10月22号 @returns Cleanup invalidating this request. @description Keep sizes scoped to this candidate generation; failures do not retry in a render loop. */
|
|
35793
|
+
function loadPairSizes() {
|
|
35794
|
+
if (!pairsNeeded || !requested.length) return;
|
|
35795
|
+
let disposed = false;
|
|
35796
|
+
/** @author ddj 2026年10月22号 @param table Candidate sizes. @description Publish only to the current request owner. */
|
|
35797
|
+
function acceptSizes(table) {
|
|
35798
|
+
if (!disposed && sizeOwnerRef.current === sizeOwner) setSizes({
|
|
35799
|
+
owner: sizeOwner,
|
|
35800
|
+
table
|
|
35801
|
+
});
|
|
35802
|
+
}
|
|
35803
|
+
/** @author ddj 2026年10月22号 @description Failed reads leave pairing unknown without breaking the changes list. */
|
|
35804
|
+
function ignoreFailure() {}
|
|
35805
|
+
/** @author ddj 2026年10月22号 @description Revoke this request on dependency change or unmount. */
|
|
35806
|
+
function cancelSizes() {
|
|
35807
|
+
disposed = true;
|
|
35808
|
+
}
|
|
35809
|
+
svnFileSizes(sessionId, requested).then(acceptSizes, ignoreFailure);
|
|
35810
|
+
return cancelSizes;
|
|
35811
|
+
}
|
|
35812
|
+
react.default.useEffect(loadPairSizes, [sizeOwner, pairsNeeded]);
|
|
35818
35813
|
const pairNoteOf = react.default.useMemo(() => {
|
|
35819
35814
|
if (!pairsKnown) return {};
|
|
35820
35815
|
const notes = {};
|
|
@@ -36286,851 +36281,6 @@ window.__ModuleLoader__.load({
|
|
|
36286
36281
|
}), remoteEl, pairCapEl, ...toolbar, react.default.createElement("div", { className: "edrv-svn-list" }, svnListBody(listState, handlers)), menuEl, aiPlanEl);
|
|
36287
36282
|
}
|
|
36288
36283
|
//#endregion
|
|
36289
|
-
//#region src/client/dap/variableTree.ts
|
|
36290
|
-
/**
|
|
36291
|
-
* 将变量树展平为 sibling rows;循环 ref 只展开一次,避免异常适配器数据造成递归。
|
|
36292
|
-
* @author ddj 2026年09月29号
|
|
36293
|
-
* @param roots 根变量
|
|
36294
|
-
* @param expanded 已展开的 variablesReference
|
|
36295
|
-
* @param cache ref → 子变量缓存
|
|
36296
|
-
* @param options 行数/深度上限
|
|
36297
|
-
*/
|
|
36298
|
-
function flattenVariableRows(roots, expanded, cache, options = {}) {
|
|
36299
|
-
const rows = [];
|
|
36300
|
-
const maxRows = options.maxRows ?? 1e3;
|
|
36301
|
-
const maxDepth = options.maxDepth ?? 32;
|
|
36302
|
-
const walk = (items, depth, ancestry, prefix) => {
|
|
36303
|
-
if (depth > maxDepth || rows.length >= maxRows) return;
|
|
36304
|
-
for (let index = 0; index < items.length && rows.length < maxRows; index += 1) {
|
|
36305
|
-
const variable = items[index];
|
|
36306
|
-
const key = prefix + "/" + index + ":" + variable.name;
|
|
36307
|
-
rows.push({
|
|
36308
|
-
key,
|
|
36309
|
-
variable,
|
|
36310
|
-
depth
|
|
36311
|
-
});
|
|
36312
|
-
if (variable.ref <= 0 || !expanded.has(variable.ref) || ancestry.has(variable.ref)) continue;
|
|
36313
|
-
const children = cache.get(variable.ref);
|
|
36314
|
-
if (!children?.length) continue;
|
|
36315
|
-
const nextAncestry = new Set(ancestry);
|
|
36316
|
-
nextAncestry.add(variable.ref);
|
|
36317
|
-
walk(children, depth + 1, nextAncestry, key);
|
|
36318
|
-
}
|
|
36319
|
-
};
|
|
36320
|
-
walk(roots, 0, /* @__PURE__ */ new Set(), "root");
|
|
36321
|
-
return rows;
|
|
36322
|
-
}
|
|
36323
|
-
//#endregion
|
|
36324
|
-
//#region src/client/dap/bpRowMenu.ts
|
|
36325
|
-
/**
|
|
36326
|
-
* 构造调试面板断点行右键菜单条目。
|
|
36327
|
-
* @author ddj 2026年09月21号
|
|
36328
|
-
* @param state 行内断点状态
|
|
36329
|
-
* @returns 菜单条目列表(顺序即展示顺序)
|
|
36330
|
-
*/
|
|
36331
|
-
function buildBpRowMenu(state) {
|
|
36332
|
-
return [
|
|
36333
|
-
{
|
|
36334
|
-
id: "edit",
|
|
36335
|
-
label: "编辑断点…"
|
|
36336
|
-
},
|
|
36337
|
-
{
|
|
36338
|
-
id: "edit-condition",
|
|
36339
|
-
label: "编辑条件…"
|
|
36340
|
-
},
|
|
36341
|
-
{
|
|
36342
|
-
id: "edit-hit-count",
|
|
36343
|
-
label: "编辑命中次数…"
|
|
36344
|
-
},
|
|
36345
|
-
{
|
|
36346
|
-
id: "edit-logpoint",
|
|
36347
|
-
label: "编辑记录点…"
|
|
36348
|
-
},
|
|
36349
|
-
state.enabled !== false ? {
|
|
36350
|
-
id: "disable",
|
|
36351
|
-
label: "禁用断点",
|
|
36352
|
-
separator: true
|
|
36353
|
-
} : {
|
|
36354
|
-
id: "enable",
|
|
36355
|
-
label: "启用断点",
|
|
36356
|
-
separator: true
|
|
36357
|
-
},
|
|
36358
|
-
{
|
|
36359
|
-
id: "remove",
|
|
36360
|
-
label: "删除断点"
|
|
36361
|
-
}
|
|
36362
|
-
];
|
|
36363
|
-
}
|
|
36364
|
-
//#endregion
|
|
36365
|
-
//#region src/client/dap/panelSplit.ts
|
|
36366
|
-
/**
|
|
36367
|
-
* dsh-vscode-mode client — 调试面板四段分栏高度(纯函数 + localStorage 持久)。
|
|
36368
|
-
* 对齐 VS Code/CodeBuddy splitview 语义:段间 sash 拖动时相邻两段高度重分配
|
|
36369
|
-
* (拖下 = 上段增高、下段减矮;任一段触到夹取界时拖动量被"吸收",分隔条停在可行位置)。
|
|
36370
|
-
* 存储:`edrv.dap.split.<scope>` → { variables, watch, stack, breakpoints }。
|
|
36371
|
-
* 作者 ddj 2026年09月21号
|
|
36372
|
-
*/
|
|
36373
|
-
/** 分栏段 key(与 DebugPanel section key 一致)。 */
|
|
36374
|
-
const SPLIT_KEYS = [
|
|
36375
|
-
"variables",
|
|
36376
|
-
"watch",
|
|
36377
|
-
"stack",
|
|
36378
|
-
"breakpoints"
|
|
36379
|
-
];
|
|
36380
|
-
/** 默认高度(沿用重构前各段 max-height 值,改前改后视觉一致)。 */
|
|
36381
|
-
const DEFAULT_HEIGHTS = {
|
|
36382
|
-
variables: 360,
|
|
36383
|
-
watch: 220,
|
|
36384
|
-
stack: 180,
|
|
36385
|
-
breakpoints: 260
|
|
36386
|
-
};
|
|
36387
|
-
/** 单段最大高度(防无限拖爆面板)。 */
|
|
36388
|
-
const MAX_H = 1200;
|
|
36389
|
-
/** localStorage key 前缀。 */
|
|
36390
|
-
const KEY_PREFIX = "edrv.dap.split.";
|
|
36391
|
-
/**
|
|
36392
|
-
* 夹取单段高度到 [MIN_H, MAX_H](非有限数回退最小值)。
|
|
36393
|
-
* @author ddj 2026年09月21号
|
|
36394
|
-
* @param px 目标高度
|
|
36395
|
-
*/
|
|
36396
|
-
function clampSectionHeight(px) {
|
|
36397
|
-
if (!Number.isFinite(px)) return 64;
|
|
36398
|
-
return Math.min(MAX_H, Math.max(64, Math.round(px)));
|
|
36399
|
-
}
|
|
36400
|
-
/**
|
|
36401
|
-
* 归一化高度表:非对象/缺 key 回退默认,非法值丢弃(损坏安全)。
|
|
36402
|
-
* @author ddj 2026年09月21号
|
|
36403
|
-
* @param input localStorage 解析结果
|
|
36404
|
-
*/
|
|
36405
|
-
function sanitizeHeights(input) {
|
|
36406
|
-
const out = { ...DEFAULT_HEIGHTS };
|
|
36407
|
-
if (!input || typeof input !== "object" || Array.isArray(input)) return out;
|
|
36408
|
-
const data = input;
|
|
36409
|
-
for (const key of SPLIT_KEYS) {
|
|
36410
|
-
const value = data[key];
|
|
36411
|
-
if (typeof value === "number" && Number.isFinite(value)) out[key] = clampSectionHeight(value);
|
|
36412
|
-
}
|
|
36413
|
-
return out;
|
|
36414
|
-
}
|
|
36415
|
-
/**
|
|
36416
|
-
* 相邻两段高度重分配:above += dy、below −= dy,各自夹取;
|
|
36417
|
-
* 一段被夹取吸收的量补给另一段(分隔条停在可行位置,拖动量尽量生效)。
|
|
36418
|
-
* @author ddj 2026年09月21号
|
|
36419
|
-
* @param heights 拖动起点高度表(不修改入参)
|
|
36420
|
-
* @param above 上邻段 key
|
|
36421
|
-
* @param below 下邻段 key
|
|
36422
|
-
* @param dy 拖动位移(>0 向下拖 = 上段增高)
|
|
36423
|
-
* @returns 新高度表
|
|
36424
|
-
*/
|
|
36425
|
-
function redistribute(heights, above, below, dy) {
|
|
36426
|
-
const clean = Math.round(Number.isFinite(dy) ? dy : 0);
|
|
36427
|
-
const next = { ...heights };
|
|
36428
|
-
const startAbove = heights[above] ?? 64;
|
|
36429
|
-
const startBelow = heights[below] ?? 64;
|
|
36430
|
-
const targetAbove = clampSectionHeight(startAbove + clean);
|
|
36431
|
-
const targetBelow = clampSectionHeight(startBelow - clean);
|
|
36432
|
-
next[above] = targetAbove;
|
|
36433
|
-
next[below] = targetBelow;
|
|
36434
|
-
const lostAbove = startAbove + clean - targetAbove;
|
|
36435
|
-
const lostBelow = startBelow - clean - targetBelow;
|
|
36436
|
-
if (lostAbove > 0) next[below] = clampSectionHeight(targetBelow + lostAbove);
|
|
36437
|
-
else if (lostBelow > 0) next[above] = clampSectionHeight(targetAbove + lostBelow);
|
|
36438
|
-
return next;
|
|
36439
|
-
}
|
|
36440
|
-
/**
|
|
36441
|
-
* 读高度表(缺失/损坏回退默认值)。
|
|
36442
|
-
* @author ddj 2026年09月21号
|
|
36443
|
-
* @param scope 状态作用域
|
|
36444
|
-
*/
|
|
36445
|
-
function loadSectionHeights(scope) {
|
|
36446
|
-
if (!scope) return { ...DEFAULT_HEIGHTS };
|
|
36447
|
-
try {
|
|
36448
|
-
const raw = localStorage.getItem(KEY_PREFIX + scope);
|
|
36449
|
-
return sanitizeHeights(raw ? JSON.parse(raw) : null);
|
|
36450
|
-
} catch {
|
|
36451
|
-
return { ...DEFAULT_HEIGHTS };
|
|
36452
|
-
}
|
|
36453
|
-
}
|
|
36454
|
-
/**
|
|
36455
|
-
* 写高度表(写失败静默;写入前归一化)。
|
|
36456
|
-
* @author ddj 2026年09月21号
|
|
36457
|
-
* @param scope 状态作用域
|
|
36458
|
-
* @param heights 高度表
|
|
36459
|
-
*/
|
|
36460
|
-
function saveSectionHeights(scope, heights) {
|
|
36461
|
-
try {
|
|
36462
|
-
localStorage.setItem(KEY_PREFIX + scope, JSON.stringify(sanitizeHeights(heights)));
|
|
36463
|
-
} catch {}
|
|
36464
|
-
}
|
|
36465
|
-
//#endregion
|
|
36466
|
-
//#region src/client/sidebar/panels/DebugPanel.ts
|
|
36467
|
-
/**
|
|
36468
|
-
* dsh-vscode-mode client — 侧边栏「调试」面板(对齐 CodeBuddy「运行和调试」视图)。
|
|
36469
|
-
* 顶部工具条:配置下拉 + 启动/继续 + 暂停 + 单步组 + 停止(禁用逻辑镜像编辑器浮动条)。
|
|
36470
|
-
* 四段折叠区(变量 / 监视 / 调用堆栈 / 断点,图2 顺序)+ 底部调试控制台(REPL);
|
|
36471
|
-
* 每段头部可折叠(状态按 scope 持久化)且带悬浮动作按钮。
|
|
36472
|
-
* 断点多方式管理(对齐 CodeBuddy 断点区):段头「新建断点」菜单(条件断点/记录点,
|
|
36473
|
-
* 落在活动编辑器光标行)、禁用/启用所有、删除所有;断点行右键菜单(编辑条件/命中次数/
|
|
36474
|
-
* 记录点/启停/删除)→ 行内展开编辑器(Enter 提交 / Escape 取消,字段语义同 BpWidget);
|
|
36475
|
-
* 行内点展示适配器回执(未验证 = 空心点 + tooltip)。
|
|
36476
|
-
* 数据自取:paused 时经 dapStore 拉栈/作用域/变量/监视求值;断点读写 dapStore 断点表;
|
|
36477
|
-
* 输出流 = host poll 事件缓存(outputs)。host 不可达或未暂停时各段空态降级。
|
|
36478
|
-
* 断点行整行可点:除启停 checkbox 与删除 × 外,点击任一处即打开并定位到该断点行。
|
|
36479
|
-
* 作者 ddj 2026年09月29号 / 2026年09月21号
|
|
36480
|
-
*/
|
|
36481
|
-
/** 变量展开缓存上限(ref → 子级;防长会话累积)。 */
|
|
36482
|
-
const VAR_CACHE_CAP = 200;
|
|
36483
|
-
/** REPL 历史行上限。 */
|
|
36484
|
-
const REPL_CAP = 200;
|
|
36485
|
-
/** 监视持久化 key 前缀(CACHE_KEY 无调试段,自管命名空间)。 */
|
|
36486
|
-
const WATCH_KEY = "edrv.dap.watch.";
|
|
36487
|
-
/** 段折叠持久化 key 前缀(存折叠段名数组;损坏安全,默认全展开)。 */
|
|
36488
|
-
const FOLD_KEY = "edrv.dap.fold.";
|
|
36489
|
-
/** 调试配置文件(工作区相对路径;⚙ 按钮跳转/新建目标;与 VS Code 的 .vscode/launch.json 互不干扰)。 */
|
|
36490
|
-
const LAUNCH_REL = DAP_LAUNCH_REL;
|
|
36491
|
-
/** 新建调试配置模板(JSONC;示例按本机已装的 EmmyLua 适配器写)。 */
|
|
36492
|
-
const LAUNCH_TEMPLATE = `{
|
|
36493
|
-
// DSH 调试配置(插件专属 .dsh/launch.json,支持注释;改完整页刷新生效)
|
|
36494
|
-
// type 来自本机已装扩展的 contributes.debuggers(EmmyLua:emmylua_attach / emmylua_launch / emmylua_new)
|
|
36495
|
-
"version": "0.2.0",
|
|
36496
|
-
"configurations": [
|
|
36497
|
-
{
|
|
36498
|
-
"name": "附加 Unity (xLua)",
|
|
36499
|
-
"type": "emmylua_attach",
|
|
36500
|
-
"request": "attach",
|
|
36501
|
-
"processName": "Unity",
|
|
36502
|
-
"captureLog": true
|
|
36503
|
-
}
|
|
36504
|
-
]
|
|
36505
|
-
}`;
|
|
36506
|
-
/** 相位徽标文案。 */
|
|
36507
|
-
const PHASE_LABEL = {
|
|
36508
|
-
idle: "未启动",
|
|
36509
|
-
starting: "启动中…",
|
|
36510
|
-
waiting: "等待目标…",
|
|
36511
|
-
running: "运行中",
|
|
36512
|
-
paused: "已暂停",
|
|
36513
|
-
terminated: "已结束"
|
|
36514
|
-
};
|
|
36515
|
-
/** 读取监视表达式列表(损坏安全)。 */
|
|
36516
|
-
function loadWatches(scope) {
|
|
36517
|
-
if (!scope) return [];
|
|
36518
|
-
try {
|
|
36519
|
-
const raw = window.localStorage.getItem(WATCH_KEY + scope);
|
|
36520
|
-
const list = raw ? JSON.parse(raw) : [];
|
|
36521
|
-
return Array.isArray(list) ? list.filter((item) => typeof item === "string" && item.trim()) : [];
|
|
36522
|
-
} catch {
|
|
36523
|
-
return [];
|
|
36524
|
-
}
|
|
36525
|
-
}
|
|
36526
|
-
/** 写监视表达式列表。 */
|
|
36527
|
-
function saveWatches(scope, list) {
|
|
36528
|
-
try {
|
|
36529
|
-
window.localStorage.setItem(WATCH_KEY + scope, JSON.stringify(list));
|
|
36530
|
-
} catch {}
|
|
36531
|
-
}
|
|
36532
|
-
/** 读折叠段名列表(损坏安全;非字符串项丢弃)。 */
|
|
36533
|
-
function loadFolds(scope) {
|
|
36534
|
-
if (!scope) return [];
|
|
36535
|
-
try {
|
|
36536
|
-
const raw = window.localStorage.getItem(FOLD_KEY + scope);
|
|
36537
|
-
const list = raw ? JSON.parse(raw) : [];
|
|
36538
|
-
return Array.isArray(list) ? list.filter((item) => typeof item === "string" && item) : [];
|
|
36539
|
-
} catch {
|
|
36540
|
-
return [];
|
|
36541
|
-
}
|
|
36542
|
-
}
|
|
36543
|
-
/** 写折叠段名列表(写失败静默)。 */
|
|
36544
|
-
function saveFolds(scope, list) {
|
|
36545
|
-
try {
|
|
36546
|
-
window.localStorage.setItem(FOLD_KEY + scope, JSON.stringify(list));
|
|
36547
|
-
} catch {}
|
|
36548
|
-
}
|
|
36549
|
-
/**
|
|
36550
|
-
* 「调试」面板组件。
|
|
36551
|
-
* @param ctx 侧栏上下文(openFileAt 跳转 / scope 持久化 / cwd / editor 光标)
|
|
36552
|
-
*/
|
|
36553
|
-
function DebugPanel({ ctx }) {
|
|
36554
|
-
const scope = ctx?.scope || "";
|
|
36555
|
-
const [, setTick] = react.default.useState(0);
|
|
36556
|
-
react.default.useEffect(() => dapStore.subscribe(() => setTick((t) => t + 1)), []);
|
|
36557
|
-
const snap = dapStore.getSnapshot();
|
|
36558
|
-
const paused = snap.phase === "paused";
|
|
36559
|
-
const dapActive = snap.phase !== "idle" && snap.phase !== "terminated";
|
|
36560
|
-
const [stacks, setStacks] = react.default.useState([]);
|
|
36561
|
-
const [scopes, setScopes] = react.default.useState([]);
|
|
36562
|
-
const [varCache, setVarCache] = react.default.useState(() => /* @__PURE__ */ new Map());
|
|
36563
|
-
const [expanded, setExpanded] = react.default.useState(() => /* @__PURE__ */ new Set());
|
|
36564
|
-
const [watches, setWatches] = react.default.useState(() => loadWatches(scope));
|
|
36565
|
-
const [watchHits, setWatchHits] = react.default.useState({});
|
|
36566
|
-
const [watchDraft, setWatchDraft] = react.default.useState("");
|
|
36567
|
-
const [replLog, setReplLog] = react.default.useState([]);
|
|
36568
|
-
const [replDraft, setReplDraft] = react.default.useState("");
|
|
36569
|
-
const [folds, setFolds] = react.default.useState(() => new Set(loadFolds(scope)));
|
|
36570
|
-
const [heights, setHeights] = react.default.useState(() => loadSectionHeights(scope));
|
|
36571
|
-
const [splitDragging, setSplitDragging] = react.default.useState(false);
|
|
36572
|
-
const [bpMenu, setBpMenu] = react.default.useState(null);
|
|
36573
|
-
const [newBpMenu, setNewBpMenu] = react.default.useState(null);
|
|
36574
|
-
const [bpEdit, setBpEdit] = react.default.useState(null);
|
|
36575
|
-
const [pickPid, setPickPid] = react.default.useState(0);
|
|
36576
|
-
const watchInputRef = react.default.useRef(null);
|
|
36577
|
-
const stackTopKey = paused && snap.topFrame ? snap.topFrame.file + ":" + snap.topFrame.line : "";
|
|
36578
|
-
react.default.useEffect(() => {
|
|
36579
|
-
if (!ctx?.cwd) return;
|
|
36580
|
-
dapStore.setWorkspace(ctx.cwd);
|
|
36581
|
-
dapStore.ensureConfigs();
|
|
36582
|
-
}, [ctx?.cwd]);
|
|
36583
|
-
const [reloadTick, setReloadTick] = react.default.useState(0);
|
|
36584
|
-
react.default.useEffect(() => {
|
|
36585
|
-
if (!paused) {
|
|
36586
|
-
setStacks([]);
|
|
36587
|
-
setScopes([]);
|
|
36588
|
-
setVarCache(/* @__PURE__ */ new Map());
|
|
36589
|
-
setExpanded(/* @__PURE__ */ new Set());
|
|
36590
|
-
setWatchHits({});
|
|
36591
|
-
return;
|
|
36592
|
-
}
|
|
36593
|
-
let alive = true;
|
|
36594
|
-
const load = async () => {
|
|
36595
|
-
const frames = await dapStore.stackTrace();
|
|
36596
|
-
if (!alive) return;
|
|
36597
|
-
setStacks(frames);
|
|
36598
|
-
const list = await dapStore.scopes(snap.selectedFrameId);
|
|
36599
|
-
if (!alive) return;
|
|
36600
|
-
setScopes(list);
|
|
36601
|
-
const first = list[0];
|
|
36602
|
-
if (first?.ref) {
|
|
36603
|
-
const vars = await dapStore.variables(first.ref);
|
|
36604
|
-
if (!alive) return;
|
|
36605
|
-
setVarCache((prev) => new Map(prev).set(first.ref, vars));
|
|
36606
|
-
setExpanded((prev) => new Set(prev).add(first.ref));
|
|
36607
|
-
}
|
|
36608
|
-
const hits = {};
|
|
36609
|
-
for (const expr of watches) hits[expr] = await dapStore.evaluate(expr, snap.selectedFrameId);
|
|
36610
|
-
if (alive) setWatchHits(hits);
|
|
36611
|
-
};
|
|
36612
|
-
load();
|
|
36613
|
-
return () => {
|
|
36614
|
-
alive = false;
|
|
36615
|
-
};
|
|
36616
|
-
}, [
|
|
36617
|
-
paused,
|
|
36618
|
-
stackTopKey,
|
|
36619
|
-
snap.selectedFrameId,
|
|
36620
|
-
watches,
|
|
36621
|
-
reloadTick
|
|
36622
|
-
]);
|
|
36623
|
-
const expandVar = async (ref) => {
|
|
36624
|
-
setExpanded((prev) => {
|
|
36625
|
-
const next = new Set(prev);
|
|
36626
|
-
if (next.has(ref)) next.delete(ref);
|
|
36627
|
-
else next.add(ref);
|
|
36628
|
-
return next;
|
|
36629
|
-
});
|
|
36630
|
-
if (!varCache.has(ref)) {
|
|
36631
|
-
const vars = await dapStore.variables(ref);
|
|
36632
|
-
setVarCache((prev) => {
|
|
36633
|
-
const next = new Map(prev);
|
|
36634
|
-
next.set(ref, vars);
|
|
36635
|
-
if (next.size > VAR_CACHE_CAP) next.delete(next.keys().next().value);
|
|
36636
|
-
return next;
|
|
36637
|
-
});
|
|
36638
|
-
}
|
|
36639
|
-
};
|
|
36640
|
-
const addWatch = () => {
|
|
36641
|
-
const expr = watchDraft.trim();
|
|
36642
|
-
if (!expr || watches.includes(expr)) {
|
|
36643
|
-
setWatchDraft("");
|
|
36644
|
-
return;
|
|
36645
|
-
}
|
|
36646
|
-
const next = [...watches, expr];
|
|
36647
|
-
setWatches(next);
|
|
36648
|
-
saveWatches(scope, next);
|
|
36649
|
-
setWatchDraft("");
|
|
36650
|
-
if (paused) dapStore.evaluate(expr, snap.selectedFrameId).then((r) => setWatchHits((prev) => ({
|
|
36651
|
-
...prev,
|
|
36652
|
-
[expr]: r
|
|
36653
|
-
})));
|
|
36654
|
-
};
|
|
36655
|
-
const removeWatch = (expr) => {
|
|
36656
|
-
const next = watches.filter((item) => item !== expr);
|
|
36657
|
-
setWatches(next);
|
|
36658
|
-
saveWatches(scope, next);
|
|
36659
|
-
};
|
|
36660
|
-
/** 移除全部监视(段头动作;持久化与命中缓存同步清)。 */
|
|
36661
|
-
const clearWatches = () => {
|
|
36662
|
-
setWatches([]);
|
|
36663
|
-
saveWatches(scope, []);
|
|
36664
|
-
setWatchHits({});
|
|
36665
|
-
};
|
|
36666
|
-
/** 聚焦监视新增输入(段折叠时先展开,二次点击聚焦)。 */
|
|
36667
|
-
const focusWatchInput = () => {
|
|
36668
|
-
if (folds.has("watch")) {
|
|
36669
|
-
toggleFold("watch");
|
|
36670
|
-
return;
|
|
36671
|
-
}
|
|
36672
|
-
watchInputRef.current?.focus?.();
|
|
36673
|
-
};
|
|
36674
|
-
const runRepl = async () => {
|
|
36675
|
-
const expr = replDraft.trim();
|
|
36676
|
-
if (!expr) return;
|
|
36677
|
-
setReplDraft("");
|
|
36678
|
-
const r = await dapStore.evaluate(expr, snap.selectedFrameId);
|
|
36679
|
-
setReplLog((prev) => {
|
|
36680
|
-
const next = [...prev, {
|
|
36681
|
-
expr,
|
|
36682
|
-
result: r.result,
|
|
36683
|
-
type: r.type
|
|
36684
|
-
}];
|
|
36685
|
-
return next.length > REPL_CAP ? next.slice(next.length - REPL_CAP) : next;
|
|
36686
|
-
});
|
|
36687
|
-
};
|
|
36688
|
-
/** 切换段折叠(持久化到 localStorage)。 */
|
|
36689
|
-
const toggleFold = (key) => {
|
|
36690
|
-
setFolds((prev) => {
|
|
36691
|
-
const next = new Set(prev);
|
|
36692
|
-
if (next.has(key)) next.delete(key);
|
|
36693
|
-
else next.add(key);
|
|
36694
|
-
saveFolds(scope, [...next]);
|
|
36695
|
-
return next;
|
|
36696
|
-
});
|
|
36697
|
-
};
|
|
36698
|
-
const splitCleanupRef = react.default.useRef(null);
|
|
36699
|
-
react.default.useEffect(() => () => {
|
|
36700
|
-
const cleanup = splitCleanupRef.current;
|
|
36701
|
-
if (cleanup) cleanup();
|
|
36702
|
-
}, []);
|
|
36703
|
-
/** 段间 sash 拖动:以起点高度为基准按 dy 相邻重分配;pointerup 持久化(镜像 dapbar 拖动模式)。 */
|
|
36704
|
-
const startSplitDrag = (above, below) => (e) => {
|
|
36705
|
-
e.preventDefault();
|
|
36706
|
-
const startY = e.clientY;
|
|
36707
|
-
const startHeights = { ...heights };
|
|
36708
|
-
const onMove = (ev) => {
|
|
36709
|
-
setHeights(redistribute(startHeights, above, below, ev.clientY - startY));
|
|
36710
|
-
};
|
|
36711
|
-
const detach = () => {
|
|
36712
|
-
window.removeEventListener("pointermove", onMove);
|
|
36713
|
-
window.removeEventListener("pointerup", onUp);
|
|
36714
|
-
splitCleanupRef.current = null;
|
|
36715
|
-
setSplitDragging(false);
|
|
36716
|
-
};
|
|
36717
|
-
const onUp = () => {
|
|
36718
|
-
detach();
|
|
36719
|
-
setHeights((prev) => {
|
|
36720
|
-
saveSectionHeights(scope, prev);
|
|
36721
|
-
return prev;
|
|
36722
|
-
});
|
|
36723
|
-
};
|
|
36724
|
-
splitCleanupRef.current = detach;
|
|
36725
|
-
window.addEventListener("pointermove", onMove);
|
|
36726
|
-
window.addEventListener("pointerup", onUp);
|
|
36727
|
-
setSplitDragging(true);
|
|
36728
|
-
};
|
|
36729
|
-
const cwd = ctx?.cwd || dapStore.workspace();
|
|
36730
|
-
const bpMap = dapStore.bpMapOf(scope);
|
|
36731
|
-
const bpRows = Object.entries(bpMap).flatMap(([path, list]) => list.map((entry) => ({
|
|
36732
|
-
path,
|
|
36733
|
-
entry
|
|
36734
|
-
}))).sort((a, b) => a.path.localeCompare(b.path) || a.entry.line - b.entry.line);
|
|
36735
|
-
const allBpEnabled = bpRows.length > 0 && bpRows.every((row) => row.entry.enabled);
|
|
36736
|
-
const toggleBpEnabled = (row) => dapStore.setBpEnabled(scope, cwd, row.path, row.entry.line, !row.entry.enabled);
|
|
36737
|
-
const removeBp = (row) => dapStore.toggleAt(scope, cwd, row.path, row.entry.line);
|
|
36738
|
-
/** 删除所有断点(confirm 守卫;逐文件同步空载荷清空 Monaco 装饰与 host 断点)。 */
|
|
36739
|
-
const removeAllBps = () => {
|
|
36740
|
-
if (ctx?.confirm && !ctx.confirm("删除所有断点?")) return;
|
|
36741
|
-
dapStore.removeAllBps(scope, cwd);
|
|
36742
|
-
setBpEdit(null);
|
|
36743
|
-
};
|
|
36744
|
-
const jumpBp = (row) => {
|
|
36745
|
-
const target = bpJumpTargetOf(row);
|
|
36746
|
-
if (target) ctx?.openFileAt?.(target.path, target.line, target.column);
|
|
36747
|
-
};
|
|
36748
|
-
const autoBpModeOf = (entry) => entry?.logMessage ? BP_MODE.LOG_MESSAGE : entry?.hitCondition ? BP_MODE.HIT_COUNT : BP_MODE.EXPRESSION;
|
|
36749
|
-
const openBpRowEditor = (path, line, entry, mode) => {
|
|
36750
|
-
setBpEdit({
|
|
36751
|
-
path,
|
|
36752
|
-
line,
|
|
36753
|
-
mode: typeof mode === "number" ? mode : autoBpModeOf(entry),
|
|
36754
|
-
drafts: {
|
|
36755
|
-
condition: entry?.condition || "",
|
|
36756
|
-
hitCondition: entry?.hitCondition || "",
|
|
36757
|
-
logMessage: entry?.logMessage || ""
|
|
36758
|
-
}
|
|
36759
|
-
});
|
|
36760
|
-
};
|
|
36761
|
-
const commitBpEdit = () => {
|
|
36762
|
-
if (!bpEdit) return;
|
|
36763
|
-
dapStore.applyBpFields(scope, cwd, bpEdit.path, bpEdit.line, { ...bpEdit.drafts });
|
|
36764
|
-
setBpEdit(null);
|
|
36765
|
-
ctx?.notify?.("断点已更新");
|
|
36766
|
-
};
|
|
36767
|
-
/** 断点行右键菜单动作分发(菜单数据由 buildBpRowMenu 产出)。 */
|
|
36768
|
-
const runBpRowAction = (action, row) => {
|
|
36769
|
-
if (action === "remove") {
|
|
36770
|
-
removeBp(row);
|
|
36771
|
-
return;
|
|
36772
|
-
}
|
|
36773
|
-
if (action === "enable" || action === "disable") {
|
|
36774
|
-
dapStore.setBpEnabled(scope, cwd, row.path, row.entry.line, action === "enable");
|
|
36775
|
-
return;
|
|
36776
|
-
}
|
|
36777
|
-
const mode = action === "edit-condition" ? BP_MODE.EXPRESSION : action === "edit-hit-count" ? BP_MODE.HIT_COUNT : action === "edit-logpoint" ? BP_MODE.LOG_MESSAGE : void 0;
|
|
36778
|
-
openBpRowEditor(row.path, row.entry.line, row.entry, mode);
|
|
36779
|
-
};
|
|
36780
|
-
/** 段头「新建断点」:条件断点/记录点落在活动编辑器光标行(已有断点则直接编辑不翻转)。 */
|
|
36781
|
-
const addBpAtCursor = (mode) => {
|
|
36782
|
-
const ed = ctx?.editor?.();
|
|
36783
|
-
const path = editorModelPathOf(ed);
|
|
36784
|
-
const line = ed?.getPosition?.()?.lineNumber;
|
|
36785
|
-
if (!path || !line || !Number.isFinite(line)) {
|
|
36786
|
-
ctx?.notify?.("无活动文件,无法添加断点");
|
|
36787
|
-
return;
|
|
36788
|
-
}
|
|
36789
|
-
if (!(dapStore.bpMapOf(scope)[path] ?? []).find((it) => it.line === line)) dapStore.toggleAt(scope, cwd, path, line);
|
|
36790
|
-
const entry = (dapStore.bpMapOf(scope)[path] ?? []).find((it) => it.line === line);
|
|
36791
|
-
if (entry) openBpRowEditor(path, line, entry, mode);
|
|
36792
|
-
};
|
|
36793
|
-
/** ⚙ 打开/新建调试配置:存在即跳转;缺失经确认后写模板(edrv.save 无 rev 仅用于新建,绝不覆盖已有文件)。 */
|
|
36794
|
-
const openLaunchConfig = async () => {
|
|
36795
|
-
if (!ctx?.cwd) {
|
|
36796
|
-
ctx?.notify?.("无工作区,无法定位 " + LAUNCH_REL);
|
|
36797
|
-
return;
|
|
36798
|
-
}
|
|
36799
|
-
try {
|
|
36800
|
-
if ((await rpc("edrv.read", {
|
|
36801
|
-
sessionId: ctx?.sessionId,
|
|
36802
|
-
path: LAUNCH_REL
|
|
36803
|
-
}).catch(() => null))?.ok) {
|
|
36804
|
-
ctx?.openFile?.(LAUNCH_REL);
|
|
36805
|
-
return;
|
|
36806
|
-
}
|
|
36807
|
-
} catch {}
|
|
36808
|
-
if (ctx?.confirm && !ctx.confirm("未找到 " + LAUNCH_REL + ",是否创建调试配置模板?")) return;
|
|
36809
|
-
try {
|
|
36810
|
-
const saved = await rpc("edrv.save", {
|
|
36811
|
-
sessionId: ctx?.sessionId,
|
|
36812
|
-
path: LAUNCH_REL,
|
|
36813
|
-
content: LAUNCH_TEMPLATE
|
|
36814
|
-
});
|
|
36815
|
-
if (!saved?.ok) {
|
|
36816
|
-
ctx?.notify?.(saved?.error || "创建 " + LAUNCH_REL + " 失败");
|
|
36817
|
-
return;
|
|
36818
|
-
}
|
|
36819
|
-
dapStore.ensureConfigs(true);
|
|
36820
|
-
ctx?.openFile?.(LAUNCH_REL);
|
|
36821
|
-
ctx?.notify?.("已创建 " + LAUNCH_REL);
|
|
36822
|
-
} catch (error) {
|
|
36823
|
-
ctx?.notify?.("创建 " + LAUNCH_REL + " 失败:" + String(error));
|
|
36824
|
-
}
|
|
36825
|
-
};
|
|
36826
|
-
/** 段头动作按钮(hover 显隐,样式见 .edrv-dapseg-act)。 */
|
|
36827
|
-
const segAct = (key, label, title, onClick) => react.default.createElement("button", {
|
|
36828
|
-
key,
|
|
36829
|
-
className: "edrv-dapseg-act",
|
|
36830
|
-
title,
|
|
36831
|
-
onClick: (e) => {
|
|
36832
|
-
e.stopPropagation();
|
|
36833
|
-
onClick(e);
|
|
36834
|
-
}
|
|
36835
|
-
}, label);
|
|
36836
|
-
/** 折叠段壳:chevron + 标题 + 悬浮动作区 + 可折叠主体(高度由分栏 state 内联接管)。 */
|
|
36837
|
-
const section = (title, key, variant, actions, children) => {
|
|
36838
|
-
const folded = folds.has(key);
|
|
36839
|
-
return react.default.createElement("div", {
|
|
36840
|
-
className: "edrv-dapseg edrv-dapseg-" + variant,
|
|
36841
|
-
key
|
|
36842
|
-
}, react.default.createElement("div", {
|
|
36843
|
-
className: "edrv-dapseg-head",
|
|
36844
|
-
onClick: () => toggleFold(key)
|
|
36845
|
-
}, react.default.createElement("span", {
|
|
36846
|
-
className: "edrv-dapseg-chevron",
|
|
36847
|
-
title: folded ? "展开" : "折叠"
|
|
36848
|
-
}, folded ? "▸" : "▾"), react.default.createElement("span", { className: "edrv-dapseg-title" }, title), react.default.createElement("span", { style: { flex: 1 } }), ...folded ? [] : actions || []), ...folded ? [] : [react.default.createElement("div", {
|
|
36849
|
-
className: "edrv-dapseg-body",
|
|
36850
|
-
style: { height: (heights[key] ?? 200) + "px" }
|
|
36851
|
-
}, ...children)]);
|
|
36852
|
-
};
|
|
36853
|
-
/** 段间分隔条(两侧段都展开时才渲染;拖动调整相邻两段高度占比)。 */
|
|
36854
|
-
const sash = (above, below) => folds.has(above) || folds.has(below) ? null : react.default.createElement("div", {
|
|
36855
|
-
key: "sash-" + above + "-" + below,
|
|
36856
|
-
className: "edrv-dapseg-sash" + (splitDragging ? " dragging" : ""),
|
|
36857
|
-
title: "拖动调整上下两段高度占比",
|
|
36858
|
-
onPointerDown: startSplitDrag(above, below)
|
|
36859
|
-
});
|
|
36860
|
-
const renderVarRow = (row) => {
|
|
36861
|
-
const v = row.variable;
|
|
36862
|
-
const depth = row.depth + 1;
|
|
36863
|
-
return react.default.createElement("div", {
|
|
36864
|
-
key: row.key,
|
|
36865
|
-
className: "edrv-dapvar",
|
|
36866
|
-
style: { paddingLeft: 8 + depth * 12 }
|
|
36867
|
-
}, v.ref > 0 ? react.default.createElement("button", {
|
|
36868
|
-
className: "edrv-dapvar-tw",
|
|
36869
|
-
title: expanded.has(v.ref) ? "折叠" : "展开",
|
|
36870
|
-
onClick: () => {
|
|
36871
|
-
expandVar(v.ref);
|
|
36872
|
-
}
|
|
36873
|
-
}, expanded.has(v.ref) ? "▾" : "▸") : react.default.createElement("span", { className: "edrv-dapvar-tw" }, ""), react.default.createElement("span", {
|
|
36874
|
-
className: "edrv-dapvar-name",
|
|
36875
|
-
title: v.name
|
|
36876
|
-
}, v.name), react.default.createElement("span", {
|
|
36877
|
-
className: "edrv-dapvar-val",
|
|
36878
|
-
title: v.value
|
|
36879
|
-
}, v.value), v.type ? react.default.createElement("span", { className: "edrv-dapvar-type" }, v.type) : null);
|
|
36880
|
-
};
|
|
36881
|
-
const stackRows = stacks.length ? stacks.map((f) => react.default.createElement("div", {
|
|
36882
|
-
key: f.id,
|
|
36883
|
-
className: "edrv-dapframe" + (f.id === snap.selectedFrameId ? " selected" : ""),
|
|
36884
|
-
title: f.rawFile,
|
|
36885
|
-
onClick: () => {
|
|
36886
|
-
dapStore.selectFrame(f.id);
|
|
36887
|
-
const target = f.file || f.rawFile;
|
|
36888
|
-
if (target) ctx?.openFileAt?.(target, f.line, 1);
|
|
36889
|
-
}
|
|
36890
|
-
}, react.default.createElement("span", { className: "edrv-dapframe-name" }, f.name || "(anonymous)"), react.default.createElement("span", { className: "edrv-dapframe-loc" }, (f.file || f.rawFile) + ":" + f.line))) : [react.default.createElement("div", {
|
|
36891
|
-
key: "empty",
|
|
36892
|
-
className: "edrv-dapempty"
|
|
36893
|
-
}, paused ? "(无调用栈)" : "暂停时显示调用堆栈")];
|
|
36894
|
-
const scopeRows = scopes.flatMap((s) => [react.default.createElement("div", {
|
|
36895
|
-
key: "scope" + s.name,
|
|
36896
|
-
className: "edrv-dapscope"
|
|
36897
|
-
}, s.name), ...flattenVariableRows(varCache.get(s.ref) ?? [], expanded, varCache, { maxRows: 800 }).map(renderVarRow)]);
|
|
36898
|
-
const varRows = scopes.length ? scopeRows : [react.default.createElement("div", {
|
|
36899
|
-
key: "e",
|
|
36900
|
-
className: "edrv-dapempty"
|
|
36901
|
-
}, "暂停时显示变量")];
|
|
36902
|
-
const watchRows = watches.flatMap((expr) => {
|
|
36903
|
-
const hit = watchHits[expr];
|
|
36904
|
-
const rows = [react.default.createElement("div", {
|
|
36905
|
-
key: expr,
|
|
36906
|
-
className: "edrv-dapwatch"
|
|
36907
|
-
}, react.default.createElement("button", {
|
|
36908
|
-
className: "edrv-dapwatch-x",
|
|
36909
|
-
title: "移除监视",
|
|
36910
|
-
onClick: () => removeWatch(expr)
|
|
36911
|
-
}, "×"), hit?.ref > 0 ? react.default.createElement("button", {
|
|
36912
|
-
className: "edrv-dapvar-tw",
|
|
36913
|
-
title: expanded.has(hit.ref) ? "折叠 table" : "展开 table",
|
|
36914
|
-
onClick: () => {
|
|
36915
|
-
expandVar(hit.ref);
|
|
36916
|
-
}
|
|
36917
|
-
}, expanded.has(hit.ref) ? "▾" : "▸") : react.default.createElement("span", { className: "edrv-dapvar-tw" }, ""), react.default.createElement("span", {
|
|
36918
|
-
className: "edrv-dapvar-name",
|
|
36919
|
-
title: expr
|
|
36920
|
-
}, expr), react.default.createElement("span", {
|
|
36921
|
-
className: "edrv-dapvar-val",
|
|
36922
|
-
title: hit?.result || ""
|
|
36923
|
-
}, hit ? "= " + hit.result : "= 不可用"), hit?.type ? react.default.createElement("span", { className: "edrv-dapvar-type" }, hit.type) : null)];
|
|
36924
|
-
if (hit?.ref > 0 && expanded.has(hit.ref)) rows.push(...flattenVariableRows(varCache.get(hit.ref) ?? [], expanded, varCache, { maxRows: 500 }).map(renderVarRow));
|
|
36925
|
-
return rows;
|
|
36926
|
-
});
|
|
36927
|
-
const watchSection = section("监视", "watch", "watch", [segAct("watch-add", "+", "新增监视表达式", focusWatchInput), segAct("watch-clear", "🗑", "移除全部监视", clearWatches)], [...watchRows, react.default.createElement("div", {
|
|
36928
|
-
key: "add",
|
|
36929
|
-
className: "edrv-dapwatch-add"
|
|
36930
|
-
}, react.default.createElement("input", {
|
|
36931
|
-
ref: watchInputRef,
|
|
36932
|
-
className: "edrv-daprepl-in",
|
|
36933
|
-
placeholder: "新增监视表达式,回车确认",
|
|
36934
|
-
value: watchDraft,
|
|
36935
|
-
onChange: (e) => setWatchDraft(e.target.value),
|
|
36936
|
-
onKeyDown: (e) => {
|
|
36937
|
-
if (e.key === "Enter") addWatch();
|
|
36938
|
-
}
|
|
36939
|
-
}))]);
|
|
36940
|
-
const bpSectionChildren = bpRows.length ? bpRows.flatMap((row) => {
|
|
36941
|
-
const base = row.path.split("/").pop() || row.path;
|
|
36942
|
-
const dir = row.path.includes("/") ? row.path.slice(0, row.path.lastIndexOf("/")) : "";
|
|
36943
|
-
const ack = dapStore.ackOf(row.path, row.entry.line);
|
|
36944
|
-
const unverified = Boolean(ack && !ack.verified);
|
|
36945
|
-
const editing = bpEdit && bpEdit.path === row.path && bpEdit.line === row.entry.line;
|
|
36946
|
-
const rows = [react.default.createElement("div", {
|
|
36947
|
-
key: row.path + ":" + row.entry.line,
|
|
36948
|
-
className: "edrv-dapbp",
|
|
36949
|
-
title: "跳转到 " + row.path + ":" + row.entry.line + (unverified && ack.message ? "(" + ack.message + ")" : ""),
|
|
36950
|
-
onClick: () => jumpBp(row),
|
|
36951
|
-
onContextMenu: (e) => {
|
|
36952
|
-
e.preventDefault();
|
|
36953
|
-
setBpMenu({
|
|
36954
|
-
x: e.clientX,
|
|
36955
|
-
y: e.clientY,
|
|
36956
|
-
row
|
|
36957
|
-
});
|
|
36958
|
-
}
|
|
36959
|
-
}, react.default.createElement("input", {
|
|
36960
|
-
type: "checkbox",
|
|
36961
|
-
checked: row.entry.enabled,
|
|
36962
|
-
title: row.entry.enabled ? "禁用断点" : "启用断点",
|
|
36963
|
-
onChange: () => toggleBpEnabled(row),
|
|
36964
|
-
onClick: (e) => e.stopPropagation()
|
|
36965
|
-
}), react.default.createElement("span", {
|
|
36966
|
-
className: "edrv-dapbp-dot" + (row.entry.enabled ? "" : " off") + (unverified ? " unverified" : ""),
|
|
36967
|
-
title: unverified && ack.message ? ack.message : void 0
|
|
36968
|
-
}), react.default.createElement("button", {
|
|
36969
|
-
className: "edrv-dapbp-file",
|
|
36970
|
-
title: row.path
|
|
36971
|
-
}, base), react.default.createElement("span", {
|
|
36972
|
-
className: "edrv-dapbp-dir",
|
|
36973
|
-
title: dir
|
|
36974
|
-
}, dir), react.default.createElement("span", { className: "edrv-dapbp-line" }, row.entry.line), react.default.createElement("button", {
|
|
36975
|
-
className: "edrv-dapbp-x",
|
|
36976
|
-
title: "删除断点",
|
|
36977
|
-
onClick: (e) => {
|
|
36978
|
-
e.stopPropagation();
|
|
36979
|
-
removeBp(row);
|
|
36980
|
-
}
|
|
36981
|
-
}, "×"))];
|
|
36982
|
-
if (editing) {
|
|
36983
|
-
const fieldKey = fieldOfMode(bpEdit.mode);
|
|
36984
|
-
const modeItem = MODES.find((m) => m.mode === bpEdit.mode) ?? MODES[0];
|
|
36985
|
-
rows.push(react.default.createElement("div", {
|
|
36986
|
-
key: row.path + ":" + row.entry.line + ":edit",
|
|
36987
|
-
className: "edrv-dapbp-edit"
|
|
36988
|
-
}, react.default.createElement("select", {
|
|
36989
|
-
className: "edrv-bpwidget-mode",
|
|
36990
|
-
title: "断点类型",
|
|
36991
|
-
value: String(bpEdit.mode),
|
|
36992
|
-
onChange: (e) => setBpEdit({
|
|
36993
|
-
...bpEdit,
|
|
36994
|
-
mode: Number(e.target.value)
|
|
36995
|
-
})
|
|
36996
|
-
}, MODES.filter((m) => m.mode !== BP_MODE.WAIT).map((m) => react.default.createElement("option", {
|
|
36997
|
-
key: m.mode,
|
|
36998
|
-
value: String(m.mode)
|
|
36999
|
-
}, m.label))), react.default.createElement("input", {
|
|
37000
|
-
className: "edrv-bpwidget-input",
|
|
37001
|
-
autoFocus: true,
|
|
37002
|
-
spellCheck: false,
|
|
37003
|
-
placeholder: modeItem?.placeholder ?? "",
|
|
37004
|
-
hidden: fieldKey === null,
|
|
37005
|
-
value: fieldKey ? bpEdit.drafts[fieldKey] || "" : "",
|
|
37006
|
-
onChange: (e) => setBpEdit({
|
|
37007
|
-
...bpEdit,
|
|
37008
|
-
drafts: {
|
|
37009
|
-
...bpEdit.drafts,
|
|
37010
|
-
[fieldKey]: e.target.value
|
|
37011
|
-
}
|
|
37012
|
-
}),
|
|
37013
|
-
onKeyDown: (e) => {
|
|
37014
|
-
if (e.key === "Enter") {
|
|
37015
|
-
e.preventDefault();
|
|
37016
|
-
commitBpEdit();
|
|
37017
|
-
return;
|
|
37018
|
-
}
|
|
37019
|
-
if (e.key === "Escape") {
|
|
37020
|
-
e.preventDefault();
|
|
37021
|
-
setBpEdit(null);
|
|
37022
|
-
}
|
|
37023
|
-
}
|
|
37024
|
-
})));
|
|
37025
|
-
}
|
|
37026
|
-
return rows;
|
|
37027
|
-
}) : [react.default.createElement("div", {
|
|
37028
|
-
key: "e",
|
|
37029
|
-
className: "edrv-dapempty"
|
|
37030
|
-
}, "在编辑器行首点击或 F9 添加断点")];
|
|
37031
|
-
const bpSection = section("断点", "breakpoints", "breakpoints", [
|
|
37032
|
-
segAct("bp-new", "新建断点 ▾", "添加条件断点 / 记录点(落在当前编辑器光标行)", (e) => setNewBpMenu({
|
|
37033
|
-
x: e.clientX,
|
|
37034
|
-
y: e.clientY
|
|
37035
|
-
})),
|
|
37036
|
-
bpRows.length ? segAct("bp-toggle", allBpEnabled ? "⊘" : "◉", allBpEnabled ? "禁用所有断点" : "启用所有断点", () => dapStore.setAllBpEnabled(scope, cwd, !allBpEnabled)) : null,
|
|
37037
|
-
bpRows.length ? segAct("bp-clear", "🗑", "删除所有断点", removeAllBps) : null
|
|
37038
|
-
], bpSectionChildren);
|
|
37039
|
-
const outputRows = dapStore.outputs().slice(-60).map((ev, idx) => react.default.createElement("div", {
|
|
37040
|
-
key: ev.seq + ":" + idx,
|
|
37041
|
-
className: "edrv-daprepl-line out"
|
|
37042
|
-
}, ev.text?.trimEnd() || ""));
|
|
37043
|
-
const configReady = snap.configs.some((c) => snap.adapters.length === 0 || snap.adapters.find((a) => a.type === c.type)?.available === true);
|
|
37044
|
-
const toolbarBtn = (key, label, title, disabled, onClick) => react.default.createElement("button", {
|
|
37045
|
-
key,
|
|
37046
|
-
className: "edrv-dappanel-run",
|
|
37047
|
-
title,
|
|
37048
|
-
disabled: disabled === true,
|
|
37049
|
-
onClick
|
|
37050
|
-
}, label);
|
|
37051
|
-
const bpMenuEl = bpMenu ? react.default.createElement(ContextMenu, {
|
|
37052
|
-
x: bpMenu.x,
|
|
37053
|
-
y: bpMenu.y,
|
|
37054
|
-
onClose: () => setBpMenu(null),
|
|
37055
|
-
entries: buildBpRowMenu({ enabled: bpMenu.row.entry.enabled }).map((item) => ({
|
|
37056
|
-
id: item.id,
|
|
37057
|
-
label: item.label,
|
|
37058
|
-
separator: item.separator,
|
|
37059
|
-
onClick: () => runBpRowAction(item.id, bpMenu.row)
|
|
37060
|
-
}))
|
|
37061
|
-
}) : null;
|
|
37062
|
-
const newBpMenuEl = newBpMenu ? react.default.createElement(ContextMenu, {
|
|
37063
|
-
x: newBpMenu.x,
|
|
37064
|
-
y: newBpMenu.y,
|
|
37065
|
-
onClose: () => setNewBpMenu(null),
|
|
37066
|
-
entries: [{
|
|
37067
|
-
id: "add-conditional",
|
|
37068
|
-
label: "添加条件断点...",
|
|
37069
|
-
onClick: () => addBpAtCursor(BP_MODE.EXPRESSION)
|
|
37070
|
-
}, {
|
|
37071
|
-
id: "add-logpoint",
|
|
37072
|
-
label: "添加记录点...",
|
|
37073
|
-
onClick: () => addBpAtCursor(BP_MODE.LOG_MESSAGE)
|
|
37074
|
-
}]
|
|
37075
|
-
}) : null;
|
|
37076
|
-
return react.default.createElement("div", { className: "edrv-dappanel" }, react.default.createElement("div", { className: "edrv-dappanel-head" }, ...snap.candidates ? [
|
|
37077
|
-
react.default.createElement("select", {
|
|
37078
|
-
key: "pick",
|
|
37079
|
-
className: "edrv-dappanel-cfg-select",
|
|
37080
|
-
title: "选择附加目标进程(processName 命中多个候选)",
|
|
37081
|
-
value: String(pickPid || snap.candidates[0]?.pid || ""),
|
|
37082
|
-
onChange: (e) => setPickPid(Number(e.target.value))
|
|
37083
|
-
}, snap.candidates.map((it) => react.default.createElement("option", {
|
|
37084
|
-
key: it.pid,
|
|
37085
|
-
value: String(it.pid)
|
|
37086
|
-
}, it.pid + " : " + it.name + (it.title ? " — " + it.title.slice(0, 44) : "")))),
|
|
37087
|
-
toolbarBtn("pick-ok", "✓", "附加到选中进程", false, () => dapStore.confirmPick(pickPid || snap.candidates[0]?.pid || 0)),
|
|
37088
|
-
toolbarBtn("pick-cancel", "✕", "取消", false, () => dapStore.cancelPick())
|
|
37089
|
-
] : [react.default.createElement("select", {
|
|
37090
|
-
key: "cfg",
|
|
37091
|
-
className: "edrv-dappanel-cfg-select",
|
|
37092
|
-
title: "调试配置(读取工作区 .dsh/launch.json;适配器由扩展清单 contributes.debuggers 提供)",
|
|
37093
|
-
value: snap.selectedConfig ?? "",
|
|
37094
|
-
onChange: (e) => dapStore.selectConfig(e.target.value)
|
|
37095
|
-
}, snap.configs.length ? snap.configs.map((c) => {
|
|
37096
|
-
const adapter = snap.adapters.find((a) => a.type === c.type);
|
|
37097
|
-
const ready = snap.adapters.length === 0 || adapter?.available === true;
|
|
37098
|
-
const suffix = ready ? "" : "(" + (adapter?.reason || "未发现该类型适配器") + ")";
|
|
37099
|
-
return react.default.createElement("option", {
|
|
37100
|
-
key: c.name,
|
|
37101
|
-
value: c.name,
|
|
37102
|
-
disabled: !ready
|
|
37103
|
-
}, c.name + suffix);
|
|
37104
|
-
}) : react.default.createElement("option", { value: "" }, "无可用调试配置"))], toolbarBtn("run", "▶", paused ? "继续(F5)" : "启动调试(F5)", !paused && (!configReady || dapActive), () => dapStore.startOrContinue()), toolbarBtn("cfg-gear", "⚙", "打开/新建调试配置(" + LAUNCH_REL + ")", !ctx?.cwd, () => {
|
|
37105
|
-
openLaunchConfig();
|
|
37106
|
-
}), toolbarBtn("pause", "⏸", "暂停", !dapActive, () => {
|
|
37107
|
-
dapStore.action("pause");
|
|
37108
|
-
}), toolbarBtn("next", "⤵", "单步跳过(F10)", !paused, () => {
|
|
37109
|
-
dapStore.action("next");
|
|
37110
|
-
}), toolbarBtn("stepin", "↓", "单步步入(F11)", !paused, () => {
|
|
37111
|
-
dapStore.action("stepIn");
|
|
37112
|
-
}), toolbarBtn("stepout", "↑", "单步步出(Shift+F11)", !paused, () => {
|
|
37113
|
-
dapStore.action("stepOut");
|
|
37114
|
-
}), toolbarBtn("stop", "⏹", "停止(Shift+F5)", !dapActive, () => {
|
|
37115
|
-
dapStore.stop();
|
|
37116
|
-
}), react.default.createElement("span", { className: "edrv-dappanel-phase" + (paused ? " paused" : "") }, PHASE_LABEL[snap.phase] || snap.phase), snap.pid ? react.default.createElement("span", { className: "edrv-dappanel-pid" }, "pid " + snap.pid) : null, react.default.createElement("span", { style: { flex: 1 } }), snap.error ? react.default.createElement("span", {
|
|
37117
|
-
className: "edrv-dappanel-err",
|
|
37118
|
-
title: snap.error
|
|
37119
|
-
}, "⚠") : null), section("变量", "variables", "variables", [segAct("var-reload", "⟳", "刷新变量", () => setReloadTick((t) => t + 1))], varRows), sash("variables", "watch"), watchSection, sash("watch", "stack"), section("调用堆栈", "stack", "stack", [], stackRows), sash("stack", "breakpoints"), bpSection, react.default.createElement("div", { className: "edrv-daprepl" }, react.default.createElement("div", { className: "edrv-dapseg-head" }, "调试控制台"), react.default.createElement("div", { className: "edrv-daprepl-log" }, ...replLog.map((row, idx) => react.default.createElement("div", {
|
|
37120
|
-
key: idx,
|
|
37121
|
-
className: "edrv-daprepl-line"
|
|
37122
|
-
}, react.default.createElement("span", { className: "edrv-dapvar-name" }, row.expr), react.default.createElement("span", { className: "edrv-dapvar-val" }, "= " + row.result))), ...outputRows), react.default.createElement("input", {
|
|
37123
|
-
className: "edrv-daprepl-in",
|
|
37124
|
-
placeholder: paused ? "输入表达式求值,回车执行(如 self.itemId)" : "暂停时才可求值",
|
|
37125
|
-
disabled: !paused,
|
|
37126
|
-
value: replDraft,
|
|
37127
|
-
onChange: (e) => setReplDraft(e.target.value),
|
|
37128
|
-
onKeyDown: (e) => {
|
|
37129
|
-
if (e.key === "Enter") runRepl();
|
|
37130
|
-
}
|
|
37131
|
-
})), bpMenuEl, newBpMenuEl);
|
|
37132
|
-
}
|
|
37133
|
-
//#endregion
|
|
37134
36284
|
//#region src/client/sidebar/panels/index.ts
|
|
37135
36285
|
/**
|
|
37136
36286
|
* dsh-vscode-mode client — 侧边栏面板定义(文件管理 + 搜索 + 规则 + SVN 变更)。
|
|
@@ -37178,7 +36328,11 @@ window.__ModuleLoader__.load({
|
|
|
37178
36328
|
title: "规则",
|
|
37179
36329
|
icon: IconListPenOutline16,
|
|
37180
36330
|
order: 20,
|
|
37181
|
-
render: (ctx) => react.default.createElement(
|
|
36331
|
+
render: (ctx) => react.default.createElement(LazyPanel, {
|
|
36332
|
+
key: "rules",
|
|
36333
|
+
panel: "rules",
|
|
36334
|
+
ctx
|
|
36335
|
+
})
|
|
37182
36336
|
};
|
|
37183
36337
|
}
|
|
37184
36338
|
/**
|
|
@@ -37231,7 +36385,11 @@ window.__ModuleLoader__.load({
|
|
|
37231
36385
|
icon: "🐞",
|
|
37232
36386
|
order: 22,
|
|
37233
36387
|
badge: () => dapStore.getSnapshot().phase === "paused" ? 1 : null,
|
|
37234
|
-
render: (ctx) => react.default.createElement(
|
|
36388
|
+
render: (ctx) => react.default.createElement(LazyPanel, {
|
|
36389
|
+
key: "debug",
|
|
36390
|
+
panel: "debug",
|
|
36391
|
+
ctx
|
|
36392
|
+
})
|
|
37235
36393
|
};
|
|
37236
36394
|
}
|
|
37237
36395
|
//#endregion
|
|
@@ -39017,6 +38175,16 @@ window.__ModuleLoader__.load({
|
|
|
39017
38175
|
* conversation.input.dock。
|
|
39018
38176
|
* 作者 ddj 2026-08-20
|
|
39019
38177
|
*/
|
|
38178
|
+
/** Root-owned live objects shared with independent panel chunks; no copied stores or transport state. */
|
|
38179
|
+
const __lazyShared = {
|
|
38180
|
+
rpc,
|
|
38181
|
+
dbg,
|
|
38182
|
+
dapStore,
|
|
38183
|
+
BP_MODE,
|
|
38184
|
+
MODES,
|
|
38185
|
+
fieldOfMode,
|
|
38186
|
+
ContextMenu
|
|
38187
|
+
};
|
|
39020
38188
|
const inject = [
|
|
39021
38189
|
"slots",
|
|
39022
38190
|
"timer",
|
|
@@ -39633,6 +38801,7 @@ window.__ModuleLoader__.load({
|
|
|
39633
38801
|
order: 40
|
|
39634
38802
|
}, (props) => react.default.createElement(PluginDetailSection, Object.assign({}, props)));
|
|
39635
38803
|
ctx.effect(() => () => {
|
|
38804
|
+
setPanelImport();
|
|
39636
38805
|
try {
|
|
39637
38806
|
disposeSnippets();
|
|
39638
38807
|
} catch {}
|
|
@@ -39660,8 +38829,11 @@ window.__ModuleLoader__.load({
|
|
|
39660
38829
|
reportUiStateEvent("客户端装配完成:水合" + (uiStateSettled() ? "已结束" : "仍在进行(界面稍后重跑恢复)"));
|
|
39661
38830
|
}
|
|
39662
38831
|
//#endregion
|
|
38832
|
+
exports.__lazyShared = __lazyShared;
|
|
38833
|
+
exports.__setPanelImport = setPanelImport;
|
|
39663
38834
|
exports.apply = apply;
|
|
39664
38835
|
exports.inject = inject;
|
|
38836
|
+
module.exports.__setPanelImport(require.async?.bind(require));
|
|
39665
38837
|
return module.exports;
|
|
39666
38838
|
}
|
|
39667
38839
|
});
|