//! Rhai wrappers for Text module functions //! //! This module provides Rhai wrappers for the functions in the Text module. use rhai::{Engine, EvalAltResult, Array, Map, Position}; use std::collections::HashMap; use crate::text::{ TextReplacer, TextReplacerBuilder, TemplateBuilder, dedent, prefix, name_fix, path_fix }; /// Register Text module functions with the Rhai engine /// /// # Arguments /// /// * `engine` - The Rhai engine to register the functions with /// /// # Returns /// /// * `Result<(), Box>` - Ok if registration was successful, Err otherwise pub fn register_text_module(engine: &mut Engine) -> Result<(), Box> { // Register types register_text_types(engine)?; // Register TextReplacer constructor engine.register_fn("text_replacer_new", text_replacer_new); // Register TextReplacerBuilder instance methods engine.register_fn("pattern", pattern); engine.register_fn("replacement", replacement); engine.register_fn("regex", regex); engine.register_fn("case_insensitive", case_insensitive); engine.register_fn("and", and); engine.register_fn("build", build); // Register TextReplacer instance methods engine.register_fn("replace", replace); engine.register_fn("replace_file", replace_file); engine.register_fn("replace_file_in_place", replace_file_in_place); engine.register_fn("replace_file_to", replace_file_to); // Register TemplateBuilder constructor engine.register_fn("template_builder_open", template_builder_open); // Register TemplateBuilder instance methods engine.register_fn("add_var", add_var_string); engine.register_fn("add_var", add_var_int); engine.register_fn("add_var", add_var_float); engine.register_fn("add_var", add_var_bool); engine.register_fn("add_var", add_var_array); engine.register_fn("add_vars", add_vars); engine.register_fn("render", render); engine.register_fn("render_to_file", render_to_file); // Register Fix functions directly from text module engine.register_fn("name_fix", crate::text::name_fix); engine.register_fn("path_fix", crate::text::path_fix); // Register Dedent functions directly from text module engine.register_fn("dedent", crate::text::dedent); engine.register_fn("prefix", crate::text::prefix); Ok(()) } /// Register Text module types with the Rhai engine fn register_text_types(engine: &mut Engine) -> Result<(), Box> { // Register TextReplacerBuilder type engine.register_type_with_name::("TextReplacerBuilder"); // Register TextReplacer type engine.register_type_with_name::("TextReplacer"); // Register TemplateBuilder type engine.register_type_with_name::("TemplateBuilder"); Ok(()) } // Helper functions for error conversion fn io_error_to_rhai_error(result: std::io::Result) -> Result> { result.map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("IO error: {}", e).into(), Position::NONE )) }) } fn tera_error_to_rhai_error(result: Result) -> Result> { result.map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( format!("Template error: {}", e).into(), Position::NONE )) }) } fn string_error_to_rhai_error(result: Result) -> Result> { result.map_err(|e| { Box::new(EvalAltResult::ErrorRuntime( e.into(), Position::NONE )) }) } // TextReplacer implementation /// Creates a new TextReplacerBuilder pub fn text_replacer_new() -> TextReplacerBuilder { TextReplacerBuilder::default() } /// Sets the pattern to search for pub fn pattern(builder: TextReplacerBuilder, pat: &str) -> TextReplacerBuilder { builder.pattern(pat) } /// Sets the replacement text pub fn replacement(builder: TextReplacerBuilder, rep: &str) -> TextReplacerBuilder { builder.replacement(rep) } /// Sets whether to use regex pub fn regex(builder: TextReplacerBuilder, yes: bool) -> TextReplacerBuilder { builder.regex(yes) } /// Sets whether the replacement should be case-insensitive pub fn case_insensitive(builder: TextReplacerBuilder, yes: bool) -> TextReplacerBuilder { builder.case_insensitive(yes) } /// Adds another replacement operation to the chain and resets the builder for a new operation pub fn and(builder: TextReplacerBuilder) -> TextReplacerBuilder { builder.and() } /// Builds the TextReplacer with all configured replacement operations pub fn build(builder: TextReplacerBuilder) -> Result> { string_error_to_rhai_error(builder.build()) } /// Applies all configured replacement operations to the input text pub fn replace(replacer: &mut TextReplacer, input: &str) -> String { replacer.replace(input) } /// Reads a file, applies all replacements, and returns the result as a string pub fn replace_file(replacer: &mut TextReplacer, path: &str) -> Result> { io_error_to_rhai_error(replacer.replace_file(path)) } /// Reads a file, applies all replacements, and writes the result back to the file pub fn replace_file_in_place(replacer: &mut TextReplacer, path: &str) -> Result<(), Box> { io_error_to_rhai_error(replacer.replace_file_in_place(path)) } /// Reads a file, applies all replacements, and writes the result to a new file pub fn replace_file_to(replacer: &mut TextReplacer, input_path: &str, output_path: &str) -> Result<(), Box> { io_error_to_rhai_error(replacer.replace_file_to(input_path, output_path)) } // TemplateBuilder implementation /// Creates a new TemplateBuilder with the specified template path pub fn template_builder_open(template_path: &str) -> Result> { io_error_to_rhai_error(TemplateBuilder::open(template_path)) } /// Adds a string variable to the template context pub fn add_var_string(builder: TemplateBuilder, name: &str, value: &str) -> TemplateBuilder { builder.add_var(name, value) } /// Adds an integer variable to the template context pub fn add_var_int(builder: TemplateBuilder, name: &str, value: i64) -> TemplateBuilder { builder.add_var(name, value) } /// Adds a float variable to the template context pub fn add_var_float(builder: TemplateBuilder, name: &str, value: f64) -> TemplateBuilder { builder.add_var(name, value) } /// Adds a boolean variable to the template context pub fn add_var_bool(builder: TemplateBuilder, name: &str, value: bool) -> TemplateBuilder { builder.add_var(name, value) } /// Adds an array variable to the template context pub fn add_var_array(builder: TemplateBuilder, name: &str, array: Array) -> TemplateBuilder { // Convert Rhai Array to Vec let vec: Vec = array.iter() .filter_map(|v| v.clone().into_string().ok()) .collect(); builder.add_var(name, vec) } /// Adds multiple variables to the template context from a Map pub fn add_vars(builder: TemplateBuilder, vars: Map) -> TemplateBuilder { // Convert Rhai Map to Rust HashMap let mut hash_map = HashMap::new(); for (key, value) in vars.iter() { if let Ok(val_str) = value.clone().into_string() { hash_map.insert(key.to_string(), val_str); } } // Add the variables builder.add_vars(hash_map) } /// Renders the template with the current context pub fn render(builder: &mut TemplateBuilder) -> Result> { tera_error_to_rhai_error(builder.render()) } /// Renders the template and writes the result to a file pub fn render_to_file(builder: &mut TemplateBuilder, output_path: &str) -> Result<(), Box> { io_error_to_rhai_error(builder.render_to_file(output_path)) }