@@ -3890,9 +3890,6 @@ pub fn completion_path(cx: &mut Context) {
3890
3890
let cur_line = text. char_to_line ( cursor) ;
3891
3891
let begin_line = text. line_to_char ( cur_line) ;
3892
3892
let line_until_cursor = text. slice ( begin_line..cursor) . to_string ( ) ;
3893
- // TODO find a good regex for most use cases (especially Windows, which is not yet covered...)
3894
- // currently only one path match per line is possible in unix
3895
- static PATH_REGEX : Lazy < Regex > = Lazy :: new ( || Regex :: new ( r"((?:\.{0,2}/)+.*)$" ) . unwrap ( ) ) ;
3896
3893
3897
3894
// TODO: trigger_offset should be the cursor offset but we also need a starting offset from where we want to apply
3898
3895
// completion filtering. For example logger.te| should filter the initial suggestion list with "te".
@@ -3908,37 +3905,76 @@ pub fn completion_path(cx: &mut Context) {
3908
3905
let callback = async move {
3909
3906
let call: job:: Callback =
3910
3907
Box :: new ( move |editor : & mut Editor , compositor : & mut Compositor | {
3911
- if doc ! ( editor) . mode ( ) != Mode :: Insert {
3908
+ let doc = doc ! ( editor) ;
3909
+ if doc. mode ( ) != Mode :: Insert {
3912
3910
// we're not in insert mode anymore
3913
3911
return ;
3914
3912
}
3915
- // read dir for a possibly matched path
3916
- let items = PATH_REGEX
3913
+
3914
+ // TODO async path completion (for this probably the whole completion system has to be reworked to be async without producing race conditions)
3915
+ let items = ui:: PATH_REGEX
3917
3916
. find ( & line_until_cursor)
3918
- . and_then ( |m| {
3919
- let mut path = PathBuf :: from ( m. as_str ( ) ) ;
3920
- if path. starts_with ( "." ) {
3921
- path = std:: env:: current_dir ( ) . unwrap ( ) . join ( path) ;
3917
+ . and_then ( |matched_path| {
3918
+ let matched_path = matched_path. as_str ( ) ;
3919
+ let mut path = PathBuf :: from ( matched_path) ;
3920
+ if path. is_relative ( ) {
3921
+ if let Some ( doc_path) = doc. path ( ) . and_then ( |dp| dp. parent ( ) ) {
3922
+ path = doc_path. join ( path) ;
3923
+ }
3922
3924
}
3923
- std:: fs:: read_dir ( path) . ok ( ) . map ( |rd| {
3924
- rd. filter_map ( |re| re. ok ( ) )
3925
- . filter_map ( |re| {
3926
- re. metadata ( ) . ok ( ) . map ( |m| CompletionItem :: Path {
3927
- path : re. path ( ) ,
3928
- permissions : m. permissions ( ) ,
3929
- path_type : if m. is_file ( ) {
3925
+ let ends_with_slash = match matched_path. chars ( ) . last ( ) {
3926
+ Some ( '/' ) => true , // TODO support Windows
3927
+ None => return Some ( vec ! [ ] ) ,
3928
+ _ => false ,
3929
+ } ;
3930
+ // check if there are chars after the last slash, and if these chars represent a directory
3931
+ let ( dir_path, typed_file_name) = match std:: fs:: metadata ( path. clone ( ) ) . ok ( )
3932
+ {
3933
+ Some ( m) if m. is_dir ( ) && ends_with_slash => {
3934
+ ( Some ( path. as_path ( ) ) , None )
3935
+ }
3936
+ _ if !ends_with_slash => {
3937
+ ( path. parent ( ) , path. file_name ( ) . and_then ( |f| f. to_str ( ) ) )
3938
+ }
3939
+ _ => return Some ( vec ! [ ] ) ,
3940
+ } ;
3941
+ // read dir for a possibly matched path
3942
+ dir_path
3943
+ . and_then ( |path| std:: fs:: read_dir ( path) . ok ( ) )
3944
+ . map ( |read_dir| {
3945
+ read_dir
3946
+ . filter_map ( |dir_entry| dir_entry. ok ( ) )
3947
+ . filter_map ( |dir_entry| {
3948
+ let path = dir_entry. path ( ) ;
3949
+ // check if <chars> in <path>/<chars><cursor> matches the start of the filename
3950
+ let filename_starts_with_prefix = match (
3951
+ path. file_name ( ) . and_then ( |f| f. to_str ( ) ) ,
3952
+ typed_file_name,
3953
+ ) {
3954
+ ( Some ( re_stem) , Some ( t) ) => re_stem. starts_with ( t) ,
3955
+ _ => true ,
3956
+ } ;
3957
+ if filename_starts_with_prefix {
3958
+ dir_entry. metadata ( ) . ok ( ) . map ( |md| ( path, md) )
3959
+ } else {
3960
+ None
3961
+ }
3962
+ } )
3963
+ . map ( |( path, md) | CompletionItem :: Path {
3964
+ path,
3965
+ permissions : md. permissions ( ) ,
3966
+ path_type : if md. is_file ( ) {
3930
3967
PathType :: File
3931
- } else if m . is_dir ( ) {
3968
+ } else if md . is_dir ( ) {
3932
3969
PathType :: Dir
3933
- } else if m . is_symlink ( ) {
3970
+ } else if md . is_symlink ( ) {
3934
3971
PathType :: Symlink
3935
3972
} else {
3936
3973
PathType :: Unknown
3937
3974
} ,
3938
3975
} )
3939
- } )
3940
- . collect :: < Vec < _ > > ( )
3941
- } )
3976
+ . collect :: < Vec < _ > > ( )
3977
+ } )
3942
3978
} )
3943
3979
. unwrap_or_default ( ) ;
3944
3980
0 commit comments