1
- pub use app:: App ;
2
-
3
- pub mod app;
1
+ use color_eyre:: Result ;
2
+ use crossterm:: event:: { Event , EventStream , KeyCode , KeyEvent , KeyEventKind , KeyModifiers } ;
3
+ use futures:: { FutureExt , StreamExt } ;
4
+ use ratatui:: {
5
+ style:: Stylize ,
6
+ text:: Line ,
7
+ widgets:: { Block , Paragraph } ,
8
+ DefaultTerminal , Frame ,
9
+ } ;
4
10
5
11
#[ tokio:: main]
6
12
async fn main ( ) -> color_eyre:: Result < ( ) > {
@@ -10,3 +16,89 @@ async fn main() -> color_eyre::Result<()> {
10
16
ratatui:: restore ( ) ;
11
17
result
12
18
}
19
+
20
+ #[ derive( Debug , Default ) ]
21
+ pub struct App {
22
+ /// Is the application running?
23
+ running : bool ,
24
+ // Event stream.
25
+ event_stream : EventStream ,
26
+ }
27
+
28
+ impl App {
29
+ /// Construct a new instance of [`App`].
30
+ pub fn new ( ) -> Self {
31
+ Self :: default ( )
32
+ }
33
+
34
+ /// Run the application's main loop.
35
+ pub async fn run ( mut self , mut terminal : DefaultTerminal ) -> Result < ( ) > {
36
+ self . running = true ;
37
+ while self . running {
38
+ terminal. draw ( |frame| self . draw ( frame) ) ?;
39
+ self . handle_crossterm_events ( ) . await ?;
40
+ }
41
+ Ok ( ( ) )
42
+ }
43
+
44
+ /// Renders the user interface.
45
+ ///
46
+ /// This is where you add new widgets. See the following resources for more information:
47
+ /// - <https://docs.rs/ratatui/latest/ratatui/widgets/index.html>
48
+ /// - <https://github.com/ratatui/ratatui/tree/master/examples>
49
+ fn draw ( & mut self , frame : & mut Frame ) {
50
+ let title = Line :: from ( "Ratatui Simple Template" )
51
+ . bold ( )
52
+ . blue ( )
53
+ . centered ( ) ;
54
+ let text = "Hello, Ratatui!\n \n \
55
+ Created using https://github.com/ratatui/templates\n \
56
+ Press `Esc`, `Ctrl-C` or `q` to stop running.";
57
+ frame. render_widget (
58
+ Paragraph :: new ( text)
59
+ . block ( Block :: bordered ( ) . title ( title) )
60
+ . centered ( ) ,
61
+ frame. area ( ) ,
62
+ )
63
+ }
64
+
65
+ /// Reads the crossterm events and updates the state of [`App`].
66
+ async fn handle_crossterm_events ( & mut self ) -> Result < ( ) > {
67
+ tokio:: select! {
68
+ event = self . event_stream. next( ) . fuse( ) => {
69
+ match event {
70
+ Some ( Ok ( evt) ) => {
71
+ match evt {
72
+ Event :: Key ( key)
73
+ if key. kind == KeyEventKind :: Press
74
+ => self . on_key_event( key) ,
75
+ Event :: Mouse ( _) => { }
76
+ Event :: Resize ( _, _) => { }
77
+ _ => { }
78
+ }
79
+ }
80
+ _ => { }
81
+ }
82
+ }
83
+ _ = tokio:: time:: sleep( tokio:: time:: Duration :: from_millis( 100 ) ) => {
84
+ // Sleep for a short duration to avoid busy waiting.
85
+ }
86
+ }
87
+ Ok ( ( ) )
88
+ }
89
+
90
+ /// Handles the key events and updates the state of [`App`].
91
+ fn on_key_event ( & mut self , key : KeyEvent ) {
92
+ match ( key. modifiers , key. code ) {
93
+ ( _, KeyCode :: Esc | KeyCode :: Char ( 'q' ) )
94
+ | ( KeyModifiers :: CONTROL , KeyCode :: Char ( 'c' ) | KeyCode :: Char ( 'C' ) ) => self . quit ( ) ,
95
+ // Add other key handlers here.
96
+ _ => { }
97
+ }
98
+ }
99
+
100
+ /// Set running to false to quit the application.
101
+ fn quit ( & mut self ) {
102
+ self . running = false ;
103
+ }
104
+ }
0 commit comments