use std::{num::NonZeroU64, path::Path, process::ExitCode}; use anyhow::Result; use log::{debug, error, info, warn}; mod args; mod nvim; mod platform; fn main() -> ExitCode { env_logger::builder() .format_timestamp(None) .filter_level(log::LevelFilter::Info) .parse_default_env() .init(); let Ok(args) = args::parse() else { let mut args = std::env::args(); let program_name = args.next(); let program_name = program_name.as_deref().unwrap_or("launch-editor-nvim"); warn!("Usage: {program_name} [line] [column]"); return ExitCode::FAILURE; }; match edit_with_nvim(&args.filename, args.line, args.col) { Ok(code) => code, Err(e) => { error!("{e}"); ExitCode::FAILURE } } } fn edit_with_nvim( path: &Path, line: Option, col: Option, ) -> Result { if log::log_enabled!(log::Level::Info) { let path = path.display(); match (line, col) { (Some(line), Some(col)) => info!("Opening {path}:{line}:{col}"), (Some(line), _) => info!("Opening {path}:{line}"), _ => info!("Opening {path}"), } } let path = path.canonicalize()?; let best_nvim = nvim::instances()? .filter_map(|nvim| { let pid = nvim.process.pid(); let cwd = nvim.process.current_dir(); debug!("Neovim {pid}: cwd={}", cwd.display()); path.strip_prefix(cwd) .inspect_err(|_| debug!("Neovim {pid} rejected: file outside cwd")) .ok() .zip(Some(nvim)) }) .min_by_key(|(suffix, nvim)| { let n = suffix.components().count(); debug!( "Neovim {pid} candidate: score = {n} (lower is better)", pid = nvim.process.pid() ); n }) .map(|(_, nvim)| nvim); match best_nvim { Some(nvim) => { nvim.edit(&path, line, col)?; Ok(ExitCode::SUCCESS) } None => { warn!("No suitable Neovim instance was found!"); info!("tip: the path must be within Neovim's current working directory"); info!("tip: try again with RUST_LOG=debug"); Ok(ExitCode::FAILURE) } } }