dsh-vscode-mode 0.7.0 → 0.8.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 +23 -6
- package/assets/icon.svg +7 -0
- package/cordis.patch.yml +12 -0
- package/lib/client.js +1167 -188
- package/lib/client.js.map +1 -1
- package/lib/index.js +845 -96
- package/lib/index.js.map +1 -1
- package/locale/en.json +4 -0
- package/locale/zh.json +4 -0
- package/package.json +3 -1
- package/src/client/compat.ts +134 -4
- package/src/client/imagePreview.ts +76 -2
- package/src/client/index.ts +65 -36
- package/src/client/monaco/lsp/lspClient.ts +46 -0
- package/src/client/monaco/lsp/providers.ts +245 -1
- package/src/client/nativeOpenStore.ts +91 -0
- package/src/client/officialSidebar.ts +11 -45
- package/src/client/outline/index.ts +1 -1
- package/src/client/pdf/pdfPanel.ts +18 -0
- package/src/client/settingsContext.ts +6 -4
- package/src/client/sidebar/panels/FileExplorer.ts +1 -1
- package/src/client/sidebar/panels/SvnPanel.ts +1 -1
- package/src/client/sidebar/panels/index.ts +1 -1
- package/src/client/styles/editor.css +5 -3
- package/src/client/svnStore.ts +6 -1
- package/src/client/ui/EditorView.ts +117 -18
- package/src/client/ui/McpSettings.ts +30 -0
- package/src/client/ui/PerfSettings.ts +4 -1
- package/src/client/ui/icons.ts +72 -0
- package/src/compat.ts +2 -2
- package/src/dshVersion.ts +2 -1
- package/src/fileOpenSettings.ts +163 -40
- package/src/index.ts +15 -1
- package/src/lsp/client.ts +24 -0
- package/src/lsp/rpc.ts +57 -0
- package/src/lsp/server.ts +272 -2
- package/src/perf.ts +90 -4
- package/src/routes.ts +13 -1
- package/src/rpc.ts +96 -34
- package/src/shared/lsp.ts +79 -0
- package/src/shared/nativeOpen.ts +91 -0
- package/src/shared/rpc.ts +146 -1
package/lib/client.js
CHANGED
|
@@ -29,10 +29,11 @@ window.__ModuleLoader__.load({
|
|
|
29
29
|
let react = require("react");
|
|
30
30
|
react = __toESM(react, 1);
|
|
31
31
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
32
|
+
_deepseek_ai_dsh_client_ui_primitives = __toESM(_deepseek_ai_dsh_client_ui_primitives, 1);
|
|
32
33
|
let react_dom = require("react-dom");
|
|
33
34
|
let react_dom_client = require("react-dom/client");
|
|
34
35
|
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
|
|
35
|
-
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[data-edrv-view] .edrv-imgview-stage { flex: 1 1 auto; min-height: 0; display: flex; align-items: center; justify-content: center; 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%; 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); }\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[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; }\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: default; 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[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-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[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; }\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: default; 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[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
37
|
const tagId$1 = "dsh-vscode-mode/editor.css";
|
|
37
38
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
38
39
|
const tag = document.createElement("style");
|
|
@@ -61,6 +62,155 @@ window.__ModuleLoader__.load({
|
|
|
61
62
|
avif: "image/avif",
|
|
62
63
|
svg: "image/svg+xml"
|
|
63
64
|
};
|
|
65
|
+
/**
|
|
66
|
+
* 路径 → 图片 MIME:按 basename 扩展名小写查 {@link IMAGE_MIME},未命中回退 application/octet-stream。
|
|
67
|
+
* @author ddj 2026年09月08号
|
|
68
|
+
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
69
|
+
* @returns MIME 字符串
|
|
70
|
+
*/
|
|
71
|
+
function imageMimeOf(path) {
|
|
72
|
+
const base = String(path || "").split(/[\\/]/).pop() || "";
|
|
73
|
+
const dot = base.lastIndexOf(".");
|
|
74
|
+
const ext = dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
|
|
75
|
+
return IMAGE_MIME[ext] ?? "application/octet-stream";
|
|
76
|
+
}
|
|
77
|
+
/** PDF 统一 MIME(host base64 响应与 client PDF 面板同源,避免两处漂移)。 */
|
|
78
|
+
const PDF_MIME = "application/pdf";
|
|
79
|
+
/**
|
|
80
|
+
* 路径 → 二进制预览 MIME:PDF 特判 {@link PDF_MIME},其余走图片表回退 octet-stream。
|
|
81
|
+
* @author ddj 2026年09月22号
|
|
82
|
+
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
83
|
+
* @returns MIME 字符串
|
|
84
|
+
*/
|
|
85
|
+
function binaryMimeOf(path) {
|
|
86
|
+
const base = String(path || "").split(/[\\/]/).pop() || "";
|
|
87
|
+
const dot = base.lastIndexOf(".");
|
|
88
|
+
if (dot > 0 && base.slice(dot + 1).toLowerCase() === "pdf") return PDF_MIME;
|
|
89
|
+
return imageMimeOf(path);
|
|
90
|
+
}
|
|
91
|
+
/** 二进制读成功响应头(octet-stream 携带元数据;同源请求可直接读取自定义头)。 */
|
|
92
|
+
const BINARY_READ_HEADERS = {
|
|
93
|
+
mime: "x-edrv-mime",
|
|
94
|
+
size: "x-edrv-size",
|
|
95
|
+
version: "x-edrv-version"
|
|
96
|
+
};
|
|
97
|
+
/** 通道探测状态:unknown=按次尝试;unwired=host 有 handler 但 routes 仍强制 JSON(本页不再尝试)。 */
|
|
98
|
+
let binaryTransport = "unknown";
|
|
99
|
+
/**
|
|
100
|
+
* 二进制预览读取(edrv.readBinary,失败自动回退 edrv.read base64 现有路径)。
|
|
101
|
+
* 降级链:非 200 / 非 octet-stream / 元数据头缺失或长度不符 / 网络错 / host 未接线
|
|
102
|
+
* 把信封 JSON 化 → 一律立即回退 base64 路径,功能不降级;
|
|
103
|
+
* 其中「信封被 JSON 化」判定为未接线,探测一次后本页生命周期内不再尝试新通道
|
|
104
|
+
* (避免每次读图都付一次无效往返与大响应序列化);其余失败不关停通道(瞬时故障可自愈)。
|
|
105
|
+
* @author ddj 2026年09月22号
|
|
106
|
+
* @param rpcJson 类型化 JSON RPC 调用(调用方传入 client rpc 包装)
|
|
107
|
+
* @param args edrv.readBinary 请求参数
|
|
108
|
+
* @returns 统一读取结果(via 标记实际通道;probed 供调用方做一次性回退日志)
|
|
109
|
+
*/
|
|
110
|
+
async function readBinaryPreview(rpcJson, args) {
|
|
111
|
+
const attempted = binaryTransport !== "unwired";
|
|
112
|
+
if (attempted) {
|
|
113
|
+
const direct = await tryBinaryRead(args);
|
|
114
|
+
if (direct) return direct;
|
|
115
|
+
}
|
|
116
|
+
return fallbackRead(rpcJson, args, attempted);
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* 新通道单次尝试:响应完全符合约定才返回二进制结果,否则返回 null 触发回退。
|
|
120
|
+
* @author ddj 2026年09月22号
|
|
121
|
+
* @param args edrv.readBinary 请求参数
|
|
122
|
+
* @returns 二进制读取结果或 null(null=回退 base64)
|
|
123
|
+
*/
|
|
124
|
+
async function tryBinaryRead(args) {
|
|
125
|
+
try {
|
|
126
|
+
const res = await fetch(RPC_PATH, {
|
|
127
|
+
method: "POST",
|
|
128
|
+
headers: { "content-type": "application/json" },
|
|
129
|
+
body: JSON.stringify({
|
|
130
|
+
method: "edrv.readBinary",
|
|
131
|
+
args
|
|
132
|
+
})
|
|
133
|
+
});
|
|
134
|
+
if (!res.ok) return null;
|
|
135
|
+
if (!(res.headers.get("content-type") ?? "").includes("application/octet-stream")) return noteJsonBody(res);
|
|
136
|
+
const size = Number(res.headers.get(BINARY_READ_HEADERS.size));
|
|
137
|
+
const bytes = new Uint8Array(await res.arrayBuffer());
|
|
138
|
+
if (!Number.isFinite(size) || size !== bytes.byteLength) return null;
|
|
139
|
+
return {
|
|
140
|
+
ok: true,
|
|
141
|
+
via: "binary",
|
|
142
|
+
bytes,
|
|
143
|
+
mime: res.headers.get(BINARY_READ_HEADERS.mime) || binaryMimeOf(args.path),
|
|
144
|
+
size: bytes.byteLength,
|
|
145
|
+
version: res.headers.get(BINARY_READ_HEADERS.version) || ""
|
|
146
|
+
};
|
|
147
|
+
} catch (error) {
|
|
148
|
+
return null;
|
|
149
|
+
}
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* 非 octet-stream 响应体判定:host 已有 edrv.readBinary 但 routes 尚未接线时,
|
|
153
|
+
* 二进制信封会被 JSON 序列化成 {bytes:{0:..}} 普通对象——识别到该形态即标记
|
|
154
|
+
* 「未接线」(本页不再尝试);其余 JSON(错误响应/未知方法)仅本次回退不关停。
|
|
155
|
+
* @author ddj 2026年09月22号
|
|
156
|
+
* @param res JSON 形态的响应
|
|
157
|
+
* @returns 恒为 null(统一由调用方回退)
|
|
158
|
+
*/
|
|
159
|
+
async function noteJsonBody(res) {
|
|
160
|
+
try {
|
|
161
|
+
const body = await res.json();
|
|
162
|
+
if (body && body.ok === true && body.binary && typeof body.binary === "object" && body.binary.bytes != null) binaryTransport = "unwired";
|
|
163
|
+
} catch (error) {}
|
|
164
|
+
return null;
|
|
165
|
+
}
|
|
166
|
+
/**
|
|
167
|
+
* base64 回退读取(现有 edrv.read JSON 通道,载荷形状与历史实现一致)。
|
|
168
|
+
* @author ddj 2026年09月22号
|
|
169
|
+
* @param rpcJson 类型化 JSON RPC 调用
|
|
170
|
+
* @param args 请求参数
|
|
171
|
+
* @param attempted 本次是否尝试过新通道(回带给调用方做一次性日志)
|
|
172
|
+
* @returns 统一读取结果(调用失败转错误结果,不向上抛)
|
|
173
|
+
*/
|
|
174
|
+
async function fallbackRead(rpcJson, args, attempted) {
|
|
175
|
+
const probed = attempted ? { probed: true } : {};
|
|
176
|
+
try {
|
|
177
|
+
const res = await rpcJson("edrv.read", {
|
|
178
|
+
sessionId: args.sessionId,
|
|
179
|
+
path: args.path,
|
|
180
|
+
encoding: "base64"
|
|
181
|
+
});
|
|
182
|
+
if (!res.ok) {
|
|
183
|
+
const legacy = res;
|
|
184
|
+
return {
|
|
185
|
+
ok: false,
|
|
186
|
+
error: legacy.error,
|
|
187
|
+
...probed,
|
|
188
|
+
...legacy.resolvedPath !== void 0 ? { resolvedPath: legacy.resolvedPath } : {}
|
|
189
|
+
};
|
|
190
|
+
}
|
|
191
|
+
if (res.encoding !== "base64") return {
|
|
192
|
+
ok: false,
|
|
193
|
+
error: "读取失败",
|
|
194
|
+
...probed
|
|
195
|
+
};
|
|
196
|
+
return {
|
|
197
|
+
ok: true,
|
|
198
|
+
via: "base64",
|
|
199
|
+
content: res.content,
|
|
200
|
+
size: res.size,
|
|
201
|
+
encoding: res.encoding,
|
|
202
|
+
mime: res.mime,
|
|
203
|
+
version: res.version,
|
|
204
|
+
...probed
|
|
205
|
+
};
|
|
206
|
+
} catch (error) {
|
|
207
|
+
return {
|
|
208
|
+
ok: false,
|
|
209
|
+
error: "read异常:" + String(error),
|
|
210
|
+
...probed
|
|
211
|
+
};
|
|
212
|
+
}
|
|
213
|
+
}
|
|
64
214
|
//#endregion
|
|
65
215
|
//#region src/client/rpc.ts
|
|
66
216
|
/**
|
|
@@ -1646,8 +1796,9 @@ window.__ModuleLoader__.load({
|
|
|
1646
1796
|
//#endregion
|
|
1647
1797
|
//#region src/client/imagePreview.ts
|
|
1648
1798
|
/**
|
|
1649
|
-
* dsh-vscode-mode client —
|
|
1650
|
-
* 纯函数、无 DOM 依赖,便于单测;MIME 表收敛在 shared/rpc.ts(host base64
|
|
1799
|
+
* dsh-vscode-mode client — 图片文件判定、data URL 组装与缩放纯逻辑(编辑区图片预览面板用)。
|
|
1800
|
+
* 纯函数、无 DOM 依赖,便于单测;MIME 表收敛在 shared/rpc.ts(host base64 响应同源);
|
|
1801
|
+
* 缩放:步进/clamp 为纯函数,页签记忆为模块级 Map(会话+路径键,EditorView 卸载清空、不持久化)。
|
|
1651
1802
|
* @author ddj 2026年09月08号
|
|
1652
1803
|
*/
|
|
1653
1804
|
/** 可预览的图片扩展名集合(小写、无点)。 */
|
|
@@ -1685,6 +1836,66 @@ window.__ModuleLoader__.load({
|
|
|
1685
1836
|
function dataUrlOf(base64, mime) {
|
|
1686
1837
|
return "data:" + (mime || "application/octet-stream") + ";base64," + base64;
|
|
1687
1838
|
}
|
|
1839
|
+
/** 图片缩放下限(25%,低于此档不再缩小)。 */
|
|
1840
|
+
const ZOOM_MIN = .25;
|
|
1841
|
+
/** 图片缩放步进(10%/档,−/+ 按钮每点一次的变化量)。 */
|
|
1842
|
+
const ZOOM_STEP = .1;
|
|
1843
|
+
/** 页签缩放记忆表:键 = zoomKeyOf(会话, 路径),值 = 显式缩放或 null(适应宽度)。 */
|
|
1844
|
+
const zoomMem = /* @__PURE__ */ new Map();
|
|
1845
|
+
/**
|
|
1846
|
+
* 图片缩放收敛:clamp 到 25%–400% 并按整百分比取整(消除浮点步进噪声)。
|
|
1847
|
+
* @author ddj 2026年09月22号
|
|
1848
|
+
* @param zoom 目标缩放(非有限数值按 100% 处理)
|
|
1849
|
+
* @returns 收敛后的缩放比例
|
|
1850
|
+
*/
|
|
1851
|
+
function clampZoom(zoom) {
|
|
1852
|
+
return Math.round(Math.min(4, Math.max(ZOOM_MIN, Number.isFinite(zoom) ? zoom : 1)) * 100) / 100;
|
|
1853
|
+
}
|
|
1854
|
+
/**
|
|
1855
|
+
* 图片缩放步进:按 10%/档变化并 clamp(dir 为负即缩小,其余按放大处理)。
|
|
1856
|
+
* @author ddj 2026年09月22号
|
|
1857
|
+
* @param base 起始缩放(适应宽度态由调用方实测当前渲染缩放传入)
|
|
1858
|
+
* @param dir 方向:< 0 缩小,≥ 0 放大
|
|
1859
|
+
* @returns 步进后的缩放比例
|
|
1860
|
+
*/
|
|
1861
|
+
function zoomStepOf(base, dir) {
|
|
1862
|
+
return clampZoom(base + (dir < 0 ? -.1 : ZOOM_STEP));
|
|
1863
|
+
}
|
|
1864
|
+
/**
|
|
1865
|
+
* 页签缩放记忆键(会话 + 路径;NUL 分隔,防止两段拼接撞键)。
|
|
1866
|
+
* @author ddj 2026年09月22号
|
|
1867
|
+
* @param sessionId 会话 id
|
|
1868
|
+
* @param path 图片路径
|
|
1869
|
+
* @returns 记忆键
|
|
1870
|
+
*/
|
|
1871
|
+
function zoomKeyOf(sessionId, path) {
|
|
1872
|
+
return String(sessionId ?? "") + "\0" + String(path ?? "");
|
|
1873
|
+
}
|
|
1874
|
+
/**
|
|
1875
|
+
* 写入页签缩放记忆(null = 适应宽度;会话级生命周期,不进 localStorage)。
|
|
1876
|
+
* @author ddj 2026年09月22号
|
|
1877
|
+
* @param key zoomKeyOf 产出的记忆键
|
|
1878
|
+
* @param zoom 记忆缩放(null = 适应宽度)
|
|
1879
|
+
*/
|
|
1880
|
+
function rememberZoom(key, zoom) {
|
|
1881
|
+
zoomMem.set(key, zoom);
|
|
1882
|
+
}
|
|
1883
|
+
/**
|
|
1884
|
+
* 读取页签缩放记忆(无记忆返回 null,调用方按初始适应宽度处理)。
|
|
1885
|
+
* @author ddj 2026年09月22号
|
|
1886
|
+
* @param key zoomKeyOf 产出的记忆键
|
|
1887
|
+
* @returns 记忆缩放或 null
|
|
1888
|
+
*/
|
|
1889
|
+
function recallZoom(key) {
|
|
1890
|
+
return zoomMem.get(key) ?? null;
|
|
1891
|
+
}
|
|
1892
|
+
/**
|
|
1893
|
+
* 清空全部页签缩放记忆(EditorView 卸载时调用)。
|
|
1894
|
+
* @author ddj 2026年09月22号
|
|
1895
|
+
*/
|
|
1896
|
+
function clearZoomMem() {
|
|
1897
|
+
zoomMem.clear();
|
|
1898
|
+
}
|
|
1688
1899
|
//#endregion
|
|
1689
1900
|
//#region src/client/markdownPreview.ts
|
|
1690
1901
|
/**
|
|
@@ -1839,6 +2050,218 @@ window.__ModuleLoader__.load({
|
|
|
1839
2050
|
for (let i = 0; i < bytes.length; i += chunk) bin += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
1840
2051
|
return btoa(bin);
|
|
1841
2052
|
}
|
|
2053
|
+
//#endregion
|
|
2054
|
+
//#region src/shared/nativeOpen.ts
|
|
2055
|
+
/**
|
|
2056
|
+
* dsh-vscode-mode shared — 原生打开范围判定(host/client 双面契约)。
|
|
2057
|
+
* 背景:DSH 文件预览双形态——本插件认领 `dsh-resource://file/**` 进 Monaco 编辑,
|
|
2058
|
+
* 官方渲染器(Office 预览/不可预览提示/表格预览)看认领让位。本模块承载「原生打开」
|
|
2059
|
+
* 范围的单一事实源:默认集 = 让位清单(插件本来就不认领的后缀),用户可经设置
|
|
2060
|
+
* `nativeOpenExts`(逗号分隔)增删;host 的 Config schema 默认值与 client 的
|
|
2061
|
+
* 文件树点击判定 / claim 认领判定共用,保证三处永不同源漂移。
|
|
2062
|
+
* 决策沿袭(不因本模块迁移而变):CSV/TSV **不在**默认集——官方 0.1.7 有表格预览,
|
|
2063
|
+
* 但编辑器可编辑性优先,仅用户显式加入 nativeOpenExts 才让位(同 avif 例外先例)。
|
|
2064
|
+
* 作者 ddj 2026年09月22号
|
|
2065
|
+
*/
|
|
2066
|
+
/**
|
|
2067
|
+
* Office 文档后缀:官方 `dsh-client-ui-sidebar-documentpreview` 的 Office 渲染器
|
|
2068
|
+
* 声明 `doc/docx/xls/xlsx/ppt/pptx`(0.1.6 起侧栏 Office 预览;0.1.7 扩展表格 CSV/TSV
|
|
2069
|
+
* 只读预览——本清单刻意不含 csv/tsv,见文件头决策)。本插件让位官方(不认领),
|
|
2070
|
+
* 否则会把这些文件路由进 Monaco 而丢掉官方预览。
|
|
2071
|
+
*/
|
|
2072
|
+
const OFFICE_EXT = [
|
|
2073
|
+
"doc",
|
|
2074
|
+
"docx",
|
|
2075
|
+
"xls",
|
|
2076
|
+
"xlsx",
|
|
2077
|
+
"ppt",
|
|
2078
|
+
"pptx",
|
|
2079
|
+
"odt",
|
|
2080
|
+
"ods",
|
|
2081
|
+
"odp",
|
|
2082
|
+
"pages",
|
|
2083
|
+
"numbers"
|
|
2084
|
+
];
|
|
2085
|
+
/**
|
|
2086
|
+
* 官方「不可预览二进制容器」清单(`UNVIEWABLE_BINARY_EXTENSIONS`,逐项取自
|
|
2087
|
+
* `dsh-client-ui-sidebar-documentpreview/lib/client.js`)。这些后缀官方会给出
|
|
2088
|
+
* 「无法预览」提示;本插件让位官方,避免把二进制当文本读成乱码。
|
|
2089
|
+
*
|
|
2090
|
+
* ⚠️ 刻意例外:官方清单含 `avif`,但本插件图片预览支持 avif(浏览器原生解码),
|
|
2091
|
+
* 故从本表**移除** `avif` —— 保留本插件的图片预览优于官方的「不可预览」。
|
|
2092
|
+
* @author ddj 2026年09月18号
|
|
2093
|
+
*/
|
|
2094
|
+
const BLIND_EXT = [
|
|
2095
|
+
"mp4",
|
|
2096
|
+
"mov",
|
|
2097
|
+
"avi",
|
|
2098
|
+
"mkv",
|
|
2099
|
+
"webm",
|
|
2100
|
+
"flv",
|
|
2101
|
+
"wmv",
|
|
2102
|
+
"m4v",
|
|
2103
|
+
"mp3",
|
|
2104
|
+
"wav",
|
|
2105
|
+
"flac",
|
|
2106
|
+
"ogg",
|
|
2107
|
+
"m4a",
|
|
2108
|
+
"aac",
|
|
2109
|
+
"wma",
|
|
2110
|
+
"opus",
|
|
2111
|
+
"zip",
|
|
2112
|
+
"gz",
|
|
2113
|
+
"tgz",
|
|
2114
|
+
"bz2",
|
|
2115
|
+
"xz",
|
|
2116
|
+
"zst",
|
|
2117
|
+
"7z",
|
|
2118
|
+
"rar",
|
|
2119
|
+
"tar",
|
|
2120
|
+
"jar",
|
|
2121
|
+
"exe",
|
|
2122
|
+
"dll",
|
|
2123
|
+
"so",
|
|
2124
|
+
"dylib",
|
|
2125
|
+
"bin",
|
|
2126
|
+
"o",
|
|
2127
|
+
"class",
|
|
2128
|
+
"pyc",
|
|
2129
|
+
"wasm",
|
|
2130
|
+
"ttf",
|
|
2131
|
+
"otf",
|
|
2132
|
+
"woff",
|
|
2133
|
+
"woff2",
|
|
2134
|
+
"eot",
|
|
2135
|
+
"dmg",
|
|
2136
|
+
"iso",
|
|
2137
|
+
"img",
|
|
2138
|
+
"sqlite",
|
|
2139
|
+
"db",
|
|
2140
|
+
"psd",
|
|
2141
|
+
"ai",
|
|
2142
|
+
"sketch",
|
|
2143
|
+
"tiff",
|
|
2144
|
+
"tif",
|
|
2145
|
+
"heic",
|
|
2146
|
+
"heif"
|
|
2147
|
+
];
|
|
2148
|
+
/** 原生打开默认后缀集 = 让位清单并集(两清单元素天然互斥,直接拼接)。 */
|
|
2149
|
+
const DEFAULT_NATIVE_EXT = [...OFFICE_EXT, ...BLIND_EXT];
|
|
2150
|
+
/** 默认范围的设置序列(逗号分隔;Config schema 默认值与设置页回显同源)。 */
|
|
2151
|
+
const DEFAULT_NATIVE_CSV = DEFAULT_NATIVE_EXT.join(",");
|
|
2152
|
+
/**
|
|
2153
|
+
* 取 path 的 basename 后缀(小写、无点);无后缀/隐藏文件返回 ''。
|
|
2154
|
+
* @author ddj 2026年09月22号
|
|
2155
|
+
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
2156
|
+
* @returns 小写后缀或 ''
|
|
2157
|
+
*/
|
|
2158
|
+
function suffixOf(path) {
|
|
2159
|
+
const base = String(path ?? "").replace(/\\/g, "/").split("/").pop() ?? "";
|
|
2160
|
+
const dot = base.lastIndexOf(".");
|
|
2161
|
+
return dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
|
|
2162
|
+
}
|
|
2163
|
+
/**
|
|
2164
|
+
* 解析设置串为后缀集合:逗号分隔、去空白、去前导点、小写;空段丢弃。
|
|
2165
|
+
* 解析失败/空串 → 空集合(= 不追加任何原生打开范围,让位仍走 deferToOfficial)。
|
|
2166
|
+
* @author ddj 2026年09月22号
|
|
2167
|
+
* @param csv 逗号分隔后缀串
|
|
2168
|
+
* @returns 后缀集合
|
|
2169
|
+
*/
|
|
2170
|
+
function parseExtCsv(csv) {
|
|
2171
|
+
const out = /* @__PURE__ */ new Set();
|
|
2172
|
+
if (typeof csv !== "string") return out;
|
|
2173
|
+
for (const raw of csv.split(",")) {
|
|
2174
|
+
const item = raw.trim().replace(/^\./, "").toLowerCase();
|
|
2175
|
+
if (item) out.add(item);
|
|
2176
|
+
}
|
|
2177
|
+
return out;
|
|
2178
|
+
}
|
|
2179
|
+
/**
|
|
2180
|
+
* 该路径是否命中「原生打开」范围(仅看用户配置集合;默认集语义由调用方
|
|
2181
|
+
* 与 deferToOfficial 取并,保持两判定各司其职)。
|
|
2182
|
+
* @author ddj 2026年09月22号
|
|
2183
|
+
* @param path 文件路径
|
|
2184
|
+
* @param exts 已解析的后缀集合(parseExtCsv 产物)
|
|
2185
|
+
* @returns 是否命中
|
|
2186
|
+
*/
|
|
2187
|
+
function inNativeOpen(path, exts) {
|
|
2188
|
+
const ext = suffixOf(path);
|
|
2189
|
+
return ext !== "" && exts.has(ext);
|
|
2190
|
+
}
|
|
2191
|
+
//#endregion
|
|
2192
|
+
//#region src/client/nativeOpenStore.ts
|
|
2193
|
+
/**
|
|
2194
|
+
* dsh-vscode-mode client — 原生打开范围的运行时状态(设置值缓存 + 官方打开 handler)。
|
|
2195
|
+
* 职责:
|
|
2196
|
+
* 1. 缓存设置字段 `nativeOpenExts` 的解析结果(mountSettingsSyncs 的 keybindings 同步
|
|
2197
|
+
* 块每拍推送;旧版设置无该字段 → 保持默认集,与 deferToOfficial 同源 shared 事实源);
|
|
2198
|
+
* 2. 持有「原生打开」执行 handler(index.ts 装配时注册 sidebarRight.openResource 包装),
|
|
2199
|
+
* EditorView 的 openFile 链路命中判定时调用,失败回退现状打开。
|
|
2200
|
+
* 单例模块级状态:值变更经 CustomEvent 广播(跨组件按需订阅;消费方多为每调用读缓存)。
|
|
2201
|
+
* @author ddj 2026年09月22号
|
|
2202
|
+
*/
|
|
2203
|
+
/** 设置值变化广播事件名(mountSettingsSyncs 推送时派发;幂等值不派发)。 */
|
|
2204
|
+
const NATIVE_OPEN_EVENT = "edrv:native-open-exts-change";
|
|
2205
|
+
/** 当前设置串(设置页回显 / 诊断用)。 */
|
|
2206
|
+
let csv = DEFAULT_NATIVE_CSV;
|
|
2207
|
+
/** 解析后的后缀集合(热路径读取,避免每次点击 split)。 */
|
|
2208
|
+
let exts = new Set(DEFAULT_NATIVE_EXT);
|
|
2209
|
+
/** 官方原生打开 handler(index.ts 装配注册;返回 false/缺失 = 回退现状打开)。 */
|
|
2210
|
+
let handler = null;
|
|
2211
|
+
/**
|
|
2212
|
+
* 该路径是否命中用户配置的原生打开范围(不含 deferToOfficial 默认让位语义——
|
|
2213
|
+
* 那部分由调用方自行取并,保持两判定各司其职)。
|
|
2214
|
+
* @author ddj 2026年09月22号
|
|
2215
|
+
* @param path 文件路径
|
|
2216
|
+
* @returns 是否命中
|
|
2217
|
+
*/
|
|
2218
|
+
function inNativePath(path) {
|
|
2219
|
+
return inNativeOpen(path, exts);
|
|
2220
|
+
}
|
|
2221
|
+
/**
|
|
2222
|
+
* 推送设置值(mountSettingsSyncs 每拍调用):解析为集合,值变化才更新并广播。
|
|
2223
|
+
* 非法/空输入 → 回落默认集(与 host schema default 同源)。
|
|
2224
|
+
* @author ddj 2026年09月22号
|
|
2225
|
+
* @param value 设置原值(unknown,兼容旧版 undefined)
|
|
2226
|
+
*/
|
|
2227
|
+
function setNativeCsv(value) {
|
|
2228
|
+
const next = typeof value === "string" && value.trim() ? value : DEFAULT_NATIVE_CSV;
|
|
2229
|
+
if (next === csv) return;
|
|
2230
|
+
csv = next;
|
|
2231
|
+
exts = parseExtCsv(next);
|
|
2232
|
+
if (exts.size === 0) exts = new Set(DEFAULT_NATIVE_EXT);
|
|
2233
|
+
try {
|
|
2234
|
+
window.dispatchEvent(new CustomEvent(NATIVE_OPEN_EVENT, { detail: { value: csv } }));
|
|
2235
|
+
} catch {}
|
|
2236
|
+
}
|
|
2237
|
+
/**
|
|
2238
|
+
* 注册原生打开执行 handler(index.ts 在官方 sidebarRight.openResource 可用时注册)。
|
|
2239
|
+
* @author ddj 2026年09月22号
|
|
2240
|
+
* @param fn handler(返回是否已原生打开成功);null 解除
|
|
2241
|
+
*/
|
|
2242
|
+
function setNativeOpenHandler(fn) {
|
|
2243
|
+
handler = fn;
|
|
2244
|
+
}
|
|
2245
|
+
/**
|
|
2246
|
+
* 尝试原生打开(EditorView openFile 链路命中判定时调用)。
|
|
2247
|
+
* @author ddj 2026年09月22号
|
|
2248
|
+
* @param path 文件路径
|
|
2249
|
+
* @returns true=已走官方原生打开;false=handler 缺失或失败(调用方回退现状)
|
|
2250
|
+
*/
|
|
2251
|
+
function tryNativeOpen(path) {
|
|
2252
|
+
if (!handler) return false;
|
|
2253
|
+
try {
|
|
2254
|
+
return handler(path) === true;
|
|
2255
|
+
} catch {
|
|
2256
|
+
return false;
|
|
2257
|
+
}
|
|
2258
|
+
}
|
|
2259
|
+
/** 复位(卸载/测试隔离用:回默认集、解绑 handler)。 */
|
|
2260
|
+
function resetNativeOpen() {
|
|
2261
|
+
csv = DEFAULT_NATIVE_CSV;
|
|
2262
|
+
exts = new Set(DEFAULT_NATIVE_EXT);
|
|
2263
|
+
handler = null;
|
|
2264
|
+
}
|
|
1842
2265
|
/** 作用域键 → 路径 → 磁盘版本令牌。 */
|
|
1843
2266
|
const baselines = /* @__PURE__ */ new Map();
|
|
1844
2267
|
/** 作用域键 → 路径 → 已读取过内容的磁盘版本(同版本不重复读盘;含当时的比对结果)。 */
|
|
@@ -2282,6 +2705,7 @@ window.__ModuleLoader__.load({
|
|
|
2282
2705
|
};
|
|
2283
2706
|
let stage = null;
|
|
2284
2707
|
let pageLabel = null;
|
|
2708
|
+
let zoomLabel = null;
|
|
2285
2709
|
let eventBus = null;
|
|
2286
2710
|
let busAbort = null;
|
|
2287
2711
|
let editorTypes = null;
|
|
@@ -2305,6 +2729,14 @@ window.__ModuleLoader__.load({
|
|
|
2305
2729
|
if (!pageLabel || !pdfViewer) return;
|
|
2306
2730
|
pageLabel.textContent = pdfViewer.currentPageNumber + " / " + pdfViewer.pagesCount;
|
|
2307
2731
|
};
|
|
2732
|
+
/**
|
|
2733
|
+
* 缩放百分比指示更新(scalechanging/pagesinit 事件;与图片预览的 x% 文本同款对齐)。
|
|
2734
|
+
* @author ddj 2026年09月22号
|
|
2735
|
+
*/
|
|
2736
|
+
const updateZoomLabel = () => {
|
|
2737
|
+
if (!zoomLabel || !(pdfViewer && pdfViewer.currentScale > 0)) return;
|
|
2738
|
+
zoomLabel.textContent = Math.round(pdfViewer.currentScale * 100) + "%";
|
|
2739
|
+
};
|
|
2308
2740
|
/** 编辑模式按钮高亮同步(annotationeditormodechanged 事件;evt.mode 为枚举数值)。 */
|
|
2309
2741
|
const syncModeButtons = (mode) => {
|
|
2310
2742
|
if (!modeButtons || !editorTypes) return;
|
|
@@ -2426,6 +2858,10 @@ window.__ModuleLoader__.load({
|
|
|
2426
2858
|
pdfViewer.increaseScale();
|
|
2427
2859
|
} catch {}
|
|
2428
2860
|
}, "edrv-pill edrv-pill-ghost edrv-pdf-zoom");
|
|
2861
|
+
zoomLabel = document.createElement("span");
|
|
2862
|
+
zoomLabel.className = "edrv-pdf-page";
|
|
2863
|
+
zoomLabel.textContent = "…";
|
|
2864
|
+
bar.appendChild(zoomLabel);
|
|
2429
2865
|
bar.appendChild(document.createElement("span")).className = "edrv-pdf-sep";
|
|
2430
2866
|
const modes = {};
|
|
2431
2867
|
modes.freetext = mkBtn("✎ 文本框", "插入文本框注释", () => applyMode("freetext"));
|
|
@@ -2485,11 +2921,13 @@ window.__ModuleLoader__.load({
|
|
|
2485
2921
|
});
|
|
2486
2922
|
linkService.setViewer(pdfViewer);
|
|
2487
2923
|
onBus("pagechanging", updatePageLabel);
|
|
2924
|
+
onBus("scalechanging", updateZoomLabel);
|
|
2488
2925
|
onBus("pagesinit", () => {
|
|
2489
2926
|
try {
|
|
2490
2927
|
pdfViewer.currentScaleValue = "page-width";
|
|
2491
2928
|
} catch {}
|
|
2492
2929
|
updatePageLabel();
|
|
2930
|
+
updateZoomLabel();
|
|
2493
2931
|
});
|
|
2494
2932
|
onBus("annotationeditormodechanged", (evt) => syncModeButtons(evt?.mode));
|
|
2495
2933
|
loadingTask = pdfjs.lib.getDocument({
|
|
@@ -2545,6 +2983,7 @@ window.__ModuleLoader__.load({
|
|
|
2545
2983
|
pdfDocument = null;
|
|
2546
2984
|
loadingTask = null;
|
|
2547
2985
|
modeButtons = null;
|
|
2986
|
+
zoomLabel = null;
|
|
2548
2987
|
};
|
|
2549
2988
|
return {
|
|
2550
2989
|
mount,
|
|
@@ -4044,7 +4483,10 @@ window.__ModuleLoader__.load({
|
|
|
4044
4483
|
};
|
|
4045
4484
|
const ensure = (sessionId, key, force = false, extra) => {
|
|
4046
4485
|
if (!key || inFlight.has(key)) return;
|
|
4047
|
-
if (!force && cache.has(key))
|
|
4486
|
+
if (!force && cache.has(key)) {
|
|
4487
|
+
latestValue = cache.get(key);
|
|
4488
|
+
return;
|
|
4489
|
+
}
|
|
4048
4490
|
const fixed = config.args ? config.args(key) : {};
|
|
4049
4491
|
const task = rpc(config.method, {
|
|
4050
4492
|
...fixed,
|
|
@@ -8266,6 +8708,43 @@ window.__ModuleLoader__.load({
|
|
|
8266
8708
|
return out;
|
|
8267
8709
|
}
|
|
8268
8710
|
/**
|
|
8711
|
+
* LSP CompletionItemKind(协议 1-based)→ Monaco CompletionItemKind 枚举名(0-based)。
|
|
8712
|
+
*
|
|
8713
|
+
* 为什么按**名称**而不是编号直传:两侧枚举编号并不一致 —— LSP 2=Method,而 Monaco
|
|
8714
|
+
* 0=Method。若把协议编号当 Monaco 编号塞回去,草稿纸上的「只差一位」会变成全表错位
|
|
8715
|
+
* (属性显示成方法图标等)。用名称映射让两侧各自的编号在各自类型系统里解析,杜绝硬编码。
|
|
8716
|
+
* 索引 i 对应 LSP kind i(索引 0 占位,协议从 1 起)。
|
|
8717
|
+
* @author ddj 2026年09月22号
|
|
8718
|
+
*/
|
|
8719
|
+
const LSP_COMPLETION_KIND_NAMES = [
|
|
8720
|
+
"",
|
|
8721
|
+
"Text",
|
|
8722
|
+
"Method",
|
|
8723
|
+
"Function",
|
|
8724
|
+
"Constructor",
|
|
8725
|
+
"Field",
|
|
8726
|
+
"Variable",
|
|
8727
|
+
"Class",
|
|
8728
|
+
"Interface",
|
|
8729
|
+
"Module",
|
|
8730
|
+
"Property",
|
|
8731
|
+
"Unit",
|
|
8732
|
+
"Value",
|
|
8733
|
+
"Enum",
|
|
8734
|
+
"Keyword",
|
|
8735
|
+
"Snippet",
|
|
8736
|
+
"Color",
|
|
8737
|
+
"File",
|
|
8738
|
+
"Reference",
|
|
8739
|
+
"Folder",
|
|
8740
|
+
"EnumMember",
|
|
8741
|
+
"Constant",
|
|
8742
|
+
"Struct",
|
|
8743
|
+
"Event",
|
|
8744
|
+
"Operator",
|
|
8745
|
+
"TypeParameter"
|
|
8746
|
+
];
|
|
8747
|
+
/**
|
|
8269
8748
|
* Monaco 位置(1-based lineNumber/column)→ LSP Position(0-based)。
|
|
8270
8749
|
* @author ddj 2026年08月27号
|
|
8271
8750
|
* @param lineNumber Monaco 行(≥1)
|
|
@@ -8458,6 +8937,58 @@ window.__ModuleLoader__.load({
|
|
|
8458
8937
|
if (!res) return null;
|
|
8459
8938
|
return res.hover || null;
|
|
8460
8939
|
}
|
|
8940
|
+
/**
|
|
8941
|
+
* 查询补全列表(列表阶段不带 documentation,由 resolve 补全)。
|
|
8942
|
+
* @author ddj 2026年09月22号
|
|
8943
|
+
* @param path 工作区相对路径
|
|
8944
|
+
* @param text 文档全文(未保存内容必须进服务器,否则按旧文本解析)
|
|
8945
|
+
* @param position Monaco 位置(1-based)
|
|
8946
|
+
* @param context LSP CompletionContext(触发类型/触发字符)
|
|
8947
|
+
* @returns { items, incomplete };失败或空时 null
|
|
8948
|
+
*/
|
|
8949
|
+
async function fetchCompletions(path, text, position, context) {
|
|
8950
|
+
await syncDoc(path, text, true);
|
|
8951
|
+
const args = {
|
|
8952
|
+
path,
|
|
8953
|
+
position: monoToLsp(position.lineNumber, position.column)
|
|
8954
|
+
};
|
|
8955
|
+
if (context) args.context = context;
|
|
8956
|
+
const res = await queryLsp("查询补全", "edrv.lsp.completion", args);
|
|
8957
|
+
if (!res || !res.completions) return null;
|
|
8958
|
+
return res.completions;
|
|
8959
|
+
}
|
|
8960
|
+
/**
|
|
8961
|
+
* 惰性补全单个候选项(completionItem/resolve)。
|
|
8962
|
+
* @author ddj 2026年09月22号
|
|
8963
|
+
* @param path 工作区相对路径
|
|
8964
|
+
* @param item host 归一化的补全项(含 data)
|
|
8965
|
+
* @returns 补全后的条目;失败时回落原条目
|
|
8966
|
+
*/
|
|
8967
|
+
async function resolveCompletion(path, item) {
|
|
8968
|
+
const res = await queryLsp("解析补全", "edrv.lsp.resolveCompletion", {
|
|
8969
|
+
path,
|
|
8970
|
+
item
|
|
8971
|
+
});
|
|
8972
|
+
if (!res || !res.item) return item;
|
|
8973
|
+
return res.item;
|
|
8974
|
+
}
|
|
8975
|
+
/**
|
|
8976
|
+
* 查询签名帮助。
|
|
8977
|
+
* @author ddj 2026年09月22号
|
|
8978
|
+
* @param path 工作区相对路径
|
|
8979
|
+
* @param text 文档全文
|
|
8980
|
+
* @param position Monaco 位置(1-based)
|
|
8981
|
+
* @returns 归一化签名帮助;无签名时 null
|
|
8982
|
+
*/
|
|
8983
|
+
async function fetchSignatureHelp(path, text, position) {
|
|
8984
|
+
await syncDoc(path, text, true);
|
|
8985
|
+
const res = await queryLsp("查询签名", "edrv.lsp.signatureHelp", {
|
|
8986
|
+
path,
|
|
8987
|
+
position: monoToLsp(position.lineNumber, position.column)
|
|
8988
|
+
});
|
|
8989
|
+
if (!res) return null;
|
|
8990
|
+
return res.signatureHelp || null;
|
|
8991
|
+
}
|
|
8461
8992
|
/** 查询当前文档的 semantic tokens(host 已归一化 legend 与 delta data)。 */
|
|
8462
8993
|
async function fetchSemanticTokens(path, text) {
|
|
8463
8994
|
await syncDoc(path, text, true);
|
|
@@ -8557,6 +9088,33 @@ window.__ModuleLoader__.load({
|
|
|
8557
9088
|
* 作者 ddj 2026-08-27 / 2026-09-11
|
|
8558
9089
|
*/
|
|
8559
9090
|
const LSP_LANGS = ["lua", "csharp"];
|
|
9091
|
+
/**
|
|
9092
|
+
* 补全触发字符(按语言)。
|
|
9093
|
+
*
|
|
9094
|
+
* 取 EmmyLua / DotRush 声明字符的**交集**且去掉噪声项:`"` `'` `\` `/` `#` 等在多语言里
|
|
9095
|
+
* 过于聒噪(每次输入都弹列表打扰手写),故只保留「成员访问 + 调用 + 索引」三类主场景。
|
|
9096
|
+
* @author ddj 2026年09月22号
|
|
9097
|
+
*/
|
|
9098
|
+
const COMPLETION_TRIGGERS = {
|
|
9099
|
+
lua: [
|
|
9100
|
+
".",
|
|
9101
|
+
":",
|
|
9102
|
+
"(",
|
|
9103
|
+
"["
|
|
9104
|
+
],
|
|
9105
|
+
csharp: [
|
|
9106
|
+
".",
|
|
9107
|
+
":",
|
|
9108
|
+
"(",
|
|
9109
|
+
"[",
|
|
9110
|
+
"<",
|
|
9111
|
+
"@"
|
|
9112
|
+
]
|
|
9113
|
+
};
|
|
9114
|
+
/** 签名帮助触发字符(与 LSP 服务器声明的 triggerCharacters 对齐)。 */
|
|
9115
|
+
const SIGNATURE_TRIGGERS = ["(", ","];
|
|
9116
|
+
/** 签名参数/签名文档上浮窗渲染的兜底最大长度(防超长 doc 撑爆浮窗)。 */
|
|
9117
|
+
const MAX_DOC_LENGTH = 4e3;
|
|
8560
9118
|
const SEMANTIC_LEGEND = {
|
|
8561
9119
|
tokenTypes: [...LSP_SEMANTIC_TOKEN_TYPES],
|
|
8562
9120
|
tokenModifiers: [...LSP_SEMANTIC_TOKEN_MODIFIERS]
|
|
@@ -8638,6 +9196,13 @@ window.__ModuleLoader__.load({
|
|
|
8638
9196
|
};
|
|
8639
9197
|
window.addEventListener("edrv:lsp-redetect", onRedetect);
|
|
8640
9198
|
disposables.push(() => window.removeEventListener("edrv:lsp-redetect", onRedetect));
|
|
9199
|
+
const withCapability = (register) => {
|
|
9200
|
+
try {
|
|
9201
|
+
const disposer = register();
|
|
9202
|
+
if (Array.isArray(disposer)) disposables.push(...disposer.filter(Boolean));
|
|
9203
|
+
else if (disposer) disposables.push(disposer);
|
|
9204
|
+
} catch (error) {}
|
|
9205
|
+
};
|
|
8641
9206
|
disposables.push(monaco.editor.registerEditorOpener({ openCodeEditor: (source, resource, selectionOrPosition) => {
|
|
8642
9207
|
const path = lspUriToAbs(resource);
|
|
8643
9208
|
if (!path) return false;
|
|
@@ -8676,6 +9241,26 @@ window.__ModuleLoader__.load({
|
|
|
8676
9241
|
},
|
|
8677
9242
|
releaseDocumentSemanticTokens: () => {}
|
|
8678
9243
|
}));
|
|
9244
|
+
withCapability(() => LSP_LANGS.map((lang) => completionsFor(monaco, lang)));
|
|
9245
|
+
withCapability(() => monaco.languages.registerSignatureHelpProvider(LSP_LANGS, {
|
|
9246
|
+
signatureHelpTriggerCharacters: SIGNATURE_TRIGGERS,
|
|
9247
|
+
signatureHelpRetriggerCharacters: SIGNATURE_TRIGGERS,
|
|
9248
|
+
provideSignatureHelp: async (model, position, token, context) => {
|
|
9249
|
+
const path = pathOfModel(model);
|
|
9250
|
+
if (!path) return null;
|
|
9251
|
+
if (token?.isCancellationRequested) return null;
|
|
9252
|
+
const help = await fetchSignatureHelp(path, model.getValue(), position);
|
|
9253
|
+
if (!help || !help.signatures.length) return null;
|
|
9254
|
+
return {
|
|
9255
|
+
value: {
|
|
9256
|
+
signatures: help.signatures.map(toMonacoSignature),
|
|
9257
|
+
activeSignature: help.activeSignature,
|
|
9258
|
+
activeParameter: help.activeParameter
|
|
9259
|
+
},
|
|
9260
|
+
dispose: () => {}
|
|
9261
|
+
};
|
|
9262
|
+
}
|
|
9263
|
+
}));
|
|
8679
9264
|
if (host) host[LSP_PROVIDERS_GLOBAL] = true;
|
|
8680
9265
|
}
|
|
8681
9266
|
/**
|
|
@@ -8749,25 +9334,181 @@ window.__ModuleLoader__.load({
|
|
|
8749
9334
|
return true;
|
|
8750
9335
|
}
|
|
8751
9336
|
/**
|
|
8752
|
-
* 当前 Monaco 是否具备引用 Peek 能力(referencesController contribution 注入即视为支持)。
|
|
8753
|
-
* @author ddj 2026年09月11号
|
|
8754
|
-
* @param ed Monaco 编辑器
|
|
8755
|
-
* @returns 是否支持
|
|
9337
|
+
* 当前 Monaco 是否具备引用 Peek 能力(referencesController contribution 注入即视为支持)。
|
|
9338
|
+
* @author ddj 2026年09月11号
|
|
9339
|
+
* @param ed Monaco 编辑器
|
|
9340
|
+
* @returns 是否支持
|
|
9341
|
+
*/
|
|
9342
|
+
function peekSupported(ed) {
|
|
9343
|
+
if (!ed || typeof ed.getContribution !== "function") return false;
|
|
9344
|
+
try {
|
|
9345
|
+
return Boolean(ed.getContribution("editor.contrib.referencesController"));
|
|
9346
|
+
} catch (error) {
|
|
9347
|
+
return false;
|
|
9348
|
+
}
|
|
9349
|
+
}
|
|
9350
|
+
/** Shift+F12 / 右键「查找所有引用」:走 Monaco 原生 References Peek(两栏引用视图)。 */
|
|
9351
|
+
async function runFindReferences(ed) {
|
|
9352
|
+
const position = ed.getPosition();
|
|
9353
|
+
if (!position) return;
|
|
9354
|
+
ed.setPosition(position);
|
|
9355
|
+
await triggerReferencePeek(ed);
|
|
9356
|
+
}
|
|
9357
|
+
/**
|
|
9358
|
+
* 构造某语言的补全 provider(触发字符按语言区分)。
|
|
9359
|
+
*
|
|
9360
|
+
* 为什么有 documentPath 传递:Monaco 调 `resolveCompletionItem(item, token)` 时**不传 model**
|
|
9361
|
+
* (实测 vendored 0.42 构建:`provider.resolveCompletionItem(this.completion, token)`),
|
|
9362
|
+
* 因此路径必须在列表阶段随候选项带上,否则 resolve 阶段无处得知该查哪个文档。
|
|
9363
|
+
* @author ddj 2026年09月22号
|
|
9364
|
+
* @param monaco Monaco 实例
|
|
9365
|
+
* @param lang 语言 id
|
|
9366
|
+
* @returns provider 注销器
|
|
9367
|
+
*/
|
|
9368
|
+
function completionsFor(monaco, lang) {
|
|
9369
|
+
return monaco.languages.registerCompletionItemProvider(lang, {
|
|
9370
|
+
triggerCharacters: COMPLETION_TRIGGERS[lang] ?? [".", ":"],
|
|
9371
|
+
provideCompletionItems: async (model, position, context, token) => {
|
|
9372
|
+
const path = pathOfModel(model);
|
|
9373
|
+
if (!path) return { suggestions: [] };
|
|
9374
|
+
const list = await fetchCompletions(path, model.getValue(), position, toLspContext(context));
|
|
9375
|
+
if (!list || !list.items.length || token?.isCancellationRequested) return { suggestions: [] };
|
|
9376
|
+
const word = model.getWordUntilPosition(position);
|
|
9377
|
+
const fallback = {
|
|
9378
|
+
startLineNumber: position.lineNumber,
|
|
9379
|
+
endLineNumber: position.lineNumber,
|
|
9380
|
+
startColumn: word.startColumn,
|
|
9381
|
+
endColumn: word.endColumn
|
|
9382
|
+
};
|
|
9383
|
+
return {
|
|
9384
|
+
suggestions: list.items.map((item) => toMonoSuggestion(monaco, item, fallback, path)),
|
|
9385
|
+
incomplete: list.incomplete === true
|
|
9386
|
+
};
|
|
9387
|
+
},
|
|
9388
|
+
resolveCompletionItem: async (item, token) => {
|
|
9389
|
+
const raw = item?.__edrvRaw;
|
|
9390
|
+
const path = item?.__edrvPath;
|
|
9391
|
+
if (!raw || !path || token?.isCancellationRequested) return item;
|
|
9392
|
+
const resolved = await resolveCompletion(path, raw).catch(() => null);
|
|
9393
|
+
if (!resolved) return item;
|
|
9394
|
+
return mergeResolved(monaco, item, resolved);
|
|
9395
|
+
}
|
|
9396
|
+
});
|
|
9397
|
+
}
|
|
9398
|
+
/**
|
|
9399
|
+
* Monaco 补全上下文 → LSP CompletionContext。
|
|
9400
|
+
*
|
|
9401
|
+
* ⚠️ 两侧 triggerKind **编号不同,必须换算**(实测 vendored 0.42 与 LSP 3.17 规范):
|
|
9402
|
+
* Monaco:0=Invoke, 1=TriggerCharacter, 2=TriggerForIncompleteCompletions
|
|
9403
|
+
* LSP :1=Invoked, 2=TriggerCharacter, 3=TriggerForIncomplete
|
|
9404
|
+
* 恒差 1。直传会把「按字符触发」谎报成 Invoked,服务器据此可能不返回成员补全
|
|
9405
|
+
* (部分服务器严格按 triggerKind 决定是否给 table 成员)。
|
|
9406
|
+
* @author ddj 2026年09月22号
|
|
9407
|
+
* @param context Monaco 上下文(可能缺字段)
|
|
9408
|
+
* @returns LSP 上下文;无触发信息时 undefined(不占载荷)
|
|
9409
|
+
*/
|
|
9410
|
+
function toLspContext(context) {
|
|
9411
|
+
const kind = context?.triggerKind;
|
|
9412
|
+
if (typeof kind !== "number" && !context?.triggerCharacter) return void 0;
|
|
9413
|
+
const out = { triggerKind: typeof kind === "number" ? Math.min(3, Math.max(1, kind + 1)) : 1 };
|
|
9414
|
+
if (typeof context?.triggerCharacter === "string") out.triggerCharacter = context.triggerCharacter;
|
|
9415
|
+
return out;
|
|
9416
|
+
}
|
|
9417
|
+
/**
|
|
9418
|
+
* LSP 补全项 → Monaco suggestion。
|
|
9419
|
+
* @author ddj 2026年09月22号
|
|
9420
|
+
* @param monaco Monaco 实例(取枚举)
|
|
9421
|
+
* @param item host 归一化补全项
|
|
9422
|
+
* @param fallback 无 textEdit 时的词范围
|
|
9423
|
+
* @param path 工作区相对路径(resolve 阶段回传用)
|
|
9424
|
+
* @returns Monaco suggestion
|
|
9425
|
+
*/
|
|
9426
|
+
function toMonoSuggestion(monaco, item, fallback, path) {
|
|
9427
|
+
const kindName = LSP_COMPLETION_KIND_NAMES[item.kind ?? 0];
|
|
9428
|
+
const kinds = monaco.languages.CompletionItemKind ?? {};
|
|
9429
|
+
const asSnippet = monaco.languages.CompletionItemInsertTextRule?.InsertAsSnippet;
|
|
9430
|
+
const suggestion = {
|
|
9431
|
+
label: item.label,
|
|
9432
|
+
kind: kindName && typeof kinds[kindName] === "number" ? kinds[kindName] : kinds.Text ?? 0,
|
|
9433
|
+
insertText: textOfCompletion(item),
|
|
9434
|
+
range: rangeOfCompletion(monaco, item, fallback),
|
|
9435
|
+
__edrvRaw: item,
|
|
9436
|
+
__edrvPath: path
|
|
9437
|
+
};
|
|
9438
|
+
if (item.detail) suggestion.detail = item.detail;
|
|
9439
|
+
if (item.documentation) suggestion.documentation = { value: clip$1(item.documentation) };
|
|
9440
|
+
if (item.filterText) suggestion.filterText = item.filterText;
|
|
9441
|
+
if (item.sortText) suggestion.sortText = item.sortText;
|
|
9442
|
+
if (item.preselect === true) suggestion.preselect = true;
|
|
9443
|
+
if (item.commitCharacters) suggestion.commitCharacters = item.commitCharacters;
|
|
9444
|
+
if (item.deprecated === true) suggestion.tags = [monaco.languages.CompletionItemTag?.Deprecated ?? 1];
|
|
9445
|
+
if (item.additionalTextEdits) suggestion.additionalTextEdits = item.additionalTextEdits.map((edit) => toMonoEdit(monaco, edit));
|
|
9446
|
+
if (item.insertTextFormat === 2 && typeof asSnippet === "number") suggestion.insertTextRules = asSnippet;
|
|
9447
|
+
return suggestion;
|
|
9448
|
+
}
|
|
9449
|
+
/**
|
|
9450
|
+
* 取补全插入文本:`textEdit.newText` 优先于 `insertText`(协议规定 textEdit 生效时以它为准)。
|
|
9451
|
+
* @author ddj 2026年09月22号
|
|
9452
|
+
*/
|
|
9453
|
+
function textOfCompletion(item) {
|
|
9454
|
+
if (item.textEdit?.newText) return item.textEdit.newText;
|
|
9455
|
+
return item.insertText ?? item.label;
|
|
9456
|
+
}
|
|
9457
|
+
/**
|
|
9458
|
+
* 取补全替换范围(Monaco 1-based):单 range 或 insert/replace 双 range 两种形态都映射。
|
|
9459
|
+
* 无 textEdit 时回落词范围 —— 缺范围会让 Monaco 用默认范围替换,可能吃掉已输入前缀。
|
|
9460
|
+
* @author ddj 2026年09月22号
|
|
8756
9461
|
*/
|
|
8757
|
-
function
|
|
8758
|
-
|
|
8759
|
-
|
|
8760
|
-
|
|
8761
|
-
|
|
8762
|
-
|
|
8763
|
-
|
|
9462
|
+
function rangeOfCompletion(monaco, item, fallback) {
|
|
9463
|
+
const edit = item.textEdit;
|
|
9464
|
+
if (!edit) return fallback;
|
|
9465
|
+
if (edit.range) return toMonoRange(monaco, edit.range);
|
|
9466
|
+
if (edit.insert && edit.replace) return {
|
|
9467
|
+
insert: toMonoRange(monaco, edit.insert),
|
|
9468
|
+
replace: toMonoRange(monaco, edit.replace)
|
|
9469
|
+
};
|
|
9470
|
+
return fallback;
|
|
8764
9471
|
}
|
|
8765
|
-
/**
|
|
8766
|
-
|
|
8767
|
-
const
|
|
8768
|
-
|
|
8769
|
-
|
|
8770
|
-
|
|
9472
|
+
/** LSP Range(0-based)→ Monaco Range(1-based)。 */
|
|
9473
|
+
function toMonoRange(monaco, range) {
|
|
9474
|
+
const s = (p) => ({
|
|
9475
|
+
lineNumber: Math.max(1, (p?.line ?? 0) + 1),
|
|
9476
|
+
column: Math.max(1, (p?.character ?? 0) + 1)
|
|
9477
|
+
});
|
|
9478
|
+
const start = s(range?.start);
|
|
9479
|
+
const end = s(range?.end);
|
|
9480
|
+
return new monaco.Range(start.lineNumber, start.column, end.lineNumber, end.column);
|
|
9481
|
+
}
|
|
9482
|
+
/** LSP TextEdit → Monaco IEditOperation(additionalTextEdits 用)。 */
|
|
9483
|
+
function toMonoEdit(monaco, edit) {
|
|
9484
|
+
return {
|
|
9485
|
+
range: toMonoRange(monaco, edit.range),
|
|
9486
|
+
text: edit.newText
|
|
9487
|
+
};
|
|
9488
|
+
}
|
|
9489
|
+
/**
|
|
9490
|
+
* 把 resolve 结果合并进已展示的候选项(保留列表阶段的 range/kind 等 Monaco 侧字段)。
|
|
9491
|
+
* @author ddj 2026年09月22号
|
|
9492
|
+
* @param monaco Monaco 实例
|
|
9493
|
+
* @param suggestion 原候选项
|
|
9494
|
+
* @param resolved resolve 后的归一化条目
|
|
9495
|
+
* @returns 合并后的候选项
|
|
9496
|
+
*/
|
|
9497
|
+
function mergeResolved(monaco, suggestion, resolved) {
|
|
9498
|
+
const merged = {
|
|
9499
|
+
...suggestion,
|
|
9500
|
+
__edrvRaw: resolved
|
|
9501
|
+
};
|
|
9502
|
+
if (resolved.detail) merged.detail = resolved.detail;
|
|
9503
|
+
if (resolved.documentation) merged.documentation = { value: clip$1(resolved.documentation) };
|
|
9504
|
+
if (resolved.additionalTextEdits) merged.additionalTextEdits = resolved.additionalTextEdits.map((edit) => toMonoEdit(monaco, edit));
|
|
9505
|
+
return merged;
|
|
9506
|
+
}
|
|
9507
|
+
/** 文档裁剪:超长 doc(少数服务器返回整段源码)会撑爆浮窗,截断并标注。 */
|
|
9508
|
+
function clip$1(text) {
|
|
9509
|
+
const value = String(text ?? "");
|
|
9510
|
+
if (value.length <= MAX_DOC_LENGTH) return value;
|
|
9511
|
+
return value.slice(0, MAX_DOC_LENGTH) + "\n\n…(内容过长已截断)";
|
|
8771
9512
|
}
|
|
8772
9513
|
/** 编辑器状态栏提示(复用 EditorView 的 status 通道)。 */
|
|
8773
9514
|
function setStatus(text) {
|
|
@@ -12427,13 +13168,70 @@ window.__ModuleLoader__.load({
|
|
|
12427
13168
|
/** 外部侧栏插件名(dsh-web-ui-all 家族的文件打开能力提供方)。 */
|
|
12428
13169
|
const SIDEBAR_PLUGIN = "dsh-better-sidebar";
|
|
12429
13170
|
/**
|
|
12430
|
-
*
|
|
13171
|
+
* 形状守卫:判断 configForms.get 返回值是否具备适配所需的最小面。
|
|
13172
|
+
* @author ddj 2026年09月22号
|
|
13173
|
+
* @param form configForms.get(entryId) 的返回值
|
|
13174
|
+
* @returns 是否为可用 ConfigForm
|
|
13175
|
+
*/
|
|
13176
|
+
function isConfigForm(form) {
|
|
13177
|
+
if (!form || typeof form !== "object") return false;
|
|
13178
|
+
const candidate = form;
|
|
13179
|
+
return typeof candidate.getSnapshot === "function" && typeof candidate.subscribe === "function" && typeof candidate.set === "function";
|
|
13180
|
+
}
|
|
13181
|
+
/**
|
|
13182
|
+
* 将 DSH 0.1.7 ConfigForm 适配为既有 SettingsScopeLike(调用方零改动)。
|
|
13183
|
+
* status/value/writable 直接透传('ready'|'loading'|'unavailable' 与既有 status 词汇一致);
|
|
13184
|
+
* set 丢弃返回的 boolean(避免给未 catch 的既有调用方新增拒绝;form.set 自身 reject 仍传导)。
|
|
13185
|
+
* @author ddj 2026年09月22号
|
|
13186
|
+
* @param form configForms.get(PLUGIN_NAME) 返回的表单
|
|
13187
|
+
* @returns 适配后的设置 scope
|
|
13188
|
+
*/
|
|
13189
|
+
function adaptConfigForm(form) {
|
|
13190
|
+
return {
|
|
13191
|
+
getSnapshot: () => {
|
|
13192
|
+
const snap = form.getSnapshot();
|
|
13193
|
+
return {
|
|
13194
|
+
status: snap.status,
|
|
13195
|
+
value: snap.value,
|
|
13196
|
+
writable: snap.writable
|
|
13197
|
+
};
|
|
13198
|
+
},
|
|
13199
|
+
subscribe: (listener) => form.subscribe(listener),
|
|
13200
|
+
set: async (field, value) => {
|
|
13201
|
+
await form.set(field, value);
|
|
13202
|
+
}
|
|
13203
|
+
};
|
|
13204
|
+
}
|
|
13205
|
+
/**
|
|
13206
|
+
* 探测 DSH 0.1.7+ configForms 官方新设置桥(entryId = PLUGIN_NAME)。
|
|
13207
|
+
* 0.1.6 无该服务、ctx.get/表单 get 抛错或形状不符时返回 undefined,交由原两级桥降级。
|
|
13208
|
+
* @author ddj 2026年09月22号
|
|
13209
|
+
* @param ctx 客户端服务上下文
|
|
13210
|
+
* @returns 适配后的设置 scope 或 undefined
|
|
13211
|
+
*/
|
|
13212
|
+
function bindConfigForm(ctx) {
|
|
13213
|
+
try {
|
|
13214
|
+
const form = ctx.get("configForms")?.get?.(PLUGIN_NAME);
|
|
13215
|
+
if (!isConfigForm(form)) return void 0;
|
|
13216
|
+
return adaptConfigForm(form);
|
|
13217
|
+
} catch {
|
|
13218
|
+
return;
|
|
13219
|
+
}
|
|
13220
|
+
}
|
|
13221
|
+
/**
|
|
13222
|
+
* 设置桥优先序:configForms(DSH 0.1.7+ 官方新桥)→ webUiSettings(linxin666 兼容桥,
|
|
13223
|
+
* 旧版现网优先级不变)→ settingsScope(DSH 0.1.6 官方旧桥)→ 无。
|
|
12431
13224
|
* 桥绑定抛错时降级到下一级,不让单个桥异常拖垮设置装配。
|
|
12432
|
-
* @author ddj 2026年08月24号
|
|
13225
|
+
* @author ddj 2026年08月24号(2026年09月22号 增补 configForms 桥)
|
|
12433
13226
|
* @param ctx 客户端服务上下文
|
|
12434
13227
|
* @returns 激活的桥名称与绑定 scope
|
|
12435
13228
|
*/
|
|
12436
13229
|
function pickSettingsBinder(ctx) {
|
|
13230
|
+
const configForm = bindConfigForm(ctx);
|
|
13231
|
+
if (configForm) return {
|
|
13232
|
+
service: "configForms",
|
|
13233
|
+
scope: configForm
|
|
13234
|
+
};
|
|
12437
13235
|
for (const service of ["webUiSettings", "settingsScope"]) try {
|
|
12438
13236
|
const scope = ctx.get(service)?.bind?.({ namespace: PLUGIN_NAME });
|
|
12439
13237
|
if (scope) return {
|
|
@@ -12447,6 +13245,55 @@ window.__ModuleLoader__.load({
|
|
|
12447
13245
|
};
|
|
12448
13246
|
}
|
|
12449
13247
|
/**
|
|
13248
|
+
* 设置桥装配(带晚到有界重试):设置桥服务一律不进 inject(0.1.6 settingsScope /
|
|
13249
|
+
* 0.1.7 configForms 互斥,写死任一桥名都会在另一版本停等),因此提供方可能晚于本插件
|
|
13250
|
+
* apply 就绪——构造时探测一次,未命中则按 schedule 节奏有界重试,命中即通知 whenReady
|
|
13251
|
+
* 订阅者(重挂设置同步 effect);重试用尽保持未就绪(与旧行为一致,不无限轮询)。
|
|
13252
|
+
* @author ddj 2026年09月22号
|
|
13253
|
+
* @param ctx 客户端服务上下文
|
|
13254
|
+
* @param options schedule 注入(缺省不重试=旧行为);attempts/intervalMs 重试节奏
|
|
13255
|
+
* @returns 设置桥
|
|
13256
|
+
*/
|
|
13257
|
+
function settingsBridge(ctx, options) {
|
|
13258
|
+
let hit = pickSettingsBinder(ctx);
|
|
13259
|
+
let attemptsLeft = options?.attempts ?? 0;
|
|
13260
|
+
const interval = options?.intervalMs ?? 2e3;
|
|
13261
|
+
const waiters = [];
|
|
13262
|
+
const notify = () => {
|
|
13263
|
+
for (const listener of waiters.splice(0)) try {
|
|
13264
|
+
listener();
|
|
13265
|
+
} catch {}
|
|
13266
|
+
};
|
|
13267
|
+
const retry = () => {
|
|
13268
|
+
if (hit.scope || attemptsLeft <= 0 || !options?.schedule) return;
|
|
13269
|
+
attemptsLeft -= 1;
|
|
13270
|
+
options.schedule(() => {
|
|
13271
|
+
hit = pickSettingsBinder(ctx);
|
|
13272
|
+
if (hit.scope) {
|
|
13273
|
+
notify();
|
|
13274
|
+
return;
|
|
13275
|
+
}
|
|
13276
|
+
retry();
|
|
13277
|
+
}, interval);
|
|
13278
|
+
};
|
|
13279
|
+
retry();
|
|
13280
|
+
return {
|
|
13281
|
+
scope: () => hit.scope,
|
|
13282
|
+
service: () => hit.service,
|
|
13283
|
+
whenReady: (listener) => {
|
|
13284
|
+
if (hit.scope) {
|
|
13285
|
+
listener();
|
|
13286
|
+
return () => {};
|
|
13287
|
+
}
|
|
13288
|
+
waiters.push(listener);
|
|
13289
|
+
return () => {
|
|
13290
|
+
const at = waiters.indexOf(listener);
|
|
13291
|
+
if (at >= 0) waiters.splice(at, 1);
|
|
13292
|
+
};
|
|
13293
|
+
}
|
|
13294
|
+
};
|
|
13295
|
+
}
|
|
13296
|
+
/**
|
|
12450
13297
|
* 跨版本 slot 安全注册:封装 ctx.slots.inject 等待声明模式(新老 DSH 通用),
|
|
12451
13298
|
* 服务缺失或注册抛错时降级为警告,不让单条 slot 拖垮装配。
|
|
12452
13299
|
* 注意:方法必须挂在服务对象上调用(slots.register 是依赖 this.records 的类方法,
|
|
@@ -12548,103 +13395,13 @@ window.__ModuleLoader__.load({
|
|
|
12548
13395
|
const OFFICIAL_FILE_TAB_ID = "dsh-vscode-mode/file";
|
|
12549
13396
|
/** file 资源类型的 kind(与页类型 edrvEditor 区分:同 kind 只允许一份 extension)。 */
|
|
12550
13397
|
const OFFICIAL_FILE_KIND = "edrvEditorFile";
|
|
12551
|
-
/**
|
|
12552
|
-
* Office 文档后缀:官方 `dsh-client-ui-sidebar-documentpreview` 的 Office 渲染器
|
|
12553
|
-
* 声明 `doc/docx/xls/xlsx/ppt/pptx`,并在 alpha.2 起提供侧栏 Office 预览。
|
|
12554
|
-
* 本插件让位官方(不认领),否则会把这些文件路由进 Monaco 而丢掉 Office 预览。
|
|
12555
|
-
*/
|
|
12556
|
-
const OFFICE_EXT = [
|
|
12557
|
-
"doc",
|
|
12558
|
-
"docx",
|
|
12559
|
-
"xls",
|
|
12560
|
-
"xlsx",
|
|
12561
|
-
"ppt",
|
|
12562
|
-
"pptx",
|
|
12563
|
-
"odt",
|
|
12564
|
-
"ods",
|
|
12565
|
-
"odp",
|
|
12566
|
-
"pages",
|
|
12567
|
-
"numbers"
|
|
12568
|
-
];
|
|
12569
|
-
/**
|
|
12570
|
-
* 官方「不可预览二进制容器」清单(`UNVIEWABLE_BINARY_EXTENSIONS`,逐项取自
|
|
12571
|
-
* `dsh-client-ui-sidebar-documentpreview/lib/client.js` 的 `UNVIEWABLE_BINARY_EXTENSIONS`)。
|
|
12572
|
-
* 这些后缀官方会给出「无法预览」提示;本插件让位官方,避免把二进制当文本读成乱码。
|
|
12573
|
-
*
|
|
12574
|
-
* ⚠️ 刻意例外:官方清单含 `avif`,但本插件 {@link IMAGE_MIME} 支持 avif 图片预览
|
|
12575
|
-
* (浏览器原生解码),故从本表**移除** `avif` —— 保留本插件的图片预览优于官方的「不可预览」。
|
|
12576
|
-
* @author ddj 2026年09月18号
|
|
12577
|
-
*/
|
|
12578
|
-
const BLIND_EXT = [
|
|
12579
|
-
"mp4",
|
|
12580
|
-
"mov",
|
|
12581
|
-
"avi",
|
|
12582
|
-
"mkv",
|
|
12583
|
-
"webm",
|
|
12584
|
-
"flv",
|
|
12585
|
-
"wmv",
|
|
12586
|
-
"m4v",
|
|
12587
|
-
"mp3",
|
|
12588
|
-
"wav",
|
|
12589
|
-
"flac",
|
|
12590
|
-
"ogg",
|
|
12591
|
-
"m4a",
|
|
12592
|
-
"aac",
|
|
12593
|
-
"wma",
|
|
12594
|
-
"opus",
|
|
12595
|
-
"zip",
|
|
12596
|
-
"gz",
|
|
12597
|
-
"tgz",
|
|
12598
|
-
"bz2",
|
|
12599
|
-
"xz",
|
|
12600
|
-
"zst",
|
|
12601
|
-
"7z",
|
|
12602
|
-
"rar",
|
|
12603
|
-
"tar",
|
|
12604
|
-
"jar",
|
|
12605
|
-
"exe",
|
|
12606
|
-
"dll",
|
|
12607
|
-
"so",
|
|
12608
|
-
"dylib",
|
|
12609
|
-
"bin",
|
|
12610
|
-
"o",
|
|
12611
|
-
"class",
|
|
12612
|
-
"pyc",
|
|
12613
|
-
"wasm",
|
|
12614
|
-
"ttf",
|
|
12615
|
-
"otf",
|
|
12616
|
-
"woff",
|
|
12617
|
-
"woff2",
|
|
12618
|
-
"eot",
|
|
12619
|
-
"dmg",
|
|
12620
|
-
"iso",
|
|
12621
|
-
"img",
|
|
12622
|
-
"sqlite",
|
|
12623
|
-
"db",
|
|
12624
|
-
"psd",
|
|
12625
|
-
"ai",
|
|
12626
|
-
"sketch",
|
|
12627
|
-
"tiff",
|
|
12628
|
-
"tif",
|
|
12629
|
-
"heic",
|
|
12630
|
-
"heif"
|
|
12631
|
-
];
|
|
12632
13398
|
/** 让位判定用后缀集合(模块级构建一次;小写、无前导点)。 */
|
|
12633
13399
|
const DEFER_EXT_SET = /* @__PURE__ */ new Set([...OFFICE_EXT, ...BLIND_EXT]);
|
|
12634
13400
|
/**
|
|
12635
|
-
* 取 path 的 basename 后缀(小写、无点);无后缀/隐藏文件返回 ''。
|
|
12636
|
-
* @author ddj 2026年09月18号
|
|
12637
|
-
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
12638
|
-
* @returns 小写后缀或 ''
|
|
12639
|
-
*/
|
|
12640
|
-
function suffixOf(path) {
|
|
12641
|
-
const base = String(path ?? "").replace(/\\/g, "/").split("/").pop() ?? "";
|
|
12642
|
-
const dot = base.lastIndexOf(".");
|
|
12643
|
-
return dot > 0 ? base.slice(dot + 1).toLowerCase() : "";
|
|
12644
|
-
}
|
|
12645
|
-
/**
|
|
12646
13401
|
* 该路径是否应让位官方查看器(Office 文档 + 官方不可预览的二进制容器)。
|
|
12647
13402
|
* 命中即不认领 `dsh-resource://file/**`,回落官方预览/提示。
|
|
13403
|
+
* 注:用户经设置 nativeOpenExts 追加的范围不走本函数,由 claim 的 canOpen 与
|
|
13404
|
+
* 文件树 openFile 叠加 nativeOpenStore 判定(见 registerOfficialFileClaim)。
|
|
12648
13405
|
* @author ddj 2026年09月18号
|
|
12649
13406
|
* @param path 文件路径(工作区相对或绝对)
|
|
12650
13407
|
* @returns 是否让位官方
|
|
@@ -12885,7 +13642,7 @@ window.__ModuleLoader__.load({
|
|
|
12885
13642
|
canOpen: (address) => {
|
|
12886
13643
|
const parsed = parseOfficialFileAddress(address);
|
|
12887
13644
|
if (parsed === null) return false;
|
|
12888
|
-
return !deferToOfficial(parsed.path);
|
|
13645
|
+
return !deferToOfficial(parsed.path) && !inNativePath(parsed.path);
|
|
12889
13646
|
},
|
|
12890
13647
|
title: (address) => officialFileTitle(address)
|
|
12891
13648
|
});
|
|
@@ -15989,6 +16746,20 @@ window.__ModuleLoader__.load({
|
|
|
15989
16746
|
}
|
|
15990
16747
|
/** 跳转目标高亮的保留时长(LSP/搜索跳转落地后给用户的位置提示,到期自动清除)。 */
|
|
15991
16748
|
const NAV_FLASH_MS = 1200;
|
|
16749
|
+
/** 二进制通道回退日志的一次性闸(整页仅报一次,避免每次读图/读 PDF 刷屏)。 */
|
|
16750
|
+
let binFallbackLogged = false;
|
|
16751
|
+
/**
|
|
16752
|
+
* 二进制通道回退的一次性诊断日志:readBinaryPreview 本次尝试过新通道并失败时上报。
|
|
16753
|
+
* 有效期:随页面生命周期仅一条;dbg 本身受诊断开关控制(关=零输出零落盘)。
|
|
16754
|
+
* @author ddj 2026年09月22号
|
|
16755
|
+
* @param sid 会话 id
|
|
16756
|
+
* @param out readBinaryPreview 统一结果(带 probed 才说明本次尝试过新通道)
|
|
16757
|
+
*/
|
|
16758
|
+
const noteBinFallback = (sid, out) => {
|
|
16759
|
+
if (binFallbackLogged || !out?.probed) return;
|
|
16760
|
+
binFallbackLogged = true;
|
|
16761
|
+
dbg(sid, "edrv.readBinary 不可用(host 未接线/旧版或网络失败),已回退 base64", "debug");
|
|
16762
|
+
};
|
|
15992
16763
|
/**
|
|
15993
16764
|
* 从 Monaco 语言目录取可选语言 id 列表(代码片段新建时的语言下拉来源)。
|
|
15994
16765
|
* 旧版 Monaco / 目录不可读时返回 undefined,由调用方回落 shared 的内置常量。
|
|
@@ -16052,6 +16823,8 @@ window.__ModuleLoader__.load({
|
|
|
16052
16823
|
const [imageSrc, setImageSrc] = react.default.useState(null);
|
|
16053
16824
|
const [imgSize, setImgSize] = react.default.useState(null);
|
|
16054
16825
|
const [imgBroken, setImgBroken] = react.default.useState(false);
|
|
16826
|
+
const [imgZoom, setImgZoom] = react.default.useState(null);
|
|
16827
|
+
const imgElRef = react.default.useRef(null);
|
|
16055
16828
|
const svgTextRef = react.default.useRef(/* @__PURE__ */ new Set());
|
|
16056
16829
|
const mdPreviewRef = react.default.useRef(/* @__PURE__ */ new Set());
|
|
16057
16830
|
const [pdfBytes, setPdfBytes] = react.default.useState(null);
|
|
@@ -16710,23 +17483,34 @@ window.__ModuleLoader__.load({
|
|
|
16710
17483
|
progress: monaco ? 72 : 12,
|
|
16711
17484
|
message: "读取图片…"
|
|
16712
17485
|
});
|
|
16713
|
-
rpc
|
|
17486
|
+
readBinaryPreview(rpc, {
|
|
16714
17487
|
sessionId: sid,
|
|
16715
|
-
path
|
|
16716
|
-
|
|
16717
|
-
}).then((res) => {
|
|
17488
|
+
path
|
|
17489
|
+
}).then((out) => {
|
|
16718
17490
|
if (seq !== loadSeqRef.current || path !== active) return;
|
|
16719
|
-
if (
|
|
16720
|
-
|
|
17491
|
+
if (out.ok && out.via === "binary") {
|
|
17492
|
+
recordBaseline(scope, path, out.version || version);
|
|
17493
|
+
clearReadVersion(scope, path);
|
|
17494
|
+
setImageSrc(dataUrlOf(bytesToBase64(out.bytes), out.mime));
|
|
17495
|
+
setLoadStage({
|
|
17496
|
+
progress: 100,
|
|
17497
|
+
message: "图片已就绪"
|
|
17498
|
+
});
|
|
17499
|
+
setStatus("已加载");
|
|
17500
|
+
return;
|
|
17501
|
+
}
|
|
17502
|
+
noteBinFallback(sid, out);
|
|
17503
|
+
if (out.ok && out.via === "base64") {
|
|
17504
|
+
if (!out.mime) {
|
|
16721
17505
|
setLoadError("host 版本过旧:图片响应缺少 mime");
|
|
16722
17506
|
setError("host 版本过旧:图片响应缺少 mime");
|
|
16723
17507
|
setStatus("读取失败");
|
|
16724
17508
|
return;
|
|
16725
17509
|
}
|
|
16726
|
-
const imgVersion =
|
|
17510
|
+
const imgVersion = out.version ?? version;
|
|
16727
17511
|
recordBaseline(scope, path, imgVersion);
|
|
16728
17512
|
clearReadVersion(scope, path);
|
|
16729
|
-
setImageSrc(dataUrlOf(
|
|
17513
|
+
setImageSrc(dataUrlOf(out.content, out.mime));
|
|
16730
17514
|
setLoadStage({
|
|
16731
17515
|
progress: 100,
|
|
16732
17516
|
message: "图片已就绪"
|
|
@@ -16734,8 +17518,8 @@ window.__ModuleLoader__.load({
|
|
|
16734
17518
|
setStatus("已加载");
|
|
16735
17519
|
return;
|
|
16736
17520
|
}
|
|
16737
|
-
const base =
|
|
16738
|
-
const message =
|
|
17521
|
+
const base = out.error ? String(out.error) : "读取失败";
|
|
17522
|
+
const message = out.resolvedPath ? base + ":" + String(out.resolvedPath) : base;
|
|
16739
17523
|
setLoadError(message);
|
|
16740
17524
|
setError(message);
|
|
16741
17525
|
setStatus("读取失败");
|
|
@@ -16776,19 +17560,33 @@ window.__ModuleLoader__.load({
|
|
|
16776
17560
|
setStatus("已加载");
|
|
16777
17561
|
return;
|
|
16778
17562
|
}
|
|
16779
|
-
rpc
|
|
17563
|
+
readBinaryPreview(rpc, {
|
|
16780
17564
|
sessionId: sid,
|
|
16781
|
-
path
|
|
16782
|
-
|
|
16783
|
-
}).then((res) => {
|
|
17565
|
+
path
|
|
17566
|
+
}).then((out) => {
|
|
16784
17567
|
if (seq !== loadSeqRef.current || path !== active) return;
|
|
16785
|
-
if (
|
|
16786
|
-
const pdfVersion =
|
|
17568
|
+
if (out.ok && out.via === "binary") {
|
|
17569
|
+
const pdfVersion = out.version || version;
|
|
17570
|
+
recordBaseline(scope, path, pdfVersion);
|
|
17571
|
+
clearReadVersion(scope, path);
|
|
17572
|
+
cache.set(path, bytesToBase64(out.bytes));
|
|
17573
|
+
while (cache.size > 6) cache.delete(cache.keys().next().value);
|
|
17574
|
+
setPdfBytes(out.bytes);
|
|
17575
|
+
setLoadStage({
|
|
17576
|
+
progress: 100,
|
|
17577
|
+
message: "PDF 已就绪"
|
|
17578
|
+
});
|
|
17579
|
+
setStatus("已加载");
|
|
17580
|
+
return;
|
|
17581
|
+
}
|
|
17582
|
+
noteBinFallback(sid, out);
|
|
17583
|
+
if (out.ok && out.via === "base64") {
|
|
17584
|
+
const pdfVersion = out.version ?? version;
|
|
16787
17585
|
recordBaseline(scope, path, pdfVersion);
|
|
16788
17586
|
clearReadVersion(scope, path);
|
|
16789
|
-
cache.set(path,
|
|
17587
|
+
cache.set(path, out.content);
|
|
16790
17588
|
while (cache.size > 6) cache.delete(cache.keys().next().value);
|
|
16791
|
-
setPdfBytes(base64ToBytes(
|
|
17589
|
+
setPdfBytes(base64ToBytes(out.content));
|
|
16792
17590
|
setLoadStage({
|
|
16793
17591
|
progress: 100,
|
|
16794
17592
|
message: "PDF 已就绪"
|
|
@@ -16796,8 +17594,8 @@ window.__ModuleLoader__.load({
|
|
|
16796
17594
|
setStatus("已加载");
|
|
16797
17595
|
return;
|
|
16798
17596
|
}
|
|
16799
|
-
const base =
|
|
16800
|
-
const message =
|
|
17597
|
+
const base = out.error ? String(out.error) : "读取失败";
|
|
17598
|
+
const message = out.resolvedPath ? base + ":" + String(out.resolvedPath) : base;
|
|
16801
17599
|
setLoadError(message);
|
|
16802
17600
|
setError(message);
|
|
16803
17601
|
setStatus("读取失败");
|
|
@@ -17258,6 +18056,7 @@ window.__ModuleLoader__.load({
|
|
|
17258
18056
|
if (!event?.detail?.scope || event.detail.scope === scope) setSvnStatus(getSvnStatus(scope));
|
|
17259
18057
|
};
|
|
17260
18058
|
window.addEventListener("edrv:svn-status", onSvnStatus);
|
|
18059
|
+
setSvnStatus(getSvnStatus(scope));
|
|
17261
18060
|
return () => window.removeEventListener("edrv:svn-status", onSvnStatus);
|
|
17262
18061
|
}, [sessionId, scope]);
|
|
17263
18062
|
react.default.useEffect(() => {
|
|
@@ -17846,6 +18645,7 @@ window.__ModuleLoader__.load({
|
|
|
17846
18645
|
}
|
|
17847
18646
|
for (const ctl of pdfCtlRef.current.values()) ctl.destroy();
|
|
17848
18647
|
pdfCtlRef.current.clear();
|
|
18648
|
+
clearZoomMem();
|
|
17849
18649
|
const root = editorRef.current && editorRef.current.getDomNode ? editorRef.current.getDomNode() : null;
|
|
17850
18650
|
if (root) {
|
|
17851
18651
|
const ov = root.querySelector(".edrv-minus-overlay");
|
|
@@ -18372,11 +19172,50 @@ window.__ModuleLoader__.load({
|
|
|
18372
19172
|
setStatus(entering ? "已切换为 Markdown 预览" : "已切换为源码编辑");
|
|
18373
19173
|
};
|
|
18374
19174
|
toggleMdPreviewRef.current = toggleMdPreview;
|
|
19175
|
+
/** 当前图片的会话+路径级缩放记忆键(页签切换回来保留同一缩放)。 */
|
|
19176
|
+
const imgZoomKey = zoomKeyOf(sessionId, active);
|
|
19177
|
+
react.default.useEffect(() => {
|
|
19178
|
+
setImgZoom(recallZoom(imgZoomKey));
|
|
19179
|
+
}, [imgZoomKey]);
|
|
18375
19180
|
/**
|
|
18376
|
-
*
|
|
18377
|
-
* @author ddj 2026年09月
|
|
19181
|
+
* 应用图片缩放并写入页签记忆(null = 适应宽度;数值经 clampZoom 收敛 25%–400%)。
|
|
19182
|
+
* @author ddj 2026年09月22号
|
|
19183
|
+
* @param next 目标缩放(null = 适应宽度)
|
|
19184
|
+
*/
|
|
19185
|
+
const applyImgZoom = (next) => {
|
|
19186
|
+
const value = next === null ? null : clampZoom(next);
|
|
19187
|
+
setImgZoom(value);
|
|
19188
|
+
rememberZoom(imgZoomKey, value);
|
|
19189
|
+
};
|
|
19190
|
+
/**
|
|
19191
|
+
* 图片缩放步进(10%/档,clamp 25%–400%);适应宽度态先按渲染尺寸实测当前缩放作基准。
|
|
19192
|
+
* @author ddj 2026年09月22号
|
|
19193
|
+
* @param dir 方向:1 放大 / -1 缩小
|
|
19194
|
+
*/
|
|
19195
|
+
const stepImgZoom = (dir) => {
|
|
19196
|
+
const el = imgElRef.current;
|
|
19197
|
+
const measured = el && el.naturalWidth ? el.clientWidth / el.naturalWidth : 1;
|
|
19198
|
+
applyImgZoom(zoomStepOf(imgZoom ?? measured, dir));
|
|
19199
|
+
};
|
|
19200
|
+
/**
|
|
19201
|
+
* 图片预览面板:工具条(尺寸 meta / 缩放 −+适应宽度 / SVG 文本切换 / 刷新)+ 棋盘底图片。
|
|
19202
|
+
* 初始适应宽度(等价 PDF page-width,0.1.7 官方统一缩放);按钮样式与 PDF 工具条同款。
|
|
19203
|
+
* @author ddj 2026年09月08号 / 2026年09月22号
|
|
18378
19204
|
*/
|
|
18379
|
-
const imagePanel = () => react.default.createElement("div", { className: "edrv-imgview" }, react.default.createElement("div", { className: "edrv-imgview-bar" }, react.default.createElement("span", { className: "edrv-imgview-meta" }, imgBroken ? "图片无法显示" : imgSize ? imgSize.w + "×" + imgSize.h : "…"), react.default.createElement("span", { style: { flex: 1 } }),
|
|
19205
|
+
const imagePanel = () => react.default.createElement("div", { className: "edrv-imgview" }, react.default.createElement("div", { className: "edrv-imgview-bar" }, react.default.createElement("span", { className: "edrv-imgview-meta" }, imgBroken ? "图片无法显示" : imgSize ? imgSize.w + "×" + imgSize.h : "…"), react.default.createElement("span", { style: { flex: 1 } }), react.default.createElement("span", { className: "edrv-pdf-page" }, imgZoom === null ? "适应" : Math.round(imgZoom * 100) + "%"), react.default.createElement("button", {
|
|
19206
|
+
className: "edrv-pill edrv-pill-ghost edrv-pdf-zoom",
|
|
19207
|
+
title: "缩小(10%/档)",
|
|
19208
|
+
onClick: () => stepImgZoom(-1)
|
|
19209
|
+
}, "−"), react.default.createElement("button", {
|
|
19210
|
+
className: "edrv-pill edrv-pill-ghost edrv-pdf-zoom",
|
|
19211
|
+
title: "放大(10%/档)",
|
|
19212
|
+
onClick: () => stepImgZoom(1)
|
|
19213
|
+
}, "+"), react.default.createElement("button", {
|
|
19214
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
19215
|
+
title: "恢复适应宽度",
|
|
19216
|
+
disabled: imgZoom === null,
|
|
19217
|
+
onClick: () => applyImgZoom(null)
|
|
19218
|
+
}, "适应宽度"), isSvgPath(active) ? react.default.createElement("button", {
|
|
18380
19219
|
className: "edrv-pill edrv-pill-ghost",
|
|
18381
19220
|
title: "以文本方式查看/编辑(SVG 为文本格式)",
|
|
18382
19221
|
onClick: () => toggleSvgText(active)
|
|
@@ -18389,8 +19228,14 @@ window.__ModuleLoader__.load({
|
|
|
18389
19228
|
onClick: () => reloadFile()
|
|
18390
19229
|
}, "重试")) : react.default.createElement("img", {
|
|
18391
19230
|
className: "edrv-imgview-img",
|
|
19231
|
+
ref: imgElRef,
|
|
18392
19232
|
src: imageSrc,
|
|
18393
19233
|
alt: active || "",
|
|
19234
|
+
style: imgZoom !== null && imgSize ? {
|
|
19235
|
+
width: Math.round(imgSize.w * imgZoom) + "px",
|
|
19236
|
+
maxWidth: "none",
|
|
19237
|
+
maxHeight: "none"
|
|
19238
|
+
} : void 0,
|
|
18394
19239
|
onLoad: (e) => {
|
|
18395
19240
|
setImgBroken(false);
|
|
18396
19241
|
setImgSize({
|
|
@@ -19040,6 +19885,7 @@ window.__ModuleLoader__.load({
|
|
|
19040
19885
|
};
|
|
19041
19886
|
const openFile = (path, focusDiff) => {
|
|
19042
19887
|
if (!path) return;
|
|
19888
|
+
if (!focusDiff && inNativePath(path) && tryNativeOpen(path)) return;
|
|
19043
19889
|
setSvnDiff(null);
|
|
19044
19890
|
recordNav();
|
|
19045
19891
|
const normalized = addTabNorm(path, true);
|
|
@@ -20392,8 +21238,9 @@ window.__ModuleLoader__.load({
|
|
|
20392
21238
|
//#region src/client/settingsContext.ts
|
|
20393
21239
|
/**
|
|
20394
21240
|
* dsh-vscode-mode client — 设置 scope 的跨组件上下文。
|
|
20395
|
-
* 绑定逻辑(webUiSettings 兼容桥 → 官方 settingsScope
|
|
20396
|
-
*
|
|
21241
|
+
* 绑定逻辑(configForms 0.1.7+ → webUiSettings 兼容桥 → 官方 settingsScope 降级,
|
|
21242
|
+
* 带晚到有界重试)统一由 compat 层提供。
|
|
21243
|
+
* 作者 ddj 2026年08月24号 / 2026年09月22号
|
|
20397
21244
|
*/
|
|
20398
21245
|
const SettingsContext = react.default.createContext(void 0);
|
|
20399
21246
|
//#endregion
|
|
@@ -21102,7 +21949,7 @@ window.__ModuleLoader__.load({
|
|
|
21102
21949
|
//#region src/client/ui/PerfSettings.ts
|
|
21103
21950
|
/**
|
|
21104
21951
|
* dsh-vscode-mode client — PerfSettings:「性能优化」设置子页(会话卫生 + 压缩调优)。
|
|
21105
|
-
* -
|
|
21952
|
+
* - 会话盘点:全工作区/每会话体积、活跃标记、官方归档/置顶徽标,按体积排序;
|
|
21106
21953
|
* - 移出到归档(先规划→确认→执行→可恢复)与归档清除;
|
|
21107
21954
|
* - DSH 内置压缩调优:写 profile patch(compaction-basic / tool-result-pruner 更低阈值,
|
|
21108
21955
|
* 带备份与撤销,需重启生效);
|
|
@@ -21170,7 +22017,13 @@ window.__ModuleLoader__.load({
|
|
|
21170
22017
|
}, row.sessionId), react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-size " + (row.bytes >= 1048576 ? "big" : "") }, formatBytes(row.bytes)), react.default.createElement("span", {
|
|
21171
22018
|
className: "vsm-perf-cell vsm-perf-mtime",
|
|
21172
22019
|
title: new Date(row.mtime).toLocaleString()
|
|
21173
|
-
}, when), row.active ? react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-active" }, "活跃") : null
|
|
22020
|
+
}, when), row.active ? react.default.createElement("span", { className: "vsm-perf-cell vsm-perf-active" }, "活跃") : null, row.archived ? react.default.createElement("span", {
|
|
22021
|
+
className: "vsm-perf-cell vsm-perf-active",
|
|
22022
|
+
title: "官方侧栏已归档(持久标志位,未搬目录)"
|
|
22023
|
+
}, "已归档") : null, row.pinned ? react.default.createElement("span", {
|
|
22024
|
+
className: "vsm-perf-cell vsm-perf-active",
|
|
22025
|
+
title: "官方侧栏已置顶"
|
|
22026
|
+
}, "已置顶") : null);
|
|
21174
22027
|
}
|
|
21175
22028
|
/**
|
|
21176
22029
|
* 工作区列表分页器:顶部文案 + 上一页/下一页交互。
|
|
@@ -21914,6 +22767,8 @@ window.__ModuleLoader__.load({
|
|
|
21914
22767
|
const [minDraft, setMinDraft] = react.default.useState(null);
|
|
21915
22768
|
const [limit, setLimit] = react.default.useState(10);
|
|
21916
22769
|
const [limitDraft, setLimitDraft] = react.default.useState(null);
|
|
22770
|
+
const [nativeSaved, setNativeSaved] = react.default.useState(DEFAULT_NATIVE_CSV);
|
|
22771
|
+
const [nativeDraft, setNativeDraft] = react.default.useState(null);
|
|
21917
22772
|
const settings = react.default.useContext(SettingsContext);
|
|
21918
22773
|
const snapshot = settings?.getSnapshot?.();
|
|
21919
22774
|
const loading = !snapshot || snapshot.status === "loading";
|
|
@@ -21926,6 +22781,8 @@ window.__ModuleLoader__.load({
|
|
|
21926
22781
|
if (typeof next === "string") setTool(next);
|
|
21927
22782
|
setMinW(normalizeSidebarMinWidth(snap?.value?.sidebarMinWidth));
|
|
21928
22783
|
setLimit(normalizeMaxOpenEditors(snap?.value?.maxOpenEditors));
|
|
22784
|
+
const native = snap?.value?.nativeOpenExts;
|
|
22785
|
+
setNativeSaved(typeof native === "string" && native.trim() ? native : DEFAULT_NATIVE_CSV);
|
|
21929
22786
|
};
|
|
21930
22787
|
onChange();
|
|
21931
22788
|
return settings?.subscribe?.(onChange);
|
|
@@ -21984,6 +22841,25 @@ window.__ModuleLoader__.load({
|
|
|
21984
22841
|
setLimitDraft(null);
|
|
21985
22842
|
saveLimit(limitDraft);
|
|
21986
22843
|
};
|
|
22844
|
+
/** 提交原生打开范围(逗号分隔后缀;空串回落默认让位清单后持久化)。 */
|
|
22845
|
+
const saveNative = (raw) => {
|
|
22846
|
+
const next = String(raw ?? "").trim() || DEFAULT_NATIVE_CSV;
|
|
22847
|
+
setNativeSaved(next);
|
|
22848
|
+
setNativeDraft(null);
|
|
22849
|
+
setBusy(true);
|
|
22850
|
+
setError("");
|
|
22851
|
+
if (!settings?.set) {
|
|
22852
|
+
setError("设置服务不可用");
|
|
22853
|
+
setBusy(false);
|
|
22854
|
+
return;
|
|
22855
|
+
}
|
|
22856
|
+
settings.set("nativeOpenExts", next).catch((e) => setError(String(e))).finally(() => setBusy(false));
|
|
22857
|
+
};
|
|
22858
|
+
/** 结束输入(blur/Enter)时提交原生打开范围草稿。 */
|
|
22859
|
+
const commitNative = () => {
|
|
22860
|
+
if (nativeDraft === null) return;
|
|
22861
|
+
saveNative(nativeDraft);
|
|
22862
|
+
};
|
|
21987
22863
|
const closeDevForm = () => {
|
|
21988
22864
|
if (!window.confirm("关闭开发形态:插件将切换为正式版安装(版本依赖 + 删除工作区链接),pnpm 装配后需重启 DSH 生效。确认关闭?")) return;
|
|
21989
22865
|
setDevBusy(true);
|
|
@@ -22045,7 +22921,18 @@ window.__ModuleLoader__.load({
|
|
|
22045
22921
|
onKeyDown: (event) => {
|
|
22046
22922
|
if (event.key === "Enter") commitLimit();
|
|
22047
22923
|
}
|
|
22048
|
-
}), react.default.createElement("small", null, "0 = 不限制;超限时关闭最久未使用的页签(固定页签除外)"))
|
|
22924
|
+
}), react.default.createElement("small", null, "0 = 不限制;超限时关闭最久未使用的页签(固定页签除外)")), react.default.createElement("label", { className: "vsm-general-row" }, react.default.createElement("span", null, "原生打开范围"), react.default.createElement("input", {
|
|
22925
|
+
type: "text",
|
|
22926
|
+
value: nativeDraft ?? nativeSaved,
|
|
22927
|
+
disabled: loading || unavailable || notReady || busy || snapshot?.writable === false,
|
|
22928
|
+
title: "逗号分隔后缀(如 doc,xlsx):文件树点击命中时用 DSH 官方预览原生打开;留空 = 默认让位清单(Office + 不可预览二进制)",
|
|
22929
|
+
placeholder: "doc,xlsx,…(留空恢复默认)",
|
|
22930
|
+
onChange: (event) => setNativeDraft(event.target.value),
|
|
22931
|
+
onBlur: commitNative,
|
|
22932
|
+
onKeyDown: (event) => {
|
|
22933
|
+
if (event.key === "Enter") commitNative();
|
|
22934
|
+
}
|
|
22935
|
+
}), react.default.createElement("small", null, "逗号分隔;命中的文件用 DSH 原生预览打开,留空恢复默认(Office + 二进制,csv/tsv 需显式加入)")))), react.default.createElement(SvnSettingsSection, null), react.default.createElement(IntegrationSettings, null));
|
|
22049
22936
|
}
|
|
22050
22937
|
/** 检测快照 → 一行状态文案(未检测/未检出/能力可用性)。 */
|
|
22051
22938
|
function svnStatusText(info) {
|
|
@@ -23294,6 +24181,74 @@ window.__ModuleLoader__.load({
|
|
|
23294
24181
|
};
|
|
23295
24182
|
}
|
|
23296
24183
|
//#endregion
|
|
24184
|
+
//#region src/client/ui/icons.ts
|
|
24185
|
+
/**
|
|
24186
|
+
* dsh-vscode-mode client — UI 原语图标跨版本出口(消费方导出名保持 ≤0.1.6 旧名)。
|
|
24187
|
+
* 背景:DSH 0.1.7 图标命名重构——`Icon<Name>16`(0.1.6 及更旧)→
|
|
24188
|
+
* `Icon<Name>Regular/Medium`(0.1.7+,size 参数化 + 双笔画档),旧名在 0.1.7
|
|
24189
|
+
* 全树已不存在(整树 grep 实证)。解析策略:namespace import 属性探测,旧名优先
|
|
24190
|
+
* (现网 0.1.6)→ 新名次之(0.1.7+)→ 皆缺走通用占位(第三态不炸渲染);
|
|
24191
|
+
* 打包期 external 不校验成员存在性,两代运行时均稳(能力探测,不做版本判定)。
|
|
24192
|
+
* 调用点零语义变化:导出名与旧垫片一致,仅改 import 来源。
|
|
24193
|
+
* @author ddj 2026年09月22号
|
|
24194
|
+
*/
|
|
24195
|
+
/**
|
|
24196
|
+
* 通用占位图标(两代皆缺的第三态兜底:空态方框,不抛错不白屏)。
|
|
24197
|
+
* @author ddj 2026年09月22号
|
|
24198
|
+
* @param props 图标 props(size/className 透传)
|
|
24199
|
+
* @returns React 元素
|
|
24200
|
+
*/
|
|
24201
|
+
function fallbackIcon(props) {
|
|
24202
|
+
return react.default.createElement("svg", {
|
|
24203
|
+
width: props.size ?? 16,
|
|
24204
|
+
height: props.size ?? 16,
|
|
24205
|
+
viewBox: "0 0 16 16",
|
|
24206
|
+
className: props.className,
|
|
24207
|
+
"aria-hidden": true,
|
|
24208
|
+
focusable: false
|
|
24209
|
+
}, react.default.createElement("rect", {
|
|
24210
|
+
x: 3.5,
|
|
24211
|
+
y: 3.5,
|
|
24212
|
+
width: 9,
|
|
24213
|
+
height: 9,
|
|
24214
|
+
rx: 2,
|
|
24215
|
+
fill: "none",
|
|
24216
|
+
stroke: "currentColor",
|
|
24217
|
+
strokeWidth: 1.2,
|
|
24218
|
+
opacity: .45
|
|
24219
|
+
}));
|
|
24220
|
+
}
|
|
24221
|
+
/**
|
|
24222
|
+
* 按候选名序列解析图标组件(首个存在的函数命中;皆缺返回占位)。
|
|
24223
|
+
* @author ddj 2026年09月22号
|
|
24224
|
+
* @param names 候选导出名(旧名在前、新名在后)
|
|
24225
|
+
* @returns 图标组件
|
|
24226
|
+
*/
|
|
24227
|
+
function iconOf(...names) {
|
|
24228
|
+
const table = _deepseek_ai_dsh_client_ui_primitives;
|
|
24229
|
+
for (const name of names) {
|
|
24230
|
+
const hit = table[name];
|
|
24231
|
+
if (typeof hit === "function") return hit;
|
|
24232
|
+
}
|
|
24233
|
+
return fallbackIcon;
|
|
24234
|
+
}
|
|
24235
|
+
/** 目录闭合图标(官方文件树同款)。 */
|
|
24236
|
+
const IconFolderClose16 = iconOf("IconFolderClose16", "IconFolderCloseRegular");
|
|
24237
|
+
/** 目录展开图标(官方文件树同款)。 */
|
|
24238
|
+
const IconFolderOpen16 = iconOf("IconFolderOpen16", "IconFolderOpenRegular");
|
|
24239
|
+
/** 目录轮廓图标(活动栏「文件管理」)。 */
|
|
24240
|
+
const IconFolderOpenOutline16 = iconOf("IconFolderOpenOutline16", "IconFolderOpenOutlineRegular");
|
|
24241
|
+
/** 刷新图标(面板工具条)。 */
|
|
24242
|
+
const IconRefreshOutline16 = iconOf("IconRefreshOutline16", "IconRefreshOutlineRegular");
|
|
24243
|
+
/** 搜索图标(活动栏「搜索」)。 */
|
|
24244
|
+
const IconSearchOutline16 = iconOf("IconSearchOutline16", "IconSearchOutlineRegular");
|
|
24245
|
+
/** 列表+笔图标(活动栏「规则」)。 */
|
|
24246
|
+
const IconListPenOutline16 = iconOf("IconListPenOutline16", "IconListPenOutlineRegular");
|
|
24247
|
+
/** 代码图标(活动栏「大纲」)。 */
|
|
24248
|
+
const IconCodeOutline16 = iconOf("IconCodeOutline16", "IconCodeOutlineRegular");
|
|
24249
|
+
/** 分支图标(SVN 面板)。 */
|
|
24250
|
+
const IconBranchOutline16 = iconOf("IconBranchOutline16", "IconBranchOutlineRegular");
|
|
24251
|
+
//#endregion
|
|
23297
24252
|
//#region src/client/sidebar/contextMenu.ts
|
|
23298
24253
|
/** 校验菜单项并写入注册表(缺 id/run/label 抛 TypeError)。 */
|
|
23299
24254
|
function itemRegister(entries, notify, item) {
|
|
@@ -23671,7 +24626,7 @@ window.__ModuleLoader__.load({
|
|
|
23671
24626
|
* @returns 图标元素;原语缺失返回 null
|
|
23672
24627
|
*/
|
|
23673
24628
|
function dirIconEl(isOpen) {
|
|
23674
|
-
const Icon = isOpen ?
|
|
24629
|
+
const Icon = isOpen ? IconFolderOpen16 : IconFolderClose16;
|
|
23675
24630
|
if (typeof Icon !== "function") return null;
|
|
23676
24631
|
return react.default.createElement(Icon, {
|
|
23677
24632
|
size: 16,
|
|
@@ -23713,8 +24668,8 @@ window.__ModuleLoader__.load({
|
|
|
23713
24668
|
* @returns 图标元素或回落文本
|
|
23714
24669
|
*/
|
|
23715
24670
|
function refreshIconEl$1() {
|
|
23716
|
-
if (typeof
|
|
23717
|
-
return react.default.createElement(
|
|
24671
|
+
if (typeof IconRefreshOutline16 !== "function") return "⟳";
|
|
24672
|
+
return react.default.createElement(IconRefreshOutline16, { size: 14 });
|
|
23718
24673
|
}
|
|
23719
24674
|
/**
|
|
23720
24675
|
* 转义 CSS 属性选择器的值(路径含引号/反斜杠时避免选择器语法错误)。
|
|
@@ -25271,8 +26226,8 @@ window.__ModuleLoader__.load({
|
|
|
25271
26226
|
* @returns 图标元素或回落文本
|
|
25272
26227
|
*/
|
|
25273
26228
|
function refreshIconEl() {
|
|
25274
|
-
if (typeof
|
|
25275
|
-
return react.default.createElement(
|
|
26229
|
+
if (typeof IconRefreshOutline16 !== "function") return "⟳";
|
|
26230
|
+
return react.default.createElement(IconRefreshOutline16, { size: 14 });
|
|
25276
26231
|
}
|
|
25277
26232
|
/**
|
|
25278
26233
|
* 条目状态字母元素(按 tone 着色)。
|
|
@@ -26484,7 +27439,7 @@ window.__ModuleLoader__.load({
|
|
|
26484
27439
|
return {
|
|
26485
27440
|
id: "explorer",
|
|
26486
27441
|
title: "文件管理",
|
|
26487
|
-
icon:
|
|
27442
|
+
icon: IconFolderOpenOutline16,
|
|
26488
27443
|
order: 10,
|
|
26489
27444
|
badge: (ctx) => ctx.sum && ctx.sum.totalFiles > 0 ? ctx.sum.totalFiles : null,
|
|
26490
27445
|
render: (ctx) => react.default.createElement(FileExplorer, { ctx })
|
|
@@ -26499,7 +27454,7 @@ window.__ModuleLoader__.load({
|
|
|
26499
27454
|
return {
|
|
26500
27455
|
id: "search",
|
|
26501
27456
|
title: "搜索",
|
|
26502
|
-
icon:
|
|
27457
|
+
icon: IconSearchOutline16,
|
|
26503
27458
|
order: 15,
|
|
26504
27459
|
render: (ctx) => react.default.createElement(SearchPanel, { ctx })
|
|
26505
27460
|
};
|
|
@@ -26513,7 +27468,7 @@ window.__ModuleLoader__.load({
|
|
|
26513
27468
|
return {
|
|
26514
27469
|
id: "rules",
|
|
26515
27470
|
title: "规则",
|
|
26516
|
-
icon:
|
|
27471
|
+
icon: IconListPenOutline16,
|
|
26517
27472
|
order: 20,
|
|
26518
27473
|
render: (ctx) => react.default.createElement(RulesPanel, { ctx })
|
|
26519
27474
|
};
|
|
@@ -26529,7 +27484,7 @@ window.__ModuleLoader__.load({
|
|
|
26529
27484
|
return {
|
|
26530
27485
|
id: "svn",
|
|
26531
27486
|
title: "SVN 变更",
|
|
26532
|
-
icon: typeof
|
|
27487
|
+
icon: typeof IconBranchOutline16 === "function" ? IconBranchOutline16 : "⎇",
|
|
26533
27488
|
order: 25,
|
|
26534
27489
|
visible: (ctx) => Boolean(ctx?.svn?.managed && ctx?.svn?.svnCli),
|
|
26535
27490
|
badge: (ctx) => {
|
|
@@ -27873,7 +28828,7 @@ window.__ModuleLoader__.load({
|
|
|
27873
28828
|
return {
|
|
27874
28829
|
id: "outline",
|
|
27875
28830
|
title: "大纲",
|
|
27876
|
-
icon:
|
|
28831
|
+
icon: IconCodeOutline16,
|
|
27877
28832
|
order: 20,
|
|
27878
28833
|
render: (ctx) => react.default.createElement(OutlinePanel, { ctx })
|
|
27879
28834
|
};
|
|
@@ -28130,8 +29085,7 @@ window.__ModuleLoader__.load({
|
|
|
28130
29085
|
"remote",
|
|
28131
29086
|
"workspaces",
|
|
28132
29087
|
"sessions",
|
|
28133
|
-
"conversation"
|
|
28134
|
-
"settingsScope"
|
|
29088
|
+
"conversation"
|
|
28135
29089
|
];
|
|
28136
29090
|
/** 指令桥装配幂等标记(同一 document 重复 apply 只装配一次,避免重复键位监听)。 */
|
|
28137
29091
|
let commandsMounted = false;
|
|
@@ -28201,8 +29155,11 @@ window.__ModuleLoader__.load({
|
|
|
28201
29155
|
return subscribeScope(ctx, () => schedule(check, 0));
|
|
28202
29156
|
}, "vscode-mode: editor tab restore");
|
|
28203
29157
|
const originalOpenPath = workspaces?.openPath;
|
|
28204
|
-
const
|
|
28205
|
-
|
|
29158
|
+
const bridge = settingsBridge(ctx, {
|
|
29159
|
+
schedule,
|
|
29160
|
+
attempts: 15,
|
|
29161
|
+
intervalMs: 2e3
|
|
29162
|
+
});
|
|
28206
29163
|
let selected = autoValue("auto");
|
|
28207
29164
|
/** 0.1.3+ 会话文件链接路由(remote.session.openWorkspacePath)是否已安装(compatSummary 展示用)。 */
|
|
28208
29165
|
let remoteOpenInstalled = false;
|
|
@@ -28222,8 +29179,8 @@ window.__ModuleLoader__.load({
|
|
|
28222
29179
|
const compatSummary = () => [
|
|
28223
29180
|
{
|
|
28224
29181
|
name: "设置桥",
|
|
28225
|
-
active:
|
|
28226
|
-
note:
|
|
29182
|
+
active: bridge.scope() !== void 0,
|
|
29183
|
+
note: bridge.scope() !== void 0 ? "使用 " + bridge.service() + " 桥" : "未绑定设置服务(fileOpenTool 持久化不可用,晚到重试窗口内自愈)"
|
|
28227
29184
|
},
|
|
28228
29185
|
{
|
|
28229
29186
|
name: "文件打开路由(workspaces.openPath)",
|
|
@@ -28316,32 +29273,40 @@ window.__ModuleLoader__.load({
|
|
|
28316
29273
|
claimDisposer = null;
|
|
28317
29274
|
}
|
|
28318
29275
|
};
|
|
28319
|
-
|
|
28320
|
-
|
|
28321
|
-
|
|
28322
|
-
|
|
28323
|
-
|
|
28324
|
-
|
|
28325
|
-
|
|
28326
|
-
|
|
28327
|
-
|
|
28328
|
-
|
|
28329
|
-
|
|
28330
|
-
|
|
28331
|
-
|
|
28332
|
-
|
|
28333
|
-
|
|
28334
|
-
|
|
28335
|
-
|
|
28336
|
-
|
|
28337
|
-
const
|
|
28338
|
-
|
|
28339
|
-
|
|
28340
|
-
|
|
28341
|
-
|
|
28342
|
-
|
|
28343
|
-
|
|
28344
|
-
|
|
29276
|
+
let settingsSyncMounted = false;
|
|
29277
|
+
const mountSettingsSyncs = () => {
|
|
29278
|
+
if (settingsSyncMounted) return;
|
|
29279
|
+
const scope = bridge.scope();
|
|
29280
|
+
if (!scope) return;
|
|
29281
|
+
settingsSyncMounted = true;
|
|
29282
|
+
ctx.effect(() => {
|
|
29283
|
+
const sync = () => {
|
|
29284
|
+
const snapshot = scope.getSnapshot();
|
|
29285
|
+
if (snapshot.status === "loading") return;
|
|
29286
|
+
selected = autoValue(snapshot.value?.fileOpenTool);
|
|
29287
|
+
syncFileClaim();
|
|
29288
|
+
window.dispatchEvent(new CustomEvent("edrv:file-open-tool-change", { detail: { value: selected } }));
|
|
29289
|
+
};
|
|
29290
|
+
sync();
|
|
29291
|
+
return scope.subscribe(sync);
|
|
29292
|
+
}, "vscode-mode: file opener setting sync");
|
|
29293
|
+
ctx.effect(() => {
|
|
29294
|
+
const sync = () => {
|
|
29295
|
+
const snapshot = scope.getSnapshot();
|
|
29296
|
+
if (snapshot.status === "loading") return;
|
|
29297
|
+
keybindingsApply(snapshot.value?.keybindings);
|
|
29298
|
+
const minW = sidebarMinApply(snapshot.value?.sidebarMinWidth);
|
|
29299
|
+
window.dispatchEvent(new CustomEvent("edrv:sidebar-min-width", { detail: { value: minW } }));
|
|
29300
|
+
const limit = editorLimitApply(snapshot.value?.maxOpenEditors);
|
|
29301
|
+
window.dispatchEvent(new CustomEvent("edrv:max-open-editors", { detail: { value: limit } }));
|
|
29302
|
+
setNativeCsv(snapshot.value?.nativeOpenExts);
|
|
29303
|
+
};
|
|
29304
|
+
sync();
|
|
29305
|
+
return scope.subscribe(sync);
|
|
29306
|
+
}, "vscode-mode: keybindings setting sync");
|
|
29307
|
+
};
|
|
29308
|
+
mountSettingsSyncs();
|
|
29309
|
+
if (!settingsSyncMounted) ctx.effect(() => bridge.whenReady(mountSettingsSyncs), "vscode-mode: settings bridge wait");
|
|
28345
29310
|
if (workspaces?.openPath) ctx.effect(() => installOpenPathRouter({
|
|
28346
29311
|
workspaces,
|
|
28347
29312
|
registry,
|
|
@@ -28440,7 +29405,18 @@ window.__ModuleLoader__.load({
|
|
|
28440
29405
|
return;
|
|
28441
29406
|
}
|
|
28442
29407
|
officialDisposer = ctx.effect(() => outcome, "vscode-mode: official sidebar editor tab");
|
|
28443
|
-
if (typeof official.service.openResource === "function")
|
|
29408
|
+
if (typeof official.service.openResource === "function") {
|
|
29409
|
+
ctx.effect(() => registry.register(officialSidebarOpener(official.service)), "vscode-mode: official sidebar opener");
|
|
29410
|
+
ctx.effect(() => {
|
|
29411
|
+
setNativeOpenHandler((path) => {
|
|
29412
|
+
const scope = readSessionScope(ctx);
|
|
29413
|
+
if (!scope.sessionId) return false;
|
|
29414
|
+
official.service.openResource?.(buildFileAddress(path, scope.sessionId));
|
|
29415
|
+
return typeof official.service.openResource === "function";
|
|
29416
|
+
});
|
|
29417
|
+
return () => setNativeOpenHandler(null);
|
|
29418
|
+
}, "vscode-mode: native open handler");
|
|
29419
|
+
}
|
|
28444
29420
|
syncFileClaim();
|
|
28445
29421
|
};
|
|
28446
29422
|
const applySideForm = () => {
|
|
@@ -28541,7 +29517,7 @@ window.__ModuleLoader__.load({
|
|
|
28541
29517
|
id: "vscode-mode",
|
|
28542
29518
|
order: 30,
|
|
28543
29519
|
label: "VSCodeMode"
|
|
28544
|
-
}, () => react.default.createElement(SettingsContext.Provider, { value:
|
|
29520
|
+
}, () => react.default.createElement(SettingsContext.Provider, { value: bridge.scope() }, react.default.createElement(McpSettings, {
|
|
28545
29521
|
openerRegistry: registry,
|
|
28546
29522
|
compatSummary
|
|
28547
29523
|
})));
|
|
@@ -28558,6 +29534,9 @@ window.__ModuleLoader__.load({
|
|
|
28558
29534
|
try {
|
|
28559
29535
|
disposeLsp();
|
|
28560
29536
|
} catch {}
|
|
29537
|
+
try {
|
|
29538
|
+
resetNativeOpen();
|
|
29539
|
+
} catch {}
|
|
28561
29540
|
}, "vscode-mode: monaco providers teardown");
|
|
28562
29541
|
}
|
|
28563
29542
|
//#endregion
|