diff --git a/public/tauri.svg b/public/tauri.svg deleted file mode 100644 index 31b62c9..0000000 --- a/public/tauri.svg +++ /dev/null @@ -1,6 +0,0 @@ - - - - - - diff --git a/public/vite.svg b/public/vite.svg deleted file mode 100644 index e7b8dfb..0000000 --- a/public/vite.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file diff --git a/src-tauri/Cargo.lock b/src-tauri/Cargo.lock index 905df4b..9f560a2 100644 --- a/src-tauri/Cargo.lock +++ b/src-tauri/Cargo.lock @@ -3703,6 +3703,21 @@ dependencies = [ "zbus", ] +[[package]] +name = "tauri-plugin-single-instance" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc61e4822b8f74d68278e09161d3e3fdd1b14b9eb781e24edccaabf10c420e8c" +dependencies = [ + "serde", + "serde_json", + "tauri", + "thiserror 2.0.18", + "tracing", + "windows-sys 0.60.2", + "zbus", +] + [[package]] name = "tauri-runtime" version = "2.10.0" @@ -4281,7 +4296,7 @@ checksum = "0b928f33d975fc6ad9f86c8f283853ad26bdd5b10b7f1542aa2fa15e2289105a" [[package]] name = "vesper" -version = "0.1.0" +version = "1.0.1" dependencies = [ "serde", "serde_json", @@ -4290,6 +4305,7 @@ dependencies = [ "tauri-plugin-dialog", "tauri-plugin-fs", "tauri-plugin-opener", + "tauri-plugin-single-instance", ] [[package]] diff --git a/src-tauri/Cargo.toml b/src-tauri/Cargo.toml index b151cc2..b8e9252 100644 --- a/src-tauri/Cargo.toml +++ b/src-tauri/Cargo.toml @@ -22,3 +22,6 @@ tauri-plugin-fs = "2" serde = { version = "1", features = ["derive"] } serde_json = "1" +[target.'cfg(not(any(target_os = "android", target_os = "ios")))'.dependencies] +tauri-plugin-single-instance = "2" + diff --git a/src-tauri/src/lib.rs b/src-tauri/src/lib.rs index 7068e58..455a83b 100644 --- a/src-tauri/src/lib.rs +++ b/src-tauri/src/lib.rs @@ -39,6 +39,31 @@ fn save_window_state(state: &WindowState) { } } +#[derive(Serialize, Clone)] +struct CliFile { + path: String, + content: String, +} + +/// Try to read a markdown file from the given path string. +fn read_md_file(file_arg: &str) -> Option { + let path = PathBuf::from(file_arg); + if !path.is_file() { return None; } + let ext = path.extension()?.to_str()?.to_lowercase(); + if ext != "md" && ext != "markdown" && ext != "txt" { return None; } + let content = fs::read_to_string(&path).ok()?; + Some(CliFile { + path: path.to_string_lossy().to_string(), + content, + }) +} + +/// Returns the file path + content if the app was launched with a .md/.markdown/.txt argument. +#[tauri::command] +fn get_cli_file() -> Option { + env::args().nth(1).and_then(|a| read_md_file(&a)) +} + #[cfg_attr(mobile, tauri::mobile_entry_point)] pub fn run() { let data_dir = get_data_dir(); @@ -51,9 +76,23 @@ pub fn run() { ); tauri::Builder::default() + .plugin(tauri_plugin_single_instance::init(|app, args, _cwd| { + // Second instance launched with a file - send it to the existing window + if let Some(file_arg) = args.get(1) { + if let Some(cli_file) = read_md_file(file_arg) { + let _ = app.emit("open-file", cli_file); + } + } + // Focus the existing window + if let Some(window) = app.get_webview_window("main") { + let _ = window.unminimize(); + let _ = window.set_focus(); + } + })) .plugin(tauri_plugin_opener::init()) .plugin(tauri_plugin_dialog::init()) .plugin(tauri_plugin_fs::init()) + .invoke_handler(tauri::generate_handler![get_cli_file]) .setup(|app| { let state = load_window_state(); let window = app.get_webview_window("main").unwrap(); @@ -64,35 +103,12 @@ pub fn run() { )); } if let (Some(w), Some(h)) = (state.width, state.height) { - let _ = window.set_size(tauri::Size::Physical( - tauri::PhysicalSize::new(w, h), - )); + let _ = window.set_size(tauri::Size::Physical(tauri::PhysicalSize::new(w, h))); } if let Some(true) = state.maximized { let _ = window.maximize(); } - // If launched with a file argument (e.g. double-clicking a .md file), - // emit the path to the frontend so it can open it as a tab. - let args: Vec = env::args().collect(); - if let Some(file_arg) = args.get(1) { - let path = PathBuf::from(file_arg); - if path.is_file() { - if let Some(ext) = path.extension().and_then(|e| e.to_str()) { - let ext_lower = ext.to_lowercase(); - if ext_lower == "md" || ext_lower == "markdown" || ext_lower == "txt" { - let path_str = path.to_string_lossy().to_string(); - let win = window.clone(); - // Emit after a short delay so the frontend has time to set up listeners - std::thread::spawn(move || { - std::thread::sleep(std::time::Duration::from_millis(500)); - let _ = win.emit("open-file", path_str); - }); - } - } - } - } - Ok(()) }) .on_window_event(|window, event| { diff --git a/src/assets/react.svg b/src/assets/react.svg deleted file mode 100644 index 6c87de9..0000000 --- a/src/assets/react.svg +++ /dev/null @@ -1 +0,0 @@ - \ No newline at end of file