diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/cmdline.rs | 3 | ||||
-rw-r--r-- | src/main.rs | 67 |
2 files changed, 58 insertions, 12 deletions
diff --git a/src/cmdline.rs b/src/cmdline.rs index 43adbec..9d3bc29 100644 --- a/src/cmdline.rs +++ b/src/cmdline.rs @@ -7,10 +7,11 @@ pub struct Args { /// Path to browser executable #[arg(short, long)] pub browser: PathBuf, + /// Path to dmenu executable #[arg(short = 'm', long)] pub dmenu: PathBuf, /// Location history sqlite database - #[arg(short = 'p', long, default_value = PathBuf::from("~/.mozilla/firefox/11ybm96o.default").into_os_string())] + #[arg(short = 'p', long, default_value = PathBuf::from("~/.mozilla/firefox/000000.default").into_os_string())] pub profile: PathBuf, /// Limit of location history entries to seek #[arg(short = 'l', long, default_value_t = 100)] diff --git a/src/main.rs b/src/main.rs index d3c927d..3a34912 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,12 +1,14 @@ mod cmdline; use clap::Parser; use cmdline::Args; -use rusqlite::{params, Connection, Result}; +use rusqlite::{Connection, Result}; +use std::io::Write; use std::{ collections::HashSet, fmt::Display, fs, - path::{Path, PathBuf}, + path::PathBuf, + process::{Command, Stdio}, }; use url; #[derive(Debug)] @@ -30,7 +32,7 @@ fn copy_db(root_path: Option<&PathBuf>) -> Option<PathBuf> { if let Ok(found_profile_path) = match_firefox_profile() { found_profile_path } else { - panic!("thing"); + panic!("[Profile] Cannot find any profiles!"); } }; root.push("places.sqlite"); @@ -38,14 +40,14 @@ fn copy_db(root_path: Option<&PathBuf>) -> Option<PathBuf> { match fs::exists(&root) { Ok(existence) => { if !existence { - panic!("[FS] DB does not exist") + panic!("[Filesystem] Database does not exist!") } else { - fs::copy(root, &tmp_path); + let _ = fs::copy(root, &tmp_path); return Some(tmp_path); } } Err(_) => { - panic!("[FS] something wrong...") + panic!("[Filesystem] Nondescript error.") } }; } @@ -54,10 +56,13 @@ fn main() -> Result<()> { let path = if let Some(p) = copy_db(Some(&args.profile)) { p } else { - panic!("baddddd") + panic!("[main] Database copying failed.") }; let conn = Connection::open(&path).unwrap(); - let query = format!("SELECT id, url FROM moz_places ORDER BY last_visit_date DESC LIMIT {}", args.limit); + let query = format!( + "SELECT id, url FROM moz_places ORDER BY last_visit_date DESC LIMIT {}", + args.limit + ); let mut stmt = conn.prepare(&query).unwrap(); let urls_iter = stmt.query_map([], |row| { Ok(FirefoxPlace { @@ -65,7 +70,7 @@ fn main() -> Result<()> { url: row.get(1)?, }) })?; - let mut hosts = HashSet::new(); + let mut hosts: HashSet<String> = HashSet::new(); for place in urls_iter { if let Ok(p) = place { let url = url::Url::parse(&p.url); @@ -76,9 +81,49 @@ fn main() -> Result<()> { } } } - for h in hosts { + for h in &hosts { println!("{}", h); } - fs::remove_file(&path); + let tmp_urls_path = PathBuf::from("/tmp/firefox-dmenu-urls.tmp"); + let _ = fs::remove_file(&path); + let dmenu_opts = hosts.into_iter().collect::<Vec<String>>().join("\n"); + println!( + "cat {} | {}", + tmp_urls_path.to_str().unwrap(), + args.dmenu.to_str().unwrap() + ); + let _ = fs::write(&tmp_urls_path, &dmenu_opts); + let source_command = Command::new("cat") + .arg(&tmp_urls_path) + .stdout(Stdio::piped()) + .output() + .expect("[cat] Failed to cat source file. Is it readable?"); + let mut dmenu_command = Command::new(args.dmenu) + .stdin(Stdio::piped()) + .stdout(Stdio::piped()) + .spawn() + .expect("[dmenu] Failed to launch dmenu. Is it executable?"); + let mut dmenu_stdin = dmenu_command + .stdin + .take() + .expect("[dmenu] Failed to take standard input from dmenu."); + std::thread::spawn(move || { + dmenu_stdin + .write_all(&source_command.stdout) + .expect("[dmenu] Failed to write to stdin of dmenu."); + }); + let dmenu_out = dmenu_command + .wait_with_output() + .expect("[dmenu] Expected dmenu to successfully execute."); + let dmenu_sel = String::from_utf8_lossy(&dmenu_out.stdout); + println!("Captured selection: {}", dmenu_sel); + println!("{}", dmenu_sel); + if dmenu_sel.to_string() == String::from("") { + println!("dmenu did not produce any output."); + return Ok(()); + } + let _ = Command::new(args.browser) + .arg(dmenu_sel.to_string()) + .spawn(); Ok(()) } |