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

Terminal 如何为Rust终端应用程序启用可编辑用户输入?,terminal,rust,Terminal,Rust,我正在用Rust中一个经典的基于终端的REPL环境项目编写一个最小Lisp 如何从箭头键读入用户输入,至少在按下enter之前,允许他们在当前输入行上来回移动?理想情况下,我将能够扩展功能,包括移动“后退”以检索旧输入,就像在任何终端或任何REPL中一样。为了清晰起见,以下是行为的图像: 我已经使用了标准库的io模块和termion板条箱,但还没有弄清楚这个功能 这是我目前的工作代码。除了使用quit()按预期退出外,它还有效地接收输入并立即将其打印回用户 有趣的是,对于这样的问题,有些基本/

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

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

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

这是我目前的工作代码。除了使用
quit()
按预期退出外,它还有效地接收输入并立即将其打印回用户


有趣的是,对于这样的问题,有些基本/基本的板条箱并没有在其他地方更容易提出,但谢天谢地,我提出了一个迄今为止我还没有找到的板条箱来回答这个问题:

对自述文件上的示例代码稍加编辑,就可以得到我想要的结果,包括历史记录、使用箭头键左/右导航的能力,甚至还可以使用诸如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();
}
外部板条箱生锈线;
使用rustyline::编辑器;
使用rustyline::error::ReadlineError;
fn main(){
println!(“精简版0.0.1”);
println!(“输入'quit()`退出”);
让mut reader=Editor:::new();
如果让Err(u)=reader.load_history(“rispy_history.txt”){
println!(“没有以前的历史记录”);
}
//连续输入
环路{
让readline=reader.readline(“rispy>>”);
匹配读线{
Ok(行)=>{
reader.add_history_条目(&行);
println!(“输入:{}”,行);
},
错误(ReadlineError::Interrupted)=>{
println!(“CTRL-C”);
println!(“再见”);
打破
}
错误(ReadlineError::Eof)=>{
println!(“CTRL-D”);
println!(“再见”);
打破
},
错误(Err)=>{
println!(“错误:{:?}”,err);
打破
}
}
}
reader.save_history(“rispy_history.txt”).unwrap();
}

作为一个开箱即用的答案,我偶尔会在任何命令行程序周围使用一个小包装器来添加基本的读线功能


运行
rlwrap cargo run
,您的原始程序现在可以按照您的要求进行编辑,以及命令历史记录和历史记录搜索,可能还有许多其他功能。

简单的方法是使用现有的板条箱。例如,包装GNU readline,或者是rust实现。@kazemakase这就是答案。您应该将其作为实际答案发布。@Boiethios我不太愿意将指向图书馆的链接作为答案发布,因为这可能意味着该问题与主题无关,尽管为图书馆服务不是我的本意。。。我读这个问题的方式是OP可能真的想自己实现它。@kazemakase我知道,但除非有人真的想玩ncurses(在这种情况下我不推荐),否则他应该使用其中一个板条箱。也许你应该发布一个答案,比如:“直接使用ncurses,或者使用一个现有的实现,比如rustyline。我推荐后者。”@Boiethios right。我要到周末以后才能写出一个好的答案。请放心替我做吧。ncurses不是唯一的选项-您还可以发出用于退格或回车的ascii码来覆盖当前行。我认为这是一个很好的答案,而且我还惊讶于我不知道与此类似的解决方案。也就是说,我正在选择我的答案(由@kazemakase在评论中提供)作为解决方案,因为它按照我的要求从程序内部而不是外部回答了问题。很高兴听到我的评论很有帮助。如果你认为这是解决问题的最好办法,你可以接受自己的答案。
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();
}