Configuration
Configuration Files
panache searches for configuration in this order:
- Explicit path:
--config <path>(errors if invalid) - Project config:
.panache.tomlorpanache.tomlin current or parent directories - User config:
~/.config/panache/config.toml(XDG) - Built-in defaults: 80 char width, auto line endings, reflow wrap
Basic Options
Flavor
Choose the Markdown flavor, which determines default extension settings:
flavor = "quarto"Available flavors:
pandoc- Standard Pandoc Markdown (default)quarto- Quarto-flavored Markdown (Pandoc + Quarto extensions)rmarkdown- R Markdown (Pandoc + R-specific extensions)gfm- GitHub Flavored Markdowncommonmark- CommonMark (minimal extensions)
Line Width
Set the maximum line width for wrapping:
line_width = 80 # Default: 80Wrapping Mode
Control how text is wrapped:
wrap = "reflow" # Options: "reflow", "preserve"reflow(default): Reformat paragraphs to fit within line widthpreserve: Keep existing line breaks
Blank Lines
Control blank line handling:
blank_lines = "collapse" # Options: "collapse", "preserve"collapse(default): Collapse multiple blank lines into onepreserve: Keep all existing blank lines
Extensions
panache supports 60+ Pandoc extensions. Each flavor has sensible defaults, but you can override any extension:
flavor = "quarto"
[extensions]
# Override flavor defaults
hard_line_breaks = false
citations = true
task_lists = trueBlock-Level Extensions
Headings
[extensions]
blank_before_header = true # Require blank line before headers
header_attributes = true # {#id .class key=value} syntaxBlock Quotes
[extensions]
blank_before_blockquote = true # Require blank line before blockquotesLists
[extensions]
fancy_lists = true # Roman numerals, letters
startnum = true # Start at arbitrary numbers
example_lists = true # (@) example markers
task_lists = true # - [ ] and - [x]
definition_lists = true # Term/definition syntaxCode Blocks
[extensions]
backtick_code_blocks = true # ``` fences
fenced_code_blocks = true # ~~~ fences
fenced_code_attributes = true # {.language #id}
inline_code_attributes = true # `code`{.class}Tables
[extensions]
simple_tables = true # Simple table syntax
multiline_tables = true # Multiline cells
grid_tables = true # Grid-style tables
pipe_tables = true # GitHub-style | tables
table_captions = true # Table captionsDivs
[extensions]
fenced_divs = true # ::: {.class} divs
native_divs = true # HTML <div> elementsInline Extensions
Emphasis
[extensions]
intraword_underscores = true # Don't trigger emphasis in snake_case
strikeout = true # ~~strikethrough~~
superscript = true # ^super^
subscript = true # ~sub~Links
[extensions]
inline_links = true # [text](url)
reference_links = true # [text][ref]
shortcut_reference_links = true # [ref]
link_attributes = true # [text](url){.class}
autolinks = true # <http://example.com>
autolink_bare_uris = false # Bare URLs → links (non-default)Images
[extensions]
inline_images = true # 
implicit_figures = true # Single image → figureMath
[extensions]
tex_math_dollars = true # $x$ and $$equation$$
tex_math_single_backslash = false # \(...\) and \[...\] (RMarkdown)
tex_math_double_backslash = false # \\(...\\) and \\[...\\]Footnotes
[extensions]
inline_footnotes = true # ^[text]
footnotes = true # [^1] referencesCitations
[extensions]
citations = true # [@cite] syntaxSpans
[extensions]
bracketed_spans = true # [text]{.class}
native_spans = true # HTML <span> elementsMetadata Extensions
[extensions]
yaml_metadata_block = true # --- YAML frontmatter
pandoc_title_block = true # % Title / % Author / % DateRaw Content Extensions
[extensions]
raw_html = true # HTML blocks and inline
markdown_in_html_blocks = true # Markdown inside HTML
raw_tex = true # LaTeX commands
raw_attribute = true # {=format} raw blocksSpecial Character Extensions
[extensions]
all_symbols_escapable = true # Backslash escapes any symbol
escaped_line_breaks = true # Backslash at line end = <br>
hard_line_breaks = false # Newline = <br> (non-default)
emoji = false # :emoji: syntax (non-default)
mark = false # ==highlighted== (non-default)Quarto-Specific Extensions
[extensions]
quarto_callouts = true # .callout-note, etc.
quarto_crossrefs = true # @fig-id, @tbl-idExternal Code Formatters
panache can invoke external formatters for code blocks—but they’re opt-in. You choose what gets formatted.
Quick Start with Presets
Enable formatters using convenient presets:
# Enable R formatting with air (fast)
[formatters.r]
preset = "air"
# Enable Python formatting with ruff (fast)
[formatters.python]
preset = "ruff"Available presets:
| Language | Preset | Command | Notes |
|---|---|---|---|
r |
air |
air format {} |
Fast, modern |
r |
styler |
Rscript -e "styler::..." |
Requires styler R package |
python |
ruff |
ruff format |
Fast, modern |
python |
black |
black - |
Popular alternative |
Formatters execute in parallel with panache’s markdown formatting. If the tool isn’t installed, code is preserved unchanged (no errors).
Disabling formatters:
[formatters.r]
enabled = false # Disable R formatting
[formatters.python]
enabled = false # Disable Python formattingCustom Configuration
For full control, define formatters manually. External formatters support two modes: stdin/stdout or file-based.
Stdin Mode (Default)
For formatters that read from stdin and write to stdout:
# Custom Python formatter (overrides built-in ruff default)
[formatters.python]
cmd = "black"
args = ["-", "--line-length=88"]
stdin = true # Default
# Add formatters for new languages
[formatters.rust]
cmd = "rustfmt"
stdin = true
[formatters.javascript]
cmd = "prettier"
args = ["--parser=babel"]
stdin = trueNote: When you define a [formatters.X] section with cmd, it completely replaces the built-in default for that language (if any). Other languages keep their defaults.
File-Based Mode
For formatters that modify files in place:
[formatters.r]
cmd = "air"
args = ["format"]
stdin = false # File-based mode
[formatters.go]
cmd = "gofmt"
args = ["-w"] # -w writes to file
stdin = falseFile path placeholder: Use {} in args to control where the file path is inserted. If omitted, it’s appended at the end.
[formatters.r]
cmd = "air"
args = ["format", "{}"] # Explicit: air format /tmp/file.tmp
stdin = false
[formatters.custom]
cmd = "myformatter"
args = ["--input", "{}", "--output", "{}"] # Multiple uses
stdin = falseBehavior
- Language matching: Code block language (e.g.,
```python) is matched to formatter key (case-insensitive) - Parallel execution: All formatters run concurrently for speed
- Error handling: Failed formatters preserve original code with a warning
- Timeout: 30 seconds per formatter invocation
- Optional: Set
enabled = falseto disable a formatter - Formatters respect their own config files (
.prettierrc,pyproject.toml, etc.)
Supported Formatters
Any CLI tool that reads stdin and writes stdout works:
- R:
styler,formatR - Python:
black,ruff format,autopep8 - Rust:
rustfmt - JavaScript/TypeScript:
prettier,deno fmt - JSON:
jq - YAML:
yamlfmt - Go:
gofmt - SQL:
sqlformat,pg_format
Performance
Formatters run in true parallel. If you have 3 code blocks and each formatter takes 1 second, all 3 complete in ~1 second (not 3 seconds sequentially).
Example Configuration
Complete example with all common options:
# Markdown flavor and basic settings
flavor = "quarto"
line_width = 80
wrap = "reflow"
blank_lines = "collapse"
# Extension overrides
[extensions]
hard_line_breaks = false
citations = true
task_lists = true
emoji = false
# External formatters (opt-in)
# Option 1: Use presets
[formatters.r]
preset = "air"
# Option 2: Full custom configuration
[formatters.python]
cmd = "black"
args = ["-", "--line-length=88"]
# Option 3: Add new formatters for other languages
[formatters.rust]
cmd = "rustfmt"
args = []
[formatters.javascript]
cmd = "prettier"
args = ["--parser=babel", "--stdin-filepath=file.js"]See Also
- CLI Reference - Using
--configflag - Formatting - How configuration affects output
- Getting Started - Basic configuration examples