# Loom

A simple and very flexible Python template engine heavily inspired by [Laravel Blade](https://laravel.com/docs/12.x/blade).

Do not use in production. Just for fun, for now.

Contrary to other languages like jinja, it allows executing any Python code within the template. Therefore, this should **not** be used for templates that can be written by external users (prefer something like jinja for this).

## Installation

```bash
pip install crya-loom
```

## Usage

### Basic Template Rendering

**Render from file:**
```python
from pathlib import Path
from crya_loom import render

# Render a template file with context
output = render(Path("templates/index.loom"), {
    "title": "Welcome",
    "users": ["Alice", "Bob", "Charlie"]
})
```

**Render from string:**
```python
from crya_loom import render_from_string

template = """
<h1>{{ title }}</h1>
@for(user in users)
    <p>{{ user }}</p>
@endfor
"""

output = render_from_string(template, {
    "title": "Users",
    "users": ["Alice", "Bob"]
})
```

### Configuration

**Component base directory:**
```python
from crya_loom import set_component_base_dir

# Set custom component directory (default: "components")
set_component_base_dir("templates/components")
```

**Cache directory:**
```python
from crya_loom import set_cache_dir

# Set custom cache directory (default: "cache/compiled/templates")
set_cache_dir("tmp/loom_cache")
```

**Template directory:**
Templates are not tied to a specific directory. Simply pass the full path to `render()`:
```python
from pathlib import Path
from crya_loom import render

# Render templates from any location
output = render(Path("/path/to/my/templates/page.loom"), context)
```

## Syntax

### Comments

```
{{-- This is a comment --}}
```

Comments can be multiline:

```
{{-- This is a multiline comment
     that spans multiple lines --}}
```

### Print (escaped)

```
{{ user.name }}
```

### Unsafe print

```
{!! user.name !!}
```

### Condition

```
@if(time == "morning")
    <div>Good morning</div>
@elif(time == "afternoon")
    <div>Good afternoon</div>
@else
    <div>Good evening</div>
@endif
```

### Loops

```
@for(user in users)
    ...
@endfor
```

### Python blocks

```
@python
    my_var = "hello"
@endpython

{{ my_var }}
```

### Non interpreted text

```
@verbatim
    I like to use these characters in my book: "{{" and "}}".
@endverbatim
```

## Components

Create reusable components with `<x-component-name>` syntax.

### Basic Usage

1. Set component directory:
```python
from crya_loom import set_component_base_dir
set_component_base_dir("templates/components")
```

2. Create component file `templates/components/alert.loom`:
```html
<div class="alert alert-{{ type }}">
    {{ slot }}
</div>
```

3. Use in templates:
```html
<x-alert type="danger">Error message</x-alert>
```

### Nested Components

Use dot notation for subdirectories:
```html
<x-card.header title="Welcome">Subtitle</x-card.header>
```
Maps to `components/card/header.loom`

### Dynamic Attributes

Prefix with `:` to evaluate expressions:
```html
<x-alert :type="error_level" :message="error_msg" />
```

### Special Variables

Components receive:
- `slot` - Content between opening/closing tags
- `attributes` - Dict of all passed attributes
- All parent template variables (inherited context)
