Language Server Protocol implementation for hledger plain text accounting
npm install hledger-lsp
- hledger Language Server
- Installation
- Command Line Usage
- LSP Server Mode (default)
- Standalone Formatter
- Other Options
- IDE Integration
- VS Code
- Neovim
- Other Editors
- Features
- Code Completion
- Hover
- Validation
- Include Directive Support
- Navigation
- Code Actions and Quick Fixes
- Formatting
- Semantic Highlighting
- Inlay Hints
- Code Lens
- Editor Integration
- Configuration
- General Settings
- Validation Settings
- Severity Settings
- Include Settings
- Workspace Settings
- Completion Settings
- Formatting Settings
- Inlay Hints Settings
- Code Lens Settings
- Development
- Prerequisites
- Building from Source
- Project Structure
- Development Commands
- Contributing
- License
- Links
A Language Server Protocol (LSP) implementation for
hledger, a plain text accounting tool.
``bash`
npm install -g hledger-lsp
This provides the hledger-lsp command globally. After installation, the
language server can be used with any LSP-compatible editor.
The hledger-lsp command can be used in two modes:
`bash`
hledger-lsp --stdio
This starts the language server for use with LSP-compatible editors.
Format journal files directly from the command line without an IDE:
`bashFormat a file and output to stdout
hledger-lsp --format myfile.journal
The formatter applies default formatting settings:
- 4-space indentation for postings
- Decimal point alignment at column 52
- Normalized transaction header spacing
$3
`bash
hledger-lsp --help # Show help message
hledger-lsp --version # Show version
`IDE Integration
This language server can be used with any LSP-compatible editor. Currently available extensions:
$3
Extension: hledger-vscode
GitHub: hledger-vscode
Install from the VS Code Marketplace or Extensions view. The extension provides
all LSP features with zero configuration.
$3
Plugin: hledger-nvim
Provides automatic LSP configuration, filetype detection, and workspace visualization.
$3
The server can be used with any LSP client. Example configuration:
`json
{
"command": "hledger-lsp",
"args": ["--stdio"],
"filetypes": ["hledger", "journal"],
"rootPatterns": [".hledger-lsp.json", ".git"]
}
`Features
This language server provides comprehensive IDE support for hledger journal
files:
$3
- Account names - Auto-complete from accounts (configurable: declared only
or all)
- Payees - Complete transaction descriptions from payees (configurable:
declared only or all)
- Commodities - Auto-complete currency symbols (configurable: declared only
or all)
- Tags - Complete tag names in comments (configurable: declared only or all)
- Directives - Complete hledger directives (account, commodity, payee, tag,
include, alias)
- Include paths - File path completion for include directives
- Smart completions - Context-aware account suggestions based on payee
history (learns from your transaction patterns)
- Smart filtering - By default, only declared items appear in completions
(can be configured to include all items)
$3
- Hover information - Lightweight hover support for accounts, payees and
dates. Hover text is provided by the language server and can be extended to show
declarations, balances and commodity formats.
$3
- Transaction balance - Verify transactions balance to zero per commodity
- Missing amounts - Ensure at most one posting omits an amount
- Undeclared items - Warn about undeclared accounts, payees, commodities,
and tags
- Date ordering - Detect out-of-order transactions
- Balance assertions - Verify balance assertions match calculated balances
- Empty transactions - Require at least 2 postings per transaction
- Date validation - Check for invalid dates (e.g., Feb 30, month 13)
- Future dates - Warn about future-dated transactions
- Empty descriptions - Warn about transactions with no description
- Include files - Detect missing include files
- Circular includes - Detect circular include dependencies
$3
- Multi-file journals - Parse and merge multiple journal files via include
directives
- Relative and absolute paths - Support both path styles, including
../
parent directory references
- Tilde expansion - Support for ~/ home directory paths
- Paths with spaces - Properly handles file paths containing spaces and
special characters (e.g., "Cloud Storage", "My Documents (2025)")
- Circular detection - Prevent infinite loops from circular includes
- Caching - Efficient parsing with include file caching
- Dependency tracking - Auto-revalidate files when included files change
- Source tracking - Track which file each entity originates from$3
- Document symbols - Outline view showing directives and transactions with
postings
- Workspace symbols - Project-wide search across all accounts, payees,
commodities, tags, and transactions
- Go to definition - Jump to declarations for accounts, payees, commodities,
and tags
- Find references - Show all usages of accounts, payees, commodities, or
tags across the document
$3
- Add declarations - Automatically add account, payee, commodity, or tag
declarations for undeclared items
- Smart insertion - Directives are inserted in appropriate locations,
grouped with similar directive types
- Rename refactoring - Rename accounts, payees, commodities, or tags across
all their references in the document
- Context-aware actions - Actions appear when cursor is positioned on
renameable items
$3
- Document formatting - Format entire journal files with consistent
indentation and spacing
- Range formatting - Format selected portions of your journal
- On-type formatting - Auto-indent postings when pressing Enter after
transaction headers
- Decimal-point alignment - Automatically align amounts by their decimal
point (or implied decimal position for whole numbers) within transactions,
making it easy to visually compare amounts
- Negative amount support - Properly aligns negative amounts regardless of
minus sign position (e.g.,
-$100.00 or $-100.00)
- Commodity format support - Reformats amounts according to declared
commodity formats (symbol placement, decimal separators, thousands separators,
precision)
- Precision preservation - Maintains decimal precision even when commodity
format specifies fewer decimal places
- Configurable - Customize indentation width, alignment column, minimum
spacing, trailing whitespace handling, and more$3
- Context-aware syntax highlighting - Rich semantic highlighting based on
token type and meaning
- Token types - Distinct highlighting for dates, accounts, payees,
commodities, tags, directives, amounts, comments, and status indicators
- Token modifiers - Additional styling for declarations (directive
definitions) and readonly items (dates, amounts)
- Hierarchical accounts - Account names highlighted as namespaces to reflect
their hierarchical nature
- Tag detection - Automatic highlighting of tags within comments (key:value
pairs)
$3
- Inferred amounts - Show calculated amounts for postings without explicit
amounts
- Running balances - Display running balances per account and commodity
after each posting
- Cost conversions - Show total cost in target commodity for postings with
cost notation (@ or @@)
- Configurable - Enable/disable each hint type independently
- Range-aware - Only show hints for visible portions of the document for
better performance
$3
- Balance assertions - Show running balances on each posting line in balance
assertion format (
= $50.00)
- Clickable - Click a balance assertion code lens to insert it into the posting
- Transaction counts - Display how many transactions each account has been
involved in on transaction headers
- Configurable - Enable/disable each lens type independently$3
- Folding ranges - Collapse/expand transactions to hide postings, fold
multi-line comment blocks
- Document links - Clickable include paths that open the referenced file
(supports relative and absolute paths)
- Selection range - Smart text selection expansion: Word → Account → Posting
→ Transaction (requires editor keybinding setup, see configuration below)
Configuration
All validations and completion behaviors can be individually configured per
workspace or document:
- Validation settings - Enable/disable individual validation rules and
customize severity levels
- Completion filtering - Control whether completions show only declared
items or all items (declared + undeclared)
$3
-
maxNumberOfProblems (number, default: 1000): Maximum number of diagnostic
problems to report per file
- hledgerPath (string, default: "hledger"): Path to the hledger executable
(reserved for future CLI integration)$3
Most validation settings default to
true and can be individually disabled:-
validation.balance (default: true): Verify transactions balance to zero per commodity
- validation.missingAmounts (default: true): Ensure at most one posting per
transaction omits an amount
- validation.undeclaredAccounts (default: true): Warn about accounts used but
not declared
- validation.undeclaredPayees (default: false): Warn about payees used but
not declared
- validation.undeclaredCommodities (default: true): Warn about commodities
used but not declared
- validation.undeclaredTags (default: false): Warn about tags used but not
declared
- validation.dateOrdering (default: true): Detect transactions with dates out
of chronological order
- validation.balanceAssertions (default: true): Verify balance assertions
match calculated balances
- validation.emptyTransactions (default: true): Require at least 2 postings
per transaction
- validation.invalidDates (default: true): Check for invalid dates (e.g.,
February 30, month 13)
- validation.futureDates (default: true): Warn about future-dated transactions
- validation.emptyDescriptions (default: true): Warn about transactions with
no description
- validation.formatMismatch (default: true): Validate that amounts match their
commodity format directives
- validation.includeFiles (default: true): Detect missing include files
- validation.circularIncludes (default: true): Detect circular include dependencies
- validation.markAllUndeclaredInstances (default: true): Mark all
instances of undeclared resources with diagnostics, not just the first occurrence$3
Customize the severity level for undeclared item warnings. Options:
"error",
"warning", "information", "hint"-
severity.undeclaredAccounts (default: "warning")
- severity.undeclaredPayees (default: "warning")
- severity.undeclaredCommodities (default: "warning")
- severity.undeclaredTags (default: "information")$3
-
include.followIncludes (boolean, default: true): Parse and merge included
journal files
- include.maxDepth (number, default: 10): Maximum include depth to prevent
infinite recursion$3
Enable workspace-aware parsing for features that need global context (running
balances, completion, validation):
-
workspace.enabled (boolean, default: true): Enable workspace-aware parsing.
When enabled, the server discovers all journal files in your workspace, builds
an include graph, and identifies a single root file. This allows features to
access workspace-wide state even when working with "leaf" files that don't
include other files.
- workspace.eagerParsing (boolean, default: true): Parse all discovered files
eagerly on startup. If disabled, files are parsed on-demand.
- workspace.autoDetectRoot (boolean, default: true): Automatically detect the
root file using heuristics (prefers files with no parents that include many
others, with names like "main", "all", or "index"). If disabled, only an
explicitly configured root file is used (see Configuration File Support below).Configuration File Support:
You can create a
.hledger-lsp.json file in your workspace to explicitly
configure workspace behavior:`json
{
"rootFile": "main.journal",
"include": ["/.journal", "/.hledger"],
"exclude": ["/archive/", "/temp/"],
"workspace": {
"enabled": true,
"eagerParsing": true,
"autoDetectRoot": false
}
}
`Settings:
-
rootFile (string): Explicit root file path (relative to config file location)
- include (array of glob patterns): File discovery patterns
(default: ["/.journal", "/.hledger"])
- exclude (array of glob patterns): Files to exclude
(default: ["/node_modules/", "/.git/", "*/."])
- workspace (object): Same workspace settings as aboveImportant: The
.hledger-lsp.json file is ONLY for workspace structure
configuration (which files to discover, which are roots, etc.).
LSP feature settings like inlay hints, code lens, validation rules,
and formatting preferences should be configured in your editor/IDE
settings (VS Code settings.json, Neovim LSP config, etc.).The configuration file will be automatically discovered by walking up the
directory tree from your journal files. Settings from VS Code/editor
configuration override settings from the config file.
Performance Tips:
- For large workspaces (>100 files), use
exclude patterns to skip unnecessary files
- Disable eagerParsing if initialization is slow
- Check LSP server logs for performance warnings and metrics$3
Control which items appear in auto-completion suggestions. All settings default
to
true (only show declared items):-
completion.onlyDeclaredAccounts (boolean, default: true): Only show accounts
declared with account directive in completions
- completion.onlyDeclaredPayees (boolean, default: true): Only show payees
declared with payee directive in completions
- completion.onlyDeclaredCommodities (boolean, default: true): Only show
commodities declared with commodity directive in completions
- completion.onlyDeclaredTags (boolean, default: true): Only show tags
declared with tag directive in completionsSet to
false to include items that are used but not explicitly declared in
completions.$3
Configure document formatting behavior:
-
formatting.indentation (number, default: 4): Number of spaces for posting
indentation
- formatting.maxCommodityWidth (number, default: 4): Maximum width allocated
for commodity symbols
- formatting.maxAmountIntegerWidth (number, default: 12): Maximum width
allocated for the integer part of amount numbers
- formatting.maxAmountDecimalWidth (number, default: 3): Maximum width
allocated for the decimal part of amount numbers
- formatting.minSpacing (number, default: 2): Minimum number of spaces between
account names and amounts
- formatting.decimalAlignColumn (number, default: 52): Target column position
for aligning decimal points in amounts
- formatting.assertionDecimalAlignColumn (number, default: 70): Target column
position for aligning decimal points in balance assertions
- formatting.signPosition (string, default: "after-symbol"): Where to place the
negative sign for prefix commodities. Options: "after-symbol" (e.g., $-100.00)
or "before-symbol" (e.g., -$100.00). This affects how amounts are displayed in
hover information, inlay hints, and other LSP features. Does not affect postfix
commodities (e.g., -100.00 EUR), which always show the sign before the number.
- formatting.showPositivesSign (boolean, default: false): Whether to show a +
sign for positive amounts$3
Configure which inline hints to display (running balances is disabled by default
as it can make the file busy):
-
inlayHints.showInferredAmounts (boolean, default: true): Show calculated
amounts for postings that omit explicit amounts
- inlayHints.showRunningBalances (boolean, default: false): Display running
balance after each posting
- inlayHints.showCostConversions (boolean, default: true): Show total cost in
target commodity for postings with @ or @@ notation$3
Configure which code lenses to display (disabled by default, largely a holding
for future features):
-
codeLens.showTransactionCounts (boolean, default: false): Show transaction
counts for each account on transaction headersDevelopment
$3
- Node.js >= 16.0.0
$3
`bash
Clone the repository
git clone https://github.com/ptimoney/hledger-lsp.git
cd hledger-lspInstall dependencies
npm installBuild the server
npm run buildRun the server directly
node out/server.js --stdio
`$3
`
hledger-lsp/
├── src/
│ ├── server.ts # Main LSP server implementation
│ ├── types.ts # Type definitions for hledger structures
│ ├── parser/ # Journal file parser
│ ├── features/ # LSP feature implementations
│ ├── server/ # Server infrastructure
│ └── utils/ # Utility functions
├── tests/ # Test suite (515+ test cases)
├── out/ # Compiled JavaScript output
└── package.json
`$3
`bash
Build once
npm run buildWatch mode (rebuild on changes)
npm run watchLint code
npm run lintRun all tests
npm testRun tests in watch mode
npm run test:watchGenerate coverage report
npm run test:coverageRun tests with verbose output
npm run test:verboseRun specific test file
npx jest tests/parser/index.test.tsRun tests matching a pattern
npx jest --testNamePattern="balance"
`$3
When working on the language server and the VS Code extension together you have two convenient workflows:
- Preferred: sibling local build
If you have the
hledger-vscode extension checked out next to this repo (as siblings), the extension will prefer a local built server at ../hledger-lsp/out/server.js. Steps:
`bash
# In this repo (language server)
cd /path/to/hledger-lsp
npm install
npm run compile # produces out/server.js # In the extension repo (open this folder in VS Code)
cd /path/to/hledger-vscode
npm install
npm run compile
` Then open the
hledger-vscode folder in VS Code and press F5 to launch the Extension Development Host. The extension will detect the local out/server.js and use it when starting the language client.- Alternative:
npm link If you prefer to keep the projects separate or want the extension to pick up a locally-installed (linked) package, use
npm link:
`bash
# In language server repo
cd /path/to/hledger-lsp
npm link # In extension repo
cd /path/to/hledger-vscode
npm link hledger-lsp
npm install
npm run compile
` This makes
require.resolve('hledger-lsp/out/server.js') resolve to your local linked package.Notes and tips
- After building the server and extension, use Developer: Reload Window in the extension host or the
hledgerLanguageServer.reload command (provided by the extension) to restart the language client so changes propagate.
- The server now logs the semantic token legend on initialize. Open View → Output and select the hledger Language Server output channel to see messages such as: Semantic tokens legend: {"tokenTypes":["namespace","keyword","class","variable","property","type","number","string","comment","operator"],"tokenModifiers":["declaration","readonly","deprecated"]}
- Running tests:
- Server tests (in
hledger-lsp): npm test (or npx jest )
- Extension tests (in hledger-vscode): npm test — these use mocked vscode and vscode-languageclient modules so they don't require a real server binary.If you want an explicit server path override, set up a quick environment variable in your debug launch configuration or use
npm link` as described above.Contributions are welcome! Please feel free to submit a Pull Request.
MIT
- VS Code Extension: hledger-vscode
- Neovim Plugin: hledger-nvim
- Report Issues: GitHub Issues
- hledger: Official Documentation
- LSP Specification: Language Server Protocol