use std::path::Path;
use std::process::Command;
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
pub enum Editor {
Cursor,
Code,
}
impl Editor {
pub fn bin(self) -> &'static str {
match self {
Editor::Cursor => "cursor",
Editor::Code => "code",
}
}
pub fn label(self) -> &'static str {
match self {
Editor::Cursor => "Cursor",
Editor::Code => "VS Code",
}
}
}
pub fn find_editors() -> Vec<Editor> {
[Editor::Cursor, Editor::Code]
.into_iter()
.filter(|editor| which::which(editor.bin()).is_ok())
.collect()
}
pub struct InstallResult {
pub editor: Editor,
pub success: bool,
pub message: String,
}
pub fn install(editor: Editor, vsix_path: &Path) -> InstallResult {
let output = Command::new(editor.bin())
.arg("--install-extension")
.arg(vsix_path)
.output();
match output {
Ok(output) if output.status.success() => InstallResult {
editor,
success: true,
message: format!("已安装到 {}", editor.label()),
},
Ok(output) => {
let stderr = String::from_utf8_lossy(&output.stderr);
let stdout = String::from_utf8_lossy(&output.stdout);
let detail = {
let stderr = stderr.trim();
if stderr.is_empty() {
stdout.trim()
} else {
stderr
}
};
InstallResult {
editor,
success: false,
message: if detail.is_empty() {
"安装失败".to_string()
} else {
detail.to_string()
},
}
}
Err(err) => InstallResult {
editor,
success: false,
message: format!("无法执行 {}:{err}", editor.bin()),
},
}
}
pub fn install_to_editors(editors: &[Editor], vsix_path: &Path) -> (bool, String) {
let results: Vec<InstallResult> = editors
.iter()
.map(|editor| install(*editor, vsix_path))
.collect();
let succeeded: Vec<&InstallResult> = results.iter().filter(|r| r.success).collect();
let failed: Vec<&InstallResult> = results.iter().filter(|r| !r.success).collect();
if failed.is_empty() {
let names = succeeded
.iter()
.map(|r| r.editor.label())
.collect::<Vec<_>>()
.join("、");
return (true, format!("已安装到 {names}"));
}
if succeeded.is_empty() {
let detail = failed
.iter()
.map(|r| format!("{}:{}", r.editor.label(), r.message))
.collect::<Vec<_>>()
.join(";");
return (false, detail);
}
let ok_names = succeeded
.iter()
.map(|r| r.editor.label())
.collect::<Vec<_>>()
.join("、");
let fail_detail = failed
.iter()
.map(|r| format!("{} 失败:{}", r.editor.label(), r.message))
.collect::<Vec<_>>()
.join(";");
(false, format!("已安装到 {ok_names};{fail_detail}"))
}