dsh-vscode-mode 0.1.63 → 0.2.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 +8 -0
- package/lib/client.js +919 -43
- package/lib/client.js.map +1 -1
- package/lib/index.js +7 -2
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/client/commandBridge.ts +83 -0
- package/src/client/commandGlobals.ts +13 -0
- package/src/client/commandPaletteStore.ts +165 -0
- package/src/client/commandRegistry.ts +144 -0
- package/src/client/commandSearch.ts +89 -0
- package/src/client/editorModelState.ts +30 -0
- package/src/client/index.ts +32 -0
- package/src/client/keybindings.ts +71 -17
- package/src/client/styles/editor.css +14 -0
- package/src/client/ui/CommandPalette.ts +158 -0
- package/src/client/ui/ConversationDiffDock.ts +17 -9
- package/src/client/ui/EditorView.ts +90 -3
- package/src/client/ui/KeybindingsPanel.ts +1 -1
- package/src/client/ui/QuickOpen.ts +11 -3
- package/src/client/ui/commandCatalog.ts +179 -0
- package/src/shared/keybindings.ts +7 -1
package/lib/client.js
CHANGED
|
@@ -28,11 +28,11 @@ window.__ModuleLoader__.load({
|
|
|
28
28
|
//#endregion
|
|
29
29
|
let react = require("react");
|
|
30
30
|
react = __toESM(react, 1);
|
|
31
|
+
let react_dom = require("react-dom");
|
|
31
32
|
let react_dom_client = require("react-dom/client");
|
|
32
33
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
33
|
-
let react_dom = require("react-dom");
|
|
34
34
|
//#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; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-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[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: 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[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[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[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: 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[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/* ===== 侧栏形态(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\n\n";
|
|
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; scrollbar-width: thin; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab { display: inline-flex; align-items: center; gap: 6px; height: 28px; padding: 0 8px 0 12px; border: none; border-radius: 6px 6px 0 0; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 12px; cursor: pointer; white-space: nowrap; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-tab.edrv-tab-active { background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); box-shadow: inset 0 -2px 0 var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-tab .edrv-tab-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[data-edrv-view] .edrv-tab-add { display: inline-flex; align-items: center; justify-content: center; width: 24px; height: 24px; margin-left: 2px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-secondary, #aaa); font-size: 14px; cursor: pointer; flex-shrink: 0; }\n[data-edrv-view] .edrv-tab-add:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.06)); }\n[data-edrv-view] .edrv-pathbar { display: flex; align-items: center; gap: 8px; height: 26px; padding: 0 10px; background: var(--dsw-alias-bg-layer-1, #ffffff); border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 12px; flex-shrink: 0; overflow: hidden; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-name { font-weight: 600; color: var(--dsw-alias-label-primary, #1f2933); white-space: nowrap; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-full { flex: 1; min-width: 0; color: var(--dsw-alias-label-tertiary, #9aa5b1); white-space: nowrap; overflow: hidden; text-overflow: ellipsis; direction: rtl; text-align: left; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-meta { flex-shrink: 0; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-variant-numeric: tabular-nums; }\n[data-edrv-view] .edrv-pathbar .edrv-pb-status { color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-path-input { flex: 1; min-width: 140px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search-wrap { position: relative; flex-shrink: 0; display: flex; align-items: center; padding: 2px 8px 2px 4px; }\n[data-edrv-view] .edrv-search { width: 190px; height: 24px; padding: 0 8px; border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 6px; background: var(--dsw-alias-bg-base, #111); color: var(--dsw-alias-label-primary, #eee); font-size: 12px; outline: none; }\n[data-edrv-view] .edrv-search:focus { border-color: var(--dsw-alias-brand-primary, #4f8cff); }\n[data-edrv-view] .edrv-search-pop { position: absolute; top: calc(100% + 4px); right: 8px; width: min(460px, calc(100vw - 24px)); max-height: 300px; overflow: auto; background: var(--dsw-alias-bg-overlay, #1c1c1c); border: 1px solid var(--dsw-alias-border-l2, #555); border-radius: 10px; box-shadow: 0 6px 20px rgba(0,0,0,.4); z-index: 60; padding: 4px; }\n[data-edrv-view] .edrv-search-item { display: flex; flex-direction: column; gap: 1px; padding: 5px 8px; border-radius: 6px; cursor: pointer; }\n[data-edrv-view] .edrv-search-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255,255,255,.07)); }\n[data-edrv-view] .edrv-search-item .n { color: var(--dsw-alias-label-primary, #eee); font-size: 12px; word-break: break-all; }\n[data-edrv-view] .edrv-search-item .d { color: var(--dsw-alias-label-tertiary, #888); font-size: 11px; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-search-empty { padding: 8px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #888); }\n[data-edrv-view] .edrv-btn-mini { font-size: 11px; padding: 2px 9px; border: none; border-radius: 999px; cursor: pointer; color: 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[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[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[data-edrv-view] .edrv-ctxmenu { position: fixed; z-index: 71; min-width: 200px; max-width: 320px; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 8px 26px rgba(31,41,51,.2); padding: 4px; display: flex; flex-direction: column; gap: 1px; }\n[data-edrv-view] .edrv-ctxmenu-item { display: flex; align-items: center; gap: 8px; font-size: 12px; line-height: 18px; padding: 7px 10px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; text-align: left; white-space: nowrap; overflow: hidden; text-overflow: ellipsis; }\n[data-edrv-view] .edrv-ctxmenu-item:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-danger { color: var(--dsw-alias-state-error-primary, #d9534f); }\n[data-edrv-view] .edrv-ctxmenu-item:disabled,\n[data-edrv-view] .edrv-ctxmenu-item.edrv-ctxmenu-disabled { color: var(--dsw-alias-label-disabled, #b0b7c0); cursor: default; background: transparent; }\n[data-edrv-view] .edrv-ctxmenu-sep { height: 1px; margin: 3px 4px; background: var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffbar-body { max-height: 130px; max-width: min(560px, calc(100vw - 40px)); overflow: auto; padding: 4px 8px 8px; display: flex; flex-direction: column; gap: 4px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); }\n[data-edrv-view] .edrv-diffrow { display: flex; align-items: center; gap: 8px; padding: 3px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 6px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); cursor: pointer; flex-wrap: wrap; }\n[data-edrv-view] .edrv-diffrow:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(15,157,88,.08)); }\n[data-edrv-view] .edrv-diffrow-l { font-size: 11px; color: var(--dsw-alias-label-primary, #1f2933); min-width: 74px; font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-o { font-size: 11px; color: var(--dsw-alias-state-error-primary, #d9534f); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-n { font-size: 11px; color: var(--dsw-alias-state-success-primary, #0f9d58); font-family: var(--ds-font-family-code, ui-monospace, monospace); }\n[data-edrv-view] .edrv-diffrow-tag { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-diffrow-stale { border-color: 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[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/* ===== 侧栏形态(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[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: 191; 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\n\n";
|
|
36
36
|
const tagId$1 = "dsh-vscode-mode/editor.css";
|
|
37
37
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
38
38
|
const tag = document.createElement("style");
|
|
@@ -2487,7 +2487,9 @@ window.__ModuleLoader__.load({
|
|
|
2487
2487
|
* 纯数据模块:host(settings schema 默认值)与 client(执行匹配/设置页)共用。
|
|
2488
2488
|
* 键位格式:修饰符 + 主键,`+` 连接,如 `Ctrl+Shift+F`;空串 = 未绑定;
|
|
2489
2489
|
* `|` 连接多个候选(任一命中即触发),如 `Alt+ArrowLeft|Ctrl+Alt+-`。
|
|
2490
|
-
*
|
|
2490
|
+
* 约束:本模块被 host 与 client 两半共用,**禁止 import client 侧模块**(React/浏览器 API)。
|
|
2491
|
+
* 与 client/ui/commandCatalog 的一致性由 tests/commands.test.ts 断言兜底。
|
|
2492
|
+
* 作者 ddj 2026年08月26号 / 2026年09月10号
|
|
2491
2493
|
*/
|
|
2492
2494
|
/** 命令 id → 默认键位(可为多候选)。命令目录以此为准,新增命令只需加一项。 */
|
|
2493
2495
|
const KEYBINDING_DEFAULTS = {
|
|
@@ -2498,7 +2500,10 @@ window.__ModuleLoader__.load({
|
|
|
2498
2500
|
"edrv.navigateBack": "Alt+ArrowLeft|Ctrl+Alt+-",
|
|
2499
2501
|
"edrv.navigateForward": "Alt+ArrowRight|Ctrl+Shift+-",
|
|
2500
2502
|
"edrv.nextTab": "Ctrl+Alt+ArrowRight|Ctrl+PageDown",
|
|
2501
|
-
"edrv.prevTab": "Ctrl+Alt+ArrowLeft|Ctrl+PageUp"
|
|
2503
|
+
"edrv.prevTab": "Ctrl+Alt+ArrowLeft|Ctrl+PageUp",
|
|
2504
|
+
"edrv.showCommands": "Ctrl+Shift+P|F1",
|
|
2505
|
+
"edrv.nextEditorRow": "Ctrl+Alt+ArrowDown",
|
|
2506
|
+
"edrv.prevEditorRow": "Ctrl+Alt+ArrowUp"
|
|
2502
2507
|
};
|
|
2503
2508
|
/**
|
|
2504
2509
|
* 返回默认键位的独立副本(调用方修改不污染目录)。
|
|
@@ -2522,49 +2527,261 @@ window.__ModuleLoader__.load({
|
|
|
2522
2527
|
return out;
|
|
2523
2528
|
}
|
|
2524
2529
|
//#endregion
|
|
2525
|
-
//#region src/client/
|
|
2530
|
+
//#region src/client/editorModelState.ts
|
|
2526
2531
|
/**
|
|
2527
|
-
*
|
|
2528
|
-
*
|
|
2529
|
-
*
|
|
2530
|
-
* 键位语义:Ctrl 与 Cmd 互认(延续现有 Ctrl+P/Ctrl+B 捕获行为)。
|
|
2531
|
-
* 作者 ddj 2026年08月26号
|
|
2532
|
+
* 当前文档是否已有 Monaco 活动模型(编辑器打开着文件而非空态)。
|
|
2533
|
+
* @author ddj 2026年09月10号
|
|
2534
|
+
* @returns 是否存在活动模型
|
|
2532
2535
|
*/
|
|
2533
|
-
|
|
2534
|
-
|
|
2536
|
+
function hasEditorModel() {
|
|
2537
|
+
if (typeof document === "undefined") return false;
|
|
2538
|
+
return document.querySelector(".monaco-editor textarea.inputarea") !== null;
|
|
2539
|
+
}
|
|
2540
|
+
//#endregion
|
|
2541
|
+
//#region src/client/ui/commandCatalog.ts
|
|
2542
|
+
/**
|
|
2543
|
+
* dsh-vscode-mode client — 编辑器指令目录(纯元数据)。
|
|
2544
|
+
* 「一条命令 = 一条注册数据」:命令栏、快捷键设置页、快捷键监听与 Monaco 右键菜单
|
|
2545
|
+
* 全部从本表读取;新增一条能力只需在 EDITOR_COMMANDS 追加一项(可选 keybinding)。
|
|
2546
|
+
* run 只派发 `edrv.command.*` 窗口事件,不直接触碰 React/Monaco(`edrv.command.` 前缀
|
|
2547
|
+
* 与既有 `edrv:` 刷新/主题事件分属不同命名空间,互不干扰)。
|
|
2548
|
+
* 作者 ddj 2026年09月10号
|
|
2549
|
+
*/
|
|
2550
|
+
/**
|
|
2551
|
+
* 派发编辑器命令事件(`edrv.command.<action>`)。
|
|
2552
|
+
* 无 window 的运行环境(纯 Node 单测)静默跳过,命令本身不因此失败。
|
|
2553
|
+
* @author ddj 2026年09月10号
|
|
2554
|
+
* @param action 动作名(不含前缀)
|
|
2555
|
+
*/
|
|
2556
|
+
function emit(action) {
|
|
2557
|
+
if (typeof window === "undefined") return;
|
|
2558
|
+
window.dispatchEvent(new CustomEvent("edrv.command." + action));
|
|
2559
|
+
}
|
|
2560
|
+
/** 需要活动编辑器模型才可用的命令(命令栏隐藏并拒绝执行)。 */
|
|
2561
|
+
function needsModel() {
|
|
2562
|
+
return hasEditorModel();
|
|
2563
|
+
}
|
|
2564
|
+
/** 面板区显隐切换始终可用(未挂载编辑器时 run 为空操作)。 */
|
|
2565
|
+
function alwaysAvailable() {
|
|
2566
|
+
return true;
|
|
2567
|
+
}
|
|
2568
|
+
/**
|
|
2569
|
+
* 光标整行下移(编辑行导航)。
|
|
2570
|
+
* @author ddj 2026年09月10号
|
|
2571
|
+
* @returns 命令定义
|
|
2572
|
+
*/
|
|
2573
|
+
function nextEditorRowDef() {
|
|
2574
|
+
return {
|
|
2575
|
+
id: "edrv.nextEditorRow",
|
|
2576
|
+
label: "下一编辑行(光标整行下移)",
|
|
2577
|
+
category: "导航",
|
|
2578
|
+
order: 50,
|
|
2579
|
+
keybinding: "Ctrl+Alt+ArrowDown",
|
|
2580
|
+
available: needsModel,
|
|
2581
|
+
run: () => emit("nextEditorRow")
|
|
2582
|
+
};
|
|
2583
|
+
}
|
|
2584
|
+
/**
|
|
2585
|
+
* 光标整行上移(编辑行导航)。
|
|
2586
|
+
* @author ddj 2026年09月10号
|
|
2587
|
+
* @returns 命令定义
|
|
2588
|
+
*/
|
|
2589
|
+
function prevEditorRowDef() {
|
|
2590
|
+
return {
|
|
2591
|
+
id: "edrv.prevEditorRow",
|
|
2592
|
+
label: "上一编辑行(光标整行上移)",
|
|
2593
|
+
category: "导航",
|
|
2594
|
+
order: 60,
|
|
2595
|
+
keybinding: "Ctrl+Alt+ArrowUp",
|
|
2596
|
+
available: needsModel,
|
|
2597
|
+
run: () => emit("prevEditorRow")
|
|
2598
|
+
};
|
|
2599
|
+
}
|
|
2600
|
+
/**
|
|
2601
|
+
* 编辑器内置指令目录(顺序 = 快捷键设置页展示顺序)。
|
|
2602
|
+
* 前置 8 条的键位由 EditorView / QuickOpen 自行 capture 监听(历史实现),
|
|
2603
|
+
* 故不进 BRIDGE_COMMANDS,避免同一按键双执行。
|
|
2604
|
+
* @author ddj 2026年09月10号
|
|
2605
|
+
*/
|
|
2606
|
+
const EDITOR_COMMANDS = [
|
|
2535
2607
|
{
|
|
2536
2608
|
id: "edrv.save",
|
|
2537
|
-
label: "保存文件"
|
|
2609
|
+
label: "保存文件",
|
|
2610
|
+
category: "文件",
|
|
2611
|
+
order: 10,
|
|
2612
|
+
keybinding: "Ctrl+S",
|
|
2613
|
+
available: needsModel,
|
|
2614
|
+
run: () => emit("save")
|
|
2538
2615
|
},
|
|
2539
2616
|
{
|
|
2540
2617
|
id: "edrv.quickOpen",
|
|
2541
|
-
label: "快速打开文件"
|
|
2618
|
+
label: "快速打开文件",
|
|
2619
|
+
category: "文件",
|
|
2620
|
+
order: 20,
|
|
2621
|
+
keybinding: "Ctrl+P",
|
|
2622
|
+
available: alwaysAvailable,
|
|
2623
|
+
run: () => emit("quickOpen")
|
|
2542
2624
|
},
|
|
2543
2625
|
{
|
|
2544
2626
|
id: "edrv.toggleSidebar",
|
|
2545
|
-
label: "切换侧边栏"
|
|
2627
|
+
label: "切换侧边栏",
|
|
2628
|
+
category: "视图",
|
|
2629
|
+
order: 10,
|
|
2630
|
+
keybinding: "Ctrl+B",
|
|
2631
|
+
available: alwaysAvailable,
|
|
2632
|
+
run: () => emit("toggleSidebar")
|
|
2546
2633
|
},
|
|
2547
2634
|
{
|
|
2548
2635
|
id: "edrv.searchInFiles",
|
|
2549
|
-
label: "在工作区中搜索"
|
|
2636
|
+
label: "在工作区中搜索",
|
|
2637
|
+
category: "视图",
|
|
2638
|
+
order: 20,
|
|
2639
|
+
keybinding: "Ctrl+Shift+F",
|
|
2640
|
+
available: alwaysAvailable,
|
|
2641
|
+
run: () => emit("searchInFiles")
|
|
2550
2642
|
},
|
|
2551
2643
|
{
|
|
2552
2644
|
id: "edrv.navigateBack",
|
|
2553
|
-
label: "后退(导航历史)"
|
|
2645
|
+
label: "后退(导航历史)",
|
|
2646
|
+
category: "导航",
|
|
2647
|
+
order: 10,
|
|
2648
|
+
keybinding: "Alt+ArrowLeft|Ctrl+Alt+-",
|
|
2649
|
+
available: needsModel,
|
|
2650
|
+
run: () => emit("navigateBack")
|
|
2554
2651
|
},
|
|
2555
2652
|
{
|
|
2556
2653
|
id: "edrv.navigateForward",
|
|
2557
|
-
label: "前进(导航历史)"
|
|
2654
|
+
label: "前进(导航历史)",
|
|
2655
|
+
category: "导航",
|
|
2656
|
+
order: 20,
|
|
2657
|
+
keybinding: "Alt+ArrowRight|Ctrl+Shift+-",
|
|
2658
|
+
available: needsModel,
|
|
2659
|
+
run: () => emit("navigateForward")
|
|
2558
2660
|
},
|
|
2559
2661
|
{
|
|
2560
2662
|
id: "edrv.nextTab",
|
|
2561
|
-
label: "下一个页签"
|
|
2663
|
+
label: "下一个页签",
|
|
2664
|
+
category: "导航",
|
|
2665
|
+
order: 30,
|
|
2666
|
+
keybinding: "Ctrl+Alt+ArrowRight|Ctrl+PageDown",
|
|
2667
|
+
available: needsModel,
|
|
2668
|
+
run: () => emit("nextTab")
|
|
2562
2669
|
},
|
|
2563
2670
|
{
|
|
2564
2671
|
id: "edrv.prevTab",
|
|
2565
|
-
label: "上一个页签"
|
|
2672
|
+
label: "上一个页签",
|
|
2673
|
+
category: "导航",
|
|
2674
|
+
order: 40,
|
|
2675
|
+
keybinding: "Ctrl+Alt+ArrowLeft|Ctrl+PageUp",
|
|
2676
|
+
available: needsModel,
|
|
2677
|
+
run: () => emit("prevTab")
|
|
2678
|
+
},
|
|
2679
|
+
{
|
|
2680
|
+
id: "edrv.goToDefinition",
|
|
2681
|
+
label: "转到定义",
|
|
2682
|
+
category: "语言智能",
|
|
2683
|
+
order: 10,
|
|
2684
|
+
available: needsModel,
|
|
2685
|
+
run: () => emit("goToDefinition")
|
|
2686
|
+
},
|
|
2687
|
+
{
|
|
2688
|
+
id: "edrv.findReferences",
|
|
2689
|
+
label: "查找所有引用",
|
|
2690
|
+
category: "语言智能",
|
|
2691
|
+
order: 20,
|
|
2692
|
+
available: needsModel,
|
|
2693
|
+
run: () => emit("findReferences")
|
|
2694
|
+
},
|
|
2695
|
+
{
|
|
2696
|
+
id: "edrv.triggerAi",
|
|
2697
|
+
label: "触发 AI 内联补全",
|
|
2698
|
+
category: "语言智能",
|
|
2699
|
+
order: 30,
|
|
2700
|
+
available: needsModel,
|
|
2701
|
+
run: () => emit("triggerAi")
|
|
2702
|
+
},
|
|
2703
|
+
{
|
|
2704
|
+
id: "edrv.openInExplorer",
|
|
2705
|
+
label: "在文件浏览器中打开",
|
|
2706
|
+
category: "文件",
|
|
2707
|
+
order: 30,
|
|
2708
|
+
available: needsModel,
|
|
2709
|
+
run: () => emit("openInExplorer")
|
|
2566
2710
|
}
|
|
2567
2711
|
];
|
|
2712
|
+
/**
|
|
2713
|
+
* 桥接派发指令(无原生监听,键位由 commandBridge 统一 capture 处理)。
|
|
2714
|
+
* 新增「只填目录、不写监听」的编辑器指令一律放这里:键位、命令栏、设置页自动可用。
|
|
2715
|
+
* @author ddj 2026年09月10号
|
|
2716
|
+
*/
|
|
2717
|
+
const BRIDGE_COMMANDS = [nextEditorRowDef(), prevEditorRowDef()];
|
|
2718
|
+
/**
|
|
2719
|
+
* 命令栏自身的命令(避免循环依赖,由 commandBridge 注入 run 后注册)。
|
|
2720
|
+
* @author ddj 2026年09月10号
|
|
2721
|
+
* @param run 打开命令栏
|
|
2722
|
+
* @returns 命令定义
|
|
2723
|
+
*/
|
|
2724
|
+
function showCommandsDef(run) {
|
|
2725
|
+
return {
|
|
2726
|
+
id: "edrv.showCommands",
|
|
2727
|
+
label: "显示所有命令",
|
|
2728
|
+
category: "视图",
|
|
2729
|
+
order: 1,
|
|
2730
|
+
keybinding: "Ctrl+Shift+P|F1",
|
|
2731
|
+
available: alwaysAvailable,
|
|
2732
|
+
run
|
|
2733
|
+
};
|
|
2734
|
+
}
|
|
2735
|
+
/**
|
|
2736
|
+
* 需要全局键位派发的指令(桥接类 + 命令栏自身;不含 EditorView/QuickOpen 原生监听的那些)。
|
|
2737
|
+
* @author ddj 2026年09月10号
|
|
2738
|
+
* @param showCommands 命令栏命令定义
|
|
2739
|
+
* @returns 派发集合
|
|
2740
|
+
*/
|
|
2741
|
+
function dispatchedCommands(showCommands) {
|
|
2742
|
+
return [...BRIDGE_COMMANDS, showCommands];
|
|
2743
|
+
}
|
|
2744
|
+
//#endregion
|
|
2745
|
+
//#region src/client/keybindings.ts
|
|
2746
|
+
/**
|
|
2747
|
+
* dsh-vscode-mode client — 快捷键配置模块(解析/匹配/状态同步)。
|
|
2748
|
+
* 纯逻辑(parseChord/parseChords/formatChord/matchEvent/chordFromEvent/normalizeKey)不依赖 DOM,可单测;
|
|
2749
|
+
* 模块状态由 settings 订阅驱动(client/index.ts 调 keybindingsApply)。
|
|
2750
|
+
* 键位语义:Ctrl 与 Cmd 互认(延续 Ctrl+P/Ctrl+B 捕获行为)。
|
|
2751
|
+
* 命令目录(COMMANDS)派生自指令目录 commandCatalog(指令 = 单一数据源,设置页自动跟随);
|
|
2752
|
+
* 另支持运行时键位表(第三方命令 register 时声明,不落设置 schema,注销即失效)。
|
|
2753
|
+
* 作者 ddj 2026年08月26号 / 2026年09月10号
|
|
2754
|
+
*/
|
|
2755
|
+
/** 命令目录(设置页展示标签;执行按目录序先匹配先执行,冲突键位确定性)。 */
|
|
2756
|
+
const COMMANDS = [
|
|
2757
|
+
...EDITOR_COMMANDS.map((command) => ({
|
|
2758
|
+
id: command.id,
|
|
2759
|
+
label: command.label
|
|
2760
|
+
})),
|
|
2761
|
+
{
|
|
2762
|
+
id: "edrv.showCommands",
|
|
2763
|
+
label: "显示所有命令"
|
|
2764
|
+
},
|
|
2765
|
+
...BRIDGE_COMMANDS.map((command) => ({
|
|
2766
|
+
id: command.id,
|
|
2767
|
+
label: command.label
|
|
2768
|
+
}))
|
|
2769
|
+
];
|
|
2770
|
+
/** 命令栏命令定义(键位自检与目录展示共用;run 不参与键位逻辑)。 */
|
|
2771
|
+
function paletteCommand() {
|
|
2772
|
+
return showCommandsDef(() => {});
|
|
2773
|
+
}
|
|
2774
|
+
/**
|
|
2775
|
+
* 目录与默认键位表一致性自检(仅告警不中断):新指令漏写共享表时第一时间可见。
|
|
2776
|
+
* @author ddj 2026年09月10号
|
|
2777
|
+
*/
|
|
2778
|
+
function checkDefaultsDrift() {
|
|
2779
|
+
for (const command of [...EDITOR_COMMANDS, paletteCommand()]) {
|
|
2780
|
+
if (!command.keybinding) continue;
|
|
2781
|
+
if (KEYBINDING_DEFAULTS[command.id] === command.keybinding) continue;
|
|
2782
|
+
log.warn("指令默认键位与共享表不一致:" + command.id + " 目录=" + command.keybinding + " 共享表=" + String(KEYBINDING_DEFAULTS[command.id]));
|
|
2783
|
+
}
|
|
2784
|
+
}
|
|
2568
2785
|
const MODIFIERS = {
|
|
2569
2786
|
ctrl: "ctrl",
|
|
2570
2787
|
cmd: "meta",
|
|
@@ -2573,8 +2790,9 @@ window.__ModuleLoader__.load({
|
|
|
2573
2790
|
alt: "alt"
|
|
2574
2791
|
};
|
|
2575
2792
|
let current = { ...KEYBINDING_DEFAULTS };
|
|
2576
|
-
|
|
2577
|
-
const listeners$
|
|
2793
|
+
const runtime = /* @__PURE__ */ new Map();
|
|
2794
|
+
const listeners$2 = /* @__PURE__ */ new Set();
|
|
2795
|
+
checkDefaultsDrift();
|
|
2578
2796
|
/**
|
|
2579
2797
|
* 应用设置快照(与默认值合并;未知 id 丢弃;空对象 = 全部默认)。
|
|
2580
2798
|
* 每个命令可含多候选键位(`|` 分隔),任一命中即触发。
|
|
@@ -2586,9 +2804,7 @@ window.__ModuleLoader__.load({
|
|
|
2586
2804
|
...KEYBINDING_DEFAULTS,
|
|
2587
2805
|
...normalizeKeybindings(raw)
|
|
2588
2806
|
};
|
|
2589
|
-
|
|
2590
|
-
for (const id of Object.keys(current)) parsed[id] = parseChords(current[id]);
|
|
2591
|
-
for (const listener of listeners$1) try {
|
|
2807
|
+
for (const listener of listeners$2) try {
|
|
2592
2808
|
listener();
|
|
2593
2809
|
} catch {}
|
|
2594
2810
|
}
|
|
@@ -2599,27 +2815,34 @@ window.__ModuleLoader__.load({
|
|
|
2599
2815
|
* @returns 取消订阅函数
|
|
2600
2816
|
*/
|
|
2601
2817
|
function subscribeKeybindings(listener) {
|
|
2602
|
-
listeners$
|
|
2603
|
-
return () => listeners$
|
|
2818
|
+
listeners$2.add(listener);
|
|
2819
|
+
return () => listeners$2.delete(listener);
|
|
2604
2820
|
}
|
|
2605
2821
|
/**
|
|
2606
|
-
*
|
|
2607
|
-
* @author ddj 2026年08月26号
|
|
2822
|
+
* 当前命令的键位弦(运行时键位优先;未绑定/空 → null)。
|
|
2823
|
+
* @author ddj 2026年08月26号 / 2026年09月10号
|
|
2608
2824
|
* @param id 命令 id
|
|
2609
2825
|
* @returns 键位弦或 null
|
|
2610
2826
|
*/
|
|
2611
2827
|
function chordOf(id) {
|
|
2828
|
+
if (runtime.has(id)) {
|
|
2829
|
+
const chords = runtime.get(id) ?? [];
|
|
2830
|
+
return chords.length ? chords.map(formatChord).join("|") : null;
|
|
2831
|
+
}
|
|
2612
2832
|
const chord = current[id];
|
|
2613
2833
|
return typeof chord === "string" && chord.trim() !== "" ? chord : null;
|
|
2614
2834
|
}
|
|
2615
2835
|
/**
|
|
2616
2836
|
* 当前命令的解析键位集合(未绑定/非法 → 空数组;含多候选)。
|
|
2617
|
-
* @author ddj 2026年08月26号
|
|
2837
|
+
* @author ddj 2026年08月26号 / 2026年09月10号
|
|
2618
2838
|
* @param id 命令 id
|
|
2619
2839
|
* @returns 解析键位数组(可能为空)
|
|
2620
2840
|
*/
|
|
2621
2841
|
function bindingsOf(id) {
|
|
2622
|
-
|
|
2842
|
+
const override = runtime.get(id);
|
|
2843
|
+
if (override) return override;
|
|
2844
|
+
const chord = current[id];
|
|
2845
|
+
return typeof chord === "string" ? parseChords(chord) : [];
|
|
2623
2846
|
}
|
|
2624
2847
|
/**
|
|
2625
2848
|
* 主键规范化:小写字母大写、空格归一为 Space,其余原样(与事件 e.key 对照)。
|
|
@@ -2793,19 +3016,26 @@ window.__ModuleLoader__.load({
|
|
|
2793
3016
|
inputRef.current?.blur?.();
|
|
2794
3017
|
};
|
|
2795
3018
|
react.default.useEffect(() => {
|
|
3019
|
+
const openBox = () => {
|
|
3020
|
+
inputRef.current?.focus?.();
|
|
3021
|
+
setOpen(true);
|
|
3022
|
+
};
|
|
2796
3023
|
const onKey = (e) => {
|
|
2797
3024
|
if (matchEvent(e, bindingsOf("edrv.quickOpen"))) {
|
|
2798
3025
|
e.preventDefault();
|
|
2799
3026
|
e.stopPropagation();
|
|
2800
|
-
|
|
2801
|
-
setOpen(true);
|
|
3027
|
+
openBox();
|
|
2802
3028
|
} else if (e.key === "Escape") {
|
|
2803
3029
|
setOpen(false);
|
|
2804
3030
|
inputRef.current?.blur?.();
|
|
2805
3031
|
}
|
|
2806
3032
|
};
|
|
2807
3033
|
window.addEventListener("keydown", onKey, true);
|
|
2808
|
-
|
|
3034
|
+
window.addEventListener("edrv.command.quickOpen", openBox);
|
|
3035
|
+
return () => {
|
|
3036
|
+
window.removeEventListener("keydown", onKey, true);
|
|
3037
|
+
window.removeEventListener("edrv.command.quickOpen", openBox);
|
|
3038
|
+
};
|
|
2809
3039
|
}, []);
|
|
2810
3040
|
const dirText = (p) => {
|
|
2811
3041
|
const base = String(p).split(/[\\/]/).pop() || String(p);
|
|
@@ -2838,6 +3068,460 @@ window.__ModuleLoader__.load({
|
|
|
2838
3068
|
}), pop);
|
|
2839
3069
|
}
|
|
2840
3070
|
//#endregion
|
|
3071
|
+
//#region src/client/commandGlobals.ts
|
|
3072
|
+
/**
|
|
3073
|
+
* dsh-vscode-mode client — 指令系统的全局挂点名约定。
|
|
3074
|
+
* 单独成模块:装配层(client/index.ts)与读取方(命令栏/第三方)都要用,
|
|
3075
|
+
* 放这里可避免 CommandPalette ↔ index 的循环依赖。
|
|
3076
|
+
*
|
|
3077
|
+
* ⚠️ 必须挂在 window 自身(双下划线 + edrv 前缀,与既有 __edrvExtPoll 同风格)。
|
|
3078
|
+
* 旧实现写 window.dsh.edrvCommands——DSH 从不创建 window.dsh 命名空间(全仓库无赋值),
|
|
3079
|
+
* 该路径恒为死代码并导致命令栏读到空表;不要再改回气泡式挂点。
|
|
3080
|
+
* 作者 ddj 2026年09月10号
|
|
3081
|
+
*/
|
|
3082
|
+
/** 指令注册表的全局挂点名:window[REGISTRY_GLOBAL](第三方注册与调试读取;命令栏首选模块引用)。 */
|
|
3083
|
+
const REGISTRY_GLOBAL = "__edrvCommands__";
|
|
3084
|
+
//#endregion
|
|
3085
|
+
//#region src/client/commandSearch.ts
|
|
3086
|
+
/** 排序用基础序(未声明 order 的命令排在已声明之后)。 */
|
|
3087
|
+
const DEFAULT_ORDER = 100;
|
|
3088
|
+
/** 命中字段权重(数值越小越优先)。 */
|
|
3089
|
+
const FIELD_WEIGHT = {
|
|
3090
|
+
label: 0,
|
|
3091
|
+
id: 1,
|
|
3092
|
+
category: 2
|
|
3093
|
+
};
|
|
3094
|
+
/** 小写化(非字符串按空串处理,容错外部脏数据)。 */
|
|
3095
|
+
function lower(text) {
|
|
3096
|
+
return typeof text === "string" ? text.toLocaleLowerCase("en-US") : "";
|
|
3097
|
+
}
|
|
3098
|
+
/** 建立一条命令的索引文本。 */
|
|
3099
|
+
function indexOf(command) {
|
|
3100
|
+
return {
|
|
3101
|
+
label: lower(command.label),
|
|
3102
|
+
id: lower(command.id),
|
|
3103
|
+
category: lower(command.category)
|
|
3104
|
+
};
|
|
3105
|
+
}
|
|
3106
|
+
/**
|
|
3107
|
+
* 命令是否命中全部 token;命中时返回最优(最小)字段权重。
|
|
3108
|
+
* @author ddj 2026年09月10号
|
|
3109
|
+
* @param fields 命令索引文本
|
|
3110
|
+
* @param tokens 小写查询 token
|
|
3111
|
+
* @returns 字段权重;未命中返回 null
|
|
3112
|
+
*/
|
|
3113
|
+
function hitWeight(fields, tokens) {
|
|
3114
|
+
let best = null;
|
|
3115
|
+
for (const token of tokens) {
|
|
3116
|
+
let tokenWeight = null;
|
|
3117
|
+
for (const field of [
|
|
3118
|
+
"label",
|
|
3119
|
+
"id",
|
|
3120
|
+
"category"
|
|
3121
|
+
]) {
|
|
3122
|
+
if (!fields[field].includes(token)) continue;
|
|
3123
|
+
const weight = FIELD_WEIGHT[field];
|
|
3124
|
+
if (tokenWeight === null || weight < tokenWeight) tokenWeight = weight;
|
|
3125
|
+
if (weight === 0) break;
|
|
3126
|
+
}
|
|
3127
|
+
if (tokenWeight === null) return null;
|
|
3128
|
+
if (best === null || tokenWeight < best) best = tokenWeight;
|
|
3129
|
+
}
|
|
3130
|
+
return best;
|
|
3131
|
+
}
|
|
3132
|
+
/** 目录序(order 缺省 100;非有限值同样按 100)。 */
|
|
3133
|
+
function orderOf$1(command) {
|
|
3134
|
+
const order = command.order;
|
|
3135
|
+
return typeof order === "number" && Number.isFinite(order) ? order : DEFAULT_ORDER;
|
|
3136
|
+
}
|
|
3137
|
+
/**
|
|
3138
|
+
* 过滤并按相关度排序命令(空查询返回全部,仅按目录序排序)。
|
|
3139
|
+
* @author ddj 2026年09月10号
|
|
3140
|
+
* @param commands 候选命令(调用方通常已按可用性过滤)
|
|
3141
|
+
* @param query 用户输入
|
|
3142
|
+
* @returns 命中命令数组
|
|
3143
|
+
*/
|
|
3144
|
+
function filterCommands(commands, query) {
|
|
3145
|
+
const tokens = lower(query).split(/\s+/).filter(Boolean);
|
|
3146
|
+
const hits = [];
|
|
3147
|
+
for (const command of commands) {
|
|
3148
|
+
const weight = tokens.length ? hitWeight(indexOf(command), tokens) : 0;
|
|
3149
|
+
if (weight !== null) hits.push({
|
|
3150
|
+
command,
|
|
3151
|
+
weight
|
|
3152
|
+
});
|
|
3153
|
+
}
|
|
3154
|
+
return hits.map((hit, index) => ({
|
|
3155
|
+
hit,
|
|
3156
|
+
index
|
|
3157
|
+
})).sort((a, b) => a.hit.weight - b.hit.weight || orderOf$1(a.hit.command) - orderOf$1(b.hit.command) || a.index - b.index).map((entry) => entry.hit.command);
|
|
3158
|
+
}
|
|
3159
|
+
//#endregion
|
|
3160
|
+
//#region src/client/commandRegistry.ts
|
|
3161
|
+
/**
|
|
3162
|
+
* dsh-vscode-mode client — 指令注册表(命令栏与快捷键系统的唯一数据源)。
|
|
3163
|
+
* 镜像 sidebar/registry.ts 的注册表模式:register 返回注销器、list/subscribe 可订阅;
|
|
3164
|
+
* 额外提供 run(id):先做可用性判定再执行,运行体异常一律捕获上报,绝不让命令抛出到事件循环。
|
|
3165
|
+
* 重复 id 按「后注册者生效」覆盖,旧注销器带身份校验(不会误删新实例,见 releaseRegistry)。
|
|
3166
|
+
* 作者 ddj 2026年09月10号
|
|
3167
|
+
*/
|
|
3168
|
+
const registryLog = log.child("commands");
|
|
3169
|
+
/** 校验命令定义(缺 id/label/run 抛 TypeError,早失败优于静默无效)。 */
|
|
3170
|
+
function assertCommand(command) {
|
|
3171
|
+
if (!command || typeof command.id !== "string" || !command.id) throw new TypeError("命令必须提供 id");
|
|
3172
|
+
if (typeof command.label !== "string" || !command.label) throw new TypeError("命令必须提供 label:" + command.id);
|
|
3173
|
+
if (typeof command.run !== "function") throw new TypeError("命令必须提供 run:" + command.id);
|
|
3174
|
+
}
|
|
3175
|
+
/** 目录序(order 缺省 100;非有限值同样按 100)。 */
|
|
3176
|
+
function orderOf(command) {
|
|
3177
|
+
return typeof command.order === "number" && Number.isFinite(command.order) ? command.order : 100;
|
|
3178
|
+
}
|
|
3179
|
+
/** 命令是否可用(available 缺省视为可用;判定异常按不可用处理)。 */
|
|
3180
|
+
function isAvailable$1(command) {
|
|
3181
|
+
if (typeof command.available !== "function") return true;
|
|
3182
|
+
try {
|
|
3183
|
+
return command.available() === true;
|
|
3184
|
+
} catch (error) {
|
|
3185
|
+
registryLog.warn("可用性判定异常(按不可用处理):" + command.id + " · " + String(error));
|
|
3186
|
+
return false;
|
|
3187
|
+
}
|
|
3188
|
+
}
|
|
3189
|
+
/**
|
|
3190
|
+
* 注销命令(仅当表中仍是本次注册的定义时移除,避免旧实例误删新实例)。
|
|
3191
|
+
* @author ddj 2026年09月10号
|
|
3192
|
+
* @param entries 命令表
|
|
3193
|
+
* @param notify 变化通知
|
|
3194
|
+
* @param command 注册时的定义
|
|
3195
|
+
* @returns 注销函数
|
|
3196
|
+
*/
|
|
3197
|
+
function releaseRegistry(entries, notify, command) {
|
|
3198
|
+
let released = false;
|
|
3199
|
+
return () => {
|
|
3200
|
+
if (released) return;
|
|
3201
|
+
released = true;
|
|
3202
|
+
if (entries.get(command.id) !== command) return;
|
|
3203
|
+
entries.delete(command.id);
|
|
3204
|
+
notify();
|
|
3205
|
+
};
|
|
3206
|
+
}
|
|
3207
|
+
/**
|
|
3208
|
+
* 执行已注册命令(可用性判定 → 运行体 → 异常上报)。
|
|
3209
|
+
* @author ddj 2026年09月10号
|
|
3210
|
+
* @param command 命令定义
|
|
3211
|
+
* @returns 是否真正执行
|
|
3212
|
+
*/
|
|
3213
|
+
function runCommand(command) {
|
|
3214
|
+
if (!isAvailable$1(command)) {
|
|
3215
|
+
registryLog.debug("命令不可用,已跳过:" + command.id);
|
|
3216
|
+
return false;
|
|
3217
|
+
}
|
|
3218
|
+
try {
|
|
3219
|
+
command.run();
|
|
3220
|
+
registryLog.debug("命令已执行:" + command.id);
|
|
3221
|
+
return true;
|
|
3222
|
+
} catch (error) {
|
|
3223
|
+
registryLog.error("命令执行失败:" + command.id + " · " + String(error));
|
|
3224
|
+
return false;
|
|
3225
|
+
}
|
|
3226
|
+
}
|
|
3227
|
+
/**
|
|
3228
|
+
* 创建指令注册表。
|
|
3229
|
+
* @author ddj 2026年09月10号
|
|
3230
|
+
* @returns 指令注册表
|
|
3231
|
+
*/
|
|
3232
|
+
function createCommandRegistry() {
|
|
3233
|
+
const entries = /* @__PURE__ */ new Map();
|
|
3234
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
3235
|
+
const notify = () => {
|
|
3236
|
+
for (const listener of listeners) try {
|
|
3237
|
+
listener();
|
|
3238
|
+
} catch (error) {
|
|
3239
|
+
registryLog.warn("注册表订阅回调异常:" + String(error));
|
|
3240
|
+
}
|
|
3241
|
+
};
|
|
3242
|
+
const list = () => [...entries.values()].sort((a, b) => orderOf(a) - orderOf(b));
|
|
3243
|
+
const available = () => list().filter(isAvailable$1);
|
|
3244
|
+
return {
|
|
3245
|
+
register(command) {
|
|
3246
|
+
assertCommand(command);
|
|
3247
|
+
if (entries.get(command.id) !== void 0) registryLog.warn("命令 id 重复注册(后者生效):" + command.id);
|
|
3248
|
+
entries.set(command.id, command);
|
|
3249
|
+
notify();
|
|
3250
|
+
return releaseRegistry(entries, notify, command);
|
|
3251
|
+
},
|
|
3252
|
+
has: (id) => entries.has(id),
|
|
3253
|
+
get: (id) => entries.get(id),
|
|
3254
|
+
list,
|
|
3255
|
+
available,
|
|
3256
|
+
match: (query) => filterCommands(available(), query),
|
|
3257
|
+
run(id) {
|
|
3258
|
+
const command = entries.get(id);
|
|
3259
|
+
if (!command) {
|
|
3260
|
+
registryLog.warn("命令未注册:" + id);
|
|
3261
|
+
return false;
|
|
3262
|
+
}
|
|
3263
|
+
return runCommand(command);
|
|
3264
|
+
},
|
|
3265
|
+
subscribe(listener) {
|
|
3266
|
+
listeners.add(listener);
|
|
3267
|
+
return () => listeners.delete(listener);
|
|
3268
|
+
}
|
|
3269
|
+
};
|
|
3270
|
+
}
|
|
3271
|
+
/** 装配期存入的指令注册表(命令栏读取候选的唯一真源)。 */
|
|
3272
|
+
let registryTable = null;
|
|
3273
|
+
/** 命令栏是否展开。 */
|
|
3274
|
+
let opened = false;
|
|
3275
|
+
/** 当前真正渲染浮层的宿主令牌(null = 无宿主)。 */
|
|
3276
|
+
let hostToken = null;
|
|
3277
|
+
/** 注入的命令执行器(commandBridge 装配时写入)。 */
|
|
3278
|
+
let runner = null;
|
|
3279
|
+
/** 打开命令栏前的焦点元素(关闭后归还焦点,键盘操作不中断)。 */
|
|
3280
|
+
let focusBack = null;
|
|
3281
|
+
const listeners$1 = /* @__PURE__ */ new Set();
|
|
3282
|
+
/** 通知全部订阅者(回调异常不影响其他订阅)。 */
|
|
3283
|
+
function notifyPalette() {
|
|
3284
|
+
for (const listener of listeners$1) try {
|
|
3285
|
+
listener();
|
|
3286
|
+
} catch {}
|
|
3287
|
+
}
|
|
3288
|
+
/**
|
|
3289
|
+
* 注入命令执行器(命令栏执行选中命令时调用)。
|
|
3290
|
+
* @author ddj 2026年09月10号
|
|
3291
|
+
* @param next 执行器(返回是否执行成功)
|
|
3292
|
+
*/
|
|
3293
|
+
function setPaletteRunner(next) {
|
|
3294
|
+
runner = next;
|
|
3295
|
+
}
|
|
3296
|
+
/**
|
|
3297
|
+
* 执行命令栏选中的命令。
|
|
3298
|
+
* @author ddj 2026年09月10号
|
|
3299
|
+
* @param id 命令 id
|
|
3300
|
+
* @returns 是否执行成功(执行器未注入/命令不可用/抛异常均为 false)
|
|
3301
|
+
*/
|
|
3302
|
+
function runPaletteCommand(id) {
|
|
3303
|
+
if (!runner) return false;
|
|
3304
|
+
return runner(id) === true;
|
|
3305
|
+
}
|
|
3306
|
+
/**
|
|
3307
|
+
* 存入指令注册表(commandBridge 装配期调用;命令栏据此读取候选)。
|
|
3308
|
+
* @author ddj 2026年09月10号
|
|
3309
|
+
* @param next 指令注册表(null = 卸载)
|
|
3310
|
+
*/
|
|
3311
|
+
function setRegistryRef(next) {
|
|
3312
|
+
registryTable = next;
|
|
3313
|
+
}
|
|
3314
|
+
/**
|
|
3315
|
+
* 读取指令注册表(未装配返回 null;浮层据此回退全局/空表)。
|
|
3316
|
+
* @author ddj 2026年09月10号
|
|
3317
|
+
* @returns 指令注册表或 null
|
|
3318
|
+
*/
|
|
3319
|
+
function registryRef() {
|
|
3320
|
+
return registryTable;
|
|
3321
|
+
}
|
|
3322
|
+
/**
|
|
3323
|
+
* 订阅命令栏开关变化。
|
|
3324
|
+
* @author ddj 2026年09月10号
|
|
3325
|
+
* @param listener 变化回调
|
|
3326
|
+
* @returns 取消订阅函数
|
|
3327
|
+
*/
|
|
3328
|
+
function subscribePalette(listener) {
|
|
3329
|
+
listeners$1.add(listener);
|
|
3330
|
+
return () => listeners$1.delete(listener);
|
|
3331
|
+
}
|
|
3332
|
+
/**
|
|
3333
|
+
* 命令栏是否展开(useSyncExternalStore 快照)。
|
|
3334
|
+
* @author ddj 2026年09月10号
|
|
3335
|
+
* @returns 是否展开
|
|
3336
|
+
*/
|
|
3337
|
+
function isPaletteOpen() {
|
|
3338
|
+
return opened;
|
|
3339
|
+
}
|
|
3340
|
+
/** 记录打开前的焦点元素(只在真正需要归还时记录)。 */
|
|
3341
|
+
function rememberFocus() {
|
|
3342
|
+
if (typeof document === "undefined") return;
|
|
3343
|
+
const active = document.activeElement;
|
|
3344
|
+
focusBack = active instanceof HTMLElement ? active : null;
|
|
3345
|
+
}
|
|
3346
|
+
/**
|
|
3347
|
+
* 打开命令栏(已打开时为空操作;记录当前焦点供关闭后归还)。
|
|
3348
|
+
* @author ddj 2026年09月10号
|
|
3349
|
+
* @param reason 唤起来源(键盘/命令/外部 API)
|
|
3350
|
+
*/
|
|
3351
|
+
function openCommandPalette(reason = "keybinding") {
|
|
3352
|
+
if (opened) return;
|
|
3353
|
+
rememberFocus();
|
|
3354
|
+
opened = true;
|
|
3355
|
+
notifyPalette();
|
|
3356
|
+
}
|
|
3357
|
+
/**
|
|
3358
|
+
* 关闭命令栏并归还焦点。
|
|
3359
|
+
* @author ddj 2026年09月10号
|
|
3360
|
+
*/
|
|
3361
|
+
function closeCommandPalette() {
|
|
3362
|
+
if (!opened) return;
|
|
3363
|
+
opened = false;
|
|
3364
|
+
notifyPalette();
|
|
3365
|
+
const target = focusBack;
|
|
3366
|
+
focusBack = null;
|
|
3367
|
+
if (!target || typeof target.focus !== "function") return;
|
|
3368
|
+
try {
|
|
3369
|
+
target.focus();
|
|
3370
|
+
} catch {}
|
|
3371
|
+
}
|
|
3372
|
+
/**
|
|
3373
|
+
* 认领命令栏宿主(返回 true 表示由本宿主渲染浮层)。
|
|
3374
|
+
* @author ddj 2026年09月10号
|
|
3375
|
+
* @returns 是否为当前宿主
|
|
3376
|
+
*/
|
|
3377
|
+
function claimPaletteHost() {
|
|
3378
|
+
if (hostToken !== null) return false;
|
|
3379
|
+
hostToken = {};
|
|
3380
|
+
return true;
|
|
3381
|
+
}
|
|
3382
|
+
/**
|
|
3383
|
+
* 释放宿主认领(仅持有者可释放,卸载顺序错乱不会顶掉新宿主)。
|
|
3384
|
+
* @author ddj 2026年09月10号
|
|
3385
|
+
* @param token 认领令牌(null 表示本宿主未认领)
|
|
3386
|
+
*/
|
|
3387
|
+
function releasePaletteHost(token) {
|
|
3388
|
+
if (token === null || hostToken !== token) return;
|
|
3389
|
+
hostToken = null;
|
|
3390
|
+
}
|
|
3391
|
+
//#endregion
|
|
3392
|
+
//#region src/client/ui/CommandPalette.ts
|
|
3393
|
+
/**
|
|
3394
|
+
* dsh-vscode-mode client — 命令栏浮层(Ctrl+Shift+P / F1)。
|
|
3395
|
+
* 订阅 commandPaletteStore 的开关状态;候选来自注入的指令注册表(window.dsh.edrvCommands),
|
|
3396
|
+
* 过滤/排序复用 commandSearch 纯函数;↑↓ 选择、Enter 执行、Esc 或点击遮罩关闭。
|
|
3397
|
+
* 浮层经 createPortal 渲染到 body,故不受编辑区三种形态(官方侧栏/better-sidebar/中央页签)影响;
|
|
3398
|
+
* 宿主单实例由 store 的 claimPaletteHost 保证(另一个宿主自动返回 null)。
|
|
3399
|
+
* 作者 ddj 2026年09月10号
|
|
3400
|
+
*/
|
|
3401
|
+
/** 空注册表(宿主未注入时的安全降级:命令栏可开但无候选)。 */
|
|
3402
|
+
let fallbackRegistry = null;
|
|
3403
|
+
/**
|
|
3404
|
+
* 读取指令注册表:① 装配期存入的模块引用(首选,不依赖全局)
|
|
3405
|
+
* ② window[REGISTRY_GLOBAL] 镜像(第三方/调试场景)③ 空表降级(仅装配异常时)。
|
|
3406
|
+
* @author ddj 2026年09月10号
|
|
3407
|
+
* @returns 指令注册表
|
|
3408
|
+
*/
|
|
3409
|
+
function useRegistry() {
|
|
3410
|
+
const injected = registryRef();
|
|
3411
|
+
if (injected) return injected;
|
|
3412
|
+
const mirrored = typeof window === "undefined" ? void 0 : window[REGISTRY_GLOBAL];
|
|
3413
|
+
if (mirrored) return mirrored;
|
|
3414
|
+
if (!fallbackRegistry) fallbackRegistry = createCommandRegistry();
|
|
3415
|
+
return fallbackRegistry;
|
|
3416
|
+
}
|
|
3417
|
+
/**
|
|
3418
|
+
* 组装候选行(先按可用性过滤,再按查询排序)。
|
|
3419
|
+
* @author ddj 2026年09月10号
|
|
3420
|
+
* @param registry 指令注册表
|
|
3421
|
+
* @param query 用户输入
|
|
3422
|
+
* @returns 候选行
|
|
3423
|
+
*/
|
|
3424
|
+
function rowsOf(registry, query) {
|
|
3425
|
+
return filterCommands(registry.available(), query).map((command) => ({
|
|
3426
|
+
command,
|
|
3427
|
+
chord: chordOf(command.id)
|
|
3428
|
+
}));
|
|
3429
|
+
}
|
|
3430
|
+
/**
|
|
3431
|
+
* 命令栏浮层(未展开/非宿主时渲染 null)。
|
|
3432
|
+
* @author ddj 2026年09月10号
|
|
3433
|
+
* @returns 浮层 React 元素或 null
|
|
3434
|
+
*/
|
|
3435
|
+
function CommandPalette() {
|
|
3436
|
+
const open = react.default.useSyncExternalStore(subscribePalette, isPaletteOpen);
|
|
3437
|
+
const registry = useRegistry();
|
|
3438
|
+
const [token] = react.default.useState(() => claimPaletteHost() ? {} : null);
|
|
3439
|
+
const [query, setQuery] = react.default.useState("");
|
|
3440
|
+
const [selected, setSelected] = react.default.useState(0);
|
|
3441
|
+
const [notice, setNotice] = react.default.useState("");
|
|
3442
|
+
const inputRef = react.default.useRef(null);
|
|
3443
|
+
const host = token !== null;
|
|
3444
|
+
react.default.useEffect(() => () => releasePaletteHost(token), [token]);
|
|
3445
|
+
react.default.useEffect(() => {
|
|
3446
|
+
if (!open) return void 0;
|
|
3447
|
+
setQuery("");
|
|
3448
|
+
setSelected(0);
|
|
3449
|
+
setNotice("");
|
|
3450
|
+
const timer = setTimeout(() => inputRef.current?.focus(), 0);
|
|
3451
|
+
return () => clearTimeout(timer);
|
|
3452
|
+
}, [open]);
|
|
3453
|
+
const rows = react.default.useMemo(() => open && host ? rowsOf(registry, query) : [], [
|
|
3454
|
+
open,
|
|
3455
|
+
host,
|
|
3456
|
+
registry,
|
|
3457
|
+
query
|
|
3458
|
+
]);
|
|
3459
|
+
const active = rows.length ? Math.min(selected, rows.length - 1) : 0;
|
|
3460
|
+
react.default.useEffect(() => {
|
|
3461
|
+
if (!open) return;
|
|
3462
|
+
const node = document.querySelector(".edrv-palette-row.edrv-palette-sel");
|
|
3463
|
+
const scroll = node?.scrollIntoView;
|
|
3464
|
+
if (typeof scroll === "function") scroll.call(node, { block: "nearest" });
|
|
3465
|
+
}, [
|
|
3466
|
+
open,
|
|
3467
|
+
active,
|
|
3468
|
+
rows.length
|
|
3469
|
+
]);
|
|
3470
|
+
/** 执行候选行(执行器内部会做可用性校验与异常上报)。 */
|
|
3471
|
+
const execute = (row) => {
|
|
3472
|
+
if (!row) return;
|
|
3473
|
+
closeCommandPalette();
|
|
3474
|
+
if (!runPaletteCommand(row.command.id)) setNotice("命令未执行:" + row.command.label);
|
|
3475
|
+
};
|
|
3476
|
+
const onKeyDown = (event) => {
|
|
3477
|
+
event.stopPropagation();
|
|
3478
|
+
if (event.key === "Escape") {
|
|
3479
|
+
event.preventDefault();
|
|
3480
|
+
closeCommandPalette();
|
|
3481
|
+
return;
|
|
3482
|
+
}
|
|
3483
|
+
if (event.key === "ArrowDown" || event.key === "ArrowUp") {
|
|
3484
|
+
event.preventDefault();
|
|
3485
|
+
if (!rows.length) return;
|
|
3486
|
+
const step = event.key === "ArrowDown" ? 1 : rows.length - 1;
|
|
3487
|
+
setSelected((value) => (Math.min(value, rows.length - 1) + step) % rows.length);
|
|
3488
|
+
return;
|
|
3489
|
+
}
|
|
3490
|
+
if (event.key === "Enter") {
|
|
3491
|
+
event.preventDefault();
|
|
3492
|
+
execute(rows[active]);
|
|
3493
|
+
}
|
|
3494
|
+
};
|
|
3495
|
+
if (!open || !host || typeof document === "undefined") return null;
|
|
3496
|
+
const list = rows.length ? rows.map((row, index) => react.default.createElement("div", {
|
|
3497
|
+
key: row.command.id,
|
|
3498
|
+
className: "edrv-palette-row" + (index === active ? " edrv-palette-sel" : ""),
|
|
3499
|
+
onMouseEnter: () => setSelected(index),
|
|
3500
|
+
onClick: () => execute(row)
|
|
3501
|
+
}, react.default.createElement("span", { className: "edrv-palette-label" }, row.command.label), react.default.createElement("span", { className: "edrv-palette-cat" }, row.command.category), row.chord ? react.default.createElement("kbd", { className: "edrv-palette-key" }, row.chord) : null)) : react.default.createElement("div", { className: "edrv-palette-empty" }, "无匹配命令");
|
|
3502
|
+
const panel = react.default.createElement("div", {
|
|
3503
|
+
className: "edrv-palette",
|
|
3504
|
+
"data-edrv-palette": "1",
|
|
3505
|
+
onKeyDown
|
|
3506
|
+
}, react.default.createElement("input", {
|
|
3507
|
+
ref: inputRef,
|
|
3508
|
+
className: "edrv-palette-input",
|
|
3509
|
+
value: query,
|
|
3510
|
+
placeholder: "输入命令名称…(↑↓ 选择 · Enter 执行 · Esc 关闭)",
|
|
3511
|
+
spellCheck: false,
|
|
3512
|
+
onChange: (event) => {
|
|
3513
|
+
setQuery(event.target.value);
|
|
3514
|
+
setSelected(0);
|
|
3515
|
+
setNotice("");
|
|
3516
|
+
}
|
|
3517
|
+
}), react.default.createElement("div", { className: "edrv-palette-list" }, list), notice ? react.default.createElement("div", { className: "edrv-palette-notice" }, notice) : null);
|
|
3518
|
+
const overlay = react.default.createElement("div", { "data-edrv-view": "1" }, react.default.createElement("div", {
|
|
3519
|
+
className: "edrv-palette-mask",
|
|
3520
|
+
onClick: () => closeCommandPalette()
|
|
3521
|
+
}), panel);
|
|
3522
|
+
return (0, react_dom.createPortal)(overlay, document.body);
|
|
3523
|
+
}
|
|
3524
|
+
//#endregion
|
|
2841
3525
|
//#region src/client/ui/shared.ts
|
|
2842
3526
|
/**
|
|
2843
3527
|
* dsh-vscode-mode client — UI 共用小工具(按钮样式/状态文案/等宽字体)。
|
|
@@ -5017,6 +5701,10 @@ window.__ModuleLoader__.load({
|
|
|
5017
5701
|
const navBackRef = react.default.useRef(null);
|
|
5018
5702
|
const navForwardRef = react.default.useRef(null);
|
|
5019
5703
|
const cycleTabRef = react.default.useRef(null);
|
|
5704
|
+
const rowNavColRef = react.default.useRef(null);
|
|
5705
|
+
const rowNavMoveRef = react.default.useRef(false);
|
|
5706
|
+
const activeRef = react.default.useRef(null);
|
|
5707
|
+
activeRef.current = active;
|
|
5020
5708
|
const tabsHostRef = react.default.useRef(null);
|
|
5021
5709
|
const [navTick, setNavTick] = react.default.useState(0);
|
|
5022
5710
|
const hoverRegionsRef = react.default.useRef([]);
|
|
@@ -5734,6 +6422,83 @@ window.__ModuleLoader__.load({
|
|
|
5734
6422
|
window.addEventListener("keydown", onKey, true);
|
|
5735
6423
|
return () => window.removeEventListener("keydown", onKey, true);
|
|
5736
6424
|
}, []);
|
|
6425
|
+
/**
|
|
6426
|
+
* 指令系统接线:命令栏/键位/第三方派发的 `edrv.command.*` 事件落到编辑器动作。
|
|
6427
|
+
* 全部动作经最新闭包执行(与窗口级键位监听同源);事件名逐条字面书写,
|
|
6428
|
+
* 便于与指令目录(ui/commandCatalog)静态对照(tests/commands.test.ts 有断言)。
|
|
6429
|
+
* @author ddj 2026年09月10号
|
|
6430
|
+
*/
|
|
6431
|
+
react.default.useEffect(() => {
|
|
6432
|
+
/** 整行上下移动:Monaco 内置 cursorUp/Down 会丢列位,故按期望列自行定位(连续移动保持同列)。 */
|
|
6433
|
+
const moveRow = (step) => {
|
|
6434
|
+
const ed = editorRef.current;
|
|
6435
|
+
const model = ed?.getModel?.();
|
|
6436
|
+
const pos = ed?.getPosition?.();
|
|
6437
|
+
if (!ed || !model || !pos) return;
|
|
6438
|
+
const col = rowNavColRef.current ?? pos.column;
|
|
6439
|
+
const line = Math.max(1, Math.min(model.getLineCount(), pos.lineNumber + step));
|
|
6440
|
+
if (line === pos.lineNumber) return;
|
|
6441
|
+
const maxCol = model.getLineMaxColumn(line);
|
|
6442
|
+
rowNavColRef.current = col;
|
|
6443
|
+
rowNavMoveRef.current = true;
|
|
6444
|
+
ed.setPosition({
|
|
6445
|
+
lineNumber: line,
|
|
6446
|
+
column: Math.max(1, Math.min(col, maxCol))
|
|
6447
|
+
});
|
|
6448
|
+
ed.revealLineInCenterIfOutsideViewport?.(line);
|
|
6449
|
+
};
|
|
6450
|
+
const handlers = [
|
|
6451
|
+
["edrv.command.save", () => {
|
|
6452
|
+
if (editorRef.current?.getModel?.()) {
|
|
6453
|
+
flushSave();
|
|
6454
|
+
doSaveRef.current?.(false);
|
|
6455
|
+
}
|
|
6456
|
+
}],
|
|
6457
|
+
["edrv.command.toggleSidebar", () => setSidebarOn((v) => !v)],
|
|
6458
|
+
["edrv.command.searchInFiles", () => {
|
|
6459
|
+
setSidebarOn(true);
|
|
6460
|
+
setActivePanel("search");
|
|
6461
|
+
setTimeout(() => window.dispatchEvent(new CustomEvent("edrv:search-focus")), 0);
|
|
6462
|
+
}],
|
|
6463
|
+
["edrv.command.navigateBack", () => navBackRef.current?.()],
|
|
6464
|
+
["edrv.command.navigateForward", () => navForwardRef.current?.()],
|
|
6465
|
+
["edrv.command.nextTab", () => cycleTabRef.current?.(1)],
|
|
6466
|
+
["edrv.command.prevTab", () => cycleTabRef.current?.(-1)],
|
|
6467
|
+
["edrv.command.nextEditorRow", () => moveRow(1)],
|
|
6468
|
+
["edrv.command.prevEditorRow", () => moveRow(-1)],
|
|
6469
|
+
["edrv.command.goToDefinition", () => {
|
|
6470
|
+
const ed = editorRef.current;
|
|
6471
|
+
if (ed) runGoToDefinition(ed);
|
|
6472
|
+
}],
|
|
6473
|
+
["edrv.command.findReferences", () => {
|
|
6474
|
+
const ed = editorRef.current;
|
|
6475
|
+
if (ed) runFindReferences(ed);
|
|
6476
|
+
}],
|
|
6477
|
+
["edrv.command.triggerAi", () => editorRef.current?.trigger?.("edrv-ai", "editor.action.inlineSuggest.trigger", null)],
|
|
6478
|
+
["edrv.command.openInExplorer", () => {
|
|
6479
|
+
const path = activeRef.current;
|
|
6480
|
+
if (!path) {
|
|
6481
|
+
setStatus("无活动文件");
|
|
6482
|
+
return;
|
|
6483
|
+
}
|
|
6484
|
+
menuHandlersRef.current?.openInExplorer?.(path);
|
|
6485
|
+
}]
|
|
6486
|
+
];
|
|
6487
|
+
const byName = new Map(handlers);
|
|
6488
|
+
const onCommand = (event) => {
|
|
6489
|
+
const action = byName.get(event.type);
|
|
6490
|
+
if (!action) return;
|
|
6491
|
+
try {
|
|
6492
|
+
action();
|
|
6493
|
+
} catch (error) {
|
|
6494
|
+
dbg(sessionId, "指令 " + event.type + " 失败:" + String(error));
|
|
6495
|
+
}
|
|
6496
|
+
};
|
|
6497
|
+
for (const [eventName] of handlers) window.addEventListener(eventName, onCommand);
|
|
6498
|
+
return () => {
|
|
6499
|
+
for (const [eventName] of handlers) window.removeEventListener(eventName, onCommand);
|
|
6500
|
+
};
|
|
6501
|
+
}, [sessionId]);
|
|
5737
6502
|
react.default.useEffect(() => {
|
|
5738
6503
|
const host = tabsHostRef.current;
|
|
5739
6504
|
if (!host) return;
|
|
@@ -6021,6 +6786,8 @@ window.__ModuleLoader__.load({
|
|
|
6021
6786
|
});
|
|
6022
6787
|
ed.onDidChangeCursorPosition((e) => {
|
|
6023
6788
|
setCursor("Ln " + e.position.lineNumber + ", Col " + e.position.column);
|
|
6789
|
+
if (rowNavMoveRef.current) rowNavMoveRef.current = false;
|
|
6790
|
+
else rowNavColRef.current = null;
|
|
6024
6791
|
if (navCursorTimerRef.current) clearTimeout(navCursorTimerRef.current);
|
|
6025
6792
|
navCursorTimerRef.current = setTimeout(() => {
|
|
6026
6793
|
navCursorTimerRef.current = null;
|
|
@@ -6097,6 +6864,24 @@ window.__ModuleLoader__.load({
|
|
|
6097
6864
|
ed.addCommand(m.KeyCode.F12, () => {
|
|
6098
6865
|
runGoToDefinition(ed);
|
|
6099
6866
|
});
|
|
6867
|
+
ed.addAction({
|
|
6868
|
+
id: "edrv.prevEditorRow",
|
|
6869
|
+
label: "上一编辑行",
|
|
6870
|
+
contextMenuGroupId: "1_edrv",
|
|
6871
|
+
run: () => window.dispatchEvent(new CustomEvent("edrv.command.prevEditorRow"))
|
|
6872
|
+
});
|
|
6873
|
+
ed.addAction({
|
|
6874
|
+
id: "edrv.nextEditorRow",
|
|
6875
|
+
label: "下一编辑行",
|
|
6876
|
+
contextMenuGroupId: "1_edrv",
|
|
6877
|
+
run: () => window.dispatchEvent(new CustomEvent("edrv.command.nextEditorRow"))
|
|
6878
|
+
});
|
|
6879
|
+
ed.addAction({
|
|
6880
|
+
id: "edrv.showCommands",
|
|
6881
|
+
label: "显示所有命令",
|
|
6882
|
+
contextMenuGroupId: "1_edrv",
|
|
6883
|
+
run: () => window.dispatchEvent(new CustomEvent("edrv.command.showCommands"))
|
|
6884
|
+
});
|
|
6100
6885
|
bindLspEditor(ed);
|
|
6101
6886
|
bindLspUnderline(ed, m);
|
|
6102
6887
|
trackAiEditor(ed);
|
|
@@ -6746,7 +7531,7 @@ window.__ModuleLoader__.load({
|
|
|
6746
7531
|
});
|
|
6747
7532
|
}
|
|
6748
7533
|
}, "重试"));
|
|
6749
|
-
else if (!active) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "暂无打开的文件"), react.default.createElement("div", { style: { fontSize: 12 } }, "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开工作区文件;agent 修改文件后顶部会出现差异角标"));
|
|
7534
|
+
else if (!active) body = react.default.createElement("div", { className: "edrv-empty" }, react.default.createElement("div", null, "暂无打开的文件"), react.default.createElement("div", { style: { fontSize: 12 } }, "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开工作区文件;" + (chordOf("edrv.showCommands") ?? "Ctrl+Shift+P") + " 打开命令栏;agent 修改文件后顶部会出现差异角标"));
|
|
6750
7535
|
else if (content === null && loadError) body = loadingBody("文件加载失败:" + loadError, 0, () => {
|
|
6751
7536
|
setLoadError(null);
|
|
6752
7537
|
setContent(null);
|
|
@@ -6971,20 +7756,24 @@ window.__ModuleLoader__.load({
|
|
|
6971
7756
|
background: "var(--dsw-alias-bg-base,transparent)",
|
|
6972
7757
|
overflow: "hidden"
|
|
6973
7758
|
};
|
|
7759
|
+
const paletteEl = react.default.createElement(CommandPalette, {
|
|
7760
|
+
key: "edrv-palette",
|
|
7761
|
+
sessionId
|
|
7762
|
+
});
|
|
6974
7763
|
return layout === "side" ? react.default.createElement("div", {
|
|
6975
7764
|
ref: viewRootRef,
|
|
6976
7765
|
"data-edrv-view": "1",
|
|
6977
7766
|
"data-edrv-layout": "side",
|
|
6978
7767
|
className: "edrv-view-side",
|
|
6979
7768
|
style: Object.assign({}, baseStyle, { height: "100%" })
|
|
6980
|
-
}, editorRow, menuBackdrop, tabMenuEl) : react.default.createElement("div", {
|
|
7769
|
+
}, editorRow, menuBackdrop, tabMenuEl, paletteEl) : react.default.createElement("div", {
|
|
6981
7770
|
ref: viewRootRef,
|
|
6982
7771
|
"data-edrv-view": "1",
|
|
6983
7772
|
style: Object.assign({}, baseStyle, {
|
|
6984
7773
|
height: "var(--edrv-editor-height, 100%)",
|
|
6985
7774
|
maxHeight: "var(--edrv-editor-height, 100%)"
|
|
6986
7775
|
})
|
|
6987
|
-
}, editorRow, menuBackdrop, tabMenuEl);
|
|
7776
|
+
}, editorRow, menuBackdrop, tabMenuEl, paletteEl);
|
|
6988
7777
|
}
|
|
6989
7778
|
//#endregion
|
|
6990
7779
|
//#region src/client/ui/DiffBadge.ts
|
|
@@ -7337,11 +8126,15 @@ window.__ModuleLoader__.load({
|
|
|
7337
8126
|
"data-edrv-diff-dock-shell": "1"
|
|
7338
8127
|
}, content);
|
|
7339
8128
|
const editorSnapshot = readDiffDock(sessionId);
|
|
8129
|
+
const palette = react.default.createElement(CommandPalette, {
|
|
8130
|
+
key: "edrv-palette",
|
|
8131
|
+
sessionId
|
|
8132
|
+
});
|
|
7340
8133
|
if (editorSnapshot) {
|
|
7341
|
-
if (editorSnapshot.mode === "editor-empty" && !editorSnapshot.fileTotal) return
|
|
7342
|
-
return renderDock(react.default.createElement(DiffBox, Object.assign({}, editorSnapshot, { dock: true })), sessionId);
|
|
8134
|
+
if (editorSnapshot.mode === "editor-empty" && !editorSnapshot.fileTotal) return palette;
|
|
8135
|
+
return react.default.createElement(react.default.Fragment, null, renderDock(react.default.createElement(DiffBox, Object.assign({}, editorSnapshot, { dock: true })), sessionId), palette);
|
|
7343
8136
|
}
|
|
7344
|
-
if (!sessionId || !summary?.pendingFiles?.length) return
|
|
8137
|
+
if (!sessionId || !summary?.pendingFiles?.length) return palette;
|
|
7345
8138
|
const paths = summary.pendingFiles.map((file) => file.path);
|
|
7346
8139
|
const click = () => {
|
|
7347
8140
|
const current = nextIndexBySession.get(sessionId) ?? 0;
|
|
@@ -7349,12 +8142,12 @@ window.__ModuleLoader__.load({
|
|
|
7349
8142
|
nextIndexBySession.set(sessionId, next.index);
|
|
7350
8143
|
if (next.path) openDiffView(next.path);
|
|
7351
8144
|
};
|
|
7352
|
-
return renderDock(react.default.createElement(DiffBox, {
|
|
8145
|
+
return react.default.createElement(react.default.Fragment, null, renderDock(react.default.createElement(DiffBox, {
|
|
7353
8146
|
mode: "chat",
|
|
7354
8147
|
dock: true,
|
|
7355
8148
|
fileTotal: paths.length,
|
|
7356
8149
|
onOpenNextFile: click
|
|
7357
|
-
}), sessionId || "chat");
|
|
8150
|
+
}), sessionId || "chat"), palette);
|
|
7358
8151
|
}
|
|
7359
8152
|
//#endregion
|
|
7360
8153
|
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/mcp.css.mjs
|
|
@@ -8130,7 +8923,7 @@ window.__ModuleLoader__.load({
|
|
|
8130
8923
|
onClick: () => resetRow(command.id)
|
|
8131
8924
|
}, "恢复"))));
|
|
8132
8925
|
});
|
|
8133
|
-
return react.default.createElement("section", { className: "vsm-general-page" }, react.default.createElement("h2", null, "快捷键"), react.default.createElement("p", null, "
|
|
8926
|
+
return react.default.createElement("section", { className: "vsm-general-page" }, react.default.createElement("h2", null, "快捷键"), react.default.createElement("p", null, "配置编辑器视图的快捷键(命令栏 / 保存 / 快速打开 / 侧边栏 / 搜索 / 后退前进 / 页签与编辑行导航)。修改即时写入配置,重新聚焦编辑器后生效;命令栏(默认 Ctrl+Shift+P 或 F1)可搜索并执行下列全部命令。"), unavailable && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, "设置服务暂不可用,当前使用默认键位。"), error && react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error), message && react.default.createElement("div", { className: "vsm-kb-message" }, message), react.default.createElement("section", { className: "vsm-panel" }, react.default.createElement("h3", { className: "vsm-panel-title" }, "编辑器键位"), react.default.createElement("div", { className: "vsm-panel-body" }, react.default.createElement("div", { className: "vsm-kb-list" }, rows)), react.default.createElement("div", { className: "vsm-panel-body vsm-kb-actionsbar" }, react.default.createElement("span", { className: "vsm-kb-dirty" }, dirty ? "有未保存的修改" : ""), react.default.createElement("button", {
|
|
8134
8927
|
className: "vsm-primary vsm-small",
|
|
8135
8928
|
disabled: unavailable || notReady || busy || snapshot?.writable === false || !dirty,
|
|
8136
8929
|
onClick: save
|
|
@@ -13391,6 +14184,64 @@ window.__ModuleLoader__.load({
|
|
|
13391
14184
|
return out;
|
|
13392
14185
|
}
|
|
13393
14186
|
//#endregion
|
|
14187
|
+
//#region src/client/commandBridge.ts
|
|
14188
|
+
/**
|
|
14189
|
+
* dsh-vscode-mode client — 指令执行桥(装配层)。
|
|
14190
|
+
* 职责三件:① 把内置指令目录注册进注册表;② 为「桥接派发」类指令挂窗口 capture 键位监听
|
|
14191
|
+
* (EditorView 原生监听的 8 条不进这里,避免双执行);③ 注入命令栏执行器。
|
|
14192
|
+
* 编辑器动作本身由 EditorView / QuickOpen 监听 `edrv.command.<action>` 窗口事件完成——桥不持有
|
|
14193
|
+
* React 状态,因此指令系统可在编辑器挂载前装配、卸载后仍安全。
|
|
14194
|
+
* 作者 ddj 2026年09月10号
|
|
14195
|
+
*/
|
|
14196
|
+
const bridgeLog = log.child("commands");
|
|
14197
|
+
/** 解析事件目标(缺省 window;无 window 返回 null)。 */
|
|
14198
|
+
function resolveTarget(options) {
|
|
14199
|
+
if (options.target) return options.target;
|
|
14200
|
+
if (typeof window === "undefined") return null;
|
|
14201
|
+
return window;
|
|
14202
|
+
}
|
|
14203
|
+
/**
|
|
14204
|
+
* 创建指令执行桥:注册内置指令 + 桥接类指令的全局键位监听。
|
|
14205
|
+
* @author ddj 2026年09月10号
|
|
14206
|
+
* @param options 装配选项(事件目标注入)
|
|
14207
|
+
* @returns 指令执行桥句柄
|
|
14208
|
+
*/
|
|
14209
|
+
function createCommandBridge(options = {}) {
|
|
14210
|
+
const registry = createCommandRegistry();
|
|
14211
|
+
const disposers = [];
|
|
14212
|
+
const palette = showCommandsDef(() => openCommandPalette("command"));
|
|
14213
|
+
for (const command of [...EDITOR_COMMANDS, ...BRIDGE_COMMANDS]) disposers.push(registry.register(command));
|
|
14214
|
+
disposers.push(registry.register(palette));
|
|
14215
|
+
setPaletteRunner((id) => registry.run(id));
|
|
14216
|
+
setRegistryRef(registry);
|
|
14217
|
+
const dispatched = dispatchedCommands(palette);
|
|
14218
|
+
const onKey = (event) => {
|
|
14219
|
+
for (const command of dispatched) {
|
|
14220
|
+
if (!matchEvent(event, bindingsOf(command.id))) continue;
|
|
14221
|
+
event.preventDefault();
|
|
14222
|
+
event.stopPropagation();
|
|
14223
|
+
registry.run(command.id);
|
|
14224
|
+
return;
|
|
14225
|
+
}
|
|
14226
|
+
};
|
|
14227
|
+
const target = resolveTarget(options);
|
|
14228
|
+
if (target) target.addEventListener("keydown", onKey, true);
|
|
14229
|
+
const dispose = () => {
|
|
14230
|
+
if (target) target.removeEventListener("keydown", onKey, true);
|
|
14231
|
+
while (disposers.length) {
|
|
14232
|
+
const release = disposers.pop();
|
|
14233
|
+
if (release) release();
|
|
14234
|
+
}
|
|
14235
|
+
setPaletteRunner(null);
|
|
14236
|
+
setRegistryRef(null);
|
|
14237
|
+
};
|
|
14238
|
+
bridgeLog.info("指令注册表已装配(" + registry.list().length + " 条指令,桥接键位 " + dispatched.length + " 条)");
|
|
14239
|
+
return {
|
|
14240
|
+
registry,
|
|
14241
|
+
dispose
|
|
14242
|
+
};
|
|
14243
|
+
}
|
|
14244
|
+
//#endregion
|
|
13394
14245
|
//#region src/client/index.ts
|
|
13395
14246
|
/**
|
|
13396
14247
|
* dsh-vscode-mode client — 浏览器半入口:slot 注册 + 装配。
|
|
@@ -13418,6 +14269,30 @@ window.__ModuleLoader__.load({
|
|
|
13418
14269
|
"conversation",
|
|
13419
14270
|
"settingsScope"
|
|
13420
14271
|
];
|
|
14272
|
+
/** 指令桥装配幂等标记(同一 document 重复 apply 只装配一次,避免重复键位监听)。 */
|
|
14273
|
+
let commandsMounted = false;
|
|
14274
|
+
/**
|
|
14275
|
+
* 装配指令注册表(指令桥 + 命令栏)。
|
|
14276
|
+
* 指令桥不依赖已挂载编辑器(run 只派发窗口事件),故可在启动期装配;
|
|
14277
|
+
* 命令栏浮层的宿主由 CommandPalette 自己在编辑区树内认领。
|
|
14278
|
+
* @author ddj 2026年09月10号
|
|
14279
|
+
* @param ctx 客户端根上下文
|
|
14280
|
+
* @returns void
|
|
14281
|
+
*/
|
|
14282
|
+
function setupCommands(ctx) {
|
|
14283
|
+
if (commandsMounted) return;
|
|
14284
|
+
commandsMounted = true;
|
|
14285
|
+
const bridge = createCommandBridge();
|
|
14286
|
+
ctx.provide(REGISTRY_GLOBAL, bridge.registry);
|
|
14287
|
+
const host = window;
|
|
14288
|
+
host[REGISTRY_GLOBAL] = bridge.registry;
|
|
14289
|
+
ctx.effect(() => () => {
|
|
14290
|
+
bridge.dispose();
|
|
14291
|
+
commandsMounted = false;
|
|
14292
|
+
if (host["__edrvCommands__"] === bridge.registry) delete host[REGISTRY_GLOBAL];
|
|
14293
|
+
}, "vscode-mode: command registry");
|
|
14294
|
+
log.info("指令系统已装配:" + bridge.registry.list().length + " 条指令,Ctrl+Shift+P 打开命令栏");
|
|
14295
|
+
}
|
|
13421
14296
|
/**
|
|
13422
14297
|
* 装配客户端:注册中央编辑区视图与 header 差异角标。
|
|
13423
14298
|
* @author ddj 2026年08月20号
|
|
@@ -13425,6 +14300,7 @@ window.__ModuleLoader__.load({
|
|
|
13425
14300
|
*/
|
|
13426
14301
|
function apply(ctx) {
|
|
13427
14302
|
const schedule = (fn, ms) => ctx.timeout(fn, ms);
|
|
14303
|
+
setupCommands(ctx);
|
|
13428
14304
|
const registry = createFileOpenerRegistry();
|
|
13429
14305
|
const workspaces = ctx.get("workspaces");
|
|
13430
14306
|
const sessions = ctx.get("sessions");
|