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.
74 lines
2.9 KiB
Markdown
74 lines
2.9 KiB
Markdown
---
|
|
# nbd-17dp
|
|
title: ASCII graph rendering in display.rs
|
|
status: completed
|
|
type: feature
|
|
priority: normal
|
|
created_at: 2026-03-10T23:30:31Z
|
|
updated_at: 2026-03-10T23:30:32Z
|
|
blocked_by:
|
|
- nbd-csdh
|
|
---
|
|
|
|
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
|
|
|
|
```rust
|
|
/// 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.rs` — `format_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]`.
|