diff --git a/CHANGELOG.md b/CHANGELOG.md index e66bfddb98..57563fce32 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -33,7 +33,7 @@ ## `bat` as a library -- Deprecate `HighlightingAssets::syntaxes()` and `HighlightingAssets::syntax_for_file_name()`. Use `HighlightingAssets::get_syntaxes()` and `HighlightingAssets::get_syntax_for_file_name()` instead. They return a `Result` which is needed for upcoming lazy-loading work to improve startup performance. They also return what `SyntaxSet` the returned `SyntaxReference` belongs to. See #1747, #1755 and #1776 (@Enselic) +- Deprecate `HighlightingAssets::syntaxes()` and `HighlightingAssets::syntax_for_file_name()`. Use `HighlightingAssets::get_syntaxes()` and `HighlightingAssets::get_syntax_for_path()` instead. They return a `Result` which is needed for upcoming lazy-loading work to improve startup performance. They also return which `SyntaxSet` the returned `SyntaxReference` belongs to. See #1747, #1755, #1776, #1862 (@Enselic) - Remove `HighlightingAssets::from_files` and `HighlightingAssets::save_to_cache`. Instead of calling the former and then the latter you now make a single call to `bat::assets::build`. See #1802 (@Enselic) - Replace the `error::Error(error::ErrorKind, _)` struct and enum with an `error::Error` enum. `Error(ErrorKind::UnknownSyntax, _)` becomes `Error::UnknownSyntax`, etc. Also remove the `error::ResultExt` trait. These changes stem from replacing `error-chain` with `thiserror`. See #1820 (@Enselic) diff --git a/src/assets.rs b/src/assets.rs index f9a990fe59..031083b652 100644 --- a/src/assets.rs +++ b/src/assets.rs @@ -140,31 +140,58 @@ impl HighlightingAssets { } } - /// Use [Self::get_syntax_for_file_name] instead + /// Use [Self::get_syntax_for_path] instead #[deprecated] pub fn syntax_for_file_name( &self, file_name: impl AsRef, mapping: &SyntaxMapping, ) -> Option<&SyntaxReference> { - self.get_syntax_for_file_name(file_name, mapping) - .expect( - ".syntax_for_file_name() is deprecated, use .get_syntax_for_file_name() instead", - ) + self.get_syntax_for_path(file_name, mapping) + .ok() .map(|syntax_in_set| syntax_in_set.syntax) } - pub fn get_syntax_for_file_name( + /// Detect the syntax based on, in order: + /// 1. Syntax mappings (e.g. `/etc/profile` -> `Bourne Again Shell (bash)`) + /// 2. The file name (e.g. `Dockerfile`) + /// 3. The file name extension (e.g. `.rs`) + /// + /// When detecting syntax based on syntax mappings, the full path is taken + /// into account. When detecting syntax based on file name, no regard is + /// taken to the path of the file. Only the file name itself matters. When + /// detecting syntax based on file name extension, only the file name + /// extension itself matters. + /// + /// Returns [Error::UndetectedSyntax] if it was not possible detect syntax + /// based on path/file name/extension (or if the path was mapped to + /// [MappingTarget::MapToUnknown]). In this case it is appropriate to fall + /// back to other methods to detect syntax. Such as using the contents of + /// the first line of the file. + /// + /// Returns [Error::UnknownSyntax] if a syntax mapping exist, but the mapped + /// syntax does not exist. + pub fn get_syntax_for_path( &self, - file_name: impl AsRef, + path: impl AsRef, mapping: &SyntaxMapping, - ) -> Result> { - let file_name = file_name.as_ref(); - Ok(match mapping.get_syntax_for(file_name) { - Some(MappingTarget::MapToUnknown) => None, - Some(MappingTarget::MapTo(syntax_name)) => self.find_syntax_by_name(syntax_name)?, - None => self.get_extension_syntax(file_name.as_os_str())?, - }) + ) -> Result { + let path = path.as_ref(); + match mapping.get_syntax_for(path) { + Some(MappingTarget::MapToUnknown) => { + Err(Error::UndetectedSyntax(path.to_string_lossy().into())) + } + + Some(MappingTarget::MapTo(syntax_name)) => self + .find_syntax_by_name(syntax_name)? + .ok_or_else(|| Error::UnknownSyntax(syntax_name.to_owned())), + + None => { + let file_name = path.file_name().unwrap_or_default(); + self.get_extension_syntax(file_name)? + .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())) + } + } } pub(crate) fn get_theme(&self, theme: &str) -> &Theme { @@ -211,24 +238,10 @@ impl HighlightingAssets { }); let path_syntax = if let Some(path) = path { - // If a path was provided, we try and detect the syntax based on extension mappings. - match mapping.get_syntax_for( + self.get_syntax_for_path( PathAbs::new(path).map_or_else(|_| path.to_owned(), |p| p.as_path().to_path_buf()), - ) { - Some(MappingTarget::MapToUnknown) => { - Err(Error::UndetectedSyntax(path.to_string_lossy().into())) - } - - Some(MappingTarget::MapTo(syntax_name)) => self - .find_syntax_by_name(syntax_name)? - .ok_or_else(|| Error::UnknownSyntax(syntax_name.to_owned())), - - None => { - let file_name = path.file_name().unwrap_or_default(); - self.get_extension_syntax(file_name)? - .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())) - } - } + mapping, + ) } else { Err(Error::UndetectedSyntax("[unknown]".into())) }; diff --git a/src/bin/bat/main.rs b/src/bin/bat/main.rs index 735c0b2b19..1f4f6e372f 100644 --- a/src/bin/bat/main.rs +++ b/src/bin/bat/main.rs @@ -104,10 +104,8 @@ pub fn get_languages(config: &Config) -> Result { } let test_file = Path::new("test").with_extension(extension); - let syntax_in_set = assets - .get_syntax_for_file_name(test_file, &config.syntax_mapping) - .unwrap(); // safe since .get_syntaxes() above worked - matches!(syntax_in_set, Some(syntax_in_set) if syntax_in_set.syntax.name == lang_name) + 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) }); }