...

Rust 开发命令行 ls 命令

效果如下:

image

视频链接: https://www.bilibili.com/video/BV1N4NizuE66?t=480.2

新建项目

cargo new bestls && cd bestls

添加依赖

修改 Cargo.toml,添加依赖 clap 和 owo-colors

[package]  
name = "bestls"  
version = "0.1.0"  
edition = "2024"  
  
[dependencies]  
clap = { version = "4.5.39", features = ["derive"] }  
owo-colors = "4.2.1"  
strum = {version = "0.27", features = ["derive"]}  
strum_macros = "0.27"
tabled = "0.20.0"
chrono = "0.4.41"
serde = {version = "1.0", features = ["derive"]}  
serde_json = "1.0"

clap 命令行使用示例

修改 src/main.rs

use std::fs;
use std::path::PathBuf;
use owo_colors::OwoColorize;
use clap::Parser;

#[derive(Debug, Parser)]
#[command(version, about, long_about = "Best Ls command ever")]
struct Cli {
    path: Option<PathBuf>,
}

fn main() {
    let cli = Cli::parse();
    let path = cli.path.unwrap_or(PathBuf::from("."));
    if let Ok(does_exist)  = fs::exists(&path) {
        if does_exist {
            
        } else { 
            println!("{}", "Path does not exist".red())
        }
    }
    println!("{}", path.display());
}

构建

cargo build

测试

target/debug/bestls -h
target/debug/bestls -V
target/debug/bestls ~/Documents/1

完整代码

修改 src/main.rs

use std::fs;
use std::path::{Path, PathBuf};
use chrono::{DateTime, Utc};
use owo_colors::OwoColorize;
use clap::Parser;
use serde::Serialize;
use strum_macros::Display;
use tabled::{Table, Tabled};
use tabled::settings::object::{Columns, Rows};
use tabled::settings::{Color, Style};

#[derive(Debug, Parser)]
#[command(version, about, long_about = "Best Ls command ever")]
struct Cli {
    path: Option<PathBuf>,
    #[arg(short, long)]
    json: bool,
}

#[derive(Debug, Display, Serialize)]
enum EntryType {
    File,
    Dir,
}

#[derive(Debug, Tabled, Serialize)]
struct FileEntry {
    #[tabled(rename = "Name")]
    name:String,
    #[tabled(rename = "Type")]
    e_type: EntryType,
    #[tabled(rename = "Size B")]
    len_bytes: u64,
    modified: String
}

fn main() {
    let cli = Cli::parse();
    let path = cli.path.unwrap_or(PathBuf::from("."));
    if let Ok(does_exist)  = fs::exists(&path) {
        if does_exist {
            if cli.json {
                let get_files = get_files(&path);
                println!("{}", serde_json::to_string(&get_files).unwrap_or("cannot parse json".to_string()));
            } else {
                print_table(path);
            }
        } else {
            println!("{}", "Path does not exist".red())
        }
    } else {
        println!("{}", "error reading directory".red())
    }
}

fn get_files(path: &Path) -> Vec<FileEntry > {
    let mut data = Vec::default();
    if let Ok(read_dir) = fs::read_dir(path) {
        for entry in read_dir {
            if let Ok(file) = entry {
                map_data(file, &mut data);
            }
        }
    }
    data
}

fn map_data(file: fs::DirEntry, data: &mut Vec<FileEntry>) {
    if let Ok(meta)  = fs::metadata(&file.path()) {
        data.push(
            FileEntry {
                name:  file.file_name().into_string().unwrap_or("unknown name".into()),
                e_type: if meta.is_dir() {EntryType::Dir} else {EntryType::File},
                len_bytes:meta.len(),
                modified: if let Ok(modi) = meta.modified() {
                    let date: DateTime<Utc> = modi.into();
                    format!("{}", date.format("%a %b %e %Y"))
                } else {
                    String::default()
                }
            }
        );
    }
}

fn print_table(path: PathBuf) {
    let get_files = get_files(&path);
    let mut table = Table::new(get_files);
    table.with(Style::rounded());
    table.modify(Columns::first(), Color::FG_BRIGHT_CYAN);
    table.modify(Columns::one(2), Color::FG_BRIGHT_MAGENTA);
    table.modify(Columns::one(3), Color::FG_BRIGHT_YELLOW);
    table.modify(Rows::first(), Color::FG_BRIGHT_GREEN);
    println!("{}", table)
}

编译

cargo build

测试

target/debug/bestls ./target
target/debug/bestls ./target -j

参考

posted @ 2025-06-25 17:01  韩志超  阅读(21)  评论(0)    收藏  举报