dsh-vscode-mode 0.2.0 → 0.3.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 +14 -2
- package/lib/client.js +822 -59
- package/lib/client.js.map +1 -1
- package/lib/index.js +476 -19
- package/lib/index.js.map +1 -1
- package/package.json +2 -2
- package/src/client/commandBridge.ts +2 -0
- package/src/client/commandPaletteStore.ts +56 -9
- package/src/client/commandRegistry.ts +6 -0
- package/src/client/monaco/loader.ts +24 -0
- package/src/client/snippets/provider.ts +172 -0
- package/src/client/styles/editor.css +39 -2
- package/src/client/ui/CommandPalette.ts +43 -7
- package/src/client/ui/EditorView.ts +97 -3
- package/src/client/ui/SnippetsPicker.ts +296 -0
- package/src/client/ui/commandCatalog.ts +25 -0
- package/src/rpc.ts +78 -0
- package/src/shared/keybindings.ts +2 -0
- package/src/shared/rpc.ts +11 -0
- package/src/shared/snippets.ts +156 -0
- package/src/snippets.ts +427 -0
package/lib/client.js
CHANGED
|
@@ -32,7 +32,7 @@ window.__ModuleLoader__.load({
|
|
|
32
32
|
let react_dom_client = require("react-dom/client");
|
|
33
33
|
let _deepseek_ai_dsh_client_ui_primitives = require("@deepseek-ai/dsh-client-ui-primitives");
|
|
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/* 命令栏(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";
|
|
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 ⚠️ 浮层 z-index 阶梯(自下而上;改动务必保持顺序,tests/overlayZOrder.test.ts 守约):\n 编辑器内浮层 60(.edrv-search-pop) / 71(.edrv-ctxmenu)\n < 190 命令栏遮罩 < 200 命令栏\n < 195 片段浮窗遮罩 < 197 片段二级弹窗遮罩\n 命令栏必须**高于**片段浮窗:曾因片段遮罩(192) 压过命令栏(191),导致片段浮窗打开时\n 命令栏被整体盖住,按 Ctrl+Shift+P 因「已打开即早退」而毫无反应(表现为快捷键失效)。 */\n[data-edrv-view] .edrv-palette-mask { position: fixed; inset: 0; z-index: 190; background: rgba(0, 0, 0, .28); }\n[data-edrv-view] .edrv-palette { position: fixed; top: 12vh; left: 50%; transform: translateX(-50%); z-index: 200; width: min(580px, calc(100vw - 32px)); max-height: 64vh; display: flex; flex-direction: column; border-radius: 10px; background: var(--dsw-alias-bg-overlay, #ffffff); border: 1px solid var(--dsw-alias-border-l2, #cbd2d9); box-shadow: 0 12px 34px rgba(31, 41, 51, .24); overflow: hidden; }\n[data-edrv-view] .edrv-palette-input { height: 38px; flex: 0 0 auto; padding: 0 12px; border: none; border-bottom: 1px solid var(--dsw-alias-border-l1, #e0e6e8); background: transparent; color: var(--dsw-alias-label-primary, #1f2933); font-size: 13px; outline: none; }\n[data-edrv-view] .edrv-palette-list { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 4px; }\n[data-edrv-view] .edrv-palette-row { display: flex; align-items: center; gap: 8px; padding: 6px 10px; border-radius: 6px; font-size: 12px; color: var(--dsw-alias-label-primary, #1f2933); cursor: pointer; }\n[data-edrv-view] .edrv-palette-row.edrv-palette-sel { background: var(--dsw-alias-interactive-bg-hover, rgba(15, 157, 88, .10)); }\n[data-edrv-view] .edrv-palette-label { flex: 1 1 auto; min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-palette-cat { flex: 0 0 auto; font-size: 10px; padding: 1px 7px; border-radius: 999px; background: var(--dsw-alias-bg-layer-2, #f0f4f4); color: var(--dsw-alias-label-tertiary, #7b8794); }\n[data-edrv-view] .edrv-palette-key { flex: 0 0 auto; font-family: var(--ds-font-family-code, ui-monospace, monospace); font-size: 10px; padding: 1px 6px; border: 1px solid var(--dsw-alias-border-l1, #e0e6e8); border-radius: 5px; background: var(--dsw-alias-bg-layer-1, #f7f9fa); color: var(--dsw-alias-label-secondary, #52606d); }\n[data-edrv-view] .edrv-palette-empty { padding: 14px 10px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #7b8794); text-align: center; }\n[data-edrv-view] .edrv-palette-notice { flex: 0 0 auto; padding: 6px 10px; border-top: 1px solid var(--dsw-alias-border-l1, #e0e6e8); font-size: 11px; color: var(--dsw-alias-state-warn-primary, #b7791f); }\n\n/* 代码片段选择器(配置 / 插入):居中浮窗 + 新建二级弹窗。\n 卡片复用 mcp.css 的 .vsm-mcp-dialog(与「添加 MCP」「工作区选择」同一视觉语言),\n 此处只补遮罩、尺寸与列表布局。⚠️ 根节点须带 data-edrv-view,否则这些规则全部失配。 */\n[data-edrv-view] .edrv-snip-mask { position: fixed; inset: 0; z-index: 195; display: flex; align-items: center; justify-content: center; padding: 24px; box-sizing: border-box; background: var(--dsw-alias-bg-mask-drop, rgba(0, 0, 0, .55)); }\n/* 二级弹窗叠在一级浮窗之上(仍在命令栏之下,见上方阶梯说明) */\n[data-edrv-view] .edrv-snip-mask-top { z-index: 197; }\n[data-edrv-view] .edrv-snip-dialog { display: flex; flex-direction: column; overflow: hidden; width: min(620px, calc(100vw - 48px)); }\n[data-edrv-view] .edrv-snip-hint { margin: 0 0 12px; font-size: 12px; line-height: 1.6; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-list { display: flex; flex-direction: column; gap: 1px; min-height: 0; max-height: 46vh; overflow: auto; }\n[data-edrv-view] .edrv-snip-group { padding: 12px 2px 4px; font-size: 11px; font-weight: 600; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-row { display: flex; align-items: center; gap: 4px; width: 100%; box-sizing: border-box; padding: 2px; border: none; border-radius: 8px; background: transparent; text-align: left; color: var(--dsw-alias-label-primary, #e6e6e6); font: inherit; }\n[data-edrv-view] .edrv-snip-row:hover { background: var(--dsw-alias-interactive-bg-hover, rgba(255, 255, 255, .06)); }\n[data-edrv-view] button.edrv-snip-row { cursor: pointer; }\n[data-edrv-view] .edrv-snip-row-main { flex: 1 1 auto; min-width: 0; display: flex; flex-direction: column; gap: 2px; padding: 8px 10px; border: none; border-radius: 6px; background: transparent; text-align: left; cursor: pointer; color: inherit; font: inherit; }\n[data-edrv-view] .edrv-snip-label { font-size: 13px; font-weight: 600; color: var(--dsw-alias-label-primary, #e6e6e6); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-desc { font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }\n[data-edrv-view] .edrv-snip-src { flex: 0 0 auto; padding-right: 6px; font-size: 11px; color: var(--dsw-alias-label-tertiary, #9aa5b1); }\n[data-edrv-view] .edrv-snip-warn { flex: 0 0 auto; font-size: 11px; padding: 2px 7px; border-radius: 999px; background: var(--dsw-alias-state-warn-tertiary, rgba(229, 185, 63, .16)); color: var(--dsw-alias-state-warn-primary, #e5b93f); white-space: nowrap; }\n[data-edrv-view] .edrv-snip-act { flex: 0 0 auto; width: 26px; height: 26px; border: none; border-radius: 6px; background: transparent; color: var(--dsw-alias-label-tertiary, #9aa5b1); font-size: 13px; line-height: 1; cursor: pointer; }\n[data-edrv-view] .edrv-snip-act:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n[data-edrv-view] .edrv-snip-empty { padding: 12px 4px; font-size: 12px; color: var(--dsw-alias-label-tertiary, #9aa5b1); line-height: 1.6; }\n/* 当前文件语言提示条(片段按语言绑定,明确告知生效范围) */\n[data-edrv-view] .edrv-snip-langbar { display: flex; align-items: center; gap: 4px; flex-wrap: wrap; margin: 0 0 10px; padding: 8px 10px; border-radius: 6px; background: var(--dsw-alias-bg-layer-1, #2b2b2b); font-size: 12px; color: var(--dsw-alias-label-secondary, #aaa); }\n[data-edrv-view] .edrv-snip-langbar b { color: var(--dsw-alias-label-primary, #e6e6e6); }\n/* 二级弹窗的动作按钮(原生 .vsm-mcp-dialog-actions 已提供排版与按钮样式) */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-dialog-actions { flex-wrap: wrap; }\n/* 删除图标按钮:.vsm-danger 的规则全部限定在 .vsm-mcp-actions button 之下,裸用无样式,此处补自有类 */\n[data-edrv-view] .edrv-snip-act.edrv-snip-danger:hover { background: var(--dsw-alias-interactive-bg-hover-danger, rgba(217, 83, 79, .16)); color: var(--dsw-alias-state-error-primary, #f07878); }\n/* 浮窗内的原生空态(.vsm-mcp-empty 默认为整页尺寸)压缩为对话框尺寸 */\n[data-edrv-view] .edrv-snip-dialog .vsm-mcp-empty { padding: 26px 16px; border: 0; }\n\n\n\n\n";
|
|
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");
|
|
@@ -1481,7 +1481,8 @@ window.__ModuleLoader__.load({
|
|
|
1481
1481
|
properties: "ini",
|
|
1482
1482
|
json5: "jsonc",
|
|
1483
1483
|
log: "plaintext",
|
|
1484
|
-
txt: "plaintext"
|
|
1484
|
+
txt: "plaintext",
|
|
1485
|
+
"code-snippets": "json"
|
|
1485
1486
|
};
|
|
1486
1487
|
/**
|
|
1487
1488
|
* 路径 → Monaco language id:取 basename 扩展名(dockerfile/Dockerfile 特判)。
|
|
@@ -1496,6 +1497,26 @@ window.__ModuleLoader__.load({
|
|
|
1496
1497
|
if (dot <= 0) return "plaintext";
|
|
1497
1498
|
return LANG_BY_EXT[base.slice(dot + 1).toLowerCase()] ?? "plaintext";
|
|
1498
1499
|
}
|
|
1500
|
+
/** 片段文件后缀(判断「文件自身是片段文件」而非普通源码)。 */
|
|
1501
|
+
const SNIPPET_FILE_SUFFIX = ".code-snippets";
|
|
1502
|
+
/**
|
|
1503
|
+
* 片段文件 → 它绑定的语言 id(VS Code 文件名约定 `<language>.code-snippets`)。
|
|
1504
|
+
*
|
|
1505
|
+
* 为什么不能直接用 {@link langOf}:`.code-snippets` 本身在 LANG_BY_EXT 里映射为 json
|
|
1506
|
+
* (编辑片段文件时要按 JSON 高亮),于是 langOf('lua.code-snippets') 会得到 'json' 而不是
|
|
1507
|
+
* 'lua' —— 曾导致「新建」默认文件名被算成 `json.code-snippets`。故这里按片段命名约定
|
|
1508
|
+
* 单独解析:去掉 `.code-snippets` 后缀取语言前缀。
|
|
1509
|
+
*
|
|
1510
|
+
* @author ddj 2026年09月10号
|
|
1511
|
+
* @param path 片段文件路径
|
|
1512
|
+
* @returns 语言 id(`global.code-snippets` / 无法识别 → 空串 = 全语言)
|
|
1513
|
+
*/
|
|
1514
|
+
function snippetLanguageOf(path) {
|
|
1515
|
+
const base = String(path || "").split(/[\\/]/).pop() || "";
|
|
1516
|
+
if (!base.toLowerCase().endsWith(SNIPPET_FILE_SUFFIX)) return langOf(path);
|
|
1517
|
+
const lang = base.slice(0, -14).toLowerCase();
|
|
1518
|
+
return lang === "global" ? "" : lang;
|
|
1519
|
+
}
|
|
1499
1520
|
/**
|
|
1500
1521
|
* 加载 Monaco Editor(AMD 构建,随插件包离线分发):注入 loader.js → require.config → editor.main。
|
|
1501
1522
|
* @author ddj 2026年08月20号
|
|
@@ -2503,7 +2524,8 @@ window.__ModuleLoader__.load({
|
|
|
2503
2524
|
"edrv.prevTab": "Ctrl+Alt+ArrowLeft|Ctrl+PageUp",
|
|
2504
2525
|
"edrv.showCommands": "Ctrl+Shift+P|F1",
|
|
2505
2526
|
"edrv.nextEditorRow": "Ctrl+Alt+ArrowDown",
|
|
2506
|
-
"edrv.prevEditorRow": "Ctrl+Alt+ArrowUp"
|
|
2527
|
+
"edrv.prevEditorRow": "Ctrl+Alt+ArrowUp",
|
|
2528
|
+
"edrv.addSelectionRef": "Ctrl+U"
|
|
2507
2529
|
};
|
|
2508
2530
|
/**
|
|
2509
2531
|
* 返回默认键位的独立副本(调用方修改不污染目录)。
|
|
@@ -2598,6 +2620,23 @@ window.__ModuleLoader__.load({
|
|
|
2598
2620
|
};
|
|
2599
2621
|
}
|
|
2600
2622
|
/**
|
|
2623
|
+
* 添加选中内容为引用(把当前选区追加进对话输入框;无选区则状态栏提示)。
|
|
2624
|
+
* 有活动编辑器模型才可用,保证对话框内按 Ctrl+U 不被本命令吞掉。
|
|
2625
|
+
* @author ddj 2026年09月10号
|
|
2626
|
+
* @returns 命令定义
|
|
2627
|
+
*/
|
|
2628
|
+
function addSelectionRefDef() {
|
|
2629
|
+
return {
|
|
2630
|
+
id: "edrv.addSelectionRef",
|
|
2631
|
+
label: "添加选中内容为引用",
|
|
2632
|
+
category: "编辑",
|
|
2633
|
+
order: 10,
|
|
2634
|
+
keybinding: "Ctrl+U",
|
|
2635
|
+
available: needsModel,
|
|
2636
|
+
run: () => emit("addSelectionRef")
|
|
2637
|
+
};
|
|
2638
|
+
}
|
|
2639
|
+
/**
|
|
2601
2640
|
* 编辑器内置指令目录(顺序 = 快捷键设置页展示顺序)。
|
|
2602
2641
|
* 前置 8 条的键位由 EditorView / QuickOpen 自行 capture 监听(历史实现),
|
|
2603
2642
|
* 故不进 BRIDGE_COMMANDS,避免同一按键双执行。
|
|
@@ -2707,6 +2746,22 @@ window.__ModuleLoader__.load({
|
|
|
2707
2746
|
order: 30,
|
|
2708
2747
|
available: needsModel,
|
|
2709
2748
|
run: () => emit("openInExplorer")
|
|
2749
|
+
},
|
|
2750
|
+
{
|
|
2751
|
+
id: "edrv.configureSnippets",
|
|
2752
|
+
label: "代码片段:配置代码片段",
|
|
2753
|
+
category: "代码片段",
|
|
2754
|
+
order: 10,
|
|
2755
|
+
available: alwaysAvailable,
|
|
2756
|
+
run: () => emit("configureSnippets")
|
|
2757
|
+
},
|
|
2758
|
+
{
|
|
2759
|
+
id: "edrv.insertSnippet",
|
|
2760
|
+
label: "插入代码片段",
|
|
2761
|
+
category: "代码片段",
|
|
2762
|
+
order: 20,
|
|
2763
|
+
available: needsModel,
|
|
2764
|
+
run: () => emit("insertSnippet")
|
|
2710
2765
|
}
|
|
2711
2766
|
];
|
|
2712
2767
|
/**
|
|
@@ -2714,7 +2769,11 @@ window.__ModuleLoader__.load({
|
|
|
2714
2769
|
* 新增「只填目录、不写监听」的编辑器指令一律放这里:键位、命令栏、设置页自动可用。
|
|
2715
2770
|
* @author ddj 2026年09月10号
|
|
2716
2771
|
*/
|
|
2717
|
-
const BRIDGE_COMMANDS = [
|
|
2772
|
+
const BRIDGE_COMMANDS = [
|
|
2773
|
+
nextEditorRowDef(),
|
|
2774
|
+
prevEditorRowDef(),
|
|
2775
|
+
addSelectionRefDef()
|
|
2776
|
+
];
|
|
2718
2777
|
/**
|
|
2719
2778
|
* 命令栏自身的命令(避免循环依赖,由 commandBridge 注入 run 后注册)。
|
|
2720
2779
|
* @author ddj 2026年09月10号
|
|
@@ -3253,6 +3312,10 @@ window.__ModuleLoader__.load({
|
|
|
3253
3312
|
get: (id) => entries.get(id),
|
|
3254
3313
|
list,
|
|
3255
3314
|
available,
|
|
3315
|
+
isAvailable: (id) => {
|
|
3316
|
+
const command = entries.get(id);
|
|
3317
|
+
return command !== void 0 && isAvailable$1(command);
|
|
3318
|
+
},
|
|
3256
3319
|
match: (query) => filterCommands(available(), query),
|
|
3257
3320
|
run(id) {
|
|
3258
3321
|
const command = entries.get(id);
|
|
@@ -3272,8 +3335,12 @@ window.__ModuleLoader__.load({
|
|
|
3272
3335
|
let registryTable = null;
|
|
3273
3336
|
/** 命令栏是否展开。 */
|
|
3274
3337
|
let opened = false;
|
|
3338
|
+
/** 唤起序号:每次 openCommandPalette 递增(含已打开时的重复唤起),驱动重新聚焦。 */
|
|
3339
|
+
let openSeq = 0;
|
|
3275
3340
|
/** 当前真正渲染浮层的宿主令牌(null = 无宿主)。 */
|
|
3276
3341
|
let hostToken = null;
|
|
3342
|
+
/** 宿主令牌版本:每次释放认领递增,驱动其余实例重试认领(宿主更替后自愈)。 */
|
|
3343
|
+
let hostRev = 0;
|
|
3277
3344
|
/** 注入的命令执行器(commandBridge 装配时写入)。 */
|
|
3278
3345
|
let runner = null;
|
|
3279
3346
|
/** 打开命令栏前的焦点元素(关闭后归还焦点,键盘操作不中断)。 */
|
|
@@ -3344,17 +3411,36 @@ window.__ModuleLoader__.load({
|
|
|
3344
3411
|
focusBack = active instanceof HTMLElement ? active : null;
|
|
3345
3412
|
}
|
|
3346
3413
|
/**
|
|
3347
|
-
*
|
|
3414
|
+
* 打开命令栏(记录当前焦点供关闭后归还)。
|
|
3415
|
+
*
|
|
3416
|
+
* 已打开时**不是空操作**:递增 openSeq 并通知订阅者,让命令栏重新获得焦点。
|
|
3417
|
+
* 事故驱动:片段浮窗遮罩曾压在命令栏之上,此时命令栏处于「已打开但看不见」状态;
|
|
3418
|
+
* 旧实现 `if (opened) return` 让快捷键毫无反应(用户报「调不出来」)。
|
|
3419
|
+
* 递增 seq 使每次触发都有可观测响应(重聚焦 + 重新置顶)。
|
|
3348
3420
|
* @author ddj 2026年09月10号
|
|
3349
3421
|
* @param reason 唤起来源(键盘/命令/外部 API)
|
|
3350
3422
|
*/
|
|
3351
3423
|
function openCommandPalette(reason = "keybinding") {
|
|
3352
|
-
if (opened)
|
|
3424
|
+
if (opened) {
|
|
3425
|
+
openSeq += 1;
|
|
3426
|
+
notifyPalette();
|
|
3427
|
+
return;
|
|
3428
|
+
}
|
|
3353
3429
|
rememberFocus();
|
|
3354
3430
|
opened = true;
|
|
3431
|
+
openSeq += 1;
|
|
3355
3432
|
notifyPalette();
|
|
3356
3433
|
}
|
|
3357
3434
|
/**
|
|
3435
|
+
* 命令栏唤起序号(每次 open 调用递增,含「已打开时的重复唤起」)。
|
|
3436
|
+
* useSyncExternalStore 快照用它感知「重复唤起」,从而重新聚焦输入框。
|
|
3437
|
+
* @author ddj 2026年09月10号
|
|
3438
|
+
* @returns 当前序号
|
|
3439
|
+
*/
|
|
3440
|
+
function paletteOpenSeq() {
|
|
3441
|
+
return openSeq;
|
|
3442
|
+
}
|
|
3443
|
+
/**
|
|
3358
3444
|
* 关闭命令栏并归还焦点。
|
|
3359
3445
|
* @author ddj 2026年09月10号
|
|
3360
3446
|
*/
|
|
@@ -3370,23 +3456,41 @@ window.__ModuleLoader__.load({
|
|
|
3370
3456
|
} catch {}
|
|
3371
3457
|
}
|
|
3372
3458
|
/**
|
|
3373
|
-
*
|
|
3459
|
+
* 认领命令栏宿主:成功返回**令牌本身**(调用方须原样持有并在卸载时传回),
|
|
3460
|
+
* 已被他人认领时返回 null。
|
|
3461
|
+
*
|
|
3462
|
+
* ⚠️ 必须返回 internal 存下的同一个对象:旧实现返回 boolean、由调用方自行 `{}` 造令牌,
|
|
3463
|
+
* 导致 `releasePaletteHost` 的身份校验恒不通过 → hostToken 永久泄漏 → 之后**任何**实例
|
|
3464
|
+
* 都认领失败、无人渲染浮层(表现为 Ctrl+Shift+P「完全没有反应」且永不恢复)。
|
|
3374
3465
|
* @author ddj 2026年09月10号
|
|
3375
|
-
* @returns
|
|
3466
|
+
* @returns 认领令牌;null 表示已有宿主
|
|
3376
3467
|
*/
|
|
3377
3468
|
function claimPaletteHost() {
|
|
3378
|
-
if (hostToken !== null) return
|
|
3379
|
-
|
|
3380
|
-
|
|
3469
|
+
if (hostToken !== null) return null;
|
|
3470
|
+
const token = {};
|
|
3471
|
+
hostToken = token;
|
|
3472
|
+
return token;
|
|
3381
3473
|
}
|
|
3382
3474
|
/**
|
|
3383
3475
|
* 释放宿主认领(仅持有者可释放,卸载顺序错乱不会顶掉新宿主)。
|
|
3476
|
+
* 释放成功后通知订阅者,让等待中的实例**重新尝试认领**(自愈,避免宿主更替后无人渲染)。
|
|
3384
3477
|
* @author ddj 2026年09月10号
|
|
3385
|
-
* @param token 认领令牌(null
|
|
3478
|
+
* @param token 认领令牌(null = 本实例未认领)
|
|
3386
3479
|
*/
|
|
3387
3480
|
function releasePaletteHost(token) {
|
|
3388
3481
|
if (token === null || hostToken !== token) return;
|
|
3389
3482
|
hostToken = null;
|
|
3483
|
+
hostRev += 1;
|
|
3484
|
+
notifyPalette();
|
|
3485
|
+
}
|
|
3486
|
+
/**
|
|
3487
|
+
* 宿主令牌版本(每次释放认领递增)。非宿主实例订阅它,在宿主更替后重试认领 ——
|
|
3488
|
+
* 否则先挂载的实例卸载后无人接管,快捷键会「完全没有反应」且永不恢复。
|
|
3489
|
+
* @author ddj 2026年09月10号
|
|
3490
|
+
* @returns 当前版本号
|
|
3491
|
+
*/
|
|
3492
|
+
function paletteHostRev() {
|
|
3493
|
+
return hostRev;
|
|
3390
3494
|
}
|
|
3391
3495
|
//#endregion
|
|
3392
3496
|
//#region src/client/ui/CommandPalette.ts
|
|
@@ -3434,22 +3538,52 @@ window.__ModuleLoader__.load({
|
|
|
3434
3538
|
*/
|
|
3435
3539
|
function CommandPalette() {
|
|
3436
3540
|
const open = react.default.useSyncExternalStore(subscribePalette, isPaletteOpen);
|
|
3541
|
+
const openSeq = react.default.useSyncExternalStore(subscribePalette, paletteOpenSeq);
|
|
3542
|
+
const hostRev = react.default.useSyncExternalStore(subscribePalette, paletteHostRev);
|
|
3437
3543
|
const registry = useRegistry();
|
|
3438
|
-
const [token] = react.default.useState(
|
|
3544
|
+
const [token, setToken] = react.default.useState(null);
|
|
3439
3545
|
const [query, setQuery] = react.default.useState("");
|
|
3440
3546
|
const [selected, setSelected] = react.default.useState(0);
|
|
3441
3547
|
const [notice, setNotice] = react.default.useState("");
|
|
3442
3548
|
const inputRef = react.default.useRef(null);
|
|
3549
|
+
const tokenRef = react.default.useRef(null);
|
|
3443
3550
|
const host = token !== null;
|
|
3444
|
-
|
|
3551
|
+
/**
|
|
3552
|
+
* 认领宿主:放在 effect(不在 render 期做副作用 —— StrictMode 双调用会让首次认领
|
|
3553
|
+
* 被判定失败而永久无人渲染)。hostRev 变化(有实例释放了宿主)时重试认领。
|
|
3554
|
+
*
|
|
3555
|
+
* ⚠️ 此处**不**做 cleanup 释放:releasePaletteHost 会通知订阅者(hostRev 变化),
|
|
3556
|
+
* 若在依赖 hostRev 的 effect 里释放,会「释放→通知→重跑→再释放」自激循环。
|
|
3557
|
+
* 释放统一交给下面的「仅卸载时」effect。
|
|
3558
|
+
*/
|
|
3445
3559
|
react.default.useEffect(() => {
|
|
3446
|
-
if (
|
|
3560
|
+
if (tokenRef.current) return;
|
|
3561
|
+
const claimed = claimPaletteHost();
|
|
3562
|
+
if (!claimed) return;
|
|
3563
|
+
tokenRef.current = claimed;
|
|
3564
|
+
setToken(claimed);
|
|
3565
|
+
}, [hostRev]);
|
|
3566
|
+
/** 仅卸载时释放宿主;释放后 store 通知其余实例接管(自愈)。 */
|
|
3567
|
+
react.default.useEffect(() => () => {
|
|
3568
|
+
releasePaletteHost(tokenRef.current);
|
|
3569
|
+
tokenRef.current = null;
|
|
3570
|
+
}, []);
|
|
3571
|
+
react.default.useEffect(() => {
|
|
3572
|
+
if (!open) return;
|
|
3447
3573
|
setQuery("");
|
|
3448
3574
|
setSelected(0);
|
|
3449
3575
|
setNotice("");
|
|
3450
|
-
const timer = setTimeout(() => inputRef.current?.focus(), 0);
|
|
3451
|
-
return () => clearTimeout(timer);
|
|
3452
3576
|
}, [open]);
|
|
3577
|
+
react.default.useEffect(() => {
|
|
3578
|
+
if (!open) return void 0;
|
|
3579
|
+
const timer = setTimeout(() => {
|
|
3580
|
+
const input = inputRef.current;
|
|
3581
|
+
if (!input) return;
|
|
3582
|
+
input.focus();
|
|
3583
|
+
input.select?.();
|
|
3584
|
+
}, 0);
|
|
3585
|
+
return () => clearTimeout(timer);
|
|
3586
|
+
}, [open, openSeq]);
|
|
3453
3587
|
const rows = react.default.useMemo(() => open && host ? rowsOf(registry, query) : [], [
|
|
3454
3588
|
open,
|
|
3455
3589
|
host,
|
|
@@ -4770,7 +4904,7 @@ window.__ModuleLoader__.load({
|
|
|
4770
4904
|
}
|
|
4771
4905
|
}
|
|
4772
4906
|
const SYNC_DEBOUNCE_MS = 250;
|
|
4773
|
-
let sessionId;
|
|
4907
|
+
let sessionId$1;
|
|
4774
4908
|
const syncTimers = /* @__PURE__ */ new Map();
|
|
4775
4909
|
let statusCache = {
|
|
4776
4910
|
servers: [],
|
|
@@ -4779,8 +4913,8 @@ window.__ModuleLoader__.load({
|
|
|
4779
4913
|
let progressListeners = /* @__PURE__ */ new Set();
|
|
4780
4914
|
/** 设置当前会话(切换会话时清理旧文档跟踪由 host 端 session/disposed 兜底)。 */
|
|
4781
4915
|
function setLspSession(id) {
|
|
4782
|
-
if (sessionId === id) return;
|
|
4783
|
-
sessionId = id;
|
|
4916
|
+
if (sessionId$1 === id) return;
|
|
4917
|
+
sessionId$1 = id;
|
|
4784
4918
|
refreshStatus();
|
|
4785
4919
|
}
|
|
4786
4920
|
/** 订阅 LSP 状态变化(服务器进度/启动状态)。 */
|
|
@@ -4801,7 +4935,7 @@ window.__ModuleLoader__.load({
|
|
|
4801
4935
|
if (immediate) {
|
|
4802
4936
|
clearPending(path);
|
|
4803
4937
|
await rpc("edrv.lsp.sync", {
|
|
4804
|
-
sessionId,
|
|
4938
|
+
sessionId: sessionId$1,
|
|
4805
4939
|
path,
|
|
4806
4940
|
text,
|
|
4807
4941
|
version: Date.now()
|
|
@@ -4812,7 +4946,7 @@ window.__ModuleLoader__.load({
|
|
|
4812
4946
|
syncTimers.set(path, setTimeout(() => {
|
|
4813
4947
|
syncTimers.delete(path);
|
|
4814
4948
|
rpc("edrv.lsp.sync", {
|
|
4815
|
-
sessionId,
|
|
4949
|
+
sessionId: sessionId$1,
|
|
4816
4950
|
path,
|
|
4817
4951
|
text,
|
|
4818
4952
|
version: Date.now()
|
|
@@ -4830,7 +4964,7 @@ window.__ModuleLoader__.load({
|
|
|
4830
4964
|
function closeDoc(path) {
|
|
4831
4965
|
clearPending(path);
|
|
4832
4966
|
rpc("edrv.lsp.close", {
|
|
4833
|
-
sessionId,
|
|
4967
|
+
sessionId: sessionId$1,
|
|
4834
4968
|
path
|
|
4835
4969
|
}).catch(() => {});
|
|
4836
4970
|
}
|
|
@@ -4838,7 +4972,7 @@ window.__ModuleLoader__.load({
|
|
|
4838
4972
|
async function findDefinition(path, text, position) {
|
|
4839
4973
|
await syncDoc(path, text, true);
|
|
4840
4974
|
const res = await rpc("edrv.lsp.definition", {
|
|
4841
|
-
sessionId,
|
|
4975
|
+
sessionId: sessionId$1,
|
|
4842
4976
|
path,
|
|
4843
4977
|
position: monoToLsp(position.lineNumber, position.column)
|
|
4844
4978
|
}).catch(() => null);
|
|
@@ -4849,7 +4983,7 @@ window.__ModuleLoader__.load({
|
|
|
4849
4983
|
async function findReferences(path, text, position, includeDeclaration = false) {
|
|
4850
4984
|
await syncDoc(path, text, true);
|
|
4851
4985
|
const res = await rpc("edrv.lsp.references", {
|
|
4852
|
-
sessionId,
|
|
4986
|
+
sessionId: sessionId$1,
|
|
4853
4987
|
path,
|
|
4854
4988
|
position: monoToLsp(position.lineNumber, position.column),
|
|
4855
4989
|
includeDeclaration
|
|
@@ -4861,7 +4995,7 @@ window.__ModuleLoader__.load({
|
|
|
4861
4995
|
async function fetchDocumentSymbols(path, text) {
|
|
4862
4996
|
await syncDoc(path, text, true);
|
|
4863
4997
|
const res = await rpc("edrv.lsp.documentSymbol", {
|
|
4864
|
-
sessionId,
|
|
4998
|
+
sessionId: sessionId$1,
|
|
4865
4999
|
path
|
|
4866
5000
|
}).catch(() => null);
|
|
4867
5001
|
if (!res || !res.ok || !Array.isArray(res.symbols)) return [];
|
|
@@ -4871,7 +5005,7 @@ window.__ModuleLoader__.load({
|
|
|
4871
5005
|
async function fetchHover(path, text, position) {
|
|
4872
5006
|
await syncDoc(path, text, true);
|
|
4873
5007
|
const res = await rpc("edrv.lsp.hover", {
|
|
4874
|
-
sessionId,
|
|
5008
|
+
sessionId: sessionId$1,
|
|
4875
5009
|
path,
|
|
4876
5010
|
position: monoToLsp(position.lineNumber, position.column)
|
|
4877
5011
|
}).catch(() => null);
|
|
@@ -4882,7 +5016,7 @@ window.__ModuleLoader__.load({
|
|
|
4882
5016
|
async function fetchSemanticTokens(path, text) {
|
|
4883
5017
|
await syncDoc(path, text, true);
|
|
4884
5018
|
const res = await rpc("edrv.lsp.semanticTokens", {
|
|
4885
|
-
sessionId,
|
|
5019
|
+
sessionId: sessionId$1,
|
|
4886
5020
|
path
|
|
4887
5021
|
}).catch(() => null);
|
|
4888
5022
|
if (!res || !res.ok || !res.tokens || !Array.isArray(res.tokens.data)) return null;
|
|
@@ -4891,7 +5025,7 @@ window.__ModuleLoader__.load({
|
|
|
4891
5025
|
/** 拉取服务器状态(带 5s 缓存)。 */
|
|
4892
5026
|
async function refreshStatus(force = false) {
|
|
4893
5027
|
if (!force && Date.now() - statusCache.at < 1500) return statusCache.servers;
|
|
4894
|
-
const res = await rpc("edrv.lsp.status", { sessionId }).catch(() => null);
|
|
5028
|
+
const res = await rpc("edrv.lsp.status", { sessionId: sessionId$1 }).catch(() => null);
|
|
4895
5029
|
const servers = res && res.ok && Array.isArray(res.servers) ? res.servers : [];
|
|
4896
5030
|
statusCache = {
|
|
4897
5031
|
servers,
|
|
@@ -5001,7 +5135,7 @@ window.__ModuleLoader__.load({
|
|
|
5001
5135
|
tokenTypes: [...LSP_SEMANTIC_TOKEN_TYPES],
|
|
5002
5136
|
tokenModifiers: [...LSP_SEMANTIC_TOKEN_MODIFIERS]
|
|
5003
5137
|
};
|
|
5004
|
-
let registered$
|
|
5138
|
+
let registered$2 = false;
|
|
5005
5139
|
const disposables = [];
|
|
5006
5140
|
/** 目标文件打开并定位(复用现有 openFileAt 的 edrv:open-editor 事件通道)。 */
|
|
5007
5141
|
function openAt(path, line, column) {
|
|
@@ -5018,8 +5152,8 @@ window.__ModuleLoader__.load({
|
|
|
5018
5152
|
}
|
|
5019
5153
|
/** 注册全部 Monaco LSP provider 与文档跟踪(幂等)。 */
|
|
5020
5154
|
function registerLspProviders(monaco) {
|
|
5021
|
-
if (registered$
|
|
5022
|
-
registered$
|
|
5155
|
+
if (registered$2) return;
|
|
5156
|
+
registered$2 = true;
|
|
5023
5157
|
const attachModel = (model) => {
|
|
5024
5158
|
if (!model || model.uri.scheme !== "edrv") return;
|
|
5025
5159
|
const path = pathOfModel(model);
|
|
@@ -5264,7 +5398,7 @@ window.__ModuleLoader__.load({
|
|
|
5264
5398
|
* 数据来源于语义 token(每 model+version 缓存 60s),不做逐词 LSP 查询。
|
|
5265
5399
|
* 作者 ddj 2026-09-02
|
|
5266
5400
|
*/
|
|
5267
|
-
const CACHE_TTL_MS$
|
|
5401
|
+
const CACHE_TTL_MS$2 = 6e4;
|
|
5268
5402
|
/**
|
|
5269
5403
|
* 给一个 Monaco 编辑器绑定 Ctrl+hover 下划线提示(幂等)。
|
|
5270
5404
|
* @author ddj 2026年09月02号
|
|
@@ -5294,7 +5428,7 @@ window.__ModuleLoader__.load({
|
|
|
5294
5428
|
const rangesOf = async (model) => {
|
|
5295
5429
|
const path = pathOfModel(model);
|
|
5296
5430
|
const version = model.getVersionId?.() ?? 0;
|
|
5297
|
-
if (cache.path === path && cache.version === version && cache.ranges && Date.now() - cache.at < CACHE_TTL_MS$
|
|
5431
|
+
if (cache.path === path && cache.version === version && cache.ranges && Date.now() - cache.at < CACHE_TTL_MS$2) return cache.ranges;
|
|
5298
5432
|
const res = await fetchSemanticTokens(path, model.getValue()).catch(() => null);
|
|
5299
5433
|
const ranges = res && Array.isArray(res.data) ? decodeSemanticTokens(res.data) : [];
|
|
5300
5434
|
cache = {
|
|
@@ -5437,12 +5571,12 @@ window.__ModuleLoader__.load({
|
|
|
5437
5571
|
/** 缓存容量上限(LRU 超限即整体清空;键空间小,够用)。 */
|
|
5438
5572
|
const CACHE_MAX = 30;
|
|
5439
5573
|
/** 缓存 TTL(毫秒)。 */
|
|
5440
|
-
const CACHE_TTL_MS = 6e4;
|
|
5441
|
-
let registered = false;
|
|
5574
|
+
const CACHE_TTL_MS$1 = 6e4;
|
|
5575
|
+
let registered$1 = false;
|
|
5442
5576
|
let seq = 0;
|
|
5443
5577
|
let inFlight = null;
|
|
5444
5578
|
let debounceTimer = null;
|
|
5445
|
-
const cache = /* @__PURE__ */ new Map();
|
|
5579
|
+
const cache$1 = /* @__PURE__ */ new Map();
|
|
5446
5580
|
/** 上次开关状态(configUpdate 后经事件刷新,关闭时立即静默)。 */
|
|
5447
5581
|
let enabled = false;
|
|
5448
5582
|
/** 供设置面板保存后同步开关状态(不重载页面即时生效)。 */
|
|
@@ -5451,7 +5585,7 @@ window.__ModuleLoader__.load({
|
|
|
5451
5585
|
emitAiStatus("config", { enabled });
|
|
5452
5586
|
if (!enabled) {
|
|
5453
5587
|
seq += 1;
|
|
5454
|
-
cache.clear();
|
|
5588
|
+
cache$1.clear();
|
|
5455
5589
|
}
|
|
5456
5590
|
}
|
|
5457
5591
|
/** 当前开关(EditorView 装配时决定是否注册)。 */
|
|
@@ -5492,8 +5626,8 @@ window.__ModuleLoader__.load({
|
|
|
5492
5626
|
* @param monaco window.monaco
|
|
5493
5627
|
*/
|
|
5494
5628
|
function registerAiInline(monaco) {
|
|
5495
|
-
if (registered || !monaco?.languages?.registerInlineCompletionsProvider) return;
|
|
5496
|
-
registered = true;
|
|
5629
|
+
if (registered$1 || !monaco?.languages?.registerInlineCompletionsProvider) return;
|
|
5630
|
+
registered$1 = true;
|
|
5497
5631
|
monaco.languages.registerInlineCompletionsProvider("*", {
|
|
5498
5632
|
async provideInlineCompletions(model, position, context, token) {
|
|
5499
5633
|
const t0 = Date.now();
|
|
@@ -5507,8 +5641,8 @@ window.__ModuleLoader__.load({
|
|
|
5507
5641
|
const trimmed = trimInlineWindow(value.slice(0, offset), value.slice(offset));
|
|
5508
5642
|
if (!inlineWorth(trimmed.prefix)) return { items: [] };
|
|
5509
5643
|
const key = cacheKey(path, position.lineNumber, position.column, trimmed.prefix);
|
|
5510
|
-
const hit = cache.get(key);
|
|
5511
|
-
if (hit && Date.now() - hit.at < CACHE_TTL_MS) return hit.items.length ? { items: hit.items } : { items: [] };
|
|
5644
|
+
const hit = cache$1.get(key);
|
|
5645
|
+
if (hit && Date.now() - hit.at < CACHE_TTL_MS$1) return hit.items.length ? { items: hit.items } : { items: [] };
|
|
5512
5646
|
return new Promise((resolve) => {
|
|
5513
5647
|
seq += 1;
|
|
5514
5648
|
const mySeq = seq;
|
|
@@ -5543,7 +5677,7 @@ window.__ModuleLoader__.load({
|
|
|
5543
5677
|
signal: controller.signal
|
|
5544
5678
|
})).json();
|
|
5545
5679
|
if (mySeq !== seq || !data?.ok || typeof data.text !== "string" || !data.text) {
|
|
5546
|
-
cache.set(key, {
|
|
5680
|
+
cache$1.set(key, {
|
|
5547
5681
|
items: [],
|
|
5548
5682
|
at: Date.now()
|
|
5549
5683
|
});
|
|
@@ -5583,8 +5717,8 @@ window.__ModuleLoader__.load({
|
|
|
5583
5717
|
}
|
|
5584
5718
|
/** 缓存写入(超限整体清空,LRU 简化)。 */
|
|
5585
5719
|
function cacheSet(key, items) {
|
|
5586
|
-
if (cache.size >= CACHE_MAX) cache.clear();
|
|
5587
|
-
cache.set(key, {
|
|
5720
|
+
if (cache$1.size >= CACHE_MAX) cache$1.clear();
|
|
5721
|
+
cache$1.set(key, {
|
|
5588
5722
|
items,
|
|
5589
5723
|
at: Date.now()
|
|
5590
5724
|
});
|
|
@@ -5594,7 +5728,7 @@ window.__ModuleLoader__.load({
|
|
|
5594
5728
|
/** EditorView 装配后调用(注册 provider + 初始化开关)。 */
|
|
5595
5729
|
function setupAiInline(monaco) {
|
|
5596
5730
|
monacoRef = monaco && { activeEditor: null };
|
|
5597
|
-
if (!registered) registerAiInline(monaco);
|
|
5731
|
+
if (!registered$1) registerAiInline(monaco);
|
|
5598
5732
|
initAiInlineState();
|
|
5599
5733
|
}
|
|
5600
5734
|
/** EditorView 每次创建/切换编辑器实例时刷新引用。 */
|
|
@@ -5602,6 +5736,551 @@ window.__ModuleLoader__.load({
|
|
|
5602
5736
|
if (monacoRef) monacoRef.activeEditor = editor;
|
|
5603
5737
|
}
|
|
5604
5738
|
//#endregion
|
|
5739
|
+
//#region src/client/snippets/provider.ts
|
|
5740
|
+
/**
|
|
5741
|
+
* dsh-vscode-mode client — 代码片段补全 provider(Monaco IntelliSense)。
|
|
5742
|
+
* 数据源:host snippets.entries(全局 ~/.dsh/snippets + 当前工作区 <工作区>/.dsh/snippets),
|
|
5743
|
+
* 条目按 model 语言过滤(language 空串 = 全语言);条目主体交给 Monaco 片段语法解析
|
|
5744
|
+
* (${1:占位} / $TM_FILENAME 等由 InsertAsSnippet 规则展开)。
|
|
5745
|
+
* 性能:条目模块级缓存 + TTL,不在每次按键打 RPC(与 ai/inlineProvider 的去抖策略异曲同工,
|
|
5746
|
+
* 但片段是本地小表,缓存足矣);edrv:snippets-changed(配置文件保存后)强制失效。
|
|
5747
|
+
* 作者 ddj 2026年09月10号
|
|
5748
|
+
*/
|
|
5749
|
+
/** 条目缓存 TTL(毫秒):片段文件本就只在用户编辑时变化。 */
|
|
5750
|
+
const CACHE_TTL_MS = 1e4;
|
|
5751
|
+
/** 补全候选上限(超大片段库下防拖慢渲染)。 */
|
|
5752
|
+
const MAX_ITEMS = 200;
|
|
5753
|
+
/** 已加载条目缓存(null = 未加载/已失效)。 */
|
|
5754
|
+
let cache = null;
|
|
5755
|
+
let cacheAt = 0;
|
|
5756
|
+
let pending = null;
|
|
5757
|
+
let registered = false;
|
|
5758
|
+
/** 当前会话 id(补全按会话工作区叠加项目片段;EditorView 装配时注入)。 */
|
|
5759
|
+
let sessionId = null;
|
|
5760
|
+
/**
|
|
5761
|
+
* 设置当前会话(会话切换时更新;缓存一并失效,使项目片段跟随工作区)。
|
|
5762
|
+
* @author ddj 2026年09月10号
|
|
5763
|
+
* @param id 会话 id
|
|
5764
|
+
*/
|
|
5765
|
+
function setSnippetsSession(id) {
|
|
5766
|
+
if (sessionId === id) return;
|
|
5767
|
+
sessionId = id;
|
|
5768
|
+
invalidateSnippets();
|
|
5769
|
+
}
|
|
5770
|
+
/**
|
|
5771
|
+
* 失效条目缓存(配置文件保存/会话切换后调用)。
|
|
5772
|
+
* @author ddj 2026年09月10号
|
|
5773
|
+
*/
|
|
5774
|
+
function invalidateSnippets() {
|
|
5775
|
+
cache = null;
|
|
5776
|
+
cacheAt = 0;
|
|
5777
|
+
pending = null;
|
|
5778
|
+
}
|
|
5779
|
+
/**
|
|
5780
|
+
* 读取条目(带缓存与在飞去重);失败返回空表(补全静默降级,不打断输入)。
|
|
5781
|
+
* @author ddj 2026年09月10号
|
|
5782
|
+
* @returns 片段条目数组
|
|
5783
|
+
*/
|
|
5784
|
+
async function loadEntries() {
|
|
5785
|
+
if (cache && Date.now() - cacheAt < CACHE_TTL_MS) return cache;
|
|
5786
|
+
if (pending) return pending;
|
|
5787
|
+
pending = rpc("snippets.entries", { sessionId }).then((res) => {
|
|
5788
|
+
const entries = res && res.ok && Array.isArray(res.entries) ? res.entries : [];
|
|
5789
|
+
cache = entries;
|
|
5790
|
+
cacheAt = Date.now();
|
|
5791
|
+
return entries;
|
|
5792
|
+
}).catch(() => {
|
|
5793
|
+
cache = [];
|
|
5794
|
+
cacheAt = Date.now();
|
|
5795
|
+
return cache;
|
|
5796
|
+
}).finally(() => {
|
|
5797
|
+
pending = null;
|
|
5798
|
+
});
|
|
5799
|
+
return pending;
|
|
5800
|
+
}
|
|
5801
|
+
/**
|
|
5802
|
+
* 按语言过滤条目:条目语言为空(全语言)或与 model 语言一致即命中。
|
|
5803
|
+
* 项目片段(scope=project)排在全局之后去重,同名同前缀时项目优先。
|
|
5804
|
+
* @author ddj 2026年09月10号
|
|
5805
|
+
* @param entries 全部条目
|
|
5806
|
+
* @param languageId 当前模型语言
|
|
5807
|
+
* @returns 生效条目(项目优先,已去重)
|
|
5808
|
+
*/
|
|
5809
|
+
function entriesForLanguage(entries, languageId) {
|
|
5810
|
+
const lang = String(languageId ?? "").toLowerCase();
|
|
5811
|
+
const global = [];
|
|
5812
|
+
const project = [];
|
|
5813
|
+
for (const entry of entries) {
|
|
5814
|
+
const entryLang = String(entry?.language ?? "").toLowerCase();
|
|
5815
|
+
if (entryLang && entryLang !== lang) continue;
|
|
5816
|
+
if (entry?.scope === "project") project.push(entry);
|
|
5817
|
+
else global.push(entry);
|
|
5818
|
+
}
|
|
5819
|
+
const projectKeys = new Set(project.map((entry) => entry.key));
|
|
5820
|
+
return global.filter((entry) => !projectKeys.has(entry.key)).concat(project).slice(0, MAX_ITEMS);
|
|
5821
|
+
}
|
|
5822
|
+
/**
|
|
5823
|
+
* 注册代码片段补全 provider(幂等;Monaco 就绪后调用一次)。
|
|
5824
|
+
* @author ddj 2026年09月10号
|
|
5825
|
+
* @param monaco window.monaco
|
|
5826
|
+
*/
|
|
5827
|
+
function registerSnippetProvider(monaco) {
|
|
5828
|
+
if (registered || !monaco?.languages?.registerCompletionItemProvider) return;
|
|
5829
|
+
const snippetKind = monaco.languages.CompletionItemKind?.Snippet;
|
|
5830
|
+
const asSnippet = monaco.languages.CompletionItemInsertTextRule?.InsertAsSnippet;
|
|
5831
|
+
if (typeof snippetKind !== "number" || typeof asSnippet !== "number") return;
|
|
5832
|
+
registered = true;
|
|
5833
|
+
monaco.languages.registerCompletionItemProvider("*", { async provideCompletionItems(model, position) {
|
|
5834
|
+
const entries = await loadEntries();
|
|
5835
|
+
if (!entries.length) return { suggestions: [] };
|
|
5836
|
+
const items = entriesForLanguage(entries, model?.getLanguageId?.());
|
|
5837
|
+
if (!items.length) return { suggestions: [] };
|
|
5838
|
+
const word = model.getWordUntilPosition(position);
|
|
5839
|
+
const range = {
|
|
5840
|
+
startLineNumber: position.lineNumber,
|
|
5841
|
+
endLineNumber: position.lineNumber,
|
|
5842
|
+
startColumn: word.startColumn,
|
|
5843
|
+
endColumn: word.endColumn
|
|
5844
|
+
};
|
|
5845
|
+
return { suggestions: items.map((entry) => ({
|
|
5846
|
+
label: entry.prefix || entry.key,
|
|
5847
|
+
insertText: entry.body,
|
|
5848
|
+
detail: (entry.scope === "project" ? "项目片段 · " : "全局片段 · ") + entry.file,
|
|
5849
|
+
documentation: entry.description || entry.key,
|
|
5850
|
+
kind: snippetKind,
|
|
5851
|
+
insertTextRules: asSnippet,
|
|
5852
|
+
filterText: entry.prefix || entry.key,
|
|
5853
|
+
range
|
|
5854
|
+
})).filter((item) => Boolean(item.label)) };
|
|
5855
|
+
} });
|
|
5856
|
+
}
|
|
5857
|
+
/**
|
|
5858
|
+
* 装配:Monaco 就绪后注册 provider(幂等)。
|
|
5859
|
+
* @author ddj 2026年09月10号
|
|
5860
|
+
* @param monaco window.monaco
|
|
5861
|
+
*/
|
|
5862
|
+
function setupSnippets(monaco) {
|
|
5863
|
+
registerSnippetProvider(monaco);
|
|
5864
|
+
}
|
|
5865
|
+
/**
|
|
5866
|
+
* 读取可插入条目(「插入代码片段」命令用;含无前缀条目)。
|
|
5867
|
+
* @author ddj 2026年09月10号
|
|
5868
|
+
* @param languageId 当前模型语言(缺省返回全语言 + 该语言条目)
|
|
5869
|
+
* @returns 生效条目数组
|
|
5870
|
+
*/
|
|
5871
|
+
async function listSnippetsFor(languageId) {
|
|
5872
|
+
const entries = await loadEntries();
|
|
5873
|
+
if (!languageId) return entries.slice(0, MAX_ITEMS);
|
|
5874
|
+
return entriesForLanguage(entries, languageId);
|
|
5875
|
+
}
|
|
5876
|
+
//#endregion
|
|
5877
|
+
//#region src/shared/snippets.ts
|
|
5878
|
+
/** 片段文件后缀。 */
|
|
5879
|
+
const SNIPPET_EXT = ".code-snippets";
|
|
5880
|
+
/**
|
|
5881
|
+
* 语言 id → 默认片段文件名(空语言回退 global)。
|
|
5882
|
+
* @author ddj 2026年09月10号
|
|
5883
|
+
* @param language 语言 id
|
|
5884
|
+
* @returns 文件名(如 `lua.code-snippets`)
|
|
5885
|
+
*/
|
|
5886
|
+
function snippetFileNameFor(language) {
|
|
5887
|
+
return (String(language ?? "").trim().toLowerCase() || "global") + SNIPPET_EXT;
|
|
5888
|
+
}
|
|
5889
|
+
/**
|
|
5890
|
+
* 归一化新建文件名:用户输入可为裸语言名(补后缀)或完整文件名;空输入为空串。
|
|
5891
|
+
* @author ddj 2026年09月10号
|
|
5892
|
+
* @param raw 用户输入
|
|
5893
|
+
* @returns 归一化后的文件名
|
|
5894
|
+
*/
|
|
5895
|
+
function normalizeSnippetFileName(raw) {
|
|
5896
|
+
const text = String(raw ?? "").trim();
|
|
5897
|
+
if (!text) return "";
|
|
5898
|
+
return text.toLowerCase().endsWith(".code-snippets") ? text : text + SNIPPET_EXT;
|
|
5899
|
+
}
|
|
5900
|
+
/**
|
|
5901
|
+
* 新建片段文件模板(一条示例,改 body 即可用)。
|
|
5902
|
+
* @author ddj 2026年09月10号
|
|
5903
|
+
* @param language 目标语言 id(空串 = 全局)
|
|
5904
|
+
* @returns JSON 文本(带尾换行)
|
|
5905
|
+
*/
|
|
5906
|
+
function snippetFileTemplate(language) {
|
|
5907
|
+
const lang = String(language ?? "").trim().toLowerCase();
|
|
5908
|
+
const sample = (lang || "global") + " 示例片段";
|
|
5909
|
+
return JSON.stringify({ [sample]: {
|
|
5910
|
+
prefix: "hello",
|
|
5911
|
+
body: ["// " + (lang || "global") + " 片段示例", "$1"],
|
|
5912
|
+
description: "示例:输入 hello 后 Tab 展开"
|
|
5913
|
+
} }, null, 2) + "\n";
|
|
5914
|
+
}
|
|
5915
|
+
/**
|
|
5916
|
+
* 可绑定语言目录(新建片段时的语言下拉来源;与 client/monaco/loader 的 LANG_BY_EXT
|
|
5917
|
+
* 取值集合保持一致)。此处冗余一份纯数据,使本模块不依赖浏览器端 Monaco
|
|
5918
|
+
* (shared 禁 import client 侧模块);一致性由 tests/snippetLanguage.test.ts 断言兜底。
|
|
5919
|
+
*/
|
|
5920
|
+
const SNIPPET_LANGUAGES = [
|
|
5921
|
+
"c",
|
|
5922
|
+
"cpp",
|
|
5923
|
+
"csharp",
|
|
5924
|
+
"css",
|
|
5925
|
+
"dart",
|
|
5926
|
+
"dockerfile",
|
|
5927
|
+
"go",
|
|
5928
|
+
"html",
|
|
5929
|
+
"ini",
|
|
5930
|
+
"java",
|
|
5931
|
+
"javascript",
|
|
5932
|
+
"json",
|
|
5933
|
+
"jsonc",
|
|
5934
|
+
"kotlin",
|
|
5935
|
+
"less",
|
|
5936
|
+
"lua",
|
|
5937
|
+
"markdown",
|
|
5938
|
+
"mdx",
|
|
5939
|
+
"php",
|
|
5940
|
+
"plaintext",
|
|
5941
|
+
"powershell",
|
|
5942
|
+
"python",
|
|
5943
|
+
"ruby",
|
|
5944
|
+
"rust",
|
|
5945
|
+
"scss",
|
|
5946
|
+
"shell",
|
|
5947
|
+
"sql",
|
|
5948
|
+
"swift",
|
|
5949
|
+
"typescript",
|
|
5950
|
+
"xml",
|
|
5951
|
+
"yaml"
|
|
5952
|
+
];
|
|
5953
|
+
/** 语言 id → 展示名(仅收录写法与 id 明显不同的;未收录的原样返回)。 */
|
|
5954
|
+
const LANGUAGE_LABELS = {
|
|
5955
|
+
cpp: "C++",
|
|
5956
|
+
csharp: "C#",
|
|
5957
|
+
javascript: "JavaScript",
|
|
5958
|
+
typescript: "TypeScript",
|
|
5959
|
+
jsonc: "JSON with Comments",
|
|
5960
|
+
powershell: "PowerShell",
|
|
5961
|
+
plaintext: "纯文本"
|
|
5962
|
+
};
|
|
5963
|
+
/**
|
|
5964
|
+
* 语言 id 的人类可读名(用于下拉与「新建 xx 代码片段文件」文案)。
|
|
5965
|
+
* @author ddj 2026年09月10号
|
|
5966
|
+
* @param id 语言 id(空串表示全语言)
|
|
5967
|
+
* @returns 展示名
|
|
5968
|
+
*/
|
|
5969
|
+
function languageLabelOf(id) {
|
|
5970
|
+
const key = String(id ?? "").trim().toLowerCase();
|
|
5971
|
+
if (!key) return "全语言";
|
|
5972
|
+
return LANGUAGE_LABELS[key] ?? key;
|
|
5973
|
+
}
|
|
5974
|
+
//#endregion
|
|
5975
|
+
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/mcp.css.mjs
|
|
5976
|
+
const css = "/* dsh-vscode-mode MCP 管理界面样式。\n 全部使用 DSH 真实主题变量(--dsw-alias-*),不再用不存在的 fg-* 变量。 */\n.vsm-mcp-page{display:flex;flex-direction:column;gap:18px;width:100%;max-width:920px;box-sizing:border-box;color:var(--dsw-alias-label-primary,#e6e6e6);padding-bottom:32px}\n\n/* 顶部:标题 + 副标题 + 添加按钮 */\n.vsm-mcp-header{display:flex;align-items:flex-start;justify-content:space-between;gap:20px}\n.vsm-mcp-header h2{margin:0 0 4px;font-size:20px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-header p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-primary{border:0;border-radius:6px;padding:8px 16px;background:var(--dsw-alias-button-primary-fill,#6d55ff);color:var(--dsw-alias-button-contrast-fill,#fff);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap}\n.vsm-primary:hover{background:var(--dsw-alias-button-primary-hover,#5a46e6)}\n.vsm-primary:disabled{opacity:.55;cursor:default}\n\n/* MCP 管理下的二级子页签:我的 MCP / 项目 MCP / MCP 市场 */\n.vsm-mcp-subhead{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:-4px}\n.vsm-mcp-subtabs{display:flex;gap:18px;border-bottom:1px solid var(--dsw-alias-border-l1,#2e2e2e);flex:1}\n.vsm-mcp-subtabs button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);padding:7px 2px 9px;cursor:pointer;font-size:13px;position:relative}\n.vsm-mcp-subtabs button:hover{color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-mcp-subtabs button.active{color:var(--dsw-alias-label-primary,#fff);font-weight:500}\n.vsm-mcp-subtabs button.active::after{content:\"\";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--dsw-alias-brand-primary,#6d55ff);border-radius:2px}\n\n/* 顶层 Tab:通用 / 快捷键 / MCP 管理 / 语言服务器 / 性能优化 / 兼容性 */\n.vsm-mcp-tabs{display:flex;gap:24px;border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-mcp-tabs button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);padding:9px 2px 11px;cursor:pointer;font-size:14px;position:relative}\n.vsm-mcp-tabs button:hover{color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-mcp-tabs button.active{color:var(--dsw-alias-label-primary,#fff);font-weight:500}\n.vsm-mcp-tabs button.active::after{content:\"\";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--dsw-alias-brand-primary,#6d55ff);border-radius:2px}\n\n/* 统一线框面板:圆角矩形边框圈住各设置分区,提升可读性。\n 用法:<section class=\"vsm-panel\"> + 可选 <h3 class=\"vsm-panel-title\">。 */\n.vsm-panel{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;background:var(--dsw-alias-bg-layer-2,transparent);overflow:hidden}\n.vsm-panel-pad{padding:14px 16px}\n.vsm-panel-title{margin:0;padding:10px 16px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,#c8c8c8);background:var(--dsw-alias-bg-mask-1,#ffffff0a);border-bottom:1px solid var(--dsw-alias-border-l1,#333)}\n.vsm-panel-body{padding:6px 16px}\n.vsm-panel-body>*:first-child{margin-top:8px}\n.vsm-panel-body>*:last-child{margin-bottom:10px}\n\n/* 通用设置 */\n.vsm-general-page{display:flex;flex-direction:column;gap:14px;max-width:720px}\n.vsm-general-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-general-page p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px}\n.vsm-general-row{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:14px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);color:var(--dsw-alias-label-primary,#eee);font-size:14px}\n.vsm-general-row:last-child{border-bottom:0}\n.vsm-general-row select{min-width:220px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);font:inherit}\n.vsm-general-row small{color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n\n/* 服务卡片 */\n.vsm-mcp-card{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:14px 16px;margin-bottom:10px;background:var(--dsw-alias-bg-layer-2,transparent);transition:border-color .15s}\n.vsm-mcp-card:hover{border-color:var(--dsw-alias-border-l3,#555)}\n.vsm-mcp-card-head{display:flex;justify-content:space-between;align-items:center;gap:12px}\n.vsm-mcp-title{display:flex;align-items:center;gap:9px;font-weight:600;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6);min-width:0}\n.vsm-mcp-source{font-size:11px;font-weight:400;padding:2px 7px;border-radius:4px;background:var(--dsw-alias-bg-mask-2,#ffffff22);color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-mcp-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-mcp-dot.connected{background:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-dot.connecting{background:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-mcp-dot.disabled{background:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-mcp-actions{display:flex;align-items:center;gap:4px;flex-shrink:0}\n.vsm-mcp-actions button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);cursor:pointer;font-size:15px;width:28px;height:28px;border-radius:6px;line-height:1}\n.vsm-mcp-actions button:hover{color:var(--dsw-alias-label-primary,#fff);background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-mcp-actions button.vsm-danger:hover{color:var(--dsw-alias-state-error-primary,#f07878);background:var(--dsw-alias-interactive-bg-hover-danger,#ff000014)}\n.vsm-switch{font-size:14px !important}\n.vsm-switch.on{color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:9px 0}\n.vsm-mcp-error{color:var(--dsw-alias-state-error-primary,#f07878);font-size:12px;margin:8px 0}\n.vsm-mcp-banner{padding:9px 12px;border:1px solid var(--dsw-alias-state-error-secondary,#d9534f55);border-radius:6px;background:var(--dsw-alias-state-error-secondary,#d9534f1a);margin-bottom:10px}\n\n/* 工具 chips */\n.vsm-mcp-tools{display:flex;flex-wrap:wrap;gap:6px}\n.vsm-mcp-chip{font:12px var(--ds-font-family-code,ui-monospace,monospace);padding:4px 8px;border-radius:5px;background:var(--dsw-alias-bg-mask-2,#ffffff14);color:var(--dsw-alias-label-secondary,#c8c8c8);border:1px solid var(--dsw-alias-border-l1,#333)}\n\n/* 空态 / 加载态 */\n.vsm-mcp-empty{text-align:center;padding:56px 20px;color:var(--dsw-alias-label-tertiary,#9aa5b1);border:1px dashed var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;font-size:13px}\n\n/* 项目搜索下拉框 */\n.vsm-project-picker{position:relative;width:100%;z-index:4}\n.vsm-project-picker-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-layer-1,transparent);color:var(--dsw-alias-label-primary,#e6e6e6);cursor:pointer;text-align:left}\n.vsm-project-picker-trigger:hover{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-label{display:flex;flex-direction:column;min-width:0;font-size:13px;font-weight:500}\n.vsm-project-picker-label small{margin-top:3px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-arrow{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:16px}\n.vsm-project-picker-menu{position:absolute;top:calc(100% + 6px);left:0;right:0;padding:8px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:9px;background:var(--dsw-alias-bg-overlay,#202020);box-shadow:0 12px 36px #0008}\n.vsm-project-picker-search{width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);outline:none}\n.vsm-project-picker-search:focus{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-options{max-height:260px;overflow:auto;margin-top:6px}\n.vsm-project-option{display:flex;width:100%;flex-direction:column;gap:3px;padding:8px 9px;border:0;border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;text-align:left}\n.vsm-project-option:hover,.vsm-project-option.highlight{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-project-option.selected{color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-option small{overflow:hidden;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-empty{padding:18px 8px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:center}\n\n/* 项目级 MCP 分组 */\n.vsm-project{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;margin-bottom:14px;overflow:hidden;background:var(--dsw-alias-bg-layer-1,transparent)}\n.vsm-project-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:var(--dsw-alias-bg-mask-1,#ffffff0a)}\n.vsm-project-title{display:flex;align-items:center;gap:10px;min-width:0}\n.vsm-project-icon{color:var(--dsw-alias-brand-primary,#6d55ff);font-size:15px;flex-shrink:0}\n.vsm-project-name{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);display:block}\n.vsm-project-path{font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-family:var(--ds-font-family-code,ui-monospace,monospace);display:block;margin-top:2px;word-break:break-all}\n.vsm-primary.vsm-small{padding:5px 12px;font-size:12px}\n.vsm-project-empty{text-align:center;padding:26px 16px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px}\n.vsm-project .vsm-mcp-card{border:0;border-radius:0;margin:0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:transparent}\n.vsm-project .vsm-mcp-card:last-child{border-bottom:0}\n.vsm-project .vsm-mcp-banner{border-radius:0;margin:0}\n\n/* 新增 MCP 弹窗 */\n.vsm-mcp-modal{position:fixed;inset:0;background:var(--dsw-alias-bg-mask-drop,#000000aa);display:flex;align-items:center;justify-content:center;z-index:50}\n.vsm-mcp-dialog{width:min(560px,calc(100vw - 40px));max-height:88vh;overflow:auto;padding:22px 24px;border-radius:12px;background:var(--dsw-alias-bg-overlay,#202020);border:1px solid var(--dsw-alias-border-l2,#444);box-shadow:0 16px 60px #000c;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-dialog h3{margin:0 0 14px;font-size:16px;font-weight:600}\n.vsm-mcp-dialog label{display:flex;flex-direction:column;gap:6px;margin:12px 0;font-size:12px;color:var(--dsw-alias-label-secondary,#aaa)}\n.vsm-mcp-dialog input,.vsm-mcp-dialog select,.vsm-mcp-dialog textarea{font:inherit;color:var(--dsw-alias-label-primary,#eee);background:var(--dsw-alias-bg-layer-1,#2b2b2b);border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 10px}\n.vsm-mcp-dialog input:focus,.vsm-mcp-dialog select:focus,.vsm-mcp-dialog textarea:focus{outline:none;border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-mcp-dialog textarea{min-height:64px;resize:vertical;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-mcp-dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}\n.vsm-mcp-dialog-actions button{padding:8px 14px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:13px}\n.vsm-mcp-dialog-actions button:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n\n/* 兼容性条目(面板标题改用 .vsm-panel-title) */\n.vsm-compat-item{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:10px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:13px;color:var(--dsw-alias-label-primary,#eee)}\n.vsm-compat-item.ok .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-compat-item.warn .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-compat-name{font-weight:500;min-width:0}\n.vsm-compat-note{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:right;min-width:0}\n\n/* 开发形态开关 */\n.vsm-devform-note{display:block;margin-top:4px;font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);word-break:break-all}\n.vsm-devform-actions{display:flex;flex-direction:column;align-items:flex-end;gap:6px;min-width:0}\n.vsm-devform-msg{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px;text-align:right}\n.vsm-general-row button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:6px 12px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-general-row button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-general-row button:disabled{opacity:.55;cursor:default}\n.vsm-general-row button.vsm-devform-close{color:var(--dsw-alias-state-error-primary,#f07878);border-color:var(--dsw-alias-state-error-secondary,#d9534f55)}\n\n/* keyboard shortcuts page */\n.vsm-kb-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}\n.vsm-kb-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:8px;background:var(--dsw-alias-bg-layer-1,#161616)}\n.vsm-kb-row.rec{border-color:var(--dsw-alias-brand-primary,#4f8cff)}\n.vsm-kb-label{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;color:var(--dsw-alias-label-primary,#eee);font-size:13px}\n.vsm-kb-warn{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px}\n.vsm-kb-key{min-width:96px;text-align:center;padding:3px 10px;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;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-kb-key.warn{border-color:var(--dsw-alias-state-warn-primary,#e5b93f);color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-key.invalid{border-color:var(--dsw-alias-state-error-primary,#d9534f);color:var(--dsw-alias-state-error-primary,#d9534f)}\n.vsm-kb-rec{font-size:12px;color:var(--dsw-alias-label-secondary,#9aa5b1)}\n.vsm-kb-actions{display:flex;gap:6px}\n.vsm-kb-actions button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:4px 10px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-kb-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-kb-actions button:disabled{opacity:.55;cursor:default}\n.vsm-kb-actionsbar{display:flex;align-items:center;gap:10px;margin-top:12px}\n.vsm-kb-dirty{flex:1;font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-message{font-size:12px;color:var(--dsw-alias-brand-primary,#4f8cff);margin-top:8px}\n\n/* 语言服务器(LSP)设置子 Tab */\n.vsm-lsp-form{display:flex;flex-direction:column;gap:6px;margin-top:8px}\n.vsm-lsp-form label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--dsw-alias-label-secondary,#9aa5b1)}\n.vsm-lsp-form input{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.vsm-lsp-form input:focus{border-color:var(--dsw-alias-brand-primary,#4f8cff)}\n.vsm-lsp-form button{align-self:flex-start;margin-top:2px}\n.vsm-lsp-hint{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin-top:10px;line-height:1.6}\n\n/* 会话性能(PerfSettings 子 Tab) */\n.vsm-perf-page{display:flex;flex-direction:column;gap:14px;max-width:920px}\n.vsm-perf-page>.vsm-panel-body>*:first-child{margin-top:0}\n.vsm-perf-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-page p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-perf-cards{display:flex;gap:12px;flex-wrap:wrap}\n.vsm-perf-card{display:flex;flex-direction:column;gap:4px;min-width:120px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;background:var(--dsw-alias-bg-layer-2,transparent)}\n.vsm-perf-card span{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-card b{font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-card b.big{color:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-perf-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\n.vsm-perf-selcount{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:0 4px}\n/* 工作区列表分页器 */\n.vsm-perf-pager{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:4px}\n.vsm-perf-pager-text{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-pager-actions{display:flex;gap:8px}\n.vsm-perf-ws-list{display:flex;flex-direction:column;gap:8px}\n.vsm-perf-ws{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;overflow:hidden}\n.vsm-perf-ws-head{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--dsw-alias-bg-layer-1,#262626);cursor:pointer;user-select:none}\n.vsm-perf-ws-head:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-perf-ws-head:focus-visible{outline:1px solid var(--dsw-alias-brand-primary,#6d55ff);outline-offset:-1px}\n.vsm-perf-ws.expanded .vsm-perf-ws-head{border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-perf-ws-caret{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;flex-shrink:0;transition:transform .15s;display:inline-block}\n.vsm-perf-ws-caret.open{transform:rotate(90deg)}\n.vsm-perf-ws .vsm-perf-ws-name{flex:1}\n.vsm-perf-ws-name{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);font-family:var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-perf-ws-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-perf-rows{display:flex;flex-direction:column}\n.vsm-perf-row{display:flex;align-items:center;gap:10px;padding:7px 14px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:12px;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-perf-row:last-child{border-bottom:0}\n.vsm-perf-row:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff0d)}\n.vsm-perf-row input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary,#6d55ff);cursor:pointer}\n.vsm-perf-cell{min-width:0}\n.vsm-perf-id{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--ds-font-family-code,ui-monospace,monospace);color:var(--dsw-alias-label-primary,#eee)}\n.vsm-perf-size{width:70px;text-align:right;flex-shrink:0;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-perf-size.big{color:var(--dsw-alias-state-error-primary,#e05252);font-weight:600}\n.vsm-perf-mtime{width:44px;flex-shrink:0;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-active{width:44px;flex-shrink:0;font-size:11px;color:var(--dsw-alias-state-warn-primary,#e5b93f);text-align:right}\n.vsm-perf-config-state{display:flex;align-items:center;gap:12px;margin:10px 0}\n.vsm-perf-note{font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-perf-block{margin:8px 0 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-base,#111);color:var(--dsw-alias-label-secondary,#c8c8c8);font-size:11px;line-height:1.5;font-family:var(--ds-font-family-code,ui-monospace,monospace);white-space:pre-wrap;overflow-x:auto;max-width:100%}\n.vsm-perf-modal{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--dsw-alias-bg-mask-1,#000000aa);z-index:1000;padding:20px}\n.vsm-perf-modal-card{width:min(560px,92vw);max-height:72vh;display:flex;flex-direction:column;gap:12px;padding:18px 20px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#1f1f1f);color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-modal-card h3{margin:0;font-size:16px}\n.vsm-perf-modal-note{font-size:12px}\n.vsm-perf-modal-list{list-style:none;margin:0;padding:0;overflow-y:auto;font-size:12px;color:var(--dsw-alias-label-secondary,#c8c8c8);display:flex;flex-direction:column;gap:4px}\n.vsm-perf-modal-list li{padding:4px 6px;border-radius:6px;background:var(--dsw-alias-bg-layer-1,#262626);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-perf-modal-more{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}\n.vsm-secondary{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 16px;background:none;color:var(--dsw-alias-label-primary,#eee);font-size:13px;cursor:pointer;white-space:nowrap}\n.vsm-secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-secondary:disabled{opacity:.55;cursor:default}\n.vsm-small{padding:4px 10px;font-size:12px}\n\n/* 扩展管理(LSP 语言服务器) */\n.vsm-mcp-actions button.vsm-primary,\n.vsm-mcp-actions button.vsm-danger{width:auto;height:auto;padding:5px 12px;font-size:12px;border-radius:6px;line-height:1.4}\n.vsm-mcp-actions button.vsm-danger{color:var(--dsw-alias-state-error-primary,#f07878);background:none}\n.vsm-mcp-actions button.vsm-danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger,#ff000014)}\n.vsm-ext-ver{font-weight:400;font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n";
|
|
5977
|
+
const tagId = "dsh-vscode-mode/mcp.css";
|
|
5978
|
+
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
5979
|
+
const tag = document.createElement("style");
|
|
5980
|
+
tag.dataset.plugin = "dsh-vscode-mode";
|
|
5981
|
+
tag.dataset.pluginCss = tagId;
|
|
5982
|
+
tag.textContent = css;
|
|
5983
|
+
document.head.appendChild(tag);
|
|
5984
|
+
}
|
|
5985
|
+
//#endregion
|
|
5986
|
+
//#region src/client/ui/SnippetsPicker.ts
|
|
5987
|
+
/**
|
|
5988
|
+
* dsh-vscode-mode client — 代码片段选择器(VS Code「Configure Snippets」形态)。
|
|
5989
|
+
*
|
|
5990
|
+
* 形态:**居中浮窗 + 二级弹窗**,复用插件原生模态样式(mcp.css 的 .vsm-mcp-dialog,
|
|
5991
|
+
* 与「添加 MCP」「工作区选择」同源),不自造视觉。
|
|
5992
|
+
* - 一级弹窗 mode='configure':按语言分组的现有片段文件列表(全局 + 当前工作区项目),
|
|
5993
|
+
* 点击在文件编辑界面打开;底部按「当前文件语言」新建,或新建全语言片段。
|
|
5994
|
+
* - 二级弹窗:新建片段文件表单(语言下拉 + 文件名),语言决定默认文件名与写入的绑定语义。
|
|
5995
|
+
* - 一级弹窗 mode='insert':当前语言生效条目列表,点击在光标处按片段语法展开。
|
|
5996
|
+
*
|
|
5997
|
+
* ⚠️ 浮层经 createPortal 挂 body,根节点必须带 `data-edrv-view`(与 CommandPalette /
|
|
5998
|
+
* ContextMenu 一致):editor.css 的浮层样式全部以 `[data-edrv-view]` 作用域限定,
|
|
5999
|
+
* 漏挂会导致样式整块失效、内容以裸流形式铺在页面底部。
|
|
6000
|
+
* 作者 ddj 2026年09月10号
|
|
6001
|
+
*/
|
|
6002
|
+
/** 片段文件行的第二行摘要:语言 + 条目数 + 相对路径。 */
|
|
6003
|
+
function fileMeta(info) {
|
|
6004
|
+
return languageLabelOf(info.language) + " · " + info.count + " 条 · [" + info.relHint + info.file + "]";
|
|
6005
|
+
}
|
|
6006
|
+
/**
|
|
6007
|
+
* 语言下拉选项:全语言 + 语言目录(去重、保持目录序)。
|
|
6008
|
+
* @author ddj 2026年09月10号
|
|
6009
|
+
* @param languages 语言 id 目录(缺省用 shared 常量)
|
|
6010
|
+
* @returns 选项数组({ id, label })
|
|
6011
|
+
*/
|
|
6012
|
+
function languageOptions(languages) {
|
|
6013
|
+
const ids = Array.isArray(languages) && languages.length ? languages : SNIPPET_LANGUAGES;
|
|
6014
|
+
const seen = /* @__PURE__ */ new Set();
|
|
6015
|
+
const out = [{
|
|
6016
|
+
id: "",
|
|
6017
|
+
label: "全语言(所有文件生效)"
|
|
6018
|
+
}];
|
|
6019
|
+
for (const raw of ids) {
|
|
6020
|
+
const id = String(raw ?? "").trim().toLowerCase();
|
|
6021
|
+
if (!id || seen.has(id)) continue;
|
|
6022
|
+
seen.add(id);
|
|
6023
|
+
out.push({
|
|
6024
|
+
id,
|
|
6025
|
+
label: languageLabelOf(id)
|
|
6026
|
+
});
|
|
6027
|
+
}
|
|
6028
|
+
return out;
|
|
6029
|
+
}
|
|
6030
|
+
/**
|
|
6031
|
+
* 片段选择器(浮窗 / 二级弹窗)。
|
|
6032
|
+
* @param props.mode 'configure'(管理文件)| 'insert'(插入条目)
|
|
6033
|
+
* @param props.sessionId 会话 id
|
|
6034
|
+
* @param props.cwd 当前会话工作区(项目片段分组与新建用)
|
|
6035
|
+
* @param props.language 当前编辑器文件绑定的语言 id(新建默认语言 / 插入过滤)
|
|
6036
|
+
* @param props.languages 可选语言目录(来自 monaco.languages.getLanguages;缺省用内置常量)
|
|
6037
|
+
* @param props.onOpenFile 在编辑界面打开片段文件回调(absPath)
|
|
6038
|
+
* @param props.onInsert 插入片段回调(entry)
|
|
6039
|
+
* @param props.onClose 关闭回调
|
|
6040
|
+
* @returns 浮层 React 元素
|
|
6041
|
+
*/
|
|
6042
|
+
function SnippetsPicker(props) {
|
|
6043
|
+
const mode = props?.mode === "insert" ? "insert" : "configure";
|
|
6044
|
+
props?.sessionId;
|
|
6045
|
+
const cwd = props?.cwd;
|
|
6046
|
+
const currentLanguage = String(props?.language ?? "").trim().toLowerCase();
|
|
6047
|
+
const options = react.default.useMemo(() => languageOptions(props?.languages), [props?.languages]);
|
|
6048
|
+
const onOpenFile = props?.onOpenFile;
|
|
6049
|
+
const onInsert = props?.onInsert;
|
|
6050
|
+
const onClose = props?.onClose;
|
|
6051
|
+
const [data, setData] = react.default.useState(null);
|
|
6052
|
+
const [entries, setEntries] = react.default.useState(null);
|
|
6053
|
+
const [error, setError] = react.default.useState("");
|
|
6054
|
+
const [busy, setBusy] = react.default.useState(false);
|
|
6055
|
+
const [draft, setDraft] = react.default.useState(null);
|
|
6056
|
+
const aliveRef = react.default.useRef(true);
|
|
6057
|
+
const isInsert = mode === "insert";
|
|
6058
|
+
/** 拉取数据:管理模式取文件列表,插入模式取当前语言条目。 */
|
|
6059
|
+
const load = react.default.useCallback(() => {
|
|
6060
|
+
if (isInsert) {
|
|
6061
|
+
listSnippetsFor(currentLanguage).then((list) => {
|
|
6062
|
+
if (!aliveRef.current) return;
|
|
6063
|
+
setEntries(list);
|
|
6064
|
+
setError("");
|
|
6065
|
+
}).catch((e) => {
|
|
6066
|
+
if (aliveRef.current) setError("读取代码片段失败:" + String(e));
|
|
6067
|
+
});
|
|
6068
|
+
return;
|
|
6069
|
+
}
|
|
6070
|
+
rpc("snippets.list", {}).then((res) => {
|
|
6071
|
+
if (!aliveRef.current) return;
|
|
6072
|
+
if (res && res.ok) {
|
|
6073
|
+
setData(res);
|
|
6074
|
+
setError("");
|
|
6075
|
+
} else setError(res?.error ?? "读取代码片段失败");
|
|
6076
|
+
}).catch((e) => {
|
|
6077
|
+
if (aliveRef.current) setError("读取代码片段失败:" + String(e));
|
|
6078
|
+
});
|
|
6079
|
+
}, [isInsert, currentLanguage]);
|
|
6080
|
+
react.default.useEffect(() => {
|
|
6081
|
+
aliveRef.current = true;
|
|
6082
|
+
load();
|
|
6083
|
+
return () => {
|
|
6084
|
+
aliveRef.current = false;
|
|
6085
|
+
};
|
|
6086
|
+
}, [load]);
|
|
6087
|
+
react.default.useEffect(() => {
|
|
6088
|
+
const onKey = (event) => {
|
|
6089
|
+
if (event.key !== "Escape") return;
|
|
6090
|
+
if (draft) closeDraft();
|
|
6091
|
+
else onClose?.();
|
|
6092
|
+
};
|
|
6093
|
+
window.addEventListener("keydown", onKey, true);
|
|
6094
|
+
return () => window.removeEventListener("keydown", onKey, true);
|
|
6095
|
+
}, [draft, onClose]);
|
|
6096
|
+
/** 打开二级弹窗(按 scope + 语言新建)。 */
|
|
6097
|
+
const openDraft = (scope, language) => {
|
|
6098
|
+
setDraft({
|
|
6099
|
+
scope,
|
|
6100
|
+
language,
|
|
6101
|
+
fileName: snippetFileNameFor(language),
|
|
6102
|
+
edited: false
|
|
6103
|
+
});
|
|
6104
|
+
setError("");
|
|
6105
|
+
};
|
|
6106
|
+
/** 关闭二级弹窗(回到一级浮窗)。 */
|
|
6107
|
+
const closeDraft = () => {
|
|
6108
|
+
setDraft(null);
|
|
6109
|
+
setError("");
|
|
6110
|
+
};
|
|
6111
|
+
/** 改语言:文件名未手改过则跟随语言联动(手改过则尊重用户输入)。 */
|
|
6112
|
+
const pickLanguage = (language) => {
|
|
6113
|
+
setDraft((prev) => prev ? {
|
|
6114
|
+
...prev,
|
|
6115
|
+
language,
|
|
6116
|
+
fileName: prev.edited ? prev.fileName : snippetFileNameFor(language)
|
|
6117
|
+
} : prev);
|
|
6118
|
+
};
|
|
6119
|
+
/** 改文件名:标记为手改,之后不再被语言联动覆盖。 */
|
|
6120
|
+
const editFileName = (value) => {
|
|
6121
|
+
setDraft((prev) => prev ? {
|
|
6122
|
+
...prev,
|
|
6123
|
+
fileName: value,
|
|
6124
|
+
edited: true
|
|
6125
|
+
} : prev);
|
|
6126
|
+
};
|
|
6127
|
+
/**
|
|
6128
|
+
* 创建并打开片段文件(二级弹窗提交)。
|
|
6129
|
+
* @author ddj 2026年09月10号
|
|
6130
|
+
*/
|
|
6131
|
+
const createFile = () => {
|
|
6132
|
+
if (!draft) return;
|
|
6133
|
+
const name = normalizeSnippetFileName(draft.fileName);
|
|
6134
|
+
if (!name) {
|
|
6135
|
+
setError("文件名不能为空");
|
|
6136
|
+
return;
|
|
6137
|
+
}
|
|
6138
|
+
if (draft.scope === "project" && !cwd) {
|
|
6139
|
+
setError("当前会话没有工作区,无法新建项目片段");
|
|
6140
|
+
return;
|
|
6141
|
+
}
|
|
6142
|
+
setBusy(true);
|
|
6143
|
+
setError("");
|
|
6144
|
+
rpc("snippets.save", {
|
|
6145
|
+
scope: draft.scope,
|
|
6146
|
+
workspacePath: draft.scope === "project" ? cwd : void 0,
|
|
6147
|
+
file: name,
|
|
6148
|
+
content: snippetFileTemplate(draft.language)
|
|
6149
|
+
}).then((res) => {
|
|
6150
|
+
if (!aliveRef.current) return;
|
|
6151
|
+
if (!res || !res.ok) {
|
|
6152
|
+
setError(res?.error ?? "新建失败");
|
|
6153
|
+
return;
|
|
6154
|
+
}
|
|
6155
|
+
invalidateSnippets();
|
|
6156
|
+
closeDraft();
|
|
6157
|
+
onOpenFile?.(res.file.absPath);
|
|
6158
|
+
onClose?.();
|
|
6159
|
+
}).catch((e) => {
|
|
6160
|
+
if (aliveRef.current) setError("新建失败:" + String(e));
|
|
6161
|
+
}).finally(() => {
|
|
6162
|
+
if (aliveRef.current) setBusy(false);
|
|
6163
|
+
});
|
|
6164
|
+
};
|
|
6165
|
+
/** 打开片段文件(在编辑界面打开,浮窗关闭)。 */
|
|
6166
|
+
const openFile = (info) => {
|
|
6167
|
+
onOpenFile?.(info.absPath);
|
|
6168
|
+
onClose?.();
|
|
6169
|
+
};
|
|
6170
|
+
/** 删除片段文件(confirm 后走 snippets.remove)。 */
|
|
6171
|
+
const removeFile = (info) => {
|
|
6172
|
+
if (!window.confirm("删除代码片段文件 " + info.file + "?(不可恢复)")) return;
|
|
6173
|
+
rpc("snippets.remove", {
|
|
6174
|
+
scope: info.scope,
|
|
6175
|
+
workspacePath: info.scope === "project" ? cwd : void 0,
|
|
6176
|
+
file: info.file
|
|
6177
|
+
}).then((res) => {
|
|
6178
|
+
if (!aliveRef.current) return;
|
|
6179
|
+
if (!res || !res.ok) {
|
|
6180
|
+
setError(res?.error ?? "删除失败");
|
|
6181
|
+
return;
|
|
6182
|
+
}
|
|
6183
|
+
invalidateSnippets();
|
|
6184
|
+
load();
|
|
6185
|
+
}).catch((e) => {
|
|
6186
|
+
if (aliveRef.current) setError("删除失败:" + String(e));
|
|
6187
|
+
});
|
|
6188
|
+
};
|
|
6189
|
+
/** 一级浮窗主体:列表 / 空态 / 错误。 */
|
|
6190
|
+
const renderBody = () => {
|
|
6191
|
+
if (error && !draft) return react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error);
|
|
6192
|
+
if (isInsert) {
|
|
6193
|
+
const list = entries ?? [];
|
|
6194
|
+
if (!list.length) return react.default.createElement("div", { className: "vsm-mcp-empty" }, entries === null ? "正在读取代码片段…" : "当前文件没有可用代码片段,可用「代码片段:配置代码片段」新建");
|
|
6195
|
+
return react.default.createElement("div", { className: "edrv-snip-list" }, list.map((entry) => react.default.createElement("button", {
|
|
6196
|
+
key: entry.scope + ":" + entry.file + ":" + entry.key,
|
|
6197
|
+
className: "edrv-snip-row",
|
|
6198
|
+
onClick: () => {
|
|
6199
|
+
onInsert?.(entry);
|
|
6200
|
+
onClose?.();
|
|
6201
|
+
}
|
|
6202
|
+
}, react.default.createElement("span", { className: "edrv-snip-row-main" }, react.default.createElement("span", { className: "edrv-snip-label" }, entry.prefix || entry.key), react.default.createElement("span", { className: "edrv-snip-desc" }, entry.description || entry.key)), react.default.createElement("span", { className: "edrv-snip-src" }, entry.file))));
|
|
6203
|
+
}
|
|
6204
|
+
if (!data) return react.default.createElement("div", { className: "vsm-mcp-empty" }, "正在读取代码片段…");
|
|
6205
|
+
const project = (data.projects ?? []).find((item) => item.workspacePath === cwd) ?? null;
|
|
6206
|
+
/** 行按语言再按文件名排序,同语言片段聚在一起(便于按文件类型找片段)。 */
|
|
6207
|
+
const sortByLanguage = (list) => [...list].sort((a, b) => String(a.language).localeCompare(String(b.language)) || String(a.file).localeCompare(String(b.file)));
|
|
6208
|
+
const rows = (list) => sortByLanguage(list).map((info) => react.default.createElement("div", {
|
|
6209
|
+
key: info.scope + ":" + info.file,
|
|
6210
|
+
className: "edrv-snip-row"
|
|
6211
|
+
}, react.default.createElement("button", {
|
|
6212
|
+
className: "edrv-snip-row-main",
|
|
6213
|
+
title: info.absPath,
|
|
6214
|
+
onClick: () => openFile(info)
|
|
6215
|
+
}, react.default.createElement("span", { className: "edrv-snip-label" }, info.file), react.default.createElement("span", { className: "edrv-snip-desc" }, fileMeta(info))), info.error ? react.default.createElement("span", { className: "vsm-mcp-chip edrv-snip-warn" }, "JSON 解析失败") : null, react.default.createElement("button", {
|
|
6216
|
+
className: "edrv-snip-act edrv-snip-danger",
|
|
6217
|
+
title: "删除",
|
|
6218
|
+
onClick: () => removeFile(info)
|
|
6219
|
+
}, "⌫")));
|
|
6220
|
+
const globalRows = rows(data.user ?? []);
|
|
6221
|
+
const projectRows = project ? rows(project.files ?? []) : [];
|
|
6222
|
+
return react.default.createElement("div", { className: "edrv-snip-list" }, react.default.createElement("div", { className: "edrv-snip-group" }, "全局代码片段(~/.dsh/snippets/)"), globalRows.length ? globalRows : react.default.createElement("div", { className: "edrv-snip-empty" }, "还没有全局代码片段"), react.default.createElement("div", { className: "edrv-snip-group" }, "项目代码片段" + (cwd ? "(" + cwd + ")" : "")), projectRows.length ? projectRows : react.default.createElement("div", { className: "edrv-snip-empty" }, cwd ? "当前项目没有代码片段" : "当前会话没有工作区"));
|
|
6223
|
+
};
|
|
6224
|
+
/** 当前文件语言提示行(让「片段绑定到哪种文件」一目了然)。 */
|
|
6225
|
+
const languageBar = react.default.createElement("div", { className: "edrv-snip-langbar" }, currentLanguage ? react.default.createElement(react.default.Fragment, null, "当前文件语言:", react.default.createElement("b", null, languageLabelOf(currentLanguage)), "(" + currentLanguage + ")") : "当前没有打开文件:可新建全语言片段,或先打开文件再新建对应语言的片段");
|
|
6226
|
+
const dialog = react.default.createElement("div", {
|
|
6227
|
+
className: "edrv-snip-mask",
|
|
6228
|
+
onClick: () => onClose?.()
|
|
6229
|
+
}, react.default.createElement("div", {
|
|
6230
|
+
className: "vsm-mcp-dialog edrv-snip-dialog",
|
|
6231
|
+
onClick: (event) => event.stopPropagation()
|
|
6232
|
+
}, react.default.createElement("h3", null, isInsert ? "插入代码片段" : "代码片段:配置代码片段"), react.default.createElement("p", { className: "edrv-snip-hint" }, isInsert ? "仅列出对当前文件语言生效的片段(选定后在光标处展开,支持 ${1:占位} 与 $TM_FILENAME 等变量)。" : "代码片段按语言绑定:`<语言>.code-snippets` 只对该类文件生效,`global.code-snippets` 对所有文件生效。选中文件即在编辑界面打开。"), isInsert ? null : languageBar, renderBody(), isInsert ? null : react.default.createElement("div", { className: "vsm-mcp-dialog-actions" }, react.default.createElement("button", {
|
|
6233
|
+
disabled: busy,
|
|
6234
|
+
onClick: () => openDraft("user", "")
|
|
6235
|
+
}, "新建全语言片段…"), react.default.createElement("button", {
|
|
6236
|
+
className: "vsm-primary",
|
|
6237
|
+
disabled: busy || !currentLanguage,
|
|
6238
|
+
title: currentLanguage ? "" : "请先打开一个文件,或改用「新建全语言片段…」",
|
|
6239
|
+
onClick: () => openDraft("user", currentLanguage)
|
|
6240
|
+
}, currentLanguage ? "新建 " + languageLabelOf(currentLanguage) + " 片段文件…" : "新建当前语言片段…"), react.default.createElement("button", {
|
|
6241
|
+
disabled: busy || !cwd,
|
|
6242
|
+
title: cwd ? "" : "当前会话没有工作区",
|
|
6243
|
+
onClick: () => openDraft("project", currentLanguage)
|
|
6244
|
+
}, "新建项目片段文件…"))));
|
|
6245
|
+
const createDialog = draft ? react.default.createElement("div", {
|
|
6246
|
+
className: "edrv-snip-mask edrv-snip-mask-top",
|
|
6247
|
+
onClick: closeDraft
|
|
6248
|
+
}, react.default.createElement("div", {
|
|
6249
|
+
className: "vsm-mcp-dialog edrv-snip-dialog",
|
|
6250
|
+
onClick: (event) => event.stopPropagation()
|
|
6251
|
+
}, react.default.createElement("h3", null, draft.scope === "project" ? "新建项目代码片段文件" : "新建全局代码片段文件"), react.default.createElement("label", null, "生效语言", react.default.createElement("select", {
|
|
6252
|
+
value: draft.language,
|
|
6253
|
+
disabled: busy,
|
|
6254
|
+
onChange: (event) => {
|
|
6255
|
+
pickLanguage(event.target.value);
|
|
6256
|
+
setError("");
|
|
6257
|
+
}
|
|
6258
|
+
}, options.map((item) => react.default.createElement("option", {
|
|
6259
|
+
key: "lang-" + item.id,
|
|
6260
|
+
value: item.id
|
|
6261
|
+
}, item.label)))), react.default.createElement("label", null, "文件名", react.default.createElement("input", {
|
|
6262
|
+
autoFocus: true,
|
|
6263
|
+
spellCheck: false,
|
|
6264
|
+
value: draft.fileName,
|
|
6265
|
+
placeholder: snippetFileNameFor(draft.language),
|
|
6266
|
+
onChange: (event) => {
|
|
6267
|
+
editFileName(event.target.value);
|
|
6268
|
+
setError("");
|
|
6269
|
+
},
|
|
6270
|
+
onKeyDown: (event) => {
|
|
6271
|
+
if (event.key === "Enter") createFile();
|
|
6272
|
+
}
|
|
6273
|
+
})), react.default.createElement("div", { className: "edrv-snip-hint" }, (draft.scope === "project" ? "将写入 " + (cwd ?? "") + "/.dsh/snippets/" : "将写入 ~/.dsh/snippets/") + normalizeSnippetFileName(draft.fileName) + (draft.language ? "(仅对 " + languageLabelOf(draft.language) + " 文件生效)" : "(对所有文件生效)")), error ? react.default.createElement("div", { className: "vsm-mcp-error vsm-mcp-banner" }, error) : null, react.default.createElement("div", { className: "vsm-mcp-dialog-actions" }, react.default.createElement("button", {
|
|
6274
|
+
disabled: busy,
|
|
6275
|
+
onClick: closeDraft
|
|
6276
|
+
}, "取消"), react.default.createElement("button", {
|
|
6277
|
+
className: "vsm-primary",
|
|
6278
|
+
disabled: busy,
|
|
6279
|
+
onClick: createFile
|
|
6280
|
+
}, busy ? "创建中…" : "创建并打开")))) : null;
|
|
6281
|
+
return (0, react_dom.createPortal)(react.default.createElement("div", { "data-edrv-view": "1" }, dialog, createDialog), document.body);
|
|
6282
|
+
}
|
|
6283
|
+
//#endregion
|
|
5605
6284
|
//#region src/client/ui/EditorView.ts
|
|
5606
6285
|
/**
|
|
5607
6286
|
* dsh-vscode-mode client — EditorView:中央 VSCode 式文件编辑器(编排层)。
|
|
@@ -5612,6 +6291,22 @@ window.__ModuleLoader__.load({
|
|
|
5612
6291
|
* 作者 ddj 2026-08-20
|
|
5613
6292
|
*/
|
|
5614
6293
|
/**
|
|
6294
|
+
* 从 Monaco 语言目录取可选语言 id 列表(代码片段新建时的语言下拉来源)。
|
|
6295
|
+
* 旧版 Monaco / 目录不可读时返回 undefined,由调用方回落 shared 的内置常量。
|
|
6296
|
+
* @author ddj 2026年09月10号
|
|
6297
|
+
* @param monaco window.monaco(可能未加载)
|
|
6298
|
+
* @returns 语言 id 数组或 undefined
|
|
6299
|
+
*/
|
|
6300
|
+
function snippetLanguageIds(monaco) {
|
|
6301
|
+
try {
|
|
6302
|
+
const languages = monaco?.languages?.getLanguages?.();
|
|
6303
|
+
if (!Array.isArray(languages) || !languages.length) return void 0;
|
|
6304
|
+
return languages.map((item) => item && typeof item.id === "string" ? item.id : "").filter(Boolean);
|
|
6305
|
+
} catch (error) {
|
|
6306
|
+
return;
|
|
6307
|
+
}
|
|
6308
|
+
}
|
|
6309
|
+
/**
|
|
5615
6310
|
* 中央编辑区:文件页签(脏点/关闭/打开路径)+ Ctrl+P 搜索 + Monaco 编辑器 +
|
|
5616
6311
|
* 底部差异条(DiffBox/空态)+ 全局差异下拉(DiffLauncher)+ 状态栏。
|
|
5617
6312
|
* @param props.sessionId 会话 id
|
|
@@ -5717,6 +6412,7 @@ window.__ModuleLoader__.load({
|
|
|
5717
6412
|
const hoverPanelRef = react.default.useRef(false);
|
|
5718
6413
|
const batchBusyRef = react.default.useRef(false);
|
|
5719
6414
|
const menuHandlersRef = react.default.useRef(null);
|
|
6415
|
+
const [snippetPicker, setSnippetPicker] = react.default.useState(null);
|
|
5720
6416
|
const doSaveRef = react.default.useRef(null);
|
|
5721
6417
|
const onEditRef = react.default.useRef(null);
|
|
5722
6418
|
const saveViewStateRef = react.default.useRef(null);
|
|
@@ -6186,6 +6882,14 @@ window.__ModuleLoader__.load({
|
|
|
6186
6882
|
if (aiStatusTimer.current) clearTimeout(aiStatusTimer.current);
|
|
6187
6883
|
};
|
|
6188
6884
|
}, []);
|
|
6885
|
+
react.default.useEffect(() => {
|
|
6886
|
+
setSnippetsSession(sessionId);
|
|
6887
|
+
}, [sessionId]);
|
|
6888
|
+
react.default.useEffect(() => {
|
|
6889
|
+
const onChanged = () => invalidateSnippets();
|
|
6890
|
+
window.addEventListener("edrv:snippets-changed", onChanged);
|
|
6891
|
+
return () => window.removeEventListener("edrv:snippets-changed", onChanged);
|
|
6892
|
+
}, []);
|
|
6189
6893
|
react.default.useEffect(() => {
|
|
6190
6894
|
const onOpen = (e) => {
|
|
6191
6895
|
const p = e?.detail?.path;
|
|
@@ -6482,6 +7186,35 @@ window.__ModuleLoader__.load({
|
|
|
6482
7186
|
return;
|
|
6483
7187
|
}
|
|
6484
7188
|
menuHandlersRef.current?.openInExplorer?.(path);
|
|
7189
|
+
}],
|
|
7190
|
+
["edrv.command.configureSnippets", () => {
|
|
7191
|
+
closeCommandPalette();
|
|
7192
|
+
setSnippetPicker("configure");
|
|
7193
|
+
}],
|
|
7194
|
+
["edrv.command.insertSnippet", () => {
|
|
7195
|
+
closeCommandPalette();
|
|
7196
|
+
setSnippetPicker("insert");
|
|
7197
|
+
}],
|
|
7198
|
+
["edrv.command.addSelectionRef", () => {
|
|
7199
|
+
const sel = editorRef.current?.getSelection?.();
|
|
7200
|
+
const path = activeRef.current;
|
|
7201
|
+
if (!path) {
|
|
7202
|
+
setStatus("无活动文件");
|
|
7203
|
+
return;
|
|
7204
|
+
}
|
|
7205
|
+
if (!sel || sel.startLineNumber === sel.endLineNumber && sel.startColumn === sel.endColumn) {
|
|
7206
|
+
setStatus("请先选中内容再添加引用");
|
|
7207
|
+
return;
|
|
7208
|
+
}
|
|
7209
|
+
const range = {
|
|
7210
|
+
startLine: sel.startLineNumber,
|
|
7211
|
+
endLine: sel.endLineNumber
|
|
7212
|
+
};
|
|
7213
|
+
if (!addToConversation) {
|
|
7214
|
+
setStatus("添加到对话不可用");
|
|
7215
|
+
return;
|
|
7216
|
+
}
|
|
7217
|
+
addToConversation.appendReference(sessionId, path, range).then((o) => setStatus(statusOfAdd(o, "已添加选中内容为引用")));
|
|
6485
7218
|
}]
|
|
6486
7219
|
];
|
|
6487
7220
|
const byName = new Map(handlers);
|
|
@@ -6573,6 +7306,7 @@ window.__ModuleLoader__.load({
|
|
|
6573
7306
|
if (!alive) return;
|
|
6574
7307
|
setMonaco(m);
|
|
6575
7308
|
setupAiInline(m);
|
|
7309
|
+
setupSnippets(m);
|
|
6576
7310
|
}).catch((e) => {
|
|
6577
7311
|
if (alive) {
|
|
6578
7312
|
setMonacoErr(String(e?.message ?? e));
|
|
@@ -6657,6 +7391,7 @@ window.__ModuleLoader__.load({
|
|
|
6657
7391
|
setDirtyMap((d) => Object.assign({}, d, { [active]: false }));
|
|
6658
7392
|
refreshRecords();
|
|
6659
7393
|
emitRefresh();
|
|
7394
|
+
if (/\.code-snippets$/i.test(active)) window.dispatchEvent(new CustomEvent("edrv:snippets-changed"));
|
|
6660
7395
|
} else {
|
|
6661
7396
|
setStatus("保存失败");
|
|
6662
7397
|
setError(res?.error ? String(res.error) : "保存失败");
|
|
@@ -7293,6 +8028,31 @@ window.__ModuleLoader__.load({
|
|
|
7293
8028
|
addRefToChat,
|
|
7294
8029
|
openInExplorer
|
|
7295
8030
|
};
|
|
8031
|
+
/**
|
|
8032
|
+
* 在光标处按片段语法展开插入(Monaco 原生 snippet 控制器解析 ${1:占位} 与 $TM_* 变量)。
|
|
8033
|
+
* @author ddj 2026年09月10号
|
|
8034
|
+
* @param entry 片段条目
|
|
8035
|
+
*/
|
|
8036
|
+
const insertSnippetAtCursor = (entry) => {
|
|
8037
|
+
const ed = editorRef.current;
|
|
8038
|
+
if (!ed || !entry) {
|
|
8039
|
+
setStatus("无活动编辑器");
|
|
8040
|
+
return;
|
|
8041
|
+
}
|
|
8042
|
+
try {
|
|
8043
|
+
ed.focus();
|
|
8044
|
+
const controller = ed.getContribution?.("snippetController2");
|
|
8045
|
+
if (controller?.insert) controller.insert(String(entry.body ?? ""));
|
|
8046
|
+
else ed.executeEdits("edrv-snippet", [{
|
|
8047
|
+
range: ed.getSelection(),
|
|
8048
|
+
text: String(entry.body ?? "")
|
|
8049
|
+
}]);
|
|
8050
|
+
setStatus("已插入代码片段:" + (entry.prefix || entry.key));
|
|
8051
|
+
} catch (error) {
|
|
8052
|
+
setStatus("插入代码片段失败");
|
|
8053
|
+
setError("插入代码片段失败:" + String(error));
|
|
8054
|
+
}
|
|
8055
|
+
};
|
|
7296
8056
|
const openFile = (path, focusDiff) => {
|
|
7297
8057
|
if (!path) return;
|
|
7298
8058
|
recordNav();
|
|
@@ -7686,6 +8446,19 @@ window.__ModuleLoader__.load({
|
|
|
7686
8446
|
dismissMenus();
|
|
7687
8447
|
}
|
|
7688
8448
|
}, "关闭标签页")) : null;
|
|
8449
|
+
const snippetPickerEl = snippetPicker ? react.default.createElement(SnippetsPicker, {
|
|
8450
|
+
mode: snippetPicker,
|
|
8451
|
+
sessionId,
|
|
8452
|
+
cwd: cwd ?? null,
|
|
8453
|
+
language: active ? snippetLanguageOf(active) : "",
|
|
8454
|
+
languages: snippetLanguageIds(monacoRef.current),
|
|
8455
|
+
onOpenFile: (absPath) => {
|
|
8456
|
+
openFileAt(absPath, 1);
|
|
8457
|
+
setStatus("已打开代码片段文件");
|
|
8458
|
+
},
|
|
8459
|
+
onInsert: insertSnippetAtCursor,
|
|
8460
|
+
onClose: () => setSnippetPicker(null)
|
|
8461
|
+
}) : null;
|
|
7689
8462
|
const sidebarPanels = props.sidebarPanels;
|
|
7690
8463
|
const sidebarCtx = {
|
|
7691
8464
|
sessionId,
|
|
@@ -7766,14 +8539,14 @@ window.__ModuleLoader__.load({
|
|
|
7766
8539
|
"data-edrv-layout": "side",
|
|
7767
8540
|
className: "edrv-view-side",
|
|
7768
8541
|
style: Object.assign({}, baseStyle, { height: "100%" })
|
|
7769
|
-
}, editorRow, menuBackdrop, tabMenuEl, paletteEl) : react.default.createElement("div", {
|
|
8542
|
+
}, editorRow, menuBackdrop, tabMenuEl, paletteEl, snippetPickerEl) : react.default.createElement("div", {
|
|
7770
8543
|
ref: viewRootRef,
|
|
7771
8544
|
"data-edrv-view": "1",
|
|
7772
8545
|
style: Object.assign({}, baseStyle, {
|
|
7773
8546
|
height: "var(--edrv-editor-height, 100%)",
|
|
7774
8547
|
maxHeight: "var(--edrv-editor-height, 100%)"
|
|
7775
8548
|
})
|
|
7776
|
-
}, editorRow, menuBackdrop, tabMenuEl, paletteEl);
|
|
8549
|
+
}, editorRow, menuBackdrop, tabMenuEl, paletteEl, snippetPickerEl);
|
|
7777
8550
|
}
|
|
7778
8551
|
//#endregion
|
|
7779
8552
|
//#region src/client/ui/DiffBadge.ts
|
|
@@ -8150,17 +8923,6 @@ window.__ModuleLoader__.load({
|
|
|
8150
8923
|
}), sessionId || "chat"), palette);
|
|
8151
8924
|
}
|
|
8152
8925
|
//#endregion
|
|
8153
|
-
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/mcp.css.mjs
|
|
8154
|
-
const css = "/* dsh-vscode-mode MCP 管理界面样式。\n 全部使用 DSH 真实主题变量(--dsw-alias-*),不再用不存在的 fg-* 变量。 */\n.vsm-mcp-page{display:flex;flex-direction:column;gap:18px;width:100%;max-width:920px;box-sizing:border-box;color:var(--dsw-alias-label-primary,#e6e6e6);padding-bottom:32px}\n\n/* 顶部:标题 + 副标题 + 添加按钮 */\n.vsm-mcp-header{display:flex;align-items:flex-start;justify-content:space-between;gap:20px}\n.vsm-mcp-header h2{margin:0 0 4px;font-size:20px;font-weight:600;line-height:1.35;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-header p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-primary{border:0;border-radius:6px;padding:8px 16px;background:var(--dsw-alias-button-primary-fill,#6d55ff);color:var(--dsw-alias-button-contrast-fill,#fff);font-size:13px;font-weight:500;cursor:pointer;white-space:nowrap}\n.vsm-primary:hover{background:var(--dsw-alias-button-primary-hover,#5a46e6)}\n.vsm-primary:disabled{opacity:.55;cursor:default}\n\n/* MCP 管理下的二级子页签:我的 MCP / 项目 MCP / MCP 市场 */\n.vsm-mcp-subhead{display:flex;align-items:center;justify-content:space-between;gap:16px;margin-top:-4px}\n.vsm-mcp-subtabs{display:flex;gap:18px;border-bottom:1px solid var(--dsw-alias-border-l1,#2e2e2e);flex:1}\n.vsm-mcp-subtabs button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);padding:7px 2px 9px;cursor:pointer;font-size:13px;position:relative}\n.vsm-mcp-subtabs button:hover{color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-mcp-subtabs button.active{color:var(--dsw-alias-label-primary,#fff);font-weight:500}\n.vsm-mcp-subtabs button.active::after{content:\"\";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--dsw-alias-brand-primary,#6d55ff);border-radius:2px}\n\n/* 顶层 Tab:通用 / 快捷键 / MCP 管理 / 语言服务器 / 性能优化 / 兼容性 */\n.vsm-mcp-tabs{display:flex;gap:24px;border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-mcp-tabs button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);padding:9px 2px 11px;cursor:pointer;font-size:14px;position:relative}\n.vsm-mcp-tabs button:hover{color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-mcp-tabs button.active{color:var(--dsw-alias-label-primary,#fff);font-weight:500}\n.vsm-mcp-tabs button.active::after{content:\"\";position:absolute;left:0;right:0;bottom:-1px;height:2px;background:var(--dsw-alias-brand-primary,#6d55ff);border-radius:2px}\n\n/* 统一线框面板:圆角矩形边框圈住各设置分区,提升可读性。\n 用法:<section class=\"vsm-panel\"> + 可选 <h3 class=\"vsm-panel-title\">。 */\n.vsm-panel{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;background:var(--dsw-alias-bg-layer-2,transparent);overflow:hidden}\n.vsm-panel-pad{padding:14px 16px}\n.vsm-panel-title{margin:0;padding:10px 16px;font-size:13px;font-weight:600;color:var(--dsw-alias-label-secondary,#c8c8c8);background:var(--dsw-alias-bg-mask-1,#ffffff0a);border-bottom:1px solid var(--dsw-alias-border-l1,#333)}\n.vsm-panel-body{padding:6px 16px}\n.vsm-panel-body>*:first-child{margin-top:8px}\n.vsm-panel-body>*:last-child{margin-bottom:10px}\n\n/* 通用设置 */\n.vsm-general-page{display:flex;flex-direction:column;gap:14px;max-width:720px}\n.vsm-general-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-general-page p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px}\n.vsm-general-row{display:flex;align-items:center;justify-content:space-between;gap:20px;padding:14px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);color:var(--dsw-alias-label-primary,#eee);font-size:14px}\n.vsm-general-row:last-child{border-bottom:0}\n.vsm-general-row select{min-width:220px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);font:inherit}\n.vsm-general-row small{color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n\n/* 服务卡片 */\n.vsm-mcp-card{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;padding:14px 16px;margin-bottom:10px;background:var(--dsw-alias-bg-layer-2,transparent);transition:border-color .15s}\n.vsm-mcp-card:hover{border-color:var(--dsw-alias-border-l3,#555)}\n.vsm-mcp-card-head{display:flex;justify-content:space-between;align-items:center;gap:12px}\n.vsm-mcp-title{display:flex;align-items:center;gap:9px;font-weight:600;font-size:14px;color:var(--dsw-alias-label-primary,#e6e6e6);min-width:0}\n.vsm-mcp-source{font-size:11px;font-weight:400;padding:2px 7px;border-radius:4px;background:var(--dsw-alias-bg-mask-2,#ffffff22);color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-mcp-dot{width:8px;height:8px;border-radius:50%;flex-shrink:0;background:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-mcp-dot.connected{background:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-dot.connecting{background:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-mcp-dot.disabled{background:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-mcp-actions{display:flex;align-items:center;gap:4px;flex-shrink:0}\n.vsm-mcp-actions button{border:0;background:none;color:var(--dsw-alias-label-tertiary,#9aa5b1);cursor:pointer;font-size:15px;width:28px;height:28px;border-radius:6px;line-height:1}\n.vsm-mcp-actions button:hover{color:var(--dsw-alias-label-primary,#fff);background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-mcp-actions button.vsm-danger:hover{color:var(--dsw-alias-state-error-primary,#f07878);background:var(--dsw-alias-interactive-bg-hover-danger,#ff000014)}\n.vsm-switch{font-size:14px !important}\n.vsm-switch.on{color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-mcp-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:9px 0}\n.vsm-mcp-error{color:var(--dsw-alias-state-error-primary,#f07878);font-size:12px;margin:8px 0}\n.vsm-mcp-banner{padding:9px 12px;border:1px solid var(--dsw-alias-state-error-secondary,#d9534f55);border-radius:6px;background:var(--dsw-alias-state-error-secondary,#d9534f1a);margin-bottom:10px}\n\n/* 工具 chips */\n.vsm-mcp-tools{display:flex;flex-wrap:wrap;gap:6px}\n.vsm-mcp-chip{font:12px var(--ds-font-family-code,ui-monospace,monospace);padding:4px 8px;border-radius:5px;background:var(--dsw-alias-bg-mask-2,#ffffff14);color:var(--dsw-alias-label-secondary,#c8c8c8);border:1px solid var(--dsw-alias-border-l1,#333)}\n\n/* 空态 / 加载态 */\n.vsm-mcp-empty{text-align:center;padding:56px 20px;color:var(--dsw-alias-label-tertiary,#9aa5b1);border:1px dashed var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;font-size:13px}\n\n/* 项目搜索下拉框 */\n.vsm-project-picker{position:relative;width:100%;z-index:4}\n.vsm-project-picker-trigger{width:100%;display:flex;align-items:center;justify-content:space-between;gap:12px;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-layer-1,transparent);color:var(--dsw-alias-label-primary,#e6e6e6);cursor:pointer;text-align:left}\n.vsm-project-picker-trigger:hover{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-label{display:flex;flex-direction:column;min-width:0;font-size:13px;font-weight:500}\n.vsm-project-picker-label small{margin-top:3px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-arrow{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:16px}\n.vsm-project-picker-menu{position:absolute;top:calc(100% + 6px);left:0;right:0;padding:8px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:9px;background:var(--dsw-alias-bg-overlay,#202020);box-shadow:0 12px 36px #0008}\n.vsm-project-picker-search{width:100%;box-sizing:border-box;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:var(--dsw-alias-bg-layer-1,#2b2b2b);color:var(--dsw-alias-label-primary,#eee);outline:none}\n.vsm-project-picker-search:focus{border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-picker-options{max-height:260px;overflow:auto;margin-top:6px}\n.vsm-project-option{display:flex;width:100%;flex-direction:column;gap:3px;padding:8px 9px;border:0;border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;text-align:left}\n.vsm-project-option:hover,.vsm-project-option.highlight{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-project-option.selected{color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-project-option small{overflow:hidden;color:var(--dsw-alias-label-tertiary,#9aa5b1);font:11px var(--ds-font-family-code,ui-monospace,monospace);text-overflow:ellipsis;white-space:nowrap}\n.vsm-project-picker-empty{padding:18px 8px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:center}\n\n/* 项目级 MCP 分组 */\n.vsm-project{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;margin-bottom:14px;overflow:hidden;background:var(--dsw-alias-bg-layer-1,transparent)}\n.vsm-project-head{display:flex;align-items:center;justify-content:space-between;gap:12px;padding:12px 16px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:var(--dsw-alias-bg-mask-1,#ffffff0a)}\n.vsm-project-title{display:flex;align-items:center;gap:10px;min-width:0}\n.vsm-project-icon{color:var(--dsw-alias-brand-primary,#6d55ff);font-size:15px;flex-shrink:0}\n.vsm-project-name{font-size:14px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);display:block}\n.vsm-project-path{font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-family:var(--ds-font-family-code,ui-monospace,monospace);display:block;margin-top:2px;word-break:break-all}\n.vsm-primary.vsm-small{padding:5px 12px;font-size:12px}\n.vsm-project-empty{text-align:center;padding:26px 16px;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px}\n.vsm-project .vsm-mcp-card{border:0;border-radius:0;margin:0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);background:transparent}\n.vsm-project .vsm-mcp-card:last-child{border-bottom:0}\n.vsm-project .vsm-mcp-banner{border-radius:0;margin:0}\n\n/* 新增 MCP 弹窗 */\n.vsm-mcp-modal{position:fixed;inset:0;background:var(--dsw-alias-bg-mask-drop,#000000aa);display:flex;align-items:center;justify-content:center;z-index:50}\n.vsm-mcp-dialog{width:min(560px,calc(100vw - 40px));max-height:88vh;overflow:auto;padding:22px 24px;border-radius:12px;background:var(--dsw-alias-bg-overlay,#202020);border:1px solid var(--dsw-alias-border-l2,#444);box-shadow:0 16px 60px #000c;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-mcp-dialog h3{margin:0 0 14px;font-size:16px;font-weight:600}\n.vsm-mcp-dialog label{display:flex;flex-direction:column;gap:6px;margin:12px 0;font-size:12px;color:var(--dsw-alias-label-secondary,#aaa)}\n.vsm-mcp-dialog input,.vsm-mcp-dialog select,.vsm-mcp-dialog textarea{font:inherit;color:var(--dsw-alias-label-primary,#eee);background:var(--dsw-alias-bg-layer-1,#2b2b2b);border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 10px}\n.vsm-mcp-dialog input:focus,.vsm-mcp-dialog select:focus,.vsm-mcp-dialog textarea:focus{outline:none;border-color:var(--dsw-alias-brand-primary,#6d55ff)}\n.vsm-mcp-dialog textarea{min-height:64px;resize:vertical;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-mcp-dialog-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:20px}\n.vsm-mcp-dialog-actions button{padding:8px 14px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:13px}\n.vsm-mcp-dialog-actions button:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n\n/* 兼容性条目(面板标题改用 .vsm-panel-title) */\n.vsm-compat-item{display:flex;align-items:baseline;justify-content:space-between;gap:16px;padding:10px 0;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:13px;color:var(--dsw-alias-label-primary,#eee)}\n.vsm-compat-item.ok .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-success-primary,#38bd75)}\n.vsm-compat-item.warn .vsm-compat-name::before{content:\"● \";color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-compat-name{font-weight:500;min-width:0}\n.vsm-compat-note{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;text-align:right;min-width:0}\n\n/* 开发形态开关 */\n.vsm-devform-note{display:block;margin-top:4px;font-size:11px;color:var(--dsw-alias-label-tertiary,#9aa5b1);word-break:break-all}\n.vsm-devform-actions{display:flex;flex-direction:column;align-items:flex-end;gap:6px;min-width:0}\n.vsm-devform-msg{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px;text-align:right}\n.vsm-general-row button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:6px 12px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-general-row button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-general-row button:disabled{opacity:.55;cursor:default}\n.vsm-general-row button.vsm-devform-close{color:var(--dsw-alias-state-error-primary,#f07878);border-color:var(--dsw-alias-state-error-secondary,#d9534f55)}\n\n/* keyboard shortcuts page */\n.vsm-kb-list{display:flex;flex-direction:column;gap:6px;margin-top:8px}\n.vsm-kb-row{display:flex;align-items:center;gap:10px;padding:8px 10px;border:1px solid var(--dsw-alias-border-l2,#555);border-radius:8px;background:var(--dsw-alias-bg-layer-1,#161616)}\n.vsm-kb-row.rec{border-color:var(--dsw-alias-brand-primary,#4f8cff)}\n.vsm-kb-label{flex:1;min-width:0;display:flex;flex-direction:column;gap:2px;color:var(--dsw-alias-label-primary,#eee);font-size:13px}\n.vsm-kb-warn{color:var(--dsw-alias-state-warn-primary,#e5b93f);font-size:11px}\n.vsm-kb-key{min-width:96px;text-align:center;padding:3px 10px;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;font-family:var(--ds-font-family-code,ui-monospace,monospace)}\n.vsm-kb-key.warn{border-color:var(--dsw-alias-state-warn-primary,#e5b93f);color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-key.invalid{border-color:var(--dsw-alias-state-error-primary,#d9534f);color:var(--dsw-alias-state-error-primary,#d9534f)}\n.vsm-kb-rec{font-size:12px;color:var(--dsw-alias-label-secondary,#9aa5b1)}\n.vsm-kb-actions{display:flex;gap:6px}\n.vsm-kb-actions button{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:4px 10px;background:none;color:var(--dsw-alias-label-primary,#eee);cursor:pointer;font-size:12px;white-space:nowrap}\n.vsm-kb-actions button:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-kb-actions button:disabled{opacity:.55;cursor:default}\n.vsm-kb-actionsbar{display:flex;align-items:center;gap:10px;margin-top:12px}\n.vsm-kb-dirty{flex:1;font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-kb-message{font-size:12px;color:var(--dsw-alias-brand-primary,#4f8cff);margin-top:8px}\n\n/* 语言服务器(LSP)设置子 Tab */\n.vsm-lsp-form{display:flex;flex-direction:column;gap:6px;margin-top:8px}\n.vsm-lsp-form label{display:flex;flex-direction:column;gap:4px;font-size:12px;color:var(--dsw-alias-label-secondary,#9aa5b1)}\n.vsm-lsp-form input{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.vsm-lsp-form input:focus{border-color:var(--dsw-alias-brand-primary,#4f8cff)}\n.vsm-lsp-form button{align-self:flex-start;margin-top:2px}\n.vsm-lsp-hint{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin-top:10px;line-height:1.6}\n\n/* 会话性能(PerfSettings 子 Tab) */\n.vsm-perf-page{display:flex;flex-direction:column;gap:14px;max-width:920px}\n.vsm-perf-page>.vsm-panel-body>*:first-child{margin-top:0}\n.vsm-perf-page h2{margin:0;font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-page p{margin:0;color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:13px;line-height:1.5}\n.vsm-perf-cards{display:flex;gap:12px;flex-wrap:wrap}\n.vsm-perf-card{display:flex;flex-direction:column;gap:4px;min-width:120px;padding:12px 16px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;background:var(--dsw-alias-bg-layer-2,transparent)}\n.vsm-perf-card span{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-card b{font-size:20px;color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-card b.big{color:var(--dsw-alias-state-error-primary,#e05252)}\n.vsm-perf-toolbar{display:flex;align-items:center;gap:8px;flex-wrap:wrap}\n.vsm-perf-selcount{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);margin:0 4px}\n/* 工作区列表分页器 */\n.vsm-perf-pager{display:flex;align-items:center;justify-content:space-between;gap:12px;flex-wrap:wrap;margin-top:4px}\n.vsm-perf-pager-text{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-pager-actions{display:flex;gap:8px}\n.vsm-perf-ws-list{display:flex;flex-direction:column;gap:8px}\n.vsm-perf-ws{border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:10px;overflow:hidden}\n.vsm-perf-ws-head{display:flex;align-items:center;gap:10px;padding:10px 14px;background:var(--dsw-alias-bg-layer-1,#262626);cursor:pointer;user-select:none}\n.vsm-perf-ws-head:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-perf-ws-head:focus-visible{outline:1px solid var(--dsw-alias-brand-primary,#6d55ff);outline-offset:-1px}\n.vsm-perf-ws.expanded .vsm-perf-ws-head{border-bottom:1px solid var(--dsw-alias-border-l2,#3a3a3a)}\n.vsm-perf-ws-caret{color:var(--dsw-alias-label-tertiary,#9aa5b1);font-size:12px;flex-shrink:0;transition:transform .15s;display:inline-block}\n.vsm-perf-ws-caret.open{transform:rotate(90deg)}\n.vsm-perf-ws .vsm-perf-ws-name{flex:1}\n.vsm-perf-ws-name{font-size:13px;font-weight:600;color:var(--dsw-alias-label-primary,#e6e6e6);font-family:var(--ds-font-family-code,ui-monospace,monospace);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-perf-ws-meta{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);flex-shrink:0}\n.vsm-perf-rows{display:flex;flex-direction:column}\n.vsm-perf-row{display:flex;align-items:center;gap:10px;padding:7px 14px;border-bottom:1px solid var(--dsw-alias-border-l1,#333);font-size:12px;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-perf-row:last-child{border-bottom:0}\n.vsm-perf-row:hover{background:var(--dsw-alias-interactive-bg-hover,#ffffff0d)}\n.vsm-perf-row input[type=checkbox]{accent-color:var(--dsw-alias-brand-primary,#6d55ff);cursor:pointer}\n.vsm-perf-cell{min-width:0}\n.vsm-perf-id{flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-family:var(--ds-font-family-code,ui-monospace,monospace);color:var(--dsw-alias-label-primary,#eee)}\n.vsm-perf-size{width:70px;text-align:right;flex-shrink:0;color:var(--dsw-alias-label-secondary,#c8c8c8)}\n.vsm-perf-size.big{color:var(--dsw-alias-state-error-primary,#e05252);font-weight:600}\n.vsm-perf-mtime{width:44px;flex-shrink:0;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-active{width:44px;flex-shrink:0;font-size:11px;color:var(--dsw-alias-state-warn-primary,#e5b93f);text-align:right}\n.vsm-perf-config-state{display:flex;align-items:center;gap:12px;margin:10px 0}\n.vsm-perf-note{font-size:12px;color:var(--dsw-alias-state-warn-primary,#e5b93f)}\n.vsm-perf-block{margin:8px 0 0;padding:10px 12px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:8px;background:var(--dsw-alias-bg-base,#111);color:var(--dsw-alias-label-secondary,#c8c8c8);font-size:11px;line-height:1.5;font-family:var(--ds-font-family-code,ui-monospace,monospace);white-space:pre-wrap;overflow-x:auto;max-width:100%}\n.vsm-perf-modal{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;background:var(--dsw-alias-bg-mask-1,#000000aa);z-index:1000;padding:20px}\n.vsm-perf-modal-card{width:min(560px,92vw);max-height:72vh;display:flex;flex-direction:column;gap:12px;padding:18px 20px;border:1px solid var(--dsw-alias-border-l2,#3a3a3a);border-radius:12px;background:var(--dsw-alias-bg-layer-2,#1f1f1f);color:var(--dsw-alias-label-primary,#e6e6e6)}\n.vsm-perf-modal-card h3{margin:0;font-size:16px}\n.vsm-perf-modal-note{font-size:12px}\n.vsm-perf-modal-list{list-style:none;margin:0;padding:0;overflow-y:auto;font-size:12px;color:var(--dsw-alias-label-secondary,#c8c8c8);display:flex;flex-direction:column;gap:4px}\n.vsm-perf-modal-list li{padding:4px 6px;border-radius:6px;background:var(--dsw-alias-bg-layer-1,#262626);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}\n.vsm-perf-modal-more{font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1)}\n.vsm-perf-modal-actions{display:flex;justify-content:flex-end;gap:10px;margin-top:4px}\n.vsm-secondary{border:1px solid var(--dsw-alias-border-l2,#555);border-radius:6px;padding:8px 16px;background:none;color:var(--dsw-alias-label-primary,#eee);font-size:13px;cursor:pointer;white-space:nowrap}\n.vsm-secondary:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover,#ffffff14)}\n.vsm-secondary:disabled{opacity:.55;cursor:default}\n.vsm-small{padding:4px 10px;font-size:12px}\n\n/* 扩展管理(LSP 语言服务器) */\n.vsm-mcp-actions button.vsm-primary,\n.vsm-mcp-actions button.vsm-danger{width:auto;height:auto;padding:5px 12px;font-size:12px;border-radius:6px;line-height:1.4}\n.vsm-mcp-actions button.vsm-danger{color:var(--dsw-alias-state-error-primary,#f07878);background:none}\n.vsm-mcp-actions button.vsm-danger:hover{background:var(--dsw-alias-interactive-bg-hover-danger,#ff000014)}\n.vsm-ext-ver{font-weight:400;font-size:12px;color:var(--dsw-alias-label-tertiary,#9aa5b1);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}\n";
|
|
8155
|
-
const tagId = "dsh-vscode-mode/mcp.css";
|
|
8156
|
-
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId) + "]") === null) {
|
|
8157
|
-
const tag = document.createElement("style");
|
|
8158
|
-
tag.dataset.plugin = "dsh-vscode-mode";
|
|
8159
|
-
tag.dataset.pluginCss = tagId;
|
|
8160
|
-
tag.textContent = css;
|
|
8161
|
-
document.head.appendChild(tag);
|
|
8162
|
-
}
|
|
8163
|
-
//#endregion
|
|
8164
8926
|
//#region src/client/compat.ts
|
|
8165
8927
|
/**
|
|
8166
8928
|
* dsh-vscode-mode client — 兼容层:设置桥选择 / slot 安全注册 / openPath 链式补丁 / 外部插件常量。
|
|
@@ -14218,6 +14980,7 @@ window.__ModuleLoader__.load({
|
|
|
14218
14980
|
const onKey = (event) => {
|
|
14219
14981
|
for (const command of dispatched) {
|
|
14220
14982
|
if (!matchEvent(event, bindingsOf(command.id))) continue;
|
|
14983
|
+
if (!registry.isAvailable(command.id)) continue;
|
|
14221
14984
|
event.preventDefault();
|
|
14222
14985
|
event.stopPropagation();
|
|
14223
14986
|
registry.run(command.id);
|