如何为 Rust 终端应用程序启用可编辑的用户输入?

zai*_*ile 2 terminal rust

我正在用 Rust 编写一个带有经典的基于终端的 REPL 环境项目的最小 Lisp。

如何从箭头键读取用户输入,允许他们至少在按下 之前在当前输入行上来回移动enter?理想情况下,我将能够扩展功能,包括“返回”以检索旧输入,就像在任何终端或任何 REPL 中一样。为了清楚起见,下面是该行为的图像:

在此输入图像描述

我已经使用了标准库的io模块和termion板条箱,但还没有弄清楚这个功能。

这是我当前的工作代码。它有效地获取输入并立即将其打印回给用户,此外还按预期退出quit()

use std::io::prelude::*;
use std::io;

fn main() {
    println!("Rispy Version 0.0.1");
    println!("Enter `quit()` to Exit");

    let mut input: String;

    // continuous input til ctrl-c or quit()
    loop {

        print!("rispy>> ");
        io::stdout().flush().unwrap();

        input = String::new();
        io::stdin().read_line(&mut input)
            .expect("Error reading line");

        print!("input: {}", input);

        match input.as_ref() {
            "quit()\n" => {
                println!("\nGoodbye");
                break;
            },
            _ => continue,
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

zai*_*ile 5

有趣的是,在其他地方没有更容易地建议一些基本/基本的板条箱来解决这样的问题,但值得庆幸的是@kazemakase通过建议一个我到目前为止还没有找到的板条箱来回答这个问题:rustyline

对自述文件中的示例代码进行轻微编辑即可产生我想要的结果,包括历史记录、使用箭头键向左/向右导航的能力,甚至可以使用 ctrl-d、ctrl-c、home 等按键。这是与所提出的问题相结合的:

extern crate rustyline;

use rustyline::Editor;
use rustyline::error::ReadlineError;

fn main() {
    println!("Rispy Version 0.0.1");
    println!("Enter `quit()` to Exit");

    let mut reader = Editor::<()>::new();
    if let Err(_) = reader.load_history("rispy_history.txt") {
        println!("No previous history.");
    }

    // continuous input
    loop {

        let readline = reader.readline("rispy>> ");

        match readline {
            Ok(line) => {
                reader.add_history_entry(&line);
                println!("input: {}", line);
            },
            Err(ReadlineError::Interrupted) => {
                println!("CTRL-C");
                println!("Goodbye");
                break
            }
            Err(ReadlineError::Eof) => {
                println!("CTRL-D");
                println!("Goodbye");
                break
            },
            Err(err) => {
                println!("Error: {:?}", err);
                break
            }
        }
    }
    reader.save_history("rispy_history.txt").unwrap();
}
Run Code Online (Sandbox Code Playgroud)