@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
package/lib/types/ink/ink.js
CHANGED
|
@@ -38,7 +38,7 @@ import { applyPositionedHighlight, scanPositions } from './render-to-screen.js';
|
|
|
38
38
|
import createRenderer from './renderer.js';
|
|
39
39
|
import { CharPool, cellAt, createScreen, HyperlinkPool, isEmptyCellAt, migrateScreenPools, StylePool } from './screen.js';
|
|
40
40
|
import { applySearchHighlight } from './transcript-highlight.js';
|
|
41
|
-
import { applySelectionOverlay, captureScrolledRows, clearSelection, createSelectionState, extendSelection, findPlainTextUrlAt, getSelectedText, hasSelection, moveFocus, pickFollowForSelection, selectLineAt, selectWordAt, shiftSelection, shiftSelectionForFollow, shiftSelectionForViewportResize, shiftSelectionForViewportTranslation, startSelection, updateSelection } from './selection.js';
|
|
41
|
+
import { applySelectionOverlay, captureScrolledRows, clearSelection, createSelectionState, extendSelection, findPlainTextUrlAt, getSelectedText, hasSelection, moveFocus, pickFollowForSelection, refreshSelectionFingerprint, selectLineAt, selectWordAt, shiftSelection, shiftSelectionForFollow, shiftSelectionForViewportResize, shiftSelectionForViewportTranslation, startSelection, updateSelection } from './selection.js';
|
|
42
42
|
import { isDecstbmSafe, SYNC_OUTPUT_SUPPORTED, serializeDiff, supportsDecrqmProbe, supportsExtendedKeys, supportsWin32InputMode, writeDiffToTerminal } from './terminal.js';
|
|
43
43
|
import { CURSOR_HOME, cursorMove, cursorPosition, DISABLE_KITTY_KEYBOARD, DISABLE_MODIFY_OTHER_KEYS, DISABLE_WIN32_INPUT_MODE, ENABLE_KITTY_KEYBOARD, ENABLE_MODIFY_OTHER_KEYS, ENABLE_WIN32_INPUT_MODE, ERASE_SCREEN, ERASE_SCROLLBACK, SGR_RESET } from './termio/csi.js';
|
|
44
44
|
import { DBP, DFE, DISABLE_MOUSE_TRACKING, ENABLE_MOUSE_TRACKING, ENTER_ALT_SCREEN, EXIT_ALT_SCREEN, SHOW_CURSOR } from './termio/dec.js';
|
|
@@ -674,9 +674,20 @@ export default class Ink {
|
|
|
674
674
|
altScreen: this.altScreenActive,
|
|
675
675
|
terminalImages: this.altScreenActive && (this.kittyGraphicsSupported || this.sixelGraphicsSupported),
|
|
676
676
|
imageReady: sixelActive ? this.sixelGraphicsManager.prepare : undefined,
|
|
677
|
+
// Sixel paints rasters over the cells: an image's own cells must then
|
|
678
|
+
// carry the surface background instead of terminal-default blanks.
|
|
679
|
+
opaqueImageBacking: sixelActive,
|
|
677
680
|
prevFrameContaminated: this.prevFrameContaminated
|
|
678
681
|
});
|
|
679
682
|
const rendererMs = performance.now() - renderStart;
|
|
683
|
+
// Whether THIS frame ran a selection-coordinate translation (viewport
|
|
684
|
+
// resize/follow-shift). A covered-rows fingerprint change in such a
|
|
685
|
+
// frame is the coordinated kind — content moved WITH the highlight.
|
|
686
|
+
// An UNcoordinated change means the rows under a stationary highlight
|
|
687
|
+
// were replaced in place (streaming transcript overwrite), and the
|
|
688
|
+
// selection is marked stale so commit-time copy refuses (see
|
|
689
|
+
// refreshSelectionFingerprint below the overlay block).
|
|
690
|
+
let selectionCoordinated = false;
|
|
680
691
|
this.maybeProbeKittyGraphics(frame.images ?? []);
|
|
681
692
|
// Viewport-shrink translation (companion to the follow block below):
|
|
682
693
|
// chrome mounting around a ScrollBox (the new-messages pill, the sticky
|
|
@@ -706,12 +717,14 @@ export default class Ink {
|
|
|
706
717
|
const hadSelection = hasSelection(this.selection);
|
|
707
718
|
if (resize.kind === 'translate') {
|
|
708
719
|
const cleared = shiftSelectionForViewportTranslation(this.selection, resize.rowDelta, resize.prevTop, resize.prevBottom, resize.top, resize.bottom);
|
|
720
|
+
selectionCoordinated = true;
|
|
709
721
|
if (cleared)
|
|
710
722
|
for (const cb of this.selectionListeners)
|
|
711
723
|
cb();
|
|
712
724
|
}
|
|
713
725
|
else {
|
|
714
726
|
shiftSelectionForViewportResize(this.selection, this.frontFrame.screen, resize.prevTop, resize.prevBottom, resize.top, resize.bottom);
|
|
727
|
+
selectionCoordinated = true;
|
|
715
728
|
// Both-ends-covered clear must notify React-land so useHasSelection
|
|
716
729
|
// re-renders and the footer copy/escape hint disappears — direct
|
|
717
730
|
// listener fire (notifySelectionChange would re-enter onRender).
|
|
@@ -775,6 +788,7 @@ export default class Ink {
|
|
|
775
788
|
// allowClear=false: both ends clamp to the edge; the ghost guard
|
|
776
789
|
// runs at release via dragBounds above.
|
|
777
790
|
shiftSelectionForFollow(this.selection, shift, viewportTop, viewportBottom, false);
|
|
791
|
+
selectionCoordinated = true;
|
|
778
792
|
}
|
|
779
793
|
else if (
|
|
780
794
|
// Flag-3 guard: the anchor check above only proves ONE endpoint is
|
|
@@ -794,6 +808,7 @@ export default class Ink {
|
|
|
794
808
|
captureScrolledRows(this.selection, this.frontFrame.screen, firstRow, lastRow, side, follow.screenRowOffset);
|
|
795
809
|
}
|
|
796
810
|
const cleared = shiftSelectionForFollow(this.selection, shift, viewportTop, viewportBottom);
|
|
811
|
+
selectionCoordinated = true;
|
|
797
812
|
// Auto-clear (both ends overshot an edge — off the top via
|
|
798
813
|
// follow/wheel-down, off the bottom via wheel-up) must notify
|
|
799
814
|
// React-land so useHasSelection re-renders and the footer
|
|
@@ -832,6 +847,13 @@ export default class Ink {
|
|
|
832
847
|
if (selActive) {
|
|
833
848
|
applySelectionOverlay(frame.screen, this.selection, this.stylePool);
|
|
834
849
|
}
|
|
850
|
+
// Commit-consistency guard: hash the rows under the highlight on the
|
|
851
|
+
// frame the copy would actually read. An uncoordinated change since
|
|
852
|
+
// the previous frame latches selection.stale; copySelectionNoClear
|
|
853
|
+
// then refuses rather than shipping whatever text now occupies the
|
|
854
|
+
// highlight coordinates. Runs on frame.screen (post-render, pre-swap)
|
|
855
|
+
// with this frame's coordinated selection coordinates.
|
|
856
|
+
refreshSelectionFingerprint(this.selection, frame.screen, selectionCoordinated);
|
|
835
857
|
// Scan-highlight: inverse on ALL visible matches (less/vim style).
|
|
836
858
|
// Position-highlight (below) overlays CURRENT (yellow) on top.
|
|
837
859
|
hlActive = applySearchHighlight(frame.screen, this.searchHighlightQuery, this.stylePool);
|
|
@@ -1910,6 +1932,19 @@ export default class Ink {
|
|
|
1910
1932
|
copySelectionNoClear() {
|
|
1911
1933
|
if (!hasSelection(this.selection))
|
|
1912
1934
|
return '';
|
|
1935
|
+
// Commit-consistency guard: the rows under the highlight changed
|
|
1936
|
+
// without follow coordination during the selection's lifetime, so
|
|
1937
|
+
// these coordinates now hold text the user never highlighted.
|
|
1938
|
+
// Shipping it would copy visibly wrong content (the "mojibake-looking"
|
|
1939
|
+
// paste of another line); refuse, clear the stale highlight, and let
|
|
1940
|
+
// the caller surface it (React callers enter through copySelection /
|
|
1941
|
+
// useCopyOnSelect's onRefused — the direct no-clear entry must not
|
|
1942
|
+
// leave the misleading highlight up either).
|
|
1943
|
+
if (this.selection.stale) {
|
|
1944
|
+
clearSelection(this.selection);
|
|
1945
|
+
this.notifySelectionChange();
|
|
1946
|
+
return '';
|
|
1947
|
+
}
|
|
1913
1948
|
const text = getSelectedText(this.selection, this.frontFrame.screen);
|
|
1914
1949
|
if (text) {
|
|
1915
1950
|
// Raw OSC 52, or DCS-passthrough-wrapped OSC 52 inside tmux (tmux
|
|
@@ -73,6 +73,14 @@ type Options = {
|
|
|
73
73
|
/** Paint image fallbacks as blank backing cells and collect placements. */
|
|
74
74
|
terminalImages?: boolean;
|
|
75
75
|
imageReady?: (placement: TerminalImagePlacement) => boolean;
|
|
76
|
+
/**
|
|
77
|
+
* True when the active protocol paints rasters OVER the cell grid (Sixel)
|
|
78
|
+
* instead of behind it (Kitty). Image-owned cells must then carry the
|
|
79
|
+
* surface background: the raster covers them anyway, and terminal-default
|
|
80
|
+
* blanks would show as black holes wherever a raster fails to cover a cell
|
|
81
|
+
* (aspect rounding, suppressed/occluded placements).
|
|
82
|
+
*/
|
|
83
|
+
opaqueImageBacking?: boolean;
|
|
76
84
|
/** Image requests from the diff baseline, reused by clean subtree blits. */
|
|
77
85
|
previousImages?: readonly TerminalImagePlacement[];
|
|
78
86
|
};
|
|
@@ -161,6 +169,7 @@ export default class Output {
|
|
|
161
169
|
private readonly stylePool;
|
|
162
170
|
private screen;
|
|
163
171
|
terminalImagesEnabled: boolean;
|
|
172
|
+
opaqueImageBacking: boolean;
|
|
164
173
|
private imageReady;
|
|
165
174
|
private readonly operations;
|
|
166
175
|
private readonly imagePlacements;
|
|
@@ -201,7 +210,7 @@ export default class Output {
|
|
|
201
210
|
* @param height - the new screen height in rows.
|
|
202
211
|
* @param screen - the screen buffer to render into.
|
|
203
212
|
*/
|
|
204
|
-
reset(width: number, height: number, screen: Screen, terminalImages?: boolean, previousImages?: readonly TerminalImagePlacement[], imageReady?: (placement: TerminalImagePlacement) => boolean): void;
|
|
213
|
+
reset(width: number, height: number, screen: Screen, terminalImages?: boolean, previousImages?: readonly TerminalImagePlacement[], imageReady?: (placement: TerminalImagePlacement) => boolean, opaqueImageBacking?: boolean): void;
|
|
205
214
|
/**
|
|
206
215
|
* Copy cells from a source screen region (blit = block image transfer).
|
|
207
216
|
* @param src - the source screen.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/ink/output.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"output.d.ts","sourceRoot":"","sources":["../../../src/ink/output.ts"],"names":[],"mappings":"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"}
|
package/lib/types/ink/output.js
CHANGED
|
@@ -274,6 +274,81 @@ function buildClusteredChars(line, stylePool, slot) {
|
|
|
274
274
|
updateStreamingSlot(slot, line, clustered, chars);
|
|
275
275
|
return clustered;
|
|
276
276
|
}
|
|
277
|
+
/**
|
|
278
|
+
* The screen rect a paint operation covers, when it can occlude a raster
|
|
279
|
+
* painted earlier in the same frame. `clip`/`unclip`/`noSelect` paint nothing.
|
|
280
|
+
*/
|
|
281
|
+
function imageOcclusionRect(op, width) {
|
|
282
|
+
if (op.type === 'write') {
|
|
283
|
+
return { x: op.x, y: op.y, width: widestLine(op.text), height: op.lines?.length ?? op.text.split('\n').length };
|
|
284
|
+
}
|
|
285
|
+
if (op.type === 'blit')
|
|
286
|
+
return op;
|
|
287
|
+
if (op.type === 'clear' || op.type === 'shade')
|
|
288
|
+
return op.region;
|
|
289
|
+
if (op.type === 'shift')
|
|
290
|
+
return { x: 0, y: op.top, width, height: op.bottom - op.top + 1 };
|
|
291
|
+
return undefined;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* The union of two rects, but only when that union covers no cell the pair did
|
|
295
|
+
* not already cover between them. Two rects qualify when one contains the
|
|
296
|
+
* other, or when they are bands sharing a full edge span (same x-span and
|
|
297
|
+
* abutting/overlapping rows, or the transpose) — exactly the pairs whose union
|
|
298
|
+
* is itself a rectangle. An L-shaped pair does not qualify: the bounding box of
|
|
299
|
+
* its two arms covers cells neither arm covers, and the caller would erase
|
|
300
|
+
* pixels that are still visible.
|
|
301
|
+
* @param a - the first rectangle.
|
|
302
|
+
* @param b - the second rectangle.
|
|
303
|
+
* @returns their union, or undefined when folding them would add cells.
|
|
304
|
+
*/
|
|
305
|
+
function exactUnion(a, b) {
|
|
306
|
+
const contains = (outer, inner) => outer.x <= inner.x && outer.y <= inner.y &&
|
|
307
|
+
outer.x + outer.width >= inner.x + inner.width &&
|
|
308
|
+
outer.y + outer.height >= inner.y + inner.height;
|
|
309
|
+
if (contains(a, b))
|
|
310
|
+
return a;
|
|
311
|
+
if (contains(b, a))
|
|
312
|
+
return b;
|
|
313
|
+
const sameColumns = a.x === b.x && a.width === b.width &&
|
|
314
|
+
a.y <= b.y + b.height && b.y <= a.y + a.height;
|
|
315
|
+
const sameRows = a.y === b.y && a.height === b.height &&
|
|
316
|
+
a.x <= b.x + b.width && b.x <= a.x + a.width;
|
|
317
|
+
return sameColumns || sameRows ? unionRect(a, b) : undefined;
|
|
318
|
+
}
|
|
319
|
+
/**
|
|
320
|
+
* Fold occluder rects that can be folded without covering anything new, so an
|
|
321
|
+
* image protocol that has to erase them (Sixel) does not repeat the same cells.
|
|
322
|
+
* One overlay usually contributes several rects for the same area (interior
|
|
323
|
+
* fill, border row, text row), and an overlay that covers several placements
|
|
324
|
+
* would otherwise erase the shared cells once per placement.
|
|
325
|
+
*
|
|
326
|
+
* Folding stops at exact unions on purpose. The erasure has to match the cells
|
|
327
|
+
* an overlay really covers: merging any two intersecting rects into their
|
|
328
|
+
* bounding box would take down the pixels beside an L-shaped cover, which are
|
|
329
|
+
* still on screen.
|
|
330
|
+
*/
|
|
331
|
+
function mergeOcclusionRects(rects) {
|
|
332
|
+
const merged = [];
|
|
333
|
+
for (const rect of rects) {
|
|
334
|
+
let current = rect;
|
|
335
|
+
let joined = true;
|
|
336
|
+
while (joined) {
|
|
337
|
+
joined = false;
|
|
338
|
+
for (let index = merged.length - 1; index >= 0; index--) {
|
|
339
|
+
const other = merged[index];
|
|
340
|
+
const union = exactUnion(current, other);
|
|
341
|
+
if (union === undefined)
|
|
342
|
+
continue;
|
|
343
|
+
current = union;
|
|
344
|
+
merged.splice(index, 1);
|
|
345
|
+
joined = true;
|
|
346
|
+
}
|
|
347
|
+
}
|
|
348
|
+
merged.push(current);
|
|
349
|
+
}
|
|
350
|
+
return merged;
|
|
351
|
+
}
|
|
277
352
|
/**
|
|
278
353
|
* Collects write/blit/clear/clip operations from the render tree, then
|
|
279
354
|
* applies them to a Screen buffer in get(). The Screen is what gets
|
|
@@ -287,6 +362,7 @@ export default class Output {
|
|
|
287
362
|
stylePool;
|
|
288
363
|
screen;
|
|
289
364
|
terminalImagesEnabled;
|
|
365
|
+
opaqueImageBacking;
|
|
290
366
|
imageReady;
|
|
291
367
|
operations = [];
|
|
292
368
|
imagePlacements = [];
|
|
@@ -345,6 +421,7 @@ export default class Output {
|
|
|
345
421
|
this.stylePool = stylePool;
|
|
346
422
|
this.screen = screen;
|
|
347
423
|
this.terminalImagesEnabled = options.terminalImages ?? false;
|
|
424
|
+
this.opaqueImageBacking = options.opaqueImageBacking ?? false;
|
|
348
425
|
this.imageReady = options.imageReady;
|
|
349
426
|
this.previousImages = options.previousImages ?? [];
|
|
350
427
|
resetScreen(screen, width, height);
|
|
@@ -359,11 +436,12 @@ export default class Output {
|
|
|
359
436
|
* @param height - the new screen height in rows.
|
|
360
437
|
* @param screen - the screen buffer to render into.
|
|
361
438
|
*/
|
|
362
|
-
reset(width, height, screen, terminalImages = false, previousImages = [], imageReady) {
|
|
439
|
+
reset(width, height, screen, terminalImages = false, previousImages = [], imageReady, opaqueImageBacking = false) {
|
|
363
440
|
this.width = width;
|
|
364
441
|
this.height = height;
|
|
365
442
|
this.screen = screen;
|
|
366
443
|
this.terminalImagesEnabled = terminalImages;
|
|
444
|
+
this.opaqueImageBacking = opaqueImageBacking;
|
|
367
445
|
this.imageReady = imageReady;
|
|
368
446
|
this.previousImages = previousImages;
|
|
369
447
|
this.operations.length = 0;
|
|
@@ -535,22 +613,36 @@ export default class Output {
|
|
|
535
613
|
if (end === undefined)
|
|
536
614
|
return placement;
|
|
537
615
|
const visible = placement.clip ?? placement;
|
|
538
|
-
const
|
|
539
|
-
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
543
|
-
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
551
|
-
|
|
552
|
-
|
|
553
|
-
|
|
616
|
+
const right = visible.x + visible.columns;
|
|
617
|
+
const bottom = visible.y + visible.rows;
|
|
618
|
+
const overlaps = (rect) => rect.x < right &&
|
|
619
|
+
rect.x + rect.width > visible.x && rect.y < bottom && rect.y + rect.height > visible.y;
|
|
620
|
+
// A later paint that covers the whole visible rect makes the raster
|
|
621
|
+
// unreachable and erasing is the only correct outcome (a blank `opaque`
|
|
622
|
+
// overlay would otherwise be pierced by the pixels beneath it). A paint
|
|
623
|
+
// that covers only part of it must not take the rest of the raster down
|
|
624
|
+
// with it — SixelGraphicsManager keeps those pixels instead.
|
|
625
|
+
const covers = (rect) => rect.x <= visible.x && rect.y <= visible.y &&
|
|
626
|
+
rect.x + rect.width >= right && rect.y + rect.height >= bottom;
|
|
627
|
+
let occluded = false;
|
|
628
|
+
let covered = false;
|
|
629
|
+
const occluders = [];
|
|
630
|
+
for (const op of this.operations.slice(end)) {
|
|
631
|
+
const rect = imageOcclusionRect(op, this.width);
|
|
632
|
+
if (rect === undefined || !overlaps(rect))
|
|
633
|
+
continue;
|
|
634
|
+
occluded = true;
|
|
635
|
+
if (covers(rect)) {
|
|
636
|
+
covered = true;
|
|
637
|
+
break;
|
|
638
|
+
}
|
|
639
|
+
occluders.push(rect);
|
|
640
|
+
}
|
|
641
|
+
if (!occluded)
|
|
642
|
+
return placement;
|
|
643
|
+
if (covered)
|
|
644
|
+
return { ...placement, occluded, occludedFully: true };
|
|
645
|
+
return { ...placement, occluded, coveredRects: mergeOcclusionRects(occluders) };
|
|
554
646
|
});
|
|
555
647
|
}
|
|
556
648
|
/** Pixel ownership is determined by paint order, not just final text values. */
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type Boxes, type BoxStyle } from 'cli-boxes';
|
|
2
2
|
import type { DOMNode } from './dom.js';
|
|
3
3
|
import type Output from './output.js';
|
|
4
|
+
import type { Color } from './styles.js';
|
|
4
5
|
/** Options for embedding a text label into a border line. */
|
|
5
6
|
export type BorderTextOptions = {
|
|
6
7
|
content: string;
|
|
@@ -30,7 +31,11 @@ export type BorderStyle = keyof Boxes | keyof typeof CUSTOM_BORDER_STYLES | BoxS
|
|
|
30
31
|
* @param y - the border's top row.
|
|
31
32
|
* @param node - the node whose border style to render.
|
|
32
33
|
* @param output - the output buffer receiving the border writes.
|
|
34
|
+
* @param background - the surface color the border's cells belong to, when the
|
|
35
|
+
* node paints its own rect (own background, `opaque`, or an occlusion color
|
|
36
|
+
* while a terminal image sits behind it). Transparent bordered overlays pass
|
|
37
|
+
* undefined and keep terminal-transparent border cells.
|
|
33
38
|
*/
|
|
34
|
-
declare const renderBorder: (x: number, y: number, node: DOMNode, output: Output) => void;
|
|
39
|
+
declare const renderBorder: (x: number, y: number, node: DOMNode, output: Output, background?: Color) => void;
|
|
35
40
|
export default renderBorder;
|
|
36
41
|
//# sourceMappingURL=render-border.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-border.d.ts","sourceRoot":"","sources":["../../../src/ink/render-border.ts"],"names":[],"mappings":"AACA,OAAiB,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAA;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"render-border.d.ts","sourceRoot":"","sources":["../../../src/ink/render-border.ts"],"names":[],"mappings":"AACA,OAAiB,EAAE,KAAK,KAAK,EAAE,KAAK,QAAQ,EAAE,MAAM,WAAW,CAAA;AAE/D,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,UAAU,CAAA;AACvC,OAAO,KAAK,MAAM,MAAM,aAAa,CAAA;AAErC,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,aAAa,CAAA;AAExC,6DAA6D;AAC7D,MAAM,MAAM,iBAAiB,GAAG;IAC9B,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,KAAK,GAAG,QAAQ,CAAA;IAC1B,KAAK,EAAE,OAAO,GAAG,KAAK,GAAG,QAAQ,CAAA;IACjC,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAA;AAED,iEAAiE;AACjE,eAAO,MAAM,oBAAoB;;;;;;;;;;;CAYvB,CAAA;AAEV,qFAAqF;AACrF,MAAM,MAAM,WAAW,GACnB,MAAM,KAAK,GACX,MAAM,OAAO,oBAAoB,GACjC,QAAQ,CAAA;AA0DZ;;;;;;;;;;;GAWG;AACH,QAAA,MAAM,YAAY,GAChB,GAAG,MAAM,EACT,GAAG,MAAM,EACT,MAAM,OAAO,EACb,QAAQ,MAAM,EACd,aAAa,KAAK,KACjB,IAqJF,CAAA;AAED,eAAe,YAAY,CAAA"}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import chalk from 'chalk';
|
|
2
2
|
import cliBoxes from 'cli-boxes';
|
|
3
|
-
import { applyColor } from './colorize.js';
|
|
3
|
+
import { applyColor, applyTextStyles } from './colorize.js';
|
|
4
4
|
import { stringWidth } from './stringWidth.js';
|
|
5
5
|
/** Built-in border styles beyond those provided by cli-boxes. */
|
|
6
6
|
export const CUSTOM_BORDER_STYLES = {
|
|
@@ -40,11 +40,19 @@ function embedTextInBorder(borderLine, text, align, offset = 0, borderChar) {
|
|
|
40
40
|
borderLine.substring(borderLength - 1);
|
|
41
41
|
return [before, text, after];
|
|
42
42
|
}
|
|
43
|
-
function styleBorderLine(line, color, dim) {
|
|
43
|
+
function styleBorderLine(line, color, dim, background) {
|
|
44
44
|
let styled = applyColor(line, color);
|
|
45
45
|
if (dim) {
|
|
46
46
|
styled = chalk.dim(styled);
|
|
47
47
|
}
|
|
48
|
+
// The cells a border occupies belong to the surface it frames. Without an
|
|
49
|
+
// explicit background they diff back to the terminal default, which reads
|
|
50
|
+
// as a black frame around any bordered surface sitting on a colored one (a
|
|
51
|
+
// tooltip over the preview card, that card over a tool card) and as a black
|
|
52
|
+
// hole wherever a Sixel raster is exposed by a border row or column.
|
|
53
|
+
if (background !== undefined) {
|
|
54
|
+
styled = applyTextStyles(styled, { backgroundColor: background });
|
|
55
|
+
}
|
|
48
56
|
return styled;
|
|
49
57
|
}
|
|
50
58
|
/**
|
|
@@ -54,8 +62,12 @@ function styleBorderLine(line, color, dim) {
|
|
|
54
62
|
* @param y - the border's top row.
|
|
55
63
|
* @param node - the node whose border style to render.
|
|
56
64
|
* @param output - the output buffer receiving the border writes.
|
|
65
|
+
* @param background - the surface color the border's cells belong to, when the
|
|
66
|
+
* node paints its own rect (own background, `opaque`, or an occlusion color
|
|
67
|
+
* while a terminal image sits behind it). Transparent bordered overlays pass
|
|
68
|
+
* undefined and keep terminal-transparent border cells.
|
|
57
69
|
*/
|
|
58
|
-
const renderBorder = (x, y, node, output) => {
|
|
70
|
+
const renderBorder = (x, y, node, output, background) => {
|
|
59
71
|
if (node.style.borderStyle) {
|
|
60
72
|
const width = Math.floor(node.yogaNode.getComputedWidth());
|
|
61
73
|
const height = Math.floor(node.yogaNode.getComputedHeight());
|
|
@@ -85,12 +97,12 @@ const renderBorder = (x, y, node, output) => {
|
|
|
85
97
|
if (showTopBorder && node.style.borderText?.position === 'top') {
|
|
86
98
|
const [before, text, after] = embedTextInBorder(topBorderLine, node.style.borderText.content, node.style.borderText.align, node.style.borderText.offset, box.top);
|
|
87
99
|
topBorder =
|
|
88
|
-
styleBorderLine(before, topBorderColor, dimTopBorderColor) +
|
|
100
|
+
styleBorderLine(before, topBorderColor, dimTopBorderColor, background) +
|
|
89
101
|
text +
|
|
90
|
-
styleBorderLine(after, topBorderColor, dimTopBorderColor);
|
|
102
|
+
styleBorderLine(after, topBorderColor, dimTopBorderColor, background);
|
|
91
103
|
}
|
|
92
104
|
else if (showTopBorder) {
|
|
93
|
-
topBorder = styleBorderLine(topBorderLine, topBorderColor, dimTopBorderColor);
|
|
105
|
+
topBorder = styleBorderLine(topBorderLine, topBorderColor, dimTopBorderColor, background);
|
|
94
106
|
}
|
|
95
107
|
let verticalBorderHeight = height;
|
|
96
108
|
if (showTopBorder) {
|
|
@@ -108,6 +120,10 @@ const renderBorder = (x, y, node, output) => {
|
|
|
108
120
|
if (dimRightBorderColor) {
|
|
109
121
|
rightBorder = chalk.dim(rightBorder);
|
|
110
122
|
}
|
|
123
|
+
if (background !== undefined) {
|
|
124
|
+
leftBorder = applyTextStyles(leftBorder, { backgroundColor: background });
|
|
125
|
+
rightBorder = applyTextStyles(rightBorder, { backgroundColor: background });
|
|
126
|
+
}
|
|
111
127
|
const bottomBorderLine = showBottomBorder
|
|
112
128
|
? (showLeftBorder ? box.bottomLeft : '') +
|
|
113
129
|
box.bottom.repeat(contentWidth) +
|
|
@@ -118,12 +134,12 @@ const renderBorder = (x, y, node, output) => {
|
|
|
118
134
|
if (showBottomBorder && node.style.borderText?.position === 'bottom') {
|
|
119
135
|
const [before, text, after] = embedTextInBorder(bottomBorderLine, node.style.borderText.content, node.style.borderText.align, node.style.borderText.offset, box.bottom);
|
|
120
136
|
bottomBorder =
|
|
121
|
-
styleBorderLine(before, bottomBorderColor, dimBottomBorderColor) +
|
|
137
|
+
styleBorderLine(before, bottomBorderColor, dimBottomBorderColor, background) +
|
|
122
138
|
text +
|
|
123
|
-
styleBorderLine(after, bottomBorderColor, dimBottomBorderColor);
|
|
139
|
+
styleBorderLine(after, bottomBorderColor, dimBottomBorderColor, background);
|
|
124
140
|
}
|
|
125
141
|
else if (showBottomBorder) {
|
|
126
|
-
bottomBorder = styleBorderLine(bottomBorderLine, bottomBorderColor, dimBottomBorderColor);
|
|
142
|
+
bottomBorder = styleBorderLine(bottomBorderLine, bottomBorderColor, dimBottomBorderColor, background);
|
|
127
143
|
}
|
|
128
144
|
const offsetY = showTopBorder ? 1 : 0;
|
|
129
145
|
if (topBorder) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"render-node-to-output.d.ts","sourceRoot":"","sources":["../../../src/ink/render-node-to-output.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"render-node-to-output.d.ts","sourceRoot":"","sources":["../../../src/ink/render-node-to-output.ts"],"names":[],"mappings":"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"}
|
|
@@ -787,10 +787,23 @@ function renderNodeToOutput(node, output, options) {
|
|
|
787
787
|
// rect, though, and those non-default-background cells would also hide
|
|
788
788
|
// the image itself. Replace only the image-owned cells with default-
|
|
789
789
|
// background spaces; layout and surrounding inherited color stay intact.
|
|
790
|
+
//
|
|
791
|
+
// Sixel paints the raster OVER the cells instead, so its backing may
|
|
792
|
+
// (and must) carry the surface background: the raster covers those
|
|
793
|
+
// cells anyway, and terminal-default blanks would show as black holes
|
|
794
|
+
// wherever the raster misses a cell — aspect rounding at the right
|
|
795
|
+
// edge, or a suppressed placement whose cells the frame no longer
|
|
796
|
+
// repaints.
|
|
790
797
|
const imageWidth = Math.floor(width);
|
|
791
798
|
const imageHeight = Math.floor(height);
|
|
799
|
+
const backingColor = output.opaqueImageBacking
|
|
800
|
+
? node.style.backgroundColor ?? inheritedBackgroundColor
|
|
801
|
+
: undefined;
|
|
792
802
|
const imageLine = ' '.repeat(imageWidth);
|
|
793
|
-
|
|
803
|
+
const fillLine = backingColor === undefined
|
|
804
|
+
? imageLine
|
|
805
|
+
: applyTextStyles(imageLine, { backgroundColor: backingColor });
|
|
806
|
+
output.write(Math.floor(x), Math.floor(y), Array(imageHeight).fill(fillLine).join('\n'));
|
|
794
807
|
output.imageBacking(node);
|
|
795
808
|
for (const child of node.childNodes) {
|
|
796
809
|
if (child.nodeName !== '#text')
|
|
@@ -891,10 +904,25 @@ function renderNodeToOutput(node, output, options) {
|
|
|
891
904
|
// Capture previous scroll bounds BEFORE overwriting — the at-bottom
|
|
892
905
|
// follow check compares against last frame's max.
|
|
893
906
|
const prevScrollHeight = node.scrollHeight ?? scrollHeight;
|
|
894
|
-
const
|
|
907
|
+
const prevViewportHeight = node.scrollViewportHeight;
|
|
908
|
+
const prevInnerHeight = prevViewportHeight ?? innerHeight;
|
|
895
909
|
const prevViewportTop = node.scrollViewportTop;
|
|
896
910
|
node.scrollHeight = scrollHeight;
|
|
897
911
|
node.scrollViewportHeight = innerHeight;
|
|
912
|
+
// Viewport-height change is the one geometry move no scroll notify
|
|
913
|
+
// covers: chrome above/below the box mounts or unmounts (pill,
|
|
914
|
+
// pinned header, recap row) or the terminal changes row count —
|
|
915
|
+
// the viewport resizes with no scroll delta and no sticky flip,
|
|
916
|
+
// while subscribers that paint from the handle's bounds still hold
|
|
917
|
+
// the previous pass's geometry. Fire only on a real transition
|
|
918
|
+
// between two passes: a first frame (`undefined`) observed no
|
|
919
|
+
// change, and scrollTop/scrollViewportTop motion is excluded on
|
|
920
|
+
// purpose (see DOMElement.onViewportHeightChange). Called in the
|
|
921
|
+
// render pass like onStickyRestore below.
|
|
922
|
+
if (prevViewportHeight !== undefined &&
|
|
923
|
+
prevViewportHeight !== innerHeight) {
|
|
924
|
+
node.onViewportHeightChange?.();
|
|
925
|
+
}
|
|
898
926
|
// Absolute screen-buffer row where the scrollable area (inside
|
|
899
927
|
// padding) begins. Exposed via ScrollBoxHandle.getViewportTop() so
|
|
900
928
|
// drag-to-scroll can detect when the drag leaves the scroll viewport.
|
|
@@ -1447,7 +1475,17 @@ function renderNodeToOutput(node, output, options) {
|
|
|
1447
1475
|
output.shade({ x: Math.floor(x), y: Math.floor(y), width: Math.floor(width), height: Math.floor(height) });
|
|
1448
1476
|
}
|
|
1449
1477
|
const ownBackgroundColor = node.style.backgroundColor ?? occlusionBackground;
|
|
1450
|
-
|
|
1478
|
+
// A Sixel image node owns cells the raster normally paints over. When
|
|
1479
|
+
// no placement is admitted — the modal suppressed graphics, the decode
|
|
1480
|
+
// is still pending, or it failed — those cells must still read as the
|
|
1481
|
+
// enclosing surface: the admitted branch above painted them with the
|
|
1482
|
+
// same inherited color, so leaving them unwritten would diff them back
|
|
1483
|
+
// to terminal-default blanks and punch black holes in the card.
|
|
1484
|
+
const imageSurfaceColor = output.opaqueImageBacking && node.nodeName === 'ink-image'
|
|
1485
|
+
? ownBackgroundColor ?? inheritedBackgroundColor
|
|
1486
|
+
: undefined;
|
|
1487
|
+
const fillColor = ownBackgroundColor ?? imageSurfaceColor;
|
|
1488
|
+
if (fillColor || node.style.opaque) {
|
|
1451
1489
|
const borderLeft = yogaNode.getComputedBorder(LayoutEdge.Left);
|
|
1452
1490
|
const borderRight = yogaNode.getComputedBorder(LayoutEdge.Right);
|
|
1453
1491
|
const borderTop = yogaNode.getComputedBorder(LayoutEdge.Top);
|
|
@@ -1456,8 +1494,8 @@ function renderNodeToOutput(node, output, options) {
|
|
|
1456
1494
|
const innerHeight = Math.floor(height) - borderTop - borderBottom;
|
|
1457
1495
|
if (innerWidth > 0 && innerHeight > 0) {
|
|
1458
1496
|
const spaces = ' '.repeat(innerWidth);
|
|
1459
|
-
const fillLine =
|
|
1460
|
-
? applyTextStyles(spaces, { backgroundColor:
|
|
1497
|
+
const fillLine = fillColor
|
|
1498
|
+
? applyTextStyles(spaces, { backgroundColor: fillColor })
|
|
1461
1499
|
: spaces;
|
|
1462
1500
|
const fill = Array(innerHeight).fill(fillLine).join('\n');
|
|
1463
1501
|
output.write(x + borderLeft, y + borderTop, fill);
|
|
@@ -1485,7 +1523,11 @@ function renderNodeToOutput(node, output, options) {
|
|
|
1485
1523
|
// Render border AFTER children to ensure it's not overwritten by child
|
|
1486
1524
|
// clearing operations. When a child shrinks, it clears its old area,
|
|
1487
1525
|
// which may overlap with where the parent's border now is.
|
|
1488
|
-
|
|
1526
|
+
// A border's cells belong to the surface it frames: pass the node's
|
|
1527
|
+
// effective background so they never fall back to the terminal default
|
|
1528
|
+
// (a black frame around a colored surface, and a black hole where a
|
|
1529
|
+
// Sixel raster is otherwise exposed by a border row or column).
|
|
1530
|
+
renderBorder(x, y, node, output, node.style.backgroundColor ?? occlusionBackground ?? inheritedBackgroundColor);
|
|
1489
1531
|
}
|
|
1490
1532
|
else if (node.nodeName === 'ink-root') {
|
|
1491
1533
|
renderChildren(node, output, x, y, hasRemovedChild, prevScreen, inheritedBackgroundColor);
|
|
@@ -13,6 +13,12 @@ export type RenderOptions = {
|
|
|
13
13
|
/** Whether terminal graphics are active for this paint pass. */
|
|
14
14
|
terminalImages?: boolean;
|
|
15
15
|
imageReady?: (placement: TerminalImagePlacement) => boolean;
|
|
16
|
+
/**
|
|
17
|
+
* True when rasters paint over the cell grid (Sixel): image-owned cells
|
|
18
|
+
* carry the surface background instead of terminal-default blanks. See
|
|
19
|
+
* Output's `opaqueImageBacking`.
|
|
20
|
+
*/
|
|
21
|
+
opaqueImageBacking?: boolean;
|
|
16
22
|
prevFrameContaminated: boolean;
|
|
17
23
|
};
|
|
18
24
|
/** Renders the DOM tree into a frame for the given options. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/ink/renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAiC,MAAM,UAAU,CAAA;AACzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAIvC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAUjE,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AAE1D,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,KAAK,CAAA;IACjB,SAAS,EAAE,KAAK,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;IAClB,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,sBAAsB,KAAK,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"renderer.d.ts","sourceRoot":"","sources":["../../../src/ink/renderer.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,KAAK,UAAU,EAAiC,MAAM,UAAU,CAAA;AACzE,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,YAAY,CAAA;AAIvC,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAA;AAUjE,OAAO,EAAgB,KAAK,SAAS,EAAE,MAAM,aAAa,CAAA;AAE1D,+DAA+D;AAC/D,MAAM,MAAM,aAAa,GAAG;IAC1B,UAAU,EAAE,KAAK,CAAA;IACjB,SAAS,EAAE,KAAK,CAAA;IAChB,KAAK,EAAE,OAAO,CAAA;IACd,aAAa,EAAE,MAAM,CAAA;IACrB,YAAY,EAAE,MAAM,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;IAClB,gEAAgE;IAChE,cAAc,CAAC,EAAE,OAAO,CAAA;IACxB,UAAU,CAAC,EAAE,CAAC,SAAS,EAAE,sBAAsB,KAAK,OAAO,CAAA;IAC3D;;;;OAIG;IACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;IAK5B,qBAAqB,EAAE,OAAO,CAAA;CAC/B,CAAA;AAED,+DAA+D;AAC/D,MAAM,MAAM,QAAQ,GAAG,CAAC,OAAO,EAAE,aAAa,KAAK,KAAK,CAAA;AAExD;;;;;;GAMG;AACH,MAAM,CAAC,OAAO,UAAU,cAAc,CACpC,IAAI,EAAE,UAAU,EAChB,SAAS,EAAE,SAAS,GACnB,QAAQ,CAqMV"}
|
|
@@ -75,7 +75,7 @@ export default function createRenderer(node, stylePool) {
|
|
|
75
75
|
const screen = backScreen ??
|
|
76
76
|
createScreen(width, height, stylePool, charPool, hyperlinkPool);
|
|
77
77
|
if (output) {
|
|
78
|
-
output.reset(width, height, screen, options.terminalImages, frontFrame.images, options.imageReady);
|
|
78
|
+
output.reset(width, height, screen, options.terminalImages, frontFrame.images, options.imageReady, options.opaqueImageBacking ?? false);
|
|
79
79
|
}
|
|
80
80
|
else {
|
|
81
81
|
output = new Output({
|
|
@@ -86,6 +86,7 @@ export default function createRenderer(node, stylePool) {
|
|
|
86
86
|
terminalImages: options.terminalImages,
|
|
87
87
|
previousImages: frontFrame.images,
|
|
88
88
|
imageReady: options.imageReady,
|
|
89
|
+
opaqueImageBacking: options.opaqueImageBacking ?? false,
|
|
89
90
|
});
|
|
90
91
|
}
|
|
91
92
|
resetLayoutShifted();
|