From 748c14588cf1c31c8b8d60a9c94349c0173ef607 Mon Sep 17 00:00:00 2001 From: 魏曹先生 <1992414357@qq.com> Date: Sun, 28 Jun 2026 09:06:08 +0800 Subject: feat(pathf): add build-time type path resolution system Add `mingling_pathf` sub-crate and `pathf` feature for automatic resolution of Mingling type module paths at build time. Scans source files, identifies macro invocations via pattern matchers, and generates mapping files consumed by `gen_program!()`. --- mingling_pathf/src/patterns/dispatcher_clap.rs | 60 ++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) create mode 100644 mingling_pathf/src/patterns/dispatcher_clap.rs (limited to 'mingling_pathf/src/patterns/dispatcher_clap.rs') diff --git a/mingling_pathf/src/patterns/dispatcher_clap.rs b/mingling_pathf/src/patterns/dispatcher_clap.rs new file mode 100644 index 0000000..398b269 --- /dev/null +++ b/mingling_pathf/src/patterns/dispatcher_clap.rs @@ -0,0 +1,60 @@ +use syn::Item; + +use crate::pattern_analyzer::{AnalyzeItem, AnalyzePattern}; + +/// Match structs annotated with `#[dispatcher_clap]`, extracting the entry type name (i.e., the struct name). +/// +/// Covers the following forms: +/// - `#[dispatcher_clap] struct EntryGreet { ... }` +/// - `#[dispatcher_clap] #[command(...)] struct EntryGreet { ... }` +pub struct DispatcherClapPattern; + +impl AnalyzePattern for DispatcherClapPattern { + fn contains(&self, content: &str) -> bool { + content.contains("dispatcher_clap(") + } + + fn analyze(&self, content: &str) -> Vec { + let Ok(syntax) = syn::parse_file(content) else { + return Vec::new(); + }; + + let mut items = Vec::new(); + + for item in &syntax.items { + match item { + Item::Struct(s) if has_attr(&s.attrs, "dispatcher_clap") => { + items.push(AnalyzeItem { + module: String::new(), + item_name: s.ident.to_string(), + }); + } + Item::Mod(item_mod) => { + if let Some((_, nested)) = &item_mod.content { + for n in nested { + if let Item::Struct(s) = n + && has_attr(&s.attrs, "dispatcher_clap") { + items.push(AnalyzeItem { + module: item_mod.ident.to_string(), + item_name: s.ident.to_string(), + }); + } + } + } + } + _ => {} + } + } + + items + } +} + +fn has_attr(attrs: &[syn::Attribute], name: &str) -> bool { + attrs.iter().any(|a| { + a.path() + .segments + .last() + .is_some_and(|s| s.ident == name) + }) +} -- cgit