From 78fba8683bdce31ad2d8e710cb70fb9f05b21e8c Mon Sep 17 00:00:00 2001 From: Blaž Hrastnik Date: Mon, 28 Feb 2022 18:15:34 +0900 Subject: Picker performance improvements --- helix-term/src/ui/mod.rs | 44 +++++++++++++++++--------------------------- 1 file changed, 17 insertions(+), 27 deletions(-) (limited to 'helix-term/src/ui/mod.rs') diff --git a/helix-term/src/ui/mod.rs b/helix-term/src/ui/mod.rs index 011ad9ba..d46de2d3 100644 --- a/helix-term/src/ui/mod.rs +++ b/helix-term/src/ui/mod.rs @@ -98,7 +98,9 @@ pub fn regex_prompt( pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePicker { use ignore::{types::TypesBuilder, WalkBuilder}; - use std::time; + use std::time::Instant; + + let now = Instant::now(); let mut walk_builder = WalkBuilder::new(&root); walk_builder @@ -116,56 +118,44 @@ pub fn file_picker(root: PathBuf, config: &helix_view::editor::Config) -> FilePi // We want to exclude files that the editor can't handle yet let mut type_builder = TypesBuilder::new(); - type_builder .add( "compressed", "*.{zip,gz,bz2,zst,lzo,sz,tgz,tbz2,lz,lz4,lzma,lzo,z,Z,xz,7z,rar,cab}", ) - // This shouldn't panic as the above is static, but if it ever - // is changed and becomes invalid it will catch here rather than - // being unnoticed. .expect("Invalid type definition"); type_builder.negate("all"); - - if let Ok(excluded_types) = type_builder.build() { - walk_builder.types(excluded_types); - } + let excluded_types = type_builder + .build() + .expect("failed to build excluded_types"); + walk_builder.types(excluded_types); // We want files along with their modification date for sorting let files = walk_builder.build().filter_map(|entry| { let entry = entry.ok()?; - // Path::is_dir() traverses symlinks, so we use it over DirEntry::is_dir - if entry.path().is_dir() { + + // This is faster than entry.path().is_dir() since it uses cached fs::Metadata fetched by ignore/walkdir + let is_dir = entry.file_type().map(|ft| ft.is_dir()).unwrap_or(false); + + if is_dir { // Will give a false positive if metadata cannot be read (eg. permission error) return None; } - let time = entry.metadata().map_or(time::UNIX_EPOCH, |metadata| { - metadata - .accessed() - .or_else(|_| metadata.modified()) - .or_else(|_| metadata.created()) - .unwrap_or(time::UNIX_EPOCH) - }); - - Some((entry.into_path(), time)) + Some(entry.into_path()) }); // Cap the number of files if we aren't in a git project, preventing // hangs when using the picker in your home directory - let mut files: Vec<_> = if root.join(".git").is_dir() { + let files: Vec<_> = if root.join(".git").is_dir() { files.collect() } else { - const MAX: usize = 8192; + // const MAX: usize = 8192; + const MAX: usize = 100_000; files.take(MAX).collect() }; - // Most recently modified first - files.sort_by_key(|file| std::cmp::Reverse(file.1)); - - // Strip the time data so we can send just the paths to the FilePicker - let files = files.into_iter().map(|(path, _)| path).collect(); + log::debug!("file_picker init {:?}", Instant::now().duration_since(now)); FilePicker::new( files, -- cgit v1.2.3-70-g09d2