Code

# Template Engine TourThis is a comprehensive guide to the Snippy template engine syntax. The template engine provides powerful text generation capabilities with variable substitution, conditionals, loops, expressions, and more.## Quick StartSnippy templates are plain text files with special syntax for dynamic content. The engine processes templates and produces final output by evaluating expressions and statements.### Basic Syntax OverviewThe template engine uses three types of delimiters:- `` - **Expressions**: Output values, variables, and calculations- `{% statement %}` - **Statements**: Control flow, variable assignment, and commands- `` - **Comments**: Documentation that doesn't appear in output## 1. Plain Text and CommentsTemplates can contain regular text that passes through unchanged:```Hello World!This is plain text.```Comments are ignored during processing:```Text before commentText after comment```**Output:**```Text before commentText after comment```## 2. Variables and Expressions### Variable OutputUse double braces to output variable values:```Hello !Welcome to .```With variables `name="Alice"` and `place="Wonderland"`:```Hello Alice!Welcome to Wonderland.```### Setting VariablesUse the `{% set %}` statement to define variables:```{% set name "John" %}{% set greeting "Hello" %} !```**Output:**```Hello John!```### Dot Notation for Namespaced VariablesVariables can have hierarchical names using dots:```{% set config.database.host "localhost" %}{% set config.database.port "5432" %}Database: :```**Output:**```Database: localhost:5432```### Clearing VariablesUse the `{% clear %}` statement to remove variables from memory:```{% set message "Hello World" %}{% set items.first "apple" %}{% set items.second "banana" %}Before clear: Items: , {% clear message %}{% clear items %}After clear: Items: , ```**Output:**```Before clear: Hello WorldItems: apple, bananaAfter clear:Items: ,```The clear statement can:- Clear individual variables: `{% clear variable_name %}`- Clear entire namespaces: `{% clear namespace %}` removes all variables starting with `namespace.`- Safely handle non-existent variables (no error if the variable doesn't exist)### Capture StatementThe `{% capture %}` statement allows you to capture template output within a specific scope and store it in a variable. This is useful for generating complex content that you want to reuse or process further.```{% set name "Alice" %}{% set count 3 %}{% capture greeting_message %}Hello ! You have  new messages.{% endcapture %}Generated message: {% set formatted_greeting "Message: " + greeting_message %}Final output: ```**Output:**```Generated message: Hello Alice! You have 3 new messages.That's quite a few!Final output: Message: Hello Alice! You have 3 new messages.That's quite a few!```The capture statement:- Captures all output (text, variables, expressions) within its scope- Stores the captured content in the specified variable- Can contain complex logic including conditionals, loops, and nested expressions- Preserves formatting and newlines from the captured content- Can be nested within other statements for advanced template composition## 3. Arithmetic and Expressions### Basic ArithmeticThe template engine supports standard mathematical operations with both integers and floating-point numbers:```Result: 8Product: 28Division: 5.0Subtraction: 8```**Output:**```Result: 8Product: 28Division: 5Subtraction: 8```### Float ArithmeticFloating-point numbers are fully supported in calculations:```Float result: 7.8Mixed: 13.14Division: 3.142857142857143Precision: 3.0```**Output:**```Float result: 7.8Mixed: 13.14Division: 3.14286Precision: 3.0```### Order of Operations and ParenthesesMathematical precedence is respected, and parentheses can override it:```Order of operations: 14With parentheses: 20Complex: 13Mixed operations: 17.0```**Output:**```Order of operations: 14With parentheses: 20Complex: 13Mixed operations: 17```### Type CastingConvert between numeric types using `int()`:```{% set value 42.7 %}Float value: Integer value: {{ int(value) }}Complex casting: {{ int((arg.a ?? 1.0) * 255) }}```**Output:**```Float value: 42.7Integer value: 42Complex casting: 255```## 4. String Operations### String ConcatenationUse the `~` operator for string concatenation (different from arithmetic `+`):```{% set first "Hello" %}{% set second "World" %} Literal concatenation```**Output:**```Hello WorldLiteral concatenation```**String Concatenation vs Addition:**```{% set str1 "Hello" %}{% set str2 "World" %}Concatenation: Addition: {{ str1 + str2 }}```**Output:**```Concatenation: HelloWorldAddition: HelloWorld```Both `~` and `+` work for string concatenation, but `~` is explicitly for strings while `+` also handles arithmetic. Use `~` when you want to be explicit about string concatenation.**Complex Concatenation:**```  Result: 8 items```### String LiteralsStrings can be defined with double quotes:```This is a string literalStrings can contain spaces and symbols!```**Output:**```This is a string literalStrings can contain spaces and symbols!```## 5. Null CoalescingUse `??` to provide fallback values for undefined variables:```Default: {{ missing ?? "fallback value" }}Found: {{ name ?? "no name" }}```With variable `name="Alice"` (and `missing` undefined):```Default: fallback valueFound: Alice```Complex null coalescing with expressions:```Complex: {{ (arg.a ?? 1.0) * 255 }}```## 6. Ternary OperatorUse the ternary operator `condition ? true_value : false_value` for conditional expressions:```{% set status "active" %}{% set name "World" %}{% set priority "" %}Status check: {{ status ? "enabled" : "disabled" }}Greeting: {{ name ? "Hello " ~ name : "Anonymous user" }}Priority level: {{ priority ? priority : "normal" }}```**Output:**```Status check: enabledGreeting: Hello WorldPriority level: normal```### Ternary with FiltersCombine ternary operators with filters for powerful conditional transformations:```{% set name "world" %}{% set status "active" %}{% set missing "" %}With filters on true branch: {{ name ? name|upper : "unknown" }}With filters on false branch: {{ missing ? "found" : "not found"|upper }}With filters on both branches: {{ status ? "active"|upper : "inactive"|lower }}```**Output:**```With filters on true branch: WORLDWith filters on false branch: NOT FOUNDWith filters on both branches: ACTIVE```### Nested Ternary ExpressionsTernary operators can be nested for complex conditional logic:```{% set priority "high" %}{% set level "medium" %}Nested ternary: {{ priority ? priority|upper : level ? level|lower : "none" }}```**Output:**```Nested ternary: HIGH```## 7. Filters and PipesApply transformations to values using the pipe operator `|`:```{% set name "hello world" %}Uppercase: Lowercase: Chain filters: MIXED CASE```**Output:**```Uppercase: HELLO WORLDLowercase: hello worldChain filters: MIXED CASE```Available filters:- `upper` - Convert to uppercase- `lower` - Convert to lowercase- `escape` - Convert special characters to escaped quoted string- `quote` - Wrap in quotes and escape internal quotes/backslashes- `join` - Join list elements with a separator### Escape FilterThe `escape` filter converts strings with special characters into quoted strings with proper escape sequences:```{% set message "Line 1Line 2" %}{% set tab_text "before	after" %}{% set quote_text "She said \"hello\"" %}Escaped newline: Escaped tab: Escaped quotes: ```**Output:**```Escaped newline: "Line 1\nLine 2"Escaped tab: "before\tafter"Escaped quotes: "She said \"hello\""```The escape filter handles:- `\n` - Newline characters- `\t` - Tab characters- `\r` - Carriage return characters- `\"` - Double quote characters- `\\` - Backslash characters- `\0` - Null charactersThe output is always wrapped in double quotes, making it suitable for generating code or configuration files.### Quote FilterThe `quote` filter wraps strings in double quotes and escapes internal quotes and backslashes:```{% set simple "test" %}{% set with_quote "test\"test" %}{% set with_backslash "test\\test" %}Simple: {{ simple | quote }}With quote: {{ with_quote | quote }}With backslash: {{ with_backslash | quote }}Literal: {{ "hello" | quote }}```**Output:**```Simple: "test"With quote: "test\"test"With backslash: "test\\test"Literal: "hello"```### Join FilterThe `join` filter combines list elements into a single string with a specified separator:```{% set keys ["KEY_A", "KEY_B", "KEY_X"] %}Combined: Comma separated: No separator: ```**Output:**```Combined: KEY_A | KEY_B | KEY_XComma separated: KEY_A, KEY_B, KEY_XNo separator: KEY_AKEY_BKEY_X```**Filter Chaining:**Filters can be chained and work with string literals, variables, or complex expressions:```{% set name "John" %}{% set greeting "Hello" %}Basic variable: Chained filters: MIXEDExpression with filter:  worldMultiple chains: TEST```**Output:**```Basic variable: JOHNChained filters: MIXEDExpression with filter: hello worldMultiple chains: TEST```## 8. Conditional Logic### Basic ConditionalsUse `{% if %}` statements for conditional content:``````With variable `enabled="true"` (and `disabled` undefined):```Feature is enabled!```### If-Elif-Else ChainsComplex conditional logic with multiple branches:```{% if var1 %}Variable 1 is set{% elif var2 %}Variable 2 is set{% else %}No variables set{% end %}```Variables are considered "truthy" if they exist and have a non-empty value.### Comparison OperatorsUse comparison operators to create more sophisticated conditions:```{% if status == "active" %}User is active{% endif %}{% if count != 0 %}Has items{% endif %}{% if priority > 5 %}High priority{% endif %}{% if score >= 90 %}Excellent score{% endif %}{% if temperature < 32 %}Below freezing{% endif %}{% if age <= 18 %}Minor{% endif %}```Available comparison operators:- `==` - Equal to- `!=` - Not equal to- `>` - Greater than- `>=` - Greater than or equal to- `<` - Less than- `<=` - Less than or equal toComparisons work with both numbers and strings:```{% if version == "2.0" %}Version 2.0{% endif %}{% if count > 10 %}Many items{% endif %}```Numeric comparisons are performed when both sides are numbers, otherwise string comparison is used.### Logical OperatorsCombine multiple conditions using logical operators:#### AND OperatorUse `and` to require all conditions to be true:```{% set enabled "true" %}{% set valid "true" %}{% set status "active" %}{% if enabled and valid %}Both enabled and valid{% endif %}{% if enabled and valid and status %}All three conditions are true{% endif %}```**Output:**```Both enabled and validAll three conditions are true```#### OR OperatorUse `or` when any condition being true is sufficient:```{% set admin "false" %}{% set moderator "true" %}{% set owner "" %}{% if admin or moderator %}User has privileges{% endif %}{% if admin or moderator or owner %}User has some level of access{% endif %}```**Output:**```User has privilegesUser has some level of access```#### Combining AND and ORUse parentheses to group logical operations:```{% set user_active "true" %}{% set is_admin "false" %}{% set is_moderator "true" %}{% set has_permission "true" %}{% if user_active and (is_admin or is_moderator) %}Active user with elevated privileges{% endif %}{% if (is_admin or is_moderator) and has_permission %}Privileged user with permissions{% endif %}```**Output:**```Active user with elevated privilegesPrivileged user with permissions```#### Complex Logical ExpressionsLogical operators work with any expressions, including comparisons:```{% set score 85 %}{% set bonus_points 10 %}{% set is_member "true" %}{% if (score > 80) and (bonus_points > 5) %}High score with bonus{% endif %}{% if (score < 60) or (is_member and bonus_points > 0) %}Either low score or member with bonus{% endif %}```**Output:**```High score with bonusEither low score or member with bonus```Logical operators follow standard precedence:- `and` has higher precedence than `or`- Use parentheses to override precedence when needed- Both operators are left-associative (evaluated left to right)### Comparison with ExpressionsComparison operators can be combined with arithmetic and other expressions:```{% if (count + 1) == 6 %}Count plus one equals six{% endif %}{% if items.length > 0 %}Has items{% endif %}{% if (value * 2) <= 100 %}Doubled value is 100 or less{% endif %}```### Conditional Syntax VariationsBoth `{% endif %}` and `{% end %}` can close conditional blocks:```{% if condition %}Content here{% end %}```## 9. Loops### Basic LoopsRepeat content a specific number of times:```{% loop 3 %}Hello World!{% end %}```**Output:**```Hello World!Hello World!Hello World!```### Variable-Driven LoopsUse variables to control loop count:```{% set iterations "5" %}{% loop iterations %}Iteration{% end %}```### Foreach LoopsIterate over namespaced variables:```{% set items.one "first" %}{% set items.two "second" %}{% set items.three "third" %}{% foreach items %}Key: , Value: {% end %}```**Output:**```Key: one, Value: firstKey: two, Value: secondKey: three, Value: third```In `{% foreach %}` loops:- `` contains the variable suffix (after the dot)- `` contains the variable's value### Nested ForeachHandle multiple namespaced variable sets:```{% set users.alice "admin" %}{% set users.bob "user" %}{% set products.laptop "$999" %}{% set products.mouse "$25" %}Users:{% foreach users %}: {% end %}Products:{% foreach products %}: ${% end %}```## 10. Lists### Basic List CreationCreate ordered lists using square bracket syntax:```{% set fruits ["apple", "banana", "cherry"] %}First fruit: {{ fruits.0 }}Second fruit: {{ fruits.1 }}Third fruit: {{ fruits.2 }}```**Output:**```First fruit: appleSecond fruit: bananaThird fruit: cherry```Lists are zero-indexed, so the first element is accessed with `.0`, second with `.1`, etc.### Mixed Data Types in ListsLists can contain different types of values including variables, numbers, and strings:```{% set mixed [var0, 1, 2, "string"] %}Index 0: {{ mixed.0 }}Index 1: {{ mixed.1 }}Index 2: {{ mixed.2 }}Index 3: {{ mixed.3 }}```With variable `var0="default_value"`:```Index 0: default_valueIndex 1: 1Index 2: 2Index 3: string```### Lists with ExpressionsList elements can be complex expressions:```{% set numbers [1, 2, 3, 4, 5] %}{% set expressions [1 + 2, 4 * 2, 10 / 2] %}First number: {{ numbers.0 }}Calculated result: {{ expressions.1 }}```**Output:**```First number: 1Calculated result: 8```### Iterating Over Lists with ForeachLists work seamlessly with `{% foreach %}` loops:```{% set items ["first", "second", "third"] %}{% foreach items %}Item : {% end %}```**Output:**```Item 0: firstItem 1: secondItem 2: third```In list iteration:- `` contains the numeric index (0, 1, 2, ...)- `` contains the list element value### Empty ListsEmpty lists can be created and handled gracefully:```{% set empty_list [] %}Before foreach{% foreach empty_list %}This will not appear{% end %}After foreach```**Output:**```Before foreachAfter foreach```### Comprehensive List ExampleCombining multiple list features:```{% set numbers [1, 2, 3, 4, 5] %}{% set expressions [1 + 2, 4 * 2, 10 / 2] %}Numbers:{% foreach numbers %}: {% end %}Expressions:{% foreach expressions %}: {% end %}Direct access: {{ numbers.0 }}, {{ expressions.1 }}```**Output:**```Numbers:0: 11: 22: 33: 44: 5Expressions:0: 31: 82: 5Direct access: 1, 8```## 11. Dictionaries and ObjectsCreate key-value structures using dictionary syntax:```{% set config { host: "localhost", port: 8080, name: "MyApp" } %}Server: :Application: ```**Output:**```Server: localhost:8080Application: MyApp```Dictionary values can be strings, numbers, or variables:```{% set debug true %}{% set settings {  environment: "development",  debug_mode: debug,  max_users: 100,  version: 1.2} %}Environment: Debug: Max users: ```## 12. List Operations### Append List StatementAdd items to existing lists using `{% append_list %}`:```{% set keys [] %}{% if arg.a %}{% append_list keys "KEY_A" %}{% endif %}{% if arg.b %}{% append_list keys "KEY_B" %}{% endif %}{% if arg.x %}{% append_list keys "KEY_X" %}{% endif %}{% if keys.0 %}Keys found: {{ keys | join(", ") }}{% endif %}```With variables `arg.a=true`, `arg.b=false`, `arg.x=true`:```Keys found: KEY_A, KEY_X```The `append_list` statement dynamically adds elements to lists, making it useful for conditional list building.### Append Unique Sub StatementAdd content to a variable only if it doesn't already exist using `{% append_unique_sub %}`:```{% set list "item1" %}{% append_unique_sub list "item2" %}{% append_unique_sub list "item1" %}{% append_unique_sub list "item3" %}List: ```**Output:**```List: item1item2item3```The `append_unique_sub` statement checks if the content already exists in the variable before appending it, preventing duplicates. This is useful for building strings where repeated content should be avoided.### List with Join Filter in PracticeCombining list operations with filters for real-world use cases:```{% set buttons [] %}{% if show_save %}{% append_list buttons "SAVE" %}{% endif %}{% if show_cancel %}{% append_list buttons "CANCEL" %}{% endif %}{% if show_help %}{% append_list buttons "HELP" %}{% endif %}{% if buttons.0 %}if (userInput & ({{ buttons | join(" | ") }})) {    handleButtonPress();}{% endif %}```## 13. Unique Line ProcessingRemove duplicate lines from content blocks:```{% unique_line %}line1line2line1line3line2{% end %}```**Output:**```line1line2line3```This is useful for generating lists where duplicates should be eliminated.## 14. AttachmentsLoad external content into variables using the attachment system:```Before attachment{% attachment "test_attachment" content %}After attachment```The attachment identifier (`"test_attachment"`) is resolved by the application's attachment resolver, which loads the content into the specified variable (`content`).## 15. MacrosThe macro system allows you to define reusable template fragments with parameters. Macros help reduce duplication and create modular, maintainable templates.### Basic Macro DefinitionDefine a macro using ``:```{{ banner() }}```**Output:**```banner motd ^===========================================|   This device is property of BigCorpCo  ||   Unauthorized access is unauthorized   ||  Unless you're authorized to access it  ||  In which case play nice and stay safe  |===========================================^```### Macros with ParametersMacros can accept parameters to make them more flexible:```{{ def_if_desc("Home Computer") }}{{ def_if_desc("Server") }}```**Output:**```Unused port, dedicated to Home Computer devicesUnused port, dedicated to Server devices```### Multiple ParametersMacros support multiple parameters separated by commas:```{{ user_info("jdoe", "Senior Developer", "Engineering") }}```**Output:**```User: jdoeRole: Senior DeveloperDepartment: Engineering```### Macros with LogicMacros can contain any template constructs including conditionals and expressions:```{{ format_status("Server Down", "high") }}{{ format_status("Maintenance", "medium") }}{{ format_status("All Good", "low") }}```**Output:**```🔴 HIGH: Server Down🟡 MEDIUM: Maintenance🟢 All Good```### Nested Macro CallsMacros can call other macros:```{{ employee_badge("E001", "John", "Doe", "IT") }}```**Output:**```ID: E001Name: John DoeDepartment: IT```### Network Configuration Example```{{ vlan_config("100", "USERS", "255.255.255.0", "192.168.100.1") }}{{ vlan_config("200", "SERVERS", "255.255.255.0", "192.168.200.1") }}```**Output:**```vlan 100 name USERS!interface vlan100 ip address 192.168.100.1 255.255.255.0 no shutdownvlan 200 name SERVERS!interface vlan200 ip address 192.168.200.1 255.255.255.0 no shutdown```### Whitespace ControlUse `{%-` and `-%}` to control whitespace in macro output:```Items: {{ compact_list("apple", "banana", "cherry") }}```**Output:**```Items: apple, banana, cherry```### Macro Best Practices1. **Use descriptive names**: `create_user_card()` instead of `card()`2. **Keep macros focused**: One responsibility per macro3. **Document parameters**: Use clear parameter names4. **Handle edge cases**: Check for empty or missing parameters5. **Use whitespace control**: Manage output formatting with `{%-` and `-%}`## 16. Advanced Expression Examples### Complex ExpressionsCombine multiple features in sophisticated expressions:```Basic parentheses: 20Nested parentheses: 13Multiple parentheses levels: 50Complex null coalescing: {{ (missing.value ?? 2.5) * (factor ?? 10) }}Type casting: {{ int((arg.a ?? 1.0) * 255) }}Mixed operators with casting: {{ int((value ?? 3.14) * 100 + (offset ?? 0)) }}Deeply nested: {{ (((a ?? 1) + (b ?? 2)) * ((c ?? 3) + (d ?? 4))) / 2 }}Division with parentheses: {{ (numerator ?? 100) / (denominator ?? 4) }}Null coalescing with zero: {{ (zero_value ?? 42) + 10 }}```**Output (with sample variables):**```Basic parentheses: 20Nested parentheses: 13Multiple parentheses levels: 50Complex null coalescing: 25.0Type casting: 255Mixed operators with casting: 314Deeply nested: 12Division with parentheses: 25Null coalescing with zero: 52```### String and Arithmetic MixingCombine string concatenation with arithmetic:```{% set a "10" %}{% set b "3" %}String concat: {{ "Value: " ~ (a + b) }}Mixed operations: {{ "Result: " ~ ((a * 2) + b) ~ " units" }}```## 17. Error Handling and Edge Cases### Empty TemplatesEmpty templates produce empty output:```(empty file)```**Output:**```(empty output)```### Undefined VariablesUndefined variables in expressions evaluate to empty strings or zero in arithmetic contexts:```Undefined in text: Undefined in arithmetic: {{ undefined_var + 5 }}With null coalescing: {{ undefined_var ?? "default" }}```**Output:**```Undefined in text:Undefined in arithmetic: 5With null coalescing: default```### Conditional Edge CasesVariables are considered false if:- They are undefined- They are empty strings- They contain only whitespace```Non-empty string is true```## 18. Best Practices### Variable Naming- Use descriptive names: `config.database.host` instead of `h`- Use dots for hierarchical organization: `user.profile.name`- Keep names readable: `max_items` instead of `mi`### Template Organization- Use comments to document complex logic- Break complex expressions into multiple variables- Group related variable assignments### Performance Considerations- Minimize deep nesting in expressions- Use null coalescing for optional variables- Prefer simple conditionals over complex boolean logic- Use ternary operators for simple conditional values### Example: Well-Structured Template```{% set config.server.host "0.0.0.0" %}{% set config.server.port "8080" %}{% set config.database.enabled "true" %}{% set config.database.host "localhost" %}{% set config.database.port "5432" %}# Server ConfigurationHost: Port: {% if env ?? "development" %}Debug Mode: EnabledLog Level: Debug{% else %}Debug Mode: DisabledLog Level: Info{% endif %}```

Comments

No comments yet. Be the first!