github Byron/dua-cli v2.44.0

3 hours ago

This is a massive release that cost my weekend and was motivated by the chance to
reduce the amount of open issues to 0.
Besides the memory usage being cut in half, one can now keep snapshots of interactive
runs, and compare them to older snapshots, or simply view them again with different
settings.
Finally, it's now possible to configure keyboarding as well.
What follows is the more elaborate, generated version of this text, and not my speech.

This release turns traversal results into durable artifacts, shows exactly where
disk usage moved, puts every interactive key under user control, and makes large
traversals substantially leaner.

dua interactive --export before.dua
# ... later ...
dua interactive --export after.dua
dua diff before.dua after.dua

Snapshots. Completed interactive traversals can now be exported atomically to
a deterministic, SHA-256-protected snapshot, with streaming zlib compression by
default. Load one with dua interactive --import for a read-only tour, or replay
it through dua aggregate --import as a flat list, a depth-limited tree, or
folded stacks, with the usual sorting and total controls. Snapshot imports retain
root order and traversal metadata; the aggregate renderers replay them with
bounded memory. The interactive view
still supports navigation, searching, sorting, marking, and opening stored paths
that continue to exist, while refresh, trash, and deletion stay safely disabled.
Its mark pane drops destructive prompts and colors for snapshots, or whenever
both destructive actions are unbound. The dua crate exposes the snapshot,
replay, and diff APIs for library users as well.

Diffing. dua diff OLD NEW streams additions, removals, and signed size
changes as a compact, colored context tree, then shows the largest additions and
removals. Use --directories-only, --prefix, --depth, --format, and
--summary-limit to shape the report. Both snapshots are checksum-verified in
parallel before their canonical entry streams are merged in bounded memory;
whole added or removed directories collapse into a single useful change.

Configurable keybindings. Every interactive action can now be rebound or
disabled, and dua config show-default documents all bindings. Pane hints follow
the configured keys, while --once understands the same named and modified
bindings as well as compact character sequences.

Lower memory use. Traversal state now uses a compact arena-backed tree,
shared filename storage, and dense directory IDs; snapshot replay borrows names
and reuses decoding buffers. In a local ~/dev scan, /usr/bin/time -lp measured
maximum RSS at 268,206,080 bytes versus 524,812,288 bytes for 2.43.1—a 49%
reduction.

More interactive polish. Shift+U can extend a completed scan into its parent,
the mark pane shows the selected percentage of the root, and Ctrl+Z now suspends
and cleanly resumes the TUI on Unix.

New Features

  • accept configured keys in --once

    Keyboard shortcuts are configurable, but --once could only synthesize plain
    character events. That made named and modified bindings impossible to reproduce
    in one-shot debugging runs.

    • Reuse the configuration keybinding parser for --once.
    • Convert parsed bindings into terminal events.
    • Preserve compact character sequences such as --once=jko.
  • add streaming snapshot diff command

    Command-line interface

    • Add dua diff OLD NEW to compare an earlier traversal snapshot with a later
      one.
    • Support byte-format selection either globally or after the subcommand, with
      the configured format as the fallback.
    • Add --directories-only for aggregate directory changes, --prefix PATH
      for a component-aware subtree filter, --depth DEPTH for limiting the
      displayed tree, and --summary-limit COUNT for sizing or hiding the largest
      additions and removals lists.
    • Treat the selected root or prefix as the first displayed depth level while
      leaving summary calculations unbounded.
    • Reject traversal-only options and input paths because diffing never walks
      the live filesystem.
    • Hash both decompressed snapshots in parallel before comparison, then validate
      their records as they stream and verify each digest again at the end.

    Streaming comparison

    • Refactor snapshot decoding into a resumable decoder and entry iterator that
      can replay a verified, seekable snapshot without materializing its tree.
    • Rewind each snapshot for every pass and verify its digest again at the end
      of replay, detecting files changed after initial validation.
    • Expose native encoded names and duplicate-sibling ordinals from decoded
      entries to build deterministic comparison keys on Unix and Windows.
    • Enforce canonical sibling ordering during decoding and distinguish repeated
      sibling names without changing the snapshot format.
    • Merge the two canonical depth-first streams in lock-step on the main thread
      while a background collector retains only bounded summary entries.
    • Pair roots in stored order and deliberately avoid cross-root matching or
      rename detection.
    • Collapse an entirely added or removed directory to one change and skip its
      descendants, keeping large subtree changes concise.

    Diff output

    • Report additions, removals, and signed size deltas with +, -, and ~
      markers in a compact tree with shared directory context.
    • Stream the tree first, then report a configurable number of the largest
      additions and removals (five by default) and the total number of changes.
    • Compare file sizes in the default mode and aggregate directory sizes in
      directory-only mode, including file-to-directory type changes.
    • Preserve full u128 size deltas and use the selected human-readable byte
      format.
    • Mark depth-collapsed branches with an ellipsis without hiding their entries
      from the largest-change summary.
    • Render terminal additions in green, removals in red, modifications in
      yellow, and directory context in cyan while keeping redirected output free
      of escape sequences.
    • Use native path separators, sanitize control characters that could split
      output lines, and emit no output for identical snapshots or unmatched
      prefixes.
  • add traversal snapshot codec

    Snapshot format

    • Add a deterministic version-1 DUASNAP\0 codec for depth-first traversal
      forests while preserving input-root order and native Unix and Windows path
      representations.
    • Encode parent distances, node flags, names, u128 sizes, nanosecond
      modification times, and optional entry counts using canonical ULEB128 fields.
    • Validate path components, tree structure, record limits, integer encodings,
      timestamps, node counts, checksums, truncation, and trailing data.
    • Protect decoded snapshot data with SHA-256 and preserve deterministic child
      ordering.
    • Support raw snapshots and streaming zlib compression through the existing
      gix::zlib dependency. Export at level 2 by default, accept levels 1–9, and
      use level 0 for raw output.
    • Verify seekable snapshots once and rewind them for bounded-memory replay
      without materializing the full tree.

    CLI integration

    • Add dua interactive --export to atomically persist a completed traversal
      through a neighboring temporary file before replacing the destination.
    • Add dua interactive --import to load a snapshot into the terminal UI
      without traversing the filesystem.
    • Add dua aggregate --import with flat, tree, depth-limited, sorted, total,
      and folded-stack output modes.
    • Reject traversal-only paths and options when importing and print snapshot
      provenance to standard error.
    • Preserve stored root ordering, sizes, entry counts, modification times, and
      metadata IO errors.

    Replay rendering

    • Add completed-traversal and replay renderers for aggregate, tree, and
      folded-stack output.
    • Keep only roots, displayed levels, or the current stack path in memory as
      required by each output mode.
    • Use checked arithmetic for aggregate and exclusive-size calculations and
      report malformed snapshot totals instead of silently saturating.
    • Handle the full u128 snapshot size range and sanitize control characters
      when writing terminal output.

    Interactive safety

    • Treat imported snapshots as read-only while retaining navigation, sorting,
      searching, marking, and display controls.
    • Disable entry existence checks, filesystem refreshes, upward scans,
      gitignore discovery, permanent deletion, and trash operations.
    • Show the actual snapshot load time until the first user event and replace
      destructive mark prompts and styling with an explicit read-only safety notice.
    • Allow opening a stored path when it still exists, without weakening the final
      read-only guards around trash and permanent deletion.
    • Expose completed traversal roots in original input order for deterministic
      export.
  • make interactive keybindings configurable

    Interactive shortcuts were hard-coded, preventing users from avoiding terminal
    conflicts or adapting the controls to their habits.

    Add per-action [keys] arrays whose defaults preserve the existing controls,
    route every interactive pane and visible shortcut hint through those settings,
    and expose all bindings as commented config show-default templates. Parse common
    named keys and modifiers while handling shifted character events consistently
    across terminal backends.

    Regression coverage verifies that overrides replace only their own defaults,
    the documented template round-trips to the built-in defaults, modified shortcuts
    remain distinct, and shifted punctuation works on Windows.

  • traverse beyond the interactive root

    Interactive mode stopped at its initial root and required a restart to inspect
    its parent.

    Handle Shift+U by scanning the parent while pruning already represented paths,
    then reattach the existing subtree at its natural position so node identities
    and prior work are preserved. The top-level message now advertises the shortcut
    when expansion is possible.

  • show marked percentage of total size

    Show the marked byte total as a percentage of the top-level root total in the
    mark pane title.

  • show gross changes for collapsed diff branches
    Not reviewed at all, only functional tests.

    Depth-limited snapshot diffs now reveal the churn hidden beneath each collapsed directory.

    • Accumulate gross additions and removals while preserving bounded streaming memory.
    • Keep directory-only output and largest-change summaries unchanged.
    • Cover mixed changes, overflow, root boundaries, context ordering, and terminal colors.

Performance

  • compact traversal storage and snapshot replay
    Admittedly, this one I waved through, but looked at the new storage for
    a more tightly packed tree closely.
    The parts with DirectoryId I just skipped over, as they are the most invasive
    overall and touch a log of places.
    Fine with me, everything seems to work, and this is beyond the time I can spend
    on reviewing, while the value proposition is too high to skip it.

    Traversal storage

    • Replace petgraph with a 64-byte arena-backed tree and compact stable indices.
    • Store native filenames in one append-only arena and reuse deleted node slots.
    • Route parents through dense directory IDs and keep glob matches outside the filesystem topology.

    Snapshot replay

    • Lend names from reusable record buffers and reuse sibling-order buffers by depth.
    • Copy names only for retained entries and sort snapshots directly from arena bytes.
    • Preserve the V1 encoding, validation, and platform-native path handling.

Bug Fixes

  • support Ctrl+Z in interactive mode

    Interactive mode consumes Ctrl+Z in raw mode, so the shell never receives the
    usual job-control signal and the TUI cannot be resumed cleanly.

    Recognize the key globally on Unix, release crossterm's focus, cursor, raw-mode,
    and alternate-screen state, raise SIGTSTP, then reclaim and clear the Ratatui
    terminal after fg resumes the process. A focused regression test covers the
    Ctrl+Z mapping.

    Validated with the repository check, unit, journey, format, and clippy targets;
    an Expect-driven PTY run also verified stop, fg redraw, and clean shell
    restoration.

Commit Statistics

  • 13 commits contributed to the release over the course of 1 calendar day.
  • 1 day passed between releases.
  • 9 commits were understood as conventional.
  • 4 unique issues were worked on: #113, #171, #65, #82

Commit Details

view details
  • #113
    • Show marked percentage of total size (5c6f4d3)
  • #171
    • Make interactive keybindings configurable (707b316)
  • #65
    • Support Ctrl+Z in interactive mode (1fbf73c)
  • #82
    • Traverse beyond the interactive root (2fef192)
  • Uncategorized
    • Show gross changes for collapsed diff branches (49f78a8)
    • Compact traversal storage and snapshot replay (9513699)
    • Accept configured keys in --once (2a9deb5)
    • Add streaming snapshot diff command (9314720)
    • Add traversal snapshot codec (3a30cc5)
    • Merge pull request #389 from Byron/configurable-keybindings (a54f427)
    • Merge pull request #388 from Byron/up-beyond-top-level (d1302c3)
    • Merge pull request #387 from Byron/ctrl-z (e136eca)
    • Merge pull request #386 from Byron/show-percentage (8ee226b)

Don't miss a new dua-cli release

NewReleases is sending notifications on new releases.