Чтение стандартного ввода по ключевому событию без опущения первой буквы - PullRequest
0 голосов
/ 03 февраля 2020

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"
...