Language Server
Overview
Panache includes a built-in Language Server Protocol (LSP) implementation that provides document formatting capabilities for editors and IDEs.
Features
The list of features is still evolving, but here is a (hopfully) comprehensive overview of the current capabilities:
- 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 - Citation references:
[@key]→[@key]: content - Quarto crossrefs:
@fig-label→ chunk/equation/figure label definition
- Reference links:
- Find references
-
Find all usages of a symbol (
textDocument/references)- Quarto crossrefs and chunk labels
- Citation keys (with optional bibliography/inline-reference declarations)
- 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
- 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)- Footnote definitions
- Citation previews
- Auto-completion
-
Smart completions for Markdown syntax (
textDocument/completion)- Citation keys
- Reference labels
- Symbol renaming
-
Rename references and their definitions together (
textDocument/rename)- Citation keys
- Reference labels
- Quarto crossref labels (including executable chunk
labeloptions)
- Document tracking
-
Incremental synchronization for efficiency (
textDocument/didOpen,textDocument/didChange,textDocument/didClose) - Configuration discovery
- Automatic detection from workspace root
Starting the Server
If you want to start the language server manually (for debugging), then you can run panache lsp in your terminal. This will start the server and wait for JSON-RPC input. But most users will want to set up their editor to start the server automatically when editing supported files. See the editor integration instructions below.
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"
}Positron
See the VS Code section above.
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 - Quarto crossrefs
-
@fig-label→#| label: fig-label(or other crossref label definitions)
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).
Find References
Find all references to the symbol under cursor (textDocument/references), including Quarto crossrefs, executable chunk labels, and citation keys.
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.