diff options
| author | 魏曹先生 <1992414357@qq.com> | 2026-06-29 03:34:41 +0800 |
|---|---|---|
| committer | 魏曹先生 <1992414357@qq.com> | 2026-06-29 03:34:41 +0800 |
| commit | ba15b7c06468cb6c52c8d2a53419fd83f9ebcb8b (patch) | |
| tree | cdaa1c71585d10dd73945cefe95f2c25f27924ed /src/expand.rs | |
| parent | ff70307869a547b13850d1eec3f72e8ca3bca265 (diff) | |
refactor: promote project to workspace with macros sub-crate
Diffstat (limited to 'src/expand.rs')
| -rw-r--r-- | src/expand.rs | 212 |
1 files changed, 0 insertions, 212 deletions
diff --git a/src/expand.rs b/src/expand.rs deleted file mode 100644 index b609113..0000000 --- a/src/expand.rs +++ /dev/null @@ -1,212 +0,0 @@ -use std::collections::HashMap; - -use just_fmt::snake_case; - -use crate::template::Template; - -const DISPLAY_BLOCK_BEGIN: &str = "??? >>> "; -const DISPLAY_BLOCK_END: &str = "??? <<<"; - -const IMPL_AREA_BEGIN: &str = "@@@ >>> "; -const IMPL_AREA_END: &str = "@@@ <<<"; - -const IMPL_BEGIN: &str = ">>>>>>>>>>"; - -const PARAM_BEGIN: &str = "<<<"; -const PARAM_BEND: &str = ">>>"; - -impl Template { - pub fn expand(mut self) -> Option<String> { - // Extract template text - let expanded = std::mem::take(&mut self.template_str); - - let (expanded, impl_areas) = read_impl_areas(expanded)?; - let expanded = apply_impls(&self, expanded, impl_areas)?; - let expanded = apply_display_blocks(&self.params, expanded); - let expanded = apply_param(&self, expanded)?; - Some(expanded.trim().to_string()) - } -} - -/// Read all ImplAreas (HashMap<Name, Codes>) -fn read_impl_areas(content: String) -> Option<(String, HashMap<String, String>)> { - let mut striped_content = String::new(); - let mut impl_areas: HashMap<String, String> = HashMap::new(); - - let mut current_area_name = String::default(); - let mut current_area_codes: Vec<String> = Vec::new(); - - for line in content.split("\n") { - let trimmed_line = line.trim(); - - // Implementation block end - if trimmed_line.starts_with(IMPL_AREA_END) { - // If the current ImplArea name length is less than 1, it means no block is being matched, - // so matching fails, exit early - if current_area_name.is_empty() { - return None; - } - - // Submit Impl Area - let name = std::mem::take(&mut current_area_name); - impl_areas.insert(name, current_area_codes.join("\n")); - current_area_codes.clear(); - continue; - } - - // Implementation block start - if trimmed_line.starts_with(IMPL_AREA_BEGIN) { - // If the current ImplArea name length is greater than 0, it means we are already inside a block, - // since nesting is not allowed, matching fails, exit early - if !current_area_name.is_empty() { - return None; - } - - // Get a snake_case name - let snake_name = snake_case!(line.trim_start_matches(IMPL_AREA_BEGIN).trim()); - current_area_name = snake_name; - - // Continue to next line - continue; - } - - // During implementation block - if !current_area_name.is_empty() { - // Add to current block code - current_area_codes.push(line.to_string()); - continue; - } else { - // Add to remaining content - striped_content += "\n"; - striped_content += line; - } - } - - Some((striped_content, impl_areas)) -} - -/// Apply Template parameters to implementation block areas -fn apply_impls( - template: &Template, - content: String, - impl_areas: HashMap<String, String>, -) -> Option<String> { - let mut applied_content = String::new(); - - let mut impled_areas: HashMap<String, Vec<String>> = HashMap::new(); - for (impl_area_name, impl_area_template) in impl_areas { - // Get user-provided parameters - let impl_items = template.impl_params.get(&impl_area_name); - - // No parameters, return early - let Some(impl_items) = impl_items else { - impled_areas.insert(impl_area_name, Vec::new()); - continue; - }; - - let mut impled_area_code_applied = Vec::new(); - - // Split items - for item in impl_items { - // Get base template - let mut applied = impl_area_template.clone(); - - // Merge global params with arm-specific params for display block check - let mut display_params = template.params.clone(); - for (k, v) in item { - display_params.insert(k.clone(), v.clone()); - } - applied = apply_display_blocks(&display_params, applied); - - // Extract parameters - for (param_name, param_value) in item { - // Apply parameter - applied = applied.replace( - &format!("{}{}{}", PARAM_BEGIN, param_name, PARAM_BEND), - param_value, - ); - } - - // Add applied template - impled_area_code_applied.push(applied); - } - - impled_areas.insert(impl_area_name, impled_area_code_applied); - } - - for line in content.split("\n") { - let trimmed_line = line.trim(); - - // Recognize implementation line - if trimmed_line.starts_with(IMPL_BEGIN) { - let impl_name = snake_case!(trimmed_line.trim_start_matches(IMPL_BEGIN).trim()); - - // Try to get implementation code block - let Some(impled_code) = impled_areas.get(&impl_name) else { - continue; - }; - - if !impled_code.is_empty() { - applied_content += "\n"; - applied_content += impled_code.join("\n").as_str(); - } - } else { - // Other content directly appended - applied_content += "\n"; - applied_content += line; - } - } - - Some(applied_content) -} - -/// Process display blocks (`??? >>> name` / `??? <<<`). -/// -/// If `params` contains a key matching the block name, the block content is -/// included (with markers removed). Otherwise the entire block is omitted. -fn apply_display_blocks(params: &HashMap<String, String>, content: String) -> String { - let mut result = String::new(); - let lines: Vec<&str> = content.split("\n").collect(); - let mut i = 0; - let mut first = true; - - while i < lines.len() { - let line = lines[i]; - let trimmed = line.trim(); - - if trimmed.starts_with(DISPLAY_BLOCK_BEGIN) { - let block_name = trimmed.trim_start_matches(DISPLAY_BLOCK_BEGIN).trim(); - let show = params.contains_key(block_name); - i += 1; - - while i < lines.len() && !lines[i].trim().starts_with(DISPLAY_BLOCK_END) { - if show { - if !first { - result += "\n"; - } - result += lines[i]; - first = false; - } - i += 1; - } - } else if !trimmed.starts_with(DISPLAY_BLOCK_END) { - if !first { - result += "\n"; - } - result += line; - first = false; - } - - i += 1; - } - - result -} - -fn apply_param(template: &Template, content: String) -> Option<String> { - let mut content = content; - for (k, v) in template.params.iter() { - content = content.replace(&format!("{}{}{}", PARAM_BEGIN, k, PARAM_BEND), v); - } - Some(content) -} |
