Skip to content

Commit 9e0f170

Browse files
committed
refactor
- be more verbose when Git couldn't be invoked to ease remote debugging later. - don't force vars to strings, retain their original encoding - avoid hashmap in favor of iterator
1 parent 9d2a6b4 commit 9e0f170

File tree

1 file changed

+33
-21
lines changed

1 file changed

+33
-21
lines changed

crates/but/src/tui/get_text.rs

Lines changed: 33 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
1-
//! Various functions that involve launching the editor.
1+
//! Various functions that involve launching the Git editor (i.e. `GIT_EDITOR`).
22
use anyhow::Result;
3-
use std::collections::HashMap;
3+
use bstr::ByteSlice;
4+
use std::ffi::OsStr;
45

56
/// Launches the user's preferred text editor to edit some initial text,
67
/// identified by a unique identifier (to avoid temp file collisions).
@@ -52,44 +53,55 @@ pub fn from_editor(identifier: &str, initial_text: &str) -> Result<String> {
5253
/// Get the user's preferred editor command.
5354
/// Runs `git var GIT_EDITOR`, which lets git do its resolution of the editor command.
5455
/// This typically uses the git config value for `core.editor`, and env vars like `GIT_EDITOR` or `EDITOR`.
55-
/// We fallback to notepad (Windows) or vi otherwise just in case we don't get something usable from `git var`.
56+
/// We fall back to notepad (Windows) or vi otherwise just in case we don't get something usable from `git var`.
5657
///
5758
/// Note: Because git config parsing is used, the current directory matters for potential local git config overrides.
5859
fn get_editor_command() -> Result<String> {
59-
let env: HashMap<String, String> = std::env::vars().collect();
60-
get_editor_command_impl(&env)
60+
get_editor_command_impl(std::env::vars_os())
6161
}
6262

63-
/// Internal implementation that can be tested with controlled environment
64-
fn get_editor_command_impl(env: &HashMap<String, String>) -> Result<String> {
63+
/// Internal implementation that can be tested with the controlled environment `env`.
64+
fn get_editor_command_impl<AsOsStr: AsRef<OsStr>>(
65+
env: impl IntoIterator<Item = (AsOsStr, AsOsStr)>,
66+
) -> Result<String> {
6567
// Run git var with the controlled environment
66-
if let Ok(output) = std::process::Command::new(gix::path::env::exe_invocation())
68+
let mut cmd = std::process::Command::new(gix::path::env::exe_invocation());
69+
let res = cmd
6770
.args(["var", "GIT_EDITOR"])
6871
.env_clear()
6972
.envs(env)
70-
.output()
73+
.output();
74+
if res.is_err() {
75+
// Avoid logging explicit env vars
76+
cmd.env_clear();
77+
tracing::warn!(
78+
?res,
79+
?cmd,
80+
"Git could not be invoked even though we expect this to work"
81+
);
82+
}
83+
if let Ok(output) = res
7184
&& output.status.success()
7285
{
73-
let editor = String::from_utf8_lossy(&output.stdout).trim().to_string();
86+
let editor = output.stdout.as_bstr().trim();
7487
if !editor.is_empty() {
75-
return Ok(editor);
88+
return Ok(editor.as_bstr().to_string());
7689
}
7790
}
78-
79-
// Simple fallback to platform defaults
80-
Ok(if cfg!(windows) { "notepad" } else { "vi" }.to_string())
91+
// fallback to platform defaults to have *something*.
92+
Ok(PLATFORM_EDITOR.into())
8193
}
8294

95+
const PLATFORM_EDITOR: &str = if cfg!(windows) { "notepad" } else { "vi" };
96+
8397
#[cfg(test)]
8498
mod tests {
8599
use super::*;
86100

87-
const OUR_PLATFORM_DEFAULT: &str = if cfg!(windows) { "notepad" } else { "vi" };
88-
89101
#[test]
90102
fn git_editor_takes_precedence() {
91-
let env = HashMap::from([("GIT_EDITOR".to_string(), "from-GIT_EDITOR".to_string())]);
92-
let actual = get_editor_command_impl(&env).unwrap();
103+
let git_editor_env = Some(("GIT_EDITOR", "from-GIT_EDITOR"));
104+
let actual = get_editor_command_impl(git_editor_env).unwrap();
93105
assert_eq!(
94106
actual, "from-GIT_EDITOR",
95107
"GIT_EDITOR should take precedence if git is executed correctly"
@@ -100,10 +112,10 @@ mod tests {
100112
fn falls_back_when_nothing_set() {
101113
// Empty environment, git considers this "dumb terminal" and `git var` will return empty string
102114
// so our own fallback will be used
103-
let env = HashMap::new();
104-
let actual = get_editor_command_impl(&env).unwrap();
115+
let no_env = None::<(String, String)>;
116+
let actual = get_editor_command_impl(no_env).unwrap();
105117
assert_eq!(
106-
actual, OUR_PLATFORM_DEFAULT,
118+
actual, PLATFORM_EDITOR,
107119
"Should fall back to vi/notepad when nothing is set"
108120
);
109121
}

0 commit comments

Comments
 (0)