dsh-vscode-mode 0.10.0 → 0.11.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 +33 -3
- package/lib/client.js +1501 -269
- package/lib/client.js.map +1 -1
- package/lib/index.js +2163 -1042
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/dap/hover.ts +2 -7
- package/src/client/index.ts +25 -0
- package/src/client/luaReservedWords.ts +10 -0
- package/src/client/monaco/lsp/keywords.ts +121 -0
- package/src/client/monaco/lsp/lspClient.ts +68 -6
- package/src/client/monaco/lsp/memberScope.ts +90 -0
- package/src/client/monaco/lsp/providers.ts +14 -4
- package/src/client/settingsDocRouter.ts +52 -0
- package/src/client/sidebar/menuItems.ts +1 -0
- package/src/client/sidebar/types.ts +2 -0
- package/src/client/styles/editor.css +143 -37
- package/src/client/svnActions.ts +4 -4
- package/src/client/ui/ContextMenu.ts +4 -2
- package/src/client/ui/EditorView.ts +132 -52
- package/src/client/ui/SvnLogDialog.ts +200 -69
- package/src/client/ui/SvnUpdateDialog.ts +472 -0
- package/src/client/ui/svnUpdateModel.ts +135 -0
- package/src/index.ts +2 -0
- package/src/lsp/completionCap.ts +80 -0
- package/src/lsp/manager.ts +42 -10
- package/src/lsp/rpc.ts +8 -5
- package/src/lsp/server.ts +18 -4
- package/src/rpc.ts +74 -2
- package/src/settingsDocPath.ts +30 -0
- package/src/shared/rpc.ts +12 -2
- package/src/shared/svn.ts +38 -0
- package/src/svn.ts +102 -7
- package/src/svnText.ts +22 -13
- package/src/svnUpdateJob.ts +588 -0
package/lib/client.js
CHANGED
|
@@ -33,7 +33,7 @@ window.__ModuleLoader__.load({
|
|
|
33
33
|
let react_dom = require("react-dom");
|
|
34
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 { 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 { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: 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[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n/* 键盘高亮项(↑↓ 选择):与 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[data-edrv-view] .edrv-mn-add-line { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n[data-edrv-view] .edrv-mn-gutter-add { color: var(--dsw-alias-state-success-primary, #0f9d58) !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); border-top: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); border-bottom: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); box-shadow: inset 0 0 0 1px var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: var(--dsw-alias-state-error-primary, #c0392b); }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-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\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[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[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/* 文件树行尾 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: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-title { margin: 0; font-size: 15px; font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-target { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); max-width: 220px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-svnlog-filter { display: flex; align-items: center; gap: 8px; flex-wrap: nowrap; }\n[data-edrv-view] .edrv-svnlog-field { flex: 0 0 auto; 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-svnlog-search { min-width: 160px; flex: 1 1 220px; 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-date { padding: 2px 4px; 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-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/* 上段修订列表:列头行 + 单行五列(版本/动作/作者/日期/信息),列宽由 cell 类与 nth-child 对齐(P0-12/D30) */\n[data-edrv-view] .edrv-svnlog-list { flex: 0 0 auto; display: flex; flex-direction: column; overflow: auto; border: 2px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 4px; }\n[data-edrv-view] .edrv-svnlog-cols { display: flex; align-items: center; gap: 6px; padding: 2px 6px; border-bottom: 2px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); 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[data-edrv-view] .edrv-svnlog-item { display: flex; align-items: center; gap: 6px; padding: 2px 6px; border-radius: 6px; cursor: pointer; white-space: nowrap; }\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)); }\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); }\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: 12px; height: 12px; border-radius: 3px; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 9px; font-weight: 700; }\n[data-edrv-view] .edrv-svnlog-badge-modified { color: var(--dsw-alias-brand-primary, #2563eb); background: rgba(37,99,235,.12); }\n[data-edrv-view] .edrv-svnlog-badge-added { color: var(--dsw-alias-state-warn-primary, #7c3aed); background: rgba(124,58,237,.12); }\n[data-edrv-view] .edrv-svnlog-badge-deleted { color: #b91c1c; background: rgba(185,28,28,.12); }\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 公共外观(上段列表自带 .edrv-svnlog-list 边框) */\n[data-edrv-view] .edrv-svnlog-pane { border: 2px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 8px; padding: 8px 10px; overflow: hidden; }\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[data-edrv-view] .edrv-svnlog-meta { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-secondary, #52606d); flex-wrap: wrap; }\n[data-edrv-view] .edrv-svnlog-date { color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-msgpane pre.edrv-svnlog-body { margin: 6px 0 0; padding: 6px 8px; border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-primary, #1f2933); font-size: 11px; line-height: 1.6; white-space: pre-wrap; word-break: break-word; overflow: auto; flex: 1 1 auto; min-height: 0; }\n/* P0-14 外框尺寸手柄(右缘调宽 / 底缘调高 / 右下角双向) */\n[data-edrv-view] .edrv-svnlog-grip { position: absolute; z-index: 2; touch-action: none; }\n[data-edrv-view] .edrv-svnlog-grip-r { top: 12px; bottom: 12px; right: 0; width: 8px; cursor: ew-resize; }\n[data-edrv-view] .edrv-svnlog-grip-b { left: 12px; right: 12px; bottom: 0; height: 8px; cursor: ns-resize; }\n[data-edrv-view] .edrv-svnlog-grip-c { right: 0; bottom: 0; width: 14px; height: 14px; cursor: nwse-resize; border-radius: 3px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); }\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-paths-head { display: flex; align-items: center; gap: 6px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #52606d); margin-bottom: 4px; }\n[data-edrv-view] .edrv-svnlog-hint { font-weight: 400; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-paths { display: flex; flex-direction: column; gap: 1px; }\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-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); }\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[data-edrv-view] .edrv-svnlog-footwrap { display: flex; flex-direction: column; gap: 4px; flex-shrink: 0; }\n[data-edrv-view] .edrv-svnlog-foot { display: flex; align-items: center; gap: 10px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-svnlog-btns { display: flex; align-items: center; gap: 6px; }\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 更新结果条(P3:update 条目级明细,可关闭) */\n[data-edrv-view] .edrv-svnres { display: flex; align-items: flex-start; gap: 8px; flex-shrink: 0; padding: 5px 10px; font-size: 11px; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: var(--dsw-alias-bg-layer-1, rgba(15,157,88,.06)); }\n[data-edrv-view] .edrv-svnres-head { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-svnres-list { display: flex; flex-wrap: wrap; gap: 4px 10px; min-width: 0; }\n[data-edrv-view] .edrv-svnres-item { display: inline-flex; align-items: center; gap: 3px; font-family: var(--ds-font-family-code, ui-monospace, monospace); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-svnres-item.edrv-svnres-conflict { color: var(--dsw-alias-state-error-primary, #d9534f); font-weight: 700; }\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); }";
|
|
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 { 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 { display: inline-flex; align-items: center; justify-content: center; width: 16px; height: 16px; border-radius: 4px; color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; }\n[data-edrv-view] .edrv-tab .edrv-tab-x:hover { background: 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[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-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[data-edrv-view] .edrv-mn-add-line { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.10)); }\n[data-edrv-view] .edrv-mn-gutter-add { color: var(--dsw-alias-state-success-primary, #0f9d58) !important; font-weight: 700; display: flex !important; align-items: center; justify-content: center; }\n[data-edrv-view] .edrv-mn-gutter-add::before { content: \"+\"; }\n[data-edrv-view] .edrv-del-zone { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.14)); border-top: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); border-bottom: 1px solid var(--dsw-alias-state-error-primary, rgba(217,83,79,.35)); box-shadow: inset 0 0 0 1px var(--dsw-alias-interactive-bg-hover-danger, rgba(217,83,79,.12)); }\n[data-edrv-view] .edrv-del-row { white-space: pre; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 12.5px; line-height: 20px; color: var(--dsw-alias-state-error-primary, #c0392b); }\n[data-edrv-view] .edrv-del-text { display: inline-block; white-space: pre; }\n[data-edrv-view] .edrv-minus-overlay { position: absolute; left: 0; top: 0; width: 100%; height: 100%; max-width: 100%; overflow: visible; pointer-events: none; z-index: 6; }\n[data-edrv-view] .edrv-minus-item { position: absolute; box-sizing: border-box; max-width: 100%; overflow: hidden; }\n[data-edrv-view] .edrv-minus-item::before { content: ''; position: absolute; left: 4px; top: 50%; width: 8px; height: 2px; transform: translateY(-50%); border-radius: 2px; background: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-monaco-host { flex: 1 1 auto; min-width: 0; min-height: 0; position: relative; overflow: hidden; }\n[data-edrv-view] .edrv-monaco-host > div { position: absolute; inset: 0; min-width: 0; min-height: 0; }\n[data-edrv-view] .edrv-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\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[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[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-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); }";
|
|
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");
|
|
@@ -4846,37 +4846,6 @@ window.__ModuleLoader__.load({
|
|
|
4846
4846
|
changesStore.refresh(sessionId, scope);
|
|
4847
4847
|
}
|
|
4848
4848
|
/**
|
|
4849
|
-
* 执行 svn update(CLI,全平台;path 工作区相对,'' = 工作区根)。
|
|
4850
|
-
* @author ddj 2026年09月16号
|
|
4851
|
-
* @param sessionId 会话 id
|
|
4852
|
-
* @param path 目标相对路径
|
|
4853
|
-
* @returns 执行结果与反馈文案
|
|
4854
|
-
*/
|
|
4855
|
-
async function svnUpdate(sessionId, path) {
|
|
4856
|
-
try {
|
|
4857
|
-
const res = await rpc("svn.update", {
|
|
4858
|
-
sessionId,
|
|
4859
|
-
path
|
|
4860
|
-
});
|
|
4861
|
-
if (!res.ok) return {
|
|
4862
|
-
ok: false,
|
|
4863
|
-
message: "SVN 更新失败:" + res.error
|
|
4864
|
-
};
|
|
4865
|
-
const conflicts = res.conflicts.length ? ";冲突:" + res.conflicts.join("、") : "";
|
|
4866
|
-
return {
|
|
4867
|
-
ok: true,
|
|
4868
|
-
message: "SVN 更新:" + res.summary + conflicts,
|
|
4869
|
-
entries: res.entries ?? [],
|
|
4870
|
-
conflicts: res.conflicts ?? []
|
|
4871
|
-
};
|
|
4872
|
-
} catch (error) {
|
|
4873
|
-
return {
|
|
4874
|
-
ok: false,
|
|
4875
|
-
message: "SVN 更新失败:" + String(error)
|
|
4876
|
-
};
|
|
4877
|
-
}
|
|
4878
|
-
}
|
|
4879
|
-
/**
|
|
4880
4849
|
* 发射 TortoiseSVN 对话框(Windows 过渡增强)。
|
|
4881
4850
|
* @author ddj 2026年09月16号
|
|
4882
4851
|
* @param sessionId 会话 id
|
|
@@ -9394,6 +9363,76 @@ window.__ModuleLoader__.load({
|
|
|
9394
9363
|
};
|
|
9395
9364
|
}
|
|
9396
9365
|
//#endregion
|
|
9366
|
+
//#region src/client/monaco/lsp/memberScope.ts
|
|
9367
|
+
/**
|
|
9368
|
+
* 外层作用域(`this` 成员)特征名。
|
|
9369
|
+
*
|
|
9370
|
+
* ⚠️ 这是**捕获派生的启发式标记**,不是通用的作用域判定:名单来自 2026-09-24
|
|
9371
|
+
* 在 `RechargeHeartView.lua` 真实键盘复现到的 87 条错答样本(`this` 成员列表)。
|
|
9372
|
+
* 用途仅是把「疑似外层作用域」的观测标出来供取证;未命中足够标记时归入 `member`,
|
|
9373
|
+
* 因此**不会**把正常的成员集误报成外层集。
|
|
9374
|
+
*/
|
|
9375
|
+
const INSTANCE_MARKERS = /* @__PURE__ */ new Set([
|
|
9376
|
+
"addframe",
|
|
9377
|
+
"addtimer",
|
|
9378
|
+
"clearalltimers",
|
|
9379
|
+
"buyheart",
|
|
9380
|
+
"canvas",
|
|
9381
|
+
"canvasgroup"
|
|
9382
|
+
]);
|
|
9383
|
+
/**
|
|
9384
|
+
* 取条目匹配文本(Monaco 口径:filterText 优先,回落 label)。
|
|
9385
|
+
*
|
|
9386
|
+
* 与 host 侧 `lsp/completionCap.ts` 的同名私有函数刻意各留一份:两者分属
|
|
9387
|
+
* host / client 两个打包平面,不为 3 行逻辑建立跨平面依赖。
|
|
9388
|
+
* @author ddj 2026年09月24号
|
|
9389
|
+
* @param item 补全项
|
|
9390
|
+
* @returns 匹配文本;无可用文本时为空串
|
|
9391
|
+
*/
|
|
9392
|
+
function textOfItem(item) {
|
|
9393
|
+
const raw = typeof item?.filterText === "string" && item.filterText ? item.filterText : item?.label;
|
|
9394
|
+
return typeof raw === "string" ? raw : "";
|
|
9395
|
+
}
|
|
9396
|
+
/**
|
|
9397
|
+
* 依据条目形态判定结果集属于哪一类。
|
|
9398
|
+
* @author ddj 2026年09月24号
|
|
9399
|
+
* @param lower 全部条目文本(已小写)
|
|
9400
|
+
* @param total 条目总数
|
|
9401
|
+
* @param csCount `CS_*` 条数
|
|
9402
|
+
* @param csRatio `CS_*` 占比
|
|
9403
|
+
* @returns 形态标签
|
|
9404
|
+
*/
|
|
9405
|
+
function kindOf(lower, total, csCount, csRatio) {
|
|
9406
|
+
if (total === 0) return "empty";
|
|
9407
|
+
if (lower.includes("this") || lower.includes("...") || csRatio > .5) return "globals";
|
|
9408
|
+
if (csCount === 0 && lower.filter((t) => INSTANCE_MARKERS.has(t)).length >= 2) return "outerScope";
|
|
9409
|
+
if (csCount === 0) return "member";
|
|
9410
|
+
return "other";
|
|
9411
|
+
}
|
|
9412
|
+
/**
|
|
9413
|
+
* 分类成员补全结果集(纯函数,无副作用)。
|
|
9414
|
+
* @author ddj 2026年09月24号
|
|
9415
|
+
* @param items 服务器归一化后的补全条目(非数组按空处理)
|
|
9416
|
+
* @param headSize 日志携带的前缀条数(缺省 3)
|
|
9417
|
+
* @returns 形态、计数与前几项
|
|
9418
|
+
*/
|
|
9419
|
+
function classifyMemberSet(items, headSize = 3) {
|
|
9420
|
+
const list = Array.isArray(items) ? items : [];
|
|
9421
|
+
const texts = list.map(textOfItem);
|
|
9422
|
+
const lower = texts.map((t) => t.toLowerCase());
|
|
9423
|
+
const total = list.length;
|
|
9424
|
+
const csCount = texts.filter((t) => t.startsWith("CS_")).length;
|
|
9425
|
+
const csRatio = total ? csCount / total : 0;
|
|
9426
|
+
const head = list.slice(0, Math.max(0, headSize)).map((item) => String(item?.label ?? ""));
|
|
9427
|
+
return {
|
|
9428
|
+
kind: kindOf(lower, total, csCount, csRatio),
|
|
9429
|
+
total,
|
|
9430
|
+
csCount,
|
|
9431
|
+
csRatio,
|
|
9432
|
+
head
|
|
9433
|
+
};
|
|
9434
|
+
}
|
|
9435
|
+
//#endregion
|
|
9397
9436
|
//#region src/client/monaco/lsp/lspClient.ts
|
|
9398
9437
|
/**
|
|
9399
9438
|
* dsh-vscode-mode client — LSP 会话与文档同步(模块级单例)。
|
|
@@ -9414,8 +9453,10 @@ window.__ModuleLoader__.load({
|
|
|
9414
9453
|
}
|
|
9415
9454
|
}
|
|
9416
9455
|
const SYNC_DEBOUNCE_MS = 250;
|
|
9456
|
+
const MAX_DOC_VERSION = 2147483647;
|
|
9417
9457
|
let sessionId$1;
|
|
9418
9458
|
const syncTimers = /* @__PURE__ */ new Map();
|
|
9459
|
+
const docVersions = /* @__PURE__ */ new Map();
|
|
9419
9460
|
let statusCache = {
|
|
9420
9461
|
servers: [],
|
|
9421
9462
|
at: 0
|
|
@@ -9436,6 +9477,9 @@ window.__ModuleLoader__.load({
|
|
|
9436
9477
|
*/
|
|
9437
9478
|
function setLspSession(id) {
|
|
9438
9479
|
if (sessionId$1 === id) return;
|
|
9480
|
+
for (const timer of syncTimers.values()) clearTimeout(timer);
|
|
9481
|
+
syncTimers.clear();
|
|
9482
|
+
docVersions.clear();
|
|
9439
9483
|
sessionId$1 = id;
|
|
9440
9484
|
refreshStatus();
|
|
9441
9485
|
}
|
|
@@ -9469,6 +9513,17 @@ window.__ModuleLoader__.load({
|
|
|
9469
9513
|
} catch (error) {}
|
|
9470
9514
|
}
|
|
9471
9515
|
/**
|
|
9516
|
+
* LSP 版本须可被 Roslyn 的 Int32 反序列化;时间戳会直接使其退出。
|
|
9517
|
+
* @author ddj 2026年09月24号
|
|
9518
|
+
* @param path 文档路径
|
|
9519
|
+
* @returns 当前文档下一个协议版本
|
|
9520
|
+
*/
|
|
9521
|
+
function nextDocVer(path) {
|
|
9522
|
+
const version = Math.min(MAX_DOC_VERSION, (docVersions.get(path) ?? 0) + 1);
|
|
9523
|
+
docVersions.set(path, version);
|
|
9524
|
+
return version;
|
|
9525
|
+
}
|
|
9526
|
+
/**
|
|
9472
9527
|
* 立即同步某文档到 host(首次打开/查询前保证服务器已认识该文档)。
|
|
9473
9528
|
* sessionId 缺失时仍发起请求:host 对唯一活跃会话有兜底解析,弃发会白白丢失文档归属。
|
|
9474
9529
|
* @author ddj 2026年08月27号 / 2026年09月11号
|
|
@@ -9484,7 +9539,7 @@ window.__ModuleLoader__.load({
|
|
|
9484
9539
|
sessionId: sessionId$1,
|
|
9485
9540
|
path,
|
|
9486
9541
|
text,
|
|
9487
|
-
version:
|
|
9542
|
+
version: nextDocVer(path)
|
|
9488
9543
|
}).catch(() => {});
|
|
9489
9544
|
return;
|
|
9490
9545
|
}
|
|
@@ -9495,7 +9550,7 @@ window.__ModuleLoader__.load({
|
|
|
9495
9550
|
sessionId: sessionId$1,
|
|
9496
9551
|
path,
|
|
9497
9552
|
text,
|
|
9498
|
-
version:
|
|
9553
|
+
version: nextDocVer(path)
|
|
9499
9554
|
}).catch(() => {});
|
|
9500
9555
|
}, SYNC_DEBOUNCE_MS));
|
|
9501
9556
|
}
|
|
@@ -9509,6 +9564,7 @@ window.__ModuleLoader__.load({
|
|
|
9509
9564
|
/** 文档关闭:停止去抖并通知 host。 */
|
|
9510
9565
|
function closeDoc(path) {
|
|
9511
9566
|
clearPending(path);
|
|
9567
|
+
docVersions.delete(path);
|
|
9512
9568
|
rpc("edrv.lsp.close", {
|
|
9513
9569
|
sessionId: sessionId$1,
|
|
9514
9570
|
path
|
|
@@ -9574,24 +9630,56 @@ window.__ModuleLoader__.load({
|
|
|
9574
9630
|
return res.hover || null;
|
|
9575
9631
|
}
|
|
9576
9632
|
/**
|
|
9633
|
+
* 成员触发字符:这类位置的补全最易被服务器的旧解析树错答(外层作用域 / 全局集)。
|
|
9634
|
+
* @author ddj 2026年09月24号
|
|
9635
|
+
*/
|
|
9636
|
+
const MEMBER_TRIGGERS = /* @__PURE__ */ new Set([".", ":"]);
|
|
9637
|
+
/**
|
|
9638
|
+
* 记录成员补全诊断(仅日志,不改结果)。
|
|
9639
|
+
*
|
|
9640
|
+
* 现场:`ECommon.` 这类成员位置偶尔返回 `this` 的外层作用域成员或全局集
|
|
9641
|
+
* (含 `this`/`...` 与大量 `CS_*`),根因指向服务器对刚输入文本的解析新鲜度,
|
|
9642
|
+
* 且非确定性。此处只把每次成员补全的形态打标,供真实使用中取证后再定修复。
|
|
9643
|
+
* @author ddj 2026年09月24号
|
|
9644
|
+
* @param path 工作区相对路径
|
|
9645
|
+
* @param position Monaco 位置(1-based)
|
|
9646
|
+
* @param context LSP CompletionContext(取触发字符)
|
|
9647
|
+
* @param prefix 当前输入前缀
|
|
9648
|
+
* @param list 服务器归一化后的补全结果
|
|
9649
|
+
*/
|
|
9650
|
+
function logMemberDiag(path, position, context, prefix, list) {
|
|
9651
|
+
const ch = context?.triggerCharacter;
|
|
9652
|
+
if (!MEMBER_TRIGGERS.has(ch)) return;
|
|
9653
|
+
const info = classifyMemberSet(list.items);
|
|
9654
|
+
dbg(sessionId$1, "成员补全诊断 ch=" + ch + " path=" + path + " pos=" + position.lineNumber + ":" + position.column + " prefix=" + JSON.stringify(prefix ?? "") + " 条数=" + info.total + " CS_*=" + info.csCount + " 分类=" + info.kind + " 首" + info.head.length + "=" + info.head.join(","));
|
|
9655
|
+
}
|
|
9656
|
+
/**
|
|
9577
9657
|
* 查询补全列表(列表阶段不带 documentation,由 resolve 补全)。
|
|
9578
|
-
*
|
|
9658
|
+
*
|
|
9659
|
+
* `prefix` 必须随请求上报:host 在 500 条上限处做前缀感知截断,不带前缀时
|
|
9660
|
+
* 只能按服务器原始顺序切,项目全局(ECommon 等)会被上万个 CS_* 桩挤出上限。
|
|
9661
|
+
* @author ddj 2026年09月22号 / 2026年09月24号
|
|
9579
9662
|
* @param path 工作区相对路径
|
|
9580
9663
|
* @param text 文档全文(未保存内容必须进服务器,否则按旧文本解析)
|
|
9581
9664
|
* @param position Monaco 位置(1-based)
|
|
9582
9665
|
* @param context LSP CompletionContext(触发类型/触发字符)
|
|
9666
|
+
* @param prefix 当前输入前缀(Monaco getWordUntilPosition 的词;可缺省)
|
|
9583
9667
|
* @returns { items, incomplete };失败或空时 null
|
|
9584
9668
|
*/
|
|
9585
|
-
async function fetchCompletions(path, text, position, context) {
|
|
9669
|
+
async function fetchCompletions(path, text, position, context, prefix) {
|
|
9586
9670
|
await syncDoc(path, text, true);
|
|
9587
9671
|
const args = {
|
|
9588
9672
|
path,
|
|
9589
9673
|
position: monoToLsp(position.lineNumber, position.column)
|
|
9590
9674
|
};
|
|
9591
9675
|
if (context) args.context = context;
|
|
9676
|
+
if (prefix) args.prefix = prefix;
|
|
9592
9677
|
const res = await queryLsp("查询补全", "edrv.lsp.completion", args);
|
|
9593
9678
|
if (!res || !res.completions) return null;
|
|
9594
|
-
|
|
9679
|
+
const list = res.completions;
|
|
9680
|
+
if (list.truncated === true) dbg(sessionId$1, "补全结果被截断(候选超上限):" + path + " prefix=" + String(prefix ?? ""));
|
|
9681
|
+
logMemberDiag(path, position, context, prefix, list);
|
|
9682
|
+
return list;
|
|
9595
9683
|
}
|
|
9596
9684
|
/**
|
|
9597
9685
|
* 惰性补全单个候选项(completionItem/resolve)。
|
|
@@ -9714,6 +9802,135 @@ window.__ModuleLoader__.load({
|
|
|
9714
9802
|
return path;
|
|
9715
9803
|
}
|
|
9716
9804
|
//#endregion
|
|
9805
|
+
//#region src/client/luaReservedWords.ts
|
|
9806
|
+
/**
|
|
9807
|
+
* Lua 5.3 保留字,供编辑器补全与调试悬停共同使用。
|
|
9808
|
+
* 作者 ddj 2026年09月24号
|
|
9809
|
+
*/
|
|
9810
|
+
const LUA_RESERVED_WORDS = [
|
|
9811
|
+
"and",
|
|
9812
|
+
"break",
|
|
9813
|
+
"do",
|
|
9814
|
+
"else",
|
|
9815
|
+
"elseif",
|
|
9816
|
+
"end",
|
|
9817
|
+
"false",
|
|
9818
|
+
"for",
|
|
9819
|
+
"function",
|
|
9820
|
+
"goto",
|
|
9821
|
+
"if",
|
|
9822
|
+
"in",
|
|
9823
|
+
"local",
|
|
9824
|
+
"nil",
|
|
9825
|
+
"not",
|
|
9826
|
+
"or",
|
|
9827
|
+
"repeat",
|
|
9828
|
+
"return",
|
|
9829
|
+
"then",
|
|
9830
|
+
"true",
|
|
9831
|
+
"until",
|
|
9832
|
+
"while"
|
|
9833
|
+
];
|
|
9834
|
+
const LUA_RESERVED_WORD_SET = new Set(LUA_RESERVED_WORDS);
|
|
9835
|
+
//#endregion
|
|
9836
|
+
//#region src/client/monaco/lsp/keywords.ts
|
|
9837
|
+
/**
|
|
9838
|
+
* 为 Lua 的 LSP 补全补充服务器缺失的保留字与注解基础类型候选。
|
|
9839
|
+
* 作者 ddj 2026年09月24号
|
|
9840
|
+
*/
|
|
9841
|
+
const LUA_BASE_TYPES = [
|
|
9842
|
+
"any",
|
|
9843
|
+
"boolean",
|
|
9844
|
+
"integer",
|
|
9845
|
+
"nil",
|
|
9846
|
+
"number",
|
|
9847
|
+
"string",
|
|
9848
|
+
"table",
|
|
9849
|
+
"thread",
|
|
9850
|
+
"userdata"
|
|
9851
|
+
];
|
|
9852
|
+
const TYPE_START = /^\s*---@(?:(?:type|return)\s+|param\s+\S+\s+|field\s+(?:(?:public|private|protected|package)\s+)?\S+\s+)(.*)$/;
|
|
9853
|
+
/**
|
|
9854
|
+
* 构造轻量本地候选,保留服务器同名项的优先权交给 mergeKeywords。
|
|
9855
|
+
* @author ddj 2026年09月24号
|
|
9856
|
+
* @param words 候选文本
|
|
9857
|
+
* @param kind Monaco 候选类型
|
|
9858
|
+
* @param range 当前单词范围
|
|
9859
|
+
* @param detail 候选说明
|
|
9860
|
+
* @returns 可直接交给 Monaco 的候选
|
|
9861
|
+
*/
|
|
9862
|
+
function keywordItems(words, kind, range, detail) {
|
|
9863
|
+
return words.map((label) => ({
|
|
9864
|
+
label,
|
|
9865
|
+
kind,
|
|
9866
|
+
insertText: label,
|
|
9867
|
+
range,
|
|
9868
|
+
detail
|
|
9869
|
+
}));
|
|
9870
|
+
}
|
|
9871
|
+
/**
|
|
9872
|
+
* 判断光标是否在 EmmyLua 注解的类型槽;普通注释和描述文字均不匹配。
|
|
9873
|
+
* @author ddj 2026年09月24号
|
|
9874
|
+
* @param model 当前文档
|
|
9875
|
+
* @param position 光标所在行
|
|
9876
|
+
* @param range 当前词范围
|
|
9877
|
+
* @returns 是否应提示基础类型
|
|
9878
|
+
*/
|
|
9879
|
+
function isLuaTypeSlot(model, position, range) {
|
|
9880
|
+
const beforeWord = model.getLineContent(position.lineNumber).slice(0, range.startColumn - 1);
|
|
9881
|
+
const match = TYPE_START.exec(beforeWord);
|
|
9882
|
+
if (!match) return false;
|
|
9883
|
+
const context = match[1] ?? "";
|
|
9884
|
+
const typePrefix = context.trimEnd();
|
|
9885
|
+
if (/[.:]$/.test(typePrefix)) return false;
|
|
9886
|
+
return !(/\s$/.test(context) && typePrefix && !/[|&,<]$/.test(typePrefix));
|
|
9887
|
+
}
|
|
9888
|
+
/**
|
|
9889
|
+
* 在普通代码位置生成关键字;成员名和类型注解位置只交给对应候选。
|
|
9890
|
+
* @author ddj 2026年09月24号
|
|
9891
|
+
* @param monaco Monaco 语言枚举
|
|
9892
|
+
* @param model 当前文档
|
|
9893
|
+
* @param position 光标所在行
|
|
9894
|
+
* @param range 当前单词的替换范围
|
|
9895
|
+
* @returns 当前上下文可用的 Lua 关键字候选
|
|
9896
|
+
*/
|
|
9897
|
+
function luaKeywordsAt(monaco, model, position, range) {
|
|
9898
|
+
const line = model.getLineContent(position.lineNumber);
|
|
9899
|
+
const beforeWord = line.charAt(range.startColumn - 2);
|
|
9900
|
+
if (beforeWord === "." || beforeWord === ":" || /^\s*---@/.test(line)) return [];
|
|
9901
|
+
return keywordItems(LUA_RESERVED_WORDS, monaco.languages.CompletionItemKind.Keyword, range, "Lua 关键字");
|
|
9902
|
+
}
|
|
9903
|
+
/**
|
|
9904
|
+
* 仅在注解类型槽补最基本类型,项目类型和服务器自带类型仍由 LSP 提供。
|
|
9905
|
+
* @author ddj 2026年09月24号
|
|
9906
|
+
* @param monaco Monaco 语言枚举
|
|
9907
|
+
* @param model 当前文档
|
|
9908
|
+
* @param position 光标所在行
|
|
9909
|
+
* @param range 当前单词的替换范围
|
|
9910
|
+
* @returns 类型候选;非注解返回空数组
|
|
9911
|
+
*/
|
|
9912
|
+
function luaTypesAt(monaco, model, position, range) {
|
|
9913
|
+
if (!isLuaTypeSlot(model, position, range)) return [];
|
|
9914
|
+
return keywordItems(LUA_BASE_TYPES, monaco.languages.CompletionItemKind.Keyword, range, "Lua 基础类型");
|
|
9915
|
+
}
|
|
9916
|
+
/**
|
|
9917
|
+
* 合并 LSP 与本地关键字,服务器同名项优先并保持原顺序。
|
|
9918
|
+
* @author ddj 2026年09月24号
|
|
9919
|
+
* @param server 服务器候选
|
|
9920
|
+
* @param keywords 本地关键字候选
|
|
9921
|
+
* @returns 去重后的补全列表
|
|
9922
|
+
*/
|
|
9923
|
+
function mergeKeywords(server, keywords) {
|
|
9924
|
+
if (keywords.length === 0) return server;
|
|
9925
|
+
const labels = new Set(server.map((item) => item.label));
|
|
9926
|
+
const merged = [...server];
|
|
9927
|
+
for (const keyword of keywords) {
|
|
9928
|
+
if (labels.has(keyword.label)) continue;
|
|
9929
|
+
merged.push(keyword);
|
|
9930
|
+
}
|
|
9931
|
+
return merged;
|
|
9932
|
+
}
|
|
9933
|
+
//#endregion
|
|
9717
9934
|
//#region src/client/monaco/lsp/providers.ts
|
|
9718
9935
|
/**
|
|
9719
9936
|
* dsh-vscode-mode client — Monaco LSP provider 注册 + 跳转/引用命令。
|
|
@@ -10007,18 +10224,20 @@ window.__ModuleLoader__.load({
|
|
|
10007
10224
|
provideCompletionItems: async (model, position, context, token) => {
|
|
10008
10225
|
const path = pathOfModel(model);
|
|
10009
10226
|
if (!path) return { suggestions: [] };
|
|
10010
|
-
const list = await fetchCompletions(path, model.getValue(), position, toLspContext(context));
|
|
10011
|
-
if (!list || !list.items.length || token?.isCancellationRequested) return { suggestions: [] };
|
|
10012
10227
|
const word = model.getWordUntilPosition(position);
|
|
10228
|
+
const list = await fetchCompletions(path, model.getValue(), position, toLspContext(context), word.word);
|
|
10229
|
+
if (token?.isCancellationRequested) return { suggestions: [] };
|
|
10230
|
+
if (lang !== "lua" && (!list || !list.items.length)) return { suggestions: [] };
|
|
10013
10231
|
const fallback = {
|
|
10014
10232
|
startLineNumber: position.lineNumber,
|
|
10015
10233
|
endLineNumber: position.lineNumber,
|
|
10016
10234
|
startColumn: word.startColumn,
|
|
10017
10235
|
endColumn: word.endColumn
|
|
10018
10236
|
};
|
|
10237
|
+
const serverItems = (list?.items ?? []).map((item) => toMonoSuggestion(monaco, item, fallback, path));
|
|
10019
10238
|
return {
|
|
10020
|
-
suggestions:
|
|
10021
|
-
incomplete: list
|
|
10239
|
+
suggestions: lang === "lua" ? mergeKeywords(serverItems, [...luaKeywordsAt(monaco, model, position, fallback), ...luaTypesAt(monaco, model, position, fallback)]) : serverItems,
|
|
10240
|
+
incomplete: list?.incomplete === true
|
|
10022
10241
|
};
|
|
10023
10242
|
},
|
|
10024
10243
|
resolveCompletionItem: async (item, token) => {
|
|
@@ -10875,31 +11094,6 @@ window.__ModuleLoader__.load({
|
|
|
10875
11094
|
function treeKeyOf(target, path) {
|
|
10876
11095
|
return target.expression + "@" + path + ":" + target.lineNumber + ":" + target.startColumn + "-" + target.endColumn;
|
|
10877
11096
|
}
|
|
10878
|
-
/** Lua 保留字集合(保留字不是可求值表达式,避免 adapter 返回 syntax err 噪声)。 */
|
|
10879
|
-
const LUA_KEYWORDS = /* @__PURE__ */ new Set([
|
|
10880
|
-
"and",
|
|
10881
|
-
"break",
|
|
10882
|
-
"do",
|
|
10883
|
-
"else",
|
|
10884
|
-
"elseif",
|
|
10885
|
-
"end",
|
|
10886
|
-
"false",
|
|
10887
|
-
"for",
|
|
10888
|
-
"function",
|
|
10889
|
-
"goto",
|
|
10890
|
-
"if",
|
|
10891
|
-
"in",
|
|
10892
|
-
"local",
|
|
10893
|
-
"nil",
|
|
10894
|
-
"not",
|
|
10895
|
-
"or",
|
|
10896
|
-
"repeat",
|
|
10897
|
-
"return",
|
|
10898
|
-
"then",
|
|
10899
|
-
"true",
|
|
10900
|
-
"until",
|
|
10901
|
-
"while"
|
|
10902
|
-
]);
|
|
10903
11097
|
/** 可求值路径表达式:标识符链,成员用 . 或 : 连接(注释里的中文文本等一律不匹配)。 */
|
|
10904
11098
|
const EVAL_EXPR = /^[A-Za-z_][A-Za-z0-9_]*(?:[.:][A-Za-z_][A-Za-z0-9_]*)*$/;
|
|
10905
11099
|
/**
|
|
@@ -10909,7 +11103,7 @@ window.__ModuleLoader__.load({
|
|
|
10909
11103
|
* @returns 是否可求值
|
|
10910
11104
|
*/
|
|
10911
11105
|
function isEvalExpr(text) {
|
|
10912
|
-
return EVAL_EXPR.test(text) && !
|
|
11106
|
+
return EVAL_EXPR.test(text) && !LUA_RESERVED_WORD_SET.has(text);
|
|
10913
11107
|
}
|
|
10914
11108
|
/**
|
|
10915
11109
|
* 从光标处提取 Lua 标识符/成员表达式(如 this.model、self:GetName)。
|
|
@@ -13461,10 +13655,11 @@ window.__ModuleLoader__.load({
|
|
|
13461
13655
|
*/
|
|
13462
13656
|
const SVN_ACTION_RUNNERS = {
|
|
13463
13657
|
update: (ctx) => {
|
|
13464
|
-
|
|
13465
|
-
ctx.notify?.(
|
|
13466
|
-
|
|
13467
|
-
}
|
|
13658
|
+
if (!ctx.openSvnUpdate) {
|
|
13659
|
+
ctx.notify?.("SVN 更新窗口不可用");
|
|
13660
|
+
return;
|
|
13661
|
+
}
|
|
13662
|
+
ctx.openSvnUpdate(ctx.path ?? "");
|
|
13468
13663
|
},
|
|
13469
13664
|
"refresh-changes": (ctx) => {
|
|
13470
13665
|
ctx.refreshChanges?.();
|
|
@@ -13664,7 +13859,7 @@ window.__ModuleLoader__.load({
|
|
|
13664
13859
|
* @param props.onClose 关闭回调(backdrop 点击/右键/Esc/点击项后触发)
|
|
13665
13860
|
*/
|
|
13666
13861
|
function ContextMenu(props) {
|
|
13667
|
-
const { x, y, entries, onClose } = props;
|
|
13862
|
+
const { x, y, entries, onClose, zIndex } = props;
|
|
13668
13863
|
const menuRef = react.default.useRef(null);
|
|
13669
13864
|
const [size, setSize] = react.default.useState(null);
|
|
13670
13865
|
react.default.useEffect(() => {
|
|
@@ -13728,7 +13923,10 @@ window.__ModuleLoader__.load({
|
|
|
13728
13923
|
const overlay = react.default.createElement("div", { "data-edrv-view": "1" }, react.default.createElement("div", {
|
|
13729
13924
|
className: "edrv-ctxmenu",
|
|
13730
13925
|
ref: menuRef,
|
|
13731
|
-
style: position
|
|
13926
|
+
style: zIndex === void 0 ? position : {
|
|
13927
|
+
...position,
|
|
13928
|
+
zIndex
|
|
13929
|
+
}
|
|
13732
13930
|
}, ...children));
|
|
13733
13931
|
return typeof document === "undefined" ? overlay : (0, react_dom.createPortal)(overlay, document.body);
|
|
13734
13932
|
}
|
|
@@ -15008,11 +15206,13 @@ window.__ModuleLoader__.load({
|
|
|
15008
15206
|
const MSG_H_MIN = 60;
|
|
15009
15207
|
/** 分段拖拽时下段保留的最小空间。 */
|
|
15010
15208
|
const PANE_KEEP_MIN = 170;
|
|
15011
|
-
/**
|
|
15209
|
+
/** 保底计算需额外扣除的两根横向分隔条合计高度(2 × 6px;拖拽 clamp 与初始 fit 共用)。 @author ddj 2026年09月24号 */
|
|
15210
|
+
const HSPLIT_TOTAL_PX = 12;
|
|
15211
|
+
/** 日志动作字母的配色分级(新增=绿、删除=红、替换=琥珀、修改=蓝;13-log-ui-polish 语义归位)。 */
|
|
15012
15212
|
const ACTION_TONE = {
|
|
15013
15213
|
A: "added",
|
|
15014
15214
|
D: "deleted",
|
|
15015
|
-
R: "
|
|
15215
|
+
R: "replaced",
|
|
15016
15216
|
M: "modified"
|
|
15017
15217
|
};
|
|
15018
15218
|
/** 排序键 → 列头名(P0-12;顺序 = 列头展示顺序)。 */
|
|
@@ -15427,7 +15627,7 @@ window.__ModuleLoader__.load({
|
|
|
15427
15627
|
return react.default.createElement("div", {
|
|
15428
15628
|
className: "edrv-svnlog-item" + (on ? " edrv-svnlog-item-on" : "") + (copied ? " edrv-svnlog-item-copied" : "") + (merged ? " edrv-svnlog-item-merged" : "") + (wc ? " edrv-svnlog-item-wc" : ""),
|
|
15429
15629
|
title,
|
|
15430
|
-
style: merged ? { paddingLeft:
|
|
15630
|
+
style: merged ? { paddingLeft: 16 + level * 18 } : void 0,
|
|
15431
15631
|
onClick: (event) => onPick(event, item),
|
|
15432
15632
|
onContextMenu: (event) => onMenu?.(event, item)
|
|
15433
15633
|
}, merged ? react.default.createElement("span", { className: "edrv-svnlog-cell edrv-svnlog-merge-mark" }, "↳") : null, react.default.createElement("span", { className: "edrv-svnlog-cell edrv-svnlog-cell-rev edrv-svnlog-rev" }, "r" + item.revision), react.default.createElement("span", { className: "edrv-svnlog-cell edrv-svnlog-cell-act" }, actions.map((a) => react.default.createElement("span", {
|
|
@@ -15460,23 +15660,39 @@ window.__ModuleLoader__.load({
|
|
|
15460
15660
|
});
|
|
15461
15661
|
}
|
|
15462
15662
|
/**
|
|
15463
|
-
*
|
|
15464
|
-
* 拖拽常把指针移出卡片,松手后 click
|
|
15465
|
-
*
|
|
15663
|
+
* 吞掉拖拽松手后的合成 click(capture;仅遮罩目标 + 300ms 窗口)。
|
|
15664
|
+
* 拖拽常把指针移出卡片,松手后 click 落在遮罩上会误触「点遮罩关闭」——原实现 setTimeout(0)
|
|
15665
|
+
* 太短,CDP/合成输入的 click 跨任务到达时窗口已释放(13-log-ui-polish 勘误3 实测复现)。
|
|
15666
|
+
* 现改为:只拦 target=遮罩 的 click(卡片内点击放行,不误吞行选中),300ms 后正常。
|
|
15667
|
+
* @author ddj 2026年09月17号 / 2026年09月24号
|
|
15466
15668
|
*/
|
|
15467
15669
|
function swallowNextClick() {
|
|
15468
15670
|
const swallow = (event) => {
|
|
15469
|
-
event.
|
|
15470
|
-
|
|
15671
|
+
if (event.target && event.target.classList && event.target.classList.contains("edrv-modal-mask")) {
|
|
15672
|
+
event.stopPropagation();
|
|
15673
|
+
event.preventDefault();
|
|
15674
|
+
}
|
|
15471
15675
|
window.removeEventListener("click", swallow, true);
|
|
15472
15676
|
};
|
|
15473
15677
|
window.addEventListener("click", swallow, true);
|
|
15474
|
-
window.setTimeout(() => window.removeEventListener("click", swallow, true),
|
|
15475
|
-
}
|
|
15678
|
+
window.setTimeout(() => window.removeEventListener("click", swallow, true), 300);
|
|
15679
|
+
}
|
|
15680
|
+
/** 八向手柄 → 提示文案(title 供无障碍与实机寻址;13-log-ui-polish 增量3)。 */
|
|
15681
|
+
const GRIP_LABEL = {
|
|
15682
|
+
n: "上缘",
|
|
15683
|
+
s: "下缘",
|
|
15684
|
+
w: "左缘",
|
|
15685
|
+
e: "右缘",
|
|
15686
|
+
nw: "左上角",
|
|
15687
|
+
ne: "右上角",
|
|
15688
|
+
sw: "左下角",
|
|
15689
|
+
se: "右下角"
|
|
15690
|
+
};
|
|
15476
15691
|
/**
|
|
15477
|
-
* 外框尺寸手柄(
|
|
15478
|
-
*
|
|
15479
|
-
* @
|
|
15692
|
+
* 外框尺寸手柄(13-log-ui-polish 增量3 八向):mode ∈ n/s/w/e/nw/ne/sw/se(四边+四角);双击复位。
|
|
15693
|
+
* 拖拽语义:拖哪边哪边动、对边固定(由弹窗侧 startResize 以 rect 起点 + absolute 锚定实现)。
|
|
15694
|
+
* @author ddj 2026年09月17号 / 2026年09月24号
|
|
15695
|
+
* @param props.mode 手柄形态(八向标准向名)
|
|
15480
15696
|
* @param props.onDragStart pointerdown 回调(弹窗侧启动 window 级跟踪)
|
|
15481
15697
|
* @param props.onReset 双击复位
|
|
15482
15698
|
* @returns 手柄元素
|
|
@@ -15485,6 +15701,7 @@ window.__ModuleLoader__.load({
|
|
|
15485
15701
|
const { mode, onDragStart, onReset } = props;
|
|
15486
15702
|
return react.default.createElement("div", {
|
|
15487
15703
|
className: "edrv-svnlog-grip edrv-svnlog-grip-" + mode,
|
|
15704
|
+
title: "调整弹窗尺寸(" + (GRIP_LABEL[mode] ?? mode) + ")· 双击复位",
|
|
15488
15705
|
onPointerDown: (event) => onDragStart(event, mode),
|
|
15489
15706
|
onDoubleClick: (event) => {
|
|
15490
15707
|
event.stopPropagation();
|
|
@@ -15493,6 +15710,24 @@ window.__ModuleLoader__.load({
|
|
|
15493
15710
|
});
|
|
15494
15711
|
}
|
|
15495
15712
|
/**
|
|
15713
|
+
* 路径两段拆分(目录段弱化 + 文件名加重;无斜杠时整段为文件名)。
|
|
15714
|
+
* @author ddj 2026年09月24号
|
|
15715
|
+
* @param text 显示用路径文本
|
|
15716
|
+
* @returns { dir, base } 目录前缀(含尾斜杠,可为空串)与文件名
|
|
15717
|
+
*/
|
|
15718
|
+
function pathSegsOf(text) {
|
|
15719
|
+
const raw = String(text ?? "");
|
|
15720
|
+
const at = raw.lastIndexOf("/");
|
|
15721
|
+
if (at < 0) return {
|
|
15722
|
+
dir: "",
|
|
15723
|
+
base: raw
|
|
15724
|
+
};
|
|
15725
|
+
return {
|
|
15726
|
+
dir: raw.slice(0, at + 1),
|
|
15727
|
+
base: raw.slice(at + 1)
|
|
15728
|
+
};
|
|
15729
|
+
}
|
|
15730
|
+
/**
|
|
15496
15731
|
* 下窗格变更路径单行(双击看差异;目录打开;Copy from 成列 P0-7;非受影响灰显 P0-5)。
|
|
15497
15732
|
* relPath 三态:null = 仓库外(显示仓库原路径);'' = 工作副本根自身变更(如合并属性,
|
|
15498
15733
|
* 显示占位文案);其余 = 工作区相对路径。根条目不提供打开/差异动作。
|
|
@@ -15516,7 +15751,7 @@ window.__ModuleLoader__.load({
|
|
|
15516
15751
|
const diff = () => {
|
|
15517
15752
|
if (actionable && item.kind !== "dir") onOpenDiff?.(item.relPath, revision);
|
|
15518
15753
|
};
|
|
15519
|
-
const
|
|
15754
|
+
const segs = pathSegsOf(outside ? item.path + "(仓库外)" : isRoot ? "(工作副本根)" : item.relPath);
|
|
15520
15755
|
const buttons = actionable ? react.default.createElement("span", { className: "edrv-svnlog-acts" }, react.default.createElement("button", {
|
|
15521
15756
|
className: "edrv-svn-act",
|
|
15522
15757
|
title: "在工作区打开该文件",
|
|
@@ -15540,7 +15775,7 @@ window.__ModuleLoader__.load({
|
|
|
15540
15775
|
else diff();
|
|
15541
15776
|
},
|
|
15542
15777
|
onContextMenu: (event) => onMenu?.(event, item, revision)
|
|
15543
|
-
}, actionLetterEl(item.action), react.default.createElement("span", { className: "edrv-svnlog-pathtext" },
|
|
15778
|
+
}, actionLetterEl(item.action), react.default.createElement("span", { className: "edrv-svnlog-pathtext" }, segs.dir ? react.default.createElement("span", { className: "edrv-svnlog-pdir" }, segs.dir) : null, react.default.createElement("span", { className: "edrv-svnlog-pbase" }, segs.base)), item.kind === "dir" ? react.default.createElement("span", { className: "edrv-svnlog-kind" }, "目录") : null, item.copyFrom ? react.default.createElement("span", { className: "edrv-svnlog-kind" }, "复制") : null, react.default.createElement("span", {
|
|
15544
15779
|
className: "edrv-svnlog-copyfrom",
|
|
15545
15780
|
title: item.copyFrom ? item.copyFrom + "@" + (item.copyFromRev ?? "?") : ""
|
|
15546
15781
|
}, item.copyFrom ? item.copyFrom + "@" + (item.copyFromRev ?? "?") : ""), buttons);
|
|
@@ -15699,7 +15934,7 @@ window.__ModuleLoader__.load({
|
|
|
15699
15934
|
type: "checkbox",
|
|
15700
15935
|
checked: regexOn,
|
|
15701
15936
|
onChange: (event) => onRegex(event.target.checked)
|
|
15702
|
-
}), "正则"), react.default.createElement("label", { className: "edrv-svnlog-check" }, "从", react.default.createElement("input", {
|
|
15937
|
+
}), "正则"), react.default.createElement("span", { className: "edrv-svnlog-dates" }, react.default.createElement("label", { className: "edrv-svnlog-check" }, "从", react.default.createElement("input", {
|
|
15703
15938
|
type: "date",
|
|
15704
15939
|
className: "edrv-svnlog-date",
|
|
15705
15940
|
value: from,
|
|
@@ -15709,7 +15944,7 @@ window.__ModuleLoader__.load({
|
|
|
15709
15944
|
className: "edrv-svnlog-date",
|
|
15710
15945
|
value: to,
|
|
15711
15946
|
onChange: (event) => onTo(event.target.value)
|
|
15712
|
-
})));
|
|
15947
|
+
}))));
|
|
15713
15948
|
}
|
|
15714
15949
|
/**
|
|
15715
15950
|
* 状态行文案(P0-11:条数 + 范围 + 选中数 + 变更路径数;信息序对齐官方)。
|
|
@@ -15773,7 +16008,7 @@ window.__ModuleLoader__.load({
|
|
|
15773
16008
|
}), "Include merged revs"), rangeActive ? react.default.createElement("span", {
|
|
15774
16009
|
className: "edrv-svnlog-check",
|
|
15775
16010
|
title: "区间模式:仅显示指定版本区间(svn -r START:END)"
|
|
15776
|
-
}, "区间模式") : null, react.default.createElement("span", { style: { flex: 1 } }), status), react.default.createElement("div", { className: "edrv-svnlog-btns" }, react.default.createElement("button", {
|
|
16011
|
+
}, "区间模式") : null, react.default.createElement("span", { style: { flex: 1 } }), status), react.default.createElement("div", { className: "edrv-svnlog-btns" }, react.default.createElement("span", { className: "edrv-svnlog-btngroup" }, react.default.createElement("button", {
|
|
15777
16012
|
className: "edrv-svn-act",
|
|
15778
16013
|
disabled: busy || !truncated || rangeActive,
|
|
15779
16014
|
title: rangeActive ? "区间模式下不可加载更多(回到最新后可用)" : truncated ? "再取 100 条" : "已到最早提交:该目标的全部历史已显示(svn 日志只含该路径发生过变更的版本)",
|
|
@@ -15793,7 +16028,7 @@ window.__ModuleLoader__.load({
|
|
|
15793
16028
|
disabled: busy,
|
|
15794
16029
|
title: "清除区间,回到默认 HEAD 往前的窗口",
|
|
15795
16030
|
onClick: onRangeReset
|
|
15796
|
-
}, "回到最新") : null, react.default.createElement("button", {
|
|
16031
|
+
}, "回到最新") : null), react.default.createElement("span", { className: "edrv-svnlog-btngroup" }, react.default.createElement("button", {
|
|
15797
16032
|
className: "edrv-svn-act",
|
|
15798
16033
|
disabled: busy || !filtered || !filtered.length,
|
|
15799
16034
|
title: "导出当前过滤后的修订列表为 CSV(带 BOM,Excel 直开;修订/作者/日期/信息/路径)",
|
|
@@ -15803,7 +16038,7 @@ window.__ModuleLoader__.load({
|
|
|
15803
16038
|
disabled: busy || !filtered || !filtered.length,
|
|
15804
16039
|
title: "导出当前过滤后的修订列表为 HTML 报表(仅本地查看,不外发)",
|
|
15805
16040
|
onClick: onExportHtml
|
|
15806
|
-
}, "导出HTML"), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("button", {
|
|
16041
|
+
}, "导出HTML")), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("span", { className: "edrv-svnlog-btngroup" }, react.default.createElement("button", {
|
|
15807
16042
|
className: "edrv-svn-act",
|
|
15808
16043
|
disabled: busy,
|
|
15809
16044
|
title: "重新读取日志(F5)",
|
|
@@ -15813,7 +16048,7 @@ window.__ModuleLoader__.load({
|
|
|
15813
16048
|
disabled: !list || !list.length,
|
|
15814
16049
|
title: "统计当前显示的修订(期间 / 按作者 / 按日期,P1-10)",
|
|
15815
16050
|
onClick: onStats
|
|
15816
|
-
}, "Statistics")));
|
|
16051
|
+
}, "Statistics"))));
|
|
15817
16052
|
}
|
|
15818
16053
|
/**
|
|
15819
16054
|
* 日志弹窗主体(P0 蓝图实施:布局/过滤/排序/菜单/键盘/按钮组)。
|
|
@@ -15856,6 +16091,7 @@ window.__ModuleLoader__.load({
|
|
|
15856
16091
|
const [menu, setMenu] = react.default.useState(null);
|
|
15857
16092
|
const [dlgW, setDlgW] = react.default.useState(() => Math.min(DIALOG_W_DEFAULT, (typeof window !== "undefined" ? window.innerWidth : 1280) - 24));
|
|
15858
16093
|
const [dlgH, setDlgH] = react.default.useState(() => Math.min(DIALOG_H_DEFAULT, (typeof window !== "undefined" ? window.innerHeight : 800) - 24));
|
|
16094
|
+
const [anchor, setAnchor] = react.default.useState(null);
|
|
15859
16095
|
const [listH, setListH] = react.default.useState(LIST_H_DEFAULT);
|
|
15860
16096
|
const [msgH, setMsgH] = react.default.useState(MSG_H_DEFAULT);
|
|
15861
16097
|
const [statsOpen, setStatsOpen] = react.default.useState(false);
|
|
@@ -15863,6 +16099,8 @@ window.__ModuleLoader__.load({
|
|
|
15863
16099
|
const [rangeFrom, setRangeFrom] = react.default.useState("");
|
|
15864
16100
|
const [rangeTo, setRangeTo] = react.default.useState("");
|
|
15865
16101
|
const bodyRef = react.default.useRef(null);
|
|
16102
|
+
const paneRef = react.default.useRef(null);
|
|
16103
|
+
const fitOnDataRef = react.default.useRef(false);
|
|
15866
16104
|
const list = Array.isArray(entries) ? entries : null;
|
|
15867
16105
|
react.default.useEffect(() => {
|
|
15868
16106
|
if (!list || !list.length) {
|
|
@@ -15973,13 +16211,55 @@ window.__ModuleLoader__.load({
|
|
|
15973
16211
|
const startResize = (event, mode) => {
|
|
15974
16212
|
event.preventDefault();
|
|
15975
16213
|
event.stopPropagation();
|
|
16214
|
+
const card = event.currentTarget.parentElement;
|
|
16215
|
+
const rect = card ? card.getBoundingClientRect() : null;
|
|
16216
|
+
if (!rect) return;
|
|
16217
|
+
const r0 = {
|
|
16218
|
+
left: rect.left,
|
|
16219
|
+
top: rect.top,
|
|
16220
|
+
width: rect.width,
|
|
16221
|
+
height: rect.height
|
|
16222
|
+
};
|
|
15976
16223
|
const startX = event.clientX;
|
|
15977
16224
|
const startY = event.clientY;
|
|
15978
|
-
const
|
|
15979
|
-
const
|
|
16225
|
+
const moveL = mode === "w" || mode === "nw" || mode === "sw";
|
|
16226
|
+
const moveR = mode === "e" || mode === "ne" || mode === "se";
|
|
16227
|
+
const moveT = mode === "n" || mode === "nw" || mode === "ne";
|
|
16228
|
+
const moveB = mode === "s" || mode === "sw" || mode === "se";
|
|
16229
|
+
const EDGE = 12;
|
|
16230
|
+
const right0 = r0.left + r0.width;
|
|
16231
|
+
const bottom0 = r0.top + r0.height;
|
|
16232
|
+
setAnchor({
|
|
16233
|
+
left: r0.left,
|
|
16234
|
+
top: r0.top
|
|
16235
|
+
});
|
|
16236
|
+
setDlgW(Math.round(r0.width));
|
|
16237
|
+
setDlgH(Math.round(r0.height));
|
|
15980
16238
|
const move = (e) => {
|
|
15981
|
-
|
|
15982
|
-
|
|
16239
|
+
const dx = e.clientX - startX;
|
|
16240
|
+
const dy = e.clientY - startY;
|
|
16241
|
+
let left = r0.left;
|
|
16242
|
+
let top = r0.top;
|
|
16243
|
+
let width = r0.width;
|
|
16244
|
+
let height = r0.height;
|
|
16245
|
+
if (moveR) width = Math.min(Math.max(DIALOG_W_MIN, r0.width + dx), window.innerWidth - EDGE - r0.left);
|
|
16246
|
+
if (moveL) {
|
|
16247
|
+
left = Math.min(Math.max(EDGE, r0.left + dx), right0 - DIALOG_W_MIN);
|
|
16248
|
+
width = right0 - left;
|
|
16249
|
+
}
|
|
16250
|
+
if (moveB) height = Math.min(Math.max(DIALOG_H_MIN, r0.height + dy), window.innerHeight - EDGE - r0.top);
|
|
16251
|
+
if (moveT) {
|
|
16252
|
+
top = Math.min(Math.max(EDGE, r0.top + dy), bottom0 - DIALOG_H_MIN);
|
|
16253
|
+
height = bottom0 - top;
|
|
16254
|
+
}
|
|
16255
|
+
const nextLeft = left;
|
|
16256
|
+
const nextTop = top;
|
|
16257
|
+
setAnchor((prev) => prev && prev.left === nextLeft && prev.top === nextTop ? prev : {
|
|
16258
|
+
left: nextLeft,
|
|
16259
|
+
top: nextTop
|
|
16260
|
+
});
|
|
16261
|
+
setDlgW(Math.round(width));
|
|
16262
|
+
setDlgH(Math.round(height));
|
|
15983
16263
|
};
|
|
15984
16264
|
const up = () => {
|
|
15985
16265
|
window.removeEventListener("pointermove", move);
|
|
@@ -15989,18 +16269,79 @@ window.__ModuleLoader__.load({
|
|
|
15989
16269
|
window.addEventListener("pointermove", move);
|
|
15990
16270
|
window.addEventListener("pointerup", up);
|
|
15991
16271
|
};
|
|
15992
|
-
/**
|
|
16272
|
+
/**
|
|
16273
|
+
* 双击复位:清锚回 flex 居中 + 默认尺寸(视口 clamp 同初始,防小屏溢出)。
|
|
16274
|
+
* @author ddj 2026年09月24号
|
|
16275
|
+
*/
|
|
16276
|
+
const resetDlgSize = () => {
|
|
16277
|
+
setAnchor(null);
|
|
16278
|
+
setDlgW(Math.min(DIALOG_W_DEFAULT, window.innerWidth - 24));
|
|
16279
|
+
setDlgH(Math.min(DIALOG_H_DEFAULT, window.innerHeight - 24));
|
|
16280
|
+
};
|
|
16281
|
+
/** 上段修订列表高度拖拽(clamp:下限 200,上限 = body 高 - 信息区/路径区/分隔条保留空间)。 */
|
|
15993
16282
|
const onListHDrag = (event) => startDrag(event, "y", listH, (next) => {
|
|
15994
16283
|
const total = bodyRef.current?.clientHeight ?? 0;
|
|
15995
|
-
const max = Math.max(280, total - msgH - PANE_KEEP_MIN);
|
|
16284
|
+
const max = Math.max(280, total - msgH - PANE_KEEP_MIN - HSPLIT_TOTAL_PX);
|
|
15996
16285
|
setListH(Math.min(max, Math.max(LIST_H_MIN, next)));
|
|
15997
16286
|
});
|
|
15998
|
-
/** 中段提交信息高度拖拽(clamp:下限 60,上限 = body 高 -
|
|
16287
|
+
/** 中段提交信息高度拖拽(clamp:下限 60,上限 = body 高 - 列表区/路径区/分隔条保留空间)。 */
|
|
15999
16288
|
const onMsgHDrag = (event) => startDrag(event, "y", msgH, (next) => {
|
|
16000
16289
|
const total = bodyRef.current?.clientHeight ?? 0;
|
|
16001
|
-
const max = Math.max(140, total - listH - PANE_KEEP_MIN);
|
|
16290
|
+
const max = Math.max(140, total - listH - PANE_KEEP_MIN - HSPLIT_TOTAL_PX);
|
|
16002
16291
|
setMsgH(Math.min(max, Math.max(MSG_H_MIN, next)));
|
|
16003
16292
|
});
|
|
16293
|
+
/**
|
|
16294
|
+
* 上/中段高度收敛进 body(初始挂载、dlgH 变化、双击复位共用;shrink-only 只缩不涨)。
|
|
16295
|
+
* 非本段占用 chrome 由 DOM 实测导出(= bodyH - 上中段 state - 下段实占;含 gap4×6 + 分隔条
|
|
16296
|
+
* 2×10 + 上段 padding/border6 + 中段 padding/border18 = 68px),免手算且 CSS 微调自动跟随;
|
|
16297
|
+
* 保下段 ≥ PANE_KEEP_MIN。极端小视口(预算 < 两段地板和)给各自下限不倒挂;
|
|
16298
|
+
* 地板救济:抬 list 至地板后超出从 msg 扣回(预算 ≥ 地板和保证不破对方地板)。
|
|
16299
|
+
* 只缩不涨 + 地板兜底,与拖拽 clamp 同向,天然不会与拖拽互相拉扯成循环。
|
|
16300
|
+
* @author ddj 2026年09月24号
|
|
16301
|
+
* @param wantList 目标上段(修订列表)高度
|
|
16302
|
+
* @param wantMsg 目标中段(提交信息)高度
|
|
16303
|
+
*/
|
|
16304
|
+
const fitHeights = (wantList, wantMsg) => {
|
|
16305
|
+
const total = bodyRef.current?.clientHeight ?? 0;
|
|
16306
|
+
if (!total) {
|
|
16307
|
+
setListH(wantList);
|
|
16308
|
+
setMsgH(wantMsg);
|
|
16309
|
+
return;
|
|
16310
|
+
}
|
|
16311
|
+
const paneOcc = paneRef.current?.offsetHeight ?? -1;
|
|
16312
|
+
const chrome = paneOcc >= 0 ? Math.max(0, total - listH - msgH - paneOcc) : HSPLIT_TOTAL_PX;
|
|
16313
|
+
const budget = total - PANE_KEEP_MIN - chrome;
|
|
16314
|
+
if (budget < 260) {
|
|
16315
|
+
setListH(Math.min(wantList, LIST_H_MIN));
|
|
16316
|
+
setMsgH(Math.min(wantMsg, MSG_H_MIN));
|
|
16317
|
+
return;
|
|
16318
|
+
}
|
|
16319
|
+
if (wantList + wantMsg <= budget) {
|
|
16320
|
+
setListH(wantList);
|
|
16321
|
+
setMsgH(wantMsg);
|
|
16322
|
+
return;
|
|
16323
|
+
}
|
|
16324
|
+
const scale = budget / (wantList + wantMsg);
|
|
16325
|
+
let nextList = Math.floor(wantList * scale);
|
|
16326
|
+
let nextMsg = Math.floor(wantMsg * scale);
|
|
16327
|
+
if (nextList < LIST_H_MIN) {
|
|
16328
|
+
nextList = LIST_H_MIN;
|
|
16329
|
+
nextMsg = Math.min(nextMsg, budget - nextList);
|
|
16330
|
+
} else if (nextMsg < MSG_H_MIN) {
|
|
16331
|
+
nextMsg = MSG_H_MIN;
|
|
16332
|
+
nextList = Math.min(nextList, budget - nextMsg);
|
|
16333
|
+
}
|
|
16334
|
+
setListH(nextList);
|
|
16335
|
+
setMsgH(nextMsg);
|
|
16336
|
+
};
|
|
16337
|
+
react.default.useEffect(() => {
|
|
16338
|
+
fitHeights(listH, msgH);
|
|
16339
|
+
}, [dlgH]);
|
|
16340
|
+
react.default.useEffect(() => {
|
|
16341
|
+
if (!list || fitOnDataRef.current) return;
|
|
16342
|
+
fitOnDataRef.current = true;
|
|
16343
|
+
fitHeights(listH, msgH);
|
|
16344
|
+
}, [list]);
|
|
16004
16345
|
react.default.useEffect(() => {
|
|
16005
16346
|
const onKey = (event) => {
|
|
16006
16347
|
if (event.key === "F5") {
|
|
@@ -16139,15 +16480,18 @@ window.__ModuleLoader__.load({
|
|
|
16139
16480
|
}), react.default.createElement(Splitter, {
|
|
16140
16481
|
title: "调整修订列表高度",
|
|
16141
16482
|
onDragStart: onListHDrag,
|
|
16142
|
-
onReset: () =>
|
|
16483
|
+
onReset: () => fitHeights(LIST_H_DEFAULT, msgH)
|
|
16143
16484
|
}), react.default.createElement("div", {
|
|
16144
16485
|
className: "edrv-svnlog-pane edrv-svnlog-msgpane",
|
|
16145
16486
|
style: { height: msgH }
|
|
16146
16487
|
}, react.default.createElement(LogMsgInner, { selected: visibleSelected })), react.default.createElement(Splitter, {
|
|
16147
16488
|
title: "调整提交信息区高度",
|
|
16148
16489
|
onDragStart: onMsgHDrag,
|
|
16149
|
-
onReset: () =>
|
|
16150
|
-
}), react.default.createElement("div", {
|
|
16490
|
+
onReset: () => fitHeights(listH, MSG_H_DEFAULT)
|
|
16491
|
+
}), react.default.createElement("div", {
|
|
16492
|
+
className: "edrv-svnlog-pane edrv-svnlog-pathspane",
|
|
16493
|
+
ref: paneRef
|
|
16494
|
+
}, react.default.createElement(LogPathsInner, {
|
|
16151
16495
|
selected: visibleSelected,
|
|
16152
16496
|
target,
|
|
16153
16497
|
onlyAffected,
|
|
@@ -16158,7 +16502,15 @@ window.__ModuleLoader__.load({
|
|
|
16158
16502
|
return react.default.createElement(ModalShell, {
|
|
16159
16503
|
dialogClass: "edrv-svnlog-dialog",
|
|
16160
16504
|
width: Math.round(dlgW) + "px",
|
|
16161
|
-
cardStyle:
|
|
16505
|
+
cardStyle: Object.assign({
|
|
16506
|
+
height: Math.round(dlgH) + "px",
|
|
16507
|
+
boxSizing: "border-box",
|
|
16508
|
+
maxHeight: "none"
|
|
16509
|
+
}, anchor ? {
|
|
16510
|
+
position: "absolute",
|
|
16511
|
+
left: Math.round(anchor.left) + "px",
|
|
16512
|
+
top: Math.round(anchor.top) + "px"
|
|
16513
|
+
} : null),
|
|
16162
16514
|
onClose
|
|
16163
16515
|
}, react.default.createElement(LogHead$1, {
|
|
16164
16516
|
target,
|
|
@@ -16199,26 +16551,37 @@ window.__ModuleLoader__.load({
|
|
|
16199
16551
|
onOpenRange: () => setRangeOpen(true),
|
|
16200
16552
|
onRangeReset: () => onRangeReset?.()
|
|
16201
16553
|
}), react.default.createElement(Grip, {
|
|
16202
|
-
mode: "
|
|
16554
|
+
mode: "n",
|
|
16203
16555
|
onDragStart: startResize,
|
|
16204
|
-
onReset:
|
|
16205
|
-
setDlgW(DIALOG_W_DEFAULT);
|
|
16206
|
-
setDlgH(DIALOG_H_DEFAULT);
|
|
16207
|
-
}
|
|
16556
|
+
onReset: resetDlgSize
|
|
16208
16557
|
}), react.default.createElement(Grip, {
|
|
16209
|
-
mode: "
|
|
16558
|
+
mode: "s",
|
|
16210
16559
|
onDragStart: startResize,
|
|
16211
|
-
onReset:
|
|
16212
|
-
setDlgW(DIALOG_W_DEFAULT);
|
|
16213
|
-
setDlgH(DIALOG_H_DEFAULT);
|
|
16214
|
-
}
|
|
16560
|
+
onReset: resetDlgSize
|
|
16215
16561
|
}), react.default.createElement(Grip, {
|
|
16216
|
-
mode: "
|
|
16562
|
+
mode: "w",
|
|
16217
16563
|
onDragStart: startResize,
|
|
16218
|
-
onReset:
|
|
16219
|
-
|
|
16220
|
-
|
|
16221
|
-
|
|
16564
|
+
onReset: resetDlgSize
|
|
16565
|
+
}), react.default.createElement(Grip, {
|
|
16566
|
+
mode: "e",
|
|
16567
|
+
onDragStart: startResize,
|
|
16568
|
+
onReset: resetDlgSize
|
|
16569
|
+
}), react.default.createElement(Grip, {
|
|
16570
|
+
mode: "nw",
|
|
16571
|
+
onDragStart: startResize,
|
|
16572
|
+
onReset: resetDlgSize
|
|
16573
|
+
}), react.default.createElement(Grip, {
|
|
16574
|
+
mode: "ne",
|
|
16575
|
+
onDragStart: startResize,
|
|
16576
|
+
onReset: resetDlgSize
|
|
16577
|
+
}), react.default.createElement(Grip, {
|
|
16578
|
+
mode: "sw",
|
|
16579
|
+
onDragStart: startResize,
|
|
16580
|
+
onReset: resetDlgSize
|
|
16581
|
+
}), react.default.createElement(Grip, {
|
|
16582
|
+
mode: "se",
|
|
16583
|
+
onDragStart: startResize,
|
|
16584
|
+
onReset: resetDlgSize
|
|
16222
16585
|
}), menu ? react.default.createElement(ContextMenu, {
|
|
16223
16586
|
x: menu.x,
|
|
16224
16587
|
y: menu.y,
|
|
@@ -16256,23 +16619,791 @@ window.__ModuleLoader__.load({
|
|
|
16256
16619
|
}, "确定")))) : null);
|
|
16257
16620
|
}
|
|
16258
16621
|
/**
|
|
16259
|
-
* 日期区间判定(P0-3:From/To 含当日全天;解析失败的条目不因区间被过滤)。
|
|
16260
|
-
* @author ddj 2026年09月17号
|
|
16261
|
-
* @param from 起始日(YYYY-MM-DD 或空)
|
|
16262
|
-
* @param to 结束日(YYYY-MM-DD 或空)
|
|
16263
|
-
* @returns 判定函数
|
|
16622
|
+
* 日期区间判定(P0-3:From/To 含当日全天;解析失败的条目不因区间被过滤)。
|
|
16623
|
+
* @author ddj 2026年09月17号
|
|
16624
|
+
* @param from 起始日(YYYY-MM-DD 或空)
|
|
16625
|
+
* @param to 结束日(YYYY-MM-DD 或空)
|
|
16626
|
+
* @returns 判定函数
|
|
16627
|
+
*/
|
|
16628
|
+
function dateRangePredicateOf(from, to) {
|
|
16629
|
+
if (!from && !to) return () => true;
|
|
16630
|
+
const min = from ? (/* @__PURE__ */ new Date(from + "T00:00:00")).getTime() : null;
|
|
16631
|
+
const max = to ? (/* @__PURE__ */ new Date(to + "T23:59:59.999")).getTime() : null;
|
|
16632
|
+
return (entry) => {
|
|
16633
|
+
const at = new Date(String(entry.date ?? "")).getTime();
|
|
16634
|
+
if (Number.isNaN(at)) return true;
|
|
16635
|
+
if (min !== null && at < min) return false;
|
|
16636
|
+
if (max !== null && at > max) return false;
|
|
16637
|
+
return true;
|
|
16638
|
+
};
|
|
16639
|
+
}
|
|
16640
|
+
//#endregion
|
|
16641
|
+
//#region src/client/ui/svnUpdateModel.ts
|
|
16642
|
+
/**
|
|
16643
|
+
* 只有真实终态允许直接关闭窗口。
|
|
16644
|
+
* @author ddj 2026年09月24号
|
|
16645
|
+
* @param phase 任务阶段
|
|
16646
|
+
* @returns 是否结束
|
|
16647
|
+
*/
|
|
16648
|
+
function updateDone(phase) {
|
|
16649
|
+
return phase === "completed" || phase === "failed" || phase === "cancelled";
|
|
16650
|
+
}
|
|
16651
|
+
/**
|
|
16652
|
+
* 后端结束并不等于前端已取完全部结果页。
|
|
16653
|
+
* @author ddj 2026年09月24号
|
|
16654
|
+
* @param phase 后台状态
|
|
16655
|
+
* @param pending 尚有未加载的明细
|
|
16656
|
+
* @returns 结果界面是否完成
|
|
16657
|
+
*/
|
|
16658
|
+
function updateReady(phase, pending) {
|
|
16659
|
+
return updateDone(phase) && !pending;
|
|
16660
|
+
}
|
|
16661
|
+
/**
|
|
16662
|
+
* 取消或异常终止会在工作副本上留下 SVN 锁(E155037/E155004);
|
|
16663
|
+
* 只按失败态原文判定,不推测其他失败的原因。
|
|
16664
|
+
* @author ddj 2026年09月28号
|
|
16665
|
+
* @param state 任务快照
|
|
16666
|
+
* @returns 是否需要先执行 cleanup
|
|
16667
|
+
*/
|
|
16668
|
+
function updateLocked(state) {
|
|
16669
|
+
if (!state || state.phase !== "failed") return false;
|
|
16670
|
+
const text = (state.error ?? "") + "\n" + (state.rawTail ?? "");
|
|
16671
|
+
return /E155037|E155004|Previous operation has not finished|run 'cleanup'|Working copy .*locked|工作副本.*锁/i.test(text);
|
|
16672
|
+
}
|
|
16673
|
+
/**
|
|
16674
|
+
* 菜单/二级对话框按 Esc 只关闭自己;连接中断后允许显式暂时关闭。
|
|
16675
|
+
* @author ddj 2026年09月24号
|
|
16676
|
+
* @param ready 已取完后台结果
|
|
16677
|
+
* @param error 连接错误
|
|
16678
|
+
* @param hasJob 是否知道后台 job
|
|
16679
|
+
* @param overlay 子弹窗或菜单是否打开
|
|
16680
|
+
* @returns 自动/显式关闭及确认要求
|
|
16681
|
+
*/
|
|
16682
|
+
function updateCloseMode(ready, error, hasJob, overlay) {
|
|
16683
|
+
return {
|
|
16684
|
+
passive: (ready || Boolean(error && !hasJob)) && !overlay,
|
|
16685
|
+
explicit: ready || Boolean(error),
|
|
16686
|
+
confirm: Boolean(error && hasJob && !ready)
|
|
16687
|
+
};
|
|
16688
|
+
}
|
|
16689
|
+
/**
|
|
16690
|
+
* 窗口只能在发起它的同一会话、同一工作区作用域中挂载。
|
|
16691
|
+
* @author ddj 2026年09月24号
|
|
16692
|
+
* @param dialog 发起窗口时记录的身份
|
|
16693
|
+
* @param sessionId 当前会话
|
|
16694
|
+
* @param scope 当前工作区作用域
|
|
16695
|
+
* @returns 是否允许挂载
|
|
16696
|
+
*/
|
|
16697
|
+
function sameUpdateOwner(dialog, sessionId, scope) {
|
|
16698
|
+
return Boolean(dialog && dialog.sessionId === sessionId && dialog.scope === scope);
|
|
16699
|
+
}
|
|
16700
|
+
/**
|
|
16701
|
+
* 为数千条结果取可视区和小幅缓冲,行高由界面固定约束。
|
|
16702
|
+
* @author ddj 2026年09月24号
|
|
16703
|
+
* @param count 当前记录数
|
|
16704
|
+
* @param scrollTop 列表滚动偏移
|
|
16705
|
+
* @param height 列表高度
|
|
16706
|
+
* @param rowHeight 固定行高
|
|
16707
|
+
* @returns 可见的起止索引(尾部不含)
|
|
16708
|
+
*/
|
|
16709
|
+
function updateRange(count, scrollTop, height, rowHeight) {
|
|
16710
|
+
return {
|
|
16711
|
+
start: Math.min(count, Math.max(0, Math.floor(Math.max(0, scrollTop) / rowHeight) - 8)),
|
|
16712
|
+
end: Math.min(count, Math.ceil((Math.max(0, scrollTop) + Math.max(0, height)) / rowHeight) + 8)
|
|
16713
|
+
};
|
|
16714
|
+
}
|
|
16715
|
+
/**
|
|
16716
|
+
* 输出不等于文件真实类型;只给已知扩展名提供可辨识的类型推断。
|
|
16717
|
+
* @author ddj 2026年09月24号
|
|
16718
|
+
* @param path SVN 输出路径
|
|
16719
|
+
* @returns 推断类型,未知为空
|
|
16720
|
+
*/
|
|
16721
|
+
function updateType(path) {
|
|
16722
|
+
const ext = path.split(".").pop()?.toLowerCase();
|
|
16723
|
+
return ext ? {
|
|
16724
|
+
bytes: "application/octet-stream",
|
|
16725
|
+
png: "image/png",
|
|
16726
|
+
jpg: "image/jpeg",
|
|
16727
|
+
jpeg: "image/jpeg",
|
|
16728
|
+
webp: "image/webp",
|
|
16729
|
+
gif: "image/gif",
|
|
16730
|
+
pdf: "application/pdf"
|
|
16731
|
+
}[ext] ?? "" : "";
|
|
16732
|
+
}
|
|
16733
|
+
/**
|
|
16734
|
+
* 行动作是否可用取决于更新是否结束、路径是否在工作区且磁盘是否有文件。
|
|
16735
|
+
* @author ddj 2026年09月24号
|
|
16736
|
+
* @param row 更新行
|
|
16737
|
+
* @param phase 任务阶段
|
|
16738
|
+
* @param kind 磁盘判型;未读到时仅开放父目录/复制
|
|
16739
|
+
* @param revision 完成修订号
|
|
16740
|
+
* @returns 菜单动作集合
|
|
16741
|
+
*/
|
|
16742
|
+
function updateActs(row, phase, kind, revision) {
|
|
16743
|
+
const valid = updateDone(phase) && Boolean(row.relPath);
|
|
16744
|
+
const file = valid && kind === "file" && row.action !== "D";
|
|
16745
|
+
const binary = Boolean(updateType(row.path));
|
|
16746
|
+
return {
|
|
16747
|
+
compare: file && Boolean(revision) && !binary,
|
|
16748
|
+
log: file,
|
|
16749
|
+
open: file,
|
|
16750
|
+
openWith: file,
|
|
16751
|
+
parent: valid,
|
|
16752
|
+
copy: Boolean(row.path)
|
|
16753
|
+
};
|
|
16754
|
+
}
|
|
16755
|
+
/**
|
|
16756
|
+
* 目录上下文使用工作区相对路径,根文件的父目录表示为工作区根。
|
|
16757
|
+
* @author ddj 2026年09月24号
|
|
16758
|
+
* @param path 工作区相对路径
|
|
16759
|
+
* @returns 父目录相对路径
|
|
16760
|
+
*/
|
|
16761
|
+
function updateParent(path) {
|
|
16762
|
+
const normalized = path.replace(/\\/g, "/");
|
|
16763
|
+
const at = normalized.lastIndexOf("/");
|
|
16764
|
+
return at < 0 ? "" : normalized.slice(0, at);
|
|
16765
|
+
}
|
|
16766
|
+
//#endregion
|
|
16767
|
+
//#region src/client/ui/SvnUpdateDialog.ts
|
|
16768
|
+
/**
|
|
16769
|
+
* dsh-vscode-mode client — live SVN update dialog with bounded virtual rows.
|
|
16770
|
+
* @author ddj 2026年09月24号
|
|
16771
|
+
*/
|
|
16772
|
+
/**
|
|
16773
|
+
* 仅恢复明确匹配的原任务;失败时不重新触发一次 SVN 更新。
|
|
16774
|
+
* @author ddj 2026年09月24号
|
|
16775
|
+
* @param props 会话与更新目标
|
|
16776
|
+
* @returns 已启动或已恢复的任务
|
|
16777
|
+
*/
|
|
16778
|
+
async function connectUpdate(props) {
|
|
16779
|
+
const result = props.resumeJobId ? await rpc("svn.updateActive", { sessionId: props.sessionId }) : await rpc("svn.updateStart", {
|
|
16780
|
+
sessionId: props.sessionId,
|
|
16781
|
+
path: props.path
|
|
16782
|
+
});
|
|
16783
|
+
if (!result.ok) throw new Error(result.error);
|
|
16784
|
+
const job = "job" in result ? result.job : result;
|
|
16785
|
+
if (!job || props.resumeJobId && job.jobId !== props.resumeJobId) throw new Error("上次 SVN 更新结果已过期");
|
|
16786
|
+
return job;
|
|
16787
|
+
}
|
|
16788
|
+
/**
|
|
16789
|
+
* 按后端有效序号剔除过期行;无新行时保留数组身份,避免多余渲染。
|
|
16790
|
+
* @author ddj 2026年09月24号
|
|
16791
|
+
* @param previous 当前可视记录
|
|
16792
|
+
* @param result 本次增量响应
|
|
16793
|
+
* @returns 新记录集
|
|
16794
|
+
*/
|
|
16795
|
+
function mergeUpdateRows(previous, result) {
|
|
16796
|
+
if (!result.rows.length && (previous[0]?.seq ?? result.offset) >= result.offset) return previous;
|
|
16797
|
+
return previous.filter((row) => row.seq >= result.offset).concat(result.rows).slice(-2e4);
|
|
16798
|
+
}
|
|
16799
|
+
/**
|
|
16800
|
+
* 轮询状态:保留已收到的行,后端页大小与 UI 可见行数独立。
|
|
16801
|
+
* @author ddj 2026年09月24号
|
|
16802
|
+
* @param props 窗口目标与回调
|
|
16803
|
+
* @returns 状态、行、连接错误
|
|
16804
|
+
*/
|
|
16805
|
+
function useUpdateJob(props) {
|
|
16806
|
+
const [state, setState] = react.default.useState(null);
|
|
16807
|
+
const [rows, setRows] = react.default.useState([]);
|
|
16808
|
+
const [error, setError] = react.default.useState("");
|
|
16809
|
+
const [pendingRows, setPendingRows] = react.default.useState(false);
|
|
16810
|
+
const doneRef = react.default.useRef("");
|
|
16811
|
+
const onDoneRef = react.default.useRef(props.onDone);
|
|
16812
|
+
onDoneRef.current = props.onDone;
|
|
16813
|
+
/**
|
|
16814
|
+
* 仅在目标变化时连接任务,销毁时停止客户端轮询但不隐式取消更新。
|
|
16815
|
+
* @author ddj 2026年09月24号
|
|
16816
|
+
* @returns 轮询释放回调
|
|
16817
|
+
*/
|
|
16818
|
+
const watchJob = () => {
|
|
16819
|
+
let alive = true;
|
|
16820
|
+
let busy = false;
|
|
16821
|
+
let jobId = "";
|
|
16822
|
+
let since = 0;
|
|
16823
|
+
/**
|
|
16824
|
+
* 每轮至多请求一页,等待下一轮继续追赶后台任务。
|
|
16825
|
+
* @author ddj 2026年09月24号
|
|
16826
|
+
*/
|
|
16827
|
+
const poll = async () => {
|
|
16828
|
+
if (!alive || busy || !jobId) return;
|
|
16829
|
+
busy = true;
|
|
16830
|
+
try {
|
|
16831
|
+
const result = await rpc("svn.updatePoll", {
|
|
16832
|
+
sessionId: props.sessionId,
|
|
16833
|
+
jobId,
|
|
16834
|
+
since
|
|
16835
|
+
});
|
|
16836
|
+
if (!alive) return;
|
|
16837
|
+
if (!result.ok) {
|
|
16838
|
+
setError(result.error);
|
|
16839
|
+
return;
|
|
16840
|
+
}
|
|
16841
|
+
setError("");
|
|
16842
|
+
since = result.nextSeq;
|
|
16843
|
+
const backlog = result.nextSeq < result.totalSeq;
|
|
16844
|
+
setPendingRows(backlog);
|
|
16845
|
+
setState(result);
|
|
16846
|
+
setRows((previous) => mergeUpdateRows(previous, result));
|
|
16847
|
+
if (updateDone(result.phase) && !backlog) window.clearInterval(timer);
|
|
16848
|
+
if (updateDone(result.phase) && !backlog && doneRef.current !== jobId) {
|
|
16849
|
+
doneRef.current = jobId;
|
|
16850
|
+
onDoneRef.current(result);
|
|
16851
|
+
}
|
|
16852
|
+
if (backlog && result.rows.length) window.setTimeout(() => {
|
|
16853
|
+
poll();
|
|
16854
|
+
}, 0);
|
|
16855
|
+
} catch (cause) {
|
|
16856
|
+
if (alive) setError("连接更新任务失败:" + String(cause));
|
|
16857
|
+
} finally {
|
|
16858
|
+
busy = false;
|
|
16859
|
+
}
|
|
16860
|
+
};
|
|
16861
|
+
/**
|
|
16862
|
+
* 恢复原任务或首次启动;UI 错误可见但绝不自动重试 SVN update。
|
|
16863
|
+
* @author ddj 2026年09月24号
|
|
16864
|
+
*/
|
|
16865
|
+
const connect = async () => {
|
|
16866
|
+
try {
|
|
16867
|
+
const job = await connectUpdate(props);
|
|
16868
|
+
if (!alive) return;
|
|
16869
|
+
jobId = job.jobId;
|
|
16870
|
+
setState(job);
|
|
16871
|
+
setPendingRows(updateDone(job.phase));
|
|
16872
|
+
poll();
|
|
16873
|
+
} catch (cause) {
|
|
16874
|
+
if (alive) setError("连接更新任务失败:" + String(cause));
|
|
16875
|
+
}
|
|
16876
|
+
};
|
|
16877
|
+
setRows([]);
|
|
16878
|
+
setState(null);
|
|
16879
|
+
setError("");
|
|
16880
|
+
setPendingRows(false);
|
|
16881
|
+
doneRef.current = "";
|
|
16882
|
+
connect();
|
|
16883
|
+
const timer = window.setInterval(() => {
|
|
16884
|
+
poll();
|
|
16885
|
+
}, 350);
|
|
16886
|
+
return () => {
|
|
16887
|
+
alive = false;
|
|
16888
|
+
window.clearInterval(timer);
|
|
16889
|
+
};
|
|
16890
|
+
};
|
|
16891
|
+
react.default.useEffect(watchJob, [
|
|
16892
|
+
props.sessionId,
|
|
16893
|
+
props.path,
|
|
16894
|
+
props.resumeJobId
|
|
16895
|
+
]);
|
|
16896
|
+
return {
|
|
16897
|
+
state,
|
|
16898
|
+
rows,
|
|
16899
|
+
error,
|
|
16900
|
+
pendingRows,
|
|
16901
|
+
setState
|
|
16902
|
+
};
|
|
16903
|
+
}
|
|
16904
|
+
/**
|
|
16905
|
+
* 中文计数只报告已观察到的条目,截断输出时 UI 会单独告警。
|
|
16906
|
+
* @author ddj 2026年09月24号
|
|
16907
|
+
* @param state 任务快照
|
|
16908
|
+
* @returns 可读的状态行
|
|
16909
|
+
*/
|
|
16910
|
+
function countText(state) {
|
|
16911
|
+
if (!state) return "等待 SVN 任务…";
|
|
16912
|
+
const c = state.counts;
|
|
16913
|
+
return "合并 " + c.G + " · 新增 " + c.A + " · 删除 " + c.D + " · 更新 " + c.U + " · 冲突 " + c.C + (c.R || c.E ? " · 其他 " + (c.R + c.E) : "");
|
|
16914
|
+
}
|
|
16915
|
+
/**
|
|
16916
|
+
* 右键命令:可用性先经会话内路径守卫,再依据真实文件判型。
|
|
16917
|
+
* @author ddj 2026年09月24号
|
|
16918
|
+
* @param props 窗口回调
|
|
16919
|
+
* @param state 任务状态
|
|
16920
|
+
* @param menu 右键目标及文件判型
|
|
16921
|
+
* @param rows 当前结果列表
|
|
16922
|
+
* @param selected 已选序号
|
|
16923
|
+
* @returns 可点击动作列表
|
|
16924
|
+
*/
|
|
16925
|
+
function menuEntries(props, state, menu, rows, selected) {
|
|
16926
|
+
const { row, kind } = menu;
|
|
16927
|
+
const actions = updateActs(row, state.phase, kind, state.revision);
|
|
16928
|
+
const rel = row.relPath ?? "";
|
|
16929
|
+
const picked = new Set(selected);
|
|
16930
|
+
const names = rows.filter((item) => picked.has(item.seq)).map((item) => item.relPath ? absoluteOf(item.relPath, props.cwd) : item.path);
|
|
16931
|
+
return [
|
|
16932
|
+
{
|
|
16933
|
+
id: "compare",
|
|
16934
|
+
label: "与工作副本比较",
|
|
16935
|
+
disabled: !actions.compare,
|
|
16936
|
+
onClick: () => props.onCompare(rel, state.revision, state.jobId)
|
|
16937
|
+
},
|
|
16938
|
+
{
|
|
16939
|
+
id: "log",
|
|
16940
|
+
label: "查看日志",
|
|
16941
|
+
disabled: !actions.log,
|
|
16942
|
+
onClick: () => props.onShowLog(rel, state.jobId)
|
|
16943
|
+
},
|
|
16944
|
+
{
|
|
16945
|
+
id: "open",
|
|
16946
|
+
label: "打开",
|
|
16947
|
+
disabled: !actions.open,
|
|
16948
|
+
separator: true,
|
|
16949
|
+
onClick: () => props.onOpenFile(rel)
|
|
16950
|
+
},
|
|
16951
|
+
{
|
|
16952
|
+
id: "open-with",
|
|
16953
|
+
label: "打开方式…",
|
|
16954
|
+
disabled: !actions.openWith,
|
|
16955
|
+
onClick: () => props.onOpenWith(rel)
|
|
16956
|
+
},
|
|
16957
|
+
{
|
|
16958
|
+
id: "parent",
|
|
16959
|
+
label: "打开父目录",
|
|
16960
|
+
disabled: !actions.parent,
|
|
16961
|
+
onClick: () => props.onOpenParent(updateParent(rel))
|
|
16962
|
+
},
|
|
16963
|
+
{
|
|
16964
|
+
id: "copy",
|
|
16965
|
+
label: selected.length > 1 ? "复制选中路径" : "复制路径",
|
|
16966
|
+
disabled: !actions.copy,
|
|
16967
|
+
separator: true,
|
|
16968
|
+
onClick: () => {
|
|
16969
|
+
copyText(names.join("\n"), "已复制路径", props.onNote);
|
|
16970
|
+
}
|
|
16971
|
+
}
|
|
16972
|
+
];
|
|
16973
|
+
}
|
|
16974
|
+
/**
|
|
16975
|
+
* 将一条增量行映射为高密度的三列;单元格显示工作副本内相对路径,完整绝对路径留在 title 中。
|
|
16976
|
+
* @author ddj 2026年09月24号
|
|
16977
|
+
* @param row 更新行
|
|
16978
|
+
* @param cwd 工作区目录
|
|
16979
|
+
* @param picked 是否选中
|
|
16980
|
+
* @param onPick 选择回调
|
|
16981
|
+
* @param onMenu 右键回调
|
|
16982
|
+
* @returns 行元素
|
|
16983
|
+
*/
|
|
16984
|
+
function rowElement(row, cwd, picked, onPick, onMenu) {
|
|
16985
|
+
const full = row.relPath ? absoluteOf(row.relPath, cwd) : row.path || row.label;
|
|
16986
|
+
const path = row.relPath || row.path || row.label;
|
|
16987
|
+
const tone = row.action === "C" ? "conflict" : row.action === "D" ? "deleted" : row.action === "A" ? "added" : row.action === "G" ? "merged" : "updated";
|
|
16988
|
+
return react.default.createElement("div", {
|
|
16989
|
+
role: "row",
|
|
16990
|
+
"aria-selected": picked,
|
|
16991
|
+
className: "edrv-update-row" + (picked ? " is-selected" : ""),
|
|
16992
|
+
onClick: onPick,
|
|
16993
|
+
onContextMenu: onMenu,
|
|
16994
|
+
title: row.raw
|
|
16995
|
+
}, react.default.createElement("span", {
|
|
16996
|
+
role: "cell",
|
|
16997
|
+
className: "edrv-update-action tone-" + tone
|
|
16998
|
+
}, row.action ? row.label : "信息"), react.default.createElement("span", {
|
|
16999
|
+
role: "cell",
|
|
17000
|
+
className: "edrv-update-path",
|
|
17001
|
+
title: full
|
|
17002
|
+
}, path), react.default.createElement("span", {
|
|
17003
|
+
role: "cell",
|
|
17004
|
+
className: "edrv-update-type"
|
|
17005
|
+
}, row.action ? updateType(row.path) : ""));
|
|
17006
|
+
}
|
|
17007
|
+
/**
|
|
17008
|
+
* 观察列表尺寸并只跟随用户尚未滚离底部的更新结果。
|
|
17009
|
+
* @author ddj 2026年09月24号
|
|
17010
|
+
* @param count 当前记录数
|
|
17011
|
+
* @returns 虚拟列表视口、行高和滚动回调
|
|
17012
|
+
*/
|
|
17013
|
+
function useUpdateView(count) {
|
|
17014
|
+
const [scrollTop, setScrollTop] = react.default.useState(0);
|
|
17015
|
+
const [height, setHeight] = react.default.useState(350);
|
|
17016
|
+
const [compact, setCompact] = react.default.useState(() => window.innerWidth < 620);
|
|
17017
|
+
const listRef = react.default.useRef(null);
|
|
17018
|
+
const followRef = react.default.useRef(true);
|
|
17019
|
+
const rowHeight = compact ? 44 : 28;
|
|
17020
|
+
react.default.useEffect(() => {
|
|
17021
|
+
const list = listRef.current;
|
|
17022
|
+
if (!list) return;
|
|
17023
|
+
const observer = new ResizeObserver(() => setHeight(list.clientHeight));
|
|
17024
|
+
observer.observe(list);
|
|
17025
|
+
setHeight(list.clientHeight);
|
|
17026
|
+
const resize = () => setCompact(window.innerWidth < 620);
|
|
17027
|
+
window.addEventListener("resize", resize);
|
|
17028
|
+
return () => {
|
|
17029
|
+
observer.disconnect();
|
|
17030
|
+
window.removeEventListener("resize", resize);
|
|
17031
|
+
};
|
|
17032
|
+
}, []);
|
|
17033
|
+
react.default.useLayoutEffect(() => {
|
|
17034
|
+
const list = listRef.current;
|
|
17035
|
+
if (list && followRef.current) {
|
|
17036
|
+
list.scrollTop = list.scrollHeight;
|
|
17037
|
+
setScrollTop(list.scrollTop);
|
|
17038
|
+
}
|
|
17039
|
+
}, [count, rowHeight]);
|
|
17040
|
+
/**
|
|
17041
|
+
* 用户离开底部后暂停自动滚动,保持当前文件可读。
|
|
17042
|
+
* @author ddj 2026年09月24号
|
|
17043
|
+
* @param event 列表滚动事件
|
|
17044
|
+
*/
|
|
17045
|
+
const onScroll = (event) => {
|
|
17046
|
+
const list = event.currentTarget;
|
|
17047
|
+
followRef.current = list.scrollHeight - list.scrollTop - list.clientHeight < 40;
|
|
17048
|
+
setScrollTop(list.scrollTop);
|
|
17049
|
+
};
|
|
17050
|
+
return {
|
|
17051
|
+
listRef,
|
|
17052
|
+
rowHeight,
|
|
17053
|
+
range: updateRange(count, scrollTop, height, rowHeight),
|
|
17054
|
+
onScroll
|
|
17055
|
+
};
|
|
17056
|
+
}
|
|
17057
|
+
/**
|
|
17058
|
+
* 行选择、右键文件判型与菜单状态只在可见行交互时运行。
|
|
17059
|
+
* @author ddj 2026年09月24号
|
|
17060
|
+
* @param props 窗口回调
|
|
17061
|
+
* @param rows 增量结果
|
|
17062
|
+
* @param state 任务状态
|
|
17063
|
+
* @returns 选择集和交互回调
|
|
17064
|
+
*/
|
|
17065
|
+
function useUpdateMenu(props, rows, state) {
|
|
17066
|
+
const [selected, setSelected] = react.default.useState([]);
|
|
17067
|
+
const [menu, setMenu] = react.default.useState(null);
|
|
17068
|
+
const anchorRef = react.default.useRef(0);
|
|
17069
|
+
const picked = react.default.useMemo(() => new Set(selected), [selected]);
|
|
17070
|
+
/**
|
|
17071
|
+
* 支持普通、Ctrl 和 Shift 范围选择。
|
|
17072
|
+
* @author ddj 2026年09月24号
|
|
17073
|
+
* @param event 行点击事件
|
|
17074
|
+
* @param row 目标行
|
|
17075
|
+
*/
|
|
17076
|
+
const pick = (event, row) => {
|
|
17077
|
+
const index = rows.findIndex((item) => item.seq === row.seq);
|
|
17078
|
+
if (event.shiftKey) {
|
|
17079
|
+
const from = Math.min(index, anchorRef.current);
|
|
17080
|
+
const to = Math.max(index, anchorRef.current);
|
|
17081
|
+
setSelected(rows.slice(from, to + 1).map((item) => item.seq));
|
|
17082
|
+
} else if (event.ctrlKey || event.metaKey) {
|
|
17083
|
+
setSelected((previous) => previous.includes(row.seq) ? previous.filter((seq) => seq !== row.seq) : previous.concat(row.seq));
|
|
17084
|
+
anchorRef.current = index;
|
|
17085
|
+
} else {
|
|
17086
|
+
setSelected([row.seq]);
|
|
17087
|
+
anchorRef.current = index;
|
|
17088
|
+
}
|
|
17089
|
+
};
|
|
17090
|
+
/**
|
|
17091
|
+
* 先开放父目录/复制,再按真实磁盘类型启用文件级操作。
|
|
17092
|
+
* @author ddj 2026年09月24号
|
|
17093
|
+
* @param event 右键位置
|
|
17094
|
+
* @param row 目标行
|
|
17095
|
+
*/
|
|
17096
|
+
const openMenu = (event, row) => {
|
|
17097
|
+
event.preventDefault();
|
|
17098
|
+
event.stopPropagation();
|
|
17099
|
+
if (!state) return;
|
|
17100
|
+
if (!picked.has(row.seq)) setSelected([row.seq]);
|
|
17101
|
+
setMenu({
|
|
17102
|
+
x: event.clientX,
|
|
17103
|
+
y: event.clientY,
|
|
17104
|
+
row,
|
|
17105
|
+
kind: "loading"
|
|
17106
|
+
});
|
|
17107
|
+
if (!row.relPath || !updateDone(state.phase) || row.action === "D") return;
|
|
17108
|
+
rpc("edrv.externalStat", { path: absoluteOf(row.relPath, props.cwd) }).then((outcome) => {
|
|
17109
|
+
setMenu((current) => current?.row.seq === row.seq ? {
|
|
17110
|
+
...current,
|
|
17111
|
+
kind: outcome.ok ? outcome.kind : "missing"
|
|
17112
|
+
} : current);
|
|
17113
|
+
}).catch(() => {});
|
|
17114
|
+
};
|
|
17115
|
+
return {
|
|
17116
|
+
selected,
|
|
17117
|
+
picked,
|
|
17118
|
+
menu,
|
|
17119
|
+
setMenu,
|
|
17120
|
+
pick,
|
|
17121
|
+
openMenu
|
|
17122
|
+
};
|
|
17123
|
+
}
|
|
17124
|
+
/**
|
|
17125
|
+
* 窗口标题和执行阶段(无活动任务时仍可展示目标)。
|
|
17126
|
+
* @author ddj 2026年09月24号
|
|
17127
|
+
* @param props 用户目标与关闭动作
|
|
17128
|
+
* @param state 任务状态
|
|
17129
|
+
* @param phase 当前阶段文案
|
|
17130
|
+
* @param closable 能否显式关闭
|
|
17131
|
+
* @param dismiss 确认后的关闭动作
|
|
17132
|
+
* @returns 标题元素
|
|
17133
|
+
*/
|
|
17134
|
+
function updateHead(props, state, phase, closable, dismiss) {
|
|
17135
|
+
return react.default.createElement("header", { className: "edrv-update-head" }, react.default.createElement("div", { className: "edrv-update-heading" }, react.default.createElement("h3", null, "SVN 更新"), react.default.createElement("span", {
|
|
17136
|
+
className: "edrv-update-target",
|
|
17137
|
+
title: state?.target ?? props.path
|
|
17138
|
+
}, state?.target || "工作区根")), react.default.createElement("span", {
|
|
17139
|
+
className: "edrv-update-phase",
|
|
17140
|
+
role: "status"
|
|
17141
|
+
}, phase), react.default.createElement("button", {
|
|
17142
|
+
type: "button",
|
|
17143
|
+
className: "edrv-update-close",
|
|
17144
|
+
disabled: !closable,
|
|
17145
|
+
title: closable ? "关闭更新窗口" : "更新运行中;请先取消",
|
|
17146
|
+
"aria-label": "关闭更新窗口",
|
|
17147
|
+
onClick: dismiss
|
|
17148
|
+
}, "✕"));
|
|
17149
|
+
}
|
|
17150
|
+
/**
|
|
17151
|
+
* 固定列头与虚拟行区域;只渲染当前视口附近的条目。
|
|
17152
|
+
* @author ddj 2026年09月24号
|
|
17153
|
+
* @param props 工作区路径
|
|
17154
|
+
* @param rows 已收到的更新行
|
|
17155
|
+
* @param view 虚拟滚动视口
|
|
17156
|
+
* @param selection 行选择/菜单
|
|
17157
|
+
* @param finished 是否终态
|
|
17158
|
+
* @returns 表格元素
|
|
17159
|
+
*/
|
|
17160
|
+
function updateTable(props, rows, view, selection, finished) {
|
|
17161
|
+
const visible = rows.slice(view.range.start, view.range.end);
|
|
17162
|
+
return react.default.createElement("div", {
|
|
17163
|
+
className: "edrv-update-table",
|
|
17164
|
+
role: "table",
|
|
17165
|
+
"aria-label": "SVN 更新文件明细",
|
|
17166
|
+
"aria-rowcount": rows.length
|
|
17167
|
+
}, react.default.createElement("div", {
|
|
17168
|
+
role: "row",
|
|
17169
|
+
className: "edrv-update-cols"
|
|
17170
|
+
}, react.default.createElement("span", { role: "columnheader" }, "操作"), react.default.createElement("span", { role: "columnheader" }, "路径"), react.default.createElement("span", {
|
|
17171
|
+
role: "columnheader",
|
|
17172
|
+
title: "仅对已知扩展名推断,非 SVN 属性"
|
|
17173
|
+
}, "类型(推断)")), react.default.createElement("div", {
|
|
17174
|
+
className: "edrv-update-list",
|
|
17175
|
+
ref: view.listRef,
|
|
17176
|
+
role: "rowgroup",
|
|
17177
|
+
onScroll: view.onScroll
|
|
17178
|
+
}, react.default.createElement("div", {
|
|
17179
|
+
className: "edrv-update-space",
|
|
17180
|
+
style: { height: rows.length * view.rowHeight }
|
|
17181
|
+
}, visible.map((row, index) => react.default.createElement("div", {
|
|
17182
|
+
key: row.seq,
|
|
17183
|
+
className: "edrv-update-pos",
|
|
17184
|
+
style: {
|
|
17185
|
+
top: (view.range.start + index) * view.rowHeight,
|
|
17186
|
+
height: view.rowHeight
|
|
17187
|
+
},
|
|
17188
|
+
"aria-rowindex": view.range.start + index + 1
|
|
17189
|
+
}, rowElement(row, props.cwd, selection.picked.has(row.seq), (event) => selection.pick(event, row), (event) => selection.openMenu(event, row))))), !rows.length ? react.default.createElement("div", { className: "edrv-update-empty" }, finished ? "没有逐文件变更" : "等待 SVN 输出…") : null));
|
|
17190
|
+
}
|
|
17191
|
+
/**
|
|
17192
|
+
* 真实修订号、耗时和错误回显;输出不完整时醒目标记;
|
|
17193
|
+
* 被中断的操作留下 SVN 锁时明确引导先清理,避免用户反复重试。
|
|
17194
|
+
* @author ddj 2026年09月24号
|
|
17195
|
+
* @param state 任务快照
|
|
17196
|
+
* @param error 连接错误
|
|
17197
|
+
* @param cleaned 本次窗口内是否已执行过清理
|
|
17198
|
+
* @returns 状态元素
|
|
17199
|
+
*/
|
|
17200
|
+
function updateStatus(state, error, cleaned) {
|
|
17201
|
+
const duration = state ? (state.elapsedMs / 1e3).toFixed(1) + " 秒" : "";
|
|
17202
|
+
const locked = updateLocked(state);
|
|
17203
|
+
return react.default.createElement("div", {
|
|
17204
|
+
className: "edrv-update-telemetry",
|
|
17205
|
+
role: "status"
|
|
17206
|
+
}, error || state?.error ? react.default.createElement("span", { className: "edrv-update-error" }, error || state?.error) : null, locked ? react.default.createElement("span", { className: "edrv-update-locked" }, cleaned ? "已执行清理,可重新点击「SVN 更新」" : "工作副本被上次中断的操作锁定:请先执行清理再重试") : null, react.default.createElement("span", null, (state?.revision ? "r" + state.revision + " · " : "") + "已耗时 " + duration), state?.truncated ? react.default.createElement("span", { className: "edrv-update-warning" }, "输出已截断,列表与计数可能不完整") : null);
|
|
17207
|
+
}
|
|
17208
|
+
/**
|
|
17209
|
+
* 运行时仅可取消,结束后才可查看日志或关闭;
|
|
17210
|
+
* 失败于工作副本锁定时额外提供一次清理入口(不自动重试更新)。
|
|
17211
|
+
* @author ddj 2026年09月24号
|
|
17212
|
+
* @param props 窗口动作
|
|
17213
|
+
* @param state 任务快照
|
|
17214
|
+
* @param closable 能否关闭
|
|
17215
|
+
* @param finished 是否终态
|
|
17216
|
+
* @param cancel 终止请求
|
|
17217
|
+
* @param dismiss 明确关闭或暂时退出窗口
|
|
17218
|
+
* @param confirmClose 是否要提示后台可能继续运行
|
|
17219
|
+
* @param cleaned 本次窗口内是否已执行过清理
|
|
17220
|
+
* @param cleanup 请求清理工作副本
|
|
17221
|
+
* @returns 操作区
|
|
17222
|
+
*/
|
|
17223
|
+
function updateFoot(props, state, closable, finished, cancel, dismiss, confirmClose, cleaned, cleanup) {
|
|
17224
|
+
const locked = updateLocked(state);
|
|
17225
|
+
return react.default.createElement("footer", { className: "edrv-update-foot" }, react.default.createElement("span", { className: "edrv-update-counts" }, countText(state)), locked ? react.default.createElement("button", {
|
|
17226
|
+
type: "button",
|
|
17227
|
+
className: "edrv-svn-act edrv-update-cleanup",
|
|
17228
|
+
disabled: !finished || cleaned,
|
|
17229
|
+
title: locked && !cleaned ? "执行 svn cleanup,清除中断残留的锁(不撤销已完成的更新)" : "已执行过清理",
|
|
17230
|
+
onClick: cleanup
|
|
17231
|
+
}, cleaned ? "已清理" : "执行清理") : null, react.default.createElement("button", {
|
|
17232
|
+
type: "button",
|
|
17233
|
+
className: "edrv-svn-act",
|
|
17234
|
+
disabled: !finished || !state,
|
|
17235
|
+
onClick: () => state && props.onShowLog(state.target, state.jobId)
|
|
17236
|
+
}, "查看日志"), react.default.createElement("button", {
|
|
17237
|
+
type: "button",
|
|
17238
|
+
className: "edrv-svn-act edrv-update-primary",
|
|
17239
|
+
disabled: !closable,
|
|
17240
|
+
onClick: dismiss
|
|
17241
|
+
}, confirmClose ? "暂时关闭" : "确定"), react.default.createElement("button", {
|
|
17242
|
+
type: "button",
|
|
17243
|
+
className: "edrv-svn-act",
|
|
17244
|
+
disabled: !state || updateDone(state.phase) || state.phase === "cancelling",
|
|
17245
|
+
onClick: cancel
|
|
17246
|
+
}, "取消更新"));
|
|
17247
|
+
}
|
|
17248
|
+
/**
|
|
17249
|
+
* 原生 SVN 更新窗口;任务只在用户打开后启动,运行中不静默关闭。
|
|
17250
|
+
* @author ddj 2026年09月24号
|
|
17251
|
+
* @param props 目标与 EditorView 的复用动作
|
|
17252
|
+
* @returns 更新窗口
|
|
17253
|
+
*/
|
|
17254
|
+
function SvnUpdateDialog(props) {
|
|
17255
|
+
const { state, rows, error, pendingRows, setState } = useUpdateJob(props);
|
|
17256
|
+
const [cleaned, setCleaned] = react.default.useState(false);
|
|
17257
|
+
const view = useUpdateView(rows.length);
|
|
17258
|
+
const selection = useUpdateMenu(props, rows, state);
|
|
17259
|
+
const processFinished = updateDone(state?.phase);
|
|
17260
|
+
const finished = updateReady(state?.phase, pendingRows);
|
|
17261
|
+
const closeMode = updateCloseMode(finished, error, Boolean(state), Boolean(selection.menu || props.childOverlay));
|
|
17262
|
+
const closable = closeMode.explicit;
|
|
17263
|
+
/**
|
|
17264
|
+
* 确认后请求终止任务;已变更文件不会自动回滚。
|
|
17265
|
+
* @author ddj 2026年09月24号
|
|
17266
|
+
*/
|
|
17267
|
+
const cancel = () => {
|
|
17268
|
+
if (!state || processFinished || state.phase === "cancelling") return;
|
|
17269
|
+
if (!window.confirm("停止 SVN 更新?已更新的文件不会回滚,工作副本可能仅完成一部分。")) return;
|
|
17270
|
+
rpc("svn.updateCancel", {
|
|
17271
|
+
sessionId: props.sessionId,
|
|
17272
|
+
jobId: state.jobId
|
|
17273
|
+
}).then((outcome) => {
|
|
17274
|
+
if (outcome.ok) setState(outcome);
|
|
17275
|
+
else props.onNote(outcome.error);
|
|
17276
|
+
}).catch((cause) => props.onNote("取消更新失败:" + String(cause)));
|
|
17277
|
+
};
|
|
17278
|
+
/**
|
|
17279
|
+
* 清理只修复工作副本锁,绝不自动重跑更新;结果经提示条回报。
|
|
17280
|
+
* @author ddj 2026年09月28号
|
|
17281
|
+
*/
|
|
17282
|
+
const cleanup = () => {
|
|
17283
|
+
if (!updateLocked(state) || cleaned) return;
|
|
17284
|
+
if (!window.confirm("对工作副本执行 svn cleanup?这会清除上次中断残留的锁,不会撤销已完成的更新。")) return;
|
|
17285
|
+
rpc("svn.cleanup", { sessionId: props.sessionId }).then((outcome) => {
|
|
17286
|
+
if (outcome.ok) {
|
|
17287
|
+
setCleaned(true);
|
|
17288
|
+
props.onNote("清理完成,可重新执行 SVN 更新");
|
|
17289
|
+
} else props.onNote(outcome.error);
|
|
17290
|
+
}).catch((cause) => props.onNote("清理失败:" + String(cause)));
|
|
17291
|
+
};
|
|
17292
|
+
/**
|
|
17293
|
+
* 连接中断时只暂时关闭窗口;从不声称 SVN 更新已经停止。
|
|
17294
|
+
* @author ddj 2026年09月24号
|
|
17295
|
+
*/
|
|
17296
|
+
const dismiss = () => {
|
|
17297
|
+
if (!closeMode.explicit) return;
|
|
17298
|
+
if (closeMode.confirm && !window.confirm("更新任务连接中断。关闭窗口不会停止可能仍在运行的 SVN 更新,确定暂时关闭?")) return;
|
|
17299
|
+
props.onClose();
|
|
17300
|
+
};
|
|
17301
|
+
const phase = pendingRows && processFinished ? "正在加载更新明细…" : state?.phase === "completed" ? "更新完成" : state?.phase === "failed" ? "更新失败" : state?.phase === "cancelled" ? "更新已停止" : state?.phase === "cancelling" ? "正在停止…" : "正在更新…";
|
|
17302
|
+
return react.default.createElement(ModalShell, {
|
|
17303
|
+
dialogClass: "edrv-update-dialog",
|
|
17304
|
+
width: "min(1320px, calc(100vw - 48px))",
|
|
17305
|
+
cardStyle: {
|
|
17306
|
+
height: "min(680px, calc(100vh - 48px))",
|
|
17307
|
+
boxSizing: "border-box",
|
|
17308
|
+
maxHeight: "none"
|
|
17309
|
+
},
|
|
17310
|
+
closeOnEsc: closeMode.passive,
|
|
17311
|
+
closeOnMask: closeMode.passive,
|
|
17312
|
+
onClose: dismiss
|
|
17313
|
+
}, updateHead(props, state, phase, closable, dismiss), updateTable(props, rows, view, selection, finished), updateStatus(state, error, cleaned), updateFoot(props, state, closable, finished, cancel, dismiss, closeMode.confirm, cleaned, cleanup), state?.rawTail && (state.phase === "failed" || state.truncated) ? react.default.createElement("details", { className: "edrv-update-raw" }, react.default.createElement("summary", null, "查看原始输出"), react.default.createElement("pre", null, state.rawTail)) : null, selection.menu && state ? react.default.createElement(ContextMenu, {
|
|
17314
|
+
x: selection.menu.x,
|
|
17315
|
+
y: selection.menu.y,
|
|
17316
|
+
entries: menuEntries(props, state, selection.menu, rows, selection.selected),
|
|
17317
|
+
zIndex: 193,
|
|
17318
|
+
onClose: () => selection.setMenu(null)
|
|
17319
|
+
}) : null);
|
|
17320
|
+
}
|
|
17321
|
+
//#endregion
|
|
17322
|
+
//#region src/client/ui/icons.ts
|
|
17323
|
+
/**
|
|
17324
|
+
* dsh-vscode-mode client — UI 原语图标跨版本出口(消费方导出名保持 ≤0.1.6 旧名)。
|
|
17325
|
+
* 背景:DSH 0.1.7 图标命名重构——`Icon<Name>16`(0.1.6 及更旧)→
|
|
17326
|
+
* `Icon<Name>Regular/Medium`(0.1.7+,size 参数化 + 双笔画档),旧名在 0.1.7
|
|
17327
|
+
* 全树已不存在(整树 grep 实证)。解析策略:namespace import 属性探测,旧名优先
|
|
17328
|
+
* (现网 0.1.6)→ 新名次之(0.1.7+)→ 皆缺走通用占位(第三态不炸渲染);
|
|
17329
|
+
* 打包期 external 不校验成员存在性,两代运行时均稳(能力探测,不做版本判定)。
|
|
17330
|
+
* 调用点零语义变化:导出名与旧垫片一致,仅改 import 来源。
|
|
17331
|
+
* @author ddj 2026年09月22号
|
|
17332
|
+
*/
|
|
17333
|
+
/**
|
|
17334
|
+
* 通用占位图标(两代皆缺的第三态兜底:空态方框,不抛错不白屏)。
|
|
17335
|
+
* @author ddj 2026年09月22号
|
|
17336
|
+
* @param props 图标 props(size/className 透传)
|
|
17337
|
+
* @returns React 元素
|
|
17338
|
+
*/
|
|
17339
|
+
function fallbackIcon(props) {
|
|
17340
|
+
return react.default.createElement("svg", {
|
|
17341
|
+
width: props.size ?? 16,
|
|
17342
|
+
height: props.size ?? 16,
|
|
17343
|
+
viewBox: "0 0 16 16",
|
|
17344
|
+
className: props.className,
|
|
17345
|
+
"aria-hidden": true,
|
|
17346
|
+
focusable: false
|
|
17347
|
+
}, react.default.createElement("rect", {
|
|
17348
|
+
x: 3.5,
|
|
17349
|
+
y: 3.5,
|
|
17350
|
+
width: 9,
|
|
17351
|
+
height: 9,
|
|
17352
|
+
rx: 2,
|
|
17353
|
+
fill: "none",
|
|
17354
|
+
stroke: "currentColor",
|
|
17355
|
+
strokeWidth: 1.2,
|
|
17356
|
+
opacity: .45
|
|
17357
|
+
}));
|
|
17358
|
+
}
|
|
17359
|
+
/**
|
|
17360
|
+
* 按候选名序列解析图标组件(首个存在的函数命中;皆缺返回占位)。
|
|
17361
|
+
* @author ddj 2026年09月22号
|
|
17362
|
+
* @param names 候选导出名(旧名在前、新名在后)
|
|
17363
|
+
* @returns 图标组件
|
|
16264
17364
|
*/
|
|
16265
|
-
function
|
|
16266
|
-
|
|
16267
|
-
|
|
16268
|
-
|
|
16269
|
-
|
|
16270
|
-
|
|
16271
|
-
|
|
16272
|
-
|
|
16273
|
-
|
|
16274
|
-
|
|
16275
|
-
|
|
17365
|
+
function iconOf(...names) {
|
|
17366
|
+
const table = _deepseek_ai_dsh_client_ui_primitives;
|
|
17367
|
+
for (const name of names) {
|
|
17368
|
+
const hit = table[name];
|
|
17369
|
+
if (typeof hit === "function") return hit;
|
|
17370
|
+
}
|
|
17371
|
+
return fallbackIcon;
|
|
17372
|
+
}
|
|
17373
|
+
/** 目录闭合图标(官方文件树同款)。 */
|
|
17374
|
+
const IconFolderClose16 = iconOf("IconFolderClose16", "IconFolderCloseRegular");
|
|
17375
|
+
/** 目录展开图标(官方文件树同款)。 */
|
|
17376
|
+
const IconFolderOpen16 = iconOf("IconFolderOpen16", "IconFolderOpenRegular");
|
|
17377
|
+
/** 目录轮廓图标(活动栏「文件管理」)。 */
|
|
17378
|
+
const IconFolderOpenOutline16 = iconOf("IconFolderOpenOutline16", "IconFolderOpenOutlineRegular");
|
|
17379
|
+
/** 刷新图标(面板工具条)。 */
|
|
17380
|
+
const IconRefreshOutline16 = iconOf("IconRefreshOutline16", "IconRefreshOutlineRegular");
|
|
17381
|
+
/** 搜索图标(活动栏「搜索」)。 */
|
|
17382
|
+
const IconSearchOutline16 = iconOf("IconSearchOutline16", "IconSearchOutlineRegular");
|
|
17383
|
+
/** 列表+笔图标(活动栏「规则」)。 */
|
|
17384
|
+
const IconListPenOutline16 = iconOf("IconListPenOutline16", "IconListPenOutlineRegular");
|
|
17385
|
+
/** 代码图标(活动栏「大纲」)。 */
|
|
17386
|
+
const IconCodeOutline16 = iconOf("IconCodeOutline16", "IconCodeOutlineRegular");
|
|
17387
|
+
/** 分支图标(SVN 面板)。 */
|
|
17388
|
+
const IconBranchOutline16 = iconOf("IconBranchOutline16", "IconBranchOutlineRegular");
|
|
17389
|
+
/**
|
|
17390
|
+
* 文件图标元素(官方 FileTypeIcon + classifyFileType 分类,未知类型为 other)。
|
|
17391
|
+
* 文件树与 SVN 变更行共用(原为 FileExplorer 私有副本,上移共享防两处漂移)。
|
|
17392
|
+
* @author ddj 2026年09月23号
|
|
17393
|
+
* @param name 文件名(含扩展名;目录由调用方走目录图标)
|
|
17394
|
+
* @returns 图标元素;原语缺失或分类异常返回 null
|
|
17395
|
+
*/
|
|
17396
|
+
function fileIconEl(name) {
|
|
17397
|
+
if (typeof _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon !== "function" || typeof _deepseek_ai_dsh_client_ui_primitives.classifyFileType !== "function") return null;
|
|
17398
|
+
try {
|
|
17399
|
+
return (0, _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon)({
|
|
17400
|
+
kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(String(name ?? "")),
|
|
17401
|
+
size: 16,
|
|
17402
|
+
className: "edrv-tree-icon"
|
|
17403
|
+
});
|
|
17404
|
+
} catch (error) {
|
|
17405
|
+
return null;
|
|
17406
|
+
}
|
|
16276
17407
|
}
|
|
16277
17408
|
//#endregion
|
|
16278
17409
|
//#region src/client/ui/SvnPatchDialog.ts
|
|
@@ -17353,6 +18484,24 @@ window.__ModuleLoader__.load({
|
|
|
17353
18484
|
* 同一工作区切换对话恢复同一份状态;无 cwd 会话回退按会话隔离(scopeStore)。
|
|
17354
18485
|
* 作者 ddj 2026-08-20
|
|
17355
18486
|
*/
|
|
18487
|
+
/**
|
|
18488
|
+
* 只在 Lua 注解类型槽开启注释自动建议;跨文件/离开类型槽立即恢复默认。
|
|
18489
|
+
* @author ddj 2026年09月24号
|
|
18490
|
+
* @param ed 当前 Monaco 编辑器
|
|
18491
|
+
* @param monaco Monaco API(读取 quickSuggestions 枚举)
|
|
18492
|
+
*/
|
|
18493
|
+
function syncTypeSuggest(ed, monaco) {
|
|
18494
|
+
const model = ed.getModel();
|
|
18495
|
+
const position = ed.getPosition();
|
|
18496
|
+
const typeSlot = model?.getLanguageId() === "lua" && position && isLuaTypeSlot(model, position, model.getWordUntilPosition(position));
|
|
18497
|
+
const options = ed.getOption(monaco.editor.EditorOption.quickSuggestions);
|
|
18498
|
+
const comments = typeSlot ? "on" : "off";
|
|
18499
|
+
if (options.comments === comments) return;
|
|
18500
|
+
ed.updateOptions({ quickSuggestions: {
|
|
18501
|
+
...options,
|
|
18502
|
+
comments
|
|
18503
|
+
} });
|
|
18504
|
+
}
|
|
17356
18505
|
/** 日志弹窗每次加载条数(「加载更多」按此步长递增;上限由 host 的 SVN_LOG_SHOW_ALL_CAP 约束)。 */
|
|
17357
18506
|
const SVN_LOG_PAGE = 100;
|
|
17358
18507
|
/**
|
|
@@ -17501,7 +18650,39 @@ window.__ModuleLoader__.load({
|
|
|
17501
18650
|
const [svnLogError, setSvnLogError] = react.default.useState("");
|
|
17502
18651
|
const [svnLogWcRev, setSvnLogWcRev] = react.default.useState(null);
|
|
17503
18652
|
const [dlogOpen, setDlogOpen] = react.default.useState(false);
|
|
17504
|
-
const [
|
|
18653
|
+
const [svnUpdateDialog, setSvnUpdateDialog] = react.default.useState(null);
|
|
18654
|
+
const [svnUpdateReturn, setSvnUpdateReturn] = react.default.useState(null);
|
|
18655
|
+
const [recentUpdate, setRecentUpdate] = react.default.useState(null);
|
|
18656
|
+
const [updateOpenWith, setUpdateOpenWith] = react.default.useState(false);
|
|
18657
|
+
const svnUpdateDoneRef = react.default.useRef(/* @__PURE__ */ new Set());
|
|
18658
|
+
react.default.useEffect(() => {
|
|
18659
|
+
setSvnUpdateDialog(null);
|
|
18660
|
+
setSvnUpdateReturn(null);
|
|
18661
|
+
setRecentUpdate(null);
|
|
18662
|
+
setUpdateOpenWith(false);
|
|
18663
|
+
}, [sessionId, scope]);
|
|
18664
|
+
react.default.useEffect(() => {
|
|
18665
|
+
if (!sessionId || svnStatus?.managed !== true) return void 0;
|
|
18666
|
+
let alive = true;
|
|
18667
|
+
rpc("svn.updateActive", { sessionId }).then((outcome) => {
|
|
18668
|
+
if (!alive || !outcome.ok || !outcome.job) return;
|
|
18669
|
+
const recovered = {
|
|
18670
|
+
path: outcome.job.target,
|
|
18671
|
+
sessionId,
|
|
18672
|
+
scope,
|
|
18673
|
+
resumeJobId: outcome.job.jobId
|
|
18674
|
+
};
|
|
18675
|
+
if (updateDone(outcome.job.phase)) setRecentUpdate(recovered);
|
|
18676
|
+
else setSvnUpdateDialog((current) => current ?? recovered);
|
|
18677
|
+
}).catch(() => {});
|
|
18678
|
+
return () => {
|
|
18679
|
+
alive = false;
|
|
18680
|
+
};
|
|
18681
|
+
}, [
|
|
18682
|
+
sessionId,
|
|
18683
|
+
scope,
|
|
18684
|
+
svnStatus?.managed
|
|
18685
|
+
]);
|
|
17505
18686
|
const [sidebarOn, setSidebarOn] = react.default.useState(layout !== "side");
|
|
17506
18687
|
const [sidebarW, setSidebarW] = react.default.useState(() => getSidebarMinWidth());
|
|
17507
18688
|
const [activePanel, setActivePanel] = react.default.useState("explorer");
|
|
@@ -19027,6 +20208,7 @@ window.__ModuleLoader__.load({
|
|
|
19027
20208
|
sessionId,
|
|
19028
20209
|
scope,
|
|
19029
20210
|
path: def.id === "update" ? relPath ?? "" : relPath,
|
|
20211
|
+
openSvnUpdate: (p) => runSvnUpdate(p),
|
|
19030
20212
|
notify: (message) => setStatus(message),
|
|
19031
20213
|
openSvnDiff: (p) => runSvnDiffBase(p),
|
|
19032
20214
|
openSvnLocalPair: runSvnDiffLocalPair,
|
|
@@ -19213,6 +20395,7 @@ window.__ModuleLoader__.load({
|
|
|
19213
20395
|
const ed = editorRef.current;
|
|
19214
20396
|
const model = getModel(active, content);
|
|
19215
20397
|
if (ed.getModel() !== model) ed.setModel(model);
|
|
20398
|
+
syncTypeSuggest(ed, monaco);
|
|
19216
20399
|
restoreViewState(active);
|
|
19217
20400
|
setLoadStage((prev) => ({
|
|
19218
20401
|
progress: Math.max(96, prev.progress),
|
|
@@ -19324,9 +20507,11 @@ window.__ModuleLoader__.load({
|
|
|
19324
20507
|
});
|
|
19325
20508
|
ed.onDidChangeModelContent(() => {
|
|
19326
20509
|
if (!ed.getModel() || programmaticRef.current) return;
|
|
20510
|
+
syncTypeSuggest(ed, m);
|
|
19327
20511
|
onEditRef.current?.();
|
|
19328
20512
|
});
|
|
19329
20513
|
ed.onDidChangeCursorPosition((e) => {
|
|
20514
|
+
syncTypeSuggest(ed, m);
|
|
19330
20515
|
setCursor("Ln " + e.position.lineNumber + ", Col " + e.position.column);
|
|
19331
20516
|
if (rowNavMoveRef.current) rowNavMoveRef.current = false;
|
|
19332
20517
|
else rowNavColRef.current = null;
|
|
@@ -20131,18 +21316,18 @@ window.__ModuleLoader__.load({
|
|
|
20131
21316
|
});
|
|
20132
21317
|
};
|
|
20133
21318
|
/**
|
|
20134
|
-
*
|
|
20135
|
-
*
|
|
21319
|
+
* 四入口共用的更新窗口:仅显式点击触发,不在背景静默更新。
|
|
21320
|
+
* @author ddj 2026年09月24号
|
|
21321
|
+
* @param relPath 工作区相对目标;空串代表根
|
|
20136
21322
|
*/
|
|
20137
21323
|
const runSvnUpdate = (relPath) => {
|
|
20138
|
-
|
|
20139
|
-
|
|
20140
|
-
|
|
20141
|
-
|
|
20142
|
-
|
|
20143
|
-
|
|
20144
|
-
|
|
20145
|
-
} : null);
|
|
21324
|
+
closeCommandPalette();
|
|
21325
|
+
setSvnUpdateReturn(null);
|
|
21326
|
+
setRecentUpdate(null);
|
|
21327
|
+
setSvnUpdateDialog({
|
|
21328
|
+
path: relPath ?? "",
|
|
21329
|
+
sessionId,
|
|
21330
|
+
scope
|
|
20146
21331
|
});
|
|
20147
21332
|
};
|
|
20148
21333
|
/** 强制重查 SVN 变更清单(命令栏「SVN 刷新变更」)。 */
|
|
@@ -20264,8 +21449,9 @@ window.__ModuleLoader__.load({
|
|
|
20264
21449
|
* @param relPath 目标工作区相对路径
|
|
20265
21450
|
* @param revision 左侧版本
|
|
20266
21451
|
* @param logTarget 来自日志弹窗时的日志目标(不传 = 非日志入口)
|
|
21452
|
+
* @param onOpened 差异视图成功打开后触发(更新结果返回用)
|
|
20267
21453
|
*/
|
|
20268
|
-
const runSvnDiffWorking = (relPath, revision, logTarget) => {
|
|
21454
|
+
const runSvnDiffWorking = (relPath, revision, logTarget, onOpened) => {
|
|
20269
21455
|
if (!relPath) {
|
|
20270
21456
|
setStatus("仅文件目标支持与工作副本比较");
|
|
20271
21457
|
return;
|
|
@@ -20290,6 +21476,7 @@ window.__ModuleLoader__.load({
|
|
|
20290
21476
|
logTarget
|
|
20291
21477
|
});
|
|
20292
21478
|
setStatus("已打开 r" + revision + " ↔ 工作副本 差异");
|
|
21479
|
+
onOpened?.();
|
|
20293
21480
|
});
|
|
20294
21481
|
};
|
|
20295
21482
|
/**
|
|
@@ -20457,6 +21644,7 @@ window.__ModuleLoader__.load({
|
|
|
20457
21644
|
sessionId,
|
|
20458
21645
|
scope,
|
|
20459
21646
|
path,
|
|
21647
|
+
openSvnUpdate: (p) => runSvnUpdate(p),
|
|
20460
21648
|
notify: (message) => setStatus(message),
|
|
20461
21649
|
openSvnDiff: (p) => runSvnDiffBase(p),
|
|
20462
21650
|
openSvnLocalPair: runSvnDiffLocalPair,
|
|
@@ -20728,7 +21916,12 @@ window.__ModuleLoader__.load({
|
|
|
20728
21916
|
const pathBar = react.default.createElement("div", {
|
|
20729
21917
|
className: "edrv-pathbar",
|
|
20730
21918
|
title: active || ""
|
|
20731
|
-
}, react.default.createElement("span", { className: "edrv-pb-name" }, active ? String(active).split(/[\\/]/).pop() : "未打开文件"), react.default.createElement("span", { className: "edrv-pb-full" }, active || "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开文件"),
|
|
21919
|
+
}, react.default.createElement("span", { className: "edrv-pb-name" }, active ? String(active).split(/[\\/]/).pop() : "未打开文件"), react.default.createElement("span", { className: "edrv-pb-full" }, active || "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开文件"), recentUpdate && !svnUpdateDialog && sameUpdateOwner(recentUpdate, sessionId, scope) ? react.default.createElement("button", {
|
|
21920
|
+
className: "edrv-pb-update",
|
|
21921
|
+
type: "button",
|
|
21922
|
+
title: "查看最近 SVN 更新结果(不重新更新)",
|
|
21923
|
+
onClick: () => setSvnUpdateDialog(recentUpdate)
|
|
21924
|
+
}, react.default.createElement(IconRefreshOutline16, { size: 14 }), "最近更新") : null, isMdActive ? react.default.createElement("button", {
|
|
20732
21925
|
className: "edrv-pill edrv-pill-ghost edrv-pb-mdbtn",
|
|
20733
21926
|
title: (mdPreviewing ? "切回源码编辑" : "预览 Markdown") + "(" + (chordOf("edrv.toggleMarkdownPreview") ?? "未绑定") + ")",
|
|
20734
21927
|
onClick: () => toggleMdPreview(active)
|
|
@@ -20902,7 +22095,13 @@ window.__ModuleLoader__.load({
|
|
|
20902
22095
|
leftLabel: svnDiff.leftLabel,
|
|
20903
22096
|
rightLabel: svnDiff.rightLabel,
|
|
20904
22097
|
onBack: svnDiff.logTarget !== void 0 ? backToSvnLog : void 0,
|
|
20905
|
-
onClose: () =>
|
|
22098
|
+
onClose: () => {
|
|
22099
|
+
setSvnDiff(null);
|
|
22100
|
+
if (svnUpdateReturn?.from === "diff") {
|
|
22101
|
+
setSvnUpdateDialog(svnUpdateReturn.dialog);
|
|
22102
|
+
setSvnUpdateReturn(null);
|
|
22103
|
+
}
|
|
22104
|
+
}
|
|
20906
22105
|
});
|
|
20907
22106
|
else if (!monaco && !monacoErr) body = loadingBody(loadStage.message, loadStage.progress);
|
|
20908
22107
|
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", {
|
|
@@ -21085,6 +22284,7 @@ window.__ModuleLoader__.load({
|
|
|
21085
22284
|
svnChanges,
|
|
21086
22285
|
svnChangeMap: svnChangeMapMemo,
|
|
21087
22286
|
openSvnDiff: (p) => runSvnDiffBase(p),
|
|
22287
|
+
openSvnUpdate: (p) => runSvnUpdate(p),
|
|
21088
22288
|
openSvnLocalPair: runSvnDiffLocalPair,
|
|
21089
22289
|
refreshSvnChanges: () => refreshSvnChanges(sessionId, scope),
|
|
21090
22290
|
openSvnLog: (p) => openSvnLog(p),
|
|
@@ -21244,34 +22444,6 @@ window.__ModuleLoader__.load({
|
|
|
21244
22444
|
"aria-label": "关闭提示",
|
|
21245
22445
|
onClick: dismissHint
|
|
21246
22446
|
}, "×")) : null;
|
|
21247
|
-
/**
|
|
21248
|
-
* SVN 更新结果条(P3):逐条展示 update 的条目级状态,冲突红字高亮,可关闭。
|
|
21249
|
-
* 只在本次 update 有条目明细时渲染(无明细/失败时不占用编辑区高度)。
|
|
21250
|
-
* @author ddj 2026年09月16号
|
|
21251
|
-
* @returns 结果条元素或 null
|
|
21252
|
-
*/
|
|
21253
|
-
const svnResultBar = () => {
|
|
21254
|
-
const result = svnUpdateResult;
|
|
21255
|
-
if (!result || !result.entries.length) return null;
|
|
21256
|
-
const conflicts = new Set(result.conflicts ?? []);
|
|
21257
|
-
return react.default.createElement("div", { className: "edrv-svnres" }, react.default.createElement("span", { className: "edrv-svnres-head" }, "SVN 更新"), react.default.createElement("div", { className: "edrv-svnres-list" }, result.entries.map((entry, idx) => react.default.createElement("span", {
|
|
21258
|
-
key: entry.path + ":" + idx,
|
|
21259
|
-
className: "edrv-svnres-item" + (conflicts.has(entry.path) ? " edrv-svnres-conflict" : ""),
|
|
21260
|
-
title: entry.label + " " + entry.path
|
|
21261
|
-
}, entry.action + " " + entry.path))), react.default.createElement("span", { style: { flex: 1 } }), conflicts.size ? react.default.createElement("button", {
|
|
21262
|
-
className: "edrv-svn-act",
|
|
21263
|
-
title: "在工作区中显示第一个冲突文件",
|
|
21264
|
-
onClick: () => {
|
|
21265
|
-
const first = [...conflicts][0];
|
|
21266
|
-
const hit = result.entries.find((entry) => entry.path === first);
|
|
21267
|
-
if (hit?.path) openFile(hit.path, false);
|
|
21268
|
-
}
|
|
21269
|
-
}, "查看冲突文件") : null, react.default.createElement("button", {
|
|
21270
|
-
className: "edrv-svn-act",
|
|
21271
|
-
title: "关闭结果条",
|
|
21272
|
-
onClick: () => setSvnUpdateResult(null)
|
|
21273
|
-
}, "✕"));
|
|
21274
|
-
};
|
|
21275
22447
|
const mainCol = react.default.createElement("div", {
|
|
21276
22448
|
className: "edrv-main-col",
|
|
21277
22449
|
style: {
|
|
@@ -21282,7 +22454,7 @@ window.__ModuleLoader__.load({
|
|
|
21282
22454
|
flexDirection: "column",
|
|
21283
22455
|
overflow: "hidden"
|
|
21284
22456
|
}
|
|
21285
|
-
}, pathBar, tabRow, sideHintEl, diskBanner(),
|
|
22457
|
+
}, pathBar, tabRow, sideHintEl, diskBanner(), editorArea, statusBar);
|
|
21286
22458
|
const editorRow = react.default.createElement("div", { className: "edrv-editor-row" }, sidebarPanels ? react.default.createElement(SidebarView, {
|
|
21287
22459
|
registry: sidebarPanels,
|
|
21288
22460
|
ctx: sidebarCtx,
|
|
@@ -21397,6 +22569,81 @@ window.__ModuleLoader__.load({
|
|
|
21397
22569
|
onClose: () => {
|
|
21398
22570
|
setSvnLog(null);
|
|
21399
22571
|
setSvnLogError("");
|
|
22572
|
+
if (svnUpdateReturn?.from === "log") {
|
|
22573
|
+
setSvnUpdateDialog(svnUpdateReturn.dialog);
|
|
22574
|
+
setSvnUpdateReturn(null);
|
|
22575
|
+
}
|
|
22576
|
+
}
|
|
22577
|
+
}) : null;
|
|
22578
|
+
/**
|
|
22579
|
+
* 更新终态只刷新一次目录树与变更缓存,切到日志再返回不重复执行。
|
|
22580
|
+
* @author ddj 2026年09月24号
|
|
22581
|
+
* @param result 已结束的更新任务
|
|
22582
|
+
*/
|
|
22583
|
+
const onSvnUpdateDone = (result) => {
|
|
22584
|
+
if (svnUpdateDoneRef.current.has(result.jobId)) return;
|
|
22585
|
+
svnUpdateDoneRef.current.add(result.jobId);
|
|
22586
|
+
const message = result.phase === "completed" ? "SVN 更新完成" : result.phase === "cancelled" ? "SVN 更新已取消(可能部分完成)" : "SVN 更新失败:" + result.error;
|
|
22587
|
+
setStatus(message);
|
|
22588
|
+
setRecentUpdate({
|
|
22589
|
+
path: result.target,
|
|
22590
|
+
sessionId,
|
|
22591
|
+
scope,
|
|
22592
|
+
resumeJobId: result.jobId
|
|
22593
|
+
});
|
|
22594
|
+
refreshSvnChanges(sessionId, scope);
|
|
22595
|
+
emitRefresh();
|
|
22596
|
+
};
|
|
22597
|
+
const svnUpdateEl = sameUpdateOwner(svnUpdateDialog, sessionId, scope) ? react.default.createElement(SvnUpdateDialog, {
|
|
22598
|
+
key: "edrv-svn-update:" + svnUpdateDialog.path + ":" + (svnUpdateDialog.resumeJobId || ""),
|
|
22599
|
+
sessionId,
|
|
22600
|
+
cwd,
|
|
22601
|
+
path: svnUpdateDialog.path,
|
|
22602
|
+
resumeJobId: svnUpdateDialog.resumeJobId,
|
|
22603
|
+
childOverlay: updateOpenWith,
|
|
22604
|
+
onDone: onSvnUpdateDone,
|
|
22605
|
+
onNote: (message) => setStatus(message),
|
|
22606
|
+
onClose: () => setSvnUpdateDialog(null),
|
|
22607
|
+
onShowLog: (target, jobId) => {
|
|
22608
|
+
setSvnUpdateReturn({
|
|
22609
|
+
from: "log",
|
|
22610
|
+
dialog: {
|
|
22611
|
+
...svnUpdateDialog,
|
|
22612
|
+
resumeJobId: jobId
|
|
22613
|
+
}
|
|
22614
|
+
});
|
|
22615
|
+
setSvnUpdateDialog(null);
|
|
22616
|
+
openSvnLog(target);
|
|
22617
|
+
},
|
|
22618
|
+
onCompare: (path, revision, jobId) => runSvnDiffWorking(path, revision, void 0, () => {
|
|
22619
|
+
setSvnUpdateReturn({
|
|
22620
|
+
from: "diff",
|
|
22621
|
+
dialog: {
|
|
22622
|
+
...svnUpdateDialog,
|
|
22623
|
+
resumeJobId: jobId
|
|
22624
|
+
}
|
|
22625
|
+
});
|
|
22626
|
+
setSvnUpdateDialog(null);
|
|
22627
|
+
}),
|
|
22628
|
+
onOpenFile: (path) => openFile(path, false),
|
|
22629
|
+
onOpenWith: (path) => {
|
|
22630
|
+
if (!props.fileOpeners) {
|
|
22631
|
+
setStatus("打开方式不可用");
|
|
22632
|
+
return;
|
|
22633
|
+
}
|
|
22634
|
+
setUpdateOpenWith(true);
|
|
22635
|
+
openWithDialog(props.fileOpeners, {
|
|
22636
|
+
sessionId,
|
|
22637
|
+
cwd: cwd ?? void 0
|
|
22638
|
+
}, path, (opener) => {
|
|
22639
|
+
setUpdateOpenWith(false);
|
|
22640
|
+
if (opener) setStatus("已用「" + opener.label + "」打开:" + baseNameOf(path));
|
|
22641
|
+
});
|
|
22642
|
+
},
|
|
22643
|
+
onOpenParent: (path) => {
|
|
22644
|
+
revealInExplorer(sessionId, path).then((outcome) => {
|
|
22645
|
+
setStatus(outcome.ok ? "已打开父目录" : "打开父目录失败:" + (outcome.error ?? "未知错误"));
|
|
22646
|
+
});
|
|
21400
22647
|
}
|
|
21401
22648
|
}) : null;
|
|
21402
22649
|
const patchDialogEl = patchDialog ? react.default.createElement(SvnPatchDialog, {
|
|
@@ -21509,14 +22756,14 @@ window.__ModuleLoader__.load({
|
|
|
21509
22756
|
"data-edrv-layout": "side",
|
|
21510
22757
|
className: "edrv-view-side",
|
|
21511
22758
|
style: Object.assign({}, baseStyle, { height: "100%" })
|
|
21512
|
-
}, editorRow, tabMenuEl, paletteEl, svnLogEl, patchDialogEl, sumDialogEl, dlogEl, snippetPickerEl, dapBpMenuEl, dapBpEditEl) : react.default.createElement("div", {
|
|
22759
|
+
}, editorRow, tabMenuEl, paletteEl, svnLogEl, svnUpdateEl, patchDialogEl, sumDialogEl, dlogEl, snippetPickerEl, dapBpMenuEl, dapBpEditEl) : react.default.createElement("div", {
|
|
21513
22760
|
ref: viewRootRef,
|
|
21514
22761
|
"data-edrv-view": "1",
|
|
21515
22762
|
style: Object.assign({}, baseStyle, {
|
|
21516
22763
|
height: "var(--edrv-editor-height, 100%)",
|
|
21517
22764
|
maxHeight: "var(--edrv-editor-height, 100%)"
|
|
21518
22765
|
})
|
|
21519
|
-
}, editorRow, tabMenuEl, paletteEl, svnLogEl, patchDialogEl, sumDialogEl, dlogEl, snippetPickerEl, dapBpMenuEl, dapBpEditEl);
|
|
22766
|
+
}, editorRow, tabMenuEl, paletteEl, svnLogEl, svnUpdateEl, patchDialogEl, sumDialogEl, dlogEl, snippetPickerEl, dapBpMenuEl, dapBpEditEl);
|
|
21520
22767
|
}
|
|
21521
22768
|
//#endregion
|
|
21522
22769
|
//#region src/client/ui/DiffBadge.ts
|
|
@@ -24138,6 +25385,48 @@ window.__ModuleLoader__.load({
|
|
|
24138
25385
|
});
|
|
24139
25386
|
}
|
|
24140
25387
|
//#endregion
|
|
25388
|
+
//#region src/client/settingsDocRouter.ts
|
|
25389
|
+
/** Redirect the DSH settings document action into the plugin editor. */
|
|
25390
|
+
/**
|
|
25391
|
+
* Patch the optional DSH settings document opener; failed handoff keeps native behavior.
|
|
25392
|
+
* @author ddj 2026年10月02号
|
|
25393
|
+
* @param service DSH remote settings namespace
|
|
25394
|
+
* @param getPath plugin RPC that prepares the profile document
|
|
25395
|
+
* @param openEditor current plugin editor action
|
|
25396
|
+
* @param logger optional diagnostic sink
|
|
25397
|
+
* @returns disposer, or null if the DSH API is unavailable
|
|
25398
|
+
*/
|
|
25399
|
+
function patchSettingsDoc(service, getPath, openEditor, logger) {
|
|
25400
|
+
return patchAccessor(service, "openSettingsDocument", async (original, ...args) => {
|
|
25401
|
+
try {
|
|
25402
|
+
const result = await getPath();
|
|
25403
|
+
if (!result.ok || !result.path) throw new Error(result.error || "设置配置文件路径不可用");
|
|
25404
|
+
openEditor(result.path);
|
|
25405
|
+
return {
|
|
25406
|
+
ok: true,
|
|
25407
|
+
value: { opened: true }
|
|
25408
|
+
};
|
|
25409
|
+
} catch (error) {
|
|
25410
|
+
logger?.("插件编辑器打开设置配置文件失败,回退 DSH 原生打开: " + String(error));
|
|
25411
|
+
return original(...args);
|
|
25412
|
+
}
|
|
25413
|
+
});
|
|
25414
|
+
}
|
|
25415
|
+
/**
|
|
25416
|
+
* Safely locate the optional DSH settings remote service.
|
|
25417
|
+
* @author ddj 2026年10月02号
|
|
25418
|
+
* @param ctx Client service context
|
|
25419
|
+
* @returns The settings service when its document opener exists
|
|
25420
|
+
*/
|
|
25421
|
+
function probeSettingsDoc(ctx) {
|
|
25422
|
+
try {
|
|
25423
|
+
const service = ctx.get("remote.settings");
|
|
25424
|
+
return typeof service?.openSettingsDocument === "function" ? service : void 0;
|
|
25425
|
+
} catch {
|
|
25426
|
+
return;
|
|
25427
|
+
}
|
|
25428
|
+
}
|
|
25429
|
+
//#endregion
|
|
24141
25430
|
//#region src/shared/externalOpen.ts
|
|
24142
25431
|
/**
|
|
24143
25432
|
* dsh-vscode-mode shared — 外部深链 URL 契约(Windows launcher / Unity 包 / client 共用)。
|
|
@@ -24876,93 +26165,6 @@ window.__ModuleLoader__.load({
|
|
|
24876
26165
|
};
|
|
24877
26166
|
}
|
|
24878
26167
|
//#endregion
|
|
24879
|
-
//#region src/client/ui/icons.ts
|
|
24880
|
-
/**
|
|
24881
|
-
* dsh-vscode-mode client — UI 原语图标跨版本出口(消费方导出名保持 ≤0.1.6 旧名)。
|
|
24882
|
-
* 背景:DSH 0.1.7 图标命名重构——`Icon<Name>16`(0.1.6 及更旧)→
|
|
24883
|
-
* `Icon<Name>Regular/Medium`(0.1.7+,size 参数化 + 双笔画档),旧名在 0.1.7
|
|
24884
|
-
* 全树已不存在(整树 grep 实证)。解析策略:namespace import 属性探测,旧名优先
|
|
24885
|
-
* (现网 0.1.6)→ 新名次之(0.1.7+)→ 皆缺走通用占位(第三态不炸渲染);
|
|
24886
|
-
* 打包期 external 不校验成员存在性,两代运行时均稳(能力探测,不做版本判定)。
|
|
24887
|
-
* 调用点零语义变化:导出名与旧垫片一致,仅改 import 来源。
|
|
24888
|
-
* @author ddj 2026年09月22号
|
|
24889
|
-
*/
|
|
24890
|
-
/**
|
|
24891
|
-
* 通用占位图标(两代皆缺的第三态兜底:空态方框,不抛错不白屏)。
|
|
24892
|
-
* @author ddj 2026年09月22号
|
|
24893
|
-
* @param props 图标 props(size/className 透传)
|
|
24894
|
-
* @returns React 元素
|
|
24895
|
-
*/
|
|
24896
|
-
function fallbackIcon(props) {
|
|
24897
|
-
return react.default.createElement("svg", {
|
|
24898
|
-
width: props.size ?? 16,
|
|
24899
|
-
height: props.size ?? 16,
|
|
24900
|
-
viewBox: "0 0 16 16",
|
|
24901
|
-
className: props.className,
|
|
24902
|
-
"aria-hidden": true,
|
|
24903
|
-
focusable: false
|
|
24904
|
-
}, react.default.createElement("rect", {
|
|
24905
|
-
x: 3.5,
|
|
24906
|
-
y: 3.5,
|
|
24907
|
-
width: 9,
|
|
24908
|
-
height: 9,
|
|
24909
|
-
rx: 2,
|
|
24910
|
-
fill: "none",
|
|
24911
|
-
stroke: "currentColor",
|
|
24912
|
-
strokeWidth: 1.2,
|
|
24913
|
-
opacity: .45
|
|
24914
|
-
}));
|
|
24915
|
-
}
|
|
24916
|
-
/**
|
|
24917
|
-
* 按候选名序列解析图标组件(首个存在的函数命中;皆缺返回占位)。
|
|
24918
|
-
* @author ddj 2026年09月22号
|
|
24919
|
-
* @param names 候选导出名(旧名在前、新名在后)
|
|
24920
|
-
* @returns 图标组件
|
|
24921
|
-
*/
|
|
24922
|
-
function iconOf(...names) {
|
|
24923
|
-
const table = _deepseek_ai_dsh_client_ui_primitives;
|
|
24924
|
-
for (const name of names) {
|
|
24925
|
-
const hit = table[name];
|
|
24926
|
-
if (typeof hit === "function") return hit;
|
|
24927
|
-
}
|
|
24928
|
-
return fallbackIcon;
|
|
24929
|
-
}
|
|
24930
|
-
/** 目录闭合图标(官方文件树同款)。 */
|
|
24931
|
-
const IconFolderClose16 = iconOf("IconFolderClose16", "IconFolderCloseRegular");
|
|
24932
|
-
/** 目录展开图标(官方文件树同款)。 */
|
|
24933
|
-
const IconFolderOpen16 = iconOf("IconFolderOpen16", "IconFolderOpenRegular");
|
|
24934
|
-
/** 目录轮廓图标(活动栏「文件管理」)。 */
|
|
24935
|
-
const IconFolderOpenOutline16 = iconOf("IconFolderOpenOutline16", "IconFolderOpenOutlineRegular");
|
|
24936
|
-
/** 刷新图标(面板工具条)。 */
|
|
24937
|
-
const IconRefreshOutline16 = iconOf("IconRefreshOutline16", "IconRefreshOutlineRegular");
|
|
24938
|
-
/** 搜索图标(活动栏「搜索」)。 */
|
|
24939
|
-
const IconSearchOutline16 = iconOf("IconSearchOutline16", "IconSearchOutlineRegular");
|
|
24940
|
-
/** 列表+笔图标(活动栏「规则」)。 */
|
|
24941
|
-
const IconListPenOutline16 = iconOf("IconListPenOutline16", "IconListPenOutlineRegular");
|
|
24942
|
-
/** 代码图标(活动栏「大纲」)。 */
|
|
24943
|
-
const IconCodeOutline16 = iconOf("IconCodeOutline16", "IconCodeOutlineRegular");
|
|
24944
|
-
/** 分支图标(SVN 面板)。 */
|
|
24945
|
-
const IconBranchOutline16 = iconOf("IconBranchOutline16", "IconBranchOutlineRegular");
|
|
24946
|
-
/**
|
|
24947
|
-
* 文件图标元素(官方 FileTypeIcon + classifyFileType 分类,未知类型为 other)。
|
|
24948
|
-
* 文件树与 SVN 变更行共用(原为 FileExplorer 私有副本,上移共享防两处漂移)。
|
|
24949
|
-
* @author ddj 2026年09月23号
|
|
24950
|
-
* @param name 文件名(含扩展名;目录由调用方走目录图标)
|
|
24951
|
-
* @returns 图标元素;原语缺失或分类异常返回 null
|
|
24952
|
-
*/
|
|
24953
|
-
function fileIconEl(name) {
|
|
24954
|
-
if (typeof _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon !== "function" || typeof _deepseek_ai_dsh_client_ui_primitives.classifyFileType !== "function") return null;
|
|
24955
|
-
try {
|
|
24956
|
-
return (0, _deepseek_ai_dsh_client_ui_primitives.FileTypeIcon)({
|
|
24957
|
-
kind: (0, _deepseek_ai_dsh_client_ui_primitives.classifyFileType)(String(name ?? "")),
|
|
24958
|
-
size: 16,
|
|
24959
|
-
className: "edrv-tree-icon"
|
|
24960
|
-
});
|
|
24961
|
-
} catch (error) {
|
|
24962
|
-
return null;
|
|
24963
|
-
}
|
|
24964
|
-
}
|
|
24965
|
-
//#endregion
|
|
24966
26168
|
//#region src/client/sidebar/contextMenu.ts
|
|
24967
26169
|
/** 校验菜单项并写入注册表(缺 id/run/label 抛 TypeError)。 */
|
|
24968
26170
|
function itemRegister(entries, notify, item) {
|
|
@@ -29604,6 +30806,7 @@ window.__ModuleLoader__.load({
|
|
|
29604
30806
|
path: target.path,
|
|
29605
30807
|
notify: (message) => ctx.notify?.(message),
|
|
29606
30808
|
openSvnDiff: (p) => ctx.openSvnDiff?.(p),
|
|
30809
|
+
openSvnUpdate: (p) => ctx.openSvnUpdate?.(p),
|
|
29607
30810
|
openSvnLog: ctx.openSvnLog,
|
|
29608
30811
|
refreshChanges: ctx.refreshSvnChanges,
|
|
29609
30812
|
confirm: ctx.confirm
|
|
@@ -30697,6 +31900,35 @@ window.__ModuleLoader__.load({
|
|
|
30697
31900
|
*/
|
|
30698
31901
|
function apply(ctx) {
|
|
30699
31902
|
const schedule = (fn, ms) => ctx.timeout(fn, ms);
|
|
31903
|
+
ctx.effect(() => {
|
|
31904
|
+
let disposed = false;
|
|
31905
|
+
let attempts = 0;
|
|
31906
|
+
let restore = null;
|
|
31907
|
+
const install = () => {
|
|
31908
|
+
if (disposed || restore || attempts >= 15) return;
|
|
31909
|
+
attempts += 1;
|
|
31910
|
+
const service = probeSettingsDoc(ctx);
|
|
31911
|
+
if (service) {
|
|
31912
|
+
restore = patchSettingsDoc(service, async () => {
|
|
31913
|
+
const result = await rpc("vscode.settingsDocumentPath", {});
|
|
31914
|
+
return result.ok ? {
|
|
31915
|
+
ok: true,
|
|
31916
|
+
path: result.path
|
|
31917
|
+
} : {
|
|
31918
|
+
ok: false,
|
|
31919
|
+
error: result.error
|
|
31920
|
+
};
|
|
31921
|
+
}, openEditorView, (message) => log.warn(message));
|
|
31922
|
+
if (restore) return;
|
|
31923
|
+
}
|
|
31924
|
+
if (attempts < 15) schedule(install, 2e3);
|
|
31925
|
+
};
|
|
31926
|
+
install();
|
|
31927
|
+
return () => {
|
|
31928
|
+
disposed = true;
|
|
31929
|
+
restore?.();
|
|
31930
|
+
};
|
|
31931
|
+
}, "vscode-mode: settings document editor route");
|
|
30700
31932
|
setupCommands(ctx);
|
|
30701
31933
|
const registry = createFileOpenerRegistry();
|
|
30702
31934
|
const workspaces = ctx.get("workspaces");
|