- Java锁的逻辑(结合对象头和ObjectMonitor)
- 还在用饼状图?来瞧瞧这些炫酷的百分比可视化新图形(附代码实现)⛵
- 自动注册实体类到EntityFrameworkCore上下文,并适配ABP及ABPVNext
- 基于Sklearn机器学习代码实战
上次我们聊到 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实现详解 。
#[derive(Debug, Clone)]
pub struct SubCmd {
pub level: usize,
pub command_name: String,
pub subcommands: Vec<String>,
}
SubCmd 结构体包含:命令级别,命令名称,以及该命令包含的子命令信息,以便在实现实现 autocomplete 时定位命令和子命令的范围 。
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);
}
#[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——子命令提示,提高用户体验的文章就讲到这里了,如果你想了解更多关于文盘Rust——子命令提示,提高用户体验的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
我有这个 html 代码: HELLO WORLD! X V HELLO WORLD! X V 我想按 X(类关闭)将父 div 的高度更改为 20px 并显示 V(类打开),但在每个 d
在会计应用程序的许多不同实现中,有两种主要的数据库设计方法来保存日志和分类帐数据。 只保留 Journal 信息,然后 Ledger 只是 Journal 的一个 View (因为 journal 总
我想在另一个子里面有一个子, sub a { sub b { } } 我想为每次调用 sub b 创建一个新的 sub a 实例。有没有办法在 Perl 中做到这一点? 当我运行上面的
我有一些代码正在查找重复项并突出显示单元格: Private Sub cmdDups_Click() Dim Rng As Range Dim cel As Range Set Rng = ThisW
可能有一个简单的解决方案,但我很难过。 我有一个包含一个 ID 字段的主表。在两个可能的字段中有一个具有该 ID 的子表。想象一个由选手 A 和选手 B 组成的 double 队。Master 表将有
假设我有一个包含对象的数组: [ { "id": "5a97e047f826a0111b754beb", "name": "Hogwarts", "parentId": "
我正在尝试对 MySQL 数据库表执行一对父/子模型的批量插入,但似乎无法使用标准的 ActiveRecord 功能来完成。所以,我尝试了 activerecord-import gem,但它也不支持
我有一个带有多个子类的父抽象类。最终,我希望通过 GUI 中的进度条显示子类中完成的进度。 我目前所做的,我意识到这是行不通的,是在父类中声明为每个子类将覆盖的虚拟方法的事件方法定义。所以像: pub
是否可以通过键数组在对象中设置变量?例如我有这个对象: var obj = {'outer': {'inner': 'value'} }; 并希望设置由键数组选择的值: var keys = ['ou
我有一个名为 companies 的 MySQL 表,如下所示: +---------+-----------+-----------+ | id_comp | comp_name | id_pare
我正在尝试使用 sublime text 在 sublime text 上的 ionic 上打开我的第一个应用程序。它给了我一个“找不到命令”的错误。如何修复? 我试过这些命令: sudo rm -r
不好意思问,但我正在使用 webapp2,我正在设计一个解决方案,以便更容易定义路由 based on this google webapp2 route function .但这完全取决于能够在子级
我有代表树的数字字符串(我不知道是否有官方名称): 012323301212 上面的例子代表了 2 棵树。根用 0 表示。根的直接子代为“1”,“1”的直接子代为“2”,依此类推。我需要将它们分组到由
是否可以在当前 Activity 之上添加 Activity 。例如,假设我单击一个按钮,然后它将第二个 Activity 添加到当前 Activity 。而第二个 Activity 只覆盖了我当前
我很难思考如何为子资源建模。 以作者的书籍为例。你可以有 N 本书,每本书只有一位作者。 /books GET /books POST /books/id PUT /books/id DELETE 到
有人可以向我解释以下内容(python 2.7) 来自已解析文件的两个字符串数字: '410.9''410.9 '(注意尾随空格) A_LIST = ['410.9 '] '410.9' in '41
背景 在 PowerShell 中构建 hash table 是很常见的通过特定属性快速访问对象,例如以 LastName 为基础建立索引: $List = ConvertFrom-Csv @' I
我真的很难弄清楚如何调用嵌套 Polymer Web 组件的函数。 这是标记: rise-distribution组件有 canPlay我想从 rise-playlist
我写了一个小工具转储(以 dot 格式)一个项目的依赖关系图,其中所有位于同一目录中的文件都聚集在一个集群中。当我尝试生成包含相应图形的 pdf 时,dot开始哭: 命令 dot -Tpdf trim
给定一个 CODE ref,是否可以: 访问该 CODE ref 的解析树 通过指定 CODE ref 的解析树来创建一个新的 CODE ref,该解析树可以包含在 1 中返回的解析树的元素 通常我们
我是一名优秀的程序员,十分优秀!