From 27e2f472802a7744af68f0b0df35bb7dd4b684ea Mon Sep 17 00:00:00 2001 From: cloudhead Date: Thu, 31 Aug 2023 14:02:56 +0200 Subject: [PATCH] term: Fallback to common editors When `EDITOR` or `VISUAL` are not set, we fallback to the most common editors. It turns out many users don't have these variables set. We also check if an editor has been configured with `git`. --- Cargo.lock | 1 + radicle-term/Cargo.toml | 9 +++++++++ radicle-term/src/editor.rs | 31 ++++++++++++++++++++++++++++++- 3 files changed, 40 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 882f74bc..eafd8ee8 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2040,6 +2040,7 @@ version = "0.1.0" dependencies = [ "anstyle-query", "anyhow", + "git2", "inquire", "libc", "once_cell", diff --git a/radicle-term/Cargo.toml b/radicle-term/Cargo.toml index 2bc16180..2fd409da 100644 --- a/radicle-term/Cargo.toml +++ b/radicle-term/Cargo.toml @@ -8,6 +8,9 @@ version = "0.1.0" authors = ["cloudhead "] edition = "2021" +[features] +default = ["git2"] + [dependencies] anyhow = { version = "1" } anstyle-query = { version = "1.0.0" } @@ -19,6 +22,12 @@ unicode-width = { version = "0.1.10", default-features = false } unicode-segmentation = { version = "1.7.1" } zeroize = { version = "1.1" } +[dependencies.git2] +version = "0.17.0" +default-features = false +features = ["vendored-libgit2"] +optional = true + [dev-dependencies] pretty_assertions = { version = "1.3.0" } tempfile = { version = "3.3.0" } diff --git a/radicle-term/src/editor.rs b/radicle-term/src/editor.rs index ace5a75d..f61b3512 100644 --- a/radicle-term/src/editor.rs +++ b/radicle-term/src/editor.rs @@ -2,11 +2,13 @@ use std::ffi::OsString; use std::io::IsTerminal; use std::io::Write; use std::os::fd::{AsRawFd, FromRawFd}; -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use std::process; use std::{env, fs, io}; pub const COMMENT_FILE: &str = "RAD_COMMENT"; +/// Some common paths where system-installed binaries are found. +pub const PATHS: &[&str] = &["/usr/local/bin", "/usr/bin", "/bin"]; /// Allows for text input in the configured editor. pub struct Editor { @@ -101,6 +103,7 @@ impl Editor { /// Get the default editor command. pub fn default_editor() -> Option { + // First check the standard environment variables. if let Ok(visual) = env::var("VISUAL") { if !visual.is_empty() { return Some(visual.into()); @@ -111,5 +114,31 @@ pub fn default_editor() -> Option { return Some(editor.into()); } } + // Check Git. The user might have configured their editor there. + #[cfg(feature = "git2")] + if let Ok(path) = git2::Config::open_default().and_then(|cfg| cfg.get_path("core.editor")) { + return Some(path.into_os_string()); + } + // On macOS, `nano` is installed by default and it's what most users are used to + // in the terminal. + if cfg!(target_os = "macos") && exists("nano") { + return Some("nano".into()); + } + // If all else fails, we try `vi`. It's usually installed on most unix-based systems. + if exists("vi") { + return Some("vi".into()); + } None } + +/// Check whether a binary can be found in the most common paths. +/// We don't bother checking the $PATH variable, as we're only looking for very standard tools +/// and prefer not to make this too complex. +fn exists(cmd: &str) -> bool { + for dir in PATHS { + if Path::new(dir).join(cmd).exists() { + return true; + } + } + false +}