1- //! Various functions that involve launching the editor.
1+ //! Various functions that involve launching the Git editor (i.e. `GIT_EDITOR`) .
22use 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.
5859fn 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) ]
8498mod 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