Use --file-name to detect syntax highlighting

Closes #891
This commit is contained in:
Kyle Criddle 2020-03-26 16:49:16 -06:00 committed by David Peter
parent 96aedf6240
commit a3f8140fbe
3 changed files with 64 additions and 14 deletions

View File

@ -176,14 +176,15 @@ impl HighlightingAssets {
pub(crate) fn get_syntax( pub(crate) fn get_syntax(
&self, &self,
language: Option<&str>, language: Option<&str>,
filename: InputFile, file: InputFile,
file_name: Option<&str>,
reader: &mut InputFileReader, reader: &mut InputFileReader,
mapping: &SyntaxMapping, mapping: &SyntaxMapping,
) -> &SyntaxReference { ) -> &SyntaxReference {
let syntax = match (language, filename) { let syntax = match (language, file, file_name) {
(Some(language), _) => self.syntax_set.find_syntax_by_token(language), (Some(language), _, _) => self.syntax_set.find_syntax_by_token(language),
(None, InputFile::Ordinary(filename)) => { (None, InputFile::Ordinary(file), _) => {
let path = Path::new(filename); let path = Path::new(file);
let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or(""); let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
let extension = path.extension().and_then(|x| x.to_str()).unwrap_or(""); let extension = path.extension().and_then(|x| x.to_str()).unwrap_or("");
@ -207,10 +208,24 @@ impl HighlightingAssets {
None => ext_syntax.or(line_syntax), None => ext_syntax.or(line_syntax),
} }
} }
(None, InputFile::StdIn) => String::from_utf8(reader.first_line.clone()) (None, InputFile::StdIn, None) => String::from_utf8(reader.first_line.clone())
.ok() .ok()
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)), .and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)),
(_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"), (None, InputFile::StdIn, Some(file_name)) => self
.syntax_set
.find_syntax_by_extension(&file_name)
.or_else(|| {
self.syntax_set.find_syntax_by_extension(
Path::new(file_name)
.extension()
.and_then(|x| x.to_str())
.unwrap_or(""),
)
})
.or(String::from_utf8(reader.first_line.clone())
.ok()
.and_then(|l| self.syntax_set.find_syntax_by_first_line(&l))),
(_, InputFile::ThemePreviewFile, _) => self.syntax_set.find_syntax_by_name("Rust"),
}; };
syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text()) syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
@ -246,7 +261,12 @@ mod tests {
} }
} }
fn synax_for_file_with_content(&self, file_name: &str, first_line: &str) -> String { fn syntax_for_file_with_content(
&self,
file_name: &str,
first_line: &str,
as_stdin: bool,
) -> String {
let file_path = self.temp_dir.path().join(file_name); let file_path = self.temp_dir.path().join(file_name);
{ {
let mut temp_file = File::create(&file_path).unwrap(); let mut temp_file = File::create(&file_path).unwrap();
@ -254,9 +274,15 @@ mod tests {
} }
let input_file = InputFile::Ordinary(OsStr::new(&file_path)); let input_file = InputFile::Ordinary(OsStr::new(&file_path));
let (file, file_name) = if as_stdin {
(InputFile::StdIn, Some(file_name))
} else {
(input_file, None)
};
let syntax = self.assets.get_syntax( let syntax = self.assets.get_syntax(
None, None,
input_file, file,
file_name,
&mut input_file.get_reader(&io::stdin()).unwrap(), &mut input_file.get_reader(&io::stdin()).unwrap(),
&self.syntax_mapping, &self.syntax_mapping,
); );
@ -265,7 +291,7 @@ mod tests {
} }
fn syntax_for_file(&self, file_name: &str) -> String { fn syntax_for_file(&self, file_name: &str) -> String {
self.synax_for_file_with_content(file_name, "") self.syntax_for_file_with_content(file_name, "", false)
} }
} }
@ -299,15 +325,15 @@ mod tests {
let test = SyntaxDetectionTest::new(); let test = SyntaxDetectionTest::new();
assert_eq!( assert_eq!(
test.synax_for_file_with_content("my_script", "#!/bin/bash"), test.syntax_for_file_with_content("my_script", "#!/bin/bash", false),
"Bourne Again Shell (bash)" "Bourne Again Shell (bash)"
); );
assert_eq!( assert_eq!(
test.synax_for_file_with_content("build", "#!/bin/bash"), test.syntax_for_file_with_content("build", "#!/bin/bash", false),
"Bourne Again Shell (bash)" "Bourne Again Shell (bash)"
); );
assert_eq!( assert_eq!(
test.synax_for_file_with_content("my_script", "<?php"), test.syntax_for_file_with_content("my_script", "<?php", false),
"PHP" "PHP"
); );
} }
@ -333,4 +359,20 @@ mod tests {
.ok(); .ok();
assert_eq!(test.syntax_for_file("README.MD"), "Markdown"); assert_eq!(test.syntax_for_file("README.MD"), "Markdown");
} }
#[test]
fn syntax_detection_stdin_filename() {
let test = SyntaxDetectionTest::new();
// from file extension
assert_eq!(
test.syntax_for_file_with_content("test.cpp", "", true),
"C++"
);
// from first line (fallback)
assert_eq!(
test.syntax_for_file_with_content("my_script", "#!/bin/bash", true),
"Bourne Again Shell (bash)"
);
}
} }

View File

@ -78,6 +78,7 @@ impl<'b> Controller<'b> {
&self.config, &self.config,
&self.assets, &self.assets,
*input_file, *input_file,
file_name,
&mut reader, &mut reader,
); );
self.print_file(reader, &mut printer, writer, *input_file, file_name) self.print_file(reader, &mut printer, writer, *input_file, file_name)

View File

@ -112,6 +112,7 @@ impl<'a> InteractivePrinter<'a> {
config: &'a Config, config: &'a Config,
assets: &'a HighlightingAssets, assets: &'a HighlightingAssets,
file: InputFile, file: InputFile,
file_name: Option<&str>,
reader: &mut InputFileReader, reader: &mut InputFileReader,
) -> Self { ) -> Self {
let theme = assets.get_theme(&config.theme); let theme = assets.get_theme(&config.theme);
@ -177,7 +178,13 @@ impl<'a> InteractivePrinter<'a> {
} }
// Determine the type of syntax for highlighting // Determine the type of syntax for highlighting
let syntax = assets.get_syntax(config.language, file, reader, &config.syntax_mapping); let syntax = assets.get_syntax(
config.language,
file,
file_name,
reader,
&config.syntax_mapping,
);
Some(HighlightLines::new(syntax, theme)) Some(HighlightLines::new(syntax, theme))
}; };