From 9ed9a6fc3d3bc985a41d613e93848a50f103e8e3 Mon Sep 17 00:00:00 2001
From: Martin Nordholts <enselic@gmail.com>
Date: Thu, 16 Sep 2021 17:01:12 +0200
Subject: [PATCH] Simplify HighlightingAssets::get_syntax() first_line logic
 (#1852)

And make self.get_first_line_syntax() be called lazily.
---
 src/assets.rs                                 | 22 ++++++++++++-------
 .../first_line_fallback.invalid-syntax        |  2 ++
 tests/integration_tests.rs                    | 15 +++++++++++++
 3 files changed, 31 insertions(+), 8 deletions(-)
 create mode 100644 tests/examples/regression_tests/first_line_fallback.invalid-syntax

diff --git a/src/assets.rs b/src/assets.rs
index 3f844bc4..dfdb8843 100644
--- a/src/assets.rs
+++ b/src/assets.rs
@@ -198,8 +198,6 @@ impl HighlightingAssets {
                 .ok_or_else(|| Error::UnknownSyntax(language.to_owned()));
         }
 
-        let line_syntax = self.get_first_line_syntax(&mut input.reader)?;
-
         // Get the path of the file:
         // If this was set by the metadata, that will take priority.
         // If it wasn't, it will use the real file path (if available).
@@ -212,7 +210,7 @@ impl HighlightingAssets {
                 _ => None,
             });
 
-        if let Some(path_str) = path_str {
+        let path_syntax = if let Some(path_str) = path_str {
             // If a path was provided, we try and detect the syntax based on extension mappings.
             let path = Path::new(path_str);
             let absolute_path = PathAbs::new(path)
@@ -221,8 +219,9 @@ impl HighlightingAssets {
                 .unwrap_or_else(|| path.to_owned());
 
             match mapping.get_syntax_for(absolute_path) {
-                Some(MappingTarget::MapToUnknown) => line_syntax
-                    .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into())),
+                Some(MappingTarget::MapToUnknown) => {
+                    Err(Error::UndetectedSyntax(path.to_string_lossy().into()))
+                }
 
                 Some(MappingTarget::MapTo(syntax_name)) => self
                     .find_syntax_by_name(syntax_name)?
@@ -231,13 +230,20 @@ impl HighlightingAssets {
                 None => {
                     let file_name = path.file_name().unwrap_or_default();
                     self.get_extension_syntax(file_name)?
-                        .or(line_syntax)
                         .ok_or_else(|| Error::UndetectedSyntax(path.to_string_lossy().into()))
                 }
             }
         } else {
-            // If a path wasn't provided, we fall back to the detect first-line syntax.
-            line_syntax.ok_or_else(|| Error::UndetectedSyntax("[unknown]".into()))
+            Err(Error::UndetectedSyntax("[unknown]".into()))
+        };
+
+        match path_syntax {
+            // If a path wasn't provided, or if path based syntax detection
+            // above failed, we fall back to first-line syntax detection.
+            Err(Error::UndetectedSyntax(path)) => self
+                .get_first_line_syntax(&mut input.reader)?
+                .ok_or(Error::UndetectedSyntax(path)),
+            _ => path_syntax,
         }
     }
 
diff --git a/tests/examples/regression_tests/first_line_fallback.invalid-syntax b/tests/examples/regression_tests/first_line_fallback.invalid-syntax
new file mode 100644
index 00000000..626c6f39
--- /dev/null
+++ b/tests/examples/regression_tests/first_line_fallback.invalid-syntax
@@ -0,0 +1,2 @@
+#!/usr/bin/env bash
+echo "Hello"
diff --git a/tests/integration_tests.rs b/tests/integration_tests.rs
index e3fb5e0f..9033d0f1 100644
--- a/tests/integration_tests.rs
+++ b/tests/integration_tests.rs
@@ -1127,6 +1127,21 @@ fn do_not_detect_different_syntax_for_stdin_and_files() {
     );
 }
 
+#[test]
+fn no_first_line_fallback_when_mapping_to_invalid_syntax() {
+    let file = "regression_tests/first_line_fallback.invalid-syntax";
+
+    bat()
+        .arg("--color=always")
+        .arg("--map-syntax=*.invalid-syntax:InvalidSyntax")
+        .arg(&format!("--file-name={}", file))
+        .arg("--style=plain")
+        .arg(file)
+        .assert()
+        .failure()
+        .stderr(predicate::str::contains("unknown syntax: 'InvalidSyntax'"));
+}
+
 #[test]
 fn show_all_mode() {
     bat()