mj_controller/
hel_readline.rs1use std::io::{self, IsTerminal, Write};
4
5use anyhow::{Context, Result};
6use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal};
7
8pub struct LineReader {
9 editor: Reedline,
10}
11
12impl Default for LineReader {
13 fn default() -> Self {
14 Self {
15 editor: Reedline::create(),
16 }
17 }
18}
19
20impl LineReader {
21 pub fn read_line(&mut self, label: &str) -> Result<Option<String>> {
24 if !io::stdin().is_terminal() || !io::stdout().is_terminal() {
25 print!("{label}");
26 io::stdout().flush()?;
27 let mut answer = String::new();
28 let read = io::stdin()
29 .read_line(&mut answer)
30 .context("read terminal response")?;
31 return Ok((read > 0).then(|| answer.trim().to_owned()));
32 }
33
34 let prompt = DefaultPrompt::new(
35 DefaultPromptSegment::Basic(label.to_owned()),
36 DefaultPromptSegment::Empty,
37 );
38 match self
39 .editor
40 .read_line(&prompt)
41 .context("read terminal response")?
42 {
43 Signal::Success(answer) => Ok(Some(answer.trim().to_owned())),
44 Signal::CtrlD => Ok(None),
45 Signal::CtrlC => Ok(Some(String::new())),
46 Signal::ExternalBreak(answer) | Signal::HostCommand(answer) => {
47 Ok(Some(answer.trim().to_owned()))
48 }
49 _ => Ok(None),
50 }
51 }
52}