# marginalia
Trivia-preserving parsing and formatting for [logos] + [lalrpop] grammars.
`marginalia` plugs into the standard Rust parsing stack and keeps comments and blank lines around
the AST, so you can write a formatter for your language without losing the user's notes.
The crate has three layers, all in one place:
- `TriviaLexer` adapts any `Iterator<Item = Result<(usize, Tok, usize), E>>` and records line,
block, and blank-line trivia in a `TriviaTable` while the parser sees only semantic tokens.
- `marginalia::attach` places those trivia events on AST node spans as leading, trailing, or
dangling comments.
- `marginalia::pretty` is a small `Doc` IR with explicit trivia slots that the renderer resolves
against a `CommentMap`.
The shape of an integration:
```rust,ignore
use marginalia::TriviaLexer;
use marginalia::attach::{attach, AttachOptions};
use marginalia::pretty::{render, RenderOpts};
let raw = my_logos_lexer(source);
let mut lex = TriviaLexer::new(raw, source);
let program = MyParser::new().parse(&mut lex)?;
let table = lex.into_table();
let map = attach(source, &table, my_spans(&program), AttachOptions::default());
let doc = program.doc();
let formatted = render(&doc, &map, RenderOpts::default());
```
The lexer must yield `Result<(usize, Tok, usize), E>` and `Tok` must implement
`marginalia::Classify` so marginalia knows which tokens are comments.
`Classify`, `Trivia`, `TriviaTable`, and `CommentMap` are all generic over a kind enum `K` (default
`BuiltinKind = Line | Block`). A language that needs richer categories supplies its own enum and an
`impl Classify<MyKind> for MyTok`. The renderer requires `K: TriviaClass` so it knows which trailing
comments terminate a line.
## Example
[`examples/calc`](examples/calc) is a 200-line calculator language with full lex + parse + format
roundtrip and comment preservation. Read it end-to-end as the canonical integration template:
```bash
cargo run -p marginalia-calc -- examples/calc/tests/input.calc
```
## License
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
[logos]: https://crates.io/crates/logos
[lalrpop]: https://crates.io/crates/lalrpop