dsh-vscode-mode 0.1.53 → 0.1.55
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 +11 -0
- package/assets/vendor/pdfjs/build/pdf.mjs +26370 -0
- package/assets/vendor/pdfjs/build/pdf.worker.mjs +61080 -0
- package/assets/vendor/pdfjs/cmaps/78-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78ms-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/78ms-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/83pv-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/90ms-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/90ms-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/90msp-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/90msp-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/90pv-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/90pv-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Add-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Add-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Add-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Add-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-0.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-1.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-3.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-4.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-5.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-6.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-CNS1-UCS2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-0.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-1.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-3.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-4.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-5.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-GB1-UCS2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-0.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-1.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-3.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-4.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-5.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-6.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Japan1-UCS2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-0.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-1.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Adobe-Korea1-UCS2.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/B5pc-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/B5pc-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/CNS-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/CNS-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/CNS1-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/CNS1-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/CNS2-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/CNS2-V.bcmap +3 -0
- package/assets/vendor/pdfjs/cmaps/ETHK-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/ETHK-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/ETen-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/ETen-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/ETenms-B5-H.bcmap +3 -0
- package/assets/vendor/pdfjs/cmaps/ETenms-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Ext-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Ext-RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Ext-RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Ext-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GB-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GB-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GB-H.bcmap +4 -0
- package/assets/vendor/pdfjs/cmaps/GB-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBK-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBK-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBK2K-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBK2K-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBKp-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBKp-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBT-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBT-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBT-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBT-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBTpc-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBTpc-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBpc-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/GBpc-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKdla-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKdla-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKdlb-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKdlb-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKgccs-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKgccs-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKm314-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKm314-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKm471-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKm471-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKscs-B5-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/HKscs-B5-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Hankaku.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Hiragana.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSC-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSC-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSC-Johab-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSC-Johab-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSCms-UHC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSCms-UHC-HW-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSCms-UHC-HW-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSCms-UHC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSCpc-EUC-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/KSCpc-EUC-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Katakana.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/LICENSE +36 -0
- package/assets/vendor/pdfjs/cmaps/NWP-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/NWP-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/RKSJ-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/RKSJ-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/Roman.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UCS2-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UCS2-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UTF16-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UTF16-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UTF8-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniCNS-UTF8-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UCS2-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UCS2-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UTF16-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UTF16-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UTF8-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniGB-UTF8-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-HW-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UCS2-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UTF16-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UTF16-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UTF8-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS-UTF8-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF16-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF16-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF8-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJIS2004-UTF8-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISPro-UCS2-HW-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISPro-UCS2-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISPro-UTF8-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISX0213-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISX0213-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniJISX02132004-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UCS2-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UCS2-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UTF16-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UTF16-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UTF32-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UTF32-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UTF8-H.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/UniKS-UTF8-V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/V.bcmap +0 -0
- package/assets/vendor/pdfjs/cmaps/WP-Symbol.bcmap +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitDingbats.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitFixed.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitFixedBold.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitFixedBoldItalic.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitFixedItalic.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitSerif.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitSerifBold.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitSerifBoldItalic.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitSerifItalic.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/FoxitSymbol.pfb +0 -0
- package/assets/vendor/pdfjs/standard_fonts/LICENSE_FOXIT +27 -0
- package/assets/vendor/pdfjs/standard_fonts/LICENSE_LIBERATION +102 -0
- package/assets/vendor/pdfjs/standard_fonts/LiberationSans-Bold.ttf +0 -0
- package/assets/vendor/pdfjs/standard_fonts/LiberationSans-BoldItalic.ttf +0 -0
- package/assets/vendor/pdfjs/standard_fonts/LiberationSans-Italic.ttf +0 -0
- package/assets/vendor/pdfjs/standard_fonts/LiberationSans-Regular.ttf +0 -0
- package/assets/vendor/pdfjs/web/pdf_viewer.css +6989 -0
- package/assets/vendor/pdfjs/web/pdf_viewer.mjs +9459 -0
- package/lib/client.js +852 -13
- package/lib/client.js.map +1 -1
- package/lib/index.js +137 -17
- package/lib/index.js.map +1 -1
- package/package.json +1 -1
- package/src/client/compat.ts +31 -0
- package/src/client/imagePreview.ts +45 -0
- package/src/client/index.ts +46 -8
- package/src/client/pdf/pdfLoader.ts +82 -0
- package/src/client/pdf/pdfPanel.ts +239 -0
- package/src/client/pdfPreview.ts +48 -0
- package/src/client/remoteOpenRouter.ts +78 -0
- package/src/client/styles/editor.css +17 -0
- package/src/client/ui/EditorView.ts +221 -2
- package/src/compat.ts +1 -1
- package/src/dshVersion.ts +1 -0
- package/src/routes.ts +3 -0
- package/src/rpc.ts +65 -13
- package/src/shared/rpc.ts +50 -2
- package/src/store.ts +2 -0
package/lib/client.js
CHANGED
|
@@ -31,7 +31,7 @@ window.__ModuleLoader__.load({
|
|
|
31
31
|
let react_dom_client = require("react-dom/client");
|
|
32
32
|
let react_dom = require("react-dom");
|
|
33
33
|
//#region \0dsh-css:/home/runner/work/DSH_VsCodeMode/DSH_VsCodeMode/src/client/styles/editor.css.mjs
|
|
34
|
-
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\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-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\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: 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: #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: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #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: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px 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: #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: #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-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: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #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: 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; }\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: #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: #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 rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; 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: #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 rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #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: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #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: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #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 rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; 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: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
|
|
34
|
+
const css$1 = "/* dsh-vscode-mode 编辑区样式(原 ensureEdrvStyles 字符串,落盘为真 .css,由 tsdown CSS-inline 注入) */\n/* 浅色主题(对齐参考图:#f8f8f8 近白底 + 薄荷绿药丸 + 青绿文字 + 三文鱼 undo + 浅灰边框):\n 在 [data-edrv-view] 作用域内重定义 --dsw-alias-*,级联命中组件内联样式与 CSS。 */\n[data-edrv-view] { box-sizing: border-box; --edrv-tab-h: 34px; --dsw-alias-bg-base: #f8f8f8; --dsw-alias-bg-layer-1: #ffffff; --dsw-alias-bg-layer-2: #f0f4f4; --dsw-alias-bg-overlay: #ffffff; --dsw-alias-label-primary: #1f2933; --dsw-alias-label-secondary: #52606d; --dsw-alias-label-tertiary: #9aa5b1; --dsw-alias-border-l1: #e0e6e8; --dsw-alias-border-l2: #cbd2d9; --dsw-alias-brand-primary: #0f9d58; --dsw-alias-state-success-primary: #0f9d58; --dsw-alias-state-error-primary: #d9534f; --dsw-alias-state-warn-primary: #d97706; --dsw-alias-interactive-bg-hover: rgba(15,157,88,.08); }\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-dot { width: 7px; height: 7px; border-radius: 50%; background: var(--dsw-alias-brand-primary, #4f8cff); flex-shrink: 0; }\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: 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: #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: rgba(15,157,88,.10); }\n[data-edrv-view] .edrv-mn-gutter-add { color: #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: #fdeaea; border-top: 1px solid rgba(217,83,79,.35); border-bottom: 1px solid rgba(217,83,79,.35); box-shadow: inset 0 0 0 1px 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: #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: #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: #e8f8e8; color: #0f7a45; border: 1px solid rgba(15,157,88,.4); }\n[data-edrv-view] .edrv-pill-undo { background: #fdeaea; color: #c0392b; border: 1px solid rgba(217,83,79,.4); }\n[data-edrv-view] .edrv-pill-ghost { background: #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: 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; }\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: #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: #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 rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; 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: #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 rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; color: var(--dsw-alias-state-error-primary, #d9534f); font-size: 11px; }\n[data-edrv-view] .edrv-search-warn { padding: 6px 8px; border: 1px solid rgba(240,173,78,.45); border-radius: 6px; background: #fdf6e3; color: #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: rgba(15,157,88,.15); color: #0b7c46; }\n[data-edrv-view] .edrv-rules-type-auto { background: rgba(79,140,255,.16); color: #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: #b9c4cc; cursor: pointer; transition: background .15s; flex-shrink: 0; padding: 0; }\n[data-edrv-view] .edrv-rules-switch.on { background: #7c5cff; }\n[data-edrv-view] .edrv-rules-knob { position: absolute; top: 2px; left: 2px; width: 12px; height: 12px; border-radius: 50%; background: #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 rgba(217,83,79,.4); border-radius: 6px; background: #fdeaea; 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: #fff; font-size: 12px; cursor: pointer; }\n[data-edrv-view] .edrv-rules-save:disabled { opacity: .5; cursor: default; }\n\n\n\n";
|
|
35
35
|
const tagId$1 = "dsh-vscode-mode/editor.css";
|
|
36
36
|
if (typeof document !== "undefined" && document.querySelector("style[data-plugin-css=" + JSON.stringify(tagId$1) + "]") === null) {
|
|
37
37
|
const tag = document.createElement("style");
|
|
@@ -44,6 +44,22 @@ window.__ModuleLoader__.load({
|
|
|
44
44
|
//#region src/shared/rpc.ts
|
|
45
45
|
/** webServer 精确路由。 */
|
|
46
46
|
const RPC_PATH = "/edrv/rpc";
|
|
47
|
+
/**
|
|
48
|
+
* 图片扩展名(小写、无点)→ MIME。edrv.read base64 响应与 client 图片预览共用,
|
|
49
|
+
* 收敛在此避免 host/client 两处漂移。
|
|
50
|
+
* @author ddj 2026年09月08号
|
|
51
|
+
*/
|
|
52
|
+
const IMAGE_MIME = {
|
|
53
|
+
png: "image/png",
|
|
54
|
+
jpg: "image/jpeg",
|
|
55
|
+
jpeg: "image/jpeg",
|
|
56
|
+
gif: "image/gif",
|
|
57
|
+
webp: "image/webp",
|
|
58
|
+
bmp: "image/bmp",
|
|
59
|
+
ico: "image/x-icon",
|
|
60
|
+
avif: "image/avif",
|
|
61
|
+
svg: "image/svg+xml"
|
|
62
|
+
};
|
|
47
63
|
//#endregion
|
|
48
64
|
//#region src/client/rpc.ts
|
|
49
65
|
/**
|
|
@@ -1105,6 +1121,457 @@ window.__ModuleLoader__.load({
|
|
|
1105
1121
|
return monacoPromise.finally(unsubscribe);
|
|
1106
1122
|
}
|
|
1107
1123
|
//#endregion
|
|
1124
|
+
//#region src/client/imagePreview.ts
|
|
1125
|
+
/**
|
|
1126
|
+
* dsh-vscode-mode client — 图片文件判定与 data URL 组装(编辑区图片预览面板用)。
|
|
1127
|
+
* 纯函数、无 DOM 依赖,便于单测;MIME 表收敛在 shared/rpc.ts(host base64 响应同源)。
|
|
1128
|
+
* @author ddj 2026年09月08号
|
|
1129
|
+
*/
|
|
1130
|
+
/** 可预览的图片扩展名集合(小写、无点)。 */
|
|
1131
|
+
const IMAGE_EXT_SET = new Set(Object.keys(IMAGE_MIME));
|
|
1132
|
+
/**
|
|
1133
|
+
* 判断路径是否为可预览的图片文件(取 basename 扩展名,大小写不敏感)。
|
|
1134
|
+
* @author ddj 2026年09月08号
|
|
1135
|
+
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
1136
|
+
* @returns 是否图片文件
|
|
1137
|
+
*/
|
|
1138
|
+
function isImagePath(path) {
|
|
1139
|
+
const base = String(path || "").split(/[\\/]/).pop() || "";
|
|
1140
|
+
const dot = base.lastIndexOf(".");
|
|
1141
|
+
if (dot <= 0) return false;
|
|
1142
|
+
return IMAGE_EXT_SET.has(base.slice(dot + 1).toLowerCase());
|
|
1143
|
+
}
|
|
1144
|
+
/**
|
|
1145
|
+
* 判断路径是否为 SVG 文件(唯一提供「以文本打开」切换的图片格式)。
|
|
1146
|
+
* @author ddj 2026年09月08号
|
|
1147
|
+
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
1148
|
+
* @returns 是否 SVG
|
|
1149
|
+
*/
|
|
1150
|
+
function isSvgPath(path) {
|
|
1151
|
+
const base = String(path || "").split(/[\\/]/).pop() || "";
|
|
1152
|
+
const dot = base.lastIndexOf(".");
|
|
1153
|
+
return dot > 0 && base.slice(dot + 1).toLowerCase() === "svg";
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* base64 文本 → 可直接赋给 `<img src>` 的 data URL。
|
|
1157
|
+
* @author ddj 2026年09月08号
|
|
1158
|
+
* @param base64 base64 文本(不含 data: 前缀)
|
|
1159
|
+
* @param mime MIME 类型(host edrv.read base64 响应携带)
|
|
1160
|
+
* @returns data URL 字符串
|
|
1161
|
+
*/
|
|
1162
|
+
function dataUrlOf(base64, mime) {
|
|
1163
|
+
return "data:" + (mime || "application/octet-stream") + ";base64," + base64;
|
|
1164
|
+
}
|
|
1165
|
+
//#endregion
|
|
1166
|
+
//#region src/client/pdfPreview.ts
|
|
1167
|
+
/**
|
|
1168
|
+
* 判断路径是否为 PDF 文件(取 basename 扩展名,大小写不敏感)。
|
|
1169
|
+
* @author ddj 2026年09月22号
|
|
1170
|
+
* @param path 文件路径(`/` 或 `\` 分隔均可)
|
|
1171
|
+
* @returns 是否 PDF 文件
|
|
1172
|
+
*/
|
|
1173
|
+
function isPdfPath(path) {
|
|
1174
|
+
const base = String(path || "").split(/[\\/]/).pop() || "";
|
|
1175
|
+
const dot = base.lastIndexOf(".");
|
|
1176
|
+
return dot > 0 && base.slice(dot + 1).toLowerCase() === "pdf";
|
|
1177
|
+
}
|
|
1178
|
+
/**
|
|
1179
|
+
* base64 文本 → 二进制字节(喂给 pdf.js getDocument 的 data 入参)。
|
|
1180
|
+
* @author ddj 2026年09月22号
|
|
1181
|
+
* @param base64 base64 文本(不含 data: 前缀,host edrv.read base64 响应携带)
|
|
1182
|
+
* @returns 原始字节
|
|
1183
|
+
*/
|
|
1184
|
+
function base64ToBytes(base64) {
|
|
1185
|
+
const bin = atob(String(base64 || ""));
|
|
1186
|
+
const bytes = new Uint8Array(bin.length);
|
|
1187
|
+
for (let i = 0; i < bin.length; i++) bytes[i] = bin.charCodeAt(i);
|
|
1188
|
+
return bytes;
|
|
1189
|
+
}
|
|
1190
|
+
/**
|
|
1191
|
+
* 二进制字节 → base64 文本(编辑保存回传 host 前的编码步骤)。
|
|
1192
|
+
* @author ddj 2026年09月22号
|
|
1193
|
+
* @param bytes 原始字节
|
|
1194
|
+
* @returns base64 文本
|
|
1195
|
+
*/
|
|
1196
|
+
function bytesToBase64(bytes) {
|
|
1197
|
+
let bin = "";
|
|
1198
|
+
const chunk = 32768;
|
|
1199
|
+
for (let i = 0; i < bytes.length; i += chunk) bin += String.fromCharCode(...bytes.subarray(i, i + chunk));
|
|
1200
|
+
return btoa(bin);
|
|
1201
|
+
}
|
|
1202
|
+
//#endregion
|
|
1203
|
+
//#region src/client/pdf/pdfLoader.ts
|
|
1204
|
+
/**
|
|
1205
|
+
* dsh-vscode-mode client — pdf.js 加载器(vendor 产物离线随包,/edrv/vendor/pdfjs/*)。
|
|
1206
|
+
* 加载链:module script 内按序动态 import build/pdf.mjs(自挂 globalThis.pdfjsLib)→
|
|
1207
|
+
* web/pdf_viewer.mjs(从 globalThis.pdfjsLib 解构)→ window.__edrvPdfjs handoff。
|
|
1208
|
+
* 用 script 注入而非打包内 import():客户端包是 CJS,bundler 会改写动态 import 破坏 URL 语义。
|
|
1209
|
+
* 作者 ddj 2026-09-22
|
|
1210
|
+
*/
|
|
1211
|
+
/** vendor 根(routes.ts /edrv/vendor 前缀路由分发 assets/vendor/*)。 */
|
|
1212
|
+
const PDFJS_BASE = "/edrv/vendor/pdfjs";
|
|
1213
|
+
/** pdf.js Worker 地址(GlobalWorkerOptions.workerSrc)。 */
|
|
1214
|
+
const PDFJS_WORKER_SRC = PDFJS_BASE + "/build/pdf.worker.mjs";
|
|
1215
|
+
/** CJK 字符映射目录(中文 PDF 渲染必需,尾斜杠固定)。 */
|
|
1216
|
+
const PDFJS_CMAP_URL = PDFJS_BASE + "/cmaps/";
|
|
1217
|
+
/** 标准字体目录(未嵌字体 PDF 兜底,尾斜杠固定)。 */
|
|
1218
|
+
const PDFJS_FONT_URL = PDFJS_BASE + "/standard_fonts/";
|
|
1219
|
+
/** 组件层样式(pdfViewer/textLayer/annotationEditor 布局)。 */
|
|
1220
|
+
const PDFJS_CSS_URL = PDFJS_BASE + "/web/pdf_viewer.css";
|
|
1221
|
+
let pdfjsPromise = null;
|
|
1222
|
+
/**
|
|
1223
|
+
* 注入 pdf_viewer.css(幂等;vendor 路由带 etag 协商缓存,重复挂载走 304)。
|
|
1224
|
+
* @author ddj 2026年09月22号
|
|
1225
|
+
*/
|
|
1226
|
+
function ensurePdfCss() {
|
|
1227
|
+
if (typeof document === "undefined") return;
|
|
1228
|
+
if (document.querySelector("link[data-edrv-pdfjs-css]")) return;
|
|
1229
|
+
const link = document.createElement("link");
|
|
1230
|
+
link.rel = "stylesheet";
|
|
1231
|
+
link.href = PDFJS_CSS_URL;
|
|
1232
|
+
link.dataset.edrvPdfjsCss = "1";
|
|
1233
|
+
document.head.appendChild(link);
|
|
1234
|
+
}
|
|
1235
|
+
/**
|
|
1236
|
+
* 加载 pdf.js(core + viewer 组件层):去重 promise,失败重置允许重试(对齐 monaco loader)。
|
|
1237
|
+
* @author ddj 2026年09月22号
|
|
1238
|
+
* @returns Promise<{lib, viewer}> lib=build/pdf.mjs(getDocument/GlobalWorkerOptions/编辑器枚举等),viewer=web/pdf_viewer.mjs(PDFViewer/EventBus 等)
|
|
1239
|
+
*/
|
|
1240
|
+
function loadPdfjs() {
|
|
1241
|
+
if (!pdfjsPromise) pdfjsPromise = new Promise((resolve, reject) => {
|
|
1242
|
+
ensurePdfCss();
|
|
1243
|
+
const boot = () => {
|
|
1244
|
+
const handoff = window.__edrvPdfjs;
|
|
1245
|
+
if (handoff && handoff.lib && handoff.viewer) {
|
|
1246
|
+
try {
|
|
1247
|
+
handoff.lib.GlobalWorkerOptions.workerSrc = PDFJS_WORKER_SRC;
|
|
1248
|
+
} catch (error) {}
|
|
1249
|
+
resolve(handoff);
|
|
1250
|
+
return;
|
|
1251
|
+
}
|
|
1252
|
+
reject(/* @__PURE__ */ new Error("pdf.js 模块加载失败:handoff 缺失"));
|
|
1253
|
+
};
|
|
1254
|
+
const fail = (error) => {
|
|
1255
|
+
pdfjsPromise = null;
|
|
1256
|
+
reject(error instanceof Error ? error : new Error(String(error)));
|
|
1257
|
+
};
|
|
1258
|
+
const existing = document.querySelector("script[data-edrv-pdfjs-loader]");
|
|
1259
|
+
if (existing) {
|
|
1260
|
+
existing.addEventListener("edrv-pdfjs-ready", boot, { once: true });
|
|
1261
|
+
if (window.__edrvPdfjs) boot();
|
|
1262
|
+
return;
|
|
1263
|
+
}
|
|
1264
|
+
const s = document.createElement("script");
|
|
1265
|
+
s.type = "module";
|
|
1266
|
+
s.textContent = "import * as lib from \"/edrv/vendor/pdfjs/build/pdf.mjs\";\nimport * as viewer from \"/edrv/vendor/pdfjs/web/pdf_viewer.mjs\";\nwindow.__edrvPdfjs = { lib, viewer };\ndocument.querySelector(\"script[data-edrv-pdfjs-loader]\")?.dispatchEvent(new Event(\"edrv-pdfjs-ready\"));";
|
|
1267
|
+
s.dataset.edrvPdfjsLoader = "1";
|
|
1268
|
+
s.onload = boot;
|
|
1269
|
+
s.onerror = () => fail(/* @__PURE__ */ new Error("pdf.js loader 脚本加载失败(检查 assets/vendor/pdfjs 完整 / /edrv/vendor 路由可达)"));
|
|
1270
|
+
document.head.appendChild(s);
|
|
1271
|
+
});
|
|
1272
|
+
return pdfjsPromise;
|
|
1273
|
+
}
|
|
1274
|
+
//#endregion
|
|
1275
|
+
//#region src/client/pdf/pdfPanel.ts
|
|
1276
|
+
/**
|
|
1277
|
+
* dsh-vscode-mode client — PDF 面板控制器(命令式 DOM,React 只渲染外壳 div)。
|
|
1278
|
+
* 浏览:PDFViewer 组件(虚拟化渲染 + 文本层);编辑:内置注释编辑器
|
|
1279
|
+
* (FreeText 文本框 / Ink 画笔 / Highlight 高亮),保存经 pdfDocument.saveDocument()
|
|
1280
|
+
* → base64 → edrv.saveBinary 回写原文件。接线方式对齐官方 viewer(web/app.js)。
|
|
1281
|
+
* 作者 ddj 2026-09-22
|
|
1282
|
+
*/
|
|
1283
|
+
/** 无障碍占位 l10n:组件内 translate 为 fire-and-forget,stub 避免触发 locale 404。 */
|
|
1284
|
+
const L10N_STUB = {
|
|
1285
|
+
get: async (key) => key,
|
|
1286
|
+
translate: async () => {},
|
|
1287
|
+
getDirection: () => "ltr"
|
|
1288
|
+
};
|
|
1289
|
+
/**
|
|
1290
|
+
* PDF 面板控制器工厂。
|
|
1291
|
+
* @author ddj 2026年09月22号
|
|
1292
|
+
* @param deps 依赖:sessionId/path(保存回写目标)+ 状态栏回调
|
|
1293
|
+
* @returns 控制器:mount/destroy/savePdf/setMode/isDirty
|
|
1294
|
+
*/
|
|
1295
|
+
function createPdfPanel(deps) {
|
|
1296
|
+
const status = (t) => {
|
|
1297
|
+
try {
|
|
1298
|
+
deps.setStatus(t);
|
|
1299
|
+
} catch {}
|
|
1300
|
+
};
|
|
1301
|
+
let stage = null;
|
|
1302
|
+
let pageLabel = null;
|
|
1303
|
+
let eventBus = null;
|
|
1304
|
+
let busAbort = null;
|
|
1305
|
+
let editorTypes = null;
|
|
1306
|
+
let pdfViewer = null;
|
|
1307
|
+
let pdfDocument = null;
|
|
1308
|
+
let loadingTask = null;
|
|
1309
|
+
let modeButtons = null;
|
|
1310
|
+
let destroyed = false;
|
|
1311
|
+
let dirty = false;
|
|
1312
|
+
let saving = false;
|
|
1313
|
+
/** 脏状态上抛(tab 脏点)+ 本地记忆。 */
|
|
1314
|
+
const setDirty = (value) => {
|
|
1315
|
+
dirty = value;
|
|
1316
|
+
if (modeButtons) modeButtons.save.classList.toggle("edrv-pdf-dirty", value);
|
|
1317
|
+
try {
|
|
1318
|
+
deps.onDirtyChange(value);
|
|
1319
|
+
} catch {}
|
|
1320
|
+
};
|
|
1321
|
+
/** 页码指示更新(pagechanging/pagesinit 事件)。 */
|
|
1322
|
+
const updatePageLabel = () => {
|
|
1323
|
+
if (!pageLabel || !pdfViewer) return;
|
|
1324
|
+
pageLabel.textContent = pdfViewer.currentPageNumber + " / " + pdfViewer.pagesCount;
|
|
1325
|
+
};
|
|
1326
|
+
/** 编辑模式按钮高亮同步(annotationeditormodechanged 事件;evt.mode 为枚举数值)。 */
|
|
1327
|
+
const syncModeButtons = (mode) => {
|
|
1328
|
+
if (!modeButtons || !editorTypes) return;
|
|
1329
|
+
const key = {
|
|
1330
|
+
[editorTypes.NONE]: "none",
|
|
1331
|
+
[editorTypes.FREETEXT]: "freetext",
|
|
1332
|
+
[editorTypes.INK]: "ink",
|
|
1333
|
+
[editorTypes.HIGHLIGHT]: "highlight"
|
|
1334
|
+
}[mode] ?? "none";
|
|
1335
|
+
for (const k of Object.keys(modeButtons.modes)) modeButtons.modes[k].classList.toggle("edrv-pdf-mode-on", k === key);
|
|
1336
|
+
};
|
|
1337
|
+
/** 编辑模式符号键 → AnnotationEditorType 数值(版本间枚举值有差异,禁止硬编码)。 */
|
|
1338
|
+
const modeValueOf = (key) => {
|
|
1339
|
+
if (!editorTypes) return null;
|
|
1340
|
+
return {
|
|
1341
|
+
none: editorTypes.NONE,
|
|
1342
|
+
freetext: editorTypes.FREETEXT,
|
|
1343
|
+
ink: editorTypes.INK,
|
|
1344
|
+
highlight: editorTypes.HIGHLIGHT
|
|
1345
|
+
}[key] ?? null;
|
|
1346
|
+
};
|
|
1347
|
+
/**
|
|
1348
|
+
* 切换编辑模式(进入注释编辑器某模式或退出回 NONE)。
|
|
1349
|
+
* @author ddj 2026年09月22号
|
|
1350
|
+
* @param key 模式符号键:none/freetext/ink/highlight
|
|
1351
|
+
*/
|
|
1352
|
+
const applyMode = (key) => {
|
|
1353
|
+
if (!pdfViewer || !pdfDocument) {
|
|
1354
|
+
status("PDF 未就绪");
|
|
1355
|
+
return;
|
|
1356
|
+
}
|
|
1357
|
+
const mode = modeValueOf(key);
|
|
1358
|
+
if (mode === null) return;
|
|
1359
|
+
try {
|
|
1360
|
+
pdfViewer.annotationEditorMode = { mode };
|
|
1361
|
+
status(key === "none" ? "已退出编辑" : "编辑模式:" + (key === "freetext" ? "文本框" : key === "ink" ? "画笔" : "高亮"));
|
|
1362
|
+
} catch (error) {
|
|
1363
|
+
status("切换编辑模式失败:" + String(error));
|
|
1364
|
+
}
|
|
1365
|
+
};
|
|
1366
|
+
/**
|
|
1367
|
+
* 保存编辑:saveDocument 导出 → base64 → edrv.saveBinary 回写。
|
|
1368
|
+
* @author ddj 2026年09月22号
|
|
1369
|
+
* @returns Promise<boolean> 是否成功
|
|
1370
|
+
*/
|
|
1371
|
+
const savePdf = async () => {
|
|
1372
|
+
if (saving) return false;
|
|
1373
|
+
if (!pdfDocument) {
|
|
1374
|
+
status("PDF 未就绪");
|
|
1375
|
+
return false;
|
|
1376
|
+
}
|
|
1377
|
+
if (!dirty) {
|
|
1378
|
+
status("PDF 无未保存修改");
|
|
1379
|
+
return true;
|
|
1380
|
+
}
|
|
1381
|
+
saving = true;
|
|
1382
|
+
status("正在保存 PDF…");
|
|
1383
|
+
try {
|
|
1384
|
+
const data = await pdfDocument.saveDocument();
|
|
1385
|
+
const res = await rpc("edrv.saveBinary", {
|
|
1386
|
+
sessionId: deps.sessionId,
|
|
1387
|
+
path: deps.path,
|
|
1388
|
+
content: bytesToBase64(data),
|
|
1389
|
+
encoding: "base64"
|
|
1390
|
+
});
|
|
1391
|
+
if (res && res.ok) {
|
|
1392
|
+
setDirty(false);
|
|
1393
|
+
try {
|
|
1394
|
+
pdfDocument.annotationStorage.resetModified();
|
|
1395
|
+
} catch {}
|
|
1396
|
+
status("已保存 " + (/* @__PURE__ */ new Date()).toTimeString().slice(0, 8));
|
|
1397
|
+
return true;
|
|
1398
|
+
}
|
|
1399
|
+
status("保存失败");
|
|
1400
|
+
try {
|
|
1401
|
+
deps.setError(res?.error ? String(res.error) : "保存失败");
|
|
1402
|
+
} catch {}
|
|
1403
|
+
return false;
|
|
1404
|
+
} catch (error) {
|
|
1405
|
+
status("保存失败");
|
|
1406
|
+
try {
|
|
1407
|
+
deps.setError("PDF 保存异常:" + String(error));
|
|
1408
|
+
} catch {}
|
|
1409
|
+
return false;
|
|
1410
|
+
} finally {
|
|
1411
|
+
saving = false;
|
|
1412
|
+
}
|
|
1413
|
+
};
|
|
1414
|
+
/** 工具条 DOM(页码/缩放/编辑模式/保存/刷新)。 */
|
|
1415
|
+
const buildToolbar = (root) => {
|
|
1416
|
+
const bar = document.createElement("div");
|
|
1417
|
+
bar.className = "edrv-pdf-bar";
|
|
1418
|
+
const mkBtn = (text, title, onClick, cls) => {
|
|
1419
|
+
const b = document.createElement("button");
|
|
1420
|
+
b.className = cls || "edrv-pill edrv-pill-ghost";
|
|
1421
|
+
b.textContent = text;
|
|
1422
|
+
b.title = title;
|
|
1423
|
+
b.addEventListener("click", onClick);
|
|
1424
|
+
bar.appendChild(b);
|
|
1425
|
+
return b;
|
|
1426
|
+
};
|
|
1427
|
+
mkBtn("◀", "上一页", () => {
|
|
1428
|
+
if (pdfViewer) pdfViewer.currentPageNumber = Math.max(1, pdfViewer.currentPageNumber - 1);
|
|
1429
|
+
});
|
|
1430
|
+
pageLabel = document.createElement("span");
|
|
1431
|
+
pageLabel.className = "edrv-pdf-page";
|
|
1432
|
+
pageLabel.textContent = "…";
|
|
1433
|
+
bar.appendChild(pageLabel);
|
|
1434
|
+
mkBtn("▶", "下一页", () => {
|
|
1435
|
+
if (pdfViewer) pdfViewer.currentPageNumber = Math.min(pdfViewer.pagesCount, pdfViewer.currentPageNumber + 1);
|
|
1436
|
+
});
|
|
1437
|
+
mkBtn("−", "缩小", () => {
|
|
1438
|
+
try {
|
|
1439
|
+
pdfViewer.decreaseScale();
|
|
1440
|
+
} catch {}
|
|
1441
|
+
}, "edrv-pill edrv-pill-ghost edrv-pdf-zoom");
|
|
1442
|
+
mkBtn("+", "放大", () => {
|
|
1443
|
+
try {
|
|
1444
|
+
pdfViewer.increaseScale();
|
|
1445
|
+
} catch {}
|
|
1446
|
+
}, "edrv-pill edrv-pill-ghost edrv-pdf-zoom");
|
|
1447
|
+
bar.appendChild(document.createElement("span")).className = "edrv-pdf-sep";
|
|
1448
|
+
const modes = {};
|
|
1449
|
+
modes.freetext = mkBtn("✎ 文本框", "插入文本框注释", () => applyMode("freetext"));
|
|
1450
|
+
modes.ink = mkBtn("🖌 画笔", "手绘画笔注释", () => applyMode("ink"));
|
|
1451
|
+
modes.highlight = mkBtn("🖍 高亮", "高亮选中文本", () => applyMode("highlight"));
|
|
1452
|
+
modes.none = mkBtn("☐ 选择", "退出编辑模式", () => applyMode("none"));
|
|
1453
|
+
modeButtons = {
|
|
1454
|
+
modes,
|
|
1455
|
+
save: null
|
|
1456
|
+
};
|
|
1457
|
+
bar.appendChild(document.createElement("span")).className = "edrv-pdf-sep";
|
|
1458
|
+
mkBtn("⟳", "重新加载文件", () => {
|
|
1459
|
+
try {
|
|
1460
|
+
deps.onReload();
|
|
1461
|
+
} catch {}
|
|
1462
|
+
});
|
|
1463
|
+
modeButtons.save = mkBtn("💾 保存", "保存修改到文件 (Ctrl+S)", () => {
|
|
1464
|
+
savePdf();
|
|
1465
|
+
});
|
|
1466
|
+
root.appendChild(bar);
|
|
1467
|
+
};
|
|
1468
|
+
/**
|
|
1469
|
+
* 挂载面板并加载 PDF 字节。
|
|
1470
|
+
* @author ddj 2026年09月22号
|
|
1471
|
+
* @param host React 渲染的外壳 div(挂载后保持引用稳定)
|
|
1472
|
+
* @param bytes PDF 原始字节
|
|
1473
|
+
* @returns Promise<void> 渲染就绪或失败(失败置 deps.setError)
|
|
1474
|
+
*/
|
|
1475
|
+
const mount = async (host, bytes) => {
|
|
1476
|
+
try {
|
|
1477
|
+
const pdfjs = await loadPdfjs();
|
|
1478
|
+
if (destroyed) return;
|
|
1479
|
+
editorTypes = pdfjs.lib.AnnotationEditorType;
|
|
1480
|
+
busAbort = new AbortController();
|
|
1481
|
+
const onBus = (name, fn) => eventBus.on(name, fn, { signal: busAbort.signal });
|
|
1482
|
+
const root = document.createElement("div");
|
|
1483
|
+
root.className = "edrv-pdf";
|
|
1484
|
+
buildToolbar(root);
|
|
1485
|
+
stage = document.createElement("div");
|
|
1486
|
+
stage.className = "edrv-pdf-stage";
|
|
1487
|
+
const viewerDiv = document.createElement("div");
|
|
1488
|
+
viewerDiv.className = "pdfViewer edrv-pdf-viewer";
|
|
1489
|
+
stage.appendChild(viewerDiv);
|
|
1490
|
+
root.appendChild(stage);
|
|
1491
|
+
host.textContent = "";
|
|
1492
|
+
host.appendChild(root);
|
|
1493
|
+
eventBus = new pdfjs.viewer.EventBus();
|
|
1494
|
+
const linkService = new pdfjs.viewer.PDFLinkService({ eventBus });
|
|
1495
|
+
pdfViewer = new pdfjs.viewer.PDFViewer({
|
|
1496
|
+
container: stage,
|
|
1497
|
+
viewer: viewerDiv,
|
|
1498
|
+
eventBus,
|
|
1499
|
+
linkService,
|
|
1500
|
+
l10n: L10N_STUB,
|
|
1501
|
+
textLayerMode: 1,
|
|
1502
|
+
annotationEditorMode: editorTypes.NONE
|
|
1503
|
+
});
|
|
1504
|
+
linkService.setViewer(pdfViewer);
|
|
1505
|
+
onBus("pagechanging", updatePageLabel);
|
|
1506
|
+
onBus("pagesinit", () => {
|
|
1507
|
+
try {
|
|
1508
|
+
pdfViewer.currentScaleValue = "page-width";
|
|
1509
|
+
} catch {}
|
|
1510
|
+
updatePageLabel();
|
|
1511
|
+
});
|
|
1512
|
+
onBus("annotationeditormodechanged", (evt) => syncModeButtons(evt?.mode));
|
|
1513
|
+
loadingTask = pdfjs.lib.getDocument({
|
|
1514
|
+
data: bytes,
|
|
1515
|
+
cMapUrl: PDFJS_CMAP_URL,
|
|
1516
|
+
cMapPacked: true,
|
|
1517
|
+
standardFontDataUrl: PDFJS_FONT_URL
|
|
1518
|
+
});
|
|
1519
|
+
pdfDocument = await loadingTask.promise;
|
|
1520
|
+
if (destroyed) {
|
|
1521
|
+
loadingTask.destroy();
|
|
1522
|
+
return;
|
|
1523
|
+
}
|
|
1524
|
+
const storage = pdfDocument.annotationStorage;
|
|
1525
|
+
storage.onSetModified = () => setDirty(true);
|
|
1526
|
+
storage.onResetModified = () => setDirty(false);
|
|
1527
|
+
pdfViewer.setDocument(pdfDocument);
|
|
1528
|
+
linkService.setDocument(pdfDocument);
|
|
1529
|
+
status("PDF 已就绪(" + pdfDocument.numPages + " 页)");
|
|
1530
|
+
} catch (error) {
|
|
1531
|
+
if (destroyed) return;
|
|
1532
|
+
const message = String(error && (error.message || error.name) || error);
|
|
1533
|
+
const friendly = message.includes("password") ? "不支持加密 PDF" : "PDF 加载失败:" + message;
|
|
1534
|
+
status("PDF 加载失败");
|
|
1535
|
+
try {
|
|
1536
|
+
deps.setError(friendly);
|
|
1537
|
+
} catch {}
|
|
1538
|
+
}
|
|
1539
|
+
};
|
|
1540
|
+
/** 是否有未保存修改(EditorView Ctrl+S 分派用)。 */
|
|
1541
|
+
const isDirty = () => dirty;
|
|
1542
|
+
/** 销毁:解绑事件、销毁文档与 DOM(重复调用安全)。 */
|
|
1543
|
+
const destroy = () => {
|
|
1544
|
+
destroyed = true;
|
|
1545
|
+
try {
|
|
1546
|
+
busAbort?.abort();
|
|
1547
|
+
} catch {}
|
|
1548
|
+
try {
|
|
1549
|
+
pdfViewer?.cleanup();
|
|
1550
|
+
} catch {}
|
|
1551
|
+
try {
|
|
1552
|
+
loadingTask?.destroy();
|
|
1553
|
+
} catch {}
|
|
1554
|
+
try {
|
|
1555
|
+
pdfDocument?.destroy();
|
|
1556
|
+
} catch {}
|
|
1557
|
+
if (stage?.parentNode) stage.parentNode.removeChild(stage);
|
|
1558
|
+
stage = null;
|
|
1559
|
+
eventBus = null;
|
|
1560
|
+
busAbort = null;
|
|
1561
|
+
editorTypes = null;
|
|
1562
|
+
pdfViewer = null;
|
|
1563
|
+
pdfDocument = null;
|
|
1564
|
+
loadingTask = null;
|
|
1565
|
+
modeButtons = null;
|
|
1566
|
+
};
|
|
1567
|
+
return {
|
|
1568
|
+
mount,
|
|
1569
|
+
destroy,
|
|
1570
|
+
savePdf,
|
|
1571
|
+
isDirty
|
|
1572
|
+
};
|
|
1573
|
+
}
|
|
1574
|
+
//#endregion
|
|
1108
1575
|
//#region src/client/monaco/diffRender.ts
|
|
1109
1576
|
/**
|
|
1110
1577
|
* dsh-vscode-mode client — 行内差异自绘(新增行绿底 + glyph margin '+';删除块 view zone 红底)。
|
|
@@ -3616,6 +4083,14 @@ window.__ModuleLoader__.load({
|
|
|
3616
4083
|
const [dirtyMap, setDirtyMap] = react.default.useState({});
|
|
3617
4084
|
const [content, setContent] = react.default.useState(null);
|
|
3618
4085
|
const [contentPath, setContentPath] = react.default.useState(null);
|
|
4086
|
+
const [imageSrc, setImageSrc] = react.default.useState(null);
|
|
4087
|
+
const [imgSize, setImgSize] = react.default.useState(null);
|
|
4088
|
+
const [imgBroken, setImgBroken] = react.default.useState(false);
|
|
4089
|
+
const svgTextRef = react.default.useRef(/* @__PURE__ */ new Set());
|
|
4090
|
+
const [pdfBytes, setPdfBytes] = react.default.useState(null);
|
|
4091
|
+
const pdfB64CacheRef = react.default.useRef(/* @__PURE__ */ new Map());
|
|
4092
|
+
const pdfCtlRef = react.default.useRef(/* @__PURE__ */ new Map());
|
|
4093
|
+
const pdfHostRef = react.default.useRef(null);
|
|
3619
4094
|
const [status, setStatus] = react.default.useState("");
|
|
3620
4095
|
const [lspServers, setLspServers] = react.default.useState([]);
|
|
3621
4096
|
const [error, setError] = react.default.useState(null);
|
|
@@ -3683,6 +4158,8 @@ window.__ModuleLoader__.load({
|
|
|
3683
4158
|
return list;
|
|
3684
4159
|
}, [records, active]);
|
|
3685
4160
|
const contentReady = content !== null && contentPath === active;
|
|
4161
|
+
const isImageActive = !!active && isImagePath(active) && !svgTextRef.current.has(active);
|
|
4162
|
+
const isPdfActive = !!active && isPdfPath(active);
|
|
3686
4163
|
const regions = react.default.useMemo(() => diffRegions(currentRecords, contentReady ? content : null).filter((r) => !r.superseded), [
|
|
3687
4164
|
currentRecords,
|
|
3688
4165
|
content,
|
|
@@ -3837,6 +4314,12 @@ window.__ModuleLoader__.load({
|
|
|
3837
4314
|
saveViewState(path);
|
|
3838
4315
|
recordNav();
|
|
3839
4316
|
}
|
|
4317
|
+
const pdfCtl = pdfCtlRef.current.get(path);
|
|
4318
|
+
if (pdfCtl) {
|
|
4319
|
+
pdfCtl.destroy();
|
|
4320
|
+
pdfCtlRef.current.delete(path);
|
|
4321
|
+
}
|
|
4322
|
+
pdfB64CacheRef.current.delete(path);
|
|
3840
4323
|
setTabs((prev) => {
|
|
3841
4324
|
const idx = prev.findIndex((t) => t.path === path);
|
|
3842
4325
|
if (idx < 0) return prev;
|
|
@@ -3888,6 +4371,14 @@ window.__ModuleLoader__.load({
|
|
|
3888
4371
|
*/
|
|
3889
4372
|
const loadContent = (path, sid, force) => {
|
|
3890
4373
|
const seq = ++loadSeqRef.current;
|
|
4374
|
+
if (isImagePath(path) && !svgTextRef.current.has(path)) {
|
|
4375
|
+
loadImage(path, sid, seq);
|
|
4376
|
+
return;
|
|
4377
|
+
}
|
|
4378
|
+
if (isPdfPath(path)) {
|
|
4379
|
+
loadPdf(path, sid, seq, force === true);
|
|
4380
|
+
return;
|
|
4381
|
+
}
|
|
3891
4382
|
const cachedModel = force ? null : modelsRef.current.get(path);
|
|
3892
4383
|
if (cachedModel) {
|
|
3893
4384
|
setContent(cachedModel.getValue());
|
|
@@ -3943,6 +4434,113 @@ window.__ModuleLoader__.load({
|
|
|
3943
4434
|
setStatus("读取失败");
|
|
3944
4435
|
});
|
|
3945
4436
|
};
|
|
4437
|
+
/**
|
|
4438
|
+
* 加载图片文件为 data URL(编辑区只读预览);失败走 loadError 面板(重试经 loadContent 分派回此)。
|
|
4439
|
+
* @author ddj 2026年09月08号
|
|
4440
|
+
* @param path 图片文件路径
|
|
4441
|
+
* @param sid 会话 id
|
|
4442
|
+
* @param seq 加载序号(过期响应丢弃)
|
|
4443
|
+
*/
|
|
4444
|
+
const loadImage = (path, sid, seq) => {
|
|
4445
|
+
setImageSrc(null);
|
|
4446
|
+
setImgSize(null);
|
|
4447
|
+
setImgBroken(false);
|
|
4448
|
+
setLoadStage({
|
|
4449
|
+
progress: monaco ? 72 : 12,
|
|
4450
|
+
message: "读取图片…"
|
|
4451
|
+
});
|
|
4452
|
+
rpc("edrv.read", {
|
|
4453
|
+
sessionId: sid,
|
|
4454
|
+
path,
|
|
4455
|
+
encoding: "base64"
|
|
4456
|
+
}).then((res) => {
|
|
4457
|
+
if (seq !== loadSeqRef.current || path !== active) return;
|
|
4458
|
+
if (res && res.ok && res.encoding === "base64") {
|
|
4459
|
+
if (!res.mime) {
|
|
4460
|
+
setLoadError("host 版本过旧:图片响应缺少 mime");
|
|
4461
|
+
setError("host 版本过旧:图片响应缺少 mime");
|
|
4462
|
+
setStatus("读取失败");
|
|
4463
|
+
return;
|
|
4464
|
+
}
|
|
4465
|
+
setImageSrc(dataUrlOf(res.content, res.mime));
|
|
4466
|
+
setLoadStage({
|
|
4467
|
+
progress: 100,
|
|
4468
|
+
message: "图片已就绪"
|
|
4469
|
+
});
|
|
4470
|
+
setStatus("已加载");
|
|
4471
|
+
return;
|
|
4472
|
+
}
|
|
4473
|
+
const base = res?.error ? String(res.error) : "读取失败";
|
|
4474
|
+
const message = res?.resolvedPath ? base + ":" + String(res.resolvedPath) : base;
|
|
4475
|
+
setLoadError(message);
|
|
4476
|
+
setError(message);
|
|
4477
|
+
setStatus("读取失败");
|
|
4478
|
+
}).catch((e) => {
|
|
4479
|
+
if (seq !== loadSeqRef.current) return;
|
|
4480
|
+
const message = "read异常:" + String(e);
|
|
4481
|
+
setLoadError(message);
|
|
4482
|
+
setError(message);
|
|
4483
|
+
setStatus("读取失败");
|
|
4484
|
+
});
|
|
4485
|
+
};
|
|
4486
|
+
/**
|
|
4487
|
+
* 加载 PDF 文件为原始字节(编辑区 PDF 面板);命中 base64 缓存秒切,force 绕过缓存重读。
|
|
4488
|
+
* 面板控制器由 pdf host mount effect 产出(per-path,关闭/卸载销毁)。
|
|
4489
|
+
* @author ddj 2026年09月22号
|
|
4490
|
+
* @param path PDF 文件路径
|
|
4491
|
+
* @param sid 会话 id
|
|
4492
|
+
* @param seq 加载序号(过期响应丢弃)
|
|
4493
|
+
* @param force true=绕过缓存强制 RPC 重读(刷新按钮)
|
|
4494
|
+
*/
|
|
4495
|
+
const loadPdf = (path, sid, seq, force) => {
|
|
4496
|
+
setPdfBytes(null);
|
|
4497
|
+
setLoadStage({
|
|
4498
|
+
progress: monaco ? 72 : 12,
|
|
4499
|
+
message: "读取 PDF…"
|
|
4500
|
+
});
|
|
4501
|
+
const cache = pdfB64CacheRef.current;
|
|
4502
|
+
const hit = !force ? cache.get(path) : void 0;
|
|
4503
|
+
if (typeof hit === "string" && hit) {
|
|
4504
|
+
cache.delete(path);
|
|
4505
|
+
cache.set(path, hit);
|
|
4506
|
+
setPdfBytes(base64ToBytes(hit));
|
|
4507
|
+
setLoadStage({
|
|
4508
|
+
progress: 100,
|
|
4509
|
+
message: "PDF 已就绪"
|
|
4510
|
+
});
|
|
4511
|
+
setStatus("已加载");
|
|
4512
|
+
return;
|
|
4513
|
+
}
|
|
4514
|
+
rpc("edrv.read", {
|
|
4515
|
+
sessionId: sid,
|
|
4516
|
+
path,
|
|
4517
|
+
encoding: "base64"
|
|
4518
|
+
}).then((res) => {
|
|
4519
|
+
if (seq !== loadSeqRef.current || path !== active) return;
|
|
4520
|
+
if (res && res.ok && res.encoding === "base64") {
|
|
4521
|
+
cache.set(path, res.content);
|
|
4522
|
+
while (cache.size > 6) cache.delete(cache.keys().next().value);
|
|
4523
|
+
setPdfBytes(base64ToBytes(res.content));
|
|
4524
|
+
setLoadStage({
|
|
4525
|
+
progress: 100,
|
|
4526
|
+
message: "PDF 已就绪"
|
|
4527
|
+
});
|
|
4528
|
+
setStatus("已加载");
|
|
4529
|
+
return;
|
|
4530
|
+
}
|
|
4531
|
+
const base = res?.error ? String(res.error) : "读取失败";
|
|
4532
|
+
const message = res?.resolvedPath ? base + ":" + String(res.resolvedPath) : base;
|
|
4533
|
+
setLoadError(message);
|
|
4534
|
+
setError(message);
|
|
4535
|
+
setStatus("读取失败");
|
|
4536
|
+
}).catch((e) => {
|
|
4537
|
+
if (seq !== loadSeqRef.current) return;
|
|
4538
|
+
const message = "read异常:" + String(e);
|
|
4539
|
+
setLoadError(message);
|
|
4540
|
+
setError(message);
|
|
4541
|
+
setStatus("读取失败");
|
|
4542
|
+
});
|
|
4543
|
+
};
|
|
3946
4544
|
react.default.useEffect(() => {
|
|
3947
4545
|
if (!sessionId) return;
|
|
3948
4546
|
refreshRecords();
|
|
@@ -4218,6 +4816,10 @@ window.__ModuleLoader__.load({
|
|
|
4218
4816
|
if (!active) return;
|
|
4219
4817
|
setContent(null);
|
|
4220
4818
|
setContentPath(null);
|
|
4819
|
+
setImageSrc(null);
|
|
4820
|
+
setImgSize(null);
|
|
4821
|
+
setImgBroken(false);
|
|
4822
|
+
setPdfBytes(null);
|
|
4221
4823
|
setLoadError(null);
|
|
4222
4824
|
setLoadStage({
|
|
4223
4825
|
progress: 10,
|
|
@@ -4292,8 +4894,26 @@ window.__ModuleLoader__.load({
|
|
|
4292
4894
|
}
|
|
4293
4895
|
};
|
|
4294
4896
|
const doSave = (silent) => {
|
|
4897
|
+
if (!active) return;
|
|
4898
|
+
if (isPdfPath(active)) {
|
|
4899
|
+
const ctl = pdfCtlRef.current.get(active);
|
|
4900
|
+
if (!ctl) {
|
|
4901
|
+
if (!silent) setStatus("PDF 未就绪");
|
|
4902
|
+
return;
|
|
4903
|
+
}
|
|
4904
|
+
if (!ctl.isDirty()) {
|
|
4905
|
+
if (!silent) setStatus("PDF 无未保存修改");
|
|
4906
|
+
return;
|
|
4907
|
+
}
|
|
4908
|
+
ctl.savePdf();
|
|
4909
|
+
return;
|
|
4910
|
+
}
|
|
4295
4911
|
const ed = editorRef.current;
|
|
4296
|
-
if (!
|
|
4912
|
+
if (!ed) return;
|
|
4913
|
+
if (isImageActive) {
|
|
4914
|
+
setStatus("图片只读预览");
|
|
4915
|
+
return;
|
|
4916
|
+
}
|
|
4297
4917
|
const text = ed.getValue();
|
|
4298
4918
|
if (!silent) setStatus("保存中…");
|
|
4299
4919
|
rpc("edrv.save", {
|
|
@@ -4340,6 +4960,32 @@ window.__ModuleLoader__.load({
|
|
|
4340
4960
|
active,
|
|
4341
4961
|
content
|
|
4342
4962
|
]);
|
|
4963
|
+
const ensurePdfHost = (node) => {
|
|
4964
|
+
pdfHostRef.current = node;
|
|
4965
|
+
};
|
|
4966
|
+
react.default.useEffect(() => {
|
|
4967
|
+
const host = pdfHostRef.current;
|
|
4968
|
+
if (!isPdfActive || !pdfBytes || !host) return;
|
|
4969
|
+
const path = active;
|
|
4970
|
+
const ctl = createPdfPanel({
|
|
4971
|
+
sessionId,
|
|
4972
|
+
path,
|
|
4973
|
+
setStatus,
|
|
4974
|
+
setError,
|
|
4975
|
+
onDirtyChange: (d) => setDirtyMap((prev) => Object.assign({}, prev, { [path]: d })),
|
|
4976
|
+
onReload: () => loadContent(path, sessionId, true)
|
|
4977
|
+
});
|
|
4978
|
+
pdfCtlRef.current.set(path, ctl);
|
|
4979
|
+
ctl.mount(host, pdfBytes);
|
|
4980
|
+
return () => {
|
|
4981
|
+
ctl.destroy();
|
|
4982
|
+
if (pdfCtlRef.current.get(path) === ctl) pdfCtlRef.current.delete(path);
|
|
4983
|
+
};
|
|
4984
|
+
}, [
|
|
4985
|
+
isPdfActive,
|
|
4986
|
+
pdfBytes,
|
|
4987
|
+
active
|
|
4988
|
+
]);
|
|
4343
4989
|
react.default.useEffect(() => {
|
|
4344
4990
|
if (!monaco || !editorRef.current || !active || content === null) return;
|
|
4345
4991
|
diffRendererRef.current.render(monaco, editorRef.current, pendingRegions, sessionId);
|
|
@@ -4363,6 +5009,8 @@ window.__ModuleLoader__.load({
|
|
|
4363
5009
|
}
|
|
4364
5010
|
for (const m of modelsRef.current.values()) m.dispose();
|
|
4365
5011
|
modelsRef.current.clear();
|
|
5012
|
+
for (const ctl of pdfCtlRef.current.values()) ctl.destroy();
|
|
5013
|
+
pdfCtlRef.current.clear();
|
|
4366
5014
|
const root = editorRef.current && editorRef.current.getDomNode ? editorRef.current.getDomNode() : null;
|
|
4367
5015
|
if (root) {
|
|
4368
5016
|
const ov = root.querySelector(".edrv-minus-overlay");
|
|
@@ -4624,6 +5272,53 @@ window.__ModuleLoader__.load({
|
|
|
4624
5272
|
refreshRecords(skipStale === true);
|
|
4625
5273
|
};
|
|
4626
5274
|
/**
|
|
5275
|
+
* SVG 在图片预览与文本编辑间切换(按路径记忆;重载分派随集合状态自动路由)。
|
|
5276
|
+
* @author ddj 2026年09月08号
|
|
5277
|
+
* @param path SVG 文件路径
|
|
5278
|
+
*/
|
|
5279
|
+
const toggleSvgText = (path) => {
|
|
5280
|
+
const next = new Set(svgTextRef.current);
|
|
5281
|
+
if (next.has(path)) next.delete(path);
|
|
5282
|
+
else next.add(path);
|
|
5283
|
+
svgTextRef.current = next;
|
|
5284
|
+
setContent(null);
|
|
5285
|
+
setContentPath(null);
|
|
5286
|
+
setImageSrc(null);
|
|
5287
|
+
setImgSize(null);
|
|
5288
|
+
setImgBroken(false);
|
|
5289
|
+
setLoadError(null);
|
|
5290
|
+
setStatus(next.has(path) ? "已切换为文本模式" : "已切换为图片预览");
|
|
5291
|
+
loadContent(path, sessionId, true);
|
|
5292
|
+
};
|
|
5293
|
+
/**
|
|
5294
|
+
* 图片预览面板:工具条(尺寸 meta / SVG 文本切换 / 刷新)+ 棋盘底自适应图片。
|
|
5295
|
+
* @author ddj 2026年09月08号
|
|
5296
|
+
*/
|
|
5297
|
+
const imagePanel = () => react.default.createElement("div", { className: "edrv-imgview" }, react.default.createElement("div", { className: "edrv-imgview-bar" }, react.default.createElement("span", { className: "edrv-imgview-meta" }, imgBroken ? "图片无法显示" : imgSize ? imgSize.w + "×" + imgSize.h : "…"), react.default.createElement("span", { style: { flex: 1 } }), isSvgPath(active) ? react.default.createElement("button", {
|
|
5298
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
5299
|
+
title: "以文本方式查看/编辑(SVG 为文本格式)",
|
|
5300
|
+
onClick: () => toggleSvgText(active)
|
|
5301
|
+
}, "以文本打开") : null, react.default.createElement("button", {
|
|
5302
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
5303
|
+
title: "重新加载图片",
|
|
5304
|
+
onClick: () => reloadFile()
|
|
5305
|
+
}, "⟳ 刷新")), react.default.createElement("div", { className: "edrv-imgview-stage" }, imgBroken ? react.default.createElement("div", { className: "edrv-imgview-broken" }, react.default.createElement("div", null, "图片解码失败,文件可能已损坏"), react.default.createElement("button", {
|
|
5306
|
+
className: "edrv-pill edrv-pill-ghost",
|
|
5307
|
+
onClick: () => reloadFile()
|
|
5308
|
+
}, "重试")) : react.default.createElement("img", {
|
|
5309
|
+
className: "edrv-imgview-img",
|
|
5310
|
+
src: imageSrc,
|
|
5311
|
+
alt: active || "",
|
|
5312
|
+
onLoad: (e) => {
|
|
5313
|
+
setImgBroken(false);
|
|
5314
|
+
setImgSize({
|
|
5315
|
+
w: e.target.naturalWidth,
|
|
5316
|
+
h: e.target.naturalHeight
|
|
5317
|
+
});
|
|
5318
|
+
},
|
|
5319
|
+
onError: () => setImgBroken(true)
|
|
5320
|
+
})));
|
|
5321
|
+
/**
|
|
4627
5322
|
* 关闭当前差异浮窗并清理 hover 锚点。
|
|
4628
5323
|
* @author ddj 2026年08月21号
|
|
4629
5324
|
*/
|
|
@@ -4875,6 +5570,14 @@ window.__ModuleLoader__.load({
|
|
|
4875
5570
|
const openPath = () => {
|
|
4876
5571
|
const p = (pathDraft || "").trim();
|
|
4877
5572
|
if (!p) return;
|
|
5573
|
+
if (isImagePath(p) || isPdfPath(p)) {
|
|
5574
|
+
openFile(p, false);
|
|
5575
|
+
setOpenInput(false);
|
|
5576
|
+
setPathDraft("");
|
|
5577
|
+
setStatus("已打开");
|
|
5578
|
+
setError(null);
|
|
5579
|
+
return;
|
|
5580
|
+
}
|
|
4878
5581
|
setStatus("打开中…");
|
|
4879
5582
|
rpc("edrv.read", {
|
|
4880
5583
|
sessionId,
|
|
@@ -4950,7 +5653,7 @@ window.__ModuleLoader__.load({
|
|
|
4950
5653
|
const pathBar = react.default.createElement("div", {
|
|
4951
5654
|
className: "edrv-pathbar",
|
|
4952
5655
|
title: active || ""
|
|
4953
|
-
}, react.default.createElement("span", { className: "edrv-pb-name" }, active ? String(active).split(/[\\/]/).pop() : "未打开文件"), react.default.createElement("span", { className: "edrv-pb-full" }, active || "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开文件"), active && langOf(active) ? react.default.createElement("span", { className: "edrv-pb-meta" }, langOf(active)) : null, cursor ? react.default.createElement("span", { className: "edrv-pb-meta" }, cursor) : null, status ? react.default.createElement("span", { className: "edrv-pb-meta edrv-pb-status" }, status) : null);
|
|
5656
|
+
}, react.default.createElement("span", { className: "edrv-pb-name" }, active ? String(active).split(/[\\/]/).pop() : "未打开文件"), react.default.createElement("span", { className: "edrv-pb-full" }, active || "使用右上搜索框 (" + (chordOf("edrv.quickOpen") ?? "Ctrl+P") + ") 打开文件"), active && !isImageActive && langOf(active) ? react.default.createElement("span", { className: "edrv-pb-meta" }, langOf(active)) : null, isImageActive && imgSize ? react.default.createElement("span", { className: "edrv-pb-meta" }, imgSize.w + "×" + imgSize.h) : null, cursor ? react.default.createElement("span", { className: "edrv-pb-meta" }, cursor) : null, status ? react.default.createElement("span", { className: "edrv-pb-meta edrv-pb-status" }, status) : null);
|
|
4954
5657
|
const lspLanguage = active ? langOf(active) : "";
|
|
4955
5658
|
const lspServer = lspServers.find((item) => item.languageId === lspLanguage);
|
|
4956
5659
|
const lspLabel = lspServer ? "LSP " + lspLanguage + " · " + ({
|
|
@@ -5056,6 +5759,14 @@ window.__ModuleLoader__.load({
|
|
|
5056
5759
|
});
|
|
5057
5760
|
loadContent(active, sessionId);
|
|
5058
5761
|
});
|
|
5762
|
+
else if (isImageActive && imageSrc) body = imagePanel();
|
|
5763
|
+
else if (isImageActive) body = loadingBody(loadStage.message || "读取图片…", loadStage.progress);
|
|
5764
|
+
else if (isPdfActive && pdfBytes) body = react.default.createElement("div", {
|
|
5765
|
+
className: "edrv-pdf-host",
|
|
5766
|
+
ref: ensurePdfHost,
|
|
5767
|
+
key: active
|
|
5768
|
+
});
|
|
5769
|
+
else if (isPdfActive) body = loadingBody(loadStage.message || "读取 PDF…", loadStage.progress);
|
|
5059
5770
|
else if (content === null) body = loadingBody(loadStage.message || "读取文件内容…", loadStage.progress);
|
|
5060
5771
|
else body = react.default.createElement("div", { className: "edrv-monaco-host" }, react.default.createElement("div", { ref: ensureEditor }));
|
|
5061
5772
|
const hoverEl = hoverAct && !launcherOpen ? react.default.createElement("div", {
|
|
@@ -5730,6 +6441,36 @@ window.__ModuleLoader__.load({
|
|
|
5730
6441
|
if (owner[key] === patched) owner[key] = original;
|
|
5731
6442
|
};
|
|
5732
6443
|
}
|
|
6444
|
+
/**
|
|
6445
|
+
* accessor 感知的链式补丁:DSH 0.1.3+ 的 remote 命名空间方法(如
|
|
6446
|
+
* remote.session.openWorkspacePath)是 getter-only accessor(Object.defineProperty
|
|
6447
|
+
* 仅定义 get,直接赋值在严格模式下抛 TypeError),须整体替换属性描述符。
|
|
6448
|
+
* 新 getter 每次访问现场调用原 getter 取最新一次性函数作 original,天然跟随
|
|
6449
|
+
* DSH 内部 methods 表变化;data 属性降级走 patchMethod;属性缺失返回 null。
|
|
6450
|
+
* @author ddj 2026年09月08号
|
|
6451
|
+
* @param owner 目标对象
|
|
6452
|
+
* @param key 属性名
|
|
6453
|
+
* @param wrapper 包装实现(original 为补丁前的实时实现)
|
|
6454
|
+
* @returns 恢复函数(幂等、带归属校验);属性缺失时返回 null
|
|
6455
|
+
*/
|
|
6456
|
+
function patchAccessor(owner, key, wrapper) {
|
|
6457
|
+
const descriptor = Object.getOwnPropertyDescriptor(owner, key);
|
|
6458
|
+
if (!descriptor) return null;
|
|
6459
|
+
if (typeof descriptor.get !== "function") return patchMethod(owner, key, wrapper);
|
|
6460
|
+
const rawGet = descriptor.get;
|
|
6461
|
+
const patchedGet = function() {
|
|
6462
|
+
const original = (...args) => rawGet.call(owner)(...args);
|
|
6463
|
+
return (...args) => wrapper(original, ...args);
|
|
6464
|
+
};
|
|
6465
|
+
Object.defineProperty(owner, key, {
|
|
6466
|
+
configurable: true,
|
|
6467
|
+
enumerable: descriptor.enumerable,
|
|
6468
|
+
get: patchedGet
|
|
6469
|
+
});
|
|
6470
|
+
return () => {
|
|
6471
|
+
if (Object.getOwnPropertyDescriptor(owner, key)?.get === patchedGet) Object.defineProperty(owner, key, descriptor);
|
|
6472
|
+
};
|
|
6473
|
+
}
|
|
5733
6474
|
//#endregion
|
|
5734
6475
|
//#region src/client/fileOpeners.ts
|
|
5735
6476
|
/**
|
|
@@ -7726,6 +8467,63 @@ window.__ModuleLoader__.load({
|
|
|
7726
8467
|
return typeof value === "string" && value.trim() ? value.trim() : AUTO_OPEN_TOOL;
|
|
7727
8468
|
}
|
|
7728
8469
|
//#endregion
|
|
8470
|
+
//#region src/client/remoteOpenRouter.ts
|
|
8471
|
+
/**
|
|
8472
|
+
* dsh-vscode-mode client — DSH 对话文件链接的 0.1.3+ 路由(remote.session 面)。
|
|
8473
|
+
* 0.1.3 起 dsh-client-ui-chat 的 openFile 直接调 ctx.remote.session.openWorkspacePath
|
|
8474
|
+
* (浏览器→host RPC session/openWorkspacePath),不再经过 workspaces.openPath,
|
|
8475
|
+
* 旧路由补丁因此落空;该方法是 getter-only accessor,补丁经 compat.patchAccessor
|
|
8476
|
+
* 换描述符安装。行为与 openPathRouter 对齐:插件打开器优先,"."(打开工作区文件夹)、
|
|
8477
|
+
* 无可用打开器或打开失败时透传原实现(系统默认应用打开)。
|
|
8478
|
+
* 纯逻辑,node 环境可单测(不依赖 DOM / events 模块)。
|
|
8479
|
+
* 作者 ddj 2026年09月08号
|
|
8480
|
+
*/
|
|
8481
|
+
/** 插件打开器接管成功时返回给调用方(chat 只看 ok,产物区读 value)。 */
|
|
8482
|
+
const OPENED_RESULT = {
|
|
8483
|
+
ok: true,
|
|
8484
|
+
value: { opened: true }
|
|
8485
|
+
};
|
|
8486
|
+
/**
|
|
8487
|
+
* 结构化探测 remote.session 命名空间服务及其 openWorkspacePath 方法。
|
|
8488
|
+
* 旧版 DSH 无该 namespace、或 api-remotes 尚未挂载时返回 undefined。
|
|
8489
|
+
* @author ddj 2026年09月08号
|
|
8490
|
+
* @param ctx 客户端服务上下文
|
|
8491
|
+
* @returns 命名空间服务实例;不可用返回 undefined
|
|
8492
|
+
*/
|
|
8493
|
+
function probeRemoteOpen(ctx) {
|
|
8494
|
+
try {
|
|
8495
|
+
const service = ctx.get("remote.session");
|
|
8496
|
+
if (!service || typeof service.openWorkspacePath !== "function") return void 0;
|
|
8497
|
+
return service;
|
|
8498
|
+
} catch {
|
|
8499
|
+
return;
|
|
8500
|
+
}
|
|
8501
|
+
}
|
|
8502
|
+
/**
|
|
8503
|
+
* 安装可卸载的 remote.session.openWorkspacePath 路由(0.1.3+ 会话文件链接主路径)。
|
|
8504
|
+
* @author ddj 2026年09月08号
|
|
8505
|
+
* @param service probeRemoteOpen 命中的命名空间服务
|
|
8506
|
+
* @param options 路由依赖
|
|
8507
|
+
* @returns 恢复函数;目标属性缺失时返回 null(调用方停止安装并告警)
|
|
8508
|
+
*/
|
|
8509
|
+
function patchRemoteOpen(service, options) {
|
|
8510
|
+
return patchAccessor(service, "openWorkspacePath", async (original, ...args) => {
|
|
8511
|
+
const fallback = original;
|
|
8512
|
+
const request = args[0] ?? {};
|
|
8513
|
+
const path = typeof request.path === "string" ? request.path : "";
|
|
8514
|
+
if (!path || path === ".") return fallback(request);
|
|
8515
|
+
const opener = selectOpener(options.registry, options.selected());
|
|
8516
|
+
if (!opener || !isAvailable(opener)) return fallback(request);
|
|
8517
|
+
try {
|
|
8518
|
+
await opener.open(path, options.context());
|
|
8519
|
+
return OPENED_RESULT;
|
|
8520
|
+
} catch (error) {
|
|
8521
|
+
options.logger?.("文件打开器 " + opener.id + " 失败,回退系统打开: " + String(error));
|
|
8522
|
+
return fallback(request);
|
|
8523
|
+
}
|
|
8524
|
+
});
|
|
8525
|
+
}
|
|
8526
|
+
//#endregion
|
|
7729
8527
|
//#region src/shared/externalOpen.ts
|
|
7730
8528
|
/**
|
|
7731
8529
|
* dsh-vscode-mode shared — 外部深链 URL 契约(Windows launcher / Unity 包 / client 共用)。
|
|
@@ -10976,6 +11774,19 @@ window.__ModuleLoader__.load({
|
|
|
10976
11774
|
const binder = pickSettingsBinder(ctx);
|
|
10977
11775
|
const settings = binder.scope;
|
|
10978
11776
|
let selected = autoValue("auto");
|
|
11777
|
+
/** 0.1.3+ 会话文件链接路由(remote.session.openWorkspacePath)是否已安装(compatSummary 展示用)。 */
|
|
11778
|
+
let remoteOpenInstalled = false;
|
|
11779
|
+
/** 两条文件链接路由共用的路由日志(openPathRouter / remoteOpenRouter)。 */
|
|
11780
|
+
const routeLogger = (message) => console.warn("[dsh-vscode-mode] " + message);
|
|
11781
|
+
/** 两条路由共用的 FileOpenContext:当前会话 id 与工作区 cwd。 */
|
|
11782
|
+
const openContext = () => {
|
|
11783
|
+
const current = sessions?.list?.getSnapshot?.();
|
|
11784
|
+
const sessionId = current?.current;
|
|
11785
|
+
return {
|
|
11786
|
+
sessionId,
|
|
11787
|
+
cwd: (sessionId ? current?.byId?.[sessionId] : void 0)?.cwd
|
|
11788
|
+
};
|
|
11789
|
+
};
|
|
10979
11790
|
/** 可选探测 betterSidebar 服务(不进 inject:缺失会让插件停靠等待,杀死回退路径)。 */
|
|
10980
11791
|
let sideService = detectSidebarService(ctx);
|
|
10981
11792
|
/** 「添加到对话」动作集:编辑区/Tab 右键菜单注入文件引用与代码块(conversation 服务缺失时各动作安全降级)。 */
|
|
@@ -10990,7 +11801,12 @@ window.__ModuleLoader__.load({
|
|
|
10990
11801
|
{
|
|
10991
11802
|
name: "文件打开路由(workspaces.openPath)",
|
|
10992
11803
|
active: Boolean(workspaces?.openPath),
|
|
10993
|
-
note: "vscode
|
|
11804
|
+
note: "vscode 打开器优先,失败回退系统打开(0.1.2 及更早 DSH 的对话文件链接主路径)"
|
|
11805
|
+
},
|
|
11806
|
+
{
|
|
11807
|
+
name: "会话文件链接路由(remote.session.openWorkspacePath)",
|
|
11808
|
+
active: remoteOpenInstalled,
|
|
11809
|
+
note: "0.1.3+ 对话文件引用/产物打开优先走插件打开器,失败回退系统打开"
|
|
10994
11810
|
},
|
|
10995
11811
|
{
|
|
10996
11812
|
name: "侧边栏打开器(dsh-better-sidebar)",
|
|
@@ -11055,16 +11871,39 @@ window.__ModuleLoader__.load({
|
|
|
11055
11871
|
workspaces,
|
|
11056
11872
|
registry,
|
|
11057
11873
|
selected: () => selected,
|
|
11058
|
-
context:
|
|
11059
|
-
|
|
11060
|
-
const sessionId = current?.current;
|
|
11061
|
-
return {
|
|
11062
|
-
sessionId,
|
|
11063
|
-
cwd: (sessionId ? current?.byId?.[sessionId] : void 0)?.cwd
|
|
11064
|
-
};
|
|
11065
|
-
},
|
|
11066
|
-
logger: (message) => console.warn("[dsh-vscode-mode] " + message)
|
|
11874
|
+
context: openContext,
|
|
11875
|
+
logger: routeLogger
|
|
11067
11876
|
}), "vscode-mode: file link routing");
|
|
11877
|
+
let remoteRetries = 0;
|
|
11878
|
+
const retryRemoteOpen = () => {
|
|
11879
|
+
if (remoteOpenInstalled || remoteRetries >= 15) {
|
|
11880
|
+
if (!remoteOpenInstalled) console.warn("[dsh-vscode-mode] 未探测到 remote.session.openWorkspacePath,0.1.3+ 会话文件链接路由未安装");
|
|
11881
|
+
return;
|
|
11882
|
+
}
|
|
11883
|
+
remoteRetries += 1;
|
|
11884
|
+
schedule(() => {
|
|
11885
|
+
if (remoteOpenInstalled) return;
|
|
11886
|
+
const service = probeRemoteOpen(ctx);
|
|
11887
|
+
if (!service) {
|
|
11888
|
+
retryRemoteOpen();
|
|
11889
|
+
return;
|
|
11890
|
+
}
|
|
11891
|
+
const disposer = patchRemoteOpen(service, {
|
|
11892
|
+
registry,
|
|
11893
|
+
selected: () => selected,
|
|
11894
|
+
context: openContext,
|
|
11895
|
+
logger: routeLogger
|
|
11896
|
+
});
|
|
11897
|
+
if (!disposer) {
|
|
11898
|
+
console.warn("[dsh-vscode-mode] remote.session 存在但 openWorkspacePath 不可补丁,会话文件链接路由未安装");
|
|
11899
|
+
return;
|
|
11900
|
+
}
|
|
11901
|
+
remoteOpenInstalled = true;
|
|
11902
|
+
ctx.effect(() => disposer, "vscode-mode: remote file link routing");
|
|
11903
|
+
console.info("[dsh-vscode-mode] 已安装 0.1.3+ 会话文件链接路由(remote.session.openWorkspacePath)");
|
|
11904
|
+
}, 2e3);
|
|
11905
|
+
};
|
|
11906
|
+
retryRemoteOpen();
|
|
11068
11907
|
const registerLegacyTab = () => {
|
|
11069
11908
|
return registerSlotSafely(ctx, {
|
|
11070
11909
|
name: "conversation.view",
|