chore: tui improvements 7a0298f1
Steve · 2026-02-19 09:12 2 file(s) · +63 −2
Cargo.toml +2 −1
8 8
path = "src/main.rs"
9 9
10 10
[[bin]]
11 -
name = "sipp-tui"
11 +
name = "sipp"
12 12
path = "src/bin/tui.rs"
13 13
14 14
[dependencies]
29 29
clap = { version = "4", features = ["derive", "env"] }
30 30
toml = "0.8"
31 31
rpassword = "5"
32 +
open = "5.3.3"
src/bin/tui.rs +61 −1
12 12
use sipp_rust::config;
13 13
use sipp_rust::db::Snippet;
14 14
use std::io::Cursor;
15 +
use std::path::PathBuf;
15 16
use std::time::{Duration, Instant};
16 17
use syntect::easy::HighlightLines;
17 18
use syntect::highlighting::Theme;
28 29
    /// API key for authenticated operations
29 30
    #[arg(short = 'k', long, env = "SIPP_API_KEY")]
30 31
    api_key: Option<String>,
32 +
33 +
    /// File path to create a snippet from (uses filename as name, file contents as content)
34 +
    #[arg(value_name = "FILE")]
35 +
    file: Option<PathBuf>,
31 36
32 37
    #[command(subcommand)]
33 38
    command: Option<Commands>,
148 153
                        let _ = clipboard.set_text(&link);
149 154
                        self.status_message =
150 155
                            Some(("Link copied!".to_string(), Instant::now()));
156 +
                    }
157 +
                }
158 +
            }
159 +
            None => {
160 +
                self.status_message =
161 +
                    Some(("No remote URL configured".to_string(), Instant::now()));
162 +
            }
163 +
        }
164 +
    }
165 +
166 +
    fn open_in_browser(&mut self) {
167 +
        match &self.remote_url {
168 +
            Some(url) => {
169 +
                if let Some(snippet) = self.selected_snippet() {
170 +
                    let link = format!("{}/s/{}", url.trim_end_matches('/'), snippet.short_id);
171 +
                    if let Err(e) = open::that(&link) {
172 +
                        self.status_message =
173 +
                            Some((format!("Failed to open browser: {}", e), Instant::now()));
174 +
                    } else {
175 +
                        self.status_message =
176 +
                            Some(("Opened in browser!".to_string(), Instant::now()));
151 177
                    }
152 178
                }
153 179
            }
345 371
346 372
    let (backend, is_remote, remote_url) = resolve_backend(&cli);
347 373
374 +
    if let Some(file_path) = &cli.file {
375 +
        let name = file_path
376 +
            .file_name()
377 +
            .ok_or("Invalid file path")?
378 +
            .to_string_lossy()
379 +
            .to_string();
380 +
        let content = std::fs::read_to_string(file_path)
381 +
            .map_err(|e| format!("Failed to read file: {}", e))?;
382 +
        let snippet = backend
383 +
            .create_snippet(&name, &content)
384 +
            .map_err(|e| format!("{}", e))?;
385 +
        let link = match &remote_url {
386 +
            Some(url) => format!("{}/s/{}", url.trim_end_matches('/'), snippet.short_id),
387 +
            None => snippet.short_id.clone(),
388 +
        };
389 +
        println!("{}", link);
390 +
        if let Ok(mut clipboard) = Clipboard::new() {
391 +
            let _ = clipboard.set_text(&link);
392 +
            println!("\u{2714} Copied to clipboard!");
393 +
        }
394 +
        return Ok(());
395 +
    }
396 +
348 397
    let snippets = match backend.list_snippets() {
349 398
        Ok(s) => s,
350 399
        Err(e) => {
518 567
            if app.show_help {
519 568
                let area = frame.area();
520 569
                let popup_width = 44u16.min(area.width.saturating_sub(4));
521 -
                let popup_height = 19u16.min(area.height.saturating_sub(4));
570 +
                let popup_height = 20u16.min(area.height.saturating_sub(4));
522 571
                let popup_area = ratatui::layout::Rect {
523 572
                    x: (area.width.saturating_sub(popup_width)) / 2,
524 573
                    y: (area.height.saturating_sub(popup_height)) / 2,
584 633
                    ]),
585 634
                    Line::from(vec![
586 635
                        Span::styled(
636 +
                            "  o    ",
637 +
                            Style::default()
638 +
                                .fg(Color::Yellow)
639 +
                                .add_modifier(Modifier::BOLD),
640 +
                        ),
641 +
                        Span::raw("Open in browser"),
642 +
                    ]),
643 +
                    Line::from(vec![
644 +
                        Span::styled(
587 645
                            "  d    ",
588 646
                            Style::default()
589 647
                                .fg(Color::Yellow)
667 725
                            KeyCode::Char('Y') => app.copy_link(),
668 726
                            KeyCode::Char('d') => app.delete_selected(backend),
669 727
                            KeyCode::Char('c') => app.start_create(),
728 +
                            KeyCode::Char('o') => app.open_in_browser(),
670 729
                            KeyCode::Char('r') if app.is_remote => app.refresh(backend),
671 730
                            KeyCode::Char('?') => app.show_help = true,
672 731
                            KeyCode::Enter | KeyCode::Char('l') => {
686 745
                            KeyCode::Char('k') | KeyCode::Up => app.scroll_up(),
687 746
                            KeyCode::Char('y') => app.copy_selected(),
688 747
                            KeyCode::Char('Y') => app.copy_link(),
748 +
                            KeyCode::Char('o') => app.open_in_browser(),
689 749
                            KeyCode::Char('?') => app.show_help = true,
690 750
                            _ => {}
691 751
                        },