Skip to content

Commit

Permalink
Open user default editor if available
Browse files Browse the repository at this point in the history
  • Loading branch information
mbergkvist committed Dec 27, 2024
1 parent cbb7ab2 commit da9939a
Showing 1 changed file with 55 additions and 23 deletions.
78 changes: 55 additions & 23 deletions crates/cli/src/editor.rs
Original file line number Diff line number Diff line change
@@ -1,34 +1,44 @@
use std::process::Command;
use std::{env, iter::once, process::Command};

/// Editors the user might be using
/// User default editor.
///
/// The user default editor is searched for in the environment variables
/// `EDITOR` and `VISUAL`.
///
/// Any arguments to the program are extracted and stored separately so they can
/// be passed to the program along with the path to open.
#[derive(Debug, PartialEq)]
pub enum Editor {
VSCode,
Zed,
pub struct Editor {
/// Default options and arguments to the program.
args: Vec<String>,
/// The program to launch.
program: String,
}

impl Editor {
/// Search the environment variables `EDITOR` and `VISUAL` for the user
/// preferred editor.
pub fn find() -> Option<Self> {
if Command::new("code").arg("--version").output().is_ok() {
return Some(Editor::VSCode);
}

if Command::new("zed").arg("--version").output().is_ok() {
return Some(Editor::Zed);
}

None
env::var("EDITOR")
.or_else(|_| env::var("VISUAL"))
.ok()
.filter(|value| !value.is_empty())
.map(|value| {
let mut parts = value.split_whitespace().map(String::from);
Self {
program: parts.next().expect("there should be a program"),
args: parts.collect(),
}
})
}

/// Open the user default editor.
pub fn open(&self, path: &str) {
Command::new(self.command()).arg(path).spawn().unwrap();
}

fn command(&self) -> &str {
match self {
Editor::VSCode => "code",
Editor::Zed => "zed",
}
let args = self.args.iter().map(|s| s.as_str()).chain(once(path));
Command::new(&self.program)
.args(args)
.spawn()
.expect("default editor failed to start");
}
}

Expand All @@ -37,7 +47,29 @@ mod tests {
use super::*;

#[test]
fn test_find_editor() {
fn test_find_user_editor() {
env::set_var("EDITOR", "editor --editor-flag");
env::set_var("VISUAL", "visual");
let editor = Editor::find();
let expected = Some(Editor {
args: vec![String::from("--editor-flag")],
program: String::from("editor"),
});
assert_eq!(editor, expected, "$EDITOR should be preferred editor");

env::remove_var("EDITOR");
env::set_var("VISUAL", "visual");
let editor = Editor::find();
let expected = Some(Editor {
args: vec![],
program: String::from("visual"),
});
assert_eq!(
editor, expected,
"$VISUAL should be used when $EDITOR is absent"
);

env::remove_var("VISUAL");
let editor = Editor::find();
assert_eq!(editor, None);
}
Expand Down

0 comments on commit da9939a

Please sign in to comment.