fresh/app/types/theme.rs
1/// Lightweight per-cell theme key provenance recorded during rendering.
2/// Stored in `ChromeLayout::cell_theme_map` so the theme inspector popup
3/// can look up the exact keys used for any screen position.
4///
5/// Keys are `Cow<'static, str>` so the hot editor/chrome paths store cheap
6/// borrowed `&'static str` literals while plugin-driven surfaces (the
7/// orchestrator dock) can record the runtime key strings their text
8/// properties carry.
9#[derive(Debug, Clone, Default)]
10pub struct CellThemeInfo {
11 /// Foreground theme key (e.g. "syntax.keyword", "editor.fg")
12 pub fg_key: Option<std::borrow::Cow<'static, str>>,
13 /// Background theme key (e.g. "editor.bg", "diagnostic.warning_bg")
14 pub bg_key: Option<std::borrow::Cow<'static, str>>,
15 /// Short region label (e.g. "Line Numbers", "Editor Content")
16 pub region: std::borrow::Cow<'static, str>,
17 /// Dynamic region suffix (e.g. syntax category display name appended to "Syntax: ")
18 pub syntax_category: Option<std::borrow::Cow<'static, str>>,
19}
20
21/// One horizontal run of cells a chrome renderer painted with a known set of
22/// theme keys, captured *as it paints*. Renderers collect these into a fresh
23/// `Vec` (sidestepping any borrow of the per-cell map / the window) and the
24/// caller applies them via [`ChromeLayout::apply_theme_runs`] once its own
25/// borrows are released. Keys are `&'static str` (all chrome keys are literals).
26#[derive(Debug, Clone, Copy)]
27pub struct ThemeRun {
28 pub x: u16,
29 pub y: u16,
30 pub w: u16,
31 pub fg_key: Option<&'static str>,
32 pub bg_key: Option<&'static str>,
33 pub region: &'static str,
34}
35
36/// Write theme-key runs into a flat per-cell map of the given `width` (rows
37/// indexed `row * width + col`). Cells outside the frame are skipped. Used by
38/// both [`super::layout::ChromeLayout::apply_theme_runs`] and the split
39/// rendering pipeline, which holds the map directly.
40pub fn apply_theme_runs(map: &mut [CellThemeInfo], width: u16, runs: &[ThemeRun]) {
41 use std::borrow::Cow;
42 if width == 0 {
43 return;
44 }
45 let stride = width as usize;
46 for r in runs {
47 for col in r.x..r.x.saturating_add(r.w) {
48 if col >= width {
49 break;
50 }
51 let idx = r.y as usize * stride + col as usize;
52 if let Some(cell) = map.get_mut(idx) {
53 cell.fg_key = r.fg_key.map(Cow::Borrowed);
54 cell.bg_key = r.bg_key.map(Cow::Borrowed);
55 cell.region = Cow::Borrowed(r.region);
56 cell.syntax_category = None;
57 }
58 }
59 }
60}
61
62/// Collects [`ThemeRun`]s during a chrome region's paint. Threaded as
63/// `Option<&mut CellThemeRecorder>` so recording is opt-in (the inspector
64/// wants it; offscreen/test renders pass `None`).
65pub struct CellThemeRecorder<'a> {
66 runs: &'a mut Vec<ThemeRun>,
67}
68
69impl<'a> CellThemeRecorder<'a> {
70 pub fn new(runs: &'a mut Vec<ThemeRun>) -> Self {
71 Self { runs }
72 }
73
74 /// Record a horizontal run of `w` cells starting at screen `(x, y)`.
75 pub fn run(
76 &mut self,
77 x: u16,
78 y: u16,
79 w: u16,
80 fg_key: Option<&'static str>,
81 bg_key: Option<&'static str>,
82 region: &'static str,
83 ) {
84 if w == 0 {
85 return;
86 }
87 self.runs.push(ThemeRun {
88 x,
89 y,
90 w,
91 fg_key,
92 bg_key,
93 region,
94 });
95 }
96}
97
98/// Information about which theme key(s) style a specific screen position.
99/// Used by the Ctrl+Right-Click theme inspector popup.
100#[derive(Debug, Clone)]
101pub struct ThemeKeyInfo {
102 /// The foreground theme key path (e.g., "syntax.keyword", "editor.fg")
103 pub fg_key: Option<String>,
104 /// The background theme key path (e.g., "editor.bg", "editor.selection_bg")
105 pub bg_key: Option<String>,
106 /// Human-readable description of the UI region
107 pub region: String,
108 /// The actual foreground color value currently applied
109 pub fg_color: Option<ratatui::style::Color>,
110 /// The actual background color value currently applied
111 pub bg_color: Option<ratatui::style::Color>,
112 /// For syntax highlights: the HighlightCategory display name
113 pub syntax_category: Option<String>,
114}
115
116/// State for the theme inspector popup (Ctrl+Right-Click)
117#[derive(Debug, Clone)]
118pub struct ThemeInfoPopup {
119 /// Screen position where popup appears (x, y)
120 pub position: (u16, u16),
121 /// Resolved theme key information
122 pub info: ThemeKeyInfo,
123 /// Whether the "Open in Theme Editor" button is highlighted (mouse hover)
124 pub button_highlighted: bool,
125}