1
1
use std:: fmt:: { Debug , Display } ;
2
2
use std:: io:: { self , Read , Write } ;
3
- use std:: sync:: { Arc , Mutex } ;
3
+ use std:: sync:: { Arc , Mutex , RwLock } ;
4
4
5
5
#[ cfg( unix) ]
6
6
use std:: os:: unix:: io:: { AsRawFd , RawFd } ;
@@ -41,6 +41,8 @@ pub enum TermTarget {
41
41
pub struct TermInner {
42
42
target : TermTarget ,
43
43
buffer : Option < Mutex < Vec < u8 > > > ,
44
+ prompt : RwLock < String > ,
45
+ prompt_guard : Mutex < ( ) > ,
44
46
}
45
47
46
48
/// The family of the terminal.
@@ -149,6 +151,8 @@ impl Term {
149
151
Term :: with_inner ( TermInner {
150
152
target : TermTarget :: Stdout ,
151
153
buffer : None ,
154
+ prompt : RwLock :: new ( String :: new ( ) ) ,
155
+ prompt_guard : Mutex :: new ( ( ) ) ,
152
156
} )
153
157
}
154
158
@@ -158,6 +162,8 @@ impl Term {
158
162
Term :: with_inner ( TermInner {
159
163
target : TermTarget :: Stderr ,
160
164
buffer : None ,
165
+ prompt : RwLock :: new ( String :: new ( ) ) ,
166
+ prompt_guard : Mutex :: new ( ( ) ) ,
161
167
} )
162
168
}
163
169
@@ -166,6 +172,8 @@ impl Term {
166
172
Term :: with_inner ( TermInner {
167
173
target : TermTarget :: Stdout ,
168
174
buffer : Some ( Mutex :: new ( vec ! [ ] ) ) ,
175
+ prompt : RwLock :: new ( String :: new ( ) ) ,
176
+ prompt_guard : Mutex :: new ( ( ) ) ,
169
177
} )
170
178
}
171
179
@@ -174,6 +182,8 @@ impl Term {
174
182
Term :: with_inner ( TermInner {
175
183
target : TermTarget :: Stderr ,
176
184
buffer : Some ( Mutex :: new ( vec ! [ ] ) ) ,
185
+ prompt : RwLock :: new ( String :: new ( ) ) ,
186
+ prompt_guard : Mutex :: new ( ( ) ) ,
177
187
} )
178
188
}
179
189
@@ -201,6 +211,8 @@ impl Term {
201
211
style,
202
212
} ) ,
203
213
buffer : None ,
214
+ prompt : RwLock :: new ( String :: new ( ) ) ,
215
+ prompt_guard : Mutex :: new ( ( ) ) ,
204
216
} )
205
217
}
206
218
@@ -231,14 +243,21 @@ impl Term {
231
243
232
244
/// Write a string to the terminal and add a newline.
233
245
pub fn write_line ( & self , s : & str ) -> io:: Result < ( ) > {
246
+ let prompt = self . inner . prompt . read ( ) . unwrap ( ) ;
247
+ if !prompt. is_empty ( ) {
248
+ self . clear_line ( ) ?;
249
+ }
234
250
match self . inner . buffer {
235
251
Some ( ref mutex) => {
236
252
let mut buffer = mutex. lock ( ) . unwrap ( ) ;
237
253
buffer. extend_from_slice ( s. as_bytes ( ) ) ;
238
254
buffer. push ( b'\n' ) ;
255
+ buffer. extend_from_slice ( prompt. as_bytes ( ) ) ;
239
256
Ok ( ( ) )
240
257
}
241
- None => self . write_through ( format ! ( "{}\n " , s) . as_bytes ( ) ) ,
258
+ None => {
259
+ self . write_through ( format ! ( "{}\n {}" , s, prompt. as_str( ) ) . as_bytes ( ) )
260
+ }
242
261
}
243
262
}
244
263
@@ -288,40 +307,54 @@ impl Term {
288
307
}
289
308
290
309
/// Read one line of input with initial text.
291
- ///
310
+ ///
311
+ /// This method blocks until no other thread is waiting for this read_line
312
+ /// before reading a line from the terminal.
292
313
/// This does not include the trailing newline. If the terminal is not
293
314
/// user attended the return value will always be an empty string.
294
315
pub fn read_line_initial_text ( & self , initial : & str ) -> io:: Result < String > {
295
316
if !self . is_tty {
296
317
return Ok ( "" . into ( ) ) ;
297
318
}
298
- self . write_str ( initial) ?;
319
+ * self . inner . prompt . write ( ) . unwrap ( ) = initial. to_string ( ) ;
320
+ // use a guard in order to prevent races with other calls to read_line_initial_text
321
+ let _guard = self . inner . prompt_guard . lock ( ) . unwrap ( ) ;
299
322
300
- let mut chars : Vec < char > = initial . chars ( ) . collect ( ) ;
323
+ self . write_str ( initial ) ? ;
301
324
302
- loop {
303
- match self . read_key ( ) ? {
304
- Key :: Backspace => {
305
- if chars. pop ( ) . is_some ( ) {
306
- self . clear_chars ( 1 ) ?;
325
+ fn read_line_internal ( slf : & Term , initial : & str ) -> io:: Result < String > {
326
+ let prefix_len = initial. len ( ) ;
327
+
328
+ let mut chars: Vec < char > = initial. chars ( ) . collect ( ) ;
329
+
330
+ loop {
331
+ match slf. read_key ( ) ? {
332
+ Key :: Backspace => {
333
+ if prefix_len < chars. len ( ) && chars. pop ( ) . is_some ( ) {
334
+ slf. clear_chars ( 1 ) ?;
335
+ }
336
+ slf. flush ( ) ?;
337
+ }
338
+ Key :: Char ( chr) => {
339
+ chars. push ( chr) ;
340
+ let mut bytes_char = [ 0 ; 4 ] ;
341
+ chr. encode_utf8 ( & mut bytes_char) ;
342
+ slf. write_str ( chr. encode_utf8 ( & mut bytes_char) ) ?;
343
+ slf. flush ( ) ?;
344
+ }
345
+ Key :: Enter => {
346
+ slf. write_through ( format ! ( "\n {}" , initial) . as_bytes ( ) ) ?;
347
+ break ;
348
+ }
349
+ _ => ( ) ,
307
350
}
308
- self . flush ( ) ?;
309
- }
310
- Key :: Char ( chr) => {
311
- chars. push ( chr) ;
312
- let mut bytes_char = [ 0 ; 4 ] ;
313
- chr. encode_utf8 ( & mut bytes_char) ;
314
- self . write_str ( chr. encode_utf8 ( & mut bytes_char) ) ?;
315
- self . flush ( ) ?;
316
- }
317
- Key :: Enter => {
318
- self . write_line ( "" ) ?;
319
- break ;
320
- }
321
- _ => ( ) ,
322
351
}
352
+ Ok ( chars. iter ( ) . skip ( prefix_len) . collect :: < String > ( ) )
323
353
}
324
- Ok ( chars. iter ( ) . collect :: < String > ( ) )
354
+ let ret = read_line_internal ( self , initial) ;
355
+
356
+ * self . inner . prompt . write ( ) . unwrap ( ) = String :: new ( ) ;
357
+ ret
325
358
}
326
359
327
360
/// Read a line of input securely.
0 commit comments