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

作者:京东科技 贾世闻

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

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

基本原理

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

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

1pub fn run() { 2 let config = Config::builder() 3 .history_ignore_space(true) 4 .completion_type(CompletionType::List) 5 .output_stream(OutputStreamType::Stdout) 6 .build(); 7 8 let h = MyHelper { 9 completer: get_command_completer(), 10 highlighter: MatchingBracketHighlighter::new(), 11 hinter: HistoryHinter {}, 12 colored_prompt: "".to_owned(), 13 validator: MatchingBracketValidator::new(), 14 }; 15 16 let mut rl = Editor::with_config(config); 17 rl.set_helper(Some(h)); 18 19 if rl.load_history("/tmp/history").is_err() { 20 println!("No previous history."); 21 } 22 23 loop { 24 let p = format!("{}> ", "interact-rs"); 25 rl.helper_mut().expect("No helper").colored_prompt = format!("\x1b[1;32m{}\x1b[0m", p); 26 let readline = rl.readline(&p); 27 match readline { 28 Ok(line) => { 29 if line.trim_start().is_empty() { 30 continue; 31 } 32 33 rl.add_history_entry(line.as_str()); 34 match split(line.as_str()).as_mut() { 35 Ok(arg) => { 36 if arg[0] == "exit" { 37 println!("bye!"); 38 break; 39 } 40 arg.insert(0, "clisample".to_string()); 41 run_from(arg.to_vec()) 42 } 43 Err(err) => { 44 println!("{}", err) 45 } 46 } 47 } 48 Err(ReadlineError::Interrupted) => { 49 println!("CTRL-C"); 50 break; 51 } 52 Err(ReadlineError::Eof) => { 53 println!("CTRL-D"); 54 break; 55 } 56 Err(err) => { 57 println!("Error: {:?}", err); 58 break; 59 } 60 } 61 } 62 rl.append_history("/tmp/history") 63 .map_err(|err| error!("{}", err)) 64 .ok(); 65}

解析主逻辑

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

处理的逻辑如下

  • 定义提示符,类似 'mysql> ',提示用户正在使用的程序
1 let p = format!("{}> ", "interact-rs"); 2 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 函数进行命令解析和执行
    1match split(line.as_str()).as_mut() { 2 Ok(arg) => { 3 if arg[0] == "exit" { 4 println!("bye!"); 5 break; 6 } 7 arg.insert(0, "clisample".to_string()); 8 run_from(arg.to_vec()) 9 } 10 Err(err) => { 11 println!("{}", err) 12 } 13 }
    • 解析中断,当用户执行 ctrl-c 或 ctrl-d 时,退出程序。
    1 Err(ReadlineError::Interrupted) => { 2 println!("CTRL-C"); 3 break; 4 } 5 Err(ReadlineError::Eof) => { 6 println!("CTRL-D"); 7 break; 8 } 9 Err(err) => { 10 println!("Error: {:?}", err); 11 break; 12 }

run 函数中其他代码的作用

  • 配置rustyline
    在 run 函数最开头 定义了一个config

    1let config = Config::builder() 2 .history_ignore_space(true) 3 .completion_type(CompletionType::List) 4 .output_stream(OutputStreamType::Stdout) 5 .build();

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

    MyHelper 用于配置命令的 autocomplete

    1let h = MyHelper { 2 completer: get_command_completer(), 3 highlighter: MatchingBracketHighlighter::new(), 4 hinter: HistoryHinter {}, 5 colored_prompt: "".to_owned(), 6 validator: MatchingBracketValidator::new(), 7};

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

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

    1rl.append_history("/tmp/history") 2 .map_err(|err| error!("{}", err)) 3 .ok();

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

点赞
收藏

评论区

加载中...

相关推荐

Golang 常见设计模式之单例模式

之前我们已经看过了Golang常见设计模式中的装饰和选项模式,今天要看的是Golang设计模式里最简单的单例模式。单例模式的作用是确保无论对象被实例化多少次,全局都只有一个实例存在。根据这一特性,我们可以将其应用到全局唯一性配置、数据库连接对象、文件访问对象等。Go语言实现单例模式的方法有很多种,下面我们就一起来看一下。饿汉式饿汉式实现单例模式非

SHELL编程四剑客之Sed工具

SED是一个非交互式文本编辑器,它可对文本文件和标准输入进行编辑,标准输入可以来自键盘输入、文本重定向、字符串、变量,甚至来自于管道的文本。Sed工具在处理文本时默认把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace)。如果要将变化写入磁盘、文件需要使用i参数。sed命令语法参数格式:sed参数‘sed内置命令字符‘

MySql基础指令

登录MySQLWindows系统下:运行cmd输入:mysqlu用户名p接着输入用户密码即可进入数据库交互界面:mysqlMacOS系统:在终端输入上面的命令,接着输入密码同样可以进入交互界面:mysql命令行创建和删除数据库MacOS系统和Windows系统需

Java应用一般架构原理

当我们架设一个系统的时候通常需要考虑到如何与其他系统交互,所以我们首先需要知道各种系统之间是如何交互的,使用何种技术实现。1\.不同系统不同语言之间的交互现在我们常见的不同系统不同语言之间的交互使用WebService,Http请求。WebService,即“Web服务”,简写为WS。从字面上理解,它其实就是“基于Web的

Linux云计算学习笔记day56

shell编程第一章1.1什么是shell?Shell其实是一个命令解释器,作用是解释执行用户输入的命令以及程序等,用户每输入一条命令,Shell给予解释执行一条。这种键盘一输入命令,就可以立即得到回应的对话方式,称为交互模式。Shell存在于操作系统的最外层,负责与用户直接对话。处理用户的输入,并将操作系

文盘Rust——子命令提示,提高用户体验 | 京东云技术团队

上次我们聊到CLI的领域交互模式。在领域交互模式中,可能存在多层次的子命令。在使用过程中如果全评记忆的话,命令少还好,多了真心记不住。频繁help也是个很麻烦的事情。如果每次按'tab'键就可以提示或补齐命令是不是很方便呢。这一节我们就来说说'autoco