Context
Я работаю над приложением pomodoro для командной строки, написанным на ржавчине, большинство из них работало хорошо, но теперь я хочу отредактировать текст элемента pomodoro в базе данных. Все действия в приложении запускаются нажатием клавиш, приостановкой / возобновлением, выходом из режима ожидания и т. Д. c. а также редактирование текста.
Теперь я хочу прочитать текст из stdin
, но ключевые события также поступают из stdin, но в другом потоке. Я придумал использовать stdin.lock()
- который работает почти нормально.
Проблема
Как мне прочитать строку из stdin
в главном потоке, не опуская первую букву, из-за того, что прослушиватель событий запускается в его потоке, до получения блокировки в основном потоке.
ожидаемое поведение:
- нажмите
t
= > print Reading from stdin!
- type
abc<enter>
=> print You typed: Some("abc")
фактическое поведение:
- press
t
=> print Reading from stdin!
- type
abc<enter>
=> print You typed: Some("bc")
Минимальный нерабочий пример
Вот пример, который показывает описанное поведение:
use failure;
use std::io::{stdin, stdout};
use std::sync::mpsc;
use std::thread;
use termion::event::Key;
use termion::input::TermRead;
use termion::raw::IntoRawMode;
use tui::backend::TermionBackend;
use tui::Terminal;
pub enum Event {
Input(Key),
}
#[allow(dead_code)]
pub struct Events {
rx: mpsc::Receiver<Event>,
input_handle: thread::JoinHandle<()>,
}
impl Events {
pub fn new() -> Events {
let (tx, rx) = mpsc::channel();
let input_handle = {
let tx = tx.clone();
thread::spawn(move || {
let stdin = stdin();
for evt in stdin.keys() {
match evt {
Ok(key) => {
if let Err(_) = tx.send(Event::Input(key)) {
return;
}
}
Err(_) => {}
}
}
})
};
Events {
rx,
input_handle,
}
}
pub fn next(&self) -> Result<Event, mpsc::RecvError> {
self.rx.recv()
}
}
pub fn key_handler(key: Key) -> bool {
match key {
Key::Char('t') => {
println!("Reading from stdin!");
let stdin = stdin();
let mut handle = stdin.lock();
let input = handle.read_line().unwrap();
println!("You typed: {:?}", input);
}
_ =>{
println!("no thing!");
}
};
key == Key::Char('q')
}
fn main() -> Result<(), failure::Error> {
let stdout = stdout().into_raw_mode()?;
let backend = TermionBackend::new(stdout);
let mut terminal = Terminal::new(backend)?;
terminal.clear()?;
terminal.hide_cursor()?;
let events = Events::new();
loop {
match events.next()? {
Event::Input(key) => {
if key_handler(key) {
break;
}
}
}
}
terminal.clear()?;
terminal.show_cursor()?;
Ok(())
}
Обновление
Автомобиль go .Toml
[package]
name = "mnwe"
version = "1.1.0"
edition = "2018"
autotests = false
[[bin]]
bench = false
path = "app/main.rs"
name = "mnwe"
[dependencies]
failure = "0.1"
termion = "1.5.3"
tui = "0.7"