···11+use crossterm::event::{KeyEvent, MouseEvent};
22+use ratatui::{
33+ Frame,
44+ layout::{Rect, Size},
55+};
66+use tokio::sync::mpsc::UnboundedSender;
77+88+use crate::{config::Config, signal::Signal, tui::Event};
99+1010+/// `Component` is a trait that represents a visual and interactive element of the user interface.
1111+///
1212+/// Implementers of this trait can be registered with the main application loop and will be able to
1313+/// receive events, update state, and be rendered on the screen.
1414+#[expect(dead_code)]
1515+pub trait Component {
1616+ /// Register a signal handler that can send signals for processing if necessary.
1717+ ///
1818+ /// # Arguments
1919+ ///
2020+ /// * `tx` - An unbounded sender that can send signals.
2121+ ///
2222+ /// # Returns
2323+ ///
2424+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
2525+ fn register_signal_handler(&mut self, tx: UnboundedSender<Signal>) -> color_eyre::Result<()> {
2626+ let _ = tx; // to appease clippy
2727+ Ok(())
2828+ }
2929+ /// Register a configuration handler that provides configuration settings if necessary.
3030+ ///
3131+ /// # Arguments
3232+ ///
3333+ /// * `config` - Configuration settings.
3434+ ///
3535+ /// # Returns
3636+ ///
3737+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
3838+ fn register_config_handler(&mut self, config: Config) -> color_eyre::Result<()> {
3939+ let _ = config; // to appease clippy
4040+ Ok(())
4141+ }
4242+ /// Initialize the component with a specified area if necessary.
4343+ ///
4444+ /// # Arguments
4545+ ///
4646+ /// * `area` - Rectangular area to initialize the component within.
4747+ ///
4848+ /// # Returns
4949+ ///
5050+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
5151+ fn init(&mut self, area: Size) -> color_eyre::Result<()> {
5252+ let _ = area; // to appease clippy
5353+ Ok(())
5454+ }
5555+ /// Handle incoming events and produce signals if necessary.
5656+ ///
5757+ /// # Arguments
5858+ ///
5959+ /// * `event` - An optional event to be processed.
6060+ ///
6161+ /// # Returns
6262+ ///
6363+ /// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
6464+ fn handle_events(&mut self, event: Option<Event>) -> color_eyre::Result<Option<Signal>> {
6565+ let signal = match event {
6666+ Some(Event::Key(key_event)) => self.handle_key_event(key_event)?,
6767+ Some(Event::Mouse(mouse_event)) => self.handle_mouse_event(mouse_event)?,
6868+ _ => None,
6969+ };
7070+ Ok(signal)
7171+ }
7272+ /// Handle key events and produce signals if necessary.
7373+ ///
7474+ /// # Arguments
7575+ ///
7676+ /// * `key` - A key event to be processed.
7777+ ///
7878+ /// # Returns
7979+ ///
8080+ /// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
8181+ fn handle_key_event(&mut self, key: KeyEvent) -> color_eyre::Result<Option<Signal>> {
8282+ let _ = key; // to appease clippy
8383+ Ok(None)
8484+ }
8585+ /// Handle mouse events and produce signals if necessary.
8686+ ///
8787+ /// # Arguments
8888+ ///
8989+ /// * `mouse` - A mouse event to be processed.
9090+ ///
9191+ /// # Returns
9292+ ///
9393+ /// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
9494+ fn handle_mouse_event(&mut self, mouse: MouseEvent) -> color_eyre::Result<Option<Signal>> {
9595+ let _ = mouse; // to appease clippy
9696+ Ok(None)
9797+ }
9898+ /// Update the state of the component based on a received signal. (REQUIRED)
9999+ ///
100100+ /// # Arguments
101101+ ///
102102+ /// * `signal` - A signal that may modify the state of the component.
103103+ ///
104104+ /// # Returns
105105+ ///
106106+ /// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
107107+ fn update(&mut self, signal: Signal) -> color_eyre::Result<Option<Signal>>;
108108+109109+ /// Render the component on the screen. (REQUIRED)
110110+ ///
111111+ /// # Arguments
112112+ ///
113113+ /// * `f` - A frame used for rendering.
114114+ /// * `area` - The area in which the component should be drawn.
115115+ ///
116116+ /// # Returns
117117+ ///
118118+ /// * [`color_eyre::Result<()>`] - An Ok result or an error.
119119+ fn draw(&mut self, frame: &mut Frame, area: Rect) -> color_eyre::Result<()>;
120120+}
···33/// Additionally the panic handler prints different information
44/// based on debug / release builds.
55pub fn init() -> color_eyre::Result<()> {
66- let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default()
66+ let (_, eyre_hook) = color_eyre::config::HookBuilder::default()
77 .panic_section(format!(
88 "This is a bug. Please report it at {}",
99 env!("CARGO_PKG_REPOSITORY")
+1
src/main.rs
···22//! My (suri.codes) personal-knowledge-system, with deeply integrated task tracking and long term goal planning capabilities.
33//!
4455+mod components;
56mod config;
67mod errors;
78mod signal;
+6-2
src/tui.rs
···1313 },
1414 terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode},
1515};
1616+use futures::{FutureExt as _, StreamExt as _};
1617use ratatui::{Terminal, prelude::CrosstermBackend};
1718use tokio::{
1819 sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
···2324use tracing::error;
24252526/// Events processed by the whole application.
2727+#[expect(dead_code)]
2628pub enum Event {
2729 /// Application initialized
2830 Init,
···7476 pub paste_enabled: bool,
7577}
76787979+#[expect(dead_code)]
7780impl Tui {
7881 /// Creates a new TUI.
7982 pub fn new() -> Result<Self> {
···150153 .expect("Tui::event_loop: Failed to send init event.");
151154 loop {
152155 let event = tokio::select! {
153153- _ = cancellation_token.cancelled() => {
156156+ () = cancellation_token.cancelled() => {
154157 break;
155158 }
156159 _ = tick_interval.tick() => Event::Tick,
···160163 // we only care about press down events,
161164 // not doing anything related to up / down keypresses
162165 CrosstermEvent::Key(key) if key.kind == KeyEventKind::Press => Event::Key(key),
166166+ CrosstermEvent::Key(_) => continue,
167167+163168 CrosstermEvent::Mouse(mouse) => Event::Mouse(mouse),
164169 CrosstermEvent::Resize(x, y) => Event::Resize(x, y),
165170 CrosstermEvent::FocusLost => {Event::FocusLost },
166171 CrosstermEvent::FocusGained => {Event::FocusGained },
167172 CrosstermEvent::Paste(s)=> {Event::Paste(s)},
168168- _ => continue,
169173170174 }
171175 Some(Err(_)) => Event::Error,