chore: add edit in editor to jotts tui
5c2e9f65
1 file(s) · +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 | _ => {} |
|