@@ -86,6 +86,13 @@ impl TextInputComponent {
86
86
Some ( index)
87
87
}
88
88
89
+ fn backspace ( & mut self ) {
90
+ if self . cursor_position > 0 {
91
+ self . decr_cursor ( ) ;
92
+ self . msg . remove ( self . cursor_position ) ;
93
+ }
94
+ }
95
+
89
96
/// Set the `msg`.
90
97
pub fn set_text ( & mut self , msg : String ) {
91
98
self . msg = msg;
@@ -96,6 +103,54 @@ impl TextInputComponent {
96
103
pub fn set_title ( & mut self , t : String ) {
97
104
self . title = t;
98
105
}
106
+
107
+ fn get_draw_text ( & self ) -> Vec < Text > {
108
+ let style = self . theme . text ( true , false ) ;
109
+
110
+ let mut txt = Vec :: new ( ) ;
111
+
112
+ // the portion of the text before the cursor is added
113
+ // if the cursor is not at the first character
114
+ if self . cursor_position > 0 {
115
+ txt. push ( Text :: styled (
116
+ & self . msg [ ..self . cursor_position ] ,
117
+ style,
118
+ ) ) ;
119
+ }
120
+
121
+ let cursor_str = if let Some ( pos) = self . next_char_position ( )
122
+ {
123
+ & self . msg [ self . cursor_position ..pos]
124
+ } else {
125
+ // if the cursor is at the end of the msg
126
+ // a whitespace is used to underline
127
+ " "
128
+ } ;
129
+
130
+ if cursor_str == "\n " {
131
+ txt. push ( Text :: styled (
132
+ "\u{21b5} " ,
133
+ self . theme
134
+ . text ( false , false )
135
+ . modifier ( Modifier :: UNDERLINED ) ,
136
+ ) ) ;
137
+ }
138
+
139
+ txt. push ( Text :: styled (
140
+ cursor_str,
141
+ style. modifier ( Modifier :: UNDERLINED ) ,
142
+ ) ) ;
143
+
144
+ // the final portion of the text is added if there is
145
+ // still remaining characters
146
+ if let Some ( pos) = self . next_char_position ( ) {
147
+ if pos < self . msg . len ( ) {
148
+ txt. push ( Text :: styled ( & self . msg [ pos..] , style) ) ;
149
+ }
150
+ }
151
+
152
+ txt
153
+ }
99
154
}
100
155
101
156
impl DrawableComponent for TextInputComponent {
@@ -105,46 +160,13 @@ impl DrawableComponent for TextInputComponent {
105
160
_rect : Rect ,
106
161
) -> Result < ( ) > {
107
162
if self . visible {
108
- let mut txt: Vec < tui:: widgets:: Text > = Vec :: new ( ) ;
109
-
110
- if self . msg . is_empty ( ) {
111
- txt. push ( Text :: styled (
163
+ let txt = if self . msg . is_empty ( ) {
164
+ vec ! [ Text :: styled(
112
165
self . default_msg. as_str( ) ,
113
166
self . theme. text( false , false ) ,
114
- ) ) ;
167
+ ) ]
115
168
} else {
116
- let style = self . theme . text ( true , false ) ;
117
-
118
- // the portion of the text before the cursor is added
119
- // if the cursor is not at the first character
120
- if self . cursor_position > 0 {
121
- txt. push ( Text :: styled (
122
- & self . msg [ ..self . cursor_position ] ,
123
- style,
124
- ) ) ;
125
- }
126
-
127
- txt. push ( Text :: styled (
128
- if let Some ( pos) = self . next_char_position ( ) {
129
- & self . msg [ self . cursor_position ..pos]
130
- } else {
131
- // if the cursor is at the end of the msg
132
- // a whitespace is used to underline
133
- " "
134
- } ,
135
- style. modifier ( Modifier :: UNDERLINED ) ,
136
- ) ) ;
137
-
138
- // the final portion of the text is added if there is
139
- // still remaining characters
140
- if let Some ( pos) = self . next_char_position ( ) {
141
- if pos < self . msg . len ( ) {
142
- txt. push ( Text :: styled (
143
- & self . msg [ pos..] ,
144
- style,
145
- ) ) ;
146
- }
147
- }
169
+ self . get_draw_text ( )
148
170
} ;
149
171
150
172
let area = ui:: centered_rect ( 60 , 20 , f. size ( ) ) ;
@@ -203,12 +225,7 @@ impl Component for TextInputComponent {
203
225
return Ok ( true ) ;
204
226
}
205
227
KeyCode :: Backspace => {
206
- if self . cursor_position > 0 {
207
- self . decr_cursor ( ) ;
208
- if self . cursor_position < self . msg . len ( ) {
209
- }
210
- self . msg . remove ( self . cursor_position ) ;
211
- }
228
+ self . backspace ( ) ;
212
229
return Ok ( true ) ;
213
230
}
214
231
KeyCode :: Left => {
@@ -248,3 +265,50 @@ impl Component for TextInputComponent {
248
265
Ok ( ( ) )
249
266
}
250
267
}
268
+
269
+ #[ cfg( test) ]
270
+ mod tests {
271
+ use super :: * ;
272
+
273
+ #[ test]
274
+ fn test_smoke ( ) {
275
+ let mut comp =
276
+ TextInputComponent :: new ( SharedTheme :: default ( ) , "" , "" ) ;
277
+
278
+ comp. set_text ( String :: from ( "a\n b" ) ) ;
279
+
280
+ assert_eq ! ( comp. cursor_position, 0 ) ;
281
+
282
+ comp. incr_cursor ( ) ;
283
+ assert_eq ! ( comp. cursor_position, 1 ) ;
284
+
285
+ comp. decr_cursor ( ) ;
286
+ assert_eq ! ( comp. cursor_position, 0 ) ;
287
+ }
288
+
289
+ fn get_text < ' a > ( t : & ' a Text ) -> Option < & ' a str > {
290
+ if let Text :: Styled ( c, _) = t {
291
+ Some ( c. as_ref ( ) )
292
+ } else {
293
+ None
294
+ }
295
+ }
296
+
297
+ #[ test]
298
+ fn test_visualize_newline ( ) {
299
+ let mut comp =
300
+ TextInputComponent :: new ( SharedTheme :: default ( ) , "" , "" ) ;
301
+
302
+ comp. set_text ( String :: from ( "a\n b" ) ) ;
303
+
304
+ comp. incr_cursor ( ) ;
305
+
306
+ let txt = comp. get_draw_text ( ) ;
307
+
308
+ assert_eq ! ( txt. len( ) , 4 ) ;
309
+ assert_eq ! ( get_text( & txt[ 0 ] ) , Some ( "a" ) ) ;
310
+ assert_eq ! ( get_text( & txt[ 1 ] ) , Some ( "\u{21b5} " ) ) ;
311
+ assert_eq ! ( get_text( & txt[ 2 ] ) , Some ( "\n " ) ) ;
312
+ assert_eq ! ( get_text( & txt[ 3 ] ) , Some ( "b" ) ) ;
313
+ }
314
+ }
0 commit comments