Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
54 changes: 32 additions & 22 deletions crates/plotnik-lib/src/engine/trace.rs
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ use std::num::NonZeroU16;
use arborium_tree_sitter::Node;

use crate::bytecode::{
format_effect, nav_symbol, trace, truncate_text, width_for_count, EffectOpcode,
cols, format_effect, nav_symbol, trace, truncate_text, width_for_count, EffectOpcode,
InstructionView, LineBuilder, MatchView, Module, Nav, Symbol,
};
use crate::Colors;
Expand Down Expand Up @@ -252,6 +252,25 @@ impl<'s> PrintTracer<'s> {
self.entrypoint_by_ip.get(&ip).map_or("?", |s| s.as_str())
}

/// Format kind with source text, dynamically truncated to fit content width.
/// Text is displayed dimmed and green, no quotes.
fn format_kind_with_text(&self, kind: &str, text: &str) -> String {
let c = &self.colors;

// Available content width = TOTAL_WIDTH - prefix_width + step_width
// prefix_width = INDENT + step_width + GAP + SYMBOL + GAP = 9 + step_width
// +step_width because ellipsis can extend into the successors column
// (sub-lines have no successors, so we use that space)
// This simplifies to: TOTAL_WIDTH - 9 = 35
let available = cols::TOTAL_WIDTH - 9;

// Text budget = available - kind.len() - 1 (space), minimum 12
let text_budget = available.saturating_sub(kind.len() + 1).max(12);

let truncated = truncate_text(text, text_budget);
format!("{} {}{}{}{}", kind, c.dim, c.green, truncated, c.reset)
}

/// Format a runtime effect for display.
fn format_effect(&self, effect: &RuntimeEffect<'_>) -> String {
use RuntimeEffect::*;
Expand Down Expand Up @@ -398,7 +417,6 @@ impl Tracer for PrintTracer<'_> {
return;
}

let c = &self.colors;
let kind = node.kind();
let symbol = match nav {
Nav::Down | Nav::DownSkip | Nav::DownExact => trace::NAV_DOWN,
Expand All @@ -407,45 +425,37 @@ impl Tracer for PrintTracer<'_> {
Nav::Stay | Nav::StayExact => Symbol::EMPTY,
};

// Text only in VeryVerbose (text is dim)
// Text only in VeryVerbose
if self.verbosity == Verbosity::VeryVerbose {
let text = truncate_text(node.utf8_text(self.source).unwrap_or("?"), 20);
self.add_subline(
symbol,
&format!("{} {}\"{}\"{}", kind, c.dim, text, c.reset),
);
let text = node.utf8_text(self.source).unwrap_or("?");
let content = self.format_kind_with_text(kind, text);
self.add_subline(symbol, &content);
} else {
self.add_subline(symbol, kind);
}
}

fn trace_match_success(&mut self, node: Node<'_>) {
let c = &self.colors;
let kind = node.kind();

// Text on match/failure in Verbose+ (text is dim)
// Text on match/failure in Verbose+
if self.verbosity != Verbosity::Default {
let text = truncate_text(node.utf8_text(self.source).unwrap_or("?"), 20);
self.add_subline(
trace::MATCH_SUCCESS,
&format!("{} {}\"{}\"{}", kind, c.dim, text, c.reset),
);
let text = node.utf8_text(self.source).unwrap_or("?");
let content = self.format_kind_with_text(kind, text);
self.add_subline(trace::MATCH_SUCCESS, &content);
} else {
self.add_subline(trace::MATCH_SUCCESS, kind);
}
}

fn trace_match_failure(&mut self, node: Node<'_>) {
let c = &self.colors;
let kind = node.kind();

// Text on match/failure in Verbose+ (text is dim)
// Text on match/failure in Verbose+
if self.verbosity != Verbosity::Default {
let text = truncate_text(node.utf8_text(self.source).unwrap_or("?"), 20);
self.add_subline(
trace::MATCH_FAILURE,
&format!("{} {}\"{}\"{}", kind, c.dim, text, c.reset),
);
let text = node.utf8_text(self.source).unwrap_or("?");
let content = self.format_kind_with_text(kind, text);
self.add_subline(trace::MATCH_FAILURE, &content);
} else {
self.add_subline(trace::MATCH_FAILURE, kind);
}
Expand Down
40 changes: 20 additions & 20 deletions docs/binary-format/08-trace-format.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ plotnik trace query.ptk source.js --fuel 10000
| `-v` | all | on match/failure | Developer |
| `-vv` | all | on all (incl. nav) | Deep debugging |

**Text budget**: Node text is truncated to 20 characters with `…` when displayed.
**Text budget**: Node text fills the line up to the successors column (minimum 12 characters). Truncated text ends with `…`.

---

Expand Down Expand Up @@ -156,11 +156,11 @@ Assignment:
Assignment:
08 ε 09
09 (assignment_expression) 10
● assignment_expression "x = y"
● assignment_expression x = y
10 ▽ left: (identifier) [Node Set(M6)] 12
▽ identifier
● left:
● identifier "x"
● identifier x
⬥ Node
⬥ Set "target"
12 ▷ right: (Expression) 13 ⯇
Expand All @@ -174,12 +174,12 @@ Expression:
22 ε [Enum(M3)] 20
⬥ Enum "Literal"
20 (number) [Node Set(M1)] 18
○ identifier "y"
○ identifier y
06 ❮❮❮
28 ε [Enum(M4)] 26
⬥ Enum "Variable"
26 (identifier) [Node Set(M2)] 24
● identifier "y"
● identifier y
⬥ Node
⬥ Set "name"
24 ε [EndEnum] 17
Expand Down Expand Up @@ -231,11 +231,11 @@ Assignment:
Assignment:
08 ε 09
09 (assignment_expression) 10
● assignment_expression "x = 1"
● assignment_expression x = 1
10 ▽ left: (identifier) [Node Set(M6)] 12
▽ identifier
● left:
● identifier "x"
● identifier x
⬥ Node
⬥ Set "target"
12 ▷ right: (Expression) 13 ⯇
Expand All @@ -249,7 +249,7 @@ Expression:
22 ε [Enum(M3)] 20
⬥ Enum "Literal"
20 (number) [Node Set(M1)] 18
● number "1"
● number 1
⬥ Node
⬥ Set "value"
18 ε [EndEnum] 17
Expand Down Expand Up @@ -288,12 +288,12 @@ Expression:
22 ε [Enum(M3)] 20
⬥ Enum "Literal"
20 (number) [Node Set(M1)] 18
○ string "hello"
○ string hello
06 ❮❮❮
28 ε [Enum(M4)] 26
⬥ Enum "Variable"
26 (identifier) [Node Set(M2)] 24
○ string "hello"
○ string hello
```

Both branches fail. No more checkpoints—query does not match. The CLI exits with code 1.
Expand All @@ -315,7 +315,7 @@ Both branches fail. No more checkpoints—query does not match. The CLI exits wi
Ident:
01 ε 02
02 (identifier) [Text Set(M0)] 04
● identifier "foo"
● identifier foo
⬥ Text
⬥ Set "name"
04 ▶
Expand Down Expand Up @@ -359,12 +359,12 @@ ReturnVal:
ReturnVal:
01 ε 02
02 (statement_block) 03
● statement_block "{ x; return 1; }"
● statement_block { x; return 1; }
03 ▽ (return_statement) [Node Set(M0)] 04
▽ expression_statement
○ expression_statement "x;"
○ expression_statement x;
▷ return_statement
● return_statement "return 1;"
● return_statement return 1;
⬥ Node
⬥ Set "ret"
04 △ 05
Expand All @@ -391,7 +391,7 @@ The `▽` lands on `(expression_statement)`, type mismatch, skip `▷` to next s
Assignment:
08 ε 09
09 (assignment_expression) 10
○ number "42"
○ number 42
```

Type check fails at root—no navigation occurs. The CLI exits with code 1.
Expand Down Expand Up @@ -429,11 +429,11 @@ Pair:
02 ε [Obj] 04
⬥ Obj
04 (pair) 05
● pair "\"x\": 1"
● pair "x": 1
05 ▽ key: (string) [SuppressBegin] 06
▽ string
● key:
● string "\"x\""
● string "x"
⬥ SuppressBegin
06 ε [SuppressEnd] 08
⬦ Node
Expand All @@ -442,7 +442,7 @@ Pair:
08 ▷ value: (number) [Node Set(M0)] 10
▷ number
● value:
● number "1"
● number 1
⬥ Node
⬥ Set "value"
10 △ 12
Expand Down Expand Up @@ -511,11 +511,11 @@ Hidden:
| ------- | ------------------- | ---------------------------- |
| (blank) | ` kind` | ` identifier` |
| ` ▽ ` | `▽ kind` | `▽ identifier` |
| ` ▽ ` | `▽ kind "text"` | `▽ identifier "foo"` |
| ` ▽ ` | `▽ kind text` | `▽ identifier foo` |
| ` ▷ ` | `▷ kind` | `▷ return_statement` |
| ` △ ` | `△ kind` | `△ assignment_expression` |
| ` ● ` | `● kind` | `● identifier` |
| ` ● ` | `● kind "text"` | `● identifier "foo"` |
| ` ● ` | `● kind text` | `● identifier foo` |
| ` ● ` | `● field:` | `● left:` |
| ` ○ ` | `○ kind` | `○ string` |
| ` ⬥ ` | `⬥ Effect` | `⬥ Node` |
Expand Down