원클릭으로
debug-formatter
// Debug a SQL formatter bug. Use when the user reports incorrect formatting output — wrong whitespace, misplaced comments, blank lines, etc.
// Debug a SQL formatter bug. Use when the user reports incorrect formatting output — wrong whitespace, misplaced comments, blank lines, etc.
Commit all current changes, push to a feature branch, and create a PR. Use when the user asks to commit, push, save progress, or ship changes.
Quickly commit and push current changes to a feature branch and create a PR, skipping pre-push checks. WARNING: if CI starts failing, use /cp instead.
Format SQL files using the syntaqlite formatter. Use when the user wants to format, reformat, or pretty-print SQL code.
Parse SQL and inspect the AST using syntaqlite. Use when the user wants to see the parse tree, debug SQL syntax, or understand how a query is structured.
Validate SQL and report diagnostics using syntaqlite. Use when the user wants to check SQL for errors, lint SQL files, or verify correctness against a schema.
Run tests to verify correctness after code changes. Use when the user asks to run tests, verify changes, or check that things still work. Runs Rust unit tests and integration tests.
| name | debug-formatter |
| description | Debug a SQL formatter bug. Use when the user reports incorrect formatting output — wrong whitespace, misplaced comments, blank lines, etc. |
| user_invocable | true |
Debug a SQL formatter bug using red-green testing and pipeline tracing.
Add a failing test to syntaqlite/tests/fmt_comments.rs (comment bugs) or the
relevant tests/fmt_diff_tests/*.py file. Always eprintln! the actual output:
#[test]
fn descriptive_name() {
let input = "...";
let out = fmt(input);
eprintln!("=== actual ===\n{out}=== end ===");
assert_eq!(out, "...\n");
}
Run it and confirm RED:
cargo test -p syntaqlite --features fmt,sqlite --test fmt_comments TEST_NAME -- --nocapture
Work through these layers to find the root cause:
| Layer | File | What to check |
|---|---|---|
| Grammar | syntaqlite-buildtools/parser-nodes/*.synq | fmt { } block; clause("KW", field) expands to IF_SET → LINE → KEYWORD → NEST(LINE, CHILD) |
| Bytecode compiler | syntaqlite-buildtools/src/dialect_codegen/fmt_compiler.rs | How Fmt::Clause, Fmt::Keyword compile to opcodes |
| Interpreter | syntaqlite/src/fmt/interpret.rs | Main loop in interpret_node; state = running (committed doc) + pending (deferred line breaks) |
| Comment drain | syntaqlite/src/fmt/comment.rs | drain_before(offset) respects has_non_comment_text guard; drain_keyword_interior() skips it for multi-word keywords |
| flush_drain | interpret.rs | Integrates DrainResult { trailing, leading } into running/pending; when leading != NIL, pending is dropped |
| Doc renderer | syntaqlite/src/fmt/doc.rs | Wadler-style; hardline always breaks, line breaks if group broken |
hardline + comment + hardline; back-to-back hardlines = blank line. Fix via continuation flag on drain_keyword_interior.flush_drain for interior comments runs before keyword text is emitted. Check flush vs keyword append ordering in the Keyword match arm.has_non_comment_text guard stops drain_before when a keyword sits between the comment and target offset. Multi-word interiors need skip_text_check: true.flush_drain with leading != NIL zeroes pending. If pending held a LINE from the clause template, that break is lost.cargo test -p syntaqlite --features fmt,sqlite --test fmt_comments TEST_NAME -- --nocapture
cargo test -p syntaqlite --features fmt,sqlite
cargo build -p syntaqlite-cli && tools/run-integration-tests
All 7 integration suites must pass (including ~650 idempotency checks).