Include Extension
The IncludeExtension is the core extension of gtext that enables including content from multiple sources.
Overview
The Include Extension processes \``include` code blocks and replaces them with content from:
- Static files: Include file content
- CLI commands: Execute commands and include output
- Glob patterns: Include multiple files matching a pattern
Syntax
Each line can use the following format:
Protocols
static:- Include static files (default if no protocol specified)cli:- Execute shell commandsglob:- Include multiple files matching a pattern
Modifiers
:expand:- Recursively process included content for nested\``include` blocks
Examples
# Basic protocols
```include
static: file.md # Static file (explicit)
file.md # Static file (implicit)
cli: date # Execute command
glob: docs/*.md # Glob pattern
```
# With expand modifier
```include
:expand:static: template.gtext # Include and recursively expand
:expand:cli: generate_doc.sh # Execute and expand output
```
Static File Includes
Basic Usage
Includes the entire content of the specified file.
Relative Paths
Paths are relative to the location of the .gtext file:
In docs/main.md.gtext:
Absolute Paths
You can also use absolute paths:
Multiple Files
Include multiple files sequentially:
Files are included in the order specified.
CLI Command Includes
Basic Usage
Executes date command and includes its output.
Command with Arguments
Shell Features
Commands support full shell syntax:
Python Scripts
Complex Commands
For complex operations, create a script:
Command Features
- Shell: Commands run with
shell=True(bash/sh syntax supported) - Working Directory: Commands execute in the current working directory
- Timeout: 30-second timeout (commands that run longer will fail)
- Output: Only
stdoutis captured (stderr is ignored)
Error Handling
If a command fails, an error comment is included:
Glob Pattern Includes
Basic Usage
Includes all .md files in the docs/ directory.
Recursive Patterns
Use ** for recursive matching:
Includes all .md files in docs/ and all subdirectories.
Pattern Syntax
*- Matches any characters except/**- Matches any characters including/(recursive)?- Matches a single character[abc]- Matches one character from the set[!abc]- Matches one character NOT in the set
Examples
# All Python files in src/
```include
glob: src/**/*.py
```
# Specific naming pattern
```include
glob: reports/2024-*.md
```
# Multiple extensions
```include
glob: docs/**/*.{md,txt}
```
File Order
Files are included in sorted order by their full path.
No Matches
If no files match, a warning is included:
Mixing Include Types
You can mix all three types in a single block:
Processing order:
1. header.md - included
2. get_version.py - executed and output included
3. All files matching sections/*.md - included in sorted order
4. date - executed and output included
5. footer.md - included
The :expand: Modifier
Overview
By default, when you include a file that contains \``include` blocks, those blocks are not processed - they remain as source code in the output.
The :expand: modifier changes this behavior by recursively processing the included content, expanding all nested \``include` blocks.
Use Cases
Show Source (default behavior):
If template.gtext contains:
Output will show the source:
Expand Content (with :expand: modifier):
Output will show expanded content:
Syntax
The :expand: modifier is placed before the protocol:
Examples
Static Files
# Include template as source
```include
static: template.gtext
```
# Include and expand template
```include
:expand:static: template.gtext
```
CLI Commands
# Execute script, include output as-is
```include
cli: python generate_doc.py
```
# Execute script, expand any includes in output
```include
:expand:cli: python generate_doc.py
```
Glob Patterns
# Include all files, show source
```include
glob: templates/*.gtext
```
# Include and expand all files
```include
:expand:glob: templates/*.gtext
```
Multi-Level Expansion
The :expand: modifier works recursively across multiple nesting levels:
File hierarchy:
Usage:
All levels will be fully expanded until reaching static content or reaching the depth limit.
Depth Limit
To prevent infinite loops (e.g., circular includes), expansion is limited to 10 levels by default.
If the depth limit is exceeded, an error is inserted:
When to Use :expand:
| Use Case | Use :expand:? |
Reason |
|---|---|---|
| Include template with dynamic content | ✅ Yes | Need to execute CLI commands in template |
| Include code examples | ❌ No | Want to show source, not execute |
| Documentation with reusable sections | ✅ Yes | Each section may have includes |
| Configuration files | ❌ No | Usually want literal content |
| Generated reports | ✅ Yes | May contain nested data generation |
Performance Considerations
- Without
:expand:: Single pass, fast - With
:expand:: Multiple passes required, slower
Use :expand: only when necessary for recursive content generation.
Future Protocols (Planned)
The following protocols are planned for future versions and are not yet implemented. They are designed to integrate with the Genro CLI ecosystem.
storage: Protocol
Access files from mounted storage volumes managed by genro-cli:
How it works:
- genro-cli manages storage volumes (local/remote/cloud)
- storage:volume/path resolves to the actual mounted location
- Portable across machines - volume name stays the same even if mount point differs
Example:
app: Protocol
Access resources from published applications managed by genro-cli:
How it works:
- genro-cli publishes applications with REST/CLI interfaces
- app:appname/resource queries the app for content
- Apps can generate dynamic content on demand
Example:
# Include data from published app
```include
app:userdata/export/summary.json
```
# Execute app command and include output
```include
:expand:app:analytics/report
```
db: Protocol
Query databases registered with genro-cli:
How it works:
- genro-cli manages database connections
- db:dbname/query/name executes stored query
- Results formatted as markdown tables
Example:
Integration Pattern
All future protocols follow the same pattern:
- Register resource with
genro-cli(storage, app, or database) - Reference by name in gtext files
- genro-cli resolves the actual location/connection
- Portable - works across different machines/environments
Protocol Resolution
When gtext encounters storage:, app:, or db: protocols:
- Calls
genro-cli query <protocol> <resource> genro-clireturns the resolved path or content- Content is included normally
- Can be combined with
:expand:modifier
Benefits
- Portability: Volume names instead of absolute paths
- Abstraction: Access resources without knowing physical location
- Security: Controlled access through genro-cli
- Dynamic: Apps and databases provide live data
Timeline
These protocols will be implemented after genro-cli is released. Current work is focused on the core gtext functionality with static:, cli:, and glob: protocols.
Context and Paths
Path Resolution
- Static files: Relative to the
.gtextfile location - Glob patterns: Relative to the
.gtextfile location - CLI commands: Execute in the current working directory
Example
In docs/main.md.gtext:
```include
includes/header.md # Relative to main.md.gtext
cli: python ../scripts/gen.py # Relative to pwd
glob: includes/*.md # Relative to main.md.gtext
```
Error Handling
The Include Extension is designed to be fault-tolerant:
File Not Found
The build continues; error is shown in output.
Command Failure
Command Timeout
Read Error
Glob Error
Security Considerations
CLI Command Execution
⚠️ Important: CLI commands are executed with shell=True, which means:
- Trusted sources only: Only process
.gtextfiles from trusted sources - Shell injection risk: Malicious
.gtextfiles can execute arbitrary commands - No sandboxing: Commands have full access to your system
Future: Safe Mode
Future versions may include a --safe-mode flag that:
- Disables CLI command execution
- Restricts file access to specific directories
- Validates glob patterns
Performance Considerations
File Includes
Fast - files are read directly.
CLI Commands
Can be slow: - Command startup overhead - Network operations - Long-running scripts
Consider: - Caching results - Pre-generating data - Using static files instead
Glob Patterns
Can be slow with: - Large directory trees - Network file systems - Many matching files
Best Practices
1. Prefer Static Files
# Fast and reliable
```include
data.md
```
# Slower, depends on script
```include
cli: python generate_data.py
```
2. Keep Commands Simple
# Good
```include
cli: date
cli: git rev-parse HEAD
```
# Complex - move to script
```include
cli: bash scripts/complex_operation.sh
```
3. Use Descriptive File Names
4. Organize Glob Patterns
# Clear and specific
```include
glob: chapters/chapter-*.md
```
# Too broad
```include
glob: **/*.md
```
5. Handle Errors Gracefully
Check generated output for error comments:
Configuration
Current Configuration Options
Via context dictionary when processing:
max_include_depth: Maximum recursion depth for:expand:(default: 10)input_path: Path to the input file for relative path resolution
Future Configuration Options
Future versions may add:
timeout: Customize command timeout (currently 30 seconds)safe_mode: Disable CLI execution entirelyallowed_commands: Whitelist for CLI commandsallowed_paths: Restrict file access to specific directories
Examples
See Examples for real-world usage patterns.
Next Steps
- Learn about Custom Extensions
- See Extension System
- Read API Reference