diff --git a/src/main.rs b/src/main.rs index 4549b43b0..a2847d3d8 100644 --- a/src/main.rs +++ b/src/main.rs @@ -51,7 +51,7 @@ use files::{ }; use log::info; use mimalloc::MiMalloc; -use parse::guess_language::{guess, language_name, Language}; +use parse::guess_language::{guess, language_name, Language, LanguageOverride}; /// The global allocator used by difftastic. /// @@ -98,12 +98,15 @@ fn main() { reset_sigpipe(); match options::parse_args() { - Mode::DumpTreeSitter { path, language_overrides} => { + Mode::DumpTreeSitter { + path, + language_overrides, + } => { let path = Path::new(&path); let bytes = read_or_die(path); let src = String::from_utf8_lossy(&bytes).to_string(); - let language = guess(path, &src); + let language = guess(path, &src, &language_overrides); match language { Some(lang) => { let ts_lang = tsp::from_language(lang); @@ -124,7 +127,7 @@ fn main() { let bytes = read_or_die(path); let src = String::from_utf8_lossy(&bytes).to_string(); - let language = guess(path, &src); + let language = guess(path, &src, &language_overrides); match language { Some(lang) => { let ts_lang = tsp::from_language(lang); @@ -138,7 +141,23 @@ fn main() { } } } - Mode::ListLanguages { use_color, language_overrides } => { + Mode::ListLanguages { + use_color, + language_overrides, + } => { + for (glob, lang_override) in language_overrides { + let mut name = match lang_override { + LanguageOverride::Language(lang) => language_name(lang), + LanguageOverride::PlainText => "Text", + } + .to_string(); + if use_color { + name = name.bold().to_string(); + } + println!("{} (from override)", name); + println!(" {}", glob.as_str()); + } + for language in Language::iter() { let mut name = language_name(language).to_string(); if use_color { @@ -199,9 +218,15 @@ fn main() { } }); - diff_directories(lhs_path, rhs_path, &display_options, &diff_options) - .try_for_each_with(send, |s, diff_result| s.send(diff_result)) - .expect("Receiver should be connected"); + diff_directories( + lhs_path, + rhs_path, + &display_options, + &diff_options, + &language_overrides, + ) + .try_for_each_with(send, |s, diff_result| s.send(diff_result)) + .expect("Receiver should be connected"); printing_thread .join() @@ -216,6 +241,7 @@ fn main() { &display_options, &diff_options, false, + &language_overrides, ); print_diff_result(&display_options, &diff_result); @@ -259,6 +285,7 @@ fn diff_file( display_options: &DisplayOptions, diff_options: &DiffOptions, missing_as_empty: bool, + overrides: &[(glob::Pattern, LanguageOverride)], ) -> DiffResult { let (lhs_bytes, rhs_bytes) = read_files_or_die(lhs_path, rhs_path, missing_as_empty); diff_file_content( @@ -270,6 +297,7 @@ fn diff_file( &rhs_bytes, display_options, diff_options, + overrides, ) } @@ -305,6 +333,7 @@ fn diff_file_content( rhs_bytes: &[u8], display_options: &DisplayOptions, diff_options: &DiffOptions, + overrides: &[(glob::Pattern, LanguageOverride)], ) -> DiffResult { let (lhs_src, rhs_src) = match (guess_content(lhs_bytes), guess_content(rhs_bytes)) { (ProbableFileKind::Binary, _) | (_, ProbableFileKind::Binary) => { @@ -330,7 +359,7 @@ fn diff_file_content( FileArgument::DevNull => (&lhs_src, Path::new(&display_path)), }; - let language = guess(guess_path, guess_src); + let language = guess(guess_path, guess_src, overrides); let lang_config = language.map(tsp::from_language); if lhs_bytes == rhs_bytes { @@ -555,9 +584,11 @@ fn diff_directories<'a>( rhs_dir: &'a Path, display_options: &DisplayOptions, diff_options: &DiffOptions, + overrides: &[(glob::Pattern, LanguageOverride)], ) -> impl ParallelIterator + 'a { let diff_options = diff_options.clone(); let display_options = display_options.clone(); + let overrides: Vec<_> = overrides.into(); // We greedily list all files in the directory, and then diff them // in parallel. This is assuming that diffing is slower than @@ -578,6 +609,7 @@ fn diff_directories<'a>( &display_options, &diff_options, true, + &overrides, ) }) } diff --git a/src/options.rs b/src/options.rs index 6a3ac3b53..82c6a164a 100644 --- a/src/options.rs +++ b/src/options.rs @@ -5,12 +5,11 @@ use std::{env, ffi::OsStr, path::Path, path::PathBuf}; use clap::{crate_authors, crate_description, crate_version, Arg, Command}; use const_format::formatcp; use crossterm::tty::IsTty; -use strum::IntoEnumIterator; use crate::{ display::style::BackgroundColor, exit_codes::EXIT_BAD_ARGUMENTS, - parse::guess_language::{self, language_name, LanguageOverride, language_override_from_name}, + parse::guess_language::{language_override_from_name, LanguageOverride}, }; pub const DEFAULT_BYTE_LIMIT: usize = 1_000_000; diff --git a/src/parse/guess_language.rs b/src/parse/guess_language.rs index b078deca8..2b256fa93 100644 --- a/src/parse/guess_language.rs +++ b/src/parse/guess_language.rs @@ -72,7 +72,7 @@ pub enum Language { Zig, } -#[derive(Debug)] +#[derive(Debug, Clone, Copy)] pub enum LanguageOverride { Language(Language), PlainText, @@ -356,7 +356,25 @@ fn looks_like_hacklang(path: &Path, src: &str) -> bool { false } -pub fn guess(path: &Path, src: &str) -> Option { +pub fn guess( + path: &Path, + src: &str, + overrides: &[(glob::Pattern, LanguageOverride)], +) -> Option { + if let Some(file_name) = path.file_name() { + let file_name = file_name.to_string_lossy(); + for (pattern, lang_override) in overrides { + if pattern.matches(&file_name) { + match lang_override { + LanguageOverride::Language(lang) => return Some(*lang), + LanguageOverride::PlainText => { + return None; + } + } + } + } + } + if let Some(lang) = from_emacs_mode_header(src) { return Some(lang); }