diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index a2c09770..f8007897 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -122,6 +122,10 @@ impl App { }; let mut syntax_mapping = SyntaxMapping::new(); + // start building glob matchers for builtin mappings immediately + // this is an appropriate approach because it's statistically likely that + // all the custom mappings need to be checked + syntax_mapping.start_offload_build_all(); if let Some(values) = self.matches.get_many::("ignored-suffix") { for suffix in values { diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index 0dac0c02..7c96c513 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -1,6 +1,14 @@ -use std::path::Path; +use std::{ + path::Path, + sync::{ + atomic::{AtomicBool, Ordering}, + Arc, + }, + thread, +}; use globset::{Candidate, GlobBuilder, GlobMatcher}; +use once_cell::sync::Lazy; use crate::error::Result; use builtin::BUILTIN_MAPPINGS; @@ -44,7 +52,20 @@ pub struct SyntaxMapping<'a> { /// /// Rules in front have precedence. custom_mappings: Vec<(GlobMatcher, MappingTarget<'a>)>, + pub(crate) ignored_suffixes: IgnoredSuffixes<'a>, + + /// A flag to halt glob matcher building, which is offloaded to another thread. + /// + /// We have this so that we can signal the thread to halt early when appropriate. + halt_glob_build: Arc, +} + +impl<'a> Drop for SyntaxMapping<'a> { + fn drop(&mut self) { + // signal the offload thread to halt early + self.halt_glob_build.store(true, Ordering::Relaxed); + } } impl<'a> SyntaxMapping<'a> { @@ -52,6 +73,24 @@ impl<'a> SyntaxMapping<'a> { Default::default() } + /// Start a thread to build the glob matchers for all builtin mappings. + /// + /// The use of this function while not necessary, is useful to speed up startup + /// times by starting this work early in parallel. + /// + /// The thread halts if/when `halt_glob_build` is set to true. + pub fn start_offload_build_all(&self) { + let halt = Arc::clone(&self.halt_glob_build); + thread::spawn(move || { + for (matcher, _) in BUILTIN_MAPPINGS.iter() { + if halt.load(Ordering::Relaxed) { + break; + } + Lazy::force(matcher); + } + }); + } + pub fn insert(&mut self, from: &str, to: MappingTarget<'a>) -> Result<()> { let matcher = make_glob_matcher(from)?; self.custom_mappings.push((matcher, to));