mirror of
https://github.com/sharkdp/bat
synced 2026-07-27 17:41:42 +00:00
Fix --ignored-suffix to fall back to first-line detection
When an ignored suffix is also a registered extension (e.g. `.txt` maps to "Plain Text"), `get_syntax_for_file_extension` matched the raw extension before attempting the suffix strip. As a result `--ignored-suffix .txt` had no effect on such files and first-line/shebang detection was never reached, so a shell script saved as `*.txt` stayed unhighlighted. Strip ignored suffixes first and detect on the remainder; only fall back to the raw extension when no ignored suffix applies. When a suffix is stripped but the remainder has no syntax, return `None` so the caller can use first-line detection. Default behavior (no `--ignored-suffix`) is unchanged. See #2745.
This commit is contained in:
+50
-8
@@ -347,15 +347,15 @@ impl HighlightingAssets {
|
||||
file_name: &OsStr,
|
||||
ignored_suffixes: &IgnoredSuffixes,
|
||||
) -> Result<Option<SyntaxReferenceInSet<'_>>> {
|
||||
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| {
|
||||
// Note: recursion
|
||||
self.get_syntax_for_file_extension(stripped_file_name, ignored_suffixes)
|
||||
})?;
|
||||
let stripped =
|
||||
ignored_suffixes.try_with_stripped_suffix(file_name, |stripped_file_name| {
|
||||
self.get_syntax_for_file_extension(stripped_file_name, ignored_suffixes)
|
||||
.map(Some)
|
||||
})?;
|
||||
match stripped {
|
||||
Some(syntax) => Ok(syntax),
|
||||
None => self.find_syntax_by_extension(Path::new(file_name).extension()),
|
||||
}
|
||||
Ok(syntax)
|
||||
}
|
||||
|
||||
fn get_first_line_syntax(
|
||||
@@ -686,6 +686,48 @@ mod tests {
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syntax_detection_ignored_suffix_falls_back_to_first_line() {
|
||||
let mut test = SyntaxDetectionTest::new();
|
||||
|
||||
// By default a `.txt` file uses Plain Text, even with a shebang: the
|
||||
// `.txt` extension wins and first-line detection is not reached.
|
||||
assert_eq!(
|
||||
test.syntax_for_file_with_content("test.txt", "#!/usr/bin/env bash"),
|
||||
"Plain Text"
|
||||
);
|
||||
|
||||
// Once `.txt` is an ignored suffix it is stripped before detection. The
|
||||
// stripped name (`test`) has no extension, so detection falls back to the
|
||||
// first line -- even though `.txt` is itself a registered extension that
|
||||
// would otherwise match as Plain Text. See #2745.
|
||||
test.syntax_mapping.insert_ignored_suffix(".txt");
|
||||
assert_eq!(
|
||||
test.syntax_for_file_with_content("test.txt", "#!/usr/bin/env bash"),
|
||||
"Bourne Again Shell (bash)"
|
||||
);
|
||||
assert_eq!(
|
||||
test.syntax_for_file_with_content("test.txt", "<?php"),
|
||||
"PHP"
|
||||
);
|
||||
|
||||
// A `.txt` file without a recognizable first line keeps no syntax (the
|
||||
// caller renders it as plain text); we must not resurrect the shadowed
|
||||
// `.txt` -> Plain Text match here.
|
||||
assert_eq!(
|
||||
test.syntax_for_file_with_content("notes.txt", "just some prose"),
|
||||
"!no syntax!"
|
||||
);
|
||||
|
||||
// Stripping that exposes a real extension still works: `.dev` is ignored,
|
||||
// and the remaining `.json` extension is detected as usual.
|
||||
test.syntax_mapping.insert_ignored_suffix(".dev");
|
||||
assert_eq!(
|
||||
test.syntax_for_file_with_content("config.json.dev", ""),
|
||||
"JSON"
|
||||
);
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn syntax_detection_is_case_insensitive() {
|
||||
let mut test = SyntaxDetectionTest::new();
|
||||
|
||||
Reference in New Issue
Block a user