Language Server Protocol
Overview
panache includes a built-in Language Server Protocol (LSP) implementation that provides document formatting capabilities for editors and IDEs.
Features
- Document formatting (
textDocument/formatting) - Range formatting (
textDocument/rangeFormatting) - Document outline (
textDocument/documentSymbol) - hierarchical view of headings, tables, and figures - Live diagnostics (
textDocument/publishDiagnostics) - linting errors and warnings - Code actions (
textDocument/codeAction) - quick fixes for lint issues - Document tracking (
textDocument/didOpen/didChange/didClose) - Configuration discovery from workspace root
- Format on save support
Starting the Server
Start the LSP server:
panache lspThe server communicates over stdin/stdout using the standard LSP JSON-RPC protocol.
Editor Configuration
Neovim
Using nvim-lspconfig:
-- Add to your LSP configuration file
local lspconfig = require('lspconfig')
local configs = require('lspconfig.configs')
-- Define panache LSP
if not configs.panache then
configs.panache = {
default_config = {
cmd = { 'panache', 'lsp' },
filetypes = { 'quarto', 'markdown', 'rmarkdown' },
root_dir = lspconfig.util.root_pattern('.panache.toml', 'panache.toml', '.git'),
settings = {},
},
}
end
-- Enable the server
lspconfig.panache.setup{}Format on Save
Add this to enable automatic formatting when saving:
vim.api.nvim_create_autocmd('BufWritePre', {
pattern = { '*.qmd', '*.md', '*.rmd' },
callback = function()
vim.lsp.buf.format({ async = false })
end,
})Manual Formatting
Format the current buffer with:
:lua vim.lsp.buf.format()
Or map it to a key:
vim.keymap.set('n', '<leader>f', vim.lsp.buf.format, { desc = 'Format buffer' })VS Code
Option 1: Custom LSP Extension
Install the Custom LSP extension, then configure in settings.json:
{
"customLsp.servers": {
"panache": {
"command": "panache",
"args": ["lsp"],
"filetypes": ["quarto", "markdown", "rmarkdown"]
}
},
"editor.formatOnSave": true
}Option 2: Generic LSP Client
Install a generic LSP client extension, then configure:
{
"languageServerExample.server": {
"command": "panache",
"args": ["lsp"],
"filetypes": ["quarto", "markdown", "rmarkdown"]
},
"editor.formatOnSave": true,
"[quarto]": {
"editor.defaultFormatter": "languageServerExample"
},
"[markdown]": {
"editor.defaultFormatter": "languageServerExample"
}
}Helix
Add to ~/.config/helix/languages.toml:
[[language]]
name = "markdown"
language-servers = ["panache-lsp"]
auto-format = true
[[language]]
name = "quarto"
language-servers = ["panache-lsp"]
auto-format = true
[language-server.panache-lsp]
command = "panache"
args = ["lsp"]Format the current file with :format or <space>f.
Emacs
Using lsp-mode:
(require 'lsp-mode)
;; Define panache LSP client
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection '("panache" "lsp"))
:activation-fn (lsp-activate-on "quarto" "markdown" "rmarkdown")
:server-id 'panache))
;; Enable for specific modes
(add-hook 'markdown-mode-hook #'lsp-deferred)
(add-hook 'quarto-mode-hook #'lsp-deferred)
;; Format on save
(add-hook 'before-save-hook #'lsp-format-buffer nil t)
Sublime Text
Using LSP package:
- Install LSP package
- Add to LSP settings:
{
"clients": {
"panache": {
"enabled": true,
"command": ["panache", "lsp"],
"selector": "text.html.markdown | source.quarto"
}
}
}Kate
Kate supports LSP servers via its LSP client plugin:
- Enable the LSP Client plugin
- Add to LSP client configuration:
{
"servers": {
"markdown": {
"command": ["panache", "lsp"],
"highlightingModeRegex": "^Markdown$"
}
}
}Configuration Discovery
The LSP automatically discovers configuration files from your workspace:
- Searches for
.panache.tomlorpanache.tomlfrom workspace root - Falls back to
~/.config/panache/config.toml - Uses built-in defaults if no config found
Workspace Root Detection
The LSP determines the workspace root by looking for:
.panache.tomlorpanache.toml.gitdirectory- Project-specific files (
.quarto.yml,_quarto.yml, etc.)
Capabilities
Document Formatting
The LSP provides full document formatting via the textDocument/formatting request. This is the same formatting as the panache format CLI command.
Format entire documents or selected ranges:
" Neovim: format buffer
:lua vim.lsp.buf.format()
" Neovim: format selected range
:'<,'>lua vim.lsp.buf.format()
Format on save is supported by all major editors (see configuration above).
Document Outline
The LSP provides a hierarchical document outline/symbol view showing:
- Headings (H1-H6) with proper nesting
- Tables (with captions when available)
- Figures (image links with alt text)
This appears in:
- VSCode: Outline view (sidebar) or breadcrumbs
- Neovim: Telescope symbols (
<leader>ss) or Aerial plugin - Helix: Symbol picker (
:symbol-picker)
The outline is automatically updated as you edit the document.
Live Diagnostics
Linting errors and warnings are shown in real-time as you type:
- Heading hierarchy violations
- Future lint rules as they’re added
Quick fixes are available via code actions:
" Neovim: show code actions at cursor
:lua vim.lsp.buf.code_action()
Document Synchronization
The LSP tracks document changes using incremental synchronization mode:
textDocument/didOpen: Document opened in editortextDocument/didChange: Document content changed (incremental sync)textDocument/didClose: Document closed
This ensures the LSP always has the current document state for formatting.
Troubleshooting
LSP Not Starting
Check that panache is in your PATH:
which panacheTest the LSP manually:
panache lsp
# Should start and wait for JSON-RPC inputFormatting Not Working
Enable LSP logging in your editor to see error messages:
Neovim:
vim.lsp.set_log_level("debug")
-- View logs: :lua vim.cmd('e'..vim.lsp.get_log_path())VS Code:
Set "customLsp.trace.server": "verbose" in settings.
Configuration Not Loading
Verify your config file is valid:
# Test with CLI first
panache format --config panache.toml test.qmdThe LSP searches for config from the workspace root, not the file’s directory.
Performance Issues
For large documents:
- Reduce
line_widthin config - Disable external formatters temporarily
- Use
wrap = "preserve"instead of"reflow"
Comparison with CLI
| Feature | LSP | CLI |
|---|---|---|
| Formatting | ✅ Same engine | ✅ Direct |
| Config discovery | ✅ From workspace root | ✅ From file directory |
| Format on save | ✅ Automatic | ❌ Manual |
| Multiple files | ✅ Per-editor-tab | ✅ Shell scripting |
| Error reporting | ✅ In-editor diagnostics | ✅ stderr output |
| External formatters | ✅ Supported | ✅ Supported |
Best Practices
- Place config at project root: Put
panache.tomlat your project root for consistent behavior - Use format on save: Enable format-on-save for automatic formatting
- Test CLI first: Verify formatting with CLI before relying on LSP
- Check logs: Enable LSP logging when debugging issues
- Restart after config changes: Restart LSP server after changing
.panache.toml
See Also
- Configuration - Configure formatting behavior
- CLI Reference - Command-line alternative
- Getting Started - Installation and basic usage