当前位置: 首页 > news >正文

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

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

实现过程

其实,rustyline 已经为我们提供了基本的helper功能框架,其中包括了completer。我们来看代码,文件位置src/interact/cli.rs

#[derive(Helper)]
struct MyHelper {completer: CommandCompleter,highlighter: MatchingBracketHighlighter,validator: MatchingBracketValidator,hinter: HistoryHinter,colored_prompt: String,
}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);// let mut rl = Editor::<()>::new();rl.set_helper(Some(h));......}

首先定义 MyHelper 结构体, 需要实现 Completer + Hinter + Highlighter + Validator trait。然后通过rustyline的set_helper函数加载我们定义好的helper。在MyHelper 结构体中,需要我们自己来实现completer的逻辑。

Sub command autocompleter实现详解

  • SubCmd 结构体
#[derive(Debug, Clone)]
pub struct SubCmd {pub level: usize,pub command_name: String,pub subcommands: Vec<String>,
}

SubCmd 结构体包含:命令级别,命令名称,以及该命令包含的子命令信息,以便在实现实现 autocomplete 时定位命令和子命令的范围

  • 在程序启动时遍历所有的command,src/cmd/rootcmd.rs 中的all_subcommand函数负责收集所有命令并转换为Vec
pub fn all_subcommand(app: &clap_Command, beginlevel: usize, input: &mut Vec<SubCmd>) {let nextlevel = beginlevel + 1;let mut subcmds = vec![];for iterm in app.get_subcommands() {subcmds.push(iterm.get_name().to_string());if iterm.has_subcommands() {all_subcommand(iterm, nextlevel, input);} else {if beginlevel == 0 {all_subcommand(iterm, nextlevel, input);}}}let subcommand = SubCmd {level: beginlevel,command_name: app.get_name().to_string(),subcommands: subcmds,};input.push(subcommand);
}
  • CommandCompleter 子命令自动补充功能的核心部分
#[derive(Debug, Clone)]
pub struct CommandCompleter {subcommands: Vec<SubCmd>,
}impl CommandCompleter {pub fn new(subcmds: Vec<SubCmd>) -> Self {Self {subcommands: subcmds,}}//获取level下所有可能的子命令pub fn level_possible_cmd(&self, level: usize) ->   Vec<String> {let mut subcmds = vec![];let cmds = self.subcommands.clone();for iterm in cmds {if iterm.level == level {subcmds.push(iterm.command_name.clone());}}return subcmds;}//获取level下某字符串开头的子命令pub fn level_prefix_possible_cmd(&self, level: usize,   prefix: &str) -> Vec<String> {let mut subcmds = vec![];let cmds = self.subcommands.clone();for iterm in cmds {if iterm.level == level && iterm.command_name.  starts_with(prefix) {subcmds.push(iterm.command_name);}}return subcmds;}//获取某level 下某subcommand的所有子命令pub fn level_cmd_possible_sub_cmd(&self, level:   usize, cmd: String) -> Vec<String> {let mut subcmds = vec![];let cmds = self.subcommands.clone();for iterm in cmds {if iterm.level == level && iterm.command_name   == cmd {subcmds = iterm.subcommands.clone();}}return subcmds;}//获取某level 下某subcommand的所有prefix子命令pub fn level_cmd_possible_prefix_sub_cmd(&self,level: usize,cmd: String,prefix: &str,) -> Vec<String> {let mut subcmds = vec![];let cmds = self.subcommands.clone();for iterm in cmds {if iterm.level == level && iterm.command_name   == cmd {for i in iterm.subcommands {if i.starts_with(prefix) {subcmds.push(i);}}}}return subcmds;}pub fn complete_cmd(&self, line: &str, pos: usize) ->   Result<(usize, Vec<Pair>)> {let mut entries: Vec<Pair> = Vec::new();let d: Vec<_> = line.split(' ').collect();if d.len() == 1 {if d.last() == Some(&"") {for str in self.level_possible_cmd(1) {let mut replace = str.clone();replace.push_str(" ");entries.push(Pair {display: str.clone(),replacement: replace,});}return Ok((pos, entries));}if let Some(last) = d.last() {for str in self.level_prefix_possible_cmd  (1, *last) {let mut replace = str.clone();replace.push_str(" ");entries.push(Pair {display: str.clone(),replacement: replace,});}return Ok((pos - last.len(), entries));}}if d.last() == Some(&"") {for str in self.level_cmd_possible_sub_cmd(d.len() - 1,   d.get(d.len() - 2).unwrap().to_string()){let mut replace = str.clone();replace.push_str(" ");entries.push(Pair {display: str.clone(),replacement: replace,});}return Ok((pos, entries));}if let Some(last) = d.last() {for str in self.  level_cmd_possible_prefix_sub_cmd(d.len() - 1,d.get(d.len() - 2).unwrap().to_string(),*last,) {let mut replace = str.clone();replace.push_str(" ");entries.push(Pair {display: str.clone(),replacement: replace,});}return Ok((pos - last.len(), entries));}Ok((pos, entries))}
}impl Completer for CommandCompleter {type Candidate = Pair;fn complete(&self, line: &str, pos: usize, _ctx: &  Context<'_>) -> Result<(usize, Vec<Pair>)> {self.complete_cmd(line, pos)}
}

CommandCompleter 的实现部分比较多,大致包括两个部分,前一部分包括:获取某一级别下所有可能的子命令、获取某级别下某字符串开头的子命令、获取某级别下某个命令的所有子命令,等基本功能。这部分代码中有注释就不一一累述。

函数complete_cmd用来计算行中的位置以及在该位置的替换内容。

输入项是命令行的内容以及光标所在位置,输出项为在该位置需要替换的内容。比如,我们在提示符下输入 “root cm” root 下包含 cmd1、cmd2 两个子命令,此时如果按 'tab’键,complete_cmd 函数就会返回 (7,[cmd1,cmd2])。

作者:京东科技 贾世闻

来源:京东云开发者社区 转载请注明来源

相关文章:

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

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

同源策略简介

什么是同源策略 同源策略/SOP&#xff08;Same origin policy&#xff09;是一种约定&#xff0c;由 Netscape 公司 1995 年引入浏览器&#xff0c;它是浏览器最核心也最基本的安全功能&#xff0c;现在所有支持 JavaScript 的浏览器都会使用这个策略。如果缺少了同源策…...

数据量大,分析困难?试试pandas随机抽样

前言 在数据分析和机器学习领域&#xff0c;随机抽样是一个非常重要的技术。它可以帮助我们从大量的数据中获取一部分样本&#xff0c;以进行统计分析、建模和预测。而在Python中&#xff0c;pandas是一个非常强大的数据分析库&#xff0c;它提供了许多方便的函数和方法来处理…...

stm32---外部中断

一、EXTI STM32F10x外部中断/事件控制器&#xff08;EXTI&#xff09;包含多达20个用于产生事件/中断请求的边沿检测器。EXTI的每根输入线都可单独进行配置&#xff0c;以选择类型&#xff08;中断或事件&#xff09;和相应的触发事件&#xff08;上升沿触发、下降沿触发…...

电子企业MES管理系统实施的功能和流程有哪些

MES生产管理系统是一种应用于电子企业的管理系统&#xff0c;旨在提高生产效率、降低浪费、优化资源利用&#xff0c;并实时监控和改善生产过程。在电子企业中&#xff0c;实施MES管理系统对于实现精细化管理、增强信息互联、提高产品质量和交货期等方面具有重要作用。 一、MES…...

代码随想录二刷day24

提示&#xff1a;文章写完后&#xff0c;目录可以自动生成&#xff0c;如何生成可参考右边的帮助文档 文章目录 前言一、回溯法模板二、力扣77. 组合 前言 一、回溯法模板 void backtracking(参数) {if (终止条件) {存放结果;return;}for (选择&#xff1a;本层集合中元素&…...

谷粒商城篇章6 ---- P193-P210 ---- 异步线程池商品详情【分布式高级篇三】

目录 1. 异步 1.1 初始化线程的 4 种方式 1.1.1 继承 Thread 1.1.2 实现 Runnable 接口 1.1.3 实现 Callable 接口 FutureTask 1.1.4 线程池 1.1.5 以上 4 种方式总结&#xff1a; 1.2 线程池详解 1.2.1 初始化线程池的 2 种方式 1.2.1.1 使用 Executors 创建 1.2…...

gcc中的cc1 collect2

当运行gcc命令编译一个C程序时&#xff0c;我们可能认为这是一个简单的操作&#xff0c;但实际上&#xff0c;编译过程包含了多个步骤和子工具的调用。gcc通常作为一个前端&#xff0c;管理这些步骤并调用其他工具来完成特定的工作。其中&#xff0c;cc1和collect2是这些子工具…...

学习day59

昨天学了插槽&#xff0c;但是没有即笔记了 今天的是vuex 总体来说&#xff0c;vuex就是一个共享单车&#xff0c;每个人都可以使用他&#xff0c;也可也对他进行反馈。即把一个数据列为vuex&#xff0c;然后每个组件可以使用这个对象&#xff0c;也可也反过来反馈他 这一个设…...

Go Tip02 指针类型 、值类型和引用类型 、标识符的命名规范

文章目录 一、指针类型二、值类型和引用类型三、标识符的命名规范 一、指针类型 package mainimport "fmt"func main() {saylocation()}func saylocation() {// 指针类型// 基本数据类型&#xff0c;变量存的是值// 用&获取变量的地址// 基本数据类型在内存的布…...

CSS中如何实现文字跑马灯效果?

聚沙成塔每天进步一点点 ⭐ 专栏简介⭐ 跑马灯⭐ 写在最后 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 记得点击上方或者右侧链接订阅本专栏哦 几何带你启航前端之旅 欢迎来到前端入门之旅&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋…...

《昆明海晏村:修缮后的新生,历史与现代的完美交融》

在昆明市的东南角&#xff0c;有一处名为海晏村的地方&#xff0c;这里曾是滇池北岸的重要码头&#xff0c;也是滇池文化的发源地之一。近年来&#xff0c;海晏村经过精心修缮&#xff0c;焕发出新的生机&#xff0c;成为了一个集历史、文化、艺术于一体的旅游胜地。那么&#…...

C++ --- Day02 封装

stack栈类 stack.h #ifndef STACK_H #define STACK_H #include <iostream> #include<string> using namespace std; //自行封装一个栈的类&#xff0c;包含私有成员属性:栈的数组、记录栈顶的变量 //成员函数完成: //构造函数、析构函数、拷贝构造函数 //入栈、出…...

墨西哥专线清关有什么要求?

墨西哥专线的清关要求是根据当地法规和国际贸易协定而定的。以下是一些墨西哥专线清关的常见要求&#xff1a; 一、 清关文件 进口货物需要提供一系列文件&#xff0c;包括商业发票、装箱单、进口许可证、运输文件、保险文件等。这些文件需要准确、完整地填写&#xff0c;并且…...

SpringMVC中的JSR303与拦截器的使用

一&#xff0c;JSR303的概念 JSR303是Java中的一个标准&#xff0c;用于验证和校验JavaBean对象的属性的合法性。它提供了一组用于定义验证规则的注解&#xff0c;如NotNull、Min、Max等。在Spring MVC中&#xff0c;可以使用JSR303注解对请求参数进行校验。 1.2 为什么要使用J…...

神经网络 01(介绍)

一、神经网络 人工神经网络 (Artificial Neural Network&#xff0c;简写为ANN)也简称为神经网络 (NN)&#xff0c;是一种模仿生物神经网络结构和功能的 计算模型。人脑可以看做是一个生物神经网络&#xff0c;由众多的神经元连接而成。各个神经元传递复杂的电信号&#xff0c…...

【element-ui】el-date-picker 之picker-options时间选择区间禁用效果的实现

element-ui 时间选择器的时间区间禁用dom层引入:picker-option <el-date-pickerv-model"searchFormObj.workTime"clearablevalue-formate"yyyy-MM-dd":picker-options"pickerOptions"placeholder"请选择时间" ></el-date-pi…...

Exchange Serve各版本说明及下载

Exchange Server各版本说明及官方下载 简介Exchange Server2019Exchange Server2016Exchange Server2013 本文为Exchange Server2013、Exchange Server2016及Exchange Server2019官方下载汇总&#xff0c;记录各版本号及发布日期的Exchange Server软件包 未经本人允许请勿转载&…...

软件测试 | 当面试时被问到“搭建过测试环境吗”, 身为小白要怎么回答?

首先&#xff0c;回答这个问题之前&#xff0c;你需要明确你所面试的职位需要什么样的测试环境。一些公司可能需要测试基础软件&#xff0c;而另一些公司则可能需要测试复杂的软件系统。因此&#xff0c;在回答这个问题之前&#xff0c;你需要了解面试职位所需要的测试环境是什…...

15.3K Star,超好用的开源协作式数字白板:tldraw

大家好&#xff0c;我是TJ 今天给大家推荐一个开源协作式数字白板&#xff1a;tldraw。 tldraw的编辑器、用户界面和其他底层库都是开源的&#xff0c;你可以在它的开源仓库中找到它们。它们也在NPM上分发&#xff0c;提供开发者使用。您可以使用tlDraw为您的产品创建一个临时…...

MGR新节点RECOVERING状态的分析与解决:caching_sha2_password验证插件的影响

起因 在GreatSQL社区上有一位用户提出了“手工构建MGR碰到的次节点一直处于recovering状态”&#xff0c;经过排查后&#xff0c;发现了是因为新密码验证插件caching_sha2_password导致的从节点一直无法连接主节点&#xff0c;帖子地址&#xff1a;(https://greatsql.cn/threa…...

git merging两边都被删除的文件

1. 场景&#xff1a; merge 另一个分支到当前分支&#xff0c;解决完冲突列表中的冲突后&#xff0c;发现项目任然在 merging 中&#xff0c;无法进行git下一步操作。 2. 原因&#xff1a; 通过 git status 发现一个文件&#xff0c;显示表面&#xff0c;该文件在当前分支和…...

项目--苍穹外卖

1.| constant | 存放相关常量类 | | context | 存放上下文类 | | enumeration | 项目的枚举类存储 | | exception | 存放自定义异常类 | | json | 处理json转换的类 | | properties | 存放SpringBoot相关的配置属性类 | | result | 返回结果类的封装 | | utils | 常用工具类 | …...

从零开发短视频电商 使用Spring WebClient发起远程Http调用

文章目录 依赖使用创建WebClient实例创建带有超时的WebClient实例示例 请求准备获取响应 高级过滤器自定义过滤器 自定义线程池自定义WebClient连接池开启日志错误处理最佳实践 示例异步请求同步请求上传文件重试过滤错误错误处理 参考 Spring WebClient 是 Spring WebFlux 项目…...

Python实现成语接龙

如图&#xff1a; 详细代码实现&#xff1a; # coding:utf-8 import string import pypinyin import sys import randomprint("初始化中&#xff0c;请稍等……")def main():f2 open(./idiom.txt, r, encodingutf-8)f f2.read() # 一次性读取完成new3_list f.sp…...

继续上一个爬虫,所以说selenium加browsermobproxy

继续&#xff0c;书接上回&#xff0c;这次我通过jsrpc&#xff0c;也学会了不少逆向的知识&#xff0c;感觉对于一般的网站应该都能应付了。当然我说的是简单的网站&#xff0c;遇到那些混淆的&#xff0c;还有那种猿人学里面的题目&#xff0c;还是免谈了。那种需要的水平太高…...

Sentinel服务熔断和流控

Sentinel服务熔断和流控 简介 Sentinel ​ 随着微服务的流行&#xff0c;服务和服务之间的稳定性变得越来越重要。Sentinel 是面向分布式服务架构的流量控制组件&#xff0c;主要以流量为切入点&#xff0c;从限流、流量整形、熔断降级、系统负载保护、热点防护等多个维度来…...

01_TMS320F28004x系列MCU介绍和资料搜集

1. TI C2000 实时微控制器 TI公司在处理器方面的产品线有&#xff1a;基于ARM内核的微控制器/微处理器、MSP430微控制器、C2000系列实时微控制器、还有数字信号处理器&#xff08;DSP&#xff09;。 其中&#xff0c;C2000是TI公司专门针对实时控制推出的32位微控制器。TI公司…...

JavaScript中获取对象属性的不同方法

JavaScript中获取对象属性的不同方法 文章目录 JavaScript中获取对象属性的不同方法一、点记法二、方括号记法三、Object.keys()方法四、Object.values()方法五、Object.entries()方法六、Object.getOwnPropertyNames()方法七、Object.getOwnPropertyDescriptors()方法 JavaScr…...

【STM32教程】第四章 STM32的外部中断EXTI

案例代码及相关资料下载链接&#xff1a; 链接&#xff1a;https://pan.baidu.com/s/1hsIibEmsB91xFclJd-YTYA?pwdjauj 提取码&#xff1a;jauj 1 中断系统 1.1 中断的概念 中断系统的定义&#xff1a;中断是指在主程序运行过程中&#xff0c;出现了特定的中断触发条件…...

外贸公司网站建设费用/seo搜索引擎优化排名

电梯控制算法 https://blog.csdn.net/nameofcsdn/article/details/106874615 两个电梯合作&#xff0c;也可以采取不对称的方式。 一&#xff0c;限层策略 限层策略下&#xff0c;2个电梯是不联动的&#xff0c;其实就是2个独立的电梯。 https://blog.csdn.net/nameofcsdn/a…...

珠海新盈科技有限公司 网站建设/竞价代运营

通俗的讲&#xff0c;Web服务器传送(serves)页面使浏览器可以浏览&#xff0c;然而应用程序服务器提供的是客户端应用程序可以调用(call)的方法(methods)。确切一点&#xff0c;你可以说&#xff1a;Web服务器专门处理HTTP请求(request)&#xff0c;但是应用程序服务器是通过很…...

网站源码开发/日本网络ip地址域名

前言&#xff1a;今天开始开启一个新篇章的学习&#xff0c;那就是games101闫令琪老师讲的《现代计算机图形学入门》课程&#xff0c;我会根据闫老师每节课讲的内容记录重点笔记&#xff0c;每节课都会整理一篇发布出来&#xff0c;希望自己可以坚持下去&#xff0c;从图形学小…...

网站建设包括哪些方面选择题/推销产品怎么推广

2019独角兽企业重金招聘Python工程师标准>>> 阿里云的分析型数据库&#xff08;AnalyticDB&#xff09;和E-MapReduce&#xff08;简称EMR&#xff09;在大数据场景下非常有用&#xff0c;本文将介绍如何尝试打通两个产品&#xff0c;将通过EMR中自带的开源工具Sqoo…...

网站实现多模板切换/网站有吗免费的

这是bootCDN上引用的bootstrap前端框架套件&#xff0c;由多个框架组合而成&#xff0c;方便平时学习和测试使用。生产环境要仔细琢磨一下&#xff0c;不要用开发版&#xff0c;而要用生产版。bootCDN的地址是&#xff1a;https://www.bootcdn.cn/ &#xff0c;是由bootstrap中…...

电商网站 开发成本/邹平县seo网页优化外包

本文实例讲述了Python类装饰器。分享给大家供大家参考&#xff0c;具体如下&#xff1a;编写类装饰器类装饰器类似于函数装饰器的概念&#xff0c;但它应用于类&#xff0c;它们可以用于管理类自身&#xff0c;或者用来拦截实例创建调用以管理实例。单体类由于类装饰器可以拦截…...