on master help sign in
Small refactoring, handle invalid UTF-8 filenames
commit34619a2e89b8f65d362a596b86337ca17409f13c authorsharkdp <davidpeter@web.de> dateTue 21 Apr 2020, 08:19 (7 years ago) parent83d408b
5 files changed+47−25
src/assets.rs+33−9 src/bin/bat/app.rs+4−3 src/controller.rs+1−1 src/inputfile.rs+6−9 src/printer.rs+3−3
src/assets.rs+33−9
@@ -1,4 +1,5 @@
11use std::collections::BTreeMap;
2+use std::ffi::OsStr;
23use std::fs::{self, File};
34use std::io::BufReader;
45use std::path::Path;
@@ -183,8 +184,7 @@ impl HighlightingAssets {
183184 let syntax = match (language, file) {
184185 (Some(language), _) => self.syntax_set.find_syntax_by_token(language),
185186 (None, InputFile::Ordinary(ofile)) => {
186− let path = Path::new(ofile.filename());
187− let file_name = path.file_name().and_then(|n| n.to_str()).unwrap_or("");
187+ let path = Path::new(ofile.provided_path());
188188 let line_syntax = self.get_first_line_syntax(reader);
189189
190190 let absolute_path = path.canonicalize().ok().unwrap_or(path.to_owned());
@@ -195,14 +195,17 @@ impl HighlightingAssets {
195195 self.syntax_set.find_syntax_by_name(syntax_name)
196196 }
197197 Some(MappingTarget::MapToUnknown) => line_syntax,
198− None => self.get_extension_syntax(file_name).or(line_syntax),
198+ None => {
199+ let file_name = path.file_name().unwrap_or_default();
200+ self.get_extension_syntax(file_name).or(line_syntax)
201+ }
199202 }
200203 }
201204 (None, InputFile::StdIn(None)) => String::from_utf8(reader.first_line.clone())
202205 .ok()
203206 .and_then(|l| self.syntax_set.find_syntax_by_first_line(&l)),
204207 (None, InputFile::StdIn(Some(file_name))) => self
205− .get_extension_syntax(file_name.to_str().unwrap())
208+ .get_extension_syntax(file_name)
206209 .or(self.get_first_line_syntax(reader)),
207210 (_, InputFile::ThemePreviewFile) => self.syntax_set.find_syntax_by_name("Rust"),
208211 };
@@ -210,15 +213,15 @@ impl HighlightingAssets {
210213 syntax.unwrap_or_else(|| self.syntax_set.find_syntax_plain_text())
211214 }
212215
213− fn get_extension_syntax(&self, file_name: &str) -> Option<&SyntaxReference> {
216+ fn get_extension_syntax(&self, file_name: &OsStr) -> Option<&SyntaxReference> {
214217 self.syntax_set
215− .find_syntax_by_extension(file_name)
218+ .find_syntax_by_extension(file_name.to_str().unwrap_or_default())
216219 .or_else(|| {
217220 self.syntax_set.find_syntax_by_extension(
218221 Path::new(file_name)
219222 .extension()
220223 .and_then(|x| x.to_str())
221− .unwrap_or(""),
224+ .unwrap_or_default(),
222225 )
223226 })
224227 }
@@ -259,14 +262,14 @@ mod tests {
259262 }
260263 }
261264
262− fn syntax_for_file_with_content(&self, file_name: &str, first_line: &str) -> String {
265+ fn syntax_for_file_with_content_os(&self, file_name: &OsStr, first_line: &str) -> String {
263266 let file_path = self.temp_dir.path().join(file_name);
264267 {
265268 let mut temp_file = File::create(&file_path).unwrap();
266269 writeln!(temp_file, "{}", first_line).unwrap();
267270 }
268271
269− let input_file = InputFile::Ordinary(OrdinaryFile::from_path(OsStr::new(&file_path)));
272+ let input_file = InputFile::Ordinary(OrdinaryFile::from_path(file_path.as_os_str()));
270273 let syntax = self.assets.get_syntax(
271274 None,
272275 input_file,
@@ -277,6 +280,14 @@ mod tests {
277280 syntax.name.clone()
278281 }
279282
283+ fn syntax_for_file_os(&self, file_name: &OsStr) -> String {
284+ self.syntax_for_file_with_content_os(file_name, "")
285+ }
286+
287+ fn syntax_for_file_with_content(&self, file_name: &str, first_line: &str) -> String {
288+ self.syntax_for_file_with_content_os(OsStr::new(file_name), first_line)
289+ }
290+
280291 fn syntax_for_file(&self, file_name: &str) -> String {
281292 self.syntax_for_file_with_content(file_name, "")
282293 }
@@ -308,6 +319,19 @@ mod tests {
308319 assert_eq!(test.syntax_for_file("Makefile"), "Makefile");
309320 }
310321
322+ #[cfg(unix)]
323+ #[test]
324+ fn syntax_detection_invalid_utf8() {
325+ use std::os::unix::ffi::OsStrExt;
326+
327+ let test = SyntaxDetectionTest::new();
328+
329+ assert_eq!(
330+ test.syntax_for_file_os(OsStr::from_bytes(b"invalid_\xFEutf8_filename.rs")),
331+ "Rust"
332+ );
333+ }
334+
311335 #[test]
312336 fn syntax_detection_well_defined_mapping_for_duplicate_extensions() {
313337 let test = SyntaxDetectionTest::new();
src/bin/bat/app.rs+4−3
@@ -264,9 +264,10 @@ impl App {
264264 if input.to_str().unwrap() == "-" {
265265 file_input.push(InputFile::StdIn(name));
266266 } else {
267− let ofile = name.map_or(OrdinaryFile::from_path(input), |n| {
268− OrdinaryFile::from_path_with_name(input, n)
269− });
267+ let mut ofile = OrdinaryFile::from_path(input);
268+ if let Some(path) = name {
269+ ofile.set_provided_path(path);
270+ }
270271 file_input.push(InputFile::Ordinary(ofile))
271272 }
272273 }
src/controller.rs+1−1
@@ -36,7 +36,7 @@ impl<'b> Controller<'b> {
3636 if self.config.paging_mode != PagingMode::Never {
3737 let call_pager = self.config.files.iter().any(|file| {
3838 if let InputFile::Ordinary(ofile) = file {
39− return Path::new(ofile.filename()).exists();
39+ return Path::new(ofile.provided_path()).exists();
4040 } else {
4141 return true;
4242 }
src/inputfile.rs+6−9
@@ -55,26 +55,23 @@ impl<'a> InputFileReader<'a> {
5555#[derive(Debug, Clone, Copy, PartialEq)]
5656pub struct OrdinaryFile<'a> {
5757 path: &'a OsStr,
58− user_provided_name: Option<&'a OsStr>,
58+ user_provided_path: Option<&'a OsStr>,
5959}
6060
6161impl<'a> OrdinaryFile<'a> {
6262 pub fn from_path(path: &'a OsStr) -> OrdinaryFile<'a> {
6363 OrdinaryFile {
6464 path,
65− user_provided_name: None,
65+ user_provided_path: None,
6666 }
6767 }
6868
69− pub fn from_path_with_name(path: &'a OsStr, user_provided_name: &'a OsStr) -> OrdinaryFile<'a> {
70− OrdinaryFile {
71− path,
72− user_provided_name: Some(user_provided_name),
73− }
69+ pub fn set_provided_path(&mut self, user_provided_path: &'a OsStr) {
70+ self.user_provided_path = Some(user_provided_path);
7471 }
7572
76− pub(crate) fn filename(&self) -> &'a OsStr {
77− self.user_provided_name.unwrap_or_else(|| self.path)
73+ pub(crate) fn provided_path(&self) -> &'a OsStr {
74+ self.user_provided_path.unwrap_or_else(|| self.path)
7875 }
7976}
8077
src/printer.rs+3−3
@@ -161,7 +161,7 @@ impl<'a> InteractivePrinter<'a> {
161161 {
162162 if config.style_components.changes() {
163163 if let InputFile::Ordinary(ofile) = file {
164− line_changes = get_git_diff(ofile.filename());
164+ line_changes = get_git_diff(ofile.provided_path());
165165 }
166166 }
167167 }
@@ -235,7 +235,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
235235 if Some(ContentType::BINARY) == self.content_type && !self.config.show_nonprintable {
236236 let input = match file {
237237 InputFile::Ordinary(ofile) => {
238− format!("file '{}'", &ofile.filename().to_string_lossy())
238+ format!("file '{}'", &ofile.provided_path().to_string_lossy())
239239 }
240240 InputFile::StdIn(Some(name)) => name.to_string_lossy().into_owned(),
241241 InputFile::StdIn(None) => "STDIN".to_owned(),
@@ -276,7 +276,7 @@ impl<'a> Printer for InteractivePrinter<'a> {
276276 let (prefix, name) = match file {
277277 InputFile::Ordinary(ofile) => (
278278 "File: ",
279− Cow::from(ofile.filename().to_string_lossy().to_owned()),
279+ Cow::from(ofile.provided_path().to_string_lossy().to_owned()),
280280 ),
281281 InputFile::StdIn(Some(name)) => {
282282 ("File: ", Cow::from(name.to_string_lossy().to_owned()))