Smart Neovim launcher for yyx990803/launch-editor
at main 83 lines 2.4 kB view raw
1use std::{num::NonZeroU64, path::Path, process::ExitCode}; 2 3use anyhow::Result; 4use log::{debug, error, info, warn}; 5 6mod args; 7mod nvim; 8mod platform; 9 10fn main() -> ExitCode { 11 env_logger::builder() 12 .format_timestamp(None) 13 .filter_level(log::LevelFilter::Info) 14 .parse_default_env() 15 .init(); 16 17 let Ok(args) = args::parse() else { 18 let mut args = std::env::args(); 19 let program_name = args.next(); 20 let program_name = program_name.as_deref().unwrap_or("launch-editor-nvim"); 21 22 warn!("Usage: {program_name} <filename> [line] [column]"); 23 return ExitCode::FAILURE; 24 }; 25 26 match edit_with_nvim(&args.filename, args.line, args.col) { 27 Ok(code) => code, 28 Err(e) => { 29 error!("{e}"); 30 ExitCode::FAILURE 31 } 32 } 33} 34 35fn edit_with_nvim( 36 path: &Path, 37 line: Option<NonZeroU64>, 38 col: Option<NonZeroU64>, 39) -> Result<ExitCode> { 40 if log::log_enabled!(log::Level::Info) { 41 let path = path.display(); 42 match (line, col) { 43 (Some(line), Some(col)) => info!("Opening {path}:{line}:{col}"), 44 (Some(line), _) => info!("Opening {path}:{line}"), 45 _ => info!("Opening {path}"), 46 } 47 } 48 49 let path = path.canonicalize()?; 50 let best_nvim = nvim::instances()? 51 .filter_map(|nvim| { 52 let pid = nvim.process.pid(); 53 let cwd = nvim.process.current_dir(); 54 55 debug!("Neovim {pid}: cwd={}", cwd.display()); 56 path.strip_prefix(cwd) 57 .inspect_err(|_| debug!("Neovim {pid} rejected: file outside cwd")) 58 .ok() 59 .zip(Some(nvim)) 60 }) 61 .min_by_key(|(suffix, nvim)| { 62 let n = suffix.components().count(); 63 debug!( 64 "Neovim {pid} candidate: score = {n} (lower is better)", 65 pid = nvim.process.pid() 66 ); 67 n 68 }) 69 .map(|(_, nvim)| nvim); 70 71 match best_nvim { 72 Some(nvim) => { 73 nvim.edit(&path, line, col)?; 74 Ok(ExitCode::SUCCESS) 75 } 76 None => { 77 warn!("No suitable Neovim instance was found!"); 78 info!("tip: the path must be within Neovim's current working directory"); 79 info!("tip: try again with RUST_LOG=debug"); 80 Ok(ExitCode::FAILURE) 81 } 82 } 83}