写点什么

文盘 Rust -- 领域交互模式如何实现

  • 2023-02-13
    北京
  • 本文字数:2536 字

    阅读完需:约 8 分钟

文盘Rust -- 领域交互模式如何实现

作者:京东科技 贾世闻

文盘 Rust -- 领域交互模式如何实现

书接上文,上回说到如何通过interactcli-rs四步实现一个命令行程序。但是 shell 交互模式在有些场景下用户体验并不是很好。比如我们要连接某个服务,比如 mysql 或者 redis 这样的服务。如果每次交互都需要输入地址、端口、用户名等信息,交互起来太麻烦。通常的做法是一次性输入和连接相关的信息或者由统一配置文件进行管理,然后进入领域交互模式,所有的命令和反馈都和该领域相关。interactcli-rs 通过 -i 参数实现领域交互模式。这回我们探索一下这一模式是如何实现的。

基本原理

interactcli-rs 实现领域交互模式主要是循环解析输入的每一行,通过rustyline 解析输入的每一行命令,并交由命令解析函数处理响应逻辑


当我们调用 ‘-i’ 参数的时候 实际上是执行了 interact::run() 函数(interact -> cli -> run())。


pub fn run() {    let config = Config::builder()        .history_ignore_space(true)        .completion_type(CompletionType::List)        .output_stream(OutputStreamType::Stdout)        .build();
let h = MyHelper { completer: get_command_completer(), highlighter: MatchingBracketHighlighter::new(), hinter: HistoryHinter {}, colored_prompt: "".to_owned(), validator: MatchingBracketValidator::new(), };
let mut rl = Editor::with_config(config); rl.set_helper(Some(h));
if rl.load_history("/tmp/history").is_err() { println!("No previous history."); }
loop { let p = format!("{}> ", "interact-rs"); rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p); let readline = rl.readline(&p); match readline { Ok(line) => { if line.trim_start().is_empty() { continue; }
rl.add_history_entry(line.as_str()); match split(line.as_str()).as_mut() { Ok(arg) => { if arg[0] == "exit" { println!("bye!"); break; } arg.insert(0, "clisample".to_string()); run_from(arg.to_vec()) } Err(err) => { println!("{}", err) } } } Err(ReadlineError::Interrupted) => { println!("CTRL-C"); break; } Err(ReadlineError::Eof) => { println!("CTRL-D"); break; } Err(err) => { println!("Error: {:?}", err); break; } } } rl.append_history("/tmp/history") .map_err(|err| error!("{}", err)) .ok();}
复制代码

解析主逻辑

交互逻辑主要集中在 ‘loop’ 循环中,每次循环处理一次输入请求。


处理的逻辑如下


  • 定义提示符,类似 'mysql> ',提示用户正在使用的程序


 let p = format!("{}> ", "interact-rs"); rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p);
复制代码


  • 读取输入行进行解析

  • 将输入的命令行加入到历史文件,执行过的命令可以通过上下键回放来增强用户体验。


    rl.add_history_entry(line.as_str());
复制代码


输入的行解析为 arg 字符串,交由 cmd::run_from 函数进行命令解析和执行


    match split(line.as_str()).as_mut() {                      Ok(arg) => {                          if arg[0] == "exit" {                              println!("bye!");                              break;                          }                          arg.insert(0, "clisample".to_string());                          run_from(arg.to_vec())                      }                      Err(err) => {                          println!("{}", err)                      }                  }
复制代码


解析中断,当用户执行 ctrl-c 或 ctrl-d 时,退出程序。


       Err(ReadlineError::Interrupted) => {                  println!("CTRL-C");                  break;              }              Err(ReadlineError::Eof) => {                  println!("CTRL-D");                  break;              }              Err(err) => {                  println!("Error: {:?}", err);                  break;              }
复制代码

run 函数中其他代码的作用

配置 rustyline

在 run 函数最开头 定义了一个 config


    let config = Config::builder()      .history_ignore_space(true)      .completion_type(CompletionType::List)      .output_stream(OutputStreamType::Stdout)      .build();
复制代码


这个 config 其实是 rustyline 的配置项,包括输出方式历史记录约束,输出方式等等。


MyHelper 用于配置命令的 autocomplete


    let h = MyHelper {      completer: get_command_completer(),      highlighter: MatchingBracketHighlighter::new(),      hinter: HistoryHinter {},      colored_prompt: "".to_owned(),      validator: MatchingBracketValidator::new(),    }; 
复制代码


这里卖个关子,下期详细讲讲 autocomplete 的实现。


配置历史文件

run 函数最后,我们为程序配置了历史文件,应用于存放执行过的历史命令。这样即便程序退出,在此打开程序的时候还是可以利用以前的执行历史。


    rl.append_history("/tmp/history")          .map_err(|err| error!("{}", err))          .ok();
复制代码


关于如何构建命令行的领域交互模式就说到这儿,下期详细介绍一下 autocomplete 如何实现。

发布于: 刚刚阅读数: 2
用户头像

拥抱技术,与开发者携手创造未来! 2018-11-20 加入

我们将持续为人工智能、大数据、云计算、物联网等相关领域的开发者,提供技术干货、行业技术内容、技术落地实践等文章内容。京东云开发者社区官方网站【https://developer.jdcloud.com/】,欢迎大家来玩

评论

发布
暂无评论
文盘Rust -- 领域交互模式如何实现_rust_京东科技开发者_InfoQ写作社区