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
-
Format entire documents or selected ranges (
textDocument/formatting,textDocument/rangeFormatting) - Go to definition
-
Jump from references to definitions (
textDocument/definition)- Reference links:
[text][ref]→[ref]: url - Reference images:
![alt][ref]→[ref]: url - Footnote references:
[^id]→[^id]: content
- Reference links:
- Document outline
-
Hierarchical view of document structure (
textDocument/documentSymbol)- Headings (H1-H6) with proper nesting
- Tables (with captions when available)
- Figures (images with alt text)
- Code folding
-
Fold sections of your document (
textDocument/foldingRange)- Headings
- Code blocks
- Fenced divs
- YAML frontmatter
- Live diagnostics
-
Real-time linting as you type (
textDocument/publishDiagnostics)- Heading hierarchy violations
- Duplicate references
- Citation validation
- Parser errors
- External linter integration (e.g., R code linting)
- Code actions
-
Quick fixes and refactorings (
textDocument/codeAction)- Auto-fix lint issues (e.g., heading hierarchy corrections)
- Convert list styles (loose ↔︎ compact)
- Convert footnote styles (inline ↔︎ reference)
- Hover information
-
Contextual information on hover (
textDocument/hover) - Auto-completion
-
Smart completions for Markdown syntax (
textDocument/completion) - Symbol renaming
-
Rename references and their definitions together (
textDocument/rename) - Document tracking
-
Incremental synchronization for efficiency (
textDocument/didOpen,textDocument/didChange,textDocument/didClose) - Configuration discovery
- Automatic detection from workspace root
- Format on save
- Automatic formatting when saving files
Starting the Server
Most users should install an editor extension and let the editor start the server automatically.
Manual start (for debugging):
panache lspThe server communicates over stdin/stdout using the standard LSP JSON-RPC protocol.
Editor Configuration
Neovim
In Neovim +0.11, you can use the built-in LSP client:
-- .config/nvim/lsp/panache.lua
return {
cmd = { "panache", "lsp" },
filetypes = { "quarto", "markdown", "rmarkdown" },
root_markers = { ".panache.toml", "panache.toml", ".git" },
settings = {},
}
-- Enable it
vim.lsp.enable({"panache"})For earlier Neovim releases, use nvim-lspconfig:
-- Add to your LSP config
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 it
lspconfig.panache.setup({})Note that you need to have panache in your PATH for the above configurations to work.
To format on save, add an autocmd:
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = { "*.qmd", "*.md", "*.rmd" },
callback = function()
vim.lsp.buf.format({ async = false })
end,
})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
Panache is available as a VS Code extension with built-in LSP support:
- VS Code Marketplace: https://marketplace.visualstudio.com/items?itemName=jolars.panache
- Open VSX: https://open-vsx.org/extension/jolars/panache
To install through the command line, run:
# VS Code
code --install-extension jolars.panacheIf you prefer to install from the VS Code UI, launch VS Code Quick Open (Ctrl+P), then run:
ext install jolars.panacheThe extension launches panache lsp automatically.
Optional extension settings:
{
"panache.commandPath": "panache",
"panache.downloadBinary": true,
"panache.releaseTag": "latest",
"panache.serverArgs": [],
"panache.serverEnv": { "RUST_LOG": "info" },
"panache.trace.server": "off"
}Cursor
Install the Panache extension from the marketplace:
ext install jolars.panache
Open a Markdown or Quarto file and the extension will automatically start the LSP server.
Helix
Add to ~/.config/helix/languages.toml:
[[language]]
name = "markdown"
language-servers = ["panache"]
auto-format = true
[[language]]
name = "quarto"
language-servers = ["panache"]
auto-format = true
[[language]]
name = "rmarkdown"
language-servers = ["panache"]
auto-format = true
[language-server.panache]
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 and range formatting via textDocument/formatting and textDocument/rangeFormatting requests. This uses the same formatting engine as the panache format CLI command.
Format entire documents or selected ranges:
" Neovim: format buffer
:lua vim.lsp.buf.format()
" Neovim: format selected range (visual mode)
:'<,'>lua vim.lsp.buf.format()
Format on save is supported by all major editors. See editor configuration sections above for setup instructions.
Go to Definition
Jump from link/footnote references to their definitions:
- Reference links
-
[text][label]→[label]: url - Shortcut reference links
-
[label]→[label]: url - Reference images
-
![alt][label]→[label]: url - Footnote references
-
[^id]→[^id]: content
Place your cursor on a reference and trigger “go to definition” (F12 in many editors).
Document Outline
The LSP provides a hierarchical document outline showing:
- Headings
- H1-H6 with proper nesting levels
- Tables
- With captions when available
- Figures
- Image links with alt text
The outline appears in:
- VSCode: Outline view (sidebar) or breadcrumbs
- Neovim: Telescope symbols (
:Telescope lsp_document_symbols) or Aerial plugin - Helix: Symbol picker (
:symbol-picker)
The outline updates automatically as you edit.
Code Actions
Quick fixes and refactorings available at the cursor position:
- Auto-fix lint issues
- Fix heading hierarchy violations automatically
- Convert list styles
- Toggle between loose (blank lines) and compact list formatting
- Convert footnote styles
-
Toggle between inline
^[text]and reference[^id]footnotes
Trigger code actions:
" Neovim: show code actions at cursor
:lua vim.lsp.buf.code_action()
Most editors show a lightbulb icon when code actions are available.
Folding Ranges
Fold sections of your document for easier navigation:
- Headings
- Fold sections under headings
- Code blocks
- Fold multi-line fenced code blocks
- Fenced divs
-
Fold
::: {.class}content - YAML frontmatter
-
Fold
---delimited metadata
Most editors support folding with default key bindings (e.g., za in Neovim, Ctrl+Shift+[ in VSCode).
Live Diagnostics
Linting errors and warnings appear in real-time as you type:
- Built-in rules
- Heading hierarchy, duplicate references, citation validation, parser errors
- External linters
-
Code block linting (e.g.,
jarlfor R when configured in[linters])
Diagnostics appear as:
- Squiggly underlines in the editor
- Hover tooltips with error messages
- Problems/diagnostics panel
Quick fixes are available via code actions where applicable.
Hover Information
Hover over elements to see contextual information (implementation varies by element type).
Auto-Completion
Smart completions for Markdown syntax (implementation varies by context).
Symbol Renaming
Rename references and their definitions together. Place cursor on a reference label or definition and trigger rename (F2 in many editors).
Document Synchronization
The LSP tracks document changes using incremental synchronization:
textDocument/didOpen- Document opened in editor
textDocument/didChange- Document content changed (incremental deltas sent)
textDocument/didClose- Document closed
This ensures the LSP always has the current document state while minimizing data transfer.
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 "panache.trace.server": "verbose" in settings.
Configuration Not Loading
Verify your config file is valid by testing with the CLI first:
panache format --config .panache.toml test.qmdThe LSP searches for config from the workspace root, not the file’s directory.