<p align="center">
<img src="static/img/colap-logo.svg" alt="Cola-p Logo" width="500">
</p>
# π₯€ colap β A Refreshingly Simple Configuration Language Parser & Code Generator
---
Tired of fighting with your config files? So were we.
**cola** is a lightweight, human-friendly configuration language designed to avoid YAMLβs whitespace traps, JSONβs curly-brace fatigue, and TOMLβs dotted-key spaghetti. Itβs backed by [`colap`](https://crates.io/crates/colap), a Rust parser and code generator that makes working with configurations effortless.
Cola is:
β
**Readable** β Clean nesting with minimal punctuation.\
β
**Writable** β No indentation anxiety. No trailing comma drama.\
β
**Composable** β Works standalone or embedded in Markdown as fenced `cola ... ` blocks.
---
## π Why cola?
### YAML: Tabs vs Spaces
Miss one indent, and your app silently loads nonsense.
### JSON: Curly Braces Forever
Nested configs turn into a forest of `{}` and `[]`.
### TOML: Dotted-Key Spaghetti
Deep nesting forces verbose dotted keys or confusing table headers.
### cola: Refreshingly Simple
- π **Not whitespace sensitive** β Tabs? Spaces? Mix them. Cola doesnβt care.
- β
**Minimal punctuation** β Just `:` for nesting and `;` to end blocks.
- π·οΈ **Infix plural syntax** β Explicitly name singular and plural forms for code generators.
- π **Markdown-native** β Embed configs directly in documentation.
---
## π Example Configuration
Here's a real-world configuration defining multiple LLM providers:
```cola
llm plural llms:
openai:
api:
type: "REST",
key: "some_api_key",
base_url: "some_base_url"
;
model plural models:
gpt-4.1:
name: "gpt-4.1",
max_input_tokens: 1048576,
output_price: 8.0,
supports_vision: true
;
gpt-4o:
name: "gpt-4o",
max_input_tokens: 1048576,
output_price: 8.0,
supports_vision: true
;
;
;
;
```
---
## π cola vs YAML / JSON / TOML
| Whitespace sensitivity | π¬ Yes | π No | π No | β
No |
| Curly brace clutter | π Minimal | π© Lots | π Minimal | β
Minimal |
| Trailing commas allowed | β No | β No | β
Yes | β
Yes |
| Multi-line strings | π€ Hard | π Escapes | β
Easy | β
Easy |
| Collections (arrays/maps) | π Indents | π© `[]`, `{}` | π Mixed | β
Infix `plural` |
| Markdown embedding | β Awkward | β Awkward | β Awkward | β
First-class |
---
## π― Design Philosophy
### πΉ Why Semicolons?
Cola uses `;` as a block terminator:
- Prevents ambiguity at the end of nested blocks.
- Avoids silent parsing errors from missing indentation (YAML) or commas (JSON).
- Familiar and clear for both humans and parsers.
---
### πΉ Why Infix `plural`?
```cola
model plural models:
gpt-4:
name: "gpt-4"
;
gpt-4o:
name: "gpt-4o"
;
;
```
- Makes singular and plural forms **explicit** in configuration.
- Eliminates brittle βadd an `s`β heuristics in code generation.
- Supports irregular plurals (e.g. `person plural people`).
- Improves clarity: developers instantly know single vs multiple semantics.
---
## π§ Features
### Parser
- Parses standalone `.cola` files and Markdown files with embedded cola blocks
- Produces structured configuration models
### Code Generator
- Generates idiomatic Rust structs and collections (`HashMap`) from cola models
- Handles plural entities clearly
- Renames Rust keywords (e.g., `type` to `type_`)
- Provides constructors and accessor methods for easy integration
---
## π¦ Installation
Add `colap` to your Rust project:
```toml
[dependencies]
colap = "0.1"
```
---
## π Codebase Structure
The colap codebase is organized into the following modules:
- `parser`: Handles parsing of Cola syntax using rustemo
- `cola.rs`: Generated parser code
- `cola_actions.rs`: Parser actions
- `model`: Contains the configuration model definitions
- `config_model.rs`: Core configuration model and node types
- `model_builder.rs`: Builds config model from parsed AST
- `source_location.rs`: Source location tracking
- `generator`: Code generation for Rust structs
- `generator_impl.rs`: Main code generator implementation
- `templates/`: Handlebars templates for code generation
- `grammar`: Contains the rustemo grammar definition
- `cola.rustemo`: Grammar rules for the Cola language
---
## π© Usage
### Command Line Interface
```bash
USAGE:
colap [OPTIONS] <input>
ARGS:
<input> Input .cola file or markdown containing Cola code blocks
OPTIONS:
-h, --help Print help information
-m, --mode <MODE> Generation mode: 'crate' or 'module' (default: crate)
-n, --crate-name <NAME> Name of the generated library crate (default: input-file-stem-config)
-o, --output <DIR> Base output directory (default: generated)
-V, --version Print version information
```
### Examples
#### Basic Crate Generation (Default)
Generate a complete Rust crate from a cola file:
```sh
colap path/to/myconfig.cola
```
This will:
1. Parse `myconfig.cola`
2. Generate code in the directory `generated/myconfig-config/`
3. Create a complete library crate with:
- `Cargo.toml` with dependencies
- `src/lib.rs` with generated structs
- `tests/integration.rs` with integration tests
- `README.md` with usage documentation
#### Module Generation
Generate a single Rust module file for embedding in your project:
```bash
colap path/to/myconfig.cola --mode module -o src -n config_parser
```
This will:
1. Parse `myconfig.cola`
2. Generate a single file `src/config_parser.rs`
3. Include inline unit tests within the module
4. Ready to be imported with `mod config_parser;` in your project
#### Custom crate name and output directory
```bash
colap path/to/myconfig.cola --crate-name my-custom-config --output custom/output/dir
```
This will:
1. Parse `myconfig.cola`
2. Generate code in the directory `custom/output/dir/my-custom-config/`
3. Create a library crate with generated structs in `custom/output/dir/my-custom-config/lib.rs`
## Code Generation Details
The code generator produces:
1. Rust structs for each entity type in the configuration
2. Collection structs (using `HashMap`) for plural entities
3. Accessor methods to retrieve fields and collections
4. Constructors for each entity type
5. Integration tests for validating parsing functionality
### Generated Code Structure
For a configuration file with entities like `Root`, `Llm`, and `Model`, the generator produces:
```rust
// Root entity struct
pub struct Root {
llm: Llm,
// other fields...
}
// Singular entity
pub struct Llm {
provider: String,
models: Models, // plural entity reference
// other fields...
}
// Plural entity (collection)
pub struct Models {
entries: HashMap<String, Model>,
}
// Entity in a collection
pub struct Model {
name: String,
context_window: i64,
// other fields...
}
```
### Type Handling
The generator maps Cola types to Rust types as follows:
| String | `String` |
| Integer | `i64` |
| Float | `f64` |
| Boolean | `bool` |
| Entity | Custom struct |
| Optional Entity | `Option<CustomStruct>` |
### Default Crate Name
If the `--crate-name` option is not provided, the crate name is derived from the input file:
1. Take the file stem (filename without extension)
2. Replace underscores with hyphens
3. Convert to lowercase
4. Append `-config` suffix
For example:
- `my_config.cola` β `my-config-config`
- `API_Model.md` β `api-model-config`
## Using the Generated Code
### Loading and Parsing a Configuration File
The generated code includes integration tests that demonstrate how to parse configuration files:
```rust
use colap::cola::ColaParser;
use colap::model_builder::ModelBuilder;
use my_config::Root; // Generated crate name
// Load and parse a configuration file
fn parse_config_file(path: &str) -> Root {
// Read the file content
let content = std::fs::read_to_string(path).expect("Failed to read config file");
// Create a parser and parse the content
let parser = ColaParser::new();
let result = parser.parse(&content).expect("Failed to parse configuration");
// Build the configuration model
let model = ModelBuilder::build_config_model(&result).expect("Failed to build config model");
// Create the root entity from the model
Root::from_model(&model)
}
// Usage example
let config = parse_config_file("path/to/config.md");
```
### Accessing Configuration Values
The generated code provides accessor methods for retrieving values:
```rust
// Get the LLM configuration
let llm = config.llm();
// Access a singular entity's properties
let provider = llm.provider(); // Returns a &String
// Access a collection (plural entity)
let models = llm.models();
// Get a specific model from the collection
if let Some(gpt4) = models.get("gpt-4.1") {
let context_window = gpt4.context_window(); // Returns an i64
println!("GPT-4.1 context window: {}", context_window);
}
// Iterate through all models
for (name, model) in models.iter() {
println!("Model: {}, Context: {}", name, model.context_window());
}
```
### Optional Fields
Optional fields are represented as `Option<T>` types:
```rust
// Optional field access with safe pattern matching
if let Some(api) = llm.api() {
if let Some(key) = api.key() {
println!("API Key: {}", key);
}
}
// Using map() for clean optional chaining
### π Embedded Markdown Support
Colap parses configurations directly from Markdown. Any fenced block marked \`\`\`cola is automatically parsed, supporting documentation-driven development.
---
## π License
This project is licensed under the [Apache License 2.0](LICENSE).
Copyright 2025 Aivolution GmbH
---