+154
-24
Diff
round #0
+5
-5
flake.lock
+5
-5
flake.lock
···
22
22
},
23
23
"nixpkgs": {
24
24
"locked": {
25
-
"lastModified": 1772542754,
26
-
"narHash": "sha256-WGV2hy+VIeQsYXpsLjdr4GvHv5eECMISX1zKLTedhdg=",
27
-
"rev": "8c809a146a140c5c8806f13399592dbcb1bb5dc4",
28
-
"revCount": 957538,
25
+
"lastModified": 1772624091,
26
+
"narHash": "sha256-QKyJ0QGWBn6r0invrMAK8dmJoBYWoOWy7lN+UHzW1jc=",
27
+
"rev": "80bdc1e5ce51f56b19791b52b2901187931f5353",
28
+
"revCount": 958232,
29
29
"type": "tarball",
30
-
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.957538%2Brev-8c809a146a140c5c8806f13399592dbcb1bb5dc4/019cb563-81c1-72cf-aec2-46679a968011/source.tar.gz"
30
+
"url": "https://api.flakehub.com/f/pinned/NixOS/nixpkgs/0.1.958232%2Brev-80bdc1e5ce51f56b19791b52b2901187931f5353/019cbcff-0413-7b59-87be-b2cea58a4043/source.tar.gz"
31
31
},
32
32
"original": {
33
33
"type": "tarball",
+120
src/components/mod.rs
+120
src/components/mod.rs
···
1
+
use crossterm::event::{KeyEvent, MouseEvent};
2
+
use ratatui::{
3
+
Frame,
4
+
layout::{Rect, Size},
5
+
};
6
+
use tokio::sync::mpsc::UnboundedSender;
7
+
8
+
use crate::{config::Config, signal::Signal, tui::Event};
9
+
10
+
/// `Component` is a trait that represents a visual and interactive element of the user interface.
11
+
///
12
+
/// Implementers of this trait can be registered with the main application loop and will be able to
13
+
/// receive events, update state, and be rendered on the screen.
14
+
#[expect(dead_code)]
15
+
pub trait Component {
16
+
/// Register a signal handler that can send signals for processing if necessary.
17
+
///
18
+
/// # Arguments
19
+
///
20
+
/// * `tx` - An unbounded sender that can send signals.
21
+
///
22
+
/// # Returns
23
+
///
24
+
/// * [`color_eyre::Result<()>`] - An Ok result or an error.
25
+
fn register_signal_handler(&mut self, tx: UnboundedSender<Signal>) -> color_eyre::Result<()> {
26
+
let _ = tx; // to appease clippy
27
+
Ok(())
28
+
}
29
+
/// Register a configuration handler that provides configuration settings if necessary.
30
+
///
31
+
/// # Arguments
32
+
///
33
+
/// * `config` - Configuration settings.
34
+
///
35
+
/// # Returns
36
+
///
37
+
/// * [`color_eyre::Result<()>`] - An Ok result or an error.
38
+
fn register_config_handler(&mut self, config: Config) -> color_eyre::Result<()> {
39
+
let _ = config; // to appease clippy
40
+
Ok(())
41
+
}
42
+
/// Initialize the component with a specified area if necessary.
43
+
///
44
+
/// # Arguments
45
+
///
46
+
/// * `area` - Rectangular area to initialize the component within.
47
+
///
48
+
/// # Returns
49
+
///
50
+
/// * [`color_eyre::Result<()>`] - An Ok result or an error.
51
+
fn init(&mut self, area: Size) -> color_eyre::Result<()> {
52
+
let _ = area; // to appease clippy
53
+
Ok(())
54
+
}
55
+
/// Handle incoming events and produce signals if necessary.
56
+
///
57
+
/// # Arguments
58
+
///
59
+
/// * `event` - An optional event to be processed.
60
+
///
61
+
/// # Returns
62
+
///
63
+
/// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
64
+
fn handle_events(&mut self, event: Option<Event>) -> color_eyre::Result<Option<Signal>> {
65
+
let signal = match event {
66
+
Some(Event::Key(key_event)) => self.handle_key_event(key_event)?,
67
+
Some(Event::Mouse(mouse_event)) => self.handle_mouse_event(mouse_event)?,
68
+
_ => None,
69
+
};
70
+
Ok(signal)
71
+
}
72
+
/// Handle key events and produce signals if necessary.
73
+
///
74
+
/// # Arguments
75
+
///
76
+
/// * `key` - A key event to be processed.
77
+
///
78
+
/// # Returns
79
+
///
80
+
/// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
81
+
fn handle_key_event(&mut self, key: KeyEvent) -> color_eyre::Result<Option<Signal>> {
82
+
let _ = key; // to appease clippy
83
+
Ok(None)
84
+
}
85
+
/// Handle mouse events and produce signals if necessary.
86
+
///
87
+
/// # Arguments
88
+
///
89
+
/// * `mouse` - A mouse event to be processed.
90
+
///
91
+
/// # Returns
92
+
///
93
+
/// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
94
+
fn handle_mouse_event(&mut self, mouse: MouseEvent) -> color_eyre::Result<Option<Signal>> {
95
+
let _ = mouse; // to appease clippy
96
+
Ok(None)
97
+
}
98
+
/// Update the state of the component based on a received signal. (REQUIRED)
99
+
///
100
+
/// # Arguments
101
+
///
102
+
/// * `signal` - A signal that may modify the state of the component.
103
+
///
104
+
/// # Returns
105
+
///
106
+
/// * [`color_eyre::Result<Option<signal>>`] - A signal to be processed or none.
107
+
fn update(&mut self, signal: Signal) -> color_eyre::Result<Option<Signal>>;
108
+
109
+
/// Render the component on the screen. (REQUIRED)
110
+
///
111
+
/// # Arguments
112
+
///
113
+
/// * `f` - A frame used for rendering.
114
+
/// * `area` - The area in which the component should be drawn.
115
+
///
116
+
/// # Returns
117
+
///
118
+
/// * [`color_eyre::Result<()>`] - An Ok result or an error.
119
+
fn draw(&mut self, frame: &mut Frame, area: Rect) -> color_eyre::Result<()>;
120
+
}
+19
-16
src/config.rs
+19
-16
src/config.rs
···
1
1
use directories::ProjectDirs;
2
2
use lazy_static::lazy_static;
3
3
use serde::Deserialize;
4
-
use std::{env, path::PathBuf};
4
+
use std::{env, path::PathBuf, sync::LazyLock};
5
5
6
-
lazy_static! {
7
-
/// Filaments
8
-
pub static ref PROJECT_NAME: String = env!("CARGO_CRATE_NAME").to_uppercase().to_string();
9
-
/// Data folder override if user has manually set FILAMENTS_DATA to a directory.
10
-
pub static ref DATA_FOLDER: Option<PathBuf> =
11
-
env::var(format!("{}_DATA", PROJECT_NAME.clone()))
12
-
.ok()
13
-
.map(PathBuf::from);
14
-
/// Config folder override if user has manually set FILAMENTS_CONFIG to a directory.
15
-
pub static ref CONFIG_FOLDER: Option<PathBuf> =
16
-
env::var(format!("{}_CONFIG", PROJECT_NAME.clone()))
17
-
.ok()
18
-
.map(PathBuf::from);
19
-
}
6
+
// #[expect(dead_code)]
7
+
static PROJECT_NAME: LazyLock<String> = LazyLock::new(|| env!("CARGO_CRATE_NAME").to_uppercase());
8
+
9
+
#[expect(dead_code)]
10
+
static DATA_FOLDER: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
11
+
env::var(format!("{}_DATA", PROJECT_NAME.clone()))
12
+
.ok()
13
+
.map(PathBuf::from)
14
+
});
15
+
#[expect(dead_code)]
16
+
static CONFIG_FOLDER: LazyLock<Option<PathBuf>> = LazyLock::new(|| {
17
+
env::var(format!("{}_CONFIG", PROJECT_NAME.clone()))
18
+
.ok()
19
+
.map(PathBuf::from)
20
+
});
20
21
21
22
/// The App Config and Data locations.
22
23
#[derive(Clone, Debug, Deserialize, Default)]
23
-
24
+
#[expect(dead_code)]
24
25
pub struct AppDirs {
25
26
#[serde(default)]
26
27
pub data_dir: PathBuf,
···
29
30
}
30
31
31
32
/// Configuration for the App
33
+
#[expect(dead_code)]
32
34
pub struct Config {
33
35
pub app_dirs: AppDirs, // pub data_dir: PathBuf,
34
36
// pub keybindings: KeyBindings,
···
36
38
// pub styles: Styles,
37
39
}
38
40
41
+
#[expect(dead_code)]
39
42
impl Config {
40
43
pub fn new() -> Self {
41
44
todo!()
+1
-1
src/errors.rs
+1
-1
src/errors.rs
···
3
3
/// Additionally the panic handler prints different information
4
4
/// based on debug / release builds.
5
5
pub fn init() -> color_eyre::Result<()> {
6
-
let (panic_hook, eyre_hook) = color_eyre::config::HookBuilder::default()
6
+
let (_, eyre_hook) = color_eyre::config::HookBuilder::default()
7
7
.panic_section(format!(
8
8
"This is a bug. Please report it at {}",
9
9
env!("CARGO_PKG_REPOSITORY")
+1
src/main.rs
+1
src/main.rs
+6
-2
src/tui.rs
+6
-2
src/tui.rs
···
13
13
},
14
14
terminal::{EnterAlternateScreen, LeaveAlternateScreen, enable_raw_mode},
15
15
};
16
+
use futures::{FutureExt as _, StreamExt as _};
16
17
use ratatui::{Terminal, prelude::CrosstermBackend};
17
18
use tokio::{
18
19
sync::mpsc::{self, UnboundedReceiver, UnboundedSender},
···
23
24
use tracing::error;
24
25
25
26
/// Events processed by the whole application.
27
+
#[expect(dead_code)]
26
28
pub enum Event {
27
29
/// Application initialized
28
30
Init,
···
74
76
pub paste_enabled: bool,
75
77
}
76
78
79
+
#[expect(dead_code)]
77
80
impl Tui {
78
81
/// Creates a new TUI.
79
82
pub fn new() -> Result<Self> {
···
150
153
.expect("Tui::event_loop: Failed to send init event.");
151
154
loop {
152
155
let event = tokio::select! {
153
-
_ = cancellation_token.cancelled() => {
156
+
() = cancellation_token.cancelled() => {
154
157
break;
155
158
}
156
159
_ = tick_interval.tick() => Event::Tick,
···
160
163
// we only care about press down events,
161
164
// not doing anything related to up / down keypresses
162
165
CrosstermEvent::Key(key) if key.kind == KeyEventKind::Press => Event::Key(key),
166
+
CrosstermEvent::Key(_) => continue,
167
+
163
168
CrosstermEvent::Mouse(mouse) => Event::Mouse(mouse),
164
169
CrosstermEvent::Resize(x, y) => Event::Resize(x, y),
165
170
CrosstermEvent::FocusLost => {Event::FocusLost },
166
171
CrosstermEvent::FocusGained => {Event::FocusGained },
167
172
CrosstermEvent::Paste(s)=> {Event::Paste(s)},
168
-
_ => continue,
169
173
170
174
}
171
175
Some(Err(_)) => Event::Error,
History
1 round
0 comments
suri.codes
submitted
#0
1 commit
expand
collapse
feat/tui: Component trait
1/2 failed, 1/2 success
expand
collapse
expand 0 comments
closed without merging