This rewrites the look of the interactive horizontal histogram in Rizin - the output of `p==v`, `p==ev`, `p==mv`, `p==0v`, `p==fv`, `p==pv`, `p==zv`, `p==Sv` and the analysis-based interactive variants. It closes #6365 and #4431 in full, and now sits on top of the recently merged static-histogram PR (#6427) so it reuses the new RzHistogramOptions struct and its helpers. Five sub-tasks from #6365: - Context-aware vertical ruler with up to 5 anchor labels (top, bottom, quarter, half, three-quarter) honouring opts->value_min..value_max, value_precision, value_scale and value_unit. Reuses the static helpers compute_ruler_gutter, render_ruler_gutter, label_value_at and select_ruler_label_rows so visual and static stay consistent. - X-axis byte-offset ruler at the bottom: `^` ticks every (addr_w + 3) cols followed by absolute byte offsets computed from opts->offpos + realj * blocksize. - Cursor offset + percentage shown right-aligned on the status line, with "Index N data V" on the left. - Top minimap: Unicode block characters (▁▂▃▄▅▆▇█) for the density of each slice of the whole data, plus a ┏━━━┓ window indicator showing the visible slice. Always rendered when the new `scr.hist.minimap` config is true. When the terminal is wide (hist->w > 200) the minimap shrinks by 43 columns to make room for a two-line `px 0x20`-style hex preview panel on the right showing the 32 bytes at the cursor's file offset. Each byte is wrapped in its px-style colour code (b0x00 / b0x7f / b0xff / btext / other) when opts->color is set, matching rz_print's rz_print_byte_color exactly. A trailing safety pad keeps the canvas from clipping the last byte of the first hex row. - Missing-half bug on `p==v` when the cursor is at offset 0 fixed by clamping `adder` to [0, histogramwidth - span]. The old expression `barnumber + 1 - histogramwidth/(zoom*2)` was always negative for the default barnumber=0, causing the rendering loop to read `data[-N]` (segfault on large files, missing left half on small ones). Cursor visibility: - The cursor column is drawn as a CONTINUOUS vertical line connecting two plain markers at the top and bottom, ALWAYS exactly one character wide. The line itself uses the dedicated `wordhl` palette colour (default red background, configurable via `ec wordhl ...`), drawn on every chart row so the cursor is always a full-height vertical strip. The markers (`▼` at the top and `▲` at the bottom, or ASCII `v` / `^` when scr.utf8=false) are intentionally left un-highlighted so they read as a clean pair of arrows pointing at the cursor column. - The cursor screen column is computed up-front (j_cursor) by inverting the data-to-column map (rel * zoom * width / histogramwidth). Two distinct widening bugs are avoided this way: 1. sizeofonebar > 1 (high zoom) - each data index spans several screen columns; only j == j_cursor && kbar == 0 renders as the cursor, the remaining kbar columns fall through to the gradient. 2. histogramwidth < width (chart much wider than data) - several adjacent screen columns map to the same data index via integer truncation; only the j_cursor column may render as the cursor. Interactive keybindings & live config: - The `:` hotkey drops into rz_core_visual_prompt_input, matching the rest of Rizin's visual modes. Lets the user run arbitrary rizin commands without leaving the histogram. - The `?` help text now uses the same colour-coded format as the visual / visual-bit-editor modes (rz_core_visual_append_help with pal.args for keys and pal.help for descriptions), shown via rz_cons_less_str. - The config-driven opts (scr.hist.minimap, scr.hist.block, scr.utf8, scr.color, hex.offset) are re-read on every redraw via refresh_visual_opts_from_config, so `:` `e scr.hist.minimap=true` <Enter> takes effect immediately without having to quit and re-enter. The canvas's `color` field is refreshed alongside so `scr.color` changes take effect on the same redraw. Hex preview panel: - When the terminal is wide (hist->w > 200) and the minimap is enabled, the visual mode shows a two-line hex preview on the right of the minimap rows: 32 bytes at the cursor's file offset, formatted as 8 pairs of 2 bytes separated by spaces (`abcd ef00 1234 5678 ...`), matching `px 0x20` minus the header / offsets / ASCII column. The bytes are fetched live via rz_io_read_at_mapped each redraw, so moving the cursor (`h` / `l`) updates the preview. - Each byte gets its px-style colour code: green for 0x00, red for 0xff, yellow for 0x7f, btext (white) for printable ASCII, "other" (magenta) for non-printable. Mirrors rz_print_byte_color so the histogram preview reads consistently with `px`. - A trailing safety pad keeps the canvas from clipping the last hex byte of the first row (a side effect of UTF-8 minimap glyphs interacting with the canvas's width tracking when the row fills the canvas exactly). - Implemented via two new fields on RzHistogramInteractive (`cursor_bytes`, `cursor_bytes_len`) that the caller fills in just before the render call and clears right after. The minimap helper grows two extra parameters that the visual function passes through; when the panel is disabled (narrow terminal, no cursor_bytes, or shrinking the minimap would leave it < 40 cols) the helper falls back to the previous full-width minimap. Closes #4431 in full: - The negative-offset crash above is the immediate segfault from the bug report. - `print_histogram_bytes` now samples one byte per block instead of reading nblocks contiguous bytes from core->offset. For an 8 GB file shown across 80 bars the original code rendered the first 80 bytes of the file; the new code samples at offsets brange->from + i * blocksize so the chart represents the full span. - The inner `int i` in the column-aggregation loop is renamed to `k` to drop the shadow over the outer `size_t i`. Refactor on the cmd_print.c side: - New default_visual_opts(core, offset) returns an RZ_OWN RzHistogramOptions* pre-populated for the visual commands (ruler=true, minimap from scr.hist.minimap, offpos from caller, palette and screen-mode toggles from config via refresh_visual_opts_from_config). The nine print_visual_bytes call sites now build opts via this helper, then pass it to print_visual_bytes which takes ownership. Entropy sets value_max=8 / value_precision=1 / data_f=fdata so the visual histogram shows the Shannon range matching the static side. - `print_visual_bytes(core, opts, data, brange)` now propagates opts cleanup along every error path; rz_histogram_interactive_new no longer leaves a heap-allocated opts pointer dangling. The redraw loop fetches 32 cursor bytes via rz_io_read_at_mapped, points hist->cursor_bytes at a stack buffer for the call, then NULLs it back so the next iteration's fetch is independent. - RzHistogramInteractive gains `blocksize`, `cursor_bytes` and `cursor_bytes_len` fields. New config option: - `scr.hist.minimap` (bool, default true) controls whether the top minimap is shown for p==v / p==ev. Surfaces as `opts->minimap` and is honoured by `rz_histogram_interactive_horizontal`. When true, the minimap is ALWAYS rendered (provided there's room) - even when the chart already shows the full data, in which case the window indicator spans the whole map. Changes via `:` `e scr.hist.minimap=...` <Enter> are picked up on the very next redraw. Tests (33 total, 10 new for the visual side): - test_histogram_interactive_horizontal_basic - smoke test with barnumber=0 (pins the #4431 crash regression). - test_histogram_interactive_horizontal_ruler_percent - fractional labels with value_max=100 / value_scale=0.01 / unit="%". - test_histogram_interactive_horizontal_ruler_default - the legacy 0..255 byte ruler. - test_histogram_interactive_horizontal_no_negative_adder - covers `p==v` at offset 0 on a small data set. - test_histogram_interactive_horizontal_percent - status-line percent indicator present. - test_histogram_interactive_horizontal_cursor_markers - the ▼/▲ cursor markers (and ASCII v/^ fallback) appear on the cursor column, left un-highlighted. - test_histogram_interactive_horizontal_cursor_full_line - the cursor bar is rendered on every chart row between the markers regardless of the data threshold (continuous vertical line). - test_histogram_interactive_horizontal_cursor_width - pins single- char width across BOTH cursor-widening bugs: high zoom (sizeofonebar > 1) AND chart wider than data (histogramwidth < width). - test_histogram_interactive_horizontal_minimap_toggle - pins the scr.hist.minimap gating across {zoomed, not zoomed} when opts->minimap=true / =false. - test_histogram_interactive_horizontal_hex_preview - 4 cases: wide terminal + cursor_bytes shows the hex panel; narrow terminal suppresses it; missing cursor_bytes suppresses it; colour mode emits ANSI escape sequences for the bytes. Both p== integration tests in test/db/cmd/cmd_print pass with their regenerated EXPECT blocks (the per-block sampling change moves the visible bars for small buffers). Co-authored-by: Anton Kochkov <anton.kochkov@gmail.com>
9 KiB
9 KiB
END
EOF
RUN
EOF
RUN