mirror of
https://github.com/LHY0125/PathEditor.git
synced 2026-06-29 01:45:54 +08:00
feat: CLI 补全至 GUI 功能 100% 对等 — 新增 9 条命令
新增: edit, move-up, move-down, clean, enable, disable, import, export, backup core: registry.rs +clean_paths, fs.rs +import_paths +export_paths CLI 特有增强: move-up/move-down 支持 --steps N 一次移动多格 Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
+203
-18
@@ -28,18 +28,67 @@ enum Command {
|
||||
index: usize,
|
||||
#[arg(short, long)] system: bool,
|
||||
},
|
||||
/// 编辑指定位置的路径
|
||||
Edit {
|
||||
index: usize,
|
||||
new_path: String,
|
||||
#[arg(short, long)] system: bool,
|
||||
},
|
||||
/// 上移路径(--steps 指定移动格数,默认 1)
|
||||
MoveUp {
|
||||
index: usize,
|
||||
#[arg(long, default_value = "1")] steps: usize,
|
||||
#[arg(short, long)] system: bool,
|
||||
},
|
||||
/// 下移路径(--steps 指定移动格数,默认 1)
|
||||
MoveDown {
|
||||
index: usize,
|
||||
#[arg(long, default_value = "1")] steps: usize,
|
||||
#[arg(short, long)] system: bool,
|
||||
},
|
||||
/// 清理无效和重复路径
|
||||
Clean {
|
||||
#[arg(short, long)] system: bool,
|
||||
#[arg(short, long)] user: bool,
|
||||
#[arg(long)] dry_run: bool,
|
||||
#[arg(long)] json: bool,
|
||||
},
|
||||
/// 启用指定位置的路径
|
||||
Enable {
|
||||
index: usize,
|
||||
#[arg(short, long)] system: bool,
|
||||
#[arg(short, long)] user: bool,
|
||||
},
|
||||
/// 禁用指定位置的路径
|
||||
Disable {
|
||||
index: usize,
|
||||
#[arg(short, long)] system: bool,
|
||||
#[arg(short, long)] user: bool,
|
||||
},
|
||||
/// 从文件导入 PATH(JSON/CSV/TXT)
|
||||
Import {
|
||||
file: String,
|
||||
#[arg(long, default_value = "both")] target: String,
|
||||
},
|
||||
/// 导出 PATH 为文件
|
||||
Export {
|
||||
#[arg(long, default_value = "json")] format: String,
|
||||
#[arg(short, long)] output: Option<String>,
|
||||
},
|
||||
/// 创建注册表备份
|
||||
Backup,
|
||||
/// 检测可执行文件冲突
|
||||
Conflicts { #[arg(long)] json: bool },
|
||||
/// 列出 PATH 中可执行文件
|
||||
/// 列出 PATH 目录中的可执行文件
|
||||
Scan {
|
||||
#[arg(long)] query: Option<String>,
|
||||
#[arg(long)] json: bool,
|
||||
},
|
||||
/// 检查管理员权限
|
||||
CheckAdmin { #[arg(long)] json: bool },
|
||||
/// 管理配置文件
|
||||
#[command(subcommand)]
|
||||
Profile(ProfileCmd),
|
||||
/// 检查管理员权限
|
||||
CheckAdmin { #[arg(long)] json: bool },
|
||||
}
|
||||
|
||||
#[derive(Subcommand)]
|
||||
@@ -65,6 +114,21 @@ fn pick_target(system: bool, _user: bool) -> &'static str {
|
||||
if system { "system" } else { "user" }
|
||||
}
|
||||
|
||||
type SaveFn = fn(Vec<String>) -> Result<(), String>;
|
||||
|
||||
fn load_and_save(system: bool, f: impl FnOnce(Vec<String>) -> Vec<String>) {
|
||||
let target = pick_target(system, false);
|
||||
let (list, save): (Vec<String>, SaveFn) = if target == "system" {
|
||||
(core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e)),
|
||||
core::registry::save_system_paths)
|
||||
} else {
|
||||
(core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e)),
|
||||
core::registry::save_user_paths)
|
||||
};
|
||||
let new_list = f(list);
|
||||
save(new_list).unwrap_or_else(|e| exit_err(&e));
|
||||
}
|
||||
|
||||
// ── 命令实现 ──
|
||||
|
||||
fn cmd_list(system: bool, user: bool, json_out: bool) {
|
||||
@@ -93,34 +157,146 @@ fn cmd_list(system: bool, user: bool, json_out: bool) {
|
||||
|
||||
fn cmd_add(path: String, system: bool, user: bool) {
|
||||
let target = pick_target(system, user);
|
||||
let (mut list, save_fn): (Vec<String>, _) = if target == "system" {
|
||||
(core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e)),
|
||||
core::registry::save_system_paths as fn(Vec<String>) -> Result<(), String>)
|
||||
} else {
|
||||
(core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e)),
|
||||
core::registry::save_user_paths as fn(Vec<String>) -> Result<(), String>)
|
||||
};
|
||||
list.push(path.clone());
|
||||
save_fn(list).unwrap_or_else(|e| exit_err(&e));
|
||||
load_and_save(system || false, |mut list| {
|
||||
list.push(path.clone());
|
||||
list
|
||||
});
|
||||
let label = if target == "system" { "系统" } else { "用户" };
|
||||
println!("已添加到{} PATH: {path}", label);
|
||||
}
|
||||
|
||||
fn cmd_remove(index: usize, system: bool) {
|
||||
let target = pick_target(system, false);
|
||||
let (mut list, save_fn): (Vec<String>, _) = if target == "system" {
|
||||
(core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e)),
|
||||
core::registry::save_system_paths as fn(Vec<String>) -> Result<(), String>)
|
||||
let mut list = if target == "system" {
|
||||
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
} else {
|
||||
(core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e)),
|
||||
core::registry::save_user_paths as fn(Vec<String>) -> Result<(), String>)
|
||||
core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
};
|
||||
if index >= list.len() { exit_err(&format!("索引 {index} 超出范围 (共 {} 条)", list.len())); }
|
||||
let removed = list.remove(index);
|
||||
save_fn(list).unwrap_or_else(|e| exit_err(&e));
|
||||
let save: SaveFn = if target == "system" { core::registry::save_system_paths } else { core::registry::save_user_paths };
|
||||
save(list).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("已删除: {removed}");
|
||||
}
|
||||
|
||||
fn cmd_edit(index: usize, new_path: String, system: bool) {
|
||||
let target = pick_target(system, false);
|
||||
let mut list = if target == "system" {
|
||||
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
} else {
|
||||
core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
};
|
||||
if index >= list.len() { exit_err(&format!("索引 {index} 超出范围 (共 {} 条)", list.len())); }
|
||||
let old = std::mem::replace(&mut list[index], new_path.clone());
|
||||
let save: SaveFn = if target == "system" { core::registry::save_system_paths } else { core::registry::save_user_paths };
|
||||
save(list).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("已编辑: {old} → {new_path}");
|
||||
}
|
||||
|
||||
fn cmd_move(index: usize, steps: usize, system: bool, up: bool) {
|
||||
load_and_save(system || false, |mut list| {
|
||||
if index >= list.len() { exit_err(&format!("索引 {index} 超出范围 (共 {} 条)", list.len())); }
|
||||
let end = if up {
|
||||
if steps > index { 0 } else { index - steps }
|
||||
} else {
|
||||
let max = list.len() - 1;
|
||||
if index + steps > max { max } else { index + steps }
|
||||
};
|
||||
let removed = list.remove(index);
|
||||
list.insert(end, removed);
|
||||
list
|
||||
});
|
||||
let dir = if up { "上移" } else { "下移" };
|
||||
println!("{dir} {steps} 格完成");
|
||||
}
|
||||
|
||||
fn cmd_clean(system: bool, user: bool, dry_run: bool, json_out: bool) {
|
||||
let target = pick_target(system, user);
|
||||
let list = if target == "system" {
|
||||
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
} else {
|
||||
core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
};
|
||||
let (kept, removed) = core::registry::clean_paths(list);
|
||||
|
||||
if json_out {
|
||||
println!("{}", json!({ "kept": kept, "removed": removed, "kept_count": kept.len(), "removed_count": removed.len() }).to_string());
|
||||
} else if dry_run {
|
||||
println!("═══ 将被移除({} 条)═══", removed.len());
|
||||
for r in &removed { println!(" ✗ {}", r); }
|
||||
println!("═══ 将保留({} 条)═══", kept.len());
|
||||
for k in &kept { println!(" ✓ {}", k); }
|
||||
} else {
|
||||
let kept_count = kept.len();
|
||||
let save: SaveFn = if target == "system" { core::registry::save_system_paths } else { core::registry::save_user_paths };
|
||||
save(kept).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("清理完成:移除 {} 条,保留 {} 条", removed.len(), kept_count);
|
||||
if !removed.is_empty() {
|
||||
for r in &removed { println!(" 已移除: {}", r); }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_toggle(index: usize, system: bool, user: bool, enable: bool) {
|
||||
let target = pick_target(system, user);
|
||||
let list = if target == "system" {
|
||||
core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
} else {
|
||||
core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e))
|
||||
};
|
||||
if index >= list.len() { exit_err(&format!("索引 {index} 超出范围 (共 {} 条)", list.len())); }
|
||||
let path = &list[index];
|
||||
|
||||
let (mut sys_dis, mut usr_dis) = core::disabled::load_disabled_state().unwrap_or_else(|_| (vec![], vec![]));
|
||||
let target_list: &mut Vec<String> = if target == "system" { &mut sys_dis } else { &mut usr_dis };
|
||||
|
||||
if enable {
|
||||
target_list.retain(|p| p != path);
|
||||
} else if !target_list.contains(path) {
|
||||
target_list.push(path.clone());
|
||||
}
|
||||
core::disabled::save_disabled_state(sys_dis, usr_dis).unwrap_or_else(|e| exit_err(&e));
|
||||
let action = if enable { "启用" } else { "禁用" };
|
||||
println!("已{action}: {path}");
|
||||
}
|
||||
|
||||
fn cmd_import(file: String, target: String) {
|
||||
let content = core::fs::read_text_file(&file).unwrap_or_else(|e| exit_err(&e));
|
||||
let (sys, usr) = core::fs::import_paths(&file, &content).unwrap_or_else(|e| exit_err(&e));
|
||||
match target.as_str() {
|
||||
"system" => {
|
||||
core::registry::save_system_paths(sys).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("已导入到系统 PATH");
|
||||
}
|
||||
"user" => {
|
||||
core::registry::save_user_paths(usr).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("已导入到用户 PATH");
|
||||
}
|
||||
_ => {
|
||||
core::registry::save_system_paths(sys).unwrap_or_else(|e| exit_err(&e));
|
||||
core::registry::save_user_paths(usr).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("已导入到系统 + 用户 PATH");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_export(format: String, output: Option<String>) {
|
||||
let sys = core::registry::load_system_paths().unwrap_or_else(|e| exit_err(&e));
|
||||
let usr = core::registry::load_user_paths().unwrap_or_else(|e| exit_err(&e));
|
||||
let content = core::fs::export_paths(&sys, &usr, &format);
|
||||
if let Some(path) = output {
|
||||
std::fs::write(&path, &content).unwrap_or_else(|e| exit_err(&format!("无法写入文件: {e}")));
|
||||
println!("已导出到: {path}");
|
||||
} else {
|
||||
println!("{content}");
|
||||
}
|
||||
}
|
||||
|
||||
fn cmd_backup() {
|
||||
let path = core::backup::backup_registry(None).unwrap_or_else(|e| exit_err(&e));
|
||||
println!("备份已保存: {path}");
|
||||
}
|
||||
|
||||
fn cmd_conflicts(json_out: bool) {
|
||||
let mut paths: Vec<String> = vec![];
|
||||
if let Ok(sys) = core::registry::load_system_paths() { paths.extend(sys); }
|
||||
@@ -216,6 +392,15 @@ fn main() {
|
||||
Command::List { system, user, json } => cmd_list(system, user, json),
|
||||
Command::Add { path, system, user } => cmd_add(path, system, user),
|
||||
Command::Remove { index, system } => cmd_remove(index, system),
|
||||
Command::Edit { index, new_path, system } => cmd_edit(index, new_path, system),
|
||||
Command::MoveUp { index, steps, system } => cmd_move(index, steps, system, true),
|
||||
Command::MoveDown { index, steps, system } => cmd_move(index, steps, system, false),
|
||||
Command::Clean { system, user, dry_run, json } => cmd_clean(system, user, dry_run, json),
|
||||
Command::Enable { index, system, user } => cmd_toggle(index, system, user, true),
|
||||
Command::Disable { index, system, user } => cmd_toggle(index, system, user, false),
|
||||
Command::Import { file, target } => cmd_import(file, target),
|
||||
Command::Export { format, output } => cmd_export(format, output),
|
||||
Command::Backup => cmd_backup(),
|
||||
Command::Conflicts { json } => cmd_conflicts(json),
|
||||
Command::Scan { query, json } => cmd_scan(query, json),
|
||||
Command::CheckAdmin { json } => cmd_check_admin(json),
|
||||
|
||||
Reference in New Issue
Block a user