@@ -18,12 +18,24 @@ use crate::tty::{Renderer, Term, Terminal};
18
18
use crate :: undo:: Changeset ;
19
19
use crate :: validate:: { ValidationContext , ValidationResult } ;
20
20
21
+
22
+ #[ derive( Debug ) ]
23
+ pub struct Prompt < ' prompt > {
24
+ /// Prompt to display (rl_prompt)
25
+ pub text : & ' prompt str ,
26
+ /// Prompt Unicode/visible width and height
27
+ pub size : Position ,
28
+ /// Is this a default (user-defined) prompt, or temporary like `(arg: 0)`?
29
+ pub is_default : bool ,
30
+ /// Is prompt rectangular or single line
31
+ pub has_continuation : bool ,
32
+ }
33
+
21
34
/// Represent the state during line editing.
22
35
/// Implement rendering.
23
36
pub struct State < ' out , ' prompt , H : Helper > {
24
37
pub out : & ' out mut <Terminal as Term >:: Writer ,
25
- prompt : & ' prompt str , // Prompt to display (rl_prompt)
26
- prompt_size : Position , // Prompt Unicode/visible width and height
38
+ prompt : Prompt < ' prompt > ,
27
39
pub line : LineBuffer , // Edited line buffer
28
40
pub layout : Layout ,
29
41
saved_line_for_history : LineBuffer , // Current edited line before history browsing
@@ -48,11 +60,18 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
48
60
helper : Option < & ' out H > ,
49
61
ctx : Context < ' out > ,
50
62
) -> State < ' out , ' prompt , H > {
51
- let prompt_size = out. calculate_position ( prompt, Position :: default ( ) ) ;
63
+ let prompt_size = out. calculate_position ( prompt, Position :: default ( ) , 0 ) ;
64
+ let has_continuation = helper
65
+ . map ( |h| h. has_continuation_prompt ( ) )
66
+ . unwrap_or ( false ) ;
52
67
State {
53
68
out,
54
- prompt,
55
- prompt_size,
69
+ prompt : Prompt {
70
+ text : prompt,
71
+ size : prompt_size,
72
+ is_default : true ,
73
+ has_continuation,
74
+ } ,
56
75
line : LineBuffer :: with_capacity ( MAX_LINE ) . can_growth ( true ) ,
57
76
layout : Layout :: default ( ) ,
58
77
saved_line_for_history : LineBuffer :: with_capacity ( MAX_LINE ) . can_growth ( true ) ,
@@ -83,9 +102,9 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
83
102
let rc = input_state. next_cmd ( rdr, self , single_esc_abort) ;
84
103
if rc. is_err ( ) && self . out . sigwinch ( ) {
85
104
self . out . update_size ( ) ;
86
- self . prompt_size = self
105
+ self . prompt . size = self
87
106
. out
88
- . calculate_position ( self . prompt , Position :: default ( ) ) ;
107
+ . calculate_position ( self . prompt . text , Position :: default ( ) , 0 ) ;
89
108
self . refresh_line ( ) ?;
90
109
continue ;
91
110
}
@@ -110,20 +129,17 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
110
129
111
130
pub fn move_cursor ( & mut self ) -> Result < ( ) > {
112
131
// calculate the desired position of the cursor
113
- let cursor = self
114
- . out
115
- . calculate_position ( & self . line [ ..self . line . pos ( ) ] , self . prompt_size ) ;
116
- if self . layout . cursor == cursor {
132
+ let new_layout = self . out . compute_layout (
133
+ & self . prompt , & self . line , None ) ;
134
+ if new_layout. cursor == self . layout . cursor {
117
135
return Ok ( ( ) ) ;
118
136
}
119
137
if self . highlight_char ( ) {
120
- let prompt_size = self . prompt_size ;
121
- self . refresh ( self . prompt , prompt_size, true , Info :: NoHint ) ?;
138
+ self . refresh_default ( Info :: NoHint ) ?;
122
139
} else {
123
- self . out . move_cursor ( self . layout . cursor , cursor) ?;
124
- self . layout . prompt_size = self . prompt_size ;
125
- self . layout . cursor = cursor;
126
- debug_assert ! ( self . layout. prompt_size <= self . layout. cursor) ;
140
+ self . out . move_cursor ( self . layout . cursor , new_layout. cursor ) ?;
141
+ self . layout . prompt_size = self . prompt . size ;
142
+ self . layout . cursor = new_layout. cursor ;
127
143
debug_assert ! ( self . layout. cursor <= self . layout. end) ;
128
144
}
129
145
Ok ( ( ) )
@@ -133,13 +149,16 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
133
149
self . out . move_cursor_at_leftmost ( rdr)
134
150
}
135
151
136
- fn refresh (
137
- & mut self ,
138
- prompt : & str ,
139
- prompt_size : Position ,
140
- default_prompt : bool ,
141
- info : Info < ' _ > ,
142
- ) -> Result < ( ) > {
152
+ fn refresh ( & mut self , prompt : & Prompt < ' _ > , info : Info < ' _ > ) -> Result < ( ) > {
153
+ self . _refresh ( Some ( prompt) , info)
154
+ }
155
+ fn refresh_default ( & mut self , info : Info < ' _ > ) -> Result < ( ) > {
156
+ // We pass None, because we can't pass `&self.prompt`
157
+ // to the method having `&mut self` as a receiver
158
+ self . _refresh ( None , info)
159
+ }
160
+ fn _refresh ( & mut self , non_default_prompt : Option < & Prompt < ' _ > > , info : Info < ' _ > ) -> Result < ( ) > {
161
+ let prompt = non_default_prompt. unwrap_or ( & self . prompt ) ;
143
162
let info = match info {
144
163
Info :: NoHint => None ,
145
164
Info :: Hint => self . hint . as_deref ( ) ,
@@ -151,10 +170,7 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
151
170
None
152
171
} ;
153
172
154
- let new_layout = self
155
- . out
156
- . compute_layout ( prompt_size, default_prompt, & self . line , info) ;
157
-
173
+ let new_layout = self . out . compute_layout ( prompt, & self . line , info) ;
158
174
debug ! ( target: "rustyline" , "old layout: {:?}" , self . layout) ;
159
175
debug ! ( target: "rustyline" , "new layout: {:?}" , new_layout) ;
160
176
self . out . refresh_line (
@@ -239,24 +255,27 @@ impl<'out, 'prompt, H: Helper> Invoke for State<'out, 'prompt, H> {
239
255
240
256
impl < ' out , ' prompt , H : Helper > Refresher for State < ' out , ' prompt , H > {
241
257
fn refresh_line ( & mut self ) -> Result < ( ) > {
242
- let prompt_size = self . prompt_size ;
243
258
self . hint ( ) ;
244
259
self . highlight_char ( ) ;
245
- self . refresh ( self . prompt , prompt_size , true , Info :: Hint )
260
+ self . refresh_default ( Info :: Hint )
246
261
}
247
262
248
263
fn refresh_line_with_msg ( & mut self , msg : Option < String > ) -> Result < ( ) > {
249
- let prompt_size = self . prompt_size ;
250
264
self . hint = None ;
251
265
self . highlight_char ( ) ;
252
- self . refresh ( self . prompt , prompt_size , true , Info :: Msg ( msg. as_deref ( ) ) )
266
+ self . refresh_default ( Info :: Msg ( msg. as_deref ( ) ) )
253
267
}
254
268
255
269
fn refresh_prompt_and_line ( & mut self , prompt : & str ) -> Result < ( ) > {
256
- let prompt_size = self . out . calculate_position ( prompt, Position :: default ( ) ) ;
270
+ let prompt = Prompt {
271
+ text : prompt,
272
+ size : self . out . calculate_position ( prompt, Position :: default ( ) , 0 ) ,
273
+ is_default : false ,
274
+ has_continuation : false ,
275
+ } ;
257
276
self . hint ( ) ;
258
277
self . highlight_char ( ) ;
259
- self . refresh ( prompt, prompt_size , false , Info :: Hint )
278
+ self . refresh ( & prompt, Info :: Hint )
260
279
}
261
280
262
281
fn doing_insert ( & mut self ) {
@@ -284,7 +303,6 @@ impl<'out, 'prompt, H: Helper> fmt::Debug for State<'out, 'prompt, H> {
284
303
fn fmt ( & self , f : & mut fmt:: Formatter < ' _ > ) -> fmt:: Result {
285
304
f. debug_struct ( "State" )
286
305
. field ( "prompt" , & self . prompt )
287
- . field ( "prompt_size" , & self . prompt_size )
288
306
. field ( "buf" , & self . line )
289
307
. field ( "cols" , & self . out . get_columns ( ) )
290
308
. field ( "layout" , & self . layout )
@@ -305,7 +323,6 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
305
323
pub fn edit_insert ( & mut self , ch : char , n : RepeatCount ) -> Result < ( ) > {
306
324
if let Some ( push) = self . line . insert ( ch, n) {
307
325
if push {
308
- let prompt_size = self . prompt_size ;
309
326
let no_previous_hint = self . hint . is_none ( ) ;
310
327
self . hint ( ) ;
311
328
let width = ch. width ( ) . unwrap_or ( 0 ) ;
@@ -318,13 +335,12 @@ impl<'out, 'prompt, H: Helper> State<'out, 'prompt, H> {
318
335
// Avoid a full update of the line in the trivial case.
319
336
self . layout . cursor . col += width;
320
337
self . layout . end . col += width;
321
- debug_assert ! ( self . layout. prompt_size <= self . layout. cursor) ;
322
338
debug_assert ! ( self . layout. cursor <= self . layout. end) ;
323
339
let bits = ch. encode_utf8 ( & mut self . byte_buffer ) ;
324
340
let bits = bits. as_bytes ( ) ;
325
341
self . out . write_and_flush ( bits)
326
342
} else {
327
- self . refresh ( self . prompt , prompt_size , true , Info :: Hint )
343
+ self . refresh_default ( Info :: Hint )
328
344
}
329
345
} else {
330
346
self . refresh_line ( )
@@ -664,8 +680,12 @@ pub fn init_state<'out, H: Helper>(
664
680
) -> State < ' out , ' static , H > {
665
681
State {
666
682
out,
667
- prompt : "" ,
668
- prompt_size : Position :: default ( ) ,
683
+ prompt : Prompt {
684
+ text : "" ,
685
+ size : Position :: default ( ) ,
686
+ is_default : true ,
687
+ has_continuation : false ,
688
+ } ,
669
689
line : LineBuffer :: init ( line, pos, None ) ,
670
690
layout : Layout :: default ( ) ,
671
691
saved_line_for_history : LineBuffer :: with_capacity ( 100 ) ,
0 commit comments