Skip to content

Commit

Permalink
feat: support check-file in typos config file
Browse files Browse the repository at this point in the history
  • Loading branch information
ronnychevalier committed Jul 29, 2024
1 parent fb4ecd2 commit 04899fd
Show file tree
Hide file tree
Showing 6 changed files with 73 additions and 130 deletions.
17 changes: 0 additions & 17 deletions Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 0 additions & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ lang-yaml = ["dep:tree-sitter-yaml"]
anyhow = "1.0.86"
clap = { version = "4.5.9", features = ["derive"] }
ignore = "0.4.22"
kstring = { version = "2.0.0", features = ["serde"] }
miette = { version = "7.2.0", features = ["fancy"] }
rayon = "1.10.0"
serde = { version = "1.0.204", features = ["derive"] }
Expand Down
5 changes: 5 additions & 0 deletions src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,11 @@ impl Args {
let config = self.to_config()?;
let walker = self.to_walk(&config)?;
let process_entry = |file: DirEntry| {
if let Some(file_type_config) = config.type_.config_from_path(file.path()) {
if !file_type_config.check_file() {
return 0;
}
}
let Ok(Some(linter)) = Linter::from_path(file.path()) else {
return 0;
};
Expand Down
103 changes: 15 additions & 88 deletions src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -6,8 +6,10 @@ use std::ffi::OsStr;
use std::path::{Path, PathBuf};

use anyhow::Context;

use ignore::WalkBuilder;
use kstring::KString;

use crate::lang::Language;

const NO_CHECK_TYPES: &[&str] = &["cert", "lock"];

Expand Down Expand Up @@ -204,21 +206,18 @@ impl Walk {
#[serde(default)]
#[serde(transparent)]
pub struct TypeEngineConfig {
pub patterns: HashMap<KString, GlobEngineConfig>,
pub patterns: HashMap<String, EngineConfig>,
}

impl TypeEngineConfig {
pub fn from_defaults() -> Self {
let mut patterns = HashMap::new();

for no_check_type in NO_CHECK_TYPES {
for &no_check_type in NO_CHECK_TYPES {
patterns.insert(
KString::from(*no_check_type),
GlobEngineConfig {
extend_glob: Vec::new(),
engine: EngineConfig {
check_file: Some(false),
},
no_check_type.to_owned(),
EngineConfig {
check_file: Some(false),
},
);
}
Expand All @@ -235,26 +234,11 @@ impl TypeEngineConfig {
}
}

pub fn patterns(&self) -> impl Iterator<Item = (KString, GlobEngineConfig)> {
let mut engine = Self::from_defaults();
engine.update(self);
engine.patterns.into_iter()
}
}

#[derive(Debug, Clone, Default, PartialEq, Eq, serde::Serialize, serde::Deserialize)]
#[serde(default)]
#[serde(rename_all = "kebab-case")]
pub struct GlobEngineConfig {
pub extend_glob: Vec<KString>,
#[serde(flatten)]
pub engine: EngineConfig,
}

impl GlobEngineConfig {
pub fn update(&mut self, source: &Self) {
self.extend_glob.extend(source.extend_glob.iter().cloned());
self.engine.update(&source.engine);
pub fn config_from_path(&self, path: impl AsRef<Path>) -> Option<&EngineConfig> {
let path = path.as_ref();
let extension = path.extension()?;
let lang = Language::from_extension(extension)?;
self.patterns.get(lang.name())
}
}

Expand Down Expand Up @@ -321,73 +305,16 @@ mod test {
assert_eq!(actual, defaulted);
}

#[test]
fn test_extend_glob_updates() {
let null = GlobEngineConfig::default();
let extended = GlobEngineConfig {
extend_glob: vec!["*.foo".into()],
..Default::default()
};

let mut actual = null;
actual.update(&extended);

assert_eq!(actual, extended);
}

#[test]
fn test_extend_glob_extends() {
let base = GlobEngineConfig {
extend_glob: vec!["*.foo".into()],
..Default::default()
};
let extended = GlobEngineConfig {
extend_glob: vec!["*.bar".into()],
..Default::default()
};

let mut actual = base;
actual.update(&extended);

let expected: Vec<KString> = vec!["*.foo".into(), "*.bar".into()];
assert_eq!(actual.extend_glob, expected);
}

#[test]
fn parse_extend_globs() {
let input = r#"[type.po]
extend-glob = ["*.po"]
check-file = true
"#;
let mut expected = Config::default();
expected.type_.patterns.insert(
"po".into(),
GlobEngineConfig {
extend_glob: vec!["*.po".into()],
engine: EngineConfig {
check_file: Some(true),
},
},
);
let actual = Config::from_toml(input).unwrap();
assert_eq!(actual, expected);
}

#[test]
fn parse_extend_words() {
let input = r#"[type.shaders]
extend-glob = [
'*.shader',
'*.cginc',
]
"#;

let mut expected = Config::default();
expected.type_.patterns.insert(
"shaders".into(),
GlobEngineConfig {
extend_glob: vec!["*.shader".into(), "*.cginc".into()],
engine: EngineConfig::default(),
EngineConfig {
check_file: Some(true),
},
);
let actual = Config::from_toml(input).unwrap();
Expand Down
76 changes: 52 additions & 24 deletions src/lang.rs
Original file line number Diff line number Diff line change
Expand Up @@ -9,38 +9,53 @@ use crate::tree::PreorderTraversal;
#[cfg(feature = "lang-markdown")]
mod markdown;

static EXTENSION_LANGUAGE: LazyLock<HashMap<&'static OsStr, Arc<Language>>> = LazyLock::new(|| {
let mut map = HashMap::new();

macro_rules! lang {
($lang:ident, $feature: literal) => {
#[cfg(feature = $feature)]
{
let lang = Arc::new(Language::$lang());
for extension in lang.extensions() {
map.insert(OsStr::new(extension), Arc::clone(&lang));
struct Mapping {
lang_from_extensions: HashMap<&'static OsStr, Arc<Language>>,
}

impl Mapping {
pub fn build() -> Self {
let mut lang_from_extensions = HashMap::new();

macro_rules! lang {
($lang:ident, $feature: literal) => {
#[cfg(feature = $feature)]
{
let lang = Arc::new(Language::$lang());
for extension in lang.extensions() {
lang_from_extensions.insert(OsStr::new(extension), Arc::clone(&lang));
}
}
}
};
};
}

lang!(rust, "lang-rust");
lang!(c, "lang-c");
lang!(cpp, "lang-cpp");
lang!(go, "lang-go");
lang!(python, "lang-python");
lang!(toml, "lang-toml");
lang!(yaml, "lang-yaml");
lang!(json, "lang-json");
lang!(markdown, "lang-markdown");

Self {
lang_from_extensions,
}
}

lang!(rust, "lang-rust");
lang!(c, "lang-c");
lang!(cpp, "lang-cpp");
lang!(go, "lang-go");
lang!(python, "lang-python");
lang!(toml, "lang-toml");
lang!(yaml, "lang-yaml");
lang!(json, "lang-json");
lang!(markdown, "lang-markdown");
pub fn find_from_extension(&self, extension: &OsStr) -> Option<Arc<Language>> {
self.lang_from_extensions.get(extension).map(Arc::clone)
}
}

map
});
static MAPPING: LazyLock<Mapping> = LazyLock::new(Mapping::build);

type CustomParser = Box<dyn Fn(&[u8]) -> anyhow::Result<Box<dyn Parsed>> + Send + Sync>;

/// Parser for a language to find strings based on its grammar
pub struct Language {
name: &'static str,
language: tree_sitter::Language,
extensions: &'static [&'static str],
tree_sitter_types: &'static [&'static str],
Expand All @@ -59,7 +74,7 @@ impl Language {
/// assert!(Language::from_extension(OsStr::new("rs")).is_some());
/// ```
pub fn from_extension(extension: &OsStr) -> Option<Arc<Self>> {
EXTENSION_LANGUAGE.get(extension).map(Arc::clone)
MAPPING.find_from_extension(extension)
}

/// Returns an array of extensions supported by this language
Expand All @@ -77,6 +92,11 @@ impl Language {
self.extensions
}

/// Returns the name of the language
pub fn name(&self) -> &'static str {
self.name
}

/// Parses the content of a file
pub fn parse(&self, source_content: impl AsRef<[u8]>) -> anyhow::Result<Box<dyn Parsed>> {
if let Some(parser) = &self.parser {
Expand All @@ -99,6 +119,7 @@ impl Language {
#[cfg(feature = "lang-rust")]
pub fn rust() -> Self {
Self {
name: "rust",
language: tree_sitter_rust::language(),
extensions: &["rs"],
tree_sitter_types: &["string_content"],
Expand All @@ -110,6 +131,7 @@ impl Language {
#[cfg(feature = "lang-cpp")]
pub fn cpp() -> Self {
Self {
name: "cpp",
language: tree_sitter_cpp::language(),
extensions: &["cpp", "cc", "hpp", "hh"],
tree_sitter_types: &["string_content"],
Expand All @@ -121,6 +143,7 @@ impl Language {
#[cfg(feature = "lang-c")]
pub fn c() -> Self {
Self {
name: "c",
language: tree_sitter_c::language(),
extensions: &["c", "h"],
tree_sitter_types: &["string_content"],
Expand All @@ -132,6 +155,7 @@ impl Language {
#[cfg(feature = "lang-go")]
pub fn go() -> Self {
Self {
name: "go",
language: tree_sitter_go::language(),
extensions: &["go"],
tree_sitter_types: &["interpreted_string_literal"],
Expand All @@ -143,6 +167,7 @@ impl Language {
#[cfg(feature = "lang-python")]
pub fn python() -> Self {
Self {
name: "python",
language: tree_sitter_python::language(),
extensions: &["py"],
tree_sitter_types: &["string", "concatenated_string"],
Expand All @@ -154,6 +179,7 @@ impl Language {
#[cfg(feature = "lang-toml")]
pub fn toml() -> Self {
Self {
name: "toml",
language: tree_sitter_toml_ng::language(),
extensions: &["toml"],
tree_sitter_types: &["string"],
Expand All @@ -165,6 +191,7 @@ impl Language {
#[cfg(feature = "lang-yaml")]
pub fn yaml() -> Self {
Self {
name: "yaml",
language: tree_sitter_yaml::language(),
extensions: &["yml", "yaml"],
tree_sitter_types: &["string_scalar"],
Expand All @@ -176,6 +203,7 @@ impl Language {
#[cfg(feature = "lang-json")]
pub fn json() -> Self {
Self {
name: "json",
language: tree_sitter_json::language(),
extensions: &["json"],
tree_sitter_types: &["string_content"],
Expand Down
1 change: 1 addition & 0 deletions src/lang/markdown.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ const TREE_SITTER_TYPES: &[&str] = &["inline"];

pub fn lang() -> Language {
Language {
name: "markdown",
language: tree_sitter_md::language(),
extensions: &["md"],
tree_sitter_types: TREE_SITTER_TYPES,
Expand Down

0 comments on commit 04899fd

Please sign in to comment.