@@ -1,7 +1,6 @@
1−use std::collections::HashMap;
21use std::ffi::OsStr;
32use std::fs;
4−use std::path::{Path, PathBuf};
3+use std::path::Path;
54
65use lazycell::LazyCell;
76
@@ -15,17 +14,26 @@ use crate::error::*;
1514use crate::input::{InputReader, OpenedInput, OpenedInputKind};
1615use crate::syntax_mapping::{MappingTarget, SyntaxMapping};
1716
17+use ignored_suffixes::*;
18+use minimal_assets::*;
19+use serialized_syntax_set::*;
20+
21+#[cfg(feature = "build-assets")]
22+pub use crate::assets::build_assets::*;
23+
24+pub(crate) mod assets_metadata;
25+#[cfg(feature = "build-assets")]
26+mod build_assets;
27+mod ignored_suffixes;
28+mod minimal_assets;
29+mod serialized_syntax_set;
30+
1831#[derive(Debug)]
1932pub struct HighlightingAssets {
2033 syntax_set_cell: LazyCell<SyntaxSet>,
2134 serialized_syntax_set: SerializedSyntaxSet,
2235
23− minimal_syntaxes: MinimalSyntaxes,
24−
25− /// Lazily load serialized [SyntaxSet]s from [Self.minimal_syntaxes]. The
26− /// index in this vec matches the index in
27− /// [Self.minimal_syntaxes.serialized_syntax_sets]
28− deserialized_minimal_syntaxes: Vec<LazyCell<SyntaxSet>>,
36+ minimal_assets: MinimalAssets,
2937
3038 theme_set: ThemeSet,
3139 fallback_theme: Option<&'static str>,
@@ -37,22 +45,6 @@ pub struct SyntaxReferenceInSet<'a> {
3745 pub syntax_set: &'a SyntaxSet,
3846}
3947
40−/// Stores and allows lookup of minimal [SyntaxSet]s. The [SyntaxSet]s are
41−/// stored in serialized form, and are deserialized on-demand. This gives good
42−/// startup performance since only the necessary [SyntaxReference]s needs to be
43−/// deserialized.
44−#[derive(Debug, Clone, serde::Deserialize, serde::Serialize)]
45−pub(crate) struct MinimalSyntaxes {
46− /// Lookup the index into `serialized_syntax_sets` of a [SyntaxSet] by the
47− /// name of any [SyntaxReference] inside the [SyntaxSet]
48− /// (We will later add `by_extension`, `by_first_line`, etc.)
49− pub(crate) by_name: HashMap<String, usize>,
50−
51− /// Serialized [SyntaxSet]s. Whether or not this data is compressed is
52− /// decided by [COMPRESS_SERIALIZED_MINIMAL_SYNTAXES]
53− pub(crate) serialized_syntax_sets: Vec<Vec<u8>>,
54−}
55−
5648// Compress for size of ~700 kB instead of ~4600 kB at the cost of ~30% longer deserialization time
5749pub(crate) const COMPRESS_SYNTAXES: bool = true;
5850
@@ -70,41 +62,16 @@ pub(crate) const COMPRESS_SERIALIZED_MINIMAL_SYNTAXES: bool = true;
7062// efficient byte-by-byte copy of `serialized_syntax_sets`.
7163pub(crate) const COMPRESS_MINIMAL_SYNTAXES: bool = false;
7264
73−const IGNORED_SUFFIXES: [&str; 13] = [
74− // Editor etc backups
75− "~",
76− ".bak",
77− ".old",
78− ".orig",
79− // Debian and derivatives apt/dpkg/ucf backups
80− ".dpkg-dist",
81− ".dpkg-old",
82− ".ucf-dist",
83− ".ucf-new",
84− ".ucf-old",
85− // Red Hat and derivatives rpm backups
86− ".rpmnew",
87− ".rpmorig",
88− ".rpmsave",
89− // Build system input/template files
90− ".in",
91−];
92−
9365impl HighlightingAssets {
9466 fn new(
9567 serialized_syntax_set: SerializedSyntaxSet,
9668 minimal_syntaxes: MinimalSyntaxes,
9769 theme_set: ThemeSet,
9870 ) -> Self {
99− // Prepare so we can lazily load minimal syntaxes without a mut reference
100− let deserialized_minimal_syntaxes =
101− vec![LazyCell::new(); minimal_syntaxes.serialized_syntax_sets.len()];
102−
10371 HighlightingAssets {
10472 syntax_set_cell: LazyCell::new(),
10573 serialized_syntax_set,
106− deserialized_minimal_syntaxes,
107− minimal_syntaxes,
74+ minimal_assets: MinimalAssets::new(minimal_syntaxes),
10875 theme_set,
10976 fallback_theme: None,
11077 }
@@ -167,37 +134,12 @@ impl HighlightingAssets {
167134 /// tries to find a minimal [SyntaxSet]. If none is found, returns the
168135 /// [SyntaxSet] that contains all syntaxes.
169136 fn get_syntax_set_by_name(&self, name: &str) -> Result<&SyntaxSet> {
170− let minimal_syntax_set = self
171− .minimal_syntaxes
172− .by_name
173− .get(&name.to_ascii_lowercase())
174− .and_then(|index| self.get_minimal_syntax_set_with_index(*index));
175−
176− match minimal_syntax_set {
137+ match self.minimal_assets.get_syntax_set_by_name(name) {
177138 Some(syntax_set) => Ok(syntax_set),
178139 None => self.get_syntax_set(),
179140 }
180141 }
181142
182− fn load_minimal_syntax_set_with_index(&self, index: usize) -> Result<SyntaxSet> {
183− let serialized_syntax_set = &self.minimal_syntaxes.serialized_syntax_sets[index];
184− asset_from_contents(
185− &serialized_syntax_set[..],
186− &format!("minimal syntax set {}", index),
187− COMPRESS_SERIALIZED_MINIMAL_SYNTAXES,
188− )
189− .map_err(|_| format!("Could not parse minimal syntax set {}", index).into())
190− }
191−
192− fn get_minimal_syntax_set_with_index(&self, index: usize) -> Option<&SyntaxSet> {
193− self.deserialized_minimal_syntaxes
194− .get(index)
195− .and_then(|cell| {
196− cell.try_borrow_with(|| self.load_minimal_syntax_set_with_index(index))
197− .ok()
198− })
199− }
200−
201143 /// Use [Self::get_syntax_for_file_name] instead
202144 #[deprecated]
203145 pub fn syntax_for_file_name(
@@ -319,7 +261,9 @@ impl HighlightingAssets {
319261 syntax = self.find_syntax_by_file_name_extension(file_name)?;
320262 }
321263 if syntax.is_none() {
322− syntax = self.get_extension_syntax_with_stripped_suffix(file_name)?;
264+ syntax = try_with_stripped_suffix(file_name, |stripped_file_name| {
265+ self.get_extension_syntax(stripped_file_name) // Note: recursion
266+ })?;
323267 }
324268 Ok(syntax)
325269 }
@@ -340,25 +284,6 @@ impl HighlightingAssets {
340284 )
341285 }
342286
343− /// If we find an ignored suffix on the file name, e.g. '~', we strip it and
344− /// then try again to find a syntax without it. Note that we do this recursively.
345− fn get_extension_syntax_with_stripped_suffix(
346− &self,
347− file_name: &OsStr,
348− ) -> Result<Option<SyntaxReferenceInSet>> {
349− let file_path = Path::new(file_name);
350− let mut syntax = None;
351− if let Some(file_str) = file_path.to_str() {
352− for suffix in &IGNORED_SUFFIXES {
353− if let Some(stripped_filename) = file_str.strip_suffix(suffix) {
354− syntax = self.get_extension_syntax(OsStr::new(stripped_filename))?;
355− break;
356− }
357− }
358− }
359− Ok(syntax)
360− }
361−
362287 fn get_first_line_syntax(
363288 &self,
364289 reader: &mut InputReader,
@@ -371,31 +296,6 @@ impl HighlightingAssets {
371296 }
372297}
373298
374−#[cfg(feature = "build-assets")]
375−pub use crate::build_assets::build_assets as build;
376−
377−/// A SyntaxSet in serialized form, i.e. bincoded and flate2 compressed.
378−/// We keep it in this format since we want to load it lazily.
379−#[derive(Debug)]
380−enum SerializedSyntaxSet {
381− /// The data comes from a user-generated cache file.
382− FromFile(PathBuf),
383−
384− /// The data to use is embedded into the bat binary.
385− FromBinary(&'static [u8]),
386−}
387−
388−impl SerializedSyntaxSet {
389− fn deserialize(&self) -> Result<SyntaxSet> {
390− match self {
391− SerializedSyntaxSet::FromBinary(data) => Ok(from_binary(data, COMPRESS_SYNTAXES)),
392− SerializedSyntaxSet::FromFile(ref path) => {
393− asset_from_cache(path, "syntax set", COMPRESS_SYNTAXES)
394− }
395− }
396− }
397−}
398−
399299pub(crate) fn get_serialized_integrated_syntaxset() -> &'static [u8] {
400300 include_bytes!("../assets/syntaxes.bin")
401301}