TuiState

Struct TuiState 

Source
pub struct TuiState {
Show 14 fields pub pending_hat: Option<(HatId, String)>, pub iteration: u32, pub prev_iteration: u32, pub loop_started: Option<Instant>, pub iteration_started: Option<Instant>, pub last_event: Option<String>, pub last_event_at: Option<Instant>, pub show_help: bool, pub loop_mode: LoopMode, pub in_scroll_mode: bool, pub search_query: String, pub search_forward: bool, pub max_iterations: Option<u32>, pub idle_timeout_remaining: Option<Duration>, /* private fields */
}
Expand description

Observable state derived from loop events.

Fields§

§pending_hat: Option<(HatId, String)>

Which hat will process next event (ID + display name).

§iteration: u32

Current iteration number (0-indexed, display as +1).

§prev_iteration: u32

Previous iteration number (for detecting changes).

§loop_started: Option<Instant>

When loop began.

§iteration_started: Option<Instant>

When current iteration began.

§last_event: Option<String>

Most recent event topic.

§last_event_at: Option<Instant>

Timestamp of last event.

§show_help: bool

Whether to show help overlay.

§loop_mode: LoopMode

Loop execution mode.

§in_scroll_mode: bool

Whether in scroll mode.

§search_query: String

Current search query (if in search input mode).

§search_forward: bool

Search direction (true = forward, false = backward).

§max_iterations: Option<u32>

Maximum iterations from config.

§idle_timeout_remaining: Option<Duration>

Idle timeout countdown.

Implementations§

Source§

impl TuiState

Source

pub fn new() -> Self

Creates empty state.

Examples found in repository?
examples/validate_widgets.rs (line 32)
27fn main() {
28    let output_dir = std::env::current_dir().unwrap().join("tui-validation");
29    fs::create_dir_all(&output_dir).unwrap();
30
31    // Create a fully populated state for validation
32    let mut state = TuiState::new();
33    let event = Event::new("task.start", "");
34    state.update(&event);
35
36    state.iteration = 2;
37    state.max_iterations = Some(10);
38    state.loop_started = Some(std::time::Instant::now().checked_sub(Duration::from_secs(272)).unwrap());
39    state.pending_hat = Some((HatId::new("builder"), "🔨Builder".to_string()));
40    state.loop_mode = ralph_tui::LoopMode::Auto;
41    state.last_event = Some("build.task".to_string());
42    state.last_event_at = Some(std::time::Instant::now()); // Active
43
44    // Render header
45    let backend = TestBackend::new(80, 3);
46    let mut terminal = Terminal::new(backend).unwrap();
47    terminal
48        .draw(|f| {
49            let widget = ralph_tui::header::render(&state);
50            f.render_widget(widget, f.area());
51        })
52        .unwrap();
53    let header_output = render_to_string(&terminal);
54    fs::write(output_dir.join("header.txt"), &header_output).unwrap();
55    println!("Header output written to tui-validation/header.txt");
56    println!("{}", header_output);
57    println!();
58
59    // Render header with scroll mode
60    state.in_scroll_mode = true;
61    let backend = TestBackend::new(80, 3);
62    let mut terminal = Terminal::new(backend).unwrap();
63    terminal
64        .draw(|f| {
65            let widget = ralph_tui::header::render(&state);
66            f.render_widget(widget, f.area());
67        })
68        .unwrap();
69    let header_scroll_output = render_to_string(&terminal);
70    fs::write(output_dir.join("header_scroll.txt"), &header_scroll_output).unwrap();
71    println!("Header (scroll mode) output written to tui-validation/header_scroll.txt");
72    println!("{}", header_scroll_output);
73    println!();
74    state.in_scroll_mode = false;
75
76    // Render header with paused mode
77    state.loop_mode = ralph_tui::LoopMode::Paused;
78    let backend = TestBackend::new(80, 3);
79    let mut terminal = Terminal::new(backend).unwrap();
80    terminal
81        .draw(|f| {
82            let widget = ralph_tui::header::render(&state);
83            f.render_widget(widget, f.area());
84        })
85        .unwrap();
86    let header_paused_output = render_to_string(&terminal);
87    fs::write(output_dir.join("header_paused.txt"), &header_paused_output).unwrap();
88    println!("Header (paused mode) output written to tui-validation/header_paused.txt");
89    println!("{}", header_paused_output);
90    println!();
91    state.loop_mode = ralph_tui::LoopMode::Auto;
92
93    // Render header with idle countdown
94    state.idle_timeout_remaining = Some(Duration::from_secs(25));
95    let backend = TestBackend::new(80, 3);
96    let mut terminal = Terminal::new(backend).unwrap();
97    terminal
98        .draw(|f| {
99            let widget = ralph_tui::header::render(&state);
100            f.render_widget(widget, f.area());
101        })
102        .unwrap();
103    let header_idle_output = render_to_string(&terminal);
104    fs::write(output_dir.join("header_idle.txt"), &header_idle_output).unwrap();
105    println!("Header (idle countdown) output written to tui-validation/header_idle.txt");
106    println!("{}", header_idle_output);
107    println!();
108    state.idle_timeout_remaining = None;
109
110    // Render footer (default)
111    let scroll_manager = ralph_tui::scroll::ScrollManager::new();
112    let backend = TestBackend::new(80, 3);
113    let mut terminal = Terminal::new(backend).unwrap();
114    terminal
115        .draw(|f| {
116            let widget = ralph_tui::footer::render(&state, &scroll_manager);
117            f.render_widget(widget, f.area());
118        })
119        .unwrap();
120    let footer_output = render_to_string(&terminal);
121    fs::write(output_dir.join("footer_active.txt"), &footer_output).unwrap();
122    println!("Footer (active) output written to tui-validation/footer_active.txt");
123    println!("{}", footer_output);
124    println!();
125
126    // Render footer (idle state)
127    state.last_event_at = Some(std::time::Instant::now().checked_sub(Duration::from_secs(10)).unwrap());
128    let backend = TestBackend::new(80, 3);
129    let mut terminal = Terminal::new(backend).unwrap();
130    terminal
131        .draw(|f| {
132            let widget = ralph_tui::footer::render(&state, &scroll_manager);
133            f.render_widget(widget, f.area());
134        })
135        .unwrap();
136    let footer_idle_output = render_to_string(&terminal);
137    fs::write(output_dir.join("footer_idle.txt"), &footer_idle_output).unwrap();
138    println!("Footer (idle) output written to tui-validation/footer_idle.txt");
139    println!("{}", footer_idle_output);
140    println!();
141
142    // Render footer (done state)
143    state.pending_hat = None;
144    let backend = TestBackend::new(80, 3);
145    let mut terminal = Terminal::new(backend).unwrap();
146    terminal
147        .draw(|f| {
148            let widget = ralph_tui::footer::render(&state, &scroll_manager);
149            f.render_widget(widget, f.area());
150        })
151        .unwrap();
152    let footer_done_output = render_to_string(&terminal);
153    fs::write(output_dir.join("footer_done.txt"), &footer_done_output).unwrap();
154    println!("Footer (done) output written to tui-validation/footer_done.txt");
155    println!("{}", footer_done_output);
156    println!();
157
158    // Render full layout simulation
159    state.pending_hat = Some((HatId::new("builder"), "🔨Builder".to_string()));
160    state.last_event_at = Some(std::time::Instant::now());
161    let backend = TestBackend::new(100, 24);
162    let mut terminal = Terminal::new(backend).unwrap();
163    terminal
164        .draw(|f| {
165            let chunks = Layout::default()
166                .direction(Direction::Vertical)
167                .constraints([
168                    Constraint::Length(3),
169                    Constraint::Min(0),
170                    Constraint::Length(3),
171                ])
172                .split(f.area());
173
174            f.render_widget(ralph_tui::header::render(&state), chunks[0]);
175            // Middle content area (just empty for this test)
176            f.render_widget(
177                ratatui::widgets::Block::default()
178                    .borders(ratatui::widgets::Borders::ALL)
179                    .title(" Terminal Output "),
180                chunks[1],
181            );
182            f.render_widget(ralph_tui::footer::render(&state, &scroll_manager), chunks[2]);
183        })
184        .unwrap();
185    let full_output = render_to_string(&terminal);
186    fs::write(output_dir.join("full_layout.txt"), &full_output).unwrap();
187    println!("Full layout output written to tui-validation/full_layout.txt");
188    println!("{}", full_output);
189
190    println!("\n=== All validation outputs written to tui-validation/ ===");
191}
Source

pub fn with_hat_map(hat_map: HashMap<String, (HatId, String)>) -> Self

Creates state with a custom hat map for dynamic topic-to-hat resolution.

Source

pub fn update(&mut self, event: &Event)

Updates state based on event topic.

Examples found in repository?
examples/validate_widgets.rs (line 34)
27fn main() {
28    let output_dir = std::env::current_dir().unwrap().join("tui-validation");
29    fs::create_dir_all(&output_dir).unwrap();
30
31    // Create a fully populated state for validation
32    let mut state = TuiState::new();
33    let event = Event::new("task.start", "");
34    state.update(&event);
35
36    state.iteration = 2;
37    state.max_iterations = Some(10);
38    state.loop_started = Some(std::time::Instant::now().checked_sub(Duration::from_secs(272)).unwrap());
39    state.pending_hat = Some((HatId::new("builder"), "🔨Builder".to_string()));
40    state.loop_mode = ralph_tui::LoopMode::Auto;
41    state.last_event = Some("build.task".to_string());
42    state.last_event_at = Some(std::time::Instant::now()); // Active
43
44    // Render header
45    let backend = TestBackend::new(80, 3);
46    let mut terminal = Terminal::new(backend).unwrap();
47    terminal
48        .draw(|f| {
49            let widget = ralph_tui::header::render(&state);
50            f.render_widget(widget, f.area());
51        })
52        .unwrap();
53    let header_output = render_to_string(&terminal);
54    fs::write(output_dir.join("header.txt"), &header_output).unwrap();
55    println!("Header output written to tui-validation/header.txt");
56    println!("{}", header_output);
57    println!();
58
59    // Render header with scroll mode
60    state.in_scroll_mode = true;
61    let backend = TestBackend::new(80, 3);
62    let mut terminal = Terminal::new(backend).unwrap();
63    terminal
64        .draw(|f| {
65            let widget = ralph_tui::header::render(&state);
66            f.render_widget(widget, f.area());
67        })
68        .unwrap();
69    let header_scroll_output = render_to_string(&terminal);
70    fs::write(output_dir.join("header_scroll.txt"), &header_scroll_output).unwrap();
71    println!("Header (scroll mode) output written to tui-validation/header_scroll.txt");
72    println!("{}", header_scroll_output);
73    println!();
74    state.in_scroll_mode = false;
75
76    // Render header with paused mode
77    state.loop_mode = ralph_tui::LoopMode::Paused;
78    let backend = TestBackend::new(80, 3);
79    let mut terminal = Terminal::new(backend).unwrap();
80    terminal
81        .draw(|f| {
82            let widget = ralph_tui::header::render(&state);
83            f.render_widget(widget, f.area());
84        })
85        .unwrap();
86    let header_paused_output = render_to_string(&terminal);
87    fs::write(output_dir.join("header_paused.txt"), &header_paused_output).unwrap();
88    println!("Header (paused mode) output written to tui-validation/header_paused.txt");
89    println!("{}", header_paused_output);
90    println!();
91    state.loop_mode = ralph_tui::LoopMode::Auto;
92
93    // Render header with idle countdown
94    state.idle_timeout_remaining = Some(Duration::from_secs(25));
95    let backend = TestBackend::new(80, 3);
96    let mut terminal = Terminal::new(backend).unwrap();
97    terminal
98        .draw(|f| {
99            let widget = ralph_tui::header::render(&state);
100            f.render_widget(widget, f.area());
101        })
102        .unwrap();
103    let header_idle_output = render_to_string(&terminal);
104    fs::write(output_dir.join("header_idle.txt"), &header_idle_output).unwrap();
105    println!("Header (idle countdown) output written to tui-validation/header_idle.txt");
106    println!("{}", header_idle_output);
107    println!();
108    state.idle_timeout_remaining = None;
109
110    // Render footer (default)
111    let scroll_manager = ralph_tui::scroll::ScrollManager::new();
112    let backend = TestBackend::new(80, 3);
113    let mut terminal = Terminal::new(backend).unwrap();
114    terminal
115        .draw(|f| {
116            let widget = ralph_tui::footer::render(&state, &scroll_manager);
117            f.render_widget(widget, f.area());
118        })
119        .unwrap();
120    let footer_output = render_to_string(&terminal);
121    fs::write(output_dir.join("footer_active.txt"), &footer_output).unwrap();
122    println!("Footer (active) output written to tui-validation/footer_active.txt");
123    println!("{}", footer_output);
124    println!();
125
126    // Render footer (idle state)
127    state.last_event_at = Some(std::time::Instant::now().checked_sub(Duration::from_secs(10)).unwrap());
128    let backend = TestBackend::new(80, 3);
129    let mut terminal = Terminal::new(backend).unwrap();
130    terminal
131        .draw(|f| {
132            let widget = ralph_tui::footer::render(&state, &scroll_manager);
133            f.render_widget(widget, f.area());
134        })
135        .unwrap();
136    let footer_idle_output = render_to_string(&terminal);
137    fs::write(output_dir.join("footer_idle.txt"), &footer_idle_output).unwrap();
138    println!("Footer (idle) output written to tui-validation/footer_idle.txt");
139    println!("{}", footer_idle_output);
140    println!();
141
142    // Render footer (done state)
143    state.pending_hat = None;
144    let backend = TestBackend::new(80, 3);
145    let mut terminal = Terminal::new(backend).unwrap();
146    terminal
147        .draw(|f| {
148            let widget = ralph_tui::footer::render(&state, &scroll_manager);
149            f.render_widget(widget, f.area());
150        })
151        .unwrap();
152    let footer_done_output = render_to_string(&terminal);
153    fs::write(output_dir.join("footer_done.txt"), &footer_done_output).unwrap();
154    println!("Footer (done) output written to tui-validation/footer_done.txt");
155    println!("{}", footer_done_output);
156    println!();
157
158    // Render full layout simulation
159    state.pending_hat = Some((HatId::new("builder"), "🔨Builder".to_string()));
160    state.last_event_at = Some(std::time::Instant::now());
161    let backend = TestBackend::new(100, 24);
162    let mut terminal = Terminal::new(backend).unwrap();
163    terminal
164        .draw(|f| {
165            let chunks = Layout::default()
166                .direction(Direction::Vertical)
167                .constraints([
168                    Constraint::Length(3),
169                    Constraint::Min(0),
170                    Constraint::Length(3),
171                ])
172                .split(f.area());
173
174            f.render_widget(ralph_tui::header::render(&state), chunks[0]);
175            // Middle content area (just empty for this test)
176            f.render_widget(
177                ratatui::widgets::Block::default()
178                    .borders(ratatui::widgets::Borders::ALL)
179                    .title(" Terminal Output "),
180                chunks[1],
181            );
182            f.render_widget(ralph_tui::footer::render(&state, &scroll_manager), chunks[2]);
183        })
184        .unwrap();
185    let full_output = render_to_string(&terminal);
186    fs::write(output_dir.join("full_layout.txt"), &full_output).unwrap();
187    println!("Full layout output written to tui-validation/full_layout.txt");
188    println!("{}", full_output);
189
190    println!("\n=== All validation outputs written to tui-validation/ ===");
191}
Source

pub fn get_pending_hat_display(&self) -> String

Returns formatted hat display (emoji + name).

Source

pub fn get_loop_elapsed(&self) -> Option<Duration>

Time since loop started.

Source

pub fn get_iteration_elapsed(&self) -> Option<Duration>

Time since iteration started.

Source

pub fn is_active(&self) -> bool

True if event received in last 2 seconds.

Source

pub fn iteration_changed(&self) -> bool

True if iteration changed since last check.

Trait Implementations§

Source§

impl Default for TuiState

Source§

fn default() -> Self

Returns the “default value” for a type. Read more

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> Downcast for T
where T: Any,

Source§

fn into_any(self: Box<T>) -> Box<dyn Any>

Convert Box<dyn Trait> (where Trait: Downcast) to Box<dyn Any>. Box<dyn Any> can then be further downcast into Box<ConcreteType> where ConcreteType implements Trait.
Source§

fn into_any_rc(self: Rc<T>) -> Rc<dyn Any>

Convert Rc<Trait> (where Trait: Downcast) to Rc<Any>. Rc<Any> can then be further downcast into Rc<ConcreteType> where ConcreteType implements Trait.
Source§

fn as_any(&self) -> &(dyn Any + 'static)

Convert &Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &Any’s vtable from &Trait’s.
Source§

fn as_any_mut(&mut self) -> &mut (dyn Any + 'static)

Convert &mut Trait (where Trait: Downcast) to &Any. This is needed since Rust cannot generate &mut Any’s vtable from &mut Trait’s.
Source§

impl<T> DowncastSync for T
where T: Any + Send + Sync,

Source§

fn into_any_arc(self: Arc<T>) -> Arc<dyn Any + Send + Sync>

Convert Arc<Trait> (where Trait: Downcast) to Arc<Any>. Arc<Any> can then be further downcast into Arc<ConcreteType> where ConcreteType implements Trait.
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more