@@ -85,6 +85,7 @@ pub type FileLocation<'a> = (PathOrId<'a>, Option<(usize, usize)>);
85
85
86
86
pub enum CachedPreview {
87
87
Document ( Box < Document > ) ,
88
+ Directory ( Vec < ( String , bool ) > ) ,
88
89
Binary ,
89
90
LargeFile ,
90
91
NotFound ,
@@ -106,12 +107,20 @@ impl Preview<'_, '_> {
106
107
}
107
108
}
108
109
110
+ fn dir_content ( & self ) -> Option < & Vec < ( String , bool ) > > {
111
+ match self {
112
+ Preview :: Cached ( CachedPreview :: Directory ( dir_content) ) => Some ( dir_content) ,
113
+ _ => None ,
114
+ }
115
+ }
116
+
109
117
/// Alternate text to show for the preview.
110
118
fn placeholder ( & self ) -> & str {
111
119
match * self {
112
120
Self :: EditorDocument ( _) => "<Invalid file location>" ,
113
121
Self :: Cached ( preview) => match preview {
114
122
CachedPreview :: Document ( _) => "<Invalid file location>" ,
123
+ CachedPreview :: Directory ( _) => "<Invalid directory location>" ,
115
124
CachedPreview :: Binary => "<Binary file>" ,
116
125
CachedPreview :: LargeFile => "<File too large to preview>" ,
117
126
CachedPreview :: NotFound => "<File not found>" ,
@@ -584,33 +593,58 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
584
593
}
585
594
586
595
let path: Arc < Path > = path. into ( ) ;
587
- let data = std:: fs:: File :: open ( & path) . and_then ( |file| {
588
- let metadata = file. metadata ( ) ?;
589
- // Read up to 1kb to detect the content type
590
- let n = file. take ( 1024 ) . read_to_end ( & mut self . read_buffer ) ?;
591
- let content_type = content_inspector:: inspect ( & self . read_buffer [ ..n] ) ;
592
- self . read_buffer . clear ( ) ;
593
- Ok ( ( metadata, content_type) )
594
- } ) ;
595
- let preview = data
596
- . map (
597
- |( metadata, content_type) | match ( metadata. len ( ) , content_type) {
598
- ( _, content_inspector:: ContentType :: BINARY ) => CachedPreview :: Binary ,
599
- ( size, _) if size > MAX_FILE_SIZE_FOR_PREVIEW => {
600
- CachedPreview :: LargeFile
596
+ let preview = std:: fs:: metadata ( & path)
597
+ . and_then ( |metadata| {
598
+ if metadata. is_dir ( ) {
599
+ let files = super :: directory_content ( & path) ?;
600
+ let file_names: Vec < _ > = files
601
+ . iter ( )
602
+ . filter_map ( |( path, is_dir) | {
603
+ let name = path. file_name ( ) ?. to_string_lossy ( ) ;
604
+ if * is_dir {
605
+ Some ( ( format ! ( "{}/" , name) , true ) )
606
+ } else {
607
+ Some ( ( name. into_owned ( ) , false ) )
608
+ }
609
+ } )
610
+ . collect ( ) ;
611
+ Ok ( CachedPreview :: Directory ( file_names) )
612
+ } else if metadata. is_file ( ) {
613
+ if metadata. len ( ) > MAX_FILE_SIZE_FOR_PREVIEW {
614
+ return Ok ( CachedPreview :: LargeFile ) ;
615
+ }
616
+ let content_type = std:: fs:: File :: open ( & path) . and_then ( |file| {
617
+ // Read up to 1kb to detect the content type
618
+ let n = file. take ( 1024 ) . read_to_end ( & mut self . read_buffer ) ?;
619
+ let content_type =
620
+ content_inspector:: inspect ( & self . read_buffer [ ..n] ) ;
621
+ self . read_buffer . clear ( ) ;
622
+ Ok ( content_type)
623
+ } ) ?;
624
+ if content_type. is_binary ( ) {
625
+ return Ok ( CachedPreview :: Binary ) ;
601
626
}
602
- _ => Document :: open ( & path, None , None , editor. config . clone ( ) )
603
- . map ( |doc| {
627
+ Document :: open ( & path, None , None , editor. config . clone ( ) ) . map_or (
628
+ Err ( std:: io:: Error :: new (
629
+ std:: io:: ErrorKind :: NotFound ,
630
+ "Cannot open document" ,
631
+ ) ) ,
632
+ |doc| {
604
633
// Asynchronously highlight the new document
605
634
helix_event:: send_blocking (
606
635
& self . preview_highlight_handler ,
607
636
path. clone ( ) ,
608
637
) ;
609
- CachedPreview :: Document ( Box :: new ( doc) )
610
- } )
611
- . unwrap_or ( CachedPreview :: NotFound ) ,
612
- } ,
613
- )
638
+ Ok ( CachedPreview :: Document ( Box :: new ( doc) ) )
639
+ } ,
640
+ )
641
+ } else {
642
+ Err ( std:: io:: Error :: new (
643
+ std:: io:: ErrorKind :: NotFound ,
644
+ "Neither a dir, nor a file" ,
645
+ ) )
646
+ }
647
+ } )
614
648
. unwrap_or ( CachedPreview :: NotFound ) ;
615
649
self . preview_cache . insert ( path. clone ( ) , preview) ;
616
650
Some ( ( Preview :: Cached ( & self . preview_cache [ & path] ) , range) )
@@ -823,6 +857,7 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
823
857
// clear area
824
858
let background = cx. editor . theme . get ( "ui.background" ) ;
825
859
let text = cx. editor . theme . get ( "ui.text" ) ;
860
+ let directory = cx. editor . theme . get ( "ui.text.directory" ) ;
826
861
surface. clear_with ( area, background) ;
827
862
828
863
const BLOCK : Block < ' _ > = Block :: bordered ( ) ;
@@ -844,6 +879,22 @@ impl<T: 'static + Send + Sync, D: 'static + Send + Sync> Picker<T, D> {
844
879
doc
845
880
}
846
881
_ => {
882
+ if let Some ( dir_content) = preview. dir_content ( ) {
883
+ for ( i, ( path, is_dir) ) in
884
+ dir_content. iter ( ) . take ( inner. height as usize ) . enumerate ( )
885
+ {
886
+ let style = if * is_dir { directory } else { text } ;
887
+ surface. set_stringn (
888
+ inner. x ,
889
+ inner. y + i as u16 ,
890
+ path,
891
+ inner. width as usize ,
892
+ style,
893
+ ) ;
894
+ }
895
+ return ;
896
+ }
897
+
847
898
let alt_text = preview. placeholder ( ) ;
848
899
let x = inner. x + inner. width . saturating_sub ( alt_text. len ( ) as u16 ) / 2 ;
849
900
let y = inner. y + inner. height / 2 ;
0 commit comments