@@ -217,7 +217,7 @@ def _raw_input(prompt="", stream=None, input=None, echo_char=None,
217217 # NOTE: The Python C API calls flockfile() (and unlock) during readline.
218218 if echo_char :
219219 return _readline_with_echo_char (stream , input , echo_char ,
220- term_ctrl_chars )
220+ term_ctrl_chars , prompt )
221221 line = input .readline ()
222222 if not line :
223223 raise EOFError
@@ -229,9 +229,10 @@ def _raw_input(prompt="", stream=None, input=None, echo_char=None,
229229class _PasswordLineEditor :
230230 """Handles line editing for password input with echo character."""
231231
232- def __init__ (self , stream , echo_char , ctrl_chars ):
232+ def __init__ (self , stream , echo_char , ctrl_chars , prompt = "" ):
233233 self .stream = stream
234234 self .echo_char = echo_char
235+ self .prompt = prompt
235236 self .passwd = []
236237 self .cursor_pos = 0
237238 self .eof_pressed = False
@@ -247,18 +248,18 @@ def __init__(self, stream, echo_char, ctrl_chars):
247248 '\b ' : self ._handle_erase , # Backspace
248249 }
249250
250- def _refresh_display (self ):
251+ def _refresh_display (self , prev_len = None ):
251252 """Redraw the entire password line with *echo_char*."""
252- self .stream .write ('\r ' + ' ' * len (self .passwd ) + '\r ' )
253- self .stream .write (self .echo_char * len (self .passwd ))
253+ prompt_len = len (self .prompt )
254+ # Use prev_len if given, otherwise current password length
255+ clear_len = prev_len if prev_len is not None else len (self .passwd )
256+ # Clear the entire line (prompt + password) and rewrite
257+ self .stream .write ('\r ' + ' ' * (prompt_len + clear_len ) + '\r ' )
258+ self .stream .write (self .prompt + self .echo_char * len (self .passwd ))
254259 if self .cursor_pos < len (self .passwd ):
255260 self .stream .write ('\b ' * (len (self .passwd ) - self .cursor_pos ))
256261 self .stream .flush ()
257262
258- def _erase_chars (self , count ):
259- """Erase *count* echo characters from display."""
260- self .stream .write ("\b \b " * count )
261-
262263 def _insert_char (self , char ):
263264 """Insert *char* at cursor position."""
264265 self .passwd .insert (self .cursor_pos , char )
@@ -282,28 +283,23 @@ def _handle_erase(self):
282283 """Delete character before cursor (Backspace/DEL)."""
283284 if self .cursor_pos <= 0 :
284285 return
286+ prev_len = len (self .passwd )
285287 del self .passwd [self .cursor_pos - 1 ]
286288 self .cursor_pos -= 1
287- # Only refresh if deleting from middle
288- if self .cursor_pos < len (self .passwd ):
289- self ._refresh_display ()
290- else :
291- self .stream .write ("\b \b " )
292- self .stream .flush ()
289+ self ._refresh_display (prev_len )
293290
294291 def _handle_kill_line (self ):
295292 """Erase entire line (Ctrl+U)."""
296- self . _erase_chars ( len (self .passwd ) )
293+ prev_len = len (self .passwd )
297294 self .passwd .clear ()
298295 self .cursor_pos = 0
299- self .stream . flush ( )
296+ self ._refresh_display ( prev_len )
300297
301298 def _handle_kill_forward (self ):
302299 """Kill from cursor to end (Ctrl+K)."""
303- chars_to_delete = len (self .passwd ) - self . cursor_pos
300+ prev_len = len (self .passwd )
304301 del self .passwd [self .cursor_pos :]
305- self ._erase_chars (chars_to_delete )
306- self .stream .flush ()
302+ self ._refresh_display (prev_len )
307303
308304 def _handle_erase_word (self ):
309305 """Erase previous word (Ctrl+W)."""
@@ -315,8 +311,9 @@ def _handle_erase_word(self):
315311 while self .cursor_pos > 0 and self .passwd [self .cursor_pos - 1 ] != ' ' :
316312 self .cursor_pos -= 1
317313 # Remove the deleted portion
314+ prev_len = len (self .passwd )
318315 del self .passwd [self .cursor_pos :old_cursor ]
319- self ._refresh_display ()
316+ self ._refresh_display (prev_len )
320317
321318 def handle (self , char ):
322319 """Handle a single character input. Returns True if handled."""
@@ -328,12 +325,13 @@ def handle(self, char):
328325 return False
329326
330327
331- def _readline_with_echo_char (stream , input , echo_char , term_ctrl_chars = None ):
328+ def _readline_with_echo_char (stream , input , echo_char , term_ctrl_chars = None ,
329+ prompt = "" ):
332330 """Read password with echo character and line editing support."""
333331 if term_ctrl_chars is None :
334332 term_ctrl_chars = _POSIX_CTRL_CHARS .copy ()
335333
336- editor = _PasswordLineEditor (stream , echo_char , term_ctrl_chars )
334+ editor = _PasswordLineEditor (stream , echo_char , term_ctrl_chars , prompt )
337335
338336 while True :
339337 char = input .read (1 )
0 commit comments