Rust · 2328 bytes Raw Blame History
1 use std::fs;
2 use std::io::{Read, Write};
3 use std::process::Command;
4
5 use serde::{Deserialize, Serialize};
6
7 use crate::db::Database;
8
9 use super::{CmdError, Result};
10
11 #[derive(Serialize, Deserialize)]
12 struct JsonEntry {
13 path: String,
14 score: f64,
15 }
16
17 #[derive(Serialize, Deserialize)]
18 struct JsonDatabase {
19 entries: Vec<JsonEntry>,
20 }
21
22 /// Edit the database in the user's editor.
23 pub fn run() -> Result<()> {
24 let db = Database::open()?;
25
26 // Export to JSON
27 let json_db = JsonDatabase {
28 entries: db
29 .entries()
30 .map(|(path, entry)| JsonEntry {
31 path: path.to_string_lossy().to_string(),
32 score: entry.score,
33 })
34 .collect(),
35 };
36
37 let json = serde_json::to_string_pretty(&json_db)
38 .map_err(|e| CmdError::Other(format!("Failed to serialize: {}", e)))?;
39
40 // Write to temp file
41 let temp_path = std::env::temp_dir().join("gump-edit.json");
42 {
43 let mut file = fs::File::create(&temp_path)?;
44 file.write_all(json.as_bytes())?;
45 }
46
47 // Get editor
48 let editor = std::env::var("EDITOR")
49 .or_else(|_| std::env::var("VISUAL"))
50 .unwrap_or_else(|_| "vi".to_string());
51
52 // Open in editor
53 let status = Command::new(&editor).arg(&temp_path).status()?;
54
55 if !status.success() {
56 return Err(CmdError::Other("Editor exited with error".to_string()));
57 }
58
59 // Read modified file
60 let mut modified = String::new();
61 {
62 let mut file = fs::File::open(&temp_path)?;
63 file.read_to_string(&mut modified)?;
64 }
65
66 // Parse modified JSON
67 let modified_db: JsonDatabase = serde_json::from_str(&modified)
68 .map_err(|e| CmdError::Other(format!("Failed to parse JSON: {}", e)))?;
69
70 // Create new database with modified entries
71 let mut new_db = Database::open()?;
72
73 // Clear existing entries by removing each one
74 let existing: Vec<_> = new_db.entries().map(|(p, _)| p.clone()).collect();
75 for path in existing {
76 let _ = new_db.remove(&path);
77 }
78
79 // Add modified entries
80 for entry in modified_db.entries {
81 new_db.import_entry(&entry.path, entry.score)?;
82 }
83
84 new_db.save()?;
85
86 // Clean up temp file
87 let _ = fs::remove_file(&temp_path);
88
89 println!("Database updated");
90 Ok(())
91 }
92