# syntaxfmt
[](https://crates.io/crates/syntaxfmt)
[](LICENSE-MIT)
[](LICENSE-APACHE)
A derive macro-based library for flexible syntax tree formatting with pretty printing support.
`syntaxfmt` provides a trait and builder based approach to formatting syntax trees with both compact and pretty-printed output modes. It's designed for compiler frontends, code generators, and any application that needs to format structured data as text with dynamic formatting.
## Features
- **Derive Macro** - Automatic implementation via `#[derive(SyntaxFmt)]`
- **Flexible Decorations** - Add prefixes, suffixes, and collection delimiters
- **Modal Formatting** - Customise formatting output for different modes, normal and pretty
- **Automatic Layout** - Automated layout control with newlines and indentation
- **Content Replacement** - Override field formatting with literals or custom functions
- **Conditional Formatting** - Format based on arbitrary boolean expressions, with else support
- **Stateful Formatting** - Pass mutable or immutable state for context-aware output
## Cargo Features
- **`derive`** (enabled by default) - Enables the `SyntaxFmt` derive macro
## Getting Started
Add `syntaxfmt` to your `Cargo.toml`:
```toml
[dependencies]
syntaxfmt = "0.2.2"
```
### Quick Start
The simplest use case is to derive `SyntaxFmt` on your types and they'll format themselves by printing each field in order:
```rust
use syntaxfmt::{SyntaxFmt, syntax_fmt};
#[derive(SyntaxFmt)]
struct BinaryOp<'src> {
left: &'src str,
op: &'src str,
right: &'src str,
}
let expr = BinaryOp { left: "x", op: "+", right: "y" };
assert_eq!(format!("{}", syntax_fmt(&expr)), "x+y");
```
### Adding Decorations
Use `pre` (prefix) and `suf` (suffix) attributes to add syntax around fields:
```rust
use syntaxfmt::{SyntaxFmt, syntax_fmt};
#[derive(SyntaxFmt)]
#[syntax(pre = "let ", suf = ";")]
struct LetStatement<'src> {
name: &'src str,
#[syntax(pre = " = ")]
value: &'src str,
}
let stmt = LetStatement { name: "x", value: "42" };
assert_eq!(format!("{}", syntax_fmt(&stmt)), "let x = 42;");
```
### Basic Pretty Printing
Enable pretty printing with the `.pretty()` method. Use modal attributes (arrays) to specify different formatting for normal vs pretty mode:
```rust
use syntaxfmt::{SyntaxFmt, syntax_fmt};
#[derive(SyntaxFmt)]
struct FunctionCall<'src> {
name: &'src str,
#[syntax(pre = ["(", "( "], suf = [")", " )"], delim = [", ", ", "])]
args: Vec<&'src str>,
}
let call = FunctionCall {
name: "max",
args: vec!["x", "y", "z"],
};
assert_eq!(format!("{}", syntax_fmt(&call)), "max(x, y, z)");
assert_eq!(format!("{}", syntax_fmt(&call).pretty()), "max( x, y, z )");
```
More advanced pretty printing is available via [Indentation and Layout](https://docs.rs/syntaxfmt/latest/syntaxfmt/#indentation-and-layout).
### Further Reading and More Examples
For complete documentation including many more examples, visit [docs.rs/syntaxfmt](https://docs.rs/syntaxfmt).
## Attribute Summary
Attributes can be applied at the type, field, or `syntax_else` level.
| `pre` | Text before content | field/type/else |
| `suf` | Text after content | field/type/else |
| `delim` | Separator between collection elements | field/type/else |
| `cont` | Literal replacement for field value | field/type/else |
| `cont_with` | Custom formatter function/closure | field/type/else |
| `eval` | Conditional expression | field/type |
| `eval_with` | Conditional function/closure | field/type |
| `nl` | Newline positions (`beg`, `pre`, `cont`, `suf`) | field/type/else |
| `ind` | Increase indent level for field content | field/type/else |
| `skip` | Omit field from formatting | field/type |
| `state` | Specify state type (type-level only) | type |
| `bound` | Add trait bound to state (type-level only) | type |
## Contributing
Contributions are welcome! Please feel free to submit a Pull Request.
## License
This project is dual licensed under:
- Apache License, Version 2.0, ([LICENSE-APACHE](LICENSE-APACHE))
- MIT license ([LICENSE-MIT](LICENSE-MIT))
Unless explicitly stated otherwise, any contribution intentionally submitted for inclusion in the work by you, as defined in the Apache-2.0 license, shall be dual licensed as above, without any additional terms or conditions.