shell_client 0.1.0

Rust进程调试工具,封装了与Unix域套接字通信、命令行自动补全、以及内置命令处理等功能。Client 可以连接到一个进程,发送自定义命令,并处理来自该进程的输出。实现了命令行读取、命令解析、进程查找、自动补全、命令执行等功能,并提供了一个循环来不断读取用户输入并执行相应的命令
Documentation
//! 完成器抽象
mod attach_completer;
mod path_completer;
mod shell_completer;

pub use attach_completer::*;
pub use path_completer::*;
pub use shell_completer::*;

use linefeed::terminal::DefaultTerminal;
use linefeed::Completion;
use linefeed::Suffix;

use crate::tools;

/// 完成器
/// - filter 是否满足当前完成器的激活条件
/// - new 创建完成器
pub trait Completer: linefeed::complete::Completer<DefaultTerminal> {
    fn filter(w: &str, b: &str) -> bool
    where
        Self: Sized;
    fn new() -> Box<dyn Completer>
    where
        Self: Sized;
}

/// 生成自动完成条目
/// cmp_data 自动完成数据
/// word 输入
pub fn gen_autocomplete_item(
    cmp_data: &Vec<(String, String)>,
    word: &str,
) -> Option<Vec<Completion>> {
    let ops: Vec<Box<dyn Fn(&(String, String), &str) -> i32>> = vec![
        Box::new(|x: &(String, String), word: &str| -> i32 {
            if tools::is_prefix(&x.0, word) {
                0
            } else {
                -1
            }
        }),
        Box::new(|x: &(String, String), word: &str| -> i32 {
            if tools::is_prefix(&x.1, word) {
                1
            } else {
                -1
            }
        }),
        Box::new(|x: &(String, String), word: &str| -> i32 {
            if tools::is_prefix_nocase(&x.0, word) {
                0
            } else {
                -1
            }
        }),
        Box::new(|x: &(String, String), word: &str| -> i32 {
            if tools::is_prefix_nocase(&x.1, word) {
                1
            } else {
                -1
            }
        }),
        Box::new(|x: &(String, String), word: &str| -> i32 {
            if tools::contain_nocase(&x.1, word) {
                1
            } else {
                -1
            }
        }),
    ];
    for op in ops {
        let col: Vec<Completion> = cmp_data
            .iter()
            .filter_map(|x| match op(x, word) {
                0 => Some(Completion {
                    completion: x.0.clone(),
                    display: Some(format!("{}({})", x.0, x.1)),
                    suffix: Suffix::Default,
                }),
                1 => Some(Completion {
                    completion: x.1.clone(),
                    display: Some(format!("{}({})", x.0, x.1)),
                    suffix: Suffix::Default,
                }),
                _ => None,
            })
            .collect();
        if col.is_empty() {
            continue;
        }
        return Some(col);
    }
    None
}