From eb0e61b1aef2fd0fddabcaec6ea318773b65717e Mon Sep 17 00:00:00 2001 From: salmonik Date: Mon, 2 Mar 2026 17:56:49 +0100 Subject: only use raw mode --- src/bin/client/repl.rs | 83 ++++++++++++++++++++++++++++++++++++++++++++------ 1 file changed, 74 insertions(+), 9 deletions(-) (limited to 'src/bin/client/repl.rs') diff --git a/src/bin/client/repl.rs b/src/bin/client/repl.rs index b2f6ecd..4e787cb 100644 --- a/src/bin/client/repl.rs +++ b/src/bin/client/repl.rs @@ -6,7 +6,7 @@ use std::time::Instant; use crate::connection; use crate::database; -use crossterm::{event::{read, Event, KeyCode, KeyModifiers}, terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType}, cursor::{MoveToColumn, Show}, execute}; +use crossterm::{event::{read, Event, KeyCode, KeyModifiers}, terminal::{disable_raw_mode, enable_raw_mode, Clear, ClearType}, cursor::{MoveToColumn, Show, Hide}, execute}; use sha2::{Sha256, Digest}; @@ -172,7 +172,7 @@ impl ClientState { if username.is_empty() { continue 'outer; } - let password = read_line("Password: "); + let password = read_password("Password: "); if password.is_empty() { continue 'outer; } @@ -217,7 +217,7 @@ impl ClientState { if username.is_empty() { break; } - let password = read_line("Password: "); + let password = read_password("Password: "); if password.is_empty() { break; } @@ -268,7 +268,7 @@ impl ClientState { if username.is_empty() { continue 'outer; } - let password = read_line("Password: "); + let password = read_password("Password: "); if password.is_empty() { continue 'outer; } @@ -367,14 +367,13 @@ impl ClientState { *current_input = matches[0].clone(); redraw(current_input); } else if matches.len() > 1 { - disable_raw_mode().unwrap(); execute!(stdout(), Show).unwrap(); println!("\nPossible completions:"); for m in &matches { print!("{} ", m); } println!(); - enable_raw_mode().unwrap(); + execute!(stdout(), Hide).unwrap(); redraw(current_input); } // else do nothing @@ -420,12 +419,78 @@ fn redraw(current_input: &str) { } fn read_line(prompt: &str) -> String { - disable_raw_mode().unwrap(); execute!(stdout(), Show).unwrap(); print!("{}", prompt); stdout().flush().unwrap(); + let mut input = String::new(); - std::io::stdin().read_line(&mut input).unwrap(); - enable_raw_mode().unwrap(); + let prompt_len = prompt.len(); + + loop { + match read().unwrap() { + Event::Key(key) => match key.code { + KeyCode::Enter => { + println!(); + break; + } + KeyCode::Backspace => { + if !input.is_empty() { + input.pop(); + // Move cursor back and clear from current position to end of line + execute!(stdout(), MoveToColumn((prompt_len + input.len() + 1) as u16), + Clear(ClearType::UntilNewLine)).unwrap(); + stdout().flush().unwrap(); + } + } + KeyCode::Char(c) => { + input.push(c); + print!("{}", c); + stdout().flush().unwrap(); + } + _ => {} + }, + _ => {} + } + } + input.trim().to_string() +} + +fn read_password(prompt: &str) -> String { + execute!(stdout(), Show).unwrap(); + print!("{}", prompt); + stdout().flush().unwrap(); + + let mut input = String::new(); + let mut display = String::new(); + let prompt_len = prompt.len(); + + loop { + match read().unwrap() { + Event::Key(key) => match key.code { + KeyCode::Enter => { + println!(); + break; + } + KeyCode::Backspace => { + if !input.is_empty() { + input.pop(); + display.pop(); + // Move cursor back and clear from current position to end of line + execute!(stdout(), MoveToColumn((prompt_len + display.len() + 1) as u16), + Clear(ClearType::UntilNewLine)).unwrap(); + stdout().flush().unwrap(); + } + } + KeyCode::Char(c) => { + input.push(c); + display.push('*'); + print!("*"); + stdout().flush().unwrap(); + } + _ => {} + }, + _ => {} + } + } input.trim().to_string() } -- cgit v1.2.3