forge_rsx/lib.rs
1#![doc = include_str!("../README.md")]
2
3/// ### Rules Module
4///
5/// A module that encapsulates the rules and functionalities of the `rsx` macro.
6///
7/// A macro to generate HTML-like markup with different indentation styles.
8///
9/// Usage:
10/// ```rust
11/// use forge_rsx::{rsx, get_char};
12///
13/// fn main() {
14/// // 1. Component defined with 'lined' (minified single line)
15/// let apple = "🍎 Apple";
16/// let apple_component = rsx!(lined, span { {&apple} });
17///
18/// // 2. Full HTML Document using 'doctype_html' and 'btfy4'
19/// let html_doc = rsx! {
20/// btfy4,
21/// doctype_html
22/// html {
23/// head {
24/// meta { charset: "UTF-8" } // No comma needed here
25/// meta { name: "viewport", content: "width=device-width, initial-scale=1.0" }
26/// title { "Forge RSX Demo" }
27/// }
28/// body {
29/// "x-data": "{ open: false }", ":class": "bg-white",
30/// h1 { "Welcome to Forge RSX" }
31/// br {}
32/// div {
33/// class: "container",
34/// "x-show": "open",
35/// "Alpine.js integration demo"
36/// }
37/// "id": "my-id", "style": "color: #4f4f4f; font-size: 2rem;" // No comma needed here
38/// }
39/// }
40/// };
41///
42/// // 3. Formatting Samples: Demonstrating 0 and 2-space indentation styles
43/// let span = rsx!(btfy0, span { "..." });
44/// let empty_p = rsx!(tabed, p { });
45/// let p = rsx!(btfy2, p {"..."});
46///
47/// // 4. Complex section with 'for' loops and logic
48/// let fruits = vec!["🍇", "mango", "orange"];
49/// let section = rsx!(btfy4, section {
50/// div {
51/// ol {
52/// for fruit in &fruits => {
53/// li {
54/// span {
55/// {
56/// if fruit == &"🍇" {
57/// &format!("{} {}", fruit.to_string(), "Grapes")
58/// } else if fruit == &"mango" {
59/// &format!("{} {}", "🥭", fruit.to_lowercase())
60/// } else {
61/// &fruit.to_uppercase()
62/// }
63/// }
64/// }
65/// }
66/// }
67/// li {
68/// {"<!-- How to join RSX component -->"}
69/// {&apple_component.to_string()}
70/// {
71/// if get_char(&apple, 1).to_string() == "🍎" {
72/// "🍎".to_string()
73/// } else {
74/// apple_component.to_string()
75/// }
76/// }
77/// }
78/// }
79/// }
80/// });
81///
82/// // 5. Printing all results
83/// println!("--- FULL HTML DOCUMENT ---\n{}\n", html_doc);
84/// println!("--- MINIFIED SPAN ---\n{}\n", span);
85/// println!("--- EMPTY P ---\n{}\n", empty_p);
86/// println!("--- P WITH CONTENT ---\n{}\n", p);
87/// println!("--- FRUIT SECTION ---\n{}", section);
88///
89/// // --- FULL HTML DOCUMENT ---
90/// // <!DOCTYPE html>
91/// // <html>
92/// // <head>
93/// // <meta charset="UTF-8">
94/// // <meta name="viewport" content="width=device-width, initial-scale=1.0">
95/// // <title>
96/// // Forge RSX Demo
97/// // </title>
98/// // </head>
99/// // <body x-data="{ open: false }" :class="bg-white" id="my-id" style="color: #4f4f4f; font-size: 2rem;">
100/// // <h1>
101/// // Welcome to Forge RSX
102/// // </h1>
103/// // <br>
104/// // <div class="container" x-show="open">
105/// // Alpine.js integration demo
106/// // </div>
107/// // </body>
108/// // </html>
109///
110/// // --- MINIFIED SPAN ---
111/// // <span>
112/// // ...
113/// // </span>
114///
115/// // --- EMPTY P ---
116/// // <p></p>
117///
118/// // --- P WITH CONTENT ---
119/// // <p>
120/// // ...
121/// // </p>
122///
123/// // --- FRUIT SECTION ---
124/// // <section>
125/// // <div>
126/// // <ol>
127/// // <li>
128/// // <span>
129/// // 🍇 Grapes
130/// // </span>
131/// // </li>
132/// // <li>
133/// // <span>
134/// // 🥭 mango
135/// // </span>
136/// // </li>
137/// // <li>
138/// // <span>
139/// // ORANGE
140/// // </span>
141/// // </li>
142/// // <li>
143/// // <!-- How to join RSX component -->
144/// // <span>🍎 Apple</span>
145/// // 🍎
146/// // </li>
147/// // </ol>
148/// // </div>
149/// // </section>
150/// }
151/// ```
152///
153/// - `lined`: produces HTML without indentation or line breaks (single-line output)
154/// - `btfy0`: uses 0 spaces (no indentation, minified output)
155/// - `btfy2`: uses 2 spaces indentation
156/// - `btfy4`: uses 4 spaces indentation
157pub mod rules;
158
159/// Returns the character at the specified 1-based index `n` from the input string `s`.
160///
161/// If `n` exceeds the number of characters in `s`, the function returns an empty string.
162///
163/// # Arguments
164///
165/// * `s` - A string slice from which to extract a character.
166/// * `n` - The 1-based position of the character to retrieve.
167///
168/// # Examples
169///
170/// ```rust
171/// use forge_rsx::get_char;
172/// let s = "Hello, forge-rsx!";
173/// assert_eq!(get_char(s, 0), ""); // Out of bounds, returns empty
174/// assert_eq!(get_char(s, 1), "H"); // First character
175/// assert_eq!(get_char(s, 50), ""); // Out of bounds, returns empty
176/// ```
177///
178/// Note: `n` starts at 1 for the first character.
179pub fn get_char(s: &str, index: usize) -> String {
180 if index == 0 || index > s.chars().count() {
181 "".to_string()
182 } else {
183 // Convert 1-based index to 0-based
184 let char_index = index - 1;
185 // Get the char at the position
186 s.chars().nth(char_index).unwrap().to_string()
187 }
188}