tenseleyflow/gump / 385efdc

Browse files

implement edit command with JSON export

Authored by mfwolffe <wolffemf@dukes.jmu.edu>
SHA
385efdc54a2c15e3ffa3d321f5d9873a9e631489
Parents
8007a1b
Tree
3e6d9ee

3 changed files

StatusFile+-
M Cargo.lock 26 0
M Cargo.toml 1 0
M src/cmd/edit.rs 86 6
Cargo.lockmodified
@@ -277,6 +277,7 @@ dependencies = [
277277
  "directories",
278278
  "nucleo",
279279
  "serde",
280
+ "serde_json",
280281
  "tempfile",
281282
  "thiserror 2.0.17",
282283
 ]
@@ -317,6 +318,12 @@ version = "1.70.2"
317318
 source = "registry+https://github.com/rust-lang/crates.io-index"
318319
 checksum = "a6cb138bb79a146c1bd460005623e142ef0181e3d0219cb493e02f7d08a35695"
319320
 
321
+[[package]]
322
+name = "itoa"
323
+version = "1.0.17"
324
+source = "registry+https://github.com/rust-lang/crates.io-index"
325
+checksum = "92ecc6618181def0457392ccd0ee51198e065e016d1d527a7ac1b6dc7c1f09d2"
326
+
320327
 [[package]]
321328
 name = "js-sys"
322329
 version = "0.3.85"
@@ -560,6 +567,19 @@ dependencies = [
560567
  "syn",
561568
 ]
562569
 
570
+[[package]]
571
+name = "serde_json"
572
+version = "1.0.149"
573
+source = "registry+https://github.com/rust-lang/crates.io-index"
574
+checksum = "83fc039473c5595ace860d8c4fafa220ff474b3fc6bfdb4293327f1a37e94d86"
575
+dependencies = [
576
+ "itoa",
577
+ "memchr",
578
+ "serde",
579
+ "serde_core",
580
+ "zmij",
581
+]
582
+
563583
 [[package]]
564584
 name = "shlex"
565585
 version = "1.3.0"
@@ -859,3 +879,9 @@ name = "wit-bindgen"
859879
 version = "0.51.0"
860880
 source = "registry+https://github.com/rust-lang/crates.io-index"
861881
 checksum = "d7249219f66ced02969388cf2bb044a09756a083d0fab1e566056b04d9fbcaa5"
882
+
883
+[[package]]
884
+name = "zmij"
885
+version = "1.0.14"
886
+source = "registry+https://github.com/rust-lang/crates.io-index"
887
+checksum = "bd8f3f50b848df28f887acb68e41201b5aea6bc8a8dacc00fb40635ff9a72fea"
Cargo.tomlmodified
@@ -17,6 +17,7 @@ directories = "5"
1717
 chrono = { version = "0.4", features = ["serde"] }
1818
 thiserror = "2"
1919
 nucleo = "0.5"
20
+serde_json = "1"
2021
 
2122
 [dev-dependencies]
2223
 tempfile = "3"
src/cmd/edit.rsmodified
@@ -1,11 +1,91 @@
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
+
19
 use super::{CmdError, Result};
210
 
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
+
322
 /// Edit the database in the user's editor.
4
-///
5
-/// This is a placeholder - full implementation will be in Sprint 4.
623
 pub fn run() -> Result<()> {
7
-    // TODO: Sprint 4 - export to JSON, open in $EDITOR, import back
8
-    Err(CmdError::Other(
9
-        "Edit not yet implemented (Sprint 4)".to_string(),
10
-    ))
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(())
1191
 }