首页 > 其他分享 > 文盘Rust -- 领域交互模式如何实现

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

时间:2023-02-13 18:32:46浏览次数:53  
标签:run err -- 文盘 rl arg println Rust history

作者:京东科技 贾世闻

文盘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 如何实现。

标签:run,err,--,文盘,rl,arg,println,Rust,history
From: https://blog.51cto.com/u_15714439/6054583

相关文章

  • 老牌交易所Kraken被SEC重罚!业内人士都咋看?
       近日,SEC宣布与加密交易所Kraken达成和解,Kraken同意“立即”停止为美国客户提供链上质押服务(该服务仍继续向美国以外的客户提供),并支付3000万美元罚款以了结SEC对其......
  • Microsoft Azure 教程_编程入门自学教程_菜鸟教程-免费教程分享
    教程简介MicrosoftAzure初学者教程-从简单和简单的步骤学习MicrosoftAzure,从基本到高级概念,包括云计算概述,WindowsAzure,组件,计算模块,结构控制器,存储,Blob,队列,表,CDN,应用......
  • Filter的是实现方式
    1、实现Filter接口或者继承Filter接口的实现类,使用@Component或者@Configuration注解注册到Spring​中importorg.springframework.stereotype.Component;importjavax.ser......
  • 通过Lambda优化 AWS EMR 成本
    背景随着AWSEMR服务用户越来越多,持续运行的AWSEMR在成本优化方面会有较多限制,本文会提供一些特定情况下AWSEMR平台成本优化的一些方法和思路。本文主要包含“控制实例组......
  • 信息论绪论
    本专栏针包含信息论与编码的核心知识,按知识点组织,可作为教学或学习的参考。markdown版本已归档至【Github仓库:​​information-theory​​】,需要的朋友们自取。或者关注公众......
  • linux文件拼接命令 paste
    paste[文件名1[文件名2]……][选项]-s把文件以行的方式拼接-d制定分隔符,默认以制表符分隔[root@localhost~]#seq5>1.txt[root@localhost~]#seq610>2.t......
  • #yyds干货盘点# LeetCode程序员面试金典:合并排序的数组
    题目:给定两个排序后的数组A和B,其中A的末端有足够的缓冲空间容纳B。编写一个方法,将B合并入A并排序。初始化 A和B的元素数量分别为 m和n。示例:输入:A=[1......
  • SpringCloud 集成 Consul+restTemplate 集群实战
      服务提供者应用两个模块(prot:8021,8021)pom.xml<?xmlversion="1.0"encoding="UTF-8"?><projectxmlns="http://maven.apache.org/POM/4.0.0"xmln......
  • Sanitizers使用介绍
    Sanitizersers是一个工具集合,由google开发并开源,项目地址sanitizers。Sanitizers包括系列工具:AddressSanitizer,检测内存访问问题MemorySanitizer,检测未初始化内存问题......
  • [JavaScript]内置对象Number初识
    学习:https://developer.mozilla.org/zh-CN/docs/Web/JavaScript/Reference/Global_Objects/NumberNumber类型可以表示整型和浮点型。123===123.0;//trueNumber......