@@ -70,6 +70,8 @@ extern crate doc_comment;
7070#[ cfg( test) ]
7171doctest ! ( "../README.md" ) ;
7272
73+ mod utils;
74+
7375use std:: cmp;
7476use std:: cmp:: Ordering ;
7577use std:: error:: Error ;
@@ -179,6 +181,7 @@ pub fn glob(pattern: &str) -> Result<Paths, PatternError> {
179181///
180182/// Paths are yielded in alphabetical order.
181183pub fn glob_with ( pattern : & str , options : MatchOptions ) -> Result < Paths , PatternError > {
184+ use utils:: { get_home_dir, get_user_name} ;
182185 #[ cfg( windows) ]
183186 fn check_windows_verbatim ( p : & Path ) -> bool {
184187 match p. components ( ) . next ( ) {
@@ -211,7 +214,34 @@ pub fn glob_with(pattern: &str, options: MatchOptions) -> Result<Paths, PatternE
211214
212215 // make sure that the pattern is valid first, else early return with error
213216 let _ = Pattern :: new ( pattern) ?;
214-
217+ let mut new_pattern = pattern. to_owned ( ) ;
218+ if options. glob_tilde_expansion {
219+ let home_dir = get_home_dir ( ) ;
220+ if pattern == "~" || pattern. starts_with ( "~/" ) {
221+ if let Some ( home) = home_dir {
222+ new_pattern = pattern. replacen ( "~" , & home, 1 ) ;
223+ }
224+ } else if pattern. starts_with ( "~" ) {
225+ if let Some ( user) = get_user_name ( ) {
226+ match pattern. strip_prefix ( "~" ) . unwrap ( ) . strip_prefix ( & user) {
227+ Some ( v) if v. starts_with ( "/" ) || v. is_empty ( ) => {
228+ if let Some ( mut v) = home_dir {
229+ v. push_str (
230+ pattern
231+ . strip_prefix ( "~" )
232+ . unwrap ( )
233+ . strip_prefix ( & user)
234+ . unwrap ( ) ,
235+ ) ;
236+ new_pattern = v;
237+ }
238+ }
239+ _ => { }
240+ } ;
241+ }
242+ }
243+ }
244+ let pattern = new_pattern. as_str ( ) ;
215245 let mut components = Path :: new ( pattern) . components ( ) . peekable ( ) ;
216246 loop {
217247 match components. peek ( ) {
@@ -1050,7 +1080,7 @@ fn chars_eq(a: char, b: char, case_sensitive: bool) -> bool {
10501080
10511081/// Configuration options to modify the behaviour of `Pattern::matches_with(..)`.
10521082#[ allow( missing_copy_implementations) ]
1053- #[ derive( Debug , Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash , Default ) ]
1083+ #[ derive( Debug , Copy , Clone , PartialEq , Eq , PartialOrd , Ord , Hash ) ]
10541084pub struct MatchOptions {
10551085 /// Whether or not patterns should be matched in a case-sensitive manner.
10561086 /// This currently only considers upper/lower case relationships between
@@ -1069,6 +1099,21 @@ pub struct MatchOptions {
10691099 /// conventionally considered hidden on Unix systems and it might be
10701100 /// desirable to skip them when listing files.
10711101 pub require_literal_leading_dot : bool ,
1102+
1103+ /// Whether or not tilde expansion should be performed. if home directory
1104+ /// or user name cannot be determined, then no tilde expansion is performed.
1105+ pub glob_tilde_expansion : bool ,
1106+ }
1107+
1108+ impl Default for MatchOptions {
1109+ fn default ( ) -> Self {
1110+ Self {
1111+ case_sensitive : true ,
1112+ require_literal_separator : false ,
1113+ require_literal_leading_dot : false ,
1114+ glob_tilde_expansion : false ,
1115+ }
1116+ }
10721117}
10731118
10741119impl MatchOptions {
@@ -1086,16 +1131,13 @@ impl MatchOptions {
10861131 /// }
10871132 /// ```
10881133 ///
1089- /// # Note
1090- /// The behavior of this method doesn't match `default()`'s. This returns
1091- /// `case_sensitive` as `true` while `default()` does it as `false`.
1092- // FIXME: Consider unity the behavior with `default()` in a next major release.
10931134 pub fn new ( ) -> Self {
1094- Self {
1095- case_sensitive : true ,
1096- require_literal_separator : false ,
1097- require_literal_leading_dot : false ,
1098- }
1135+ Self :: default ( )
1136+ }
1137+ /// Enables or disables tilde (`~`) expansion in glob patterns
1138+ pub fn glob_tilde_expansion ( mut self , v : bool ) -> Self {
1139+ self . glob_tilde_expansion = v;
1140+ self
10991141 }
11001142}
11011143
0 commit comments