cfun/
c_cmd.rs

1#[cfg(feature = "cmd")]
2use anstyle::{
3    AnsiColor::{BrightBlue, BrightCyan, BrightGreen, Green, Red},
4    Color::Ansi,
5    Style,
6};
7#[cfg(feature = "cmd")]
8use chardet::detect;
9#[cfg(feature = "cmd")]
10use encoding_rs::{Encoding, GBK, UTF_8, WINDOWS_1252};
11#[cfg(feature = "cmd")]
12use serde::{Deserialize, Serialize};
13
14#[cfg(feature = "cmd")]
15fn detect_encoding(buf: &[u8]) -> &'static Encoding {
16    let result = detect(buf);
17    let encoding_name = result.0.to_lowercase();
18    let encoding_label = encoding_name.as_bytes();
19
20    // 检测 BOM 编码
21    if let Some((bom_encoding, _)) = Encoding::for_bom(buf) {
22        return bom_encoding;
23    }
24
25    // 尝试使用 chardet 检测的编码
26    if let Some(encoding) = Encoding::for_label(encoding_label) {
27        return encoding;
28    }
29
30    // 如果无法确定编码,尝试 UTF-8、GBK 和 ISO-8859-1
31    let (_, _, utf8_had_errors) = UTF_8.decode(buf);
32    if !utf8_had_errors {
33        return UTF_8;
34    }
35
36    let (_, _, gbk_had_errors) = GBK.decode(buf);
37    if !gbk_had_errors {
38        return GBK;
39    }
40
41    WINDOWS_1252
42}
43/// config the style of clap lib help info
44/// # Example
45/// ```
46/// #[derive(Parser, Debug)]
47/// #[clap(author, version, about)]
48/// #[command(styles=clap_help_styles())]
49/// pub struct CFunArgs {
50///
51/// }
52/// ```
53#[cfg(feature = "cmd")]
54pub fn clap_help_styles() -> clap::builder::Styles {
55    clap::builder::Styles::styled()
56        .usage(Style::new().fg_color(Some(Ansi(BrightBlue))))
57        .header(Style::new().fg_color(Some(Ansi(BrightBlue))))
58        .literal(Style::new().fg_color(Some(Ansi(BrightGreen))))
59        .invalid(Style::new().bold().fg_color(Some(Ansi(Red))))
60        .error(Style::new().bold().fg_color(Some(Ansi(Red))))
61        .valid(Style::new().fg_color(Some(Ansi(Green))))
62        .placeholder(Style::new().fg_color(Some(Ansi(BrightCyan))))
63}
64
65#[cfg(feature = "cmd")]
66#[derive(Debug, Deserialize, Serialize)]
67pub struct CmdResult {
68    pub code: i32,
69    pub stdout: String,
70    pub stderr: String,
71}
72/// exec a command and get the result,if get the command's exit code failed, default to -1
73#[cfg(feature = "cmd")]
74pub fn exec(cmd: &str, args: &Vec<&str>) -> Result<CmdResult, std::io::Error> {
75    use std::process::Command;
76    let mut cmd = Command::new(cmd);
77    if !args.is_empty() {
78        cmd.args(args);
79    }
80    let ret = cmd.output();
81    let Ok(ret) = ret else {
82        return Err(ret.unwrap_err());
83    };
84
85    let code = ret.status.code().unwrap_or(-1);
86    let coding = detect_encoding(&ret.stdout);
87    println!("{}", coding.name());
88    let stdout = coding.decode(&ret.stdout).0.to_string();
89    let coding = detect_encoding(&ret.stderr);
90    let stderr = coding.decode(&ret.stderr).0.to_string();
91    println!("{}", coding.name());
92
93    Ok(CmdResult {
94        code,
95        stdout,
96        stderr,
97    })
98}
99
100#[test]
101#[cfg(feature = "cmd")]
102fn test_exec() {
103    let ret = exec("cmd", &vec!["dir"]).unwrap();
104    println!("{:?}", ret);
105}