You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

2.9 KiB

+++ title = "ASCII graph rendering in display.rs" priority = 5 status = "done" ticket_type = "feature" dependencies = ["9c9ebe"] +++ Add format_graph and print_graph to src/display.rs to render a ticket dependency DAG as an ASCII tree.

Motivation

The nbd graph command needs to convert the TicketGraph data structure (from src/graph.rs) into a human-readable ASCII representation. Rendering belongs in display.rs next to format_list and format_ticket.

Output format

The graph is a forest of trees. Each root ticket (no in-graph dependencies) starts at column 0. Its dependents (tickets that depend on it) are indented below it using box-drawing characters.

a3f9c2  [todo]        Fix login bug
├── b7d41e  [todo]    Add rate limiting
│   └── c9e823  [in_progress]  Write tests
└── d1f302  [done]    Update docs
e4a781  [todo]        New feature (no deps)

Node format per line:

{prefix}{id}  [{status}]  {title}

Where {prefix} is built from indentation characters (, ├── , └── ).

Blocked indicator (optional): Consider marking tickets that have unresolved (non-done/closed) dependencies with a [blocked] tag or ! prefix so the graph visually distinguishes ready from blocked tickets.

Signatures

/// Render the full dependency forest as an ASCII tree string.
pub fn format_graph(graph: &TicketGraph) -> String

/// Print the full dependency forest.
pub fn print_graph(graph: &TicketGraph)

/// Render the subtree rooted at `root_id` as an ASCII tree string.
pub fn format_subtree(graph: &TicketGraph, root_id: &str) -> String

/// Print the subtree rooted at `root_id`.
pub fn print_subtree(graph: &TicketGraph, root_id: &str)

Implementation notes

  • Use a recursive helper that tracks a prefix: String carrying the accumulated indentation characters.
  • For each node's children (its dependents in the graph), iterate:
    • If not the last child: prefix extension is ; connector is ├── .
    • If the last child: prefix extension is ; connector is └── .
  • Cycle guard: track a visited: HashSet<&str> across the recursion; if a node ID is already visited, render {prefix}{connector}{id} [cycle] and stop descending.
  • Status is shown as the serde string: todo, in_progress, done, closed.

Files touched

  • src/display.rsformat_graph, print_graph, format_subtree, print_subtree

Tests (unit, in src/tests.rs)

  • format_graph on a single ticket with no deps produces a single line.
  • format_graph on a two-ticket chain shows the child indented with └──.
  • format_graph with a branching parent shows ├── for all but the last child and └── for the last.
  • format_subtree only shows the specified root's subtree.
  • A cycle in the graph does not cause infinite recursion; the repeated node is labelled [cycle].