Components / Data display
Diff viewer
Compares two versions of a text line by line.
Functions: cui_diff_view

Usage
static int mode = 0, change = 0; /* 0 split, 1 inline; the selected change */
static const char *const modes[] = { "Split", "Inline" };
cui_segmented(ui, "mode", modes, 2, &mode, .size = CUI_SIZE_SM);
cui_diff_result r = cui_diff_view(ui, "diff", before, after, .mode = mode ? CUI_DIFF_INLINE : CUI_DIFF_SPLIT,
.current = &change, .language = "c",
.old_title = "config.c (main)", .new_title = "config.c");
if (cui_icon_button(ui, CUI_ICON_ARROW_DOWN, .tooltip = "Next change", .shortcut = "N", .disabled = change >= r.changes - 1))
change++; /* the view scrolls to it */
cui_textf(ui, "+%d -%d", r.added, r.removed);
Split mode puts the old text on the left and the new on the right, rows aligned with a quiet filler opposite added or removed lines; inline mode shows removed lines above the lines that replaced them. Below split_min_width (560 points by default) split shows inline, so the view reads on a phone, and r.mode says which mode is shown. Each side has its line numbers and a + or - sign, added lines are tinted with the success color and removed lines with the danger color, and the words that changed inside a replaced line get a stronger tint. With .language the code keeps its syntax colors. Lines longer than the view scroll sideways, both sides together.
Unchanged stretches keep .context lines (3) next to each change and fold the rest into a "42 unchanged lines" row that opens on a click (.no_fold shows everything). With the view focused, N or Alt+Down goes to the next change and P or Alt+Up to the previous one, E opens every fold and Shift+E folds them again, arrows and Page Up/Down scroll, and clicking a change selects it. .current is read and written, so buttons only have to change the number; the result also has the +added -removed summary, the change count and whether the texts were diffed again this frame.
The texts are copied and diffed only when one of them changes, and only the rows in sight are built. The diff is Myers' shortest edit script in linear memory; lines with no match in the other text are set aside first, which keeps large diffs fast and exact. Texts that would need a very long search (many repeated lines, rewritten throughout) stop after about 16 million steps and show the rest as replaced, still a correct diff, flagged by r.approximate. cui_diff_compute returns the hunks without a view, cui_diff_words the changed words of two lines, and cui_diff_view_rows the rows as shown, for line comments.
Keyboard
- With the view focused, N or Alt+Down goes to the next change and P or Alt+Up to the previous one, E opens every fold and Shift+E folds them again, arrows and Page Up/Down scroll, and clicking a change selects it.
Options of cui_diff_view
| Option | Type | Default | Description |
|---|---|---|---|
.mode | cui_diff_mode | One of CUI_DIFF_SPLIT or CUI_DIFF_INLINE. | |
.language | const char * | syntax colors, as cui_code_block: "c", "js", "python", ... | |
.old_title | const char * | a header above the sides, e.g. file names, with the +/- summary | |
.new_title | const char * | a header above the sides, e.g. file names, with the +/- summary | |
.current | int * | the selected change, read and written (may be NULL); set it to scroll to a change | |
.context | int | 3 | unchanged lines kept beside each change, default 3 |
.no_fold | bool | show every unchanged line | |
.ignore_eol | bool | "\r\n" equals "\n", and a missing final newline does not count | |
.split_min_width | float | 560 | below this width split shows inline, default 560 |
.width | cui_size | fill | default fill |
.height | float | the rows, up to 420 | default: the rows, up to 420; negative fills the space |
.size | float | 12 | font size, default 12 |
cui_diff_result
| Field | Type | Description |
|---|---|---|
added | int | lines |
removed | int | lines |
changes | int | change blocks (hunks without context) |
current | int | the selected change, -1 none |
current_changed | bool | this frame, by the keys, a click or .current |
mode | cui_diff_mode | what is shown: inline when split did not fit |
folds | int | folded rows shown, and the unchanged lines they hide |
hidden | int | folded rows shown, and the unchanged lines they hide |
recomputed | bool | a text changed and was diffed this frame |
approximate | bool | the search hit its limit: correct, maybe not the shortest |
cui_diff_mode: CUI_DIFF_SPLIT, CUI_DIFF_INLINE
Related
- Icon button: A round button with only an icon, ghost by default.
- Segmented control: A compact set of two to five choices where one is always selected, for switching between views of the same content.
- Property inspector: A panel of named properties in folding groups, each edited with the control that fits its type.
- Code editor: An editable code field with syntax highlighting, for shader editors, script consoles and config files.