1
+ use crossterm:: event:: {
2
+ poll, KeyboardEnhancementFlags , PopKeyboardEnhancementFlags , PushKeyboardEnhancementFlags ,
3
+ } ;
4
+
1
5
use crossterm:: {
6
+ cursor,
2
7
event:: { self , Event , KeyCode , KeyEvent } ,
8
+ execute, queue,
3
9
style:: { Color , Print , SetForegroundColor , Stylize } ,
10
+ terminal:: { disable_raw_mode, enable_raw_mode} ,
4
11
ExecutableCommand ,
5
12
} ;
6
- use std:: io:: { self , stdout, Write } ;
13
+ use std:: io:: { self , stdout, Stdout , Write } ;
7
14
8
15
use crate :: connect:: AgentPool ;
9
16
10
17
const RESERVED_WORDS : [ & str ; 3 ] = [ "ping" , "infoserver" , "createpredindex" ] ;
11
18
19
+ #[ derive( Debug ) ]
20
+ enum SpecialEntry {
21
+ Enter ,
22
+ Up ,
23
+ Down ,
24
+ Break ,
25
+ Left ,
26
+ Right ,
27
+ }
28
+
29
+ #[ derive( Debug ) ]
30
+ enum Entry {
31
+ Char ( char ) ,
32
+ Special ( SpecialEntry ) ,
33
+ Other ( KeyCode ) ,
34
+ None ,
35
+ }
36
+
12
37
pub struct Term {
13
38
client_pool : AgentPool ,
14
39
}
@@ -18,23 +43,20 @@ impl Term {
18
43
Self { client_pool }
19
44
}
20
45
21
- pub ( crate ) fn read_line ( & self ) -> io:: Result < String > {
22
- let mut line = String :: new ( ) ;
23
- while let Event :: Key ( KeyEvent { code, .. } ) = event:: read ( ) ? {
24
- match code {
25
- KeyCode :: Enter => {
26
- break ;
27
- }
28
- KeyCode :: Char ( c) => {
29
- line. push ( c) ;
30
- }
31
- KeyCode :: Esc => {
32
- break ;
33
- }
34
- _ => { }
35
- }
46
+ pub ( crate ) fn read_char ( & self ) -> io:: Result < Entry > {
47
+ if let Event :: Key ( KeyEvent { code, .. } ) = event:: read ( ) ? {
48
+ Ok ( match code {
49
+ KeyCode :: Enter => Entry :: Special ( SpecialEntry :: Enter ) ,
50
+ KeyCode :: Char ( c) => Entry :: Char ( c) ,
51
+ KeyCode :: Left => Entry :: Special ( SpecialEntry :: Left ) ,
52
+ KeyCode :: Up => Entry :: Special ( SpecialEntry :: Up ) ,
53
+ KeyCode :: Down => Entry :: Special ( SpecialEntry :: Down ) ,
54
+ KeyCode :: Right => Entry :: Special ( SpecialEntry :: Right ) ,
55
+ _ => Entry :: Other ( code) ,
56
+ } )
57
+ } else {
58
+ Ok ( Entry :: None )
36
59
}
37
- Ok ( line)
38
60
}
39
61
pub fn welcome_message ( & self ) -> io:: Result < ( ) > {
40
62
let mut stdout = stdout ( ) ;
@@ -48,50 +70,109 @@ impl Term {
48
70
Ok ( ( ) )
49
71
}
50
72
51
- pub ( crate ) fn ahnlich_prompt ( & self ) -> io:: Result < ( ) > {
52
- let mut stdout = stdout ( ) ;
73
+ pub ( crate ) fn ahnlich_prompt ( & self , stdout : & mut Stdout ) -> io:: Result < ( ) > {
53
74
stdout. execute ( SetForegroundColor ( Color :: White ) ) ?;
54
75
stdout. execute ( Print ( ">>> " ) ) ?;
55
76
stdout. execute ( SetForegroundColor ( Color :: White ) ) ?;
77
+
56
78
stdout. flush ( ) ?;
57
- //stdout.flush()?;
58
79
Ok ( ( ) )
59
80
}
60
81
61
- pub ( crate ) fn print_query ( & self , query : & str ) -> io:: Result < ( ) > {
62
- self . ahnlich_prompt ( ) ?;
63
- let output = String :: from_iter ( query. split ( ' ' ) . map ( |ex| {
64
- if RESERVED_WORDS . contains ( & ( ex. to_lowercase ( ) . as_str ( ) ) ) {
65
- format ! ( "{} " , ex. magenta( ) )
66
- } else {
67
- format ! ( "{} " , ex. white( ) )
68
- }
69
- } ) ) ;
82
+ // pub(crate) fn print_query(&self, query: &str) -> io::Result<()> {
83
+ // self.ahnlich_prompt()?;
84
+ // let output = String::from_iter(query.split(' ').map(|ex| {
85
+ // if RESERVED_WORDS.contains(&(ex.to_lowercase().as_str())) {
86
+ // format!("{} ", ex.magenta())
87
+ // } else {
88
+ // format!("{} ", ex.white())
89
+ // }
90
+ // }));
70
91
71
- println ! ( "{output}" ) ;
92
+ // println!("{output}");
72
93
73
- Ok ( ( ) )
94
+ // Ok(())
95
+ // }
96
+
97
+ fn read_line ( & self , stdout : & mut Stdout ) -> io:: Result < String > {
98
+ let ( start_pos_col, _) = cursor:: position ( ) ?;
99
+ let mut output = String :: new ( ) ;
100
+
101
+ loop {
102
+ let char = self . read_char ( ) ?;
103
+ let ( current_pos_col, _) = cursor:: position ( ) ?;
104
+ match char {
105
+ Entry :: Char ( c) => {
106
+ output. push ( c) ;
107
+ stdout. execute ( Print ( c) ) ?;
108
+ stdout. flush ( ) ?;
109
+ }
110
+ Entry :: Special ( special) => match special {
111
+ SpecialEntry :: Up | SpecialEntry :: Down => {
112
+ continue ;
113
+ }
114
+ SpecialEntry :: Enter | SpecialEntry :: Break => {
115
+ queue ! ( stdout, Print ( "\n " ) , cursor:: MoveToColumn ( 0 ) ) ?;
116
+ stdout. flush ( ) ?;
117
+ break ;
118
+ }
119
+ SpecialEntry :: Left => {
120
+ if start_pos_col < current_pos_col {
121
+ stdout. execute ( cursor:: MoveLeft ( 1 ) ) ?;
122
+ }
123
+ }
124
+ SpecialEntry :: Right => {
125
+ if start_pos_col + output. len ( ) as u16 > current_pos_col {
126
+ stdout. execute ( cursor:: MoveRight ( 1 ) ) ?;
127
+ }
128
+ }
129
+ } ,
130
+ Entry :: Other ( _) | Entry :: None => {
131
+ continue ;
132
+ }
133
+ }
134
+ }
135
+ Ok ( output)
74
136
}
75
137
76
138
pub async fn run ( & self ) -> io:: Result < ( ) > {
139
+ enable_raw_mode ( ) ?;
140
+ let mut stdout = stdout ( ) ;
141
+ stdout. execute ( cursor:: EnableBlinking ) ?;
142
+ stdout. execute ( cursor:: SetCursorStyle :: BlinkingBar ) ?;
143
+
77
144
loop {
78
- self . ahnlich_prompt ( ) ?;
79
- let input = self . read_line ( ) ?;
145
+ self . ahnlich_prompt ( & mut stdout ) ?;
146
+ let input = self . read_line ( & mut stdout ) ?;
80
147
match input. as_str ( ) {
81
148
"quit" | "exit()" => break ,
82
149
command => {
83
- self . print_query ( command) ?;
84
150
let response = self . client_pool . parse_queries ( command) . await ;
85
151
86
152
match response {
87
153
Ok ( success) => {
88
- println ! ( "{}" , success. join( "\n \n " ) )
154
+ for msg in success {
155
+ queue ! (
156
+ stdout,
157
+ Print ( format!( "{}\n " , msg) ) ,
158
+ cursor:: MoveToColumn ( 0 )
159
+ ) ?;
160
+ }
161
+ stdout. flush ( ) ?;
162
+ }
163
+ Err ( err) => {
164
+ queue ! (
165
+ stdout,
166
+ Print ( format!( "{}\n " , err. red( ) ) ) ,
167
+ cursor:: MoveToColumn ( 0 )
168
+ ) ?;
169
+ stdout. flush ( ) ?;
89
170
}
90
- Err ( err) => println ! ( "{}" , err. red( ) ) ,
91
171
}
92
172
}
93
173
} ;
94
174
}
175
+ disable_raw_mode ( ) ?;
95
176
Ok ( ( ) )
96
177
}
97
178
}
0 commit comments