@deepseek-harness-tui/dsh-tui 0.10.2 → 0.11.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +171 -124
- package/bin/dsh-tui.js +748 -22
- package/cordis.patch.yml +38 -10
- package/cordis.yml +2 -0
- package/lib/types/adapter/channel/session-projection.d.ts.map +1 -1
- package/lib/types/adapter/channel/session-projection.js +2 -0
- package/lib/types/adapter/channel/ui-policy.d.ts +4 -1
- package/lib/types/adapter/channel/ui-policy.d.ts.map +1 -1
- package/lib/types/adapter/channel/ui-policy.js +5 -1
- package/lib/types/adapter/kernel/host-facade.d.ts.map +1 -1
- package/lib/types/adapter/kernel/host-facade.js +1 -0
- package/lib/types/adapter/kernel/replay.d.ts.map +1 -1
- package/lib/types/adapter/kernel/replay.js +3 -0
- package/lib/types/adapter/kernel/runtime.d.ts.map +1 -1
- package/lib/types/adapter/kernel/runtime.js +2 -0
- package/lib/types/adapter/kernel/slices/workspace.d.ts.map +1 -1
- package/lib/types/adapter/kernel/slices/workspace.js +1 -0
- package/lib/types/adapter/ports/channel-ui.d.ts +22 -2
- package/lib/types/adapter/ports/channel-ui.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-view.d.ts +66 -0
- package/lib/types/adapter/ports/channel-view.d.ts.map +1 -1
- package/lib/types/adapter/ports/channel-workspace.d.ts +23 -0
- package/lib/types/adapter/ports/channel-workspace.d.ts.map +1 -1
- package/lib/types/adapter/ports/workspace.d.ts +2 -0
- package/lib/types/adapter/ports/workspace.d.ts.map +1 -1
- package/lib/types/adapter/upstream/workspace-driver.d.ts.map +1 -1
- package/lib/types/adapter/upstream/workspace-driver.js +10 -2
- package/lib/types/commands.d.ts.map +1 -1
- package/lib/types/commands.js +1 -0
- package/lib/types/components/ContextBarView.d.ts +15 -7
- package/lib/types/components/ContextBarView.d.ts.map +1 -1
- package/lib/types/components/ContextBarView.js +26 -22
- package/lib/types/components/ImagePreviewOverlay.d.ts.map +1 -1
- package/lib/types/components/ImagePreviewOverlay.js +11 -5
- package/lib/types/components/Markdown.d.ts +11 -1
- package/lib/types/components/Markdown.d.ts.map +1 -1
- package/lib/types/components/Markdown.js +20 -2
- package/lib/types/components/MermaidDiagram.d.ts +13 -0
- package/lib/types/components/MermaidDiagram.d.ts.map +1 -0
- package/lib/types/components/MermaidDiagram.js +61 -0
- package/lib/types/components/MessageList.d.ts +26 -1
- package/lib/types/components/MessageList.d.ts.map +1 -1
- package/lib/types/components/MessageList.js +72 -7
- package/lib/types/components/PageMargin.d.ts +1 -1
- package/lib/types/components/PromptInput.d.ts +37 -1
- package/lib/types/components/PromptInput.d.ts.map +1 -1
- package/lib/types/components/PromptInput.js +243 -28
- package/lib/types/components/ScrollbarGutter.d.ts +20 -5
- package/lib/types/components/ScrollbarGutter.d.ts.map +1 -1
- package/lib/types/components/ScrollbarGutter.js +88 -10
- package/lib/types/components/StreamingMarkdown.d.ts.map +1 -1
- package/lib/types/components/StreamingMarkdown.js +30 -28
- package/lib/types/components/Tooltip.d.ts.map +1 -1
- package/lib/types/components/Tooltip.js +45 -7
- package/lib/types/components/messages/UserPromptMessage.d.ts.map +1 -1
- package/lib/types/components/messages/UserPromptMessage.js +5 -7
- package/lib/types/components/messages/useImageInspection.d.ts.map +1 -1
- package/lib/types/components/messages/useImageInspection.js +19 -9
- package/lib/types/components/promptDraftCache.d.ts +102 -0
- package/lib/types/components/promptDraftCache.d.ts.map +1 -0
- package/lib/types/components/promptDraftCache.js +76 -0
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts +17 -1
- package/lib/types/components/questions/AskUserQuestionPanel.d.ts.map +1 -1
- package/lib/types/components/questions/AskUserQuestionPanel.js +40 -7
- package/lib/types/components/questions/QuestionMinimizedBar.d.ts +12 -0
- package/lib/types/components/questions/QuestionMinimizedBar.d.ts.map +1 -0
- package/lib/types/components/questions/QuestionMinimizedBar.js +43 -0
- package/lib/types/components/sessions/SessionListRow.d.ts +23 -1
- package/lib/types/components/sessions/SessionListRow.d.ts.map +1 -1
- package/lib/types/components/sessions/SessionListRow.js +52 -5
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts +49 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.d.ts.map +1 -0
- package/lib/types/components/workspaces/HomeWorkspaceRow.js +50 -0
- package/lib/types/dsh-adapter/bundled-presets.d.ts +10 -0
- package/lib/types/dsh-adapter/bundled-presets.d.ts.map +1 -0
- package/lib/types/dsh-adapter/bundled-presets.js +80 -0
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/action-readiness.js +3 -0
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/agent-view-projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/agent-view-projection.js +19 -2
- package/lib/types/dsh-adapter/channel/background-action.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/background-action.js +52 -29
- package/lib/types/dsh-adapter/channel/binding.d.ts +19 -2
- package/lib/types/dsh-adapter/channel/binding.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/binding.js +78 -18
- package/lib/types/dsh-adapter/channel/composer-images.d.ts +5 -0
- package/lib/types/dsh-adapter/channel/composer-images.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/composer-images.js +105 -6
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts +8 -0
- package/lib/types/dsh-adapter/channel/context-bookkeeping.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/context-bookkeeping.js +3 -2
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts +58 -0
- package/lib/types/dsh-adapter/channel/ide-selection.d.ts.map +1 -0
- package/lib/types/dsh-adapter/channel/ide-selection.js +226 -0
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/input-delivery.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/input-delivery.js +9 -1
- package/lib/types/dsh-adapter/channel/local-actions.d.ts +3 -19
- package/lib/types/dsh-adapter/channel/local-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/local-actions.js +2 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/model-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-actions.js +82 -6
- package/lib/types/dsh-adapter/channel/model-switch.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/model-switch.js +49 -31
- package/lib/types/dsh-adapter/channel/projection.d.ts +4 -0
- package/lib/types/dsh-adapter/channel/projection.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/projection.js +29 -19
- package/lib/types/dsh-adapter/channel/reports.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/reports.js +4 -12
- package/lib/types/dsh-adapter/channel/session-fork.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-fork.js +26 -2
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts +3 -0
- package/lib/types/dsh-adapter/channel/session-live-adoption.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-live-adoption.js +1 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts +10 -0
- package/lib/types/dsh-adapter/channel/session-metadata.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-metadata.js +2 -2
- package/lib/types/dsh-adapter/channel/session-resume.d.ts +11 -2
- package/lib/types/dsh-adapter/channel/session-resume.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-resume.js +291 -94
- package/lib/types/dsh-adapter/channel/session-rewind.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-rewind.js +34 -16
- package/lib/types/dsh-adapter/channel/session-tree-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/session-tree-actions.js +19 -3
- package/lib/types/dsh-adapter/channel/settings-host.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/settings-host.js +4 -3
- package/lib/types/dsh-adapter/channel/state.d.ts +1 -1
- package/lib/types/dsh-adapter/channel/state.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/state.js +1 -1
- package/lib/types/dsh-adapter/channel/transcript.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/transcript.js +6 -12
- package/lib/types/dsh-adapter/channel/types.d.ts +6 -1
- package/lib/types/dsh-adapter/channel/types.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts +4 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel/workspace-actions.js +41 -1
- package/lib/types/dsh-adapter/channel.d.ts.map +1 -1
- package/lib/types/dsh-adapter/channel.js +67 -6
- package/lib/types/dsh-adapter/compat/messages.d.ts +15 -0
- package/lib/types/dsh-adapter/compat/messages.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/messages.js +15 -0
- package/lib/types/dsh-adapter/compat/settings.d.ts +33 -0
- package/lib/types/dsh-adapter/compat/settings.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/settings.js +43 -0
- package/lib/types/dsh-adapter/compat/shell.d.ts +25 -0
- package/lib/types/dsh-adapter/compat/shell.d.ts.map +1 -0
- package/lib/types/dsh-adapter/compat/shell.js +11 -0
- package/lib/types/dsh-adapter/contract.d.ts +4 -4
- package/lib/types/dsh-adapter/contract.d.ts.map +1 -1
- package/lib/types/dsh-adapter/contract.js +15 -6
- package/lib/types/dsh-adapter/ide-channel.d.ts +224 -0
- package/lib/types/dsh-adapter/ide-channel.d.ts.map +1 -0
- package/lib/types/dsh-adapter/ide-channel.js +556 -0
- package/lib/types/dsh-adapter/index.d.ts +18 -3
- package/lib/types/dsh-adapter/index.d.ts.map +1 -1
- package/lib/types/dsh-adapter/index.js +32 -5
- package/lib/types/dsh-adapter/plugin.d.ts +5 -2
- package/lib/types/dsh-adapter/plugin.d.ts.map +1 -1
- package/lib/types/dsh-adapter/plugin.js +173 -42
- package/lib/types/dsh-adapter/preset-resolution.d.ts +8 -0
- package/lib/types/dsh-adapter/preset-resolution.d.ts.map +1 -1
- package/lib/types/dsh-adapter/preset-resolution.js +10 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts +53 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.d.ts.map +1 -0
- package/lib/types/dsh-adapter/session-mount-heartbeat.js +100 -0
- package/lib/types/dsh-adapter/sessionTree.d.ts.map +1 -1
- package/lib/types/dsh-adapter/sessionTree.js +3 -2
- package/lib/types/dsh-adapter/subagents.d.ts.map +1 -1
- package/lib/types/dsh-adapter/subagents.js +6 -5
- package/lib/types/dsh-adapter/workspaces.d.ts +46 -3
- package/lib/types/dsh-adapter/workspaces.d.ts.map +1 -1
- package/lib/types/dsh-adapter/workspaces.js +116 -0
- package/lib/types/effortPrefs.d.ts +15 -3
- package/lib/types/effortPrefs.d.ts.map +1 -1
- package/lib/types/effortPrefs.js +37 -3
- package/lib/types/homePrefs.d.ts +15 -0
- package/lib/types/homePrefs.d.ts.map +1 -0
- package/lib/types/homePrefs.js +53 -0
- package/lib/types/i18n.d.ts +257 -296
- package/lib/types/i18n.d.ts.map +1 -1
- package/lib/types/i18n.js +78 -84
- package/lib/types/ink/colorize.d.ts +10 -0
- package/lib/types/ink/colorize.d.ts.map +1 -1
- package/lib/types/ink/colorize.js +21 -0
- package/lib/types/ink/components/ScrollBox.d.ts.map +1 -1
- package/lib/types/ink/components/ScrollBox.js +12 -1
- package/lib/types/ink/dom.d.ts +1 -0
- package/lib/types/ink/dom.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts +5 -1
- package/lib/types/ink/hooks/use-copy-on-select.d.ts.map +1 -1
- package/lib/types/ink/hooks/use-copy-on-select.js +15 -1
- package/lib/types/ink/ink.d.ts.map +1 -1
- package/lib/types/ink/ink.js +36 -1
- package/lib/types/ink/output.d.ts +10 -1
- package/lib/types/ink/output.d.ts.map +1 -1
- package/lib/types/ink/output.js +109 -17
- package/lib/types/ink/render-border.d.ts +6 -1
- package/lib/types/ink/render-border.d.ts.map +1 -1
- package/lib/types/ink/render-border.js +25 -9
- package/lib/types/ink/render-node-to-output.d.ts.map +1 -1
- package/lib/types/ink/render-node-to-output.js +48 -6
- package/lib/types/ink/renderer.d.ts +6 -0
- package/lib/types/ink/renderer.d.ts.map +1 -1
- package/lib/types/ink/renderer.js +2 -1
- package/lib/types/ink/selection.d.ts +60 -0
- package/lib/types/ink/selection.d.ts.map +1 -1
- package/lib/types/ink/selection.js +129 -0
- package/lib/types/ink/sixel-graphics.d.ts +19 -1
- package/lib/types/ink/sixel-graphics.d.ts.map +1 -1
- package/lib/types/ink/sixel-graphics.js +124 -12
- package/lib/types/ink/terminal-image.d.ts +18 -1
- package/lib/types/ink/terminal-image.d.ts.map +1 -1
- package/lib/types/ink/terminal.d.ts +17 -0
- package/lib/types/ink/terminal.d.ts.map +1 -1
- package/lib/types/ink/terminal.js +20 -1
- package/lib/types/screens/Chat.d.ts +17 -1
- package/lib/types/screens/Chat.d.ts.map +1 -1
- package/lib/types/screens/Chat.js +284 -72
- package/lib/types/screens/SessionSupervisor.d.ts +84 -0
- package/lib/types/screens/SessionSupervisor.d.ts.map +1 -0
- package/lib/types/screens/SessionSupervisor.js +350 -0
- package/lib/types/screens/SessionTree.js +2 -2
- package/lib/types/screens/Settings.d.ts.map +1 -1
- package/lib/types/screens/Settings.js +32 -9
- package/lib/types/screens/StatusLine.d.ts +13 -0
- package/lib/types/screens/StatusLine.d.ts.map +1 -1
- package/lib/types/screens/StatusLine.js +36 -17
- package/lib/types/screens/StatusMetrics.d.ts +79 -22
- package/lib/types/screens/StatusMetrics.d.ts.map +1 -1
- package/lib/types/screens/StatusMetrics.js +153 -88
- package/lib/types/screens/sessionSupervisor/model.d.ts +83 -0
- package/lib/types/screens/sessionSupervisor/model.d.ts.map +1 -0
- package/lib/types/screens/sessionSupervisor/model.js +69 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts +120 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.d.ts.map +1 -0
- package/lib/types/screens/sessionSupervisor/useSessionSupervisor.js +593 -0
- package/lib/types/sessionMounts.d.ts +272 -0
- package/lib/types/sessionMounts.d.ts.map +1 -0
- package/lib/types/sessionMounts.js +706 -0
- package/lib/types/sessions/format.d.ts.map +1 -1
- package/lib/types/sessions/format.js +4 -1
- package/lib/types/sessions/resumeFailure.d.ts +38 -0
- package/lib/types/sessions/resumeFailure.d.ts.map +1 -0
- package/lib/types/sessions/resumeFailure.js +58 -0
- package/lib/types/terminal-utils/mermaid.d.ts +44 -0
- package/lib/types/terminal-utils/mermaid.d.ts.map +1 -0
- package/lib/types/terminal-utils/mermaid.js +83 -0
- package/lib/types/tips.d.ts.map +1 -1
- package/lib/types/tips.js +175 -19
- package/lib/types/tuiDisplayPrefs.d.ts +7 -9
- package/lib/types/tuiDisplayPrefs.d.ts.map +1 -1
- package/lib/types/tuiDisplayPrefs.js +31 -28
- package/lib/types/update.d.ts +61 -0
- package/lib/types/update.d.ts.map +1 -1
- package/lib/types/update.js +194 -0
- package/lib/types/utils/imageResize.d.ts +90 -0
- package/lib/types/utils/imageResize.d.ts.map +1 -0
- package/lib/types/utils/imageResize.js +272 -0
- package/lib/types/utils/keymap.d.ts +5 -1
- package/lib/types/utils/keymap.d.ts.map +1 -1
- package/lib/types/utils/keymap.js +23 -0
- package/lib/types/workspaces.d.ts +2 -1
- package/lib/types/workspaces.d.ts.map +1 -1
- package/lib/types/workspaces.js +1 -1
- package/node_modules/@deepseek-harness-tui/dsh-auth/package.json +10 -10
- package/package.json +120 -103
- package/presets/liangshen/.dsh-tui-managed.json +1 -1
- package/presets/liangshen/agent.cordis.yml +15 -0
- package/lib/types/screens/AgentView.d.ts +0 -23
- package/lib/types/screens/AgentView.d.ts.map +0 -1
- package/lib/types/screens/AgentView.js +0 -546
- package/lib/types/screens/SessionBrowser.d.ts +0 -42
- package/lib/types/screens/SessionBrowser.d.ts.map +0 -1
- package/lib/types/screens/SessionBrowser.js +0 -911
|
@@ -76,6 +76,25 @@ export type SelectionState = {
|
|
|
76
76
|
* were on, xterm.js would have consumed the event for native selection
|
|
77
77
|
* and we'd never receive it. Used by the footer to show the right hint. */
|
|
78
78
|
lastPressHadAlt: boolean;
|
|
79
|
+
/** Rolling fingerprint (hash) of the rows under the highlight. Ink's
|
|
80
|
+
* render loop refreshes it every frame; a change between frames
|
|
81
|
+
* WITHOUT a paired follow-shift means screen content was replaced in
|
|
82
|
+
* place under a stationary selection (a streaming transcript
|
|
83
|
+
* overwriting the rows the highlight covers), and a copy from these
|
|
84
|
+
* coordinates would read whatever text now sits there — not what the
|
|
85
|
+
* user highlighted. Null until the first frame observes the
|
|
86
|
+
* selection. */
|
|
87
|
+
coveredFingerprint: number | null;
|
|
88
|
+
/** Geometry key (start/end row:col) the fingerprint was taken at. Any
|
|
89
|
+
* user-driven geometry change (drag motion, word/line extension,
|
|
90
|
+
* keyboard pan, multi-click) re-baselines instead of judging — the
|
|
91
|
+
* guard only ever indicts a STATIONARY highlight whose text was
|
|
92
|
+
* swapped underneath. Owned by refreshSelectionFingerprint. */
|
|
93
|
+
coveredGeometry: string | null;
|
|
94
|
+
/** Sticky once the covered rows changed without follow coordination.
|
|
95
|
+
* Commit-time copy (copySelectionNoClear) refuses and clears instead
|
|
96
|
+
* of shipping the replaced text. Cleared on start/clear. */
|
|
97
|
+
stale: boolean;
|
|
79
98
|
};
|
|
80
99
|
/**
|
|
81
100
|
* Create a new selection state with no active selection.
|
|
@@ -379,6 +398,47 @@ export declare function selectionBounds(s: SelectionState): {
|
|
|
379
398
|
* @returns true when the cell lies inside the selection range.
|
|
380
399
|
*/
|
|
381
400
|
export declare function isCellSelected(s: SelectionState, col: number, row: number): boolean;
|
|
401
|
+
/**
|
|
402
|
+
* Rehash the rows under the highlight and latch `stale` when they changed
|
|
403
|
+
* without a coordinated shift this frame.
|
|
404
|
+
*
|
|
405
|
+
* Copy reads whatever text occupies the highlight's screen coordinates at
|
|
406
|
+
* commit time. When the transcript REPLACES those rows in place while the
|
|
407
|
+
* highlight sits still (streaming output overwriting folded rows, a card
|
|
408
|
+
* collapsing under the anchor), the copied text is whatever moved in —
|
|
409
|
+
* visibly wrong text, not mojibake from a width bug. The follow/resize
|
|
410
|
+
* shifts keep the highlight anchored to text that MOVES; this guard catches
|
|
411
|
+
* the complementary case: stationary coordinates, moving content.
|
|
412
|
+
*
|
|
413
|
+
* Called once per rendered frame (post-render, pre-swap) on the frame the
|
|
414
|
+
* copy would read. The hash covers every visible cell of every covered row
|
|
415
|
+
* (same visibility rules as getSelectedText: noSelect and spacer cells
|
|
416
|
+
* skipped) via the cell's TEXT — `charPool.get(charId)` — not its pool
|
|
417
|
+
* index, plus the two soft-wrap inputs that decide how those cells are laid
|
|
418
|
+
* out into lines (the row's own `softWrap[row]`, and the `softWrap[row + 1]`
|
|
419
|
+
* extractRowText reads as this row's content end). styleId is excluded so
|
|
420
|
+
* the selection overlay and syntax highlighting themselves cannot trip the
|
|
421
|
+
* guard.
|
|
422
|
+
*
|
|
423
|
+
* Why content and not charId: a charId is an index into a generational
|
|
424
|
+
* CharPool, not a stable identity. Ink.resetPools() (ink.tsx) swaps in a
|
|
425
|
+
* fresh CharPool every ~5 minutes and re-interns the front frame through
|
|
426
|
+
* migrateScreenPools, so the SAME glyph comes back under a different
|
|
427
|
+
* number. Hashing ids would read that renumbering as "the covered rows
|
|
428
|
+
* changed" and refuse a perfectly legitimate copy with the stale-content
|
|
429
|
+
* notice — a false positive on a screen where nothing was replaced. The
|
|
430
|
+
* pool lookup is an array index plus a 1-2 code-unit hash loop, measured
|
|
431
|
+
* at ~0.05ms for a full 200x50 selection (~0.14ms at 200x200), i.e. no
|
|
432
|
+
* worse than hashing the ids themselves.
|
|
433
|
+
*
|
|
434
|
+
* @param s - the selection state to fingerprint.
|
|
435
|
+
* @param screen - the frame's screen buffer.
|
|
436
|
+
* @param coordinated - true when this frame translated the selection
|
|
437
|
+
* endpoints (follow-shift or viewport resize); a fingerprint change in
|
|
438
|
+
* such a frame is the expected content scroll, not an overwrite.
|
|
439
|
+
* @returns true when an uncoordinated change latched `stale` this call.
|
|
440
|
+
*/
|
|
441
|
+
export declare function refreshSelectionFingerprint(s: SelectionState, screen: Screen, coordinated: boolean): boolean;
|
|
382
442
|
/**
|
|
383
443
|
* Extract text from the screen buffer within the selection range.
|
|
384
444
|
* Rows are joined with newlines unless the screen's softWrap bitmap
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/ink/selection.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,aAAa,CAAA;AAGpD,KAAK,KAAK,GAAG;IAAE,GAAG,EAAE,MAAM,CAAC;IAAC,GAAG,EAAE,MAAM,CAAA;CAAE,CAAA;AAEzC;;;GAGG;AACH,MAAM,MAAM,cAAc,GAAG;IAC3B,6DAA6D;IAC7D,MAAM,EAAE,KAAK,GAAG,IAAI,CAAA;IACpB,oEAAoE;IACpE,KAAK,EAAE,KAAK,GAAG,IAAI,CAAA;IACnB,4CAA4C;IAC5C,UAAU,EAAE,OAAO,CAAA;IACnB;;;;4EAIwE;IACxE,UAAU,EAAE;QAAE,EAAE,EAAE,KAAK,CAAC;QAAC,EAAE,EAAE,KAAK,CAAC;QAAC,IAAI,EAAE,MAAM,GAAG,MAAM,CAAA;KAAE,GAAG,IAAI,CAAA;IAClE;;;;0EAIsE;IACtE,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,qEAAqE;IACrE,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B;;;;;iBAKa;IACb,kBAAkB,EAAE,OAAO,EAAE,CAAA;IAC7B,oCAAoC;IACpC,kBAAkB,EAAE,OAAO,EAAE,CAAA;IAC7B;;;;uEAImE;IACnE,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,sBAAsB;IACtB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;0DAKsD;IACtD,UAAU,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAA;IAC5C;;;;gFAI4E;IAC5E,eAAe,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"selection.d.ts","sourceRoot":"","sources":["../../../src/ink/selection.ts"],"names":[],"mappings":"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"}
|
|
@@ -26,6 +26,9 @@ export function createSelectionState() {
|
|
|
26
26
|
scrolledOffAboveSW: [],
|
|
27
27
|
scrolledOffBelowSW: [],
|
|
28
28
|
lastPressHadAlt: false,
|
|
29
|
+
coveredFingerprint: null,
|
|
30
|
+
coveredGeometry: null,
|
|
31
|
+
stale: false,
|
|
29
32
|
};
|
|
30
33
|
}
|
|
31
34
|
/**
|
|
@@ -52,6 +55,9 @@ export function startSelection(s, col, row) {
|
|
|
52
55
|
s.virtualFocusRow = undefined;
|
|
53
56
|
s.dragBounds = undefined;
|
|
54
57
|
s.lastPressHadAlt = false;
|
|
58
|
+
s.coveredFingerprint = null;
|
|
59
|
+
s.coveredGeometry = null;
|
|
60
|
+
s.stale = false;
|
|
55
61
|
}
|
|
56
62
|
/**
|
|
57
63
|
* Track the drag position: update focus to (col, row). No-op while not
|
|
@@ -120,6 +126,9 @@ export function clearSelection(s) {
|
|
|
120
126
|
s.virtualFocusRow = undefined;
|
|
121
127
|
s.dragBounds = undefined;
|
|
122
128
|
s.lastPressHadAlt = false;
|
|
129
|
+
s.coveredFingerprint = null;
|
|
130
|
+
s.coveredGeometry = null;
|
|
131
|
+
s.stale = false;
|
|
123
132
|
}
|
|
124
133
|
// Unicode-aware word character matcher: letters (any script), digits,
|
|
125
134
|
// and the punctuation set iTerm2 treats as word-part by default.
|
|
@@ -969,6 +978,126 @@ function joinRows(lines, text, sw) {
|
|
|
969
978
|
lines.push(text);
|
|
970
979
|
}
|
|
971
980
|
}
|
|
981
|
+
/**
|
|
982
|
+
* Rehash the rows under the highlight and latch `stale` when they changed
|
|
983
|
+
* without a coordinated shift this frame.
|
|
984
|
+
*
|
|
985
|
+
* Copy reads whatever text occupies the highlight's screen coordinates at
|
|
986
|
+
* commit time. When the transcript REPLACES those rows in place while the
|
|
987
|
+
* highlight sits still (streaming output overwriting folded rows, a card
|
|
988
|
+
* collapsing under the anchor), the copied text is whatever moved in —
|
|
989
|
+
* visibly wrong text, not mojibake from a width bug. The follow/resize
|
|
990
|
+
* shifts keep the highlight anchored to text that MOVES; this guard catches
|
|
991
|
+
* the complementary case: stationary coordinates, moving content.
|
|
992
|
+
*
|
|
993
|
+
* Called once per rendered frame (post-render, pre-swap) on the frame the
|
|
994
|
+
* copy would read. The hash covers every visible cell of every covered row
|
|
995
|
+
* (same visibility rules as getSelectedText: noSelect and spacer cells
|
|
996
|
+
* skipped) via the cell's TEXT — `charPool.get(charId)` — not its pool
|
|
997
|
+
* index, plus the two soft-wrap inputs that decide how those cells are laid
|
|
998
|
+
* out into lines (the row's own `softWrap[row]`, and the `softWrap[row + 1]`
|
|
999
|
+
* extractRowText reads as this row's content end). styleId is excluded so
|
|
1000
|
+
* the selection overlay and syntax highlighting themselves cannot trip the
|
|
1001
|
+
* guard.
|
|
1002
|
+
*
|
|
1003
|
+
* Why content and not charId: a charId is an index into a generational
|
|
1004
|
+
* CharPool, not a stable identity. Ink.resetPools() (ink.tsx) swaps in a
|
|
1005
|
+
* fresh CharPool every ~5 minutes and re-interns the front frame through
|
|
1006
|
+
* migrateScreenPools, so the SAME glyph comes back under a different
|
|
1007
|
+
* number. Hashing ids would read that renumbering as "the covered rows
|
|
1008
|
+
* changed" and refuse a perfectly legitimate copy with the stale-content
|
|
1009
|
+
* notice — a false positive on a screen where nothing was replaced. The
|
|
1010
|
+
* pool lookup is an array index plus a 1-2 code-unit hash loop, measured
|
|
1011
|
+
* at ~0.05ms for a full 200x50 selection (~0.14ms at 200x200), i.e. no
|
|
1012
|
+
* worse than hashing the ids themselves.
|
|
1013
|
+
*
|
|
1014
|
+
* @param s - the selection state to fingerprint.
|
|
1015
|
+
* @param screen - the frame's screen buffer.
|
|
1016
|
+
* @param coordinated - true when this frame translated the selection
|
|
1017
|
+
* endpoints (follow-shift or viewport resize); a fingerprint change in
|
|
1018
|
+
* such a frame is the expected content scroll, not an overwrite.
|
|
1019
|
+
* @returns true when an uncoordinated change latched `stale` this call.
|
|
1020
|
+
*/
|
|
1021
|
+
export function refreshSelectionFingerprint(s, screen, coordinated) {
|
|
1022
|
+
if (s.stale)
|
|
1023
|
+
return false;
|
|
1024
|
+
const b = selectionBounds(s);
|
|
1025
|
+
if (!b) {
|
|
1026
|
+
s.coveredFingerprint = null;
|
|
1027
|
+
s.coveredGeometry = null;
|
|
1028
|
+
return false;
|
|
1029
|
+
}
|
|
1030
|
+
// Any geometry change re-baselines: drag motion, word/line extension,
|
|
1031
|
+
// keyboard pan, multi-click — the user redefined what is highlighted, so
|
|
1032
|
+
// the next copy legitimately reads the new band's CURRENT text. Only a
|
|
1033
|
+
// stationary highlight can go stale.
|
|
1034
|
+
const geometry = `${b.start.row}:${b.start.col}-${b.end.row}:${b.end.col}`;
|
|
1035
|
+
if (geometry !== s.coveredGeometry) {
|
|
1036
|
+
s.coveredGeometry = geometry;
|
|
1037
|
+
s.coveredFingerprint = null;
|
|
1038
|
+
}
|
|
1039
|
+
const { cells, noSelect, width, height, charPool, softWrap } = screen;
|
|
1040
|
+
let h = 0x811c9dc5;
|
|
1041
|
+
for (let row = b.start.row; row <= b.end.row; row++) {
|
|
1042
|
+
if (row < 0 || row >= height)
|
|
1043
|
+
continue;
|
|
1044
|
+
const rowOff = row * width;
|
|
1045
|
+
// Column bounds mirror getSelectedText exactly: the boundary rows hash
|
|
1046
|
+
// only from start.col / through end.col. Streaming text appended to a
|
|
1047
|
+
// covered row OUTSIDE the selected column range (stable head selected,
|
|
1048
|
+
// live tail still writing) must not latch stale — the copy would not
|
|
1049
|
+
// read those columns anyway.
|
|
1050
|
+
const colStart = row === b.start.row ? b.start.col : 0;
|
|
1051
|
+
const colEnd = row === b.end.row ? b.end.col : width - 1;
|
|
1052
|
+
for (let col = colStart; col <= colEnd; col++) {
|
|
1053
|
+
const ci = (rowOff + col) * 2;
|
|
1054
|
+
// word1's low 2 bits are the cell width; SpacerTail/SpacerHead carry
|
|
1055
|
+
// no text of their own.
|
|
1056
|
+
if ((cells[ci + 1] & 3) >= 2 /* CellWidth.SpacerTail */)
|
|
1057
|
+
continue;
|
|
1058
|
+
if (noSelect[rowOff + col] === 1)
|
|
1059
|
+
continue;
|
|
1060
|
+
// Resolve the id through the pool and hash the actual characters —
|
|
1061
|
+
// the exact string getSelectedText would emit for this cell. Two
|
|
1062
|
+
// pools holding the same glyph hash identically, so a generational
|
|
1063
|
+
// pool swap is invisible here; a different glyph is not.
|
|
1064
|
+
const ch = charPool.get(cells[ci]);
|
|
1065
|
+
for (let k = 0; k < ch.length; k++) {
|
|
1066
|
+
h = Math.imul(h ^ ch.charCodeAt(k), 0x01000193);
|
|
1067
|
+
}
|
|
1068
|
+
}
|
|
1069
|
+
// Row separator + the row's soft-wrap bit: getSelectedText joins a
|
|
1070
|
+
// wrapped row onto the previous line with NO newline (softWrap[row]>0)
|
|
1071
|
+
// but emits a real newline otherwise — identical cells with a flipped
|
|
1072
|
+
// wrap bit produce a different copy, so the fingerprint must see it.
|
|
1073
|
+
h = Math.imul(h ^ 0x9e3779b9 ^ (softWrap[row] > 0 ? 0x51ed270b : 0), 0x85ebca6b);
|
|
1074
|
+
// The row BELOW is an input to THIS row's copy. extractRowText reads
|
|
1075
|
+
// softWrap[row + 1] as this row's content end: > 0 means the row wraps
|
|
1076
|
+
// into the next one, which both clamps the last column to
|
|
1077
|
+
// min(colEnd, contentEnd - 1) and suppresses the trailing-blank trim.
|
|
1078
|
+
// Flipping only the next row's wrap bit therefore rewrites the last
|
|
1079
|
+
// covered line's trailing columns ("A" → "A ") with every
|
|
1080
|
+
// covered CELL unchanged — the guard has to see the wrap, not just the
|
|
1081
|
+
// cells. Hash exactly what extractRowText consumes (0 = not wrapped) so
|
|
1082
|
+
// a contentEnd change that does not move the clamp stays invisible
|
|
1083
|
+
// instead of becoming a false positive.
|
|
1084
|
+
const contentEnd = row + 1 < height ? softWrap[row + 1] : 0;
|
|
1085
|
+
const wrapClamp = contentEnd > 0 ? Math.min(colEnd, contentEnd - 1) + 1 : 0;
|
|
1086
|
+
h = Math.imul(h ^ 0x27d4eb2f ^ wrapClamp, 0x165667b1);
|
|
1087
|
+
}
|
|
1088
|
+
if (s.coveredFingerprint === null) {
|
|
1089
|
+
// First frame observing this selection: baseline, no verdict.
|
|
1090
|
+
s.coveredFingerprint = h;
|
|
1091
|
+
return false;
|
|
1092
|
+
}
|
|
1093
|
+
if (h === s.coveredFingerprint)
|
|
1094
|
+
return false;
|
|
1095
|
+
s.coveredFingerprint = h;
|
|
1096
|
+
if (coordinated)
|
|
1097
|
+
return false;
|
|
1098
|
+
s.stale = true;
|
|
1099
|
+
return true;
|
|
1100
|
+
}
|
|
972
1101
|
/**
|
|
973
1102
|
* Extract text from the screen buffer within the selection range.
|
|
974
1103
|
* Rows are joined with newlines unless the screen's softWrap bitmap
|
|
@@ -19,6 +19,8 @@ export declare class SixelGraphicsManager {
|
|
|
19
19
|
private desired;
|
|
20
20
|
private displayed;
|
|
21
21
|
private nextDisplay;
|
|
22
|
+
/** Rects kept on screen this frame (replacement pending or covered). */
|
|
23
|
+
private readonly held;
|
|
22
24
|
private readonly repaint;
|
|
23
25
|
private worker;
|
|
24
26
|
private workerKeys;
|
|
@@ -35,7 +37,23 @@ export declare class SixelGraphicsManager {
|
|
|
35
37
|
beginFrame(columns: number, rows: number): void;
|
|
36
38
|
readonly prepare: (placement: TerminalImagePlacement) => boolean;
|
|
37
39
|
private variant;
|
|
38
|
-
/**
|
|
40
|
+
/**
|
|
41
|
+
* Reconcile ALL old rectangles before diffing, with only one baseline copy.
|
|
42
|
+
*
|
|
43
|
+
* A rect is erased only when this frame replaces it (a ready raster at a new
|
|
44
|
+
* key/geometry, erased and drawn in the same write) or drops it entirely.
|
|
45
|
+
* Rects whose replacement is still being encoded, or which a later paint
|
|
46
|
+
* covers, are held: erasing them without drawing a replacement in the same
|
|
47
|
+
* frame is exactly the black flash seen while scrolling and the vanishing
|
|
48
|
+
* image under an overlay. {@link paint} folds the held rects back into
|
|
49
|
+
* `displayed`, and the frame that finally replaces one forces a repaint
|
|
50
|
+
* through the `held` marker.
|
|
51
|
+
*
|
|
52
|
+
* A held rect that an overlay PARTLY covers still has to give up the covered
|
|
53
|
+
* cells: its pixels outlive cell writes (a background-only space cell diffs
|
|
54
|
+
* as unchanged, so the frame never rewrites it) and would show through the
|
|
55
|
+
* overlay. Those sub-rects are erased with the placement's surface color.
|
|
56
|
+
*/
|
|
39
57
|
reconcile(screen: Screen, previous: Screen, placements?: readonly TerminalImagePlacement[]): {
|
|
40
58
|
erase: string;
|
|
41
59
|
baseline: Screen;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sixel-graphics.d.ts","sourceRoot":"","sources":["../../../src/ink/sixel-graphics.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAA2C,MAAM,kBAAkB,CAAA;AAChH,OAAO,EAIL,KAAK,gBAAgB,EAAE,KAAK,sBAAsB,EACnD,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;
|
|
1
|
+
{"version":3,"file":"sixel-graphics.d.ts","sourceRoot":"","sources":["../../../src/ink/sixel-graphics.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,kBAAkB,EAAE,WAAW,EAA2C,MAAM,kBAAkB,CAAA;AAChH,OAAO,EAIL,KAAK,gBAAgB,EAAE,KAAK,sBAAsB,EACnD,MAAM,qBAAqB,CAAA;AAC5B,OAAO,EAAuB,KAAK,MAAM,EAAE,MAAM,aAAa,CAAA;AAC9D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAwBtC,KAAK,OAAO,GAAG,CAAC,OAAO,EAAE,kBAAkB,KAAK,OAAO,CAAC,WAAW,CAAC,CAAA;AAiBpE,oFAAoF;AACpF,qBAAa,oBAAoB;IAyBnB,OAAO,CAAC,QAAQ,CAAC,OAAO;IAAc,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAC;IAxB3E,OAAO,CAAC,IAAI,CAA+C;IAC3D,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAoC;IACxD,OAAO,CAAC,MAAM,CAAI;IAClB,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAwC;IAC9D,OAAO,CAAC,WAAW,CAAI;IACvB,OAAO,CAAC,UAAU,CAAI;IACtB,OAAO,CAAC,MAAM,CAAqB;IACnC,OAAO,CAAC,OAAO,CAAgB;IAC/B,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAiC;IACvD,OAAO,CAAC,OAAO,CAAoB;IACnC,OAAO,CAAC,SAAS,CAAmC;IACpD,OAAO,CAAC,WAAW,CAAmC;IACtD,wEAAwE;IACxE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAmC;IACxD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAwB;IAChD,OAAO,CAAC,MAAM,CAAoB;IAClC,OAAO,CAAC,UAAU,CAAoB;IACtC,OAAO,CAAC,YAAY,CAAuC;IAC3D,OAAO,CAAC,QAAQ,CAAQ;IACxB,OAAO,CAAC,KAAK,CAAQ;IACrB,OAAO,CAAC,OAAO,CAAI;IACnB,OAAO,CAAC,IAAI,CAAI;IAChB,OAAO,CAAC,cAAc,CAAQ;gBAED,OAAO,EAAE,MAAM,IAAI,EAAmB,OAAO,CAAC,EAAE,OAAO,YAAA;IAEpF,IAAI,QAAQ,IAAI,OAAO,CAAgE;IAEvF,cAAc,CAAC,OAAO,EAAE,OAAO,GAAG,IAAI;IAKtC,WAAW,CAAC,IAAI,EAAE,gBAAgB,GAAG,OAAO;IAQ5C,UAAU,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI;IAO/C,QAAQ,CAAC,OAAO,GAAI,WAAW,sBAAsB,KAAG,OAAO,CAc9D;IAED,OAAO,CAAC,OAAO;IAgDf;;;;;;;;;;;;;;;;OAgBG;IACH,SAAS,CAAC,MAAM,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,SAAS,sBAAsB,EAAE,GAAG;QAAE,KAAK,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE;IAwGhI,iFAAiF;IACjF,KAAK,CAAC,IAAI,EAAE,IAAI,GAAG,MAAM;IAmBzB,aAAa,IAAI,IAAI;IAErB,KAAK,IAAI,MAAM;IAWf,OAAO,IAAI,MAAM;IAajB,OAAO,CAAC,KAAK;IAiBb,OAAO,CAAC,WAAW;IAcnB,OAAO,CAAC,UAAU;IAwBlB,OAAO,CAAC,KAAK;IAWb,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,cAAc;CAkEvB"}
|
|
@@ -2,10 +2,21 @@ import { Worker } from 'node:worker_threads';
|
|
|
2
2
|
import { DEFAULT_TERMINAL_CELL_SIZE, normalizeTerminalCellSize, TERMINAL_IMAGE_MAX_EDGE, TERMINAL_IMAGE_MAX_BYTES, TERMINAL_IMAGE_PREVIEW_MAX_EDGE, TERMINAL_IMAGE_PREVIEW_MAX_BYTES, SIXEL_MAX_ENCODED_BYTES, SIXEL_THUMBNAIL_FRAME_BYTES, SIXEL_CACHE_BYTES, SIXEL_CACHE_ENTRIES, } from './terminal-image.js';
|
|
3
3
|
import { cellAt, clearRegion } from './screen.js';
|
|
4
4
|
import { stringWidth } from './stringWidth.js';
|
|
5
|
+
import { backgroundOpenCode } from './colorize.js';
|
|
5
6
|
function overlaps(a, b) {
|
|
6
7
|
return a.x < b.x + b.columns && a.x + a.columns > b.x &&
|
|
7
8
|
a.y < b.y + b.rows && a.y + a.rows > b.y;
|
|
8
9
|
}
|
|
10
|
+
/** Intersection of two cell rects, or undefined when they do not overlap. */
|
|
11
|
+
function intersectRects(a, b) {
|
|
12
|
+
const x = Math.max(a.x, b.x);
|
|
13
|
+
const y = Math.max(a.y, b.y);
|
|
14
|
+
const right = Math.min(a.x + a.columns, b.x + b.columns);
|
|
15
|
+
const bottom = Math.min(a.y + a.rows, b.y + b.rows);
|
|
16
|
+
if (right <= x || bottom <= y)
|
|
17
|
+
return undefined;
|
|
18
|
+
return { x, y, columns: right - x, rows: bottom - y };
|
|
19
|
+
}
|
|
9
20
|
/** Viewport-owned pixels. Encoding is shared; placement/erasure is per DOM node. */
|
|
10
21
|
export class SixelGraphicsManager {
|
|
11
22
|
onReady;
|
|
@@ -22,6 +33,8 @@ export class SixelGraphicsManager {
|
|
|
22
33
|
desired = new Set();
|
|
23
34
|
displayed = new Map();
|
|
24
35
|
nextDisplay = new Map();
|
|
36
|
+
/** Rects kept on screen this frame (replacement pending or covered). */
|
|
37
|
+
held = new Map();
|
|
25
38
|
repaint = new Set();
|
|
26
39
|
worker;
|
|
27
40
|
workerKeys = new Set();
|
|
@@ -119,22 +132,59 @@ export class SixelGraphicsManager {
|
|
|
119
132
|
crop: { left, top, width: cropWidth, height: cropHeight } },
|
|
120
133
|
};
|
|
121
134
|
}
|
|
122
|
-
/**
|
|
135
|
+
/**
|
|
136
|
+
* Reconcile ALL old rectangles before diffing, with only one baseline copy.
|
|
137
|
+
*
|
|
138
|
+
* A rect is erased only when this frame replaces it (a ready raster at a new
|
|
139
|
+
* key/geometry, erased and drawn in the same write) or drops it entirely.
|
|
140
|
+
* Rects whose replacement is still being encoded, or which a later paint
|
|
141
|
+
* covers, are held: erasing them without drawing a replacement in the same
|
|
142
|
+
* frame is exactly the black flash seen while scrolling and the vanishing
|
|
143
|
+
* image under an overlay. {@link paint} folds the held rects back into
|
|
144
|
+
* `displayed`, and the frame that finally replaces one forces a repaint
|
|
145
|
+
* through the `held` marker.
|
|
146
|
+
*
|
|
147
|
+
* A held rect that an overlay PARTLY covers still has to give up the covered
|
|
148
|
+
* cells: its pixels outlive cell writes (a background-only space cell diffs
|
|
149
|
+
* as unchanged, so the frame never rewrites it) and would show through the
|
|
150
|
+
* overlay. Those sub-rects are erased with the placement's surface color.
|
|
151
|
+
*/
|
|
123
152
|
reconcile(screen, previous, placements) {
|
|
124
153
|
const actual = placements ? new Map(placements.map(p => [p.node, p])) : undefined;
|
|
125
154
|
const visible = [];
|
|
126
155
|
this.desired = new Set();
|
|
127
156
|
this.nextDisplay.clear();
|
|
157
|
+
this.held.clear();
|
|
128
158
|
this.repaint.clear();
|
|
159
|
+
// Nodes whose raster this frame drops (the paint no longer registers an
|
|
160
|
+
// image, or a later paint covers every visible cell): their pixels must be
|
|
161
|
+
// erased, unlike the ones merely held below.
|
|
162
|
+
const dropped = new Set();
|
|
129
163
|
for (const [node, variant] of this.frame) {
|
|
130
164
|
const placement = actual?.get(node);
|
|
131
|
-
if (
|
|
165
|
+
if (actual && !placement) {
|
|
166
|
+
dropped.add(node);
|
|
167
|
+
continue;
|
|
168
|
+
}
|
|
169
|
+
if (placement?.occludedFully) {
|
|
170
|
+
dropped.add(node);
|
|
132
171
|
continue;
|
|
172
|
+
}
|
|
133
173
|
visible.push(variant);
|
|
134
174
|
this.desired.add(variant.key);
|
|
175
|
+
// Partially covered: drawing would pierce the overlay that covers it, so
|
|
176
|
+
// keep the pixels already on screen and wait for the cover to clear.
|
|
177
|
+
if (placement?.occluded)
|
|
178
|
+
continue;
|
|
135
179
|
const raster = this.cache.get(variant.key);
|
|
136
180
|
if (variant.ready && raster && placement?.graphicsReady !== false && this.isUncovered(variant.rect, screen)) {
|
|
137
|
-
|
|
181
|
+
const background = variant.placement.background;
|
|
182
|
+
this.nextDisplay.set(node, {
|
|
183
|
+
...variant.rect,
|
|
184
|
+
key: variant.key,
|
|
185
|
+
raster,
|
|
186
|
+
...(background === undefined ? {} : { background }),
|
|
187
|
+
});
|
|
138
188
|
}
|
|
139
189
|
}
|
|
140
190
|
const unique = new Map();
|
|
@@ -145,27 +195,71 @@ export class SixelGraphicsManager {
|
|
|
145
195
|
this.pending = [...unique.values()].sort((a, b) => Number(b.placement.presentation === 'preview') - Number(a.placement.presentation === 'preview'));
|
|
146
196
|
this.drain();
|
|
147
197
|
const erased = [];
|
|
198
|
+
let coverErase = '';
|
|
148
199
|
for (const [node, old] of this.displayed) {
|
|
149
200
|
const next = this.nextDisplay.get(node);
|
|
150
|
-
if (
|
|
151
|
-
|
|
201
|
+
if (next !== undefined) {
|
|
202
|
+
if (this.dirty || old.key !== next.key || old.x !== next.x || old.y !== next.y)
|
|
203
|
+
erased.push(old);
|
|
204
|
+
continue;
|
|
205
|
+
}
|
|
206
|
+
// Still requested this frame, but its replacement raster is not ready
|
|
207
|
+
// (scrolling re-crops per row and the encoder is async) or a later paint
|
|
208
|
+
// covers it. Erasing here would leave a hole with no draw in the same
|
|
209
|
+
// frame — the black flash while scrolling and the vanishing image under
|
|
210
|
+
// a tooltip. Keep the pixels already on screen until a replacement can
|
|
211
|
+
// be drawn in the same write.
|
|
212
|
+
if (!this.dirty && this.frame.has(node) && !dropped.has(node)) {
|
|
213
|
+
const placement = actual?.get(node);
|
|
214
|
+
const coveredRects = placement?.coveredRects;
|
|
215
|
+
const coveredKey = coveredRects === undefined || coveredRects.length === 0
|
|
216
|
+
? undefined
|
|
217
|
+
: coveredRects.map(rect => `${rect.x},${rect.y},${rect.width},${rect.height}`).join(';');
|
|
218
|
+
if (coveredKey !== undefined && coveredKey !== old.covered) {
|
|
219
|
+
// The overlay paints these cells, but only the ones whose style
|
|
220
|
+
// changes get a write: an unchanged background-only space keeps the
|
|
221
|
+
// raster's pixels. Erase the covered cells (with the surface color,
|
|
222
|
+
// so they match the cell model) and leave the rest held.
|
|
223
|
+
const visibleRect = { x: old.x, y: old.y, columns: old.columns, rows: old.rows };
|
|
224
|
+
for (const rect of coveredRects) {
|
|
225
|
+
const clipped = intersectRects(visibleRect, { x: rect.x, y: rect.y, columns: rect.width, rows: rect.height });
|
|
226
|
+
if (clipped !== undefined)
|
|
227
|
+
coverErase += this.erase(clipped, old.background);
|
|
228
|
+
}
|
|
229
|
+
}
|
|
230
|
+
this.held.set(node, coveredKey === undefined
|
|
231
|
+
? { ...old, held: true }
|
|
232
|
+
: { ...old, held: true, covered: coveredKey });
|
|
233
|
+
continue;
|
|
234
|
+
}
|
|
235
|
+
erased.push(old);
|
|
152
236
|
}
|
|
153
237
|
for (const [node, next] of this.nextDisplay) {
|
|
154
238
|
const old = this.displayed.get(node);
|
|
155
|
-
if (!old || this.dirty || old.
|
|
239
|
+
if (!old || this.dirty || old.held === true ||
|
|
240
|
+
old.key !== next.key || old.x !== next.x || old.y !== next.y ||
|
|
156
241
|
erased.some(rect => overlaps(rect, next)))
|
|
157
242
|
this.repaint.add(node);
|
|
158
243
|
}
|
|
159
|
-
if (erased.length === 0)
|
|
160
|
-
return
|
|
244
|
+
if (erased.length === 0) {
|
|
245
|
+
return coverErase === ''
|
|
246
|
+
? { erase: '', baseline: previous }
|
|
247
|
+
: { erase: coverErase + '\x1b[H', baseline: previous };
|
|
248
|
+
}
|
|
161
249
|
const cells = previous.cells.slice();
|
|
162
250
|
const baseline = { ...previous, cells, cells64: new BigInt64Array(cells.buffer), noSelect: previous.noSelect.slice() };
|
|
163
251
|
let erase = '';
|
|
164
252
|
for (const rect of erased) {
|
|
165
253
|
clearRegion(baseline, rect.x, rect.y, rect.columns, rect.rows);
|
|
254
|
+
// Erase at the terminal default, never at the placement's surface color:
|
|
255
|
+
// clearRegion just reset these cells to a default blank in the model, so
|
|
256
|
+
// the frame writes back everything it has to show and leaves the rest
|
|
257
|
+
// alone — an erase filled with the surface color would keep that color
|
|
258
|
+
// on screen with no write to correct it (the white card of a closed
|
|
259
|
+
// light-theme preview, cleared only when unrelated text scrolls past).
|
|
166
260
|
erase += this.erase(rect);
|
|
167
261
|
}
|
|
168
|
-
return { erase: erase + '\x1b[H', baseline };
|
|
262
|
+
return { erase: coverErase + erase + '\x1b[H', baseline };
|
|
169
263
|
}
|
|
170
264
|
/** Unchanged images have zero transport cost, including unrelated text ticks. */
|
|
171
265
|
paint(diff) {
|
|
@@ -181,6 +275,10 @@ export class SixelGraphicsManager {
|
|
|
181
275
|
draw += `\x1b[${next.y + 1};${next.x + 1}H${next.raster.data}`;
|
|
182
276
|
}
|
|
183
277
|
this.displayed = new Map(this.nextDisplay);
|
|
278
|
+
// Rects held this frame stay on screen: they were neither erased nor
|
|
279
|
+
// redrawn, so the terminal still shows them.
|
|
280
|
+
for (const [node, entry] of this.held)
|
|
281
|
+
this.displayed.set(node, entry);
|
|
184
282
|
this.dirty = false;
|
|
185
283
|
if (draw === '')
|
|
186
284
|
return '';
|
|
@@ -191,6 +289,7 @@ export class SixelGraphicsManager {
|
|
|
191
289
|
const output = [...this.displayed.values()].map(rect => this.erase(rect)).join('');
|
|
192
290
|
this.displayed.clear();
|
|
193
291
|
this.nextDisplay.clear();
|
|
292
|
+
this.held.clear();
|
|
194
293
|
this.frame.clear();
|
|
195
294
|
this.desired.clear();
|
|
196
295
|
this.pending = [];
|
|
@@ -208,21 +307,34 @@ export class SixelGraphicsManager {
|
|
|
208
307
|
this.workerKeys.clear();
|
|
209
308
|
return output;
|
|
210
309
|
}
|
|
211
|
-
erase(rect) {
|
|
310
|
+
erase(rect, background) {
|
|
212
311
|
const columns = Math.min(rect.columns, this.columns - rect.x);
|
|
213
312
|
const rows = Math.min(rect.rows, this.rows - rect.y);
|
|
214
313
|
if (columns <= 0 || rows <= 0)
|
|
215
314
|
return '';
|
|
216
|
-
|
|
315
|
+
// Erase-Character fills with the cell's current background and is the only
|
|
316
|
+
// way to drop pixels a frame never rewrites. The surface color is for the
|
|
317
|
+
// one rect the frame cannot correct afterwards — cells a later paint
|
|
318
|
+
// covers while keeping their style (see reconcile); every caller that
|
|
319
|
+
// hands those cells back to the diff passes no color.
|
|
320
|
+
// The placement carries the raw color string; Color is its renderer form.
|
|
321
|
+
const open = background === undefined ? '' : backgroundOpenCode(background);
|
|
322
|
+
let data = `\x1b[0m${open}`;
|
|
217
323
|
for (let y = rect.y; y < rect.y + rows; y++)
|
|
218
324
|
data += `\x1b[${y + 1};${rect.x + 1}H\x1b[${columns}X`;
|
|
325
|
+
if (open !== '')
|
|
326
|
+
data += '\x1b[0m';
|
|
219
327
|
return data;
|
|
220
328
|
}
|
|
221
329
|
isUncovered(rect, screen) {
|
|
330
|
+
// Any visible glyph under the raster blocks it; background-only cells do
|
|
331
|
+
// not. Image-owned cells carry the surface background in Sixel mode (an
|
|
332
|
+
// opaque backing is required there), and comparing against the empty
|
|
333
|
+
// style would reject the raster's own backing.
|
|
222
334
|
for (let y = rect.y; y < rect.y + rect.rows; y++) {
|
|
223
335
|
for (let x = rect.x; x < rect.x + rect.columns; x++) {
|
|
224
336
|
const cell = cellAt(screen, x, y);
|
|
225
|
-
if (cell &&
|
|
337
|
+
if (cell && cell.char !== ' ' && cell.char !== '')
|
|
226
338
|
return false;
|
|
227
339
|
}
|
|
228
340
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import type { DOMElement } from './dom.js';
|
|
2
|
+
import type { Rectangle } from './layout/geometry.js';
|
|
2
3
|
/** Hard bounds for one decoded image admitted to the terminal renderer. */
|
|
3
4
|
export declare const TERMINAL_IMAGE_MAX_EDGE = 1024;
|
|
4
5
|
export declare const TERMINAL_IMAGE_MAX_BYTES: number;
|
|
@@ -60,8 +61,24 @@ export interface TerminalImagePlacement {
|
|
|
60
61
|
readonly background?: string;
|
|
61
62
|
/** False while a protocol-specific raster is pending or unavailable. */
|
|
62
63
|
readonly graphicsReady?: boolean;
|
|
63
|
-
/** Later paint operations cover this
|
|
64
|
+
/** Later paint operations cover part of this raster's visible cells. */
|
|
64
65
|
readonly occluded?: boolean;
|
|
66
|
+
/**
|
|
67
|
+
* Later paint operations cover every visible cell of this raster, so it is
|
|
68
|
+
* unreachable and must be erased rather than kept (a blank `opaque` overlay
|
|
69
|
+
* would otherwise be pierced by the pixels beneath it). Partial coverage
|
|
70
|
+
* sets {@link occluded} only.
|
|
71
|
+
*/
|
|
72
|
+
readonly occludedFully?: boolean;
|
|
73
|
+
/**
|
|
74
|
+
* The later paint operations that cover PART of this raster, in absolute
|
|
75
|
+
* screen cells. A protocol whose pixels outlive cell writes must erase these
|
|
76
|
+
* rects itself: with Sixel, a background-only space cell over the raster has
|
|
77
|
+
* the same style as the image's own backing cell, so the frame diff emits no
|
|
78
|
+
* write for it and the old pixels keep showing through the overlay (the white
|
|
79
|
+
* block between "100%" and "原像素" in a preview tooltip).
|
|
80
|
+
*/
|
|
81
|
+
readonly coveredRects?: readonly Rectangle[];
|
|
65
82
|
}
|
|
66
83
|
/**
|
|
67
84
|
* Normalize terminal-reported cell pixels before they reach allocation math.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal-image.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal-image.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,UAAU,CAAA;
|
|
1
|
+
{"version":3,"file":"terminal-image.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal-image.ts"],"names":[],"mappings":"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"}
|
|
@@ -32,6 +32,14 @@ export declare function isProgressReportingAvailable(): boolean;
|
|
|
32
32
|
* @returns true when the process runs in a JetBrains IDE terminal.
|
|
33
33
|
*/
|
|
34
34
|
export declare function isJetBrainsIdeTerminal(): boolean;
|
|
35
|
+
/**
|
|
36
|
+
* Detects zellij, which multiplexes the outer terminal instead of emulating
|
|
37
|
+
* it. Capability probes therefore describe the *outer* terminal — zellij even
|
|
38
|
+
* forwards KITTY_WINDOW_ID into the pane, so kitty detection matches — while
|
|
39
|
+
* zellij's own grid decides how control sequences actually apply.
|
|
40
|
+
* @returns true when the process runs inside a zellij pane.
|
|
41
|
+
*/
|
|
42
|
+
export declare function isZellij(): boolean;
|
|
35
43
|
/**
|
|
36
44
|
* Checks if the terminal supports DEC mode 2026 (synchronized output).
|
|
37
45
|
* When supported, BSU/ESU sequences prevent visible flicker during redraws.
|
|
@@ -136,6 +144,15 @@ export declare const SYNC_OUTPUT_SUPPORTED: boolean;
|
|
|
136
144
|
* as content scrolls (the "JetBrains terminal slowly garbles" bug class).
|
|
137
145
|
* The diff engine falls back to repainting the shifted rows cell-by-cell,
|
|
138
146
|
* which every terminal renders identically. Disable DECSTBM on JetBrains terminals.
|
|
147
|
+
*
|
|
148
|
+
* zellij is excluded for the same class of reason. Its `CSI T`
|
|
149
|
+
* (grid.rs rotate_scroll_region_up) shifts rows only while the cursor sits
|
|
150
|
+
* inside the scroll region, and its `CSI r` does not home the cursor outside
|
|
151
|
+
* origin mode — but the renderer parks the cursor on the last screen row,
|
|
152
|
+
* below every ScrollBox. The shift is silently dropped while the diff assumes
|
|
153
|
+
* it happened, so stale rows survive every scroll-up frame (tearing, leftover
|
|
154
|
+
* transcript lines). Only DECSTBM is withdrawn: zellij does implement DEC
|
|
155
|
+
* 2026, so BSU/ESU stay on and frames remain atomic.
|
|
139
156
|
* @returns true when DECSTBM scroll optimization is safe on this terminal.
|
|
140
157
|
*/
|
|
141
158
|
export declare function isDecstbmSafe(): boolean;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAKtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAYtC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,eAAe,CAAA;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAuCtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAwDvD;AAcD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAGnC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAyBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,WAAW,GAAE,MAAM,GAAG,SAAoC,EAC1D,kBAAkB,GAAE,MAAM,GAAG,SAA4C,GACxE,OAAO,CAOT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,SAAkC,CAAA;AAEpE
|
|
1
|
+
{"version":3,"file":"terminal.d.ts","sourceRoot":"","sources":["../../../src/ink/terminal.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,QAAQ,CAAA;AAKtC,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,YAAY,CAAA;AAYtC;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,KAAK,EAAE,SAAS,GAAG,WAAW,GAAG,OAAO,GAAG,eAAe,CAAA;IAC1D,UAAU,CAAC,EAAE,MAAM,CAAA;CACpB,CAAA;AAED;;;;;;;;;GASG;AACH,wBAAgB,4BAA4B,IAAI,OAAO,CAuCtD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;;;;GAMG;AACH,wBAAgB,QAAQ,IAAI,OAAO,CAElC;AAED;;;;GAIG;AACH,wBAAgB,6BAA6B,IAAI,OAAO,CAwDvD;AAcD;;;;GAIG;AACH,wBAAgB,gBAAgB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CAEnD;AAED;;;;;;;GAOG;AACH,wBAAgB,SAAS,IAAI,OAAO,CAGnC;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAgB,mBAAmB,IAAI,OAAO,CAE7C;AAyBD;;;;;;;;;GASG;AACH,wBAAgB,oBAAoB,IAAI,OAAO,CAG9C;AAED;;;;;;;;;;;;;;;;;;GAkBG;AACH,wBAAgB,sBAAsB,CACpC,QAAQ,GAAE,MAAM,CAAC,QAA2B,EAC5C,WAAW,GAAE,MAAM,GAAG,SAAoC,EAC1D,kBAAkB,GAAE,MAAM,GAAG,SAA4C,GACxE,OAAO,CAOT;AAED;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,IAAI,OAAO,CAEpD;AAED;;;;GAIG;AACH,eAAO,MAAM,qBAAqB,SAAkC,CAAA;AAEpE;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,aAAa,IAAI,OAAO,CAEvC;AAuBD;;GAEG;AACH,MAAM,MAAM,QAAQ,GAAG;IACrB,MAAM,EAAE,QAAQ,CAAA;IAChB,MAAM,EAAE,QAAQ,CAAA;CACjB,CAAA;AAED;;;;;;;GAOG;AACH;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAC3B,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,eAAe,UAAQ,GACtB,MAAM,CAwFR;AAED;;;;;;;GAOG;AACH,wBAAgB,mBAAmB,CACjC,QAAQ,EAAE,QAAQ,EAClB,IAAI,EAAE,IAAI,EACV,eAAe,UAAQ,GACtB,IAAI,CAMN"}
|