Raxol.UI.Components.Harness.DiffViewer (Raxol v2.6.1)

View Source

Pre-apply file diff viewer.

Renders the line-based diff between a file's current content (old) and a proposed edit (new) BEFORE the edit is applied. This is the "pre-apply confirmation over post-hoc undo" surface described in docs/proposals/in-flight/harness-spec-frontend.md: framing always reads as "this WILL change" -- a "Proposed change" header and a "Not yet applied" caption, never past tense.

Visual language

Ports the Pierre (@pierre/diffs) visual language -- docs/proposals/in-flight/pierre-diffs-analysis.md -- flattened for a terminal cell grid (one bg + one fg per cell, no alpha compositing):

  • Diff paints background only; syntax tokens own foreground and are never overridden. Added rows get a dark-green bg wash, removed rows dark-red, with a brighter "emphasis" bg tier on the word-level-changed sub-ranges of a paired change row -- syntax colors show through both tiers unchanged.
  • A gutter bar (green/red) replaces the classic +/- text marker, per Pierre's bars indicator style.
  • Long unchanged runs (> 2 * context + 1 lines) fold into a single dim "N unchanged lines" row; context: :all disables folding.
  • Split mode is borderless and label-less -- the red/green gutters carry the old/new identity -- and the unpaired side of a change block stays blank to keep the panes vertically aligned.

Line differencing is computed by Raxol.UI.Components.Harness.LineDiff (a plain LCS line diff). Intra-line word ranges come from Raxol.UI.Components.Harness.WordDiff (positional deletion/addition pairing within a changed hunk, word-level LCS, word-alt span merging). Syntax tokens come from Raxol.UI.SyntaxHighlighter (Makeup-based; language: nil skips highlighting entirely).

Props

  • :path - file path shown in the header (default "").
  • :old - original file content (default "").
  • :new - proposed file content (default "").
  • :mode - :auto (default), :unified, or :split. In :auto, split is chosen when both rendered panes fit side by side in the available width, otherwise unified. Width comes from the :width prop, else from the render context (:available_width,:width, ordimensions.width); with no width information auto falls back to unified (the safe narrow default). *:width- available width in terminal columns, used only by:auto(defaultnil). *:language- source language for syntax highlighting (e.g."elixir"), passed toRaxol.UI.SyntaxHighlighter.highlight_lines/3.nil(default) disables highlighting -- lines render as plain diff-tinted text. *:syntax_theme- Makeup style atom (e.g.:one_dark,:dracula) or a%Makeup.Styles.HTML.Style{}, passed through to the highlighter (default:one_dark). Distinct from the:themeprop below, which is the Raxol UI theme override map, not a code theme. *:context- number of unchanged lines kept visible at each edge of a folded hunk, or:allto disable folding entirely (default3). *:id,:style,:theme` - standard component props. ## Example {:ok, state} = DiffViewer.init( path: "lib/orders/total.ex", old: old_text, new: new_text, language: "elixir" ) DiffViewer.render(state, %{})

Summary

Functions

The single source of the merged diff visual language's hex tiers (row wash, intra-line emphasis, gutter tint -- see the comment above @diff_palette): add_base/add_row_bg/add_emphasis_bg/add_gutter_bg and their del_* counterparts, each an "#RRGGBB" string. This Component's own grid rendering (render/2) always reads it through the private per-tier accessors above; diff_palette/0 exposes the SAME map publicly so a second renderer of this diff visual language never forks its own copy of these hexes. Raxol.Harness.DiffExpansion's per-row line renderer (the full-screen diff expansion's row-level tier of this same visual language -- gutter bar plus row wash, no word-level emphasis or syntax highlighting) is the first such caller.

The mode render/2 will actually use for this state and context.

Types

fold_context()

@type fold_context() :: non_neg_integer() | :all

mode()

@type mode() :: :unified | :split | :auto

t()

@type t() :: %{
  id: String.t() | atom(),
  path: String.t(),
  old: String.t(),
  new: String.t(),
  mode: mode(),
  width: pos_integer() | nil,
  language: String.t() | nil,
  syntax_theme: atom() | struct(),
  context: fold_context(),
  style: map(),
  theme: map()
}

Functions

broadcast(msg)

command(cmd)

diff_palette()

@spec diff_palette() :: %{
  add_base: String.t(),
  add_row_bg: String.t(),
  add_emphasis_bg: String.t(),
  add_gutter_bg: String.t(),
  del_base: String.t(),
  del_row_bg: String.t(),
  del_emphasis_bg: String.t(),
  del_gutter_bg: String.t()
}

The single source of the merged diff visual language's hex tiers (row wash, intra-line emphasis, gutter tint -- see the comment above @diff_palette): add_base/add_row_bg/add_emphasis_bg/add_gutter_bg and their del_* counterparts, each an "#RRGGBB" string. This Component's own grid rendering (render/2) always reads it through the private per-tier accessors above; diff_palette/0 exposes the SAME map publicly so a second renderer of this diff visual language never forks its own copy of these hexes. Raxol.Harness.DiffExpansion's per-row line renderer (the full-screen diff expansion's row-level tier of this same visual language -- gutter bar plus row wash, no word-level emphasis or syntax highlighting) is the first such caller.

effective_mode(state, context)

@spec effective_mode(t(), map()) :: :unified | :split

The mode render/2 will actually use for this state and context.

Resolves :auto against the available width: :split when both panes fit side by side, :unified otherwise (including when no width is known). Explicit :unified/:split pass through unchanged. Exposed so demos and callers can display or act on the auto decision.

handle_event(event, state, context)

Callback implementation for Raxol.UI.Components.Base.Component.handle_event/3.

mount(state)

Callback implementation for Raxol.UI.Components.Base.Component.mount/1.

schedule(msg, delay)

unmount(state)

Callback implementation for Raxol.UI.Components.Base.Component.unmount/1.

update(props, state)

Callback implementation for Raxol.UI.Components.Base.Component.update/2.