chore: add edit in editor to jotts tui 5c2e9f65
Steve · 2026-04-13 22:11 1 file(s) · +75 −0
apps/jotts/src/tui.rs +75 −0
13 13
};
14 14
use std::time::{Duration, Instant};
15 15
16 +
fn edit_in_external_editor(
17 +
    terminal: &mut DefaultTerminal,
18 +
    app: &mut App,
19 +
    backend: &Backend,
20 +
) -> Result<(), Box<dyn std::error::Error>> {
21 +
    let (short_id, title, content) = match app.selected_note() {
22 +
        Some(n) => (n.short_id.clone(), n.title.clone(), n.content.clone()),
23 +
        None => return Ok(()),
24 +
    };
25 +
26 +
    let editor = match std::env::var("EDITOR") {
27 +
        Ok(e) if !e.trim().is_empty() => e,
28 +
        _ => {
29 +
            app.status_message = Some(("EDITOR env not set".to_string(), Instant::now()));
30 +
            return Ok(());
31 +
        }
32 +
    };
33 +
34 +
    let mut path = std::env::temp_dir();
35 +
    path.push(format!("jotts-{}.md", short_id));
36 +
    std::fs::write(&path, &content)?;
37 +
38 +
    ratatui::restore();
39 +
40 +
    let status = std::process::Command::new(&editor).arg(&path).status();
41 +
42 +
    *terminal = ratatui::init();
43 +
    terminal.clear()?;
44 +
45 +
    match status {
46 +
        Ok(s) if s.success() => {
47 +
            let new_content = std::fs::read_to_string(&path)?;
48 +
            let _ = std::fs::remove_file(&path);
49 +
            if new_content == content {
50 +
                app.status_message = Some(("No changes".to_string(), Instant::now()));
51 +
                return Ok(());
52 +
            }
53 +
            match backend.update_note(&short_id, &title, &new_content) {
54 +
                Ok(Some(updated)) => {
55 +
                    if let Some(pos) = app.notes.iter().position(|n| n.short_id == short_id) {
56 +
                        app.notes[pos] = updated;
57 +
                    }
58 +
                    app.status_message = Some(("Updated!".to_string(), Instant::now()));
59 +
                }
60 +
                Ok(None) => {
61 +
                    app.status_message = Some(("Note not found".to_string(), Instant::now()));
62 +
                }
63 +
                Err(e) => {
64 +
                    app.status_message = Some((e.to_string(), Instant::now()));
65 +
                }
66 +
            }
67 +
        }
68 +
        Ok(_) => {
69 +
            let _ = std::fs::remove_file(&path);
70 +
            app.status_message = Some(("Editor exited non-zero".to_string(), Instant::now()));
71 +
        }
72 +
        Err(e) => {
73 +
            let _ = std::fs::remove_file(&path);
74 +
            app.status_message =
75 +
                Some((format!("Failed to launch editor: {}", e), Instant::now()));
76 +
        }
77 +
    }
78 +
    Ok(())
79 +
}
80 +
16 81
enum Focus {
17 82
    List,
18 83
    Content,
863 928
                        Span::raw("Edit note"),
864 929
                    ]),
865 930
                    Line::from(vec![
931 +
                        Span::styled("  E    ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)),
932 +
                        Span::raw("Edit in $EDITOR"),
933 +
                    ]),
934 +
                    Line::from(vec![
866 935
                        Span::styled("  /    ", Style::default().fg(Color::Yellow).add_modifier(Modifier::BOLD)),
867 936
                        Span::raw("Search notes"),
868 937
                    ]),
930 999
                            KeyCode::Char('d') => app.confirm_delete = true,
931 1000
                            KeyCode::Char('c') => app.start_create(),
932 1001
                            KeyCode::Char('e') => app.start_edit(),
1002 +
                            KeyCode::Char('E') => {
1003 +
                                edit_in_external_editor(terminal, &mut app, backend)?
1004 +
                            }
933 1005
                            KeyCode::Char('/') => app.start_search(),
934 1006
                            KeyCode::Char('o') => app.open_in_browser(),
935 1007
                            KeyCode::Char('r') if app.is_remote => app.refresh(backend),
955 1027
                            KeyCode::Char('y') => app.copy_selected(),
956 1028
                            KeyCode::Char('Y') => app.copy_link(),
957 1029
                            KeyCode::Char('e') => app.start_edit(),
1030 +
                            KeyCode::Char('E') => {
1031 +
                                edit_in_external_editor(terminal, &mut app, backend)?
1032 +
                            }
958 1033
                            KeyCode::Char('o') => app.open_in_browser(),
959 1034
                            KeyCode::Char('?') => app.show_help = true,
960 1035
                            _ => {}