@@ -86,6 +86,13 @@ impl TextInputComponent {
8686 Some ( index)
8787 }
8888
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+
8996 /// Set the `msg`.
9097 pub fn set_text ( & mut self , msg : String ) {
9198 self . msg = msg;
@@ -96,6 +103,54 @@ impl TextInputComponent {
96103 pub fn set_title ( & mut self , t : String ) {
97104 self . title = t;
98105 }
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+ }
99154}
100155
101156impl DrawableComponent for TextInputComponent {
@@ -105,46 +160,13 @@ impl DrawableComponent for TextInputComponent {
105160 _rect : Rect ,
106161 ) -> Result < ( ) > {
107162 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(
112165 self . default_msg. as_str( ) ,
113166 self . theme. text( false , false ) ,
114- ) ) ;
167+ ) ]
115168 } 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 ( )
148170 } ;
149171
150172 let area = ui:: centered_rect ( 60 , 20 , f. size ( ) ) ;
@@ -203,12 +225,7 @@ impl Component for TextInputComponent {
203225 return Ok ( true ) ;
204226 }
205227 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 ( ) ;
212229 return Ok ( true ) ;
213230 }
214231 KeyCode :: Left => {
@@ -248,3 +265,50 @@ impl Component for TextInputComponent {
248265 Ok ( ( ) )
249266 }
250267}
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