1
1
use std:: ffi:: OsStr ;
2
- use std:: path:: Path ;
2
+ use std:: path:: { Path , PathBuf } ;
3
3
use std:: { env, io} ;
4
4
5
5
/* We use a two-phase init here: the first phase gives a simple command to the
@@ -17,12 +17,62 @@ using whatever mechanism is available in the host shell--this two-phase solution
17
17
has been developed as a compatibility measure with `eval $(starship init X)`
18
18
*/
19
19
20
- fn path_to_starship ( ) -> io:: Result < String > {
21
- let current_exe = env:: current_exe ( ) ?
22
- . to_str ( )
23
- . ok_or_else ( || io:: Error :: new ( io:: ErrorKind :: Other , "can't convert to str" ) ) ?
24
- . to_string ( ) ;
25
- Ok ( current_exe)
20
+ struct StarshipPath {
21
+ native_path : PathBuf ,
22
+ }
23
+ impl StarshipPath {
24
+ fn init ( ) -> io:: Result < Self > {
25
+ Ok ( Self {
26
+ native_path : env:: current_exe ( ) ?,
27
+ } )
28
+ }
29
+ fn str_path ( & self ) -> io:: Result < & str > {
30
+ let current_exe = self
31
+ . native_path
32
+ . to_str ( )
33
+ . ok_or_else ( || io:: Error :: new ( io:: ErrorKind :: Other , "can't convert to str" ) ) ?;
34
+ Ok ( current_exe)
35
+ }
36
+ fn sprint ( & self ) -> io:: Result < String > {
37
+ self . str_path ( ) . map ( |s| s. replace ( "\" " , "\" '\" '\" " ) )
38
+ }
39
+ fn sprint_posix ( & self ) -> io:: Result < String > {
40
+ // On non-Windows platform, return directly.
41
+ if cfg ! ( not( target_os = "windows" ) ) {
42
+ return self . sprint ( ) ;
43
+ }
44
+ let str_path = self . str_path ( ) ?;
45
+ let res = std:: process:: Command :: new ( "cygpath.exe" )
46
+ . arg ( str_path)
47
+ . output ( ) ;
48
+ let output = match res {
49
+ Ok ( output) => output,
50
+ Err ( e) => {
51
+ if e. kind ( ) != io:: ErrorKind :: NotFound {
52
+ log:: warn!( "Failed to convert \" {}\" to unix path:\n {:?}" , str_path, e) ;
53
+ }
54
+ // Failed to execute cygpath.exe means there're not inside cygwin evironment,return directly.
55
+ return self . sprint ( ) ;
56
+ }
57
+ } ;
58
+ let res = String :: from_utf8 ( output. stdout ) ;
59
+ let posix_path = match res {
60
+ Ok ( ref cygpath_path) if output. status . success ( ) => cygpath_path. trim ( ) ,
61
+ Ok ( _) => {
62
+ log:: warn!(
63
+ "Failed to convert \" {}\" to unix path:\n {}" ,
64
+ str_path,
65
+ String :: from_utf8_lossy( & output. stderr) ,
66
+ ) ;
67
+ str_path
68
+ }
69
+ Err ( e) => {
70
+ log:: warn!( "Failed to convert \" {}\" to unix path:\n {}" , str_path, e) ;
71
+ str_path
72
+ }
73
+ } ;
74
+ Ok ( posix_path. replace ( "\" " , "\" '\" '\" " ) )
75
+ }
26
76
}
27
77
28
78
/* This prints the setup stub, the short piece of code which sets up the main
@@ -33,7 +83,7 @@ pub fn init_stub(shell_name: &str) -> io::Result<()> {
33
83
34
84
let shell_basename = Path :: new ( shell_name) . file_stem ( ) . and_then ( OsStr :: to_str) ;
35
85
36
- let starship = path_to_starship ( ) ?. replace ( " \" " , " \" ' \" ' \" " ) ;
86
+ let starship = StarshipPath :: init ( ) ?;
37
87
38
88
let setup_stub = match shell_basename {
39
89
Some ( "bash" ) => {
@@ -72,25 +122,28 @@ pub fn init_stub(shell_name: &str) -> io::Result<()> {
72
122
format ! (
73
123
r#"if [ "${{BASH_VERSINFO[0]}}" -gt 4 ] || ([ "${{BASH_VERSINFO[0]}}" -eq 4 ] && [ "${{BASH_VERSINFO[1]}}" -ge 1 ])
74
124
then
75
- source <("{}" init bash --print-full-init)
125
+ source <("{0 }" init bash --print-full-init)
76
126
else
77
- source /dev/stdin <<<"$("{}" init bash --print-full-init)"
127
+ source /dev/stdin <<<"$("{0 }" init bash --print-full-init)"
78
128
fi"# ,
79
- starship, starship
129
+ starship. sprint_posix ( ) ?
80
130
)
81
131
} ;
82
132
83
133
Some ( script)
84
134
}
85
135
Some ( "zsh" ) => {
86
- let script = format ! ( "source <(\" {}\" init zsh --print-full-init)" , starship) ;
136
+ let script = format ! (
137
+ "source <(\" {}\" init zsh --print-full-init)" ,
138
+ starship. sprint_posix( ) ?
139
+ ) ;
87
140
Some ( script)
88
141
}
89
142
Some ( "fish" ) => {
90
143
// Fish does process substitution with pipes and psub instead of bash syntax
91
144
let script = format ! (
92
145
"source (\" {}\" init fish --print-full-init | psub)" ,
93
- starship
146
+ starship. sprint_posix ( ) ?
94
147
) ;
95
148
Some ( script)
96
149
}
@@ -105,12 +158,12 @@ fi"#,
105
158
// Powershell escapes with ` instead of \ thus `n translates to a newline.
106
159
let script = format ! (
107
160
"Invoke-Expression (@(&\" {}\" init powershell --print-full-init) -join \" `n\" )" ,
108
- starship
161
+ starship. sprint ( ) ?
109
162
) ;
110
163
Some ( script)
111
164
}
112
165
Some ( "ion" ) => {
113
- let script = format ! ( "eval $({} init ion --print-full-init)" , starship) ;
166
+ let script = format ! ( "eval $({} init ion --print-full-init)" , starship. sprint ( ) ? ) ;
114
167
Some ( script)
115
168
}
116
169
None => {
@@ -143,32 +196,31 @@ fi"#,
143
196
/* This function (called when `--print-full-init` is passed to `starship init`)
144
197
prints out the main initialization script */
145
198
pub fn init_main ( shell_name : & str ) -> io:: Result < ( ) > {
146
- let starship_path = path_to_starship ( ) ?. replace ( " \" " , " \" ' \" ' \" " ) ;
147
-
148
- let setup_script = match shell_name {
149
- "bash" => Some ( BASH_INIT ) ,
150
- "zsh" => Some ( ZSH_INIT ) ,
151
- "fish" => Some ( FISH_INIT ) ,
152
- "powershell" => Some ( PWSH_INIT ) ,
153
- "ion" => Some ( ION_INIT ) ,
199
+ let starship_path = StarshipPath :: init ( ) ?;
200
+
201
+ match shell_name {
202
+ "bash" => print_script ( BASH_INIT , & starship_path . sprint_posix ( ) ? ) ,
203
+ "zsh" => print_script ( ZSH_INIT , & starship_path . sprint_posix ( ) ? ) ,
204
+ "fish" => print_script ( FISH_INIT , & starship_path . sprint_posix ( ) ? ) ,
205
+ "powershell" => print_script ( PWSH_INIT , & starship_path . sprint ( ) ? ) ,
206
+ "ion" => print_script ( ION_INIT , & starship_path . sprint ( ) ? ) ,
154
207
_ => {
155
208
println ! (
156
209
"printf \" Shell name detection failed on phase two init.\\ n\
157
210
This probably indicates a bug within starship: please open\\ n\
158
211
an issue at https://github.com/starship/starship/issues/new\\ n\" "
159
212
) ;
160
- None
161
213
}
162
- } ;
163
- if let Some ( script) = setup_script {
164
- // Set up quoting for starship path in case it has spaces.
165
- let starship_path_string = format ! ( "\" {}\" " , starship_path) ;
166
- let script = script. replace ( "::STARSHIP::" , & starship_path_string) ;
167
- print ! ( "{}" , script) ;
168
- } ;
214
+ }
169
215
Ok ( ( ) )
170
216
}
171
217
218
+ fn print_script ( script : & str , path : & str ) {
219
+ let starship_path_string = format ! ( "\" {}\" " , path) ;
220
+ let script = script. replace ( "::STARSHIP::" , & starship_path_string) ;
221
+ print ! ( "{}" , script) ;
222
+ }
223
+
172
224
/* GENERAL INIT SCRIPT NOTES
173
225
174
226
Each init script will be passed as-is. Global notes for init scripts are in this
0 commit comments