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

京东云开发者
• 阅读 434

作者:京东科技 贾世闻

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

点赞
收藏
评论区
推荐文章
3A网络 3A网络
2年前
Golang 常见设计模式之单例模式
之前我们已经看过了Golang常见设计模式中的装饰和选项模式,今天要看的是Golang设计模式里最简单的单例模式。单例模式的作用是确保无论对象被实例化多少次,全局都只有一个实例存在。根据这一特性,我们可以将其应用到全局唯一性配置、数据库连接对象、文件访问对象等。Go语言实现单例模式的方法有很多种,下面我们就一起来看一下。饿汉式饿汉式实现单例模式非
Stella981 Stella981
3年前
SHELL编程四剑客之Sed工具
SED是一个非交互式文本编辑器,它可对文本文件和标准输入进行编辑,标准输入可以来自键盘输入、文本重定向、字符串、变量,甚至来自于管道的文本。Sed工具在处理文本时默认把当前处理的行存储在临时缓冲区中,称为“模式空间”(patternspace)。如果要将变化写入磁盘、文件需要使用i参数。sed命令语法参数格式:sed参数‘sed内置命令字符‘
Wesley13 Wesley13
3年前
MySql基础指令
登录MySQLWindows系统下:运行cmd输入:mysqlu用户名p接着输入用户密码即可进入数据库交互界面:mysqlMacOS系统:在终端输入上面的命令,接着输入密码同样可以进入交互界面:mysql命令行创建和删除数据库MacOS系统和Windows系统需
Wesley13 Wesley13
3年前
Java应用一般架构原理
当我们架设一个系统的时候通常需要考虑到如何与其他系统交互,所以我们首先需要知道各种系统之间是如何交互的,使用何种技术实现。1\.不同系统不同语言之间的交互现在我们常见的不同系统不同语言之间的交互使用WebService,Http请求。WebService,即“Web服务”,简写为WS。从字面上理解,它其实就是“基于Web的
Stella981 Stella981
3年前
Linux云计算学习笔记day56
shell编程第一章1.1什么是shell?Shell其实是一个命令解释器,作用是解释执行用户输入的命令以及程序等,用户每输入一条命令,Shell给予解释执行一条。这种键盘一输入命令,就可以立即得到回应的对话方式,称为交互模式。Shell存在于操作系统的最外层,负责与用户直接对话。处理用户的输入,并将操作系
Stella981 Stella981
3年前
MediatorPattern中介者模式
中介者模式1.定义使用一个中介对象封装一系列的对象交互,中介者使用对象不需要显式的相互作用,从而实降现低耦合度,且可以独立改变被封装的一些列对象之间的交互。中介者模式也叫做调停者模式:对象之间的依赖就像战争,很混乱,加入一个中心,所有对象都和中心交流,接受中心的调停处理。中介者模式通常有4个角色Abstrac
四儿 四儿
1年前
手势识别数据集:利用数据注释让机器学习
手势识别是现代计算机视觉领域不可或缺的一部分,是指通过分析输入信号的空间变化来获取表达者的意图。手势识别技术可以应用于很多领域,比如交互式系统、人脸识别以及智能家居等。在许多场景中,手势识别是更加便捷的控制方式,它可以更方便地与设备进行交互,并且可以方便地
四儿 四儿
1年前
未来手势交互将成为新一代“触屏”
手势追踪被视为人机交互(HCI)/人类数据交互(Humandatainteraction,HDI)中最直观的交互模式之一,是混合现实(XR)终端交互的最新趋势。在XR领域中,手部运动轨迹的感知与追踪是改善用户在不同技术领域和平台体验的一个重要组成部分。手部
文盘Rust——子命令提示,提高用户体验 | 京东云技术团队
上次我们聊到CLI的领域交互模式。在领域交互模式中,可能存在多层次的子命令。在使用过程中如果全评记忆的话,命令少还好,多了真心记不住。频繁help也是个很麻烦的事情。如果每次按'tab'键就可以提示或补齐命令是不是很方便呢。这一节我们就来说说'autoco
四儿 四儿
1年前
情感语音识别的应用与挑战
一、引言情感语音识别是一种通过分析人类语音中的情感信息实现智能化和个性化人机交互的技术。本文将探讨情感语音识别的应用领域、优势以及所面临的挑战。二、情感语音识别的应用领域娱乐产业:在娱乐产业中,情感语音识别技术被广泛应用于游戏、电影、音乐等领域。通过识别用