From 700ee57f5861138e4638ef9b12c8fe4cb03989da Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sat, 9 Oct 2021 15:13:36 -0400 Subject: [PATCH 01/15] Support for ignored-suffix CLI arguments --- src/assets.rs | 23 ++++--- src/assets/ignored_suffixes.rs | 42 ------------- src/bin/bat/app.rs | 6 ++ src/bin/bat/assets.rs | 11 ++-- src/bin/bat/clap_app.rs | 11 ++++ src/bin/bat/main.rs | 6 +- src/config.rs | 3 + src/ignored_suffixes.rs | 104 +++++++++++++++++++++++++++++++ src/lib.rs | 1 + src/pretty_printer.rs | 3 +- tests/assets.rs | 4 +- tests/no_duplicate_extensions.rs | 4 +- 12 files changed, 156 insertions(+), 62 deletions(-) delete mode 100644 src/assets/ignored_suffixes.rs create mode 100644 src/ignored_suffixes.rs diff --git a/src/assets.rs b/src/assets.rs index 5b35d8033f..e2592a5e48 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -11,10 +11,10 @@ use path_abs::PathAbs; use crate::bat_warning; use crate::error::*; +use crate::ignored_suffixes::IgnoredSuffixes; use crate::input::{InputReader, OpenedInput}; use crate::syntax_mapping::{MappingTarget, SyntaxMapping}; -use ignored_suffixes::*; use minimal_assets::*; use serialized_syntax_set::*; @@ -24,7 +24,6 @@ pub use crate::assets::build_assets::*; pub(crate) mod assets_metadata; #[cfg(feature = "build-assets")] mod build_assets; -mod ignored_suffixes; mod minimal_assets; mod serialized_syntax_set; @@ -37,6 +36,7 @@ pub struct HighlightingAssets { theme_set: ThemeSet, fallback_theme: Option<&'static str>, + ignored_suffixes: IgnoredSuffixes, } #[derive(Debug)] @@ -67,6 +67,7 @@ impl HighlightingAssets { serialized_syntax_set: SerializedSyntaxSet, minimal_syntaxes: MinimalSyntaxes, theme_set: ThemeSet, + ignored_suffixes: IgnoredSuffixes, ) -> Self { HighlightingAssets { syntax_set_cell: LazyCell::new(), @@ -74,6 +75,7 @@ impl HighlightingAssets { minimal_assets: MinimalAssets::new(minimal_syntaxes), theme_set, fallback_theme: None, + ignored_suffixes, } } @@ -81,7 +83,7 @@ impl HighlightingAssets { "Monokai Extended" } - pub fn from_cache(cache_path: &Path) -> Result { + pub fn from_cache(cache_path: &Path, ignored_suffixes: IgnoredSuffixes) -> Result { Ok(HighlightingAssets::new( SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")), asset_from_cache( @@ -90,14 +92,16 @@ impl HighlightingAssets { COMPRESS_MINIMAL_SYNTAXES, )?, asset_from_cache(&cache_path.join("themes.bin"), "theme set", COMPRESS_THEMES)?, + ignored_suffixes, )) } - pub fn from_binary() -> Self { + pub fn from_binary(ignored_suffixes: IgnoredSuffixes) -> Self { HighlightingAssets::new( SerializedSyntaxSet::FromBinary(get_serialized_integrated_syntaxset()), get_integrated_minimal_syntaxes(), get_integrated_themeset(), + ignored_suffixes, ) } @@ -269,9 +273,12 @@ impl HighlightingAssets { syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?; } if syntax.is_none() { - syntax = try_with_stripped_suffix(file_name, |stripped_file_name| { - self.get_extension_syntax(stripped_file_name) // Note: recursion - })?; + syntax = self.ignored_suffixes.try_with_stripped_suffix( + file_name, + |stripped_file_name| { + self.get_extension_syntax(stripped_file_name) // Note: recursion + }, + )?; } Ok(syntax) } @@ -358,7 +365,7 @@ mod tests { impl<'a> SyntaxDetectionTest<'a> { fn new() -> Self { SyntaxDetectionTest { - assets: HighlightingAssets::from_binary(), + assets: HighlightingAssets::from_binary(IgnoredSuffixes::default()), syntax_mapping: SyntaxMapping::builtin(), temp_dir: TempDir::new().expect("creation of temporary directory"), } diff --git a/src/assets/ignored_suffixes.rs b/src/assets/ignored_suffixes.rs deleted file mode 100644 index f653e3a052..0000000000 --- a/src/assets/ignored_suffixes.rs +++ /dev/null @@ -1,42 +0,0 @@ -use std::ffi::OsStr; -use std::path::Path; - -use crate::error::*; - -const IGNORED_SUFFIXES: [&str; 13] = [ - // Editor etc backups - "~", - ".bak", - ".old", - ".orig", - // Debian and derivatives apt/dpkg/ucf backups - ".dpkg-dist", - ".dpkg-old", - ".ucf-dist", - ".ucf-new", - ".ucf-old", - // Red Hat and derivatives rpm backups - ".rpmnew", - ".rpmorig", - ".rpmsave", - // Build system input/template files - ".in", -]; - -/// If we find an ignored suffix on the file name, e.g. '~', we strip it and -/// then try again without it. -pub fn try_with_stripped_suffix(file_name: &OsStr, func: F) -> Result> -where - F: Fn(&OsStr) -> Result>, -{ - let mut from_stripped = None; - if let Some(file_str) = Path::new(file_name).to_str() { - for suffix in &IGNORED_SUFFIXES { - if let Some(stripped_filename) = file_str.strip_suffix(suffix) { - from_stripped = func(OsStr::new(stripped_filename))?; - break; - } - } - } - Ok(from_stripped) -} diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index df89915948..b074ae69ca 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -235,6 +235,12 @@ impl App { .map(HighlightedLineRanges) .unwrap_or_default(), use_custom_assets: !self.matches.is_present("no-custom-assets"), + ignored_suffixes: self + .matches + .values_of("ignored-suffix") + .unwrap_or_default() + .map(String::from) + .collect(), }) } diff --git a/src/bin/bat/assets.rs b/src/bin/bat/assets.rs index b775a4d9f6..1f9f00f097 100644 --- a/src/bin/bat/assets.rs +++ b/src/bin/bat/assets.rs @@ -1,6 +1,8 @@ use std::borrow::Cow; use std::fs; +use bat::config::Config; +use bat::ignored_suffixes::IgnoredSuffixes; use clap::crate_version; use crate::directories::PROJECT_DIRS; @@ -24,7 +26,7 @@ pub fn clear_assets() { clear_asset("metadata.yaml", "metadata file"); } -pub fn assets_from_cache_or_binary(use_custom_assets: bool) -> Result { +pub fn assets_from_cache_or_binary(config: &Config) -> Result { let cache_dir = PROJECT_DIRS.cache_dir(); if let Some(metadata) = AssetsMetadata::load_from_folder(cache_dir)? { if !metadata.is_compatible_with(crate_version!()) { @@ -42,12 +44,13 @@ pub fn assets_from_cache_or_binary(use_custom_assets: bool) -> Result ClapApp<'static, 'static> { .hidden_short_help(true) .help("Show diagnostic information for bug reports.") ) + .arg( + Arg::with_name("ignored-suffix") + .number_of_values(1) + .multiple(true) + .takes_value(true) + .long("ignored-suffix") + .help( + "Ignore extension. For example:\n \ + 'bat --ignored-suffix \".dev\" my_file.json.dev' will use JSON syntax, and ignore '.dev'" + ) + ) .help_message("Print this help message.") .version_message("Show version information."); diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 891aace8d6..248338ebc8 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -84,7 +84,7 @@ fn get_syntax_mapping_to_paths<'a>( pub fn get_languages(config: &Config) -> Result { let mut result: String = String::new(); - let assets = assets_from_cache_or_binary(config.use_custom_assets)?; + let assets = assets_from_cache_or_binary(config)?; let mut languages = assets .get_syntaxes()? .iter() @@ -177,7 +177,7 @@ fn theme_preview_file<'a>() -> Input<'a> { } pub fn list_themes(cfg: &Config) -> Result<()> { - let assets = assets_from_cache_or_binary(cfg.use_custom_assets)?; + let assets = assets_from_cache_or_binary(cfg)?; let mut config = cfg.clone(); let mut style = HashSet::new(); style.insert(StyleComponent::Plain); @@ -218,7 +218,7 @@ pub fn list_themes(cfg: &Config) -> Result<()> { } fn run_controller(inputs: Vec, config: &Config) -> Result { - let assets = assets_from_cache_or_binary(config.use_custom_assets)?; + let assets = assets_from_cache_or_binary(config)?; let controller = Controller::new(config, &assets); controller.run(inputs) } diff --git a/src/config.rs b/src/config.rs index 76eb3990cf..d3a4cb2229 100644 --- a/src/config.rs +++ b/src/config.rs @@ -86,6 +86,9 @@ pub struct Config<'a> { /// Whether or not to allow custom assets. If this is false or if custom assets (a.k.a. /// cached assets) are not available, assets from the binary will be used instead. pub use_custom_assets: bool, + + /// Ignored suffixes + pub ignored_suffixes: Vec, } #[cfg(all(feature = "minimal-application", feature = "paging"))] diff --git a/src/ignored_suffixes.rs b/src/ignored_suffixes.rs new file mode 100644 index 0000000000..537d212938 --- /dev/null +++ b/src/ignored_suffixes.rs @@ -0,0 +1,104 @@ +use std::ffi::OsStr; +use std::path::Path; + +use crate::error::*; + +const IGNORED_SUFFIXES: [&str; 13] = [ + // Editor etc backups + "~", + ".bak", + ".old", + ".orig", + // Debian and derivatives apt/dpkg/ucf backups + ".dpkg-dist", + ".dpkg-old", + ".ucf-dist", + ".ucf-new", + ".ucf-old", + // Red Hat and derivatives rpm backups + ".rpmnew", + ".rpmorig", + ".rpmsave", + // Build system input/template files + ".in", +]; + +#[derive(Debug, Clone, Default)] +pub struct IgnoredSuffixes { + values: Vec, +} + +impl IgnoredSuffixes { + pub fn new(values: Vec) -> Self { + IgnoredSuffixes { values } + } + + /// If we find an ignored suffix on the file name, e.g. '~', we strip it and + /// then try again without it. + pub fn try_with_stripped_suffix<'a, T, F>( + &self, + file_name: &'a OsStr, + func: F, + ) -> Result> + where + F: Fn(&'a OsStr) -> Result>, + { + let mut from_stripped = None; + if let Some(file_str) = Path::new(file_name).to_str() { + for suffix in self + .values + .iter() + .map(|v| v.as_str()) + .chain(IGNORED_SUFFIXES.iter().map(|v| *v)) + { + if let Some(stripped_filename) = file_str.strip_suffix(suffix) { + from_stripped = func(OsStr::new(stripped_filename))?; + break; + } + } + } + Ok(from_stripped) + } +} + +#[test] +fn internal_suffixes() { + let ignored_suffixes = IgnoredSuffixes::new(vec![]); + + let file_names = IGNORED_SUFFIXES + .iter() + .map(|suffix| format!("test.json{}", suffix)); + for file_name_str in file_names { + let file_name = OsStr::new(&file_name_str); + let expected_stripped_file_name = OsStr::new("test.json"); + let stripped_file_name = ignored_suffixes + .try_with_stripped_suffix(file_name, |stripped_file_name| Ok(Some(stripped_file_name))); + assert_eq!( + expected_stripped_file_name, + stripped_file_name.unwrap().unwrap() + ); + } +} + +#[test] +fn external_suffixes() { + let ignored_suffixes = IgnoredSuffixes::new(vec![ + String::from(".development"), + String::from(".production"), + ]); + + let file_names = ignored_suffixes + .values + .iter() + .map(|suffix| format!("test.json{}", suffix)); + for file_name_str in file_names { + let file_name = OsStr::new(&file_name_str); + let expected_stripped_file_name = OsStr::new("test.json"); + let stripped_file_name = ignored_suffixes + .try_with_stripped_suffix(file_name, |stripped_file_name| Ok(Some(stripped_file_name))); + assert_eq!( + expected_stripped_file_name, + stripped_file_name.unwrap().unwrap() + ); + } +} diff --git a/src/lib.rs b/src/lib.rs index 02e1fefca3..0d5ca034c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,6 +32,7 @@ pub mod controller; mod decorations; mod diff; pub mod error; +pub mod ignored_suffixes; pub mod input; mod less; pub mod line_range; diff --git a/src/pretty_printer.rs b/src/pretty_printer.rs index d537b89062..9ff7befe8c 100644 --- a/src/pretty_printer.rs +++ b/src/pretty_printer.rs @@ -9,6 +9,7 @@ use crate::{ config::{Config, VisibleLines}, controller::Controller, error::Result, + ignored_suffixes::IgnoredSuffixes, input, line_range::{HighlightedLineRanges, LineRange, LineRanges}, style::{StyleComponent, StyleComponents}, @@ -49,7 +50,7 @@ impl<'a> PrettyPrinter<'a> { PrettyPrinter { inputs: vec![], config, - assets: HighlightingAssets::from_binary(), + assets: HighlightingAssets::from_binary(IgnoredSuffixes::default()), highlighted_lines: vec![], term_width: None, diff --git a/tests/assets.rs b/tests/assets.rs index f7b207fcaf..8796bf382a 100644 --- a/tests/assets.rs +++ b/tests/assets.rs @@ -1,11 +1,11 @@ -use bat::assets::HighlightingAssets; +use bat::{assets::HighlightingAssets, ignored_suffixes::IgnoredSuffixes}; /// This test ensures that we are not accidentally removing themes due to submodule updates. /// It is 'ignore'd by default because it requires themes.bin to be up-to-date. #[test] #[ignore] fn all_themes_are_present() { - let assets = HighlightingAssets::from_binary(); + let assets = HighlightingAssets::from_binary(IgnoredSuffixes::default()); let mut themes: Vec<_> = assets.themes().collect(); themes.sort_unstable(); diff --git a/tests/no_duplicate_extensions.rs b/tests/no_duplicate_extensions.rs index c28a9c6a5d..fe5a977031 100644 --- a/tests/no_duplicate_extensions.rs +++ b/tests/no_duplicate_extensions.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use bat::assets::HighlightingAssets; +use bat::{assets::HighlightingAssets, ignored_suffixes::IgnoredSuffixes}; #[test] fn no_duplicate_extensions() { @@ -22,7 +22,7 @@ fn no_duplicate_extensions() { "v", ]; - let assets = HighlightingAssets::from_binary(); + let assets = HighlightingAssets::from_binary(IgnoredSuffixes::default()); let mut extensions = HashSet::new(); From 74405b9c4ee380d78c2b0fc6d7a89dd665fc0513 Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Mon, 11 Oct 2021 17:17:04 -0400 Subject: [PATCH 02/15] Refactored - passing config around --- src/assets.rs | 212 +++++++++++++++++++------------ src/bin/bat/assets.rs | 7 +- src/bin/bat/main.rs | 2 +- src/ignored_suffixes.rs | 2 +- src/pretty_printer.rs | 3 +- src/printer.rs | 15 +-- tests/assets.rs | 4 +- tests/no_duplicate_extensions.rs | 4 +- 8 files changed, 149 insertions(+), 100 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index e2592a5e48..a87625522b 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -10,10 +10,11 @@ use syntect::parsing::{SyntaxReference, SyntaxSet}; use path_abs::PathAbs; use crate::bat_warning; +use crate::config::Config; use crate::error::*; use crate::ignored_suffixes::IgnoredSuffixes; use crate::input::{InputReader, OpenedInput}; -use crate::syntax_mapping::{MappingTarget, SyntaxMapping}; +use crate::syntax_mapping::MappingTarget; use minimal_assets::*; use serialized_syntax_set::*; @@ -36,7 +37,6 @@ pub struct HighlightingAssets { theme_set: ThemeSet, fallback_theme: Option<&'static str>, - ignored_suffixes: IgnoredSuffixes, } #[derive(Debug)] @@ -67,7 +67,6 @@ impl HighlightingAssets { serialized_syntax_set: SerializedSyntaxSet, minimal_syntaxes: MinimalSyntaxes, theme_set: ThemeSet, - ignored_suffixes: IgnoredSuffixes, ) -> Self { HighlightingAssets { syntax_set_cell: LazyCell::new(), @@ -75,7 +74,6 @@ impl HighlightingAssets { minimal_assets: MinimalAssets::new(minimal_syntaxes), theme_set, fallback_theme: None, - ignored_suffixes, } } @@ -83,7 +81,7 @@ impl HighlightingAssets { "Monokai Extended" } - pub fn from_cache(cache_path: &Path, ignored_suffixes: IgnoredSuffixes) -> Result { + pub fn from_cache(cache_path: &Path) -> Result { Ok(HighlightingAssets::new( SerializedSyntaxSet::FromFile(cache_path.join("syntaxes.bin")), asset_from_cache( @@ -92,16 +90,14 @@ impl HighlightingAssets { COMPRESS_MINIMAL_SYNTAXES, )?, asset_from_cache(&cache_path.join("themes.bin"), "theme set", COMPRESS_THEMES)?, - ignored_suffixes, )) } - pub fn from_binary(ignored_suffixes: IgnoredSuffixes) -> Self { + pub fn from_binary() -> Self { HighlightingAssets::new( SerializedSyntaxSet::FromBinary(get_serialized_integrated_syntaxset()), get_integrated_minimal_syntaxes(), get_integrated_themeset(), - ignored_suffixes, ) } @@ -149,9 +145,9 @@ impl HighlightingAssets { pub fn syntax_for_file_name( &self, file_name: impl AsRef, - mapping: &SyntaxMapping, + config: &Config, ) -> Option<&SyntaxReference> { - self.get_syntax_for_path(file_name, mapping) + self.get_syntax_for_path(file_name, config) .ok() .map(|syntax_in_set| syntax_in_set.syntax) } @@ -178,10 +174,10 @@ impl HighlightingAssets { pub fn get_syntax_for_path( &self, path: impl AsRef, - mapping: &SyntaxMapping, + config: &Config, ) -> Result { let path = path.as_ref(); - match mapping.get_syntax_for(path) { + match config.syntax_mapping.get_syntax_for(path) { Some(MappingTarget::MapToUnknown) => { Err(Error::UndetectedSyntax(path.to_string_lossy().into())) } @@ -192,7 +188,7 @@ impl HighlightingAssets { None => { let file_name = path.file_name().unwrap_or_default(); - self.get_extension_syntax(file_name)? + self.get_extension_syntax(file_name, config)? .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())) } } @@ -219,7 +215,7 @@ impl HighlightingAssets { &self, language: Option<&str>, input: &mut OpenedInput, - mapping: &SyntaxMapping, + config: &Config, ) -> Result { if let Some(language) = language { let syntax_set = self.get_syntax_set_by_name(language)?; @@ -233,7 +229,7 @@ impl HighlightingAssets { let path_syntax = if let Some(path) = path { self.get_syntax_for_path( PathAbs::new(path).map_or_else(|_| path.to_owned(), |p| p.as_path().to_path_buf()), - mapping, + config, ) } else { Err(Error::UndetectedSyntax("[unknown]".into())) @@ -267,18 +263,21 @@ impl HighlightingAssets { .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) } - fn get_extension_syntax(&self, file_name: &OsStr) -> Result> { + fn get_extension_syntax( + &self, + file_name: &OsStr, + config: &Config, + ) -> Result> { let mut syntax = self.find_syntax_by_extension(Some(file_name))?; + let ignored_suffixes = IgnoredSuffixes::new(config.ignored_suffixes.clone()); if syntax.is_none() { syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?; } if syntax.is_none() { - syntax = self.ignored_suffixes.try_with_stripped_suffix( - file_name, - |stripped_file_name| { - self.get_extension_syntax(stripped_file_name) // Note: recursion - }, - )?; + syntax = + ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { + self.get_extension_syntax(stripped_file_name, config) // Note: recursion + })?; } Ok(syntax) } @@ -355,18 +354,17 @@ mod tests { use tempfile::TempDir; use crate::input::Input; + use crate::SyntaxMapping; - struct SyntaxDetectionTest<'a> { + struct SyntaxDetectionTest { assets: HighlightingAssets, - pub syntax_mapping: SyntaxMapping<'a>, pub temp_dir: TempDir, } - impl<'a> SyntaxDetectionTest<'a> { + impl SyntaxDetectionTest { fn new() -> Self { SyntaxDetectionTest { - assets: HighlightingAssets::from_binary(IgnoredSuffixes::default()), - syntax_mapping: SyntaxMapping::builtin(), + assets: HighlightingAssets::from_binary(), temp_dir: TempDir::new().expect("creation of temporary directory"), } } @@ -375,10 +373,10 @@ mod tests { &self, language: Option<&str>, input: &mut OpenedInput, - mapping: &SyntaxMapping, + config: &Config, ) -> String { self.assets - .get_syntax(language, input, mapping) + .get_syntax(language, input, config) .map(|syntax_in_set| syntax_in_set.syntax.name.clone()) .unwrap_or_else(|_| "!no syntax!".to_owned()) } @@ -387,6 +385,7 @@ mod tests { &self, file_name: &OsStr, first_line: &str, + config: &Config, ) -> String { let file_path = self.temp_dir.path().join(file_name); { @@ -398,42 +397,64 @@ mod tests { let dummy_stdin: &[u8] = &[]; let mut opened_input = input.open(dummy_stdin, None).unwrap(); - self.get_syntax_name(None, &mut opened_input, &self.syntax_mapping) + self.get_syntax_name(None, &mut opened_input, &config) } - fn syntax_for_file_with_content_os(&self, file_name: &OsStr, first_line: &str) -> String { + fn syntax_for_file_with_content_os( + &self, + file_name: &OsStr, + first_line: &str, + config: &Config, + ) -> String { let file_path = self.temp_dir.path().join(file_name); let input = Input::from_reader(Box::new(BufReader::new(first_line.as_bytes()))) .with_name(Some(&file_path)); let dummy_stdin: &[u8] = &[]; let mut opened_input = input.open(dummy_stdin, None).unwrap(); - self.get_syntax_name(None, &mut opened_input, &self.syntax_mapping) + self.get_syntax_name(None, &mut opened_input, config) } #[cfg(unix)] - fn syntax_for_file_os(&self, file_name: &OsStr) -> String { - self.syntax_for_file_with_content_os(file_name, "") + fn syntax_for_file_os(&self, file_name: &OsStr, config: &Config) -> String { + self.syntax_for_file_with_content_os(file_name, "", config) } - fn syntax_for_file_with_content(&self, file_name: &str, first_line: &str) -> String { - self.syntax_for_file_with_content_os(OsStr::new(file_name), first_line) + fn syntax_for_file_with_content( + &self, + file_name: &str, + first_line: &str, + config: &Config, + ) -> String { + self.syntax_for_file_with_content_os(OsStr::new(file_name), first_line, config) } - fn syntax_for_file(&self, file_name: &str) -> String { - self.syntax_for_file_with_content(file_name, "") + fn syntax_for_file(&self, file_name: &str, config: &Config) -> String { + self.syntax_for_file_with_content(file_name, "", config) } - fn syntax_for_stdin_with_content(&self, file_name: &str, content: &[u8]) -> String { + fn syntax_for_stdin_with_content( + &self, + file_name: &str, + content: &[u8], + config: &Config, + ) -> String { let input = Input::stdin().with_name(Some(file_name)); let mut opened_input = input.open(content, None).unwrap(); - self.get_syntax_name(None, &mut opened_input, &self.syntax_mapping) + self.get_syntax_name(None, &mut opened_input, config) } - fn syntax_is_same_for_inputkinds(&self, file_name: &str, content: &str) -> bool { - let as_file = self.syntax_for_real_file_with_content_os(file_name.as_ref(), content); - let as_reader = self.syntax_for_file_with_content_os(file_name.as_ref(), content); + fn syntax_is_same_for_inputkinds( + &self, + file_name: &str, + content: &str, + config: &Config, + ) -> bool { + let as_file = + self.syntax_for_real_file_with_content_os(file_name.as_ref(), content, config); + let as_reader = + self.syntax_for_file_with_content_os(file_name.as_ref(), content, &config); let consistent = as_file == as_reader; // TODO: Compare StdIn somehow? @@ -451,16 +472,23 @@ mod tests { #[test] fn syntax_detection_basic() { let test = SyntaxDetectionTest::new(); + let config = Config::default(); - assert_eq!(test.syntax_for_file("test.rs"), "Rust"); - assert_eq!(test.syntax_for_file("test.cpp"), "C++"); - assert_eq!(test.syntax_for_file("test.build"), "NAnt Build File"); + assert_eq!(test.syntax_for_file("test.rs", &config), "Rust"); + assert_eq!(test.syntax_for_file("test.cpp", &config), "C++"); assert_eq!( - test.syntax_for_file("PKGBUILD"), + test.syntax_for_file("test.build", &config), + "NAnt Build File" + ); + assert_eq!( + test.syntax_for_file("PKGBUILD", &config), + "Bourne Again Shell (bash)" + ); + assert_eq!( + test.syntax_for_file(".bashrc", &config), "Bourne Again Shell (bash)" ); - assert_eq!(test.syntax_for_file(".bashrc"), "Bourne Again Shell (bash)"); - assert_eq!(test.syntax_for_file("Makefile"), "Makefile"); + assert_eq!(test.syntax_for_file("Makefile", &config), "Makefile"); } #[cfg(unix)] @@ -469,94 +497,116 @@ mod tests { use std::os::unix::ffi::OsStrExt; let test = SyntaxDetectionTest::new(); + let config = Config::default(); assert_eq!( - test.syntax_for_file_os(OsStr::from_bytes(b"invalid_\xFEutf8_filename.rs")), + test.syntax_for_file_os(OsStr::from_bytes(b"invalid_\xFEutf8_filename.rs"), &config), "Rust" ); } #[test] fn syntax_detection_same_for_inputkinds() { - let mut test = SyntaxDetectionTest::new(); + let test = SyntaxDetectionTest::new(); + let mut config = Config::default(); + config.syntax_mapping = SyntaxMapping::builtin(); - test.syntax_mapping + config + .syntax_mapping .insert("*.myext", MappingTarget::MapTo("C")) .ok(); - test.syntax_mapping + config + .syntax_mapping .insert("MY_FILE", MappingTarget::MapTo("Markdown")) .ok(); - assert!(test.syntax_is_same_for_inputkinds("Test.md", "")); - assert!(test.syntax_is_same_for_inputkinds("Test.txt", "#!/bin/bash")); - assert!(test.syntax_is_same_for_inputkinds(".bashrc", "")); - assert!(test.syntax_is_same_for_inputkinds("test.h", "")); - assert!(test.syntax_is_same_for_inputkinds("test.js", "#!/bin/bash")); - assert!(test.syntax_is_same_for_inputkinds("test.myext", "")); - assert!(test.syntax_is_same_for_inputkinds("MY_FILE", "")); - assert!(test.syntax_is_same_for_inputkinds("MY_FILE", " Result Result { } let test_file = Path::new("test").with_extension(extension); - let syntax_in_set = assets.get_syntax_for_path(test_file, &config.syntax_mapping); + let syntax_in_set = assets.get_syntax_for_path(test_file, config); matches!(syntax_in_set, Ok(syntax_in_set) if syntax_in_set.syntax.name == lang_name) }); } diff --git a/src/ignored_suffixes.rs b/src/ignored_suffixes.rs index 537d212938..8cdd055df0 100644 --- a/src/ignored_suffixes.rs +++ b/src/ignored_suffixes.rs @@ -49,7 +49,7 @@ impl IgnoredSuffixes { .values .iter() .map(|v| v.as_str()) - .chain(IGNORED_SUFFIXES.iter().map(|v| *v)) + .chain(IGNORED_SUFFIXES.iter().copied()) { if let Some(stripped_filename) = file_str.strip_suffix(suffix) { from_stripped = func(OsStr::new(stripped_filename))?; diff --git a/src/pretty_printer.rs b/src/pretty_printer.rs index 9ff7befe8c..d537b89062 100644 --- a/src/pretty_printer.rs +++ b/src/pretty_printer.rs @@ -9,7 +9,6 @@ use crate::{ config::{Config, VisibleLines}, controller::Controller, error::Result, - ignored_suffixes::IgnoredSuffixes, input, line_range::{HighlightedLineRanges, LineRange, LineRanges}, style::{StyleComponent, StyleComponents}, @@ -50,7 +49,7 @@ impl<'a> PrettyPrinter<'a> { PrettyPrinter { inputs: vec![], config, - assets: HighlightingAssets::from_binary(IgnoredSuffixes::default()), + assets: HighlightingAssets::from_binary(), highlighted_lines: vec![], term_width: None, diff --git a/src/printer.rs b/src/printer.rs index 1ecbbd74f7..472972319e 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -184,14 +184,13 @@ impl<'a> InteractivePrinter<'a> { None } else { // Determine the type of syntax for highlighting - let syntax_in_set = - match assets.get_syntax(config.language, input, &config.syntax_mapping) { - Ok(syntax_in_set) => syntax_in_set, - Err(Error::UndetectedSyntax(_)) => assets - .find_syntax_by_name("Plain Text")? - .expect("A plain text syntax is available"), - Err(e) => return Err(e), - }; + let syntax_in_set = match assets.get_syntax(config.language, input, config) { + Ok(syntax_in_set) => syntax_in_set, + Err(Error::UndetectedSyntax(_)) => assets + .find_syntax_by_name("Plain Text")? + .expect("A plain text syntax is available"), + Err(e) => return Err(e), + }; Some(HighlighterFromSet::new(syntax_in_set, theme)) }; diff --git a/tests/assets.rs b/tests/assets.rs index 8796bf382a..f7b207fcaf 100644 --- a/tests/assets.rs +++ b/tests/assets.rs @@ -1,11 +1,11 @@ -use bat::{assets::HighlightingAssets, ignored_suffixes::IgnoredSuffixes}; +use bat::assets::HighlightingAssets; /// This test ensures that we are not accidentally removing themes due to submodule updates. /// It is 'ignore'd by default because it requires themes.bin to be up-to-date. #[test] #[ignore] fn all_themes_are_present() { - let assets = HighlightingAssets::from_binary(IgnoredSuffixes::default()); + let assets = HighlightingAssets::from_binary(); let mut themes: Vec<_> = assets.themes().collect(); themes.sort_unstable(); diff --git a/tests/no_duplicate_extensions.rs b/tests/no_duplicate_extensions.rs index fe5a977031..c28a9c6a5d 100644 --- a/tests/no_duplicate_extensions.rs +++ b/tests/no_duplicate_extensions.rs @@ -1,6 +1,6 @@ use std::collections::HashSet; -use bat::{assets::HighlightingAssets, ignored_suffixes::IgnoredSuffixes}; +use bat::assets::HighlightingAssets; #[test] fn no_duplicate_extensions() { @@ -22,7 +22,7 @@ fn no_duplicate_extensions() { "v", ]; - let assets = HighlightingAssets::from_binary(IgnoredSuffixes::default()); + let assets = HighlightingAssets::from_binary(); let mut extensions = HashSet::new(); From 6ad11bffc8e21c574e3430c7fdc41664c6c294e4 Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sat, 16 Oct 2021 10:47:32 -0400 Subject: [PATCH 03/15] Removed clone from recursive function call --- src/assets.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index a87625522b..e6f2f2356c 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -188,7 +188,8 @@ impl HighlightingAssets { None => { let file_name = path.file_name().unwrap_or_default(); - self.get_extension_syntax(file_name, config)? + let ignored_suffixes = IgnoredSuffixes::new(config.ignored_suffixes.clone()); + self.get_extension_syntax(file_name, &ignored_suffixes)? .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())) } } @@ -266,17 +267,16 @@ impl HighlightingAssets { fn get_extension_syntax( &self, file_name: &OsStr, - config: &Config, + ignored_suffixes: &IgnoredSuffixes, ) -> Result> { let mut syntax = self.find_syntax_by_extension(Some(file_name))?; - let ignored_suffixes = IgnoredSuffixes::new(config.ignored_suffixes.clone()); if syntax.is_none() { syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?; } if syntax.is_none() { syntax = ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { - self.get_extension_syntax(stripped_file_name, config) // Note: recursion + self.get_extension_syntax(stripped_file_name, ignored_suffixes) // Note: recursion })?; } Ok(syntax) From b5019c92e6e72d4f2eccd40f5a2764a8dee04311 Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sat, 16 Oct 2021 10:54:16 -0400 Subject: [PATCH 04/15] Cargo fmt --- src/assets.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/assets.rs b/src/assets.rs index e6f2f2356c..f190693767 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -276,7 +276,8 @@ impl HighlightingAssets { if syntax.is_none() { syntax = ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { - self.get_extension_syntax(stripped_file_name, ignored_suffixes) // Note: recursion + // Note: recursion + self.get_extension_syntax(stripped_file_name, ignored_suffixes) })?; } Ok(syntax) From fbdeadd7551c47f81ff4d72683b302b727ce346b Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sat, 6 Nov 2021 17:47:02 -0400 Subject: [PATCH 05/15] Moved ignored suffixes to syntax mapping --- src/assets.rs | 220 +++++++++++++------------------- src/bin/bat/app.rs | 14 +- src/bin/bat/main.rs | 2 +- src/config.rs | 3 - src/ignored_suffixes.rs | 29 +++-- src/lib.rs | 2 +- src/printer.rs | 15 ++- src/syntax_mapping.rs | 3 +- tests/examples/test.json.suffix | 1 + tests/examples/test.json~ | 1 + tests/integration_tests.rs | 22 ++++ 11 files changed, 147 insertions(+), 165 deletions(-) create mode 100644 tests/examples/test.json.suffix create mode 100644 tests/examples/test.json~ diff --git a/src/assets.rs b/src/assets.rs index 33779117e0..02b9f2c7a2 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -9,12 +9,11 @@ use syntect::parsing::{SyntaxReference, SyntaxSet}; use path_abs::PathAbs; -use crate::bat_warning; -use crate::config::Config; use crate::error::*; use crate::ignored_suffixes::IgnoredSuffixes; use crate::input::{InputReader, OpenedInput}; use crate::syntax_mapping::MappingTarget; +use crate::{bat_warning, SyntaxMapping}; use minimal_assets::*; use serialized_syntax_set::*; @@ -145,9 +144,9 @@ impl HighlightingAssets { pub fn syntax_for_file_name( &self, file_name: impl AsRef, - config: &Config, + mapping: &SyntaxMapping, ) -> Option<&SyntaxReference> { - self.get_syntax_for_path(file_name, config) + self.get_syntax_for_path(file_name, mapping) .ok() .map(|syntax_in_set| syntax_in_set.syntax) } @@ -177,12 +176,11 @@ impl HighlightingAssets { pub fn get_syntax_for_path( &self, path: impl AsRef, - config: &Config, + mapping: &SyntaxMapping, ) -> Result { let path = path.as_ref(); - let syntax_match = config.syntax_mapping.get_syntax_for(path); - let ignored_suffixes = IgnoredSuffixes::new(config.ignored_suffixes.clone()); + let syntax_match = mapping.get_syntax_for(path); if let Some(MappingTarget::MapToUnknown) = syntax_match { return Err(Error::UndetectedSyntax(path.to_string_lossy().into())); @@ -197,7 +195,7 @@ impl HighlightingAssets { let file_name = path.file_name().unwrap_or_default(); match ( - self.get_syntax_for_file_name(file_name, &ignored_suffixes)?, + self.get_syntax_for_file_name(file_name, &mapping.ignored_suffixes)?, syntax_match, ) { (Some(syntax), _) => Ok(syntax), @@ -207,7 +205,7 @@ impl HighlightingAssets { } _ => self - .get_syntax_for_file_extension(file_name, &ignored_suffixes)? + .get_syntax_for_file_extension(file_name, &mapping.ignored_suffixes)? .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())), } } @@ -233,7 +231,7 @@ impl HighlightingAssets { &self, language: Option<&str>, input: &mut OpenedInput, - config: &Config, + mapping: &SyntaxMapping, ) -> Result { if let Some(language) = language { let syntax_set = self.get_syntax_set_by_name(language)?; @@ -247,7 +245,7 @@ impl HighlightingAssets { let path_syntax = if let Some(path) = path { self.get_syntax_for_path( PathAbs::new(path).map_or_else(|_| path.to_owned(), |p| p.as_path().to_path_buf()), - config, + mapping, ) } else { Err(Error::UndetectedSyntax("[unknown]".into())) @@ -273,9 +271,18 @@ impl HighlightingAssets { .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) } - fn find_syntax_by_extension(&self, e: Option<&OsStr>) -> Result> { + fn find_syntax_by_extension( + &self, + e: Option<&OsStr>, + ignored_suffixes: &IgnoredSuffixes, + ) -> Result> { let syntax_set = self.get_syntax_set()?; - let extension = e.and_then(|x| x.to_str()).unwrap_or_default(); + let mut extension = e.and_then(|x| x.to_str()).unwrap_or_default(); + + if let Some(stripped_extension) = ignored_suffixes.strip_suffix(extension) { + extension = stripped_extension; + } + Ok(syntax_set .find_syntax_by_extension(extension) .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) @@ -286,7 +293,7 @@ impl HighlightingAssets { file_name: &OsStr, ignored_suffixes: &IgnoredSuffixes, ) -> Result> { - let mut syntax = self.find_syntax_by_extension(Some(file_name))?; + let mut syntax = self.find_syntax_by_extension(Some(file_name), ignored_suffixes)?; if syntax.is_none() { syntax = ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { @@ -302,7 +309,8 @@ impl HighlightingAssets { file_name: &OsStr, ignored_suffixes: &IgnoredSuffixes, ) -> Result> { - let mut syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?; + let mut syntax = + self.find_syntax_by_extension(Path::new(file_name).extension(), ignored_suffixes)?; if syntax.is_none() { syntax = ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { @@ -385,17 +393,18 @@ mod tests { use tempfile::TempDir; use crate::input::Input; - use crate::SyntaxMapping; - struct SyntaxDetectionTest { + struct SyntaxDetectionTest<'a> { assets: HighlightingAssets, + pub syntax_mapping: SyntaxMapping<'a>, pub temp_dir: TempDir, } - impl SyntaxDetectionTest { + impl<'a> SyntaxDetectionTest<'a> { fn new() -> Self { SyntaxDetectionTest { assets: HighlightingAssets::from_binary(), + syntax_mapping: SyntaxMapping::builtin(), temp_dir: TempDir::new().expect("creation of temporary directory"), } } @@ -404,10 +413,10 @@ mod tests { &self, language: Option<&str>, input: &mut OpenedInput, - config: &Config, + mapping: &SyntaxMapping, ) -> String { self.assets - .get_syntax(language, input, config) + .get_syntax(language, input, mapping) .map(|syntax_in_set| syntax_in_set.syntax.name.clone()) .unwrap_or_else(|_| "!no syntax!".to_owned()) } @@ -416,7 +425,6 @@ mod tests { &self, file_name: &OsStr, first_line: &str, - config: &Config, ) -> String { let file_path = self.temp_dir.path().join(file_name); { @@ -428,64 +436,42 @@ mod tests { let dummy_stdin: &[u8] = &[]; let mut opened_input = input.open(dummy_stdin, None).unwrap(); - self.get_syntax_name(None, &mut opened_input, &config) + self.get_syntax_name(None, &mut opened_input, &self.syntax_mapping) } - fn syntax_for_file_with_content_os( - &self, - file_name: &OsStr, - first_line: &str, - config: &Config, - ) -> String { + fn syntax_for_file_with_content_os(&self, file_name: &OsStr, first_line: &str) -> String { let file_path = self.temp_dir.path().join(file_name); let input = Input::from_reader(Box::new(BufReader::new(first_line.as_bytes()))) .with_name(Some(&file_path)); let dummy_stdin: &[u8] = &[]; let mut opened_input = input.open(dummy_stdin, None).unwrap(); - self.get_syntax_name(None, &mut opened_input, config) + self.get_syntax_name(None, &mut opened_input, &self.syntax_mapping) } #[cfg(unix)] - fn syntax_for_file_os(&self, file_name: &OsStr, config: &Config) -> String { - self.syntax_for_file_with_content_os(file_name, "", config) + fn syntax_for_file_os(&self, file_name: &OsStr) -> String { + self.syntax_for_file_with_content_os(file_name, "") } - fn syntax_for_file_with_content( - &self, - file_name: &str, - first_line: &str, - config: &Config, - ) -> String { - self.syntax_for_file_with_content_os(OsStr::new(file_name), first_line, config) + fn syntax_for_file_with_content(&self, file_name: &str, first_line: &str) -> String { + self.syntax_for_file_with_content_os(OsStr::new(file_name), first_line) } - fn syntax_for_file(&self, file_name: &str, config: &Config) -> String { - self.syntax_for_file_with_content(file_name, "", config) + fn syntax_for_file(&self, file_name: &str) -> String { + self.syntax_for_file_with_content(file_name, "") } - fn syntax_for_stdin_with_content( - &self, - file_name: &str, - content: &[u8], - config: &Config, - ) -> String { + fn syntax_for_stdin_with_content(&self, file_name: &str, content: &[u8]) -> String { let input = Input::stdin().with_name(Some(file_name)); let mut opened_input = input.open(content, None).unwrap(); - self.get_syntax_name(None, &mut opened_input, config) + self.get_syntax_name(None, &mut opened_input, &self.syntax_mapping) } - fn syntax_is_same_for_inputkinds( - &self, - file_name: &str, - content: &str, - config: &Config, - ) -> bool { - let as_file = - self.syntax_for_real_file_with_content_os(file_name.as_ref(), content, config); - let as_reader = - self.syntax_for_file_with_content_os(file_name.as_ref(), content, &config); + fn syntax_is_same_for_inputkinds(&self, file_name: &str, content: &str) -> bool { + let as_file = self.syntax_for_real_file_with_content_os(file_name.as_ref(), content); + let as_reader = self.syntax_for_file_with_content_os(file_name.as_ref(), content); let consistent = as_file == as_reader; // TODO: Compare StdIn somehow? @@ -503,23 +489,16 @@ mod tests { #[test] fn syntax_detection_basic() { let test = SyntaxDetectionTest::new(); - let config = Config::default(); - assert_eq!(test.syntax_for_file("test.rs", &config), "Rust"); - assert_eq!(test.syntax_for_file("test.cpp", &config), "C++"); - assert_eq!( - test.syntax_for_file("test.build", &config), - "NAnt Build File" - ); + assert_eq!(test.syntax_for_file("test.rs"), "Rust"); + assert_eq!(test.syntax_for_file("test.cpp"), "C++"); + assert_eq!(test.syntax_for_file("test.build"), "NAnt Build File"); assert_eq!( - test.syntax_for_file("PKGBUILD", &config), + test.syntax_for_file("PKGBUILD"), "Bourne Again Shell (bash)" ); - assert_eq!( - test.syntax_for_file(".bashrc", &config), - "Bourne Again Shell (bash)" - ); - assert_eq!(test.syntax_for_file("Makefile", &config), "Makefile"); + assert_eq!(test.syntax_for_file(".bashrc"), "Bourne Again Shell (bash)"); + assert_eq!(test.syntax_for_file("Makefile"), "Makefile"); } #[cfg(unix)] @@ -528,155 +507,130 @@ mod tests { use std::os::unix::ffi::OsStrExt; let test = SyntaxDetectionTest::new(); - let config = Config::default(); assert_eq!( - test.syntax_for_file_os(OsStr::from_bytes(b"invalid_\xFEutf8_filename.rs"), &config), + test.syntax_for_file_os(OsStr::from_bytes(b"invalid_\xFEutf8_filename.rs")), "Rust" ); } #[test] fn syntax_detection_same_for_inputkinds() { - let test = SyntaxDetectionTest::new(); - let mut config = Config::default(); - config.syntax_mapping = SyntaxMapping::builtin(); + let mut test = SyntaxDetectionTest::new(); - config - .syntax_mapping + test.syntax_mapping .insert("*.myext", MappingTarget::MapTo("C")) .ok(); - config - .syntax_mapping + test.syntax_mapping .insert("MY_FILE", MappingTarget::MapTo("Markdown")) .ok(); - assert!(test.syntax_is_same_for_inputkinds("Test.md", "", &config)); - assert!(test.syntax_is_same_for_inputkinds("Test.txt", "#!/bin/bash", &config)); - assert!(test.syntax_is_same_for_inputkinds(".bashrc", "", &config)); - assert!(test.syntax_is_same_for_inputkinds("test.h", "", &config)); - assert!(test.syntax_is_same_for_inputkinds("test.js", "#!/bin/bash", &config)); - assert!(test.syntax_is_same_for_inputkinds("test.myext", "", &config)); - assert!(test.syntax_is_same_for_inputkinds("MY_FILE", "", &config)); - assert!(test.syntax_is_same_for_inputkinds("MY_FILE", " Result { } let test_file = Path::new("test").with_extension(extension); - let syntax_in_set = assets.get_syntax_for_path(test_file, config); + let syntax_in_set = assets.get_syntax_for_path(test_file, &config.syntax_mapping); matches!(syntax_in_set, Ok(syntax_in_set) if syntax_in_set.syntax.name == lang_name) }); } diff --git a/src/config.rs b/src/config.rs index d3a4cb2229..76eb3990cf 100644 --- a/src/config.rs +++ b/src/config.rs @@ -86,9 +86,6 @@ pub struct Config<'a> { /// Whether or not to allow custom assets. If this is false or if custom assets (a.k.a. /// cached assets) are not available, assets from the binary will be used instead. pub use_custom_assets: bool, - - /// Ignored suffixes - pub ignored_suffixes: Vec, } #[cfg(all(feature = "minimal-application", feature = "paging"))] diff --git a/src/ignored_suffixes.rs b/src/ignored_suffixes.rs index 8cdd055df0..f0a80c8117 100644 --- a/src/ignored_suffixes.rs +++ b/src/ignored_suffixes.rs @@ -33,6 +33,20 @@ impl IgnoredSuffixes { IgnoredSuffixes { values } } + pub fn strip_suffix<'a>(&self, file_name: &'a str) -> Option<&'a str> { + for suffix in self + .values + .iter() + .map(|v| v.as_str()) + .chain(IGNORED_SUFFIXES.iter().copied()) + { + if let Some(stripped_file_name) = file_name.strip_suffix(suffix) { + return Some(stripped_file_name); + } + } + None + } + /// If we find an ignored suffix on the file name, e.g. '~', we strip it and /// then try again without it. pub fn try_with_stripped_suffix<'a, T, F>( @@ -43,21 +57,12 @@ impl IgnoredSuffixes { where F: Fn(&'a OsStr) -> Result>, { - let mut from_stripped = None; if let Some(file_str) = Path::new(file_name).to_str() { - for suffix in self - .values - .iter() - .map(|v| v.as_str()) - .chain(IGNORED_SUFFIXES.iter().copied()) - { - if let Some(stripped_filename) = file_str.strip_suffix(suffix) { - from_stripped = func(OsStr::new(stripped_filename))?; - break; - } + if let Some(stripped_file_name) = self.strip_suffix(file_str) { + return func(OsStr::new(stripped_file_name)); } } - Ok(from_stripped) + Ok(None) } } diff --git a/src/lib.rs b/src/lib.rs index 0d5ca034c4..9e595a6920 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ mod preprocessor; mod pretty_printer; pub(crate) mod printer; pub mod style; -pub(crate) mod syntax_mapping; +mod syntax_mapping; mod terminal; pub(crate) mod wrapping; diff --git a/src/printer.rs b/src/printer.rs index 472972319e..1ecbbd74f7 100644 --- a/src/printer.rs +++ b/src/printer.rs @@ -184,13 +184,14 @@ impl<'a> InteractivePrinter<'a> { None } else { // Determine the type of syntax for highlighting - let syntax_in_set = match assets.get_syntax(config.language, input, config) { - Ok(syntax_in_set) => syntax_in_set, - Err(Error::UndetectedSyntax(_)) => assets - .find_syntax_by_name("Plain Text")? - .expect("A plain text syntax is available"), - Err(e) => return Err(e), - }; + let syntax_in_set = + match assets.get_syntax(config.language, input, &config.syntax_mapping) { + Ok(syntax_in_set) => syntax_in_set, + Err(Error::UndetectedSyntax(_)) => assets + .find_syntax_by_name("Plain Text")? + .expect("A plain text syntax is available"), + Err(e) => return Err(e), + }; Some(HighlighterFromSet::new(syntax_in_set, theme)) }; diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index 8b105df29b..485a0458a6 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -1,6 +1,6 @@ use std::path::Path; -use crate::error::Result; +use crate::{error::Result, ignored_suffixes::IgnoredSuffixes}; use globset::{Candidate, GlobBuilder, GlobMatcher}; @@ -26,6 +26,7 @@ pub enum MappingTarget<'a> { #[derive(Debug, Clone, Default)] pub struct SyntaxMapping<'a> { mappings: Vec<(GlobMatcher, MappingTarget<'a>)>, + pub ignored_suffixes: IgnoredSuffixes, } impl<'a> SyntaxMapping<'a> { diff --git a/tests/examples/test.json.suffix b/tests/examples/test.json.suffix new file mode 100644 index 0000000000..20ec3289a0 --- /dev/null +++ b/tests/examples/test.json.suffix @@ -0,0 +1 @@ +{"test": "value"} \ No newline at end of file diff --git a/tests/examples/test.json~ b/tests/examples/test.json~ new file mode 100644 index 0000000000..20ec3289a0 --- /dev/null +++ b/tests/examples/test.json~ @@ -0,0 +1 @@ +{"test": "value"} \ No newline at end of file diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 9033d0f133..9f24a539f5 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -1225,3 +1225,25 @@ fn grid_for_file_without_newline() { ) .stderr(""); } + +#[test] +fn ignored_suffix_arg() { + bat() + .arg("-f") + .arg("-p") + .arg("test.json~") + .assert() + .success() + .stdout("\u{1b}[38;5;231m{\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;208mtest\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;231m:\u{1b}[0m\u{1b}[38;5;231m \u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;186mvalue\u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;231m}\u{1b}[0m") + .stderr(""); + + bat() + .arg("-f") + .arg("-p") + .arg("--ignored-suffix=.suffix") + .arg("test.json.suffix") + .assert() + .success() + .stdout("\u{1b}[38;5;231m{\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;208mtest\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;231m:\u{1b}[0m\u{1b}[38;5;231m \u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;186mvalue\u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;231m}\u{1b}[0m") + .stderr(""); +} From 13c067a38d56ff513fbaa2d005bda976fbcee4db Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sat, 6 Nov 2021 18:10:07 -0400 Subject: [PATCH 06/15] Reverted unnecessary changes --- src/bin/bat/assets.rs | 6 ++---- src/bin/bat/main.rs | 6 +++--- src/lib.rs | 2 +- 3 files changed, 6 insertions(+), 8 deletions(-) diff --git a/src/bin/bat/assets.rs b/src/bin/bat/assets.rs index 2298f1f9e1..26d599b29a 100644 --- a/src/bin/bat/assets.rs +++ b/src/bin/bat/assets.rs @@ -2,8 +2,6 @@ use std::borrow::Cow; use std::fs; use std::io; -use bat::config::Config; - use clap::crate_version; use crate::directories::PROJECT_DIRS; @@ -27,7 +25,7 @@ pub fn clear_assets() { clear_asset("metadata.yaml", "metadata file"); } -pub fn assets_from_cache_or_binary(config: &Config) -> Result { +pub fn assets_from_cache_or_binary(use_custom_assets: bool) -> Result { let cache_dir = PROJECT_DIRS.cache_dir(); if let Some(metadata) = AssetsMetadata::load_from_folder(cache_dir)? { if !metadata.is_compatible_with(crate_version!()) { @@ -45,7 +43,7 @@ pub fn assets_from_cache_or_binary(config: &Config) -> Result( pub fn get_languages(config: &Config) -> Result { let mut result: String = String::new(); - let assets = assets_from_cache_or_binary(config)?; + let assets = assets_from_cache_or_binary(config.use_custom_assets)?; let mut languages = assets .get_syntaxes()? .iter() @@ -178,7 +178,7 @@ fn theme_preview_file<'a>() -> Input<'a> { } pub fn list_themes(cfg: &Config) -> Result<()> { - let assets = assets_from_cache_or_binary(cfg)?; + let assets = assets_from_cache_or_binary(cfg.use_custom_assets)?; let mut config = cfg.clone(); let mut style = HashSet::new(); style.insert(StyleComponent::Plain); @@ -219,7 +219,7 @@ pub fn list_themes(cfg: &Config) -> Result<()> { } fn run_controller(inputs: Vec, config: &Config) -> Result { - let assets = assets_from_cache_or_binary(config)?; + let assets = assets_from_cache_or_binary(config.use_custom_assets)?; let controller = Controller::new(config, &assets); controller.run(inputs) } diff --git a/src/lib.rs b/src/lib.rs index 9e595a6920..0d5ca034c4 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -45,7 +45,7 @@ mod preprocessor; mod pretty_printer; pub(crate) mod printer; pub mod style; -mod syntax_mapping; +pub(crate) mod syntax_mapping; mod terminal; pub(crate) mod wrapping; From b311b7e949cc981f467ccf075470365339e62f7f Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sat, 6 Nov 2021 18:17:41 -0400 Subject: [PATCH 07/15] Changed visibility of ignored_suffixes module to private --- src/assets.rs | 2 +- src/bin/bat/app.rs | 4 +--- src/lib.rs | 2 +- src/syntax_mapping.rs | 8 +++++--- 4 files changed, 8 insertions(+), 8 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index 02b9f2c7a2..a6a53f6076 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -404,7 +404,7 @@ mod tests { fn new() -> Self { SyntaxDetectionTest { assets: HighlightingAssets::from_binary(), - syntax_mapping: SyntaxMapping::builtin(), + syntax_mapping: SyntaxMapping::builtin(vec![]), temp_dir: TempDir::new().expect("creation of temporary directory"), } } diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 12b1186675..35e984aa83 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -19,7 +19,6 @@ use bat::{ bat_warning, config::{Config, VisibleLines}, error::*, - ignored_suffixes::IgnoredSuffixes, input::Input, line_range::{HighlightedLineRanges, LineRange, LineRanges}, style::{StyleComponent, StyleComponents}, @@ -106,8 +105,7 @@ impl App { _ => unreachable!("other values for --paging are not allowed"), }; - let mut syntax_mapping = SyntaxMapping::builtin(); - syntax_mapping.ignored_suffixes = IgnoredSuffixes::new( + let mut syntax_mapping = SyntaxMapping::builtin( self.matches .values_of("ignored-suffix") .unwrap_or_default() diff --git a/src/lib.rs b/src/lib.rs index 0d5ca034c4..e71fb223a5 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,7 @@ pub mod controller; mod decorations; mod diff; pub mod error; -pub mod ignored_suffixes; +mod ignored_suffixes; pub mod input; mod less; pub mod line_range; diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index 485a0458a6..85deb4ee31 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -34,7 +34,7 @@ impl<'a> SyntaxMapping<'a> { Default::default() } - pub fn builtin() -> SyntaxMapping<'a> { + pub fn builtin(ignored_suffixes: Vec) -> SyntaxMapping<'a> { let mut mapping = Self::empty(); mapping.insert("*.h", MappingTarget::MapTo("C++")).unwrap(); mapping.insert("*.fs", MappingTarget::MapTo("F#")).unwrap(); @@ -143,6 +143,8 @@ impl<'a> SyntaxMapping<'a> { .ok(); } + mapping.ignored_suffixes = IgnoredSuffixes::new(ignored_suffixes); + mapping } @@ -197,7 +199,7 @@ fn basic() { #[test] fn user_can_override_builtin_mappings() { - let mut map = SyntaxMapping::builtin(); + let mut map = SyntaxMapping::builtin(vec![]); assert_eq!( map.get_syntax_for("/etc/profile"), @@ -213,7 +215,7 @@ fn user_can_override_builtin_mappings() { #[test] fn builtin_mappings() { - let map = SyntaxMapping::builtin(); + let map = SyntaxMapping::builtin(vec![]); assert_eq!( map.get_syntax_for("/path/to/build"), From fb7c0784efd6767678b60dc8b874d66951cf43d4 Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sun, 7 Nov 2021 09:27:23 -0500 Subject: [PATCH 08/15] Reverted SyntaxMapping::builtin, moved default ignored suffixes, and changed type --- src/assets.rs | 2 +- src/bin/bat/app.rs | 16 +++++---- src/ignored_suffixes.rs | 76 ++++++++++++++++++++--------------------- src/syntax_mapping.rs | 14 ++++---- 4 files changed, 56 insertions(+), 52 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index a6a53f6076..02b9f2c7a2 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -404,7 +404,7 @@ mod tests { fn new() -> Self { SyntaxDetectionTest { assets: HighlightingAssets::from_binary(), - syntax_mapping: SyntaxMapping::builtin(vec![]), + syntax_mapping: SyntaxMapping::builtin(), temp_dir: TempDir::new().expect("creation of temporary directory"), } } diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 35e984aa83..0deee5062a 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -105,13 +105,15 @@ impl App { _ => unreachable!("other values for --paging are not allowed"), }; - let mut syntax_mapping = SyntaxMapping::builtin( - self.matches - .values_of("ignored-suffix") - .unwrap_or_default() - .map(String::from) - .collect(), - ); + let mut syntax_mapping = SyntaxMapping::builtin(); + + let ignored_suffixes: Vec<&str> = self.matches + .values_of("ignored-suffix") + .unwrap_or_default() + .collect(); + for suffix in ignored_suffixes { + syntax_mapping.insert_ignored_suffix(suffix); + } if let Some(values) = self.matches.values_of("map-syntax") { for from_to in values { diff --git a/src/ignored_suffixes.rs b/src/ignored_suffixes.rs index f0a80c8117..8f2b5fd8af 100644 --- a/src/ignored_suffixes.rs +++ b/src/ignored_suffixes.rs @@ -1,44 +1,45 @@ use std::ffi::OsStr; +use std::fmt::Debug; use std::path::Path; use crate::error::*; -const IGNORED_SUFFIXES: [&str; 13] = [ - // Editor etc backups - "~", - ".bak", - ".old", - ".orig", - // Debian and derivatives apt/dpkg/ucf backups - ".dpkg-dist", - ".dpkg-old", - ".ucf-dist", - ".ucf-new", - ".ucf-old", - // Red Hat and derivatives rpm backups - ".rpmnew", - ".rpmorig", - ".rpmsave", - // Build system input/template files - ".in", -]; +#[derive(Debug, Clone)] +pub struct IgnoredSuffixes<'a> { + values: Vec<&'a str>, +} -#[derive(Debug, Clone, Default)] -pub struct IgnoredSuffixes { - values: Vec, +impl Default for IgnoredSuffixes<'_> { + fn default() -> Self { + Self { values: vec![ + // Editor etc backups + "~", + ".bak", + ".old", + ".orig", + // Debian and derivatives apt/dpkg/ucf backups + ".dpkg-dist", + ".dpkg-old", + ".ucf-dist", + ".ucf-new", + ".ucf-old", + // Red Hat and derivatives rpm backups + ".rpmnew", + ".rpmorig", + ".rpmsave", + // Build system input/template files + ".in", + ] } + } } -impl IgnoredSuffixes { - pub fn new(values: Vec) -> Self { - IgnoredSuffixes { values } +impl<'a> IgnoredSuffixes<'a> { + pub fn add_suffix(&mut self, suffix: &'a str) { + self.values.push(suffix) } - pub fn strip_suffix<'a>(&self, file_name: &'a str) -> Option<&'a str> { - for suffix in self - .values - .iter() - .map(|v| v.as_str()) - .chain(IGNORED_SUFFIXES.iter().copied()) + pub fn strip_suffix(&self, file_name: &'a str) -> Option<&'a str> { + for suffix in self.values.iter() { if let Some(stripped_file_name) = file_name.strip_suffix(suffix) { return Some(stripped_file_name); @@ -49,7 +50,7 @@ impl IgnoredSuffixes { /// If we find an ignored suffix on the file name, e.g. '~', we strip it and /// then try again without it. - pub fn try_with_stripped_suffix<'a, T, F>( + pub fn try_with_stripped_suffix( &self, file_name: &'a OsStr, func: F, @@ -68,9 +69,9 @@ impl IgnoredSuffixes { #[test] fn internal_suffixes() { - let ignored_suffixes = IgnoredSuffixes::new(vec![]); + let ignored_suffixes = IgnoredSuffixes::default(); - let file_names = IGNORED_SUFFIXES + let file_names = ignored_suffixes.values .iter() .map(|suffix| format!("test.json{}", suffix)); for file_name_str in file_names { @@ -87,10 +88,9 @@ fn internal_suffixes() { #[test] fn external_suffixes() { - let ignored_suffixes = IgnoredSuffixes::new(vec![ - String::from(".development"), - String::from(".production"), - ]); + let mut ignored_suffixes = IgnoredSuffixes::default(); + ignored_suffixes.add_suffix(".development"); + ignored_suffixes.add_suffix(".production"); let file_names = ignored_suffixes .values diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index 85deb4ee31..dccea76115 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -26,7 +26,7 @@ pub enum MappingTarget<'a> { #[derive(Debug, Clone, Default)] pub struct SyntaxMapping<'a> { mappings: Vec<(GlobMatcher, MappingTarget<'a>)>, - pub ignored_suffixes: IgnoredSuffixes, + pub(crate) ignored_suffixes: IgnoredSuffixes<'a>, } impl<'a> SyntaxMapping<'a> { @@ -34,7 +34,7 @@ impl<'a> SyntaxMapping<'a> { Default::default() } - pub fn builtin(ignored_suffixes: Vec) -> SyntaxMapping<'a> { + pub fn builtin() -> SyntaxMapping<'a> { let mut mapping = Self::empty(); mapping.insert("*.h", MappingTarget::MapTo("C++")).unwrap(); mapping.insert("*.fs", MappingTarget::MapTo("F#")).unwrap(); @@ -143,8 +143,6 @@ impl<'a> SyntaxMapping<'a> { .ok(); } - mapping.ignored_suffixes = IgnoredSuffixes::new(ignored_suffixes); - mapping } @@ -175,6 +173,10 @@ impl<'a> SyntaxMapping<'a> { } None } + + pub fn insert_ignored_suffix(&mut self, suffix: &'a str) { + self.ignored_suffixes.add_suffix(suffix); + } } #[test] @@ -199,7 +201,7 @@ fn basic() { #[test] fn user_can_override_builtin_mappings() { - let mut map = SyntaxMapping::builtin(vec![]); + let mut map = SyntaxMapping::builtin(); assert_eq!( map.get_syntax_for("/etc/profile"), @@ -215,7 +217,7 @@ fn user_can_override_builtin_mappings() { #[test] fn builtin_mappings() { - let map = SyntaxMapping::builtin(vec![]); + let map = SyntaxMapping::builtin(); assert_eq!( map.get_syntax_for("/path/to/build"), From 06c0532bab244bb29f9c3f1bf97f2d6f8582d2df Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Sun, 7 Nov 2021 09:33:42 -0500 Subject: [PATCH 09/15] Fmt --- src/bin/bat/app.rs | 3 ++- src/ignored_suffixes.rs | 52 ++++++++++++++++++++--------------------- 2 files changed, 27 insertions(+), 28 deletions(-) diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 0deee5062a..636a03fa36 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -107,7 +107,8 @@ impl App { let mut syntax_mapping = SyntaxMapping::builtin(); - let ignored_suffixes: Vec<&str> = self.matches + let ignored_suffixes: Vec<&str> = self + .matches .values_of("ignored-suffix") .unwrap_or_default() .collect(); diff --git a/src/ignored_suffixes.rs b/src/ignored_suffixes.rs index 8f2b5fd8af..3daf06e828 100644 --- a/src/ignored_suffixes.rs +++ b/src/ignored_suffixes.rs @@ -11,25 +11,27 @@ pub struct IgnoredSuffixes<'a> { impl Default for IgnoredSuffixes<'_> { fn default() -> Self { - Self { values: vec![ - // Editor etc backups - "~", - ".bak", - ".old", - ".orig", - // Debian and derivatives apt/dpkg/ucf backups - ".dpkg-dist", - ".dpkg-old", - ".ucf-dist", - ".ucf-new", - ".ucf-old", - // Red Hat and derivatives rpm backups - ".rpmnew", - ".rpmorig", - ".rpmsave", - // Build system input/template files - ".in", - ] } + Self { + values: vec![ + // Editor etc backups + "~", + ".bak", + ".old", + ".orig", + // Debian and derivatives apt/dpkg/ucf backups + ".dpkg-dist", + ".dpkg-old", + ".ucf-dist", + ".ucf-new", + ".ucf-old", + // Red Hat and derivatives rpm backups + ".rpmnew", + ".rpmorig", + ".rpmsave", + // Build system input/template files + ".in", + ], + } } } @@ -39,8 +41,7 @@ impl<'a> IgnoredSuffixes<'a> { } pub fn strip_suffix(&self, file_name: &'a str) -> Option<&'a str> { - for suffix in self.values.iter() - { + for suffix in self.values.iter() { if let Some(stripped_file_name) = file_name.strip_suffix(suffix) { return Some(stripped_file_name); } @@ -50,11 +51,7 @@ impl<'a> IgnoredSuffixes<'a> { /// If we find an ignored suffix on the file name, e.g. '~', we strip it and /// then try again without it. - pub fn try_with_stripped_suffix( - &self, - file_name: &'a OsStr, - func: F, - ) -> Result> + pub fn try_with_stripped_suffix(&self, file_name: &'a OsStr, func: F) -> Result> where F: Fn(&'a OsStr) -> Result>, { @@ -71,7 +68,8 @@ impl<'a> IgnoredSuffixes<'a> { fn internal_suffixes() { let ignored_suffixes = IgnoredSuffixes::default(); - let file_names = ignored_suffixes.values + let file_names = ignored_suffixes + .values .iter() .map(|suffix| format!("test.json{}", suffix)); for file_name_str in file_names { From 327ae7150d0a69482ad911cd8c7c07543304a74e Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Mon, 8 Nov 2021 17:53:13 -0500 Subject: [PATCH 10/15] Added one more test case and reverted find_syntax_by_extension --- src/assets.rs | 17 ++++------------- tests/integration_tests.rs | 37 +++++++++++++++++++++++-------------- 2 files changed, 27 insertions(+), 27 deletions(-) diff --git a/src/assets.rs b/src/assets.rs index 02b9f2c7a2..874e80e1ab 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -271,17 +271,9 @@ impl HighlightingAssets { .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) } - fn find_syntax_by_extension( - &self, - e: Option<&OsStr>, - ignored_suffixes: &IgnoredSuffixes, - ) -> Result> { + fn find_syntax_by_extension(&self, e: Option<&OsStr>) -> Result> { let syntax_set = self.get_syntax_set()?; - let mut extension = e.and_then(|x| x.to_str()).unwrap_or_default(); - - if let Some(stripped_extension) = ignored_suffixes.strip_suffix(extension) { - extension = stripped_extension; - } + let extension = e.and_then(|x| x.to_str()).unwrap_or_default(); Ok(syntax_set .find_syntax_by_extension(extension) @@ -293,7 +285,7 @@ impl HighlightingAssets { file_name: &OsStr, ignored_suffixes: &IgnoredSuffixes, ) -> Result> { - let mut syntax = self.find_syntax_by_extension(Some(file_name), ignored_suffixes)?; + let mut syntax = self.find_syntax_by_extension(Some(file_name))?; if syntax.is_none() { syntax = ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { @@ -309,8 +301,7 @@ impl HighlightingAssets { file_name: &OsStr, ignored_suffixes: &IgnoredSuffixes, ) -> Result> { - let mut syntax = - self.find_syntax_by_extension(Path::new(file_name).extension(), ignored_suffixes)?; + let mut syntax = self.find_syntax_by_extension(Path::new(file_name).extension())?; if syntax.is_none() { syntax = ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| { diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 9f24a539f5..80d63a1785 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -843,30 +843,30 @@ fn unicode_wrap() { .stdout( " 1 ビタミンA ビタミンD ビタミンE ビ タミンK ビタミンB1 ビタミンB2 ナ - イアシン パントテン酸 ビタミンB6 + イアシン パントテン酸 ビタミンB6 ビタミンB12 葉酸 ビオチン ビタ ミンC - 2 - 3 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 + 2 + 3 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 고양이 - 4 + 4 5 1 บวก 2 บวก 3 บวก 4 บวก 5 บวก 6 บวก 7 บวก 8 บวก 9 บวก 10 บวก 11 บวก 12 บวก 13 บวก 14 บวก 15 บวก 16 บวก 17 บวก 18 บวก 19 บวก 20 - 6 + 6 7 Бельгия Болгария Чехия Дания Герман - ия Эстония Ирландия Греция Испания + ия Эстония Ирландия Греция Испания Франция Хорватия Италия Кипр Латвия Литва Люксембург Венгрия Мальта Ни - дерланды Австрия Польша Португалия + дерланды Австрия Польша Португалия Румыния Словения Словакия Финляндия Швеция Великобритания ", @@ -1246,4 +1246,13 @@ fn ignored_suffix_arg() { .success() .stdout("\u{1b}[38;5;231m{\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;208mtest\u{1b}[0m\u{1b}[38;5;208m\"\u{1b}[0m\u{1b}[38;5;231m:\u{1b}[0m\u{1b}[38;5;231m \u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;186mvalue\u{1b}[0m\u{1b}[38;5;186m\"\u{1b}[0m\u{1b}[38;5;231m}\u{1b}[0m") .stderr(""); + + bat() + .arg("-f") + .arg("-p") + .arg("test.json.suffix") + .assert() + .success() + .stdout("\u{1b}[38;5;231m{\"test\": \"value\"}\u{1b}[0m") + .stderr(""); } From 43d1f4e5085f6126bd72964b89ac5bbd3b24660d Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Mon, 8 Nov 2021 18:00:49 -0500 Subject: [PATCH 11/15] Accidental change revert --- tests/integration_tests.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs index 80d63a1785..17e9dc4e1f 100644 --- a/tests/integration_tests.rs +++ b/tests/integration_tests.rs @@ -843,30 +843,30 @@ fn unicode_wrap() { .stdout( " 1 ビタミンA ビタミンD ビタミンE ビ タミンK ビタミンB1 ビタミンB2 ナ - イアシン パントテン酸 ビタミンB6 + イアシン パントテン酸 ビタミンB6 ビタミンB12 葉酸 ビオチン ビタ ミンC - 2 - 3 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 - 고양이 고양이 고양이 고양이 고양이 + 2 + 3 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 + 고양이 고양이 고양이 고양이 고양이 고양이 - 4 + 4 5 1 บวก 2 บวก 3 บวก 4 บวก 5 บวก 6 บวก 7 บวก 8 บวก 9 บวก 10 บวก 11 บวก 12 บวก 13 บวก 14 บวก 15 บวก 16 บวก 17 บวก 18 บวก 19 บวก 20 - 6 + 6 7 Бельгия Болгария Чехия Дания Герман - ия Эстония Ирландия Греция Испания + ия Эстония Ирландия Греция Испания Франция Хорватия Италия Кипр Латвия Литва Люксембург Венгрия Мальта Ни - дерланды Австрия Польша Португалия + дерланды Австрия Польша Португалия Румыния Словения Словакия Финляндия Швеция Великобритания ", From 9446e1fc926979dc74f3fe5bf9239e0db015d84a Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Fri, 12 Nov 2021 17:41:29 -0500 Subject: [PATCH 12/15] PR comments addressed - minor refactor and module move --- src/assets.rs | 3 +-- src/bin/bat/app.rs | 11 ++++------- src/lib.rs | 1 - src/syntax_mapping.rs | 5 ++++- src/{ => syntax_mapping}/ignored_suffixes.rs | 0 5 files changed, 9 insertions(+), 11 deletions(-) rename src/{ => syntax_mapping}/ignored_suffixes.rs (100%) diff --git a/src/assets.rs b/src/assets.rs index 874e80e1ab..220f9fc268 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -10,8 +10,8 @@ use syntect::parsing::{SyntaxReference, SyntaxSet}; use path_abs::PathAbs; use crate::error::*; -use crate::ignored_suffixes::IgnoredSuffixes; use crate::input::{InputReader, OpenedInput}; +use crate::syntax_mapping::ignored_suffixes::IgnoredSuffixes; use crate::syntax_mapping::MappingTarget; use crate::{bat_warning, SyntaxMapping}; @@ -274,7 +274,6 @@ impl HighlightingAssets { fn find_syntax_by_extension(&self, e: Option<&OsStr>) -> Result> { let syntax_set = self.get_syntax_set()?; let extension = e.and_then(|x| x.to_str()).unwrap_or_default(); - Ok(syntax_set .find_syntax_by_extension(extension) .map(|syntax| SyntaxReferenceInSet { syntax, syntax_set })) diff --git a/src/bin/bat/app.rs b/src/bin/bat/app.rs index 636a03fa36..842eec656c 100644 --- a/src/bin/bat/app.rs +++ b/src/bin/bat/app.rs @@ -107,13 +107,10 @@ impl App { let mut syntax_mapping = SyntaxMapping::builtin(); - let ignored_suffixes: Vec<&str> = self - .matches - .values_of("ignored-suffix") - .unwrap_or_default() - .collect(); - for suffix in ignored_suffixes { - syntax_mapping.insert_ignored_suffix(suffix); + if let Some(values) = self.matches.values_of("ignored-suffix") { + for suffix in values { + syntax_mapping.insert_ignored_suffix(suffix); + } } if let Some(values) = self.matches.values_of("map-syntax") { diff --git a/src/lib.rs b/src/lib.rs index e71fb223a5..02e1fefca3 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -32,7 +32,6 @@ pub mod controller; mod decorations; mod diff; pub mod error; -mod ignored_suffixes; pub mod input; mod less; pub mod line_range; diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index dccea76115..f8260fb2d5 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -1,9 +1,12 @@ use std::path::Path; -use crate::{error::Result, ignored_suffixes::IgnoredSuffixes}; +use self::ignored_suffixes::IgnoredSuffixes; +use crate::error::Result; use globset::{Candidate, GlobBuilder, GlobMatcher}; +pub(crate) mod ignored_suffixes; + #[derive(Debug, Clone, Copy, PartialEq)] pub enum MappingTarget<'a> { /// For mapping a path to a specific syntax. diff --git a/src/ignored_suffixes.rs b/src/syntax_mapping/ignored_suffixes.rs similarity index 100% rename from src/ignored_suffixes.rs rename to src/syntax_mapping/ignored_suffixes.rs From 41afa2572c84a1544a6fbf42ad1a77f210403e8f Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Fri, 12 Nov 2021 17:51:31 -0500 Subject: [PATCH 13/15] Changelog update --- CHANGELOG.md | 1 + 1 file changed, 1 insertion(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 92fad76de1..6adf469a36 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,6 +2,7 @@ ## Features +- Support for `--ignored-suffix` argument. See #1892 (@bojan88) - `$BAT_CONFIG_DIR` is now a recognized environment variable. It has precedence over `$XDG_CONFIG_HOME`, see #1727 (@billrisher) - Support for `x:+delta` syntax in line ranges (e.g. `20:+10`). See #1810 (@bojan88) From ee05a9911645e1f7d4dde8705fa730bce0e000dc Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Fri, 12 Nov 2021 17:56:54 -0500 Subject: [PATCH 14/15] Minor change - pub(crate) seemed unnecessary for ignored_suffixes module --- src/syntax_mapping.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/syntax_mapping.rs b/src/syntax_mapping.rs index f8260fb2d5..25dfbbcf28 100644 --- a/src/syntax_mapping.rs +++ b/src/syntax_mapping.rs @@ -1,11 +1,11 @@ use std::path::Path; -use self::ignored_suffixes::IgnoredSuffixes; use crate::error::Result; +use ignored_suffixes::IgnoredSuffixes; use globset::{Candidate, GlobBuilder, GlobMatcher}; -pub(crate) mod ignored_suffixes; +pub mod ignored_suffixes; #[derive(Debug, Clone, Copy, PartialEq)] pub enum MappingTarget<'a> { From 2bb9ec204aa9166ed3de53e332c59c4c6e7163f2 Mon Sep 17 00:00:00 2001 From: Bojan Durdevic Date: Wed, 17 Nov 2021 17:59:48 -0500 Subject: [PATCH 15/15] PR comments addressed - added .hidden_short_help(true) --- src/bin/bat/clap_app.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/src/bin/bat/clap_app.rs b/src/bin/bat/clap_app.rs index 3f3d7b3a0e..8f913a1106 100644 --- a/src/bin/bat/clap_app.rs +++ b/src/bin/bat/clap_app.rs @@ -515,6 +515,7 @@ pub fn build_app(interactive_output: bool) -> ClapApp<'static, 'static> { .multiple(true) .takes_value(true) .long("ignored-suffix") + .hidden_short_help(true) .help( "Ignore extension. For example:\n \ 'bat --ignored-suffix \".dev\" my_file.json.dev' will use JSON syntax, and ignore '.dev'"