A Language Server Protocol (LSP) implementation for Beancount, the double-entry bookkeeping language. This provides rich editing features like completions, diagnostics, formatting, and more for Beancount files in your favorite editor.
LSP Feature | Description | Status |
---|---|---|
Completions | Smart autocompletion for accounts, payees, dates, narration, tags, links, and transaction types | ✅ |
Diagnostics | Real-time error checking and validation via beancount Python integration | ✅ |
Formatting | Document formatting compatible with bean-format , with support for prefix-width, num-width, and currency-column options |
✅ |
Rename | Rename symbols across files | ✅ |
References | Find all references to accounts, payees, etc. | ✅ |
- Accounts: Autocomplete account names with hierarchy support (
Assets:Checking
) - Payees: Previously used payee names
- Dates: Smart date completion (today, this month, previous month, next month)
- Narration: Previously used transaction descriptions
- Tags: Complete hashtags (
#vacation
) - Links: Complete links (
^receipt-123
) - Transaction Types:
txn
,balance
,open
,close
, etc.
LSP Feature | Description | Priority |
---|---|---|
Hover | Show account balances, transaction details, account metadata | High |
Go to Definition | Jump to account/payee/commodity definitions | High |
Document Symbols | Outline view showing accounts, transactions, and structure | High |
Folding Ranges | Fold transactions, account hierarchies, and multi-line entries | Medium |
Semantic Highlighting | Advanced syntax highlighting with semantic information | Medium |
Code Actions | Quick fixes, refactoring, auto-balance transactions | Medium |
Inlay Hints | Show computed balances, exchange rates, running totals | Low |
Signature Help | Help with transaction syntax and directive parameters | Low |
Workspace Symbols | Find accounts, payees, commodities across all files | Low |
cargo install beancount-language-server
Download the latest release for your platform from the releases page.
Supported Platforms:
- Linux (x86_64, aarch64, loongarch64)
- macOS (x86_64, aarch64)
- Windows (x86_64)
brew install beancount-language-server
# Using nix-env
nix-env -iA nixpkgs.beancount-language-server
# Using nix shell
nix shell nixpkgs#beancount-language-server
# Development environment
nix develop
git clone https://github.com/polarmutex/beancount-language-server.git
cd beancount-language-server
cargo build --release
The binary will be available at target/release/beancount-language-server
.
- Beancount: Install the Python beancount package for diagnostics
pip install beancount
- Bean-format: The language server includes built-in formatting that's fully compatible with bean-format. Installing bean-format is optional for comparison or standalone use
pip install bean-format
The language server accepts configuration via LSP initialization options:
{
"journal_file": "/path/to/main.beancount",
"formatting": {
"prefix_width": 30,
"num_width": 10,
"currency_column": 60,
"account_amount_spacing": 2,
"number_currency_spacing": 1
}
}
Option | Type | Description | Default |
---|---|---|---|
journal_file |
string | Path to the main beancount journal file | None |
Option | Type | Description | Default | Bean-format Equivalent |
---|---|---|---|---|
prefix_width |
number | Fixed width for account names (overrides auto-detection) | Auto-calculated | --prefix-width (-w ) |
num_width |
number | Fixed width for number alignment (overrides auto-detection) | Auto-calculated | --num-width (-W ) |
currency_column |
number | Align currencies at this specific column | None (right-align) | --currency-column (-c ) |
account_amount_spacing |
number | Minimum spaces between account names and amounts | 2 | N/A |
number_currency_spacing |
number | Number of spaces between number and currency | 1 | N/A |
Default Mode (no currency_column
specified):
- Accounts are left-aligned
- Numbers are right-aligned with consistent end positions
- Behaves like
bean-format
with no special options
Currency Column Mode (currency_column
specified):
- Currencies are aligned at the specified column
- Numbers are positioned to place currencies at the target column
- Equivalent to
bean-format --currency-column N
Basic formatting with auto-detection:
{
"formatting": {}
}
Fixed prefix width (like bean-format -w 25
):
{
"formatting": {
"prefix_width": 25
}
}
Currency column alignment (like bean-format -c 60
):
{
"formatting": {
"currency_column": 60
}
}
Number-currency spacing control:
{
"formatting": {
"number_currency_spacing": 2
}
}
This controls the whitespace between numbers and currency codes:
0
: No space (100.00USD
)1
: Single space (100.00 USD
) - default2
: Two spaces (100.00 USD
)
Combined options:
{
"formatting": {
"prefix_width": 30,
"currency_column": 65,
"account_amount_spacing": 3,
"number_currency_spacing": 1
}
}
- Install the Beancount extension from the marketplace
- Configure in
settings.json
:{ "beancount.journal_file": "/path/to/main.beancount", "beancount.formatting": { "prefix_width": 30, "currency_column": 60, "number_currency_spacing": 1 } }
Using nvim-lspconfig:
local lspconfig = require('lspconfig')
lspconfig.beancount.setup({
init_options = {
journal_file = "/path/to/main.beancount",
formatting = {
prefix_width = 30,
currency_column = 60,
number_currency_spacing = 1,
},
},
})
File type detection: Ensure beancount files are detected. Add to your config:
vim.filetype.add({
extension = {
beancount = "beancount",
bean = "beancount",
},
})
Add to your languages.toml
:
[language-server.beancount-language-server]
command = "beancount-language-server"
args = ["--stdio"]
[language-server.beancount-language-server.config]
journal_file = "/path/to/main.beancount"
[language-server.beancount-language-server.config.formatting]
prefix_width = 30
currency_column = 60
number_currency_spacing = 1
[[language]]
name = "beancount"
language-servers = [{ name = "beancount-language-server" }]
Using lsp-mode:
(use-package lsp-mode
:hook (beancount-mode . lsp-deferred)
:config
(lsp-register-client
(make-lsp-client
:new-connection (lsp-stdio-connection "beancount-language-server")
:major-modes '(beancount-mode)
:server-id 'beancount-language-server
:initialization-options
(lambda () (list :journal_file "/path/to/main.beancount"
:formatting '(:prefix_width 30 :currency_column 60 :number_currency_spacing 1))))))
Using vim-lsp:
if executable('beancount-language-server')
au User lsp_setup call lsp#register_server({
\ 'name': 'beancount-language-server',
\ 'cmd': {server_info->['beancount-language-server']},
\ 'allowlist': ['beancount'],
\ 'initialization_options': {
\ 'journal_file': '/path/to/main.beancount',
\ 'formatting': {
\ 'prefix_width': 30,
\ 'currency_column': 60,
\ 'number_currency_spacing': 1
\ }
\ }
\ })
endif
Using LSP:
Add to LSP settings:
{
"clients": {
"beancount-language-server": {
"enabled": true,
"command": ["beancount-language-server"],
"selector": "source.beancount",
"initializationOptions": {
"journal_file": "/path/to/main.beancount",
"formatting": {
"prefix_width": 30,
"currency_column": 60,
"number_currency_spacing": 1
}
}
}
}
}
┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐
│ Editor │◄──►│ LSP Server │◄──►│ Beancount │
│ │ │ │ │ (Python) │
│ - VSCode │ │ - Completion │ │ - Validation │
│ - Neovim │ │ - Formatting │ │ - Parsing │
│ - Helix │ │ - Diagnostics │ │ - Bean-check │
│ - Emacs │ │ - Tree-sitter │ │ │
└─────────────────┘ └─────────────────┘ └─────────────────┘
- LSP Server: Main Rust application handling LSP protocol
- Tree-sitter Parser: Fast, incremental parsing of Beancount syntax
- Completion Engine: Smart autocompletion with context awareness
- Diagnostic Provider: Integration with beancount Python for validation
- Formatter: Code formatting fully compatible with bean-format, supporting prefix-width, num-width, and currency-column options
beancount-language-server/
├── crates/lsp/ # Main LSP server implementation
│ ├── src/
│ │ ├── handlers.rs # LSP request/notification handlers
│ │ ├── providers/ # Feature providers (completion, diagnostics, etc.)
│ │ └── server.rs # Core LSP server logic
├── vscode/ # VS Code extension
├── python/ # Python integration utilities
└── flake.nix # Nix development environment
- Rust (stable toolchain)
- Python with beancount
- Node.js (for VS Code extension)
Using Nix (Recommended):
nix develop
Manual Setup:
# Install Rust dependencies
cargo build
# Install Node.js dependencies (for VS Code extension)
cd vscode && npm install
# Install development tools
cargo install cargo-watch
# Run all tests
cargo test
# Run with coverage
cargo llvm-cov --all-features --locked --workspace --lcov --output-path lcov.info
# Run specific test
cargo test test_completion
# Format code
cargo fmt
# Lint code
cargo clippy --all-targets --all-features
# Check formatting
cargo fmt -- --check
- Make changes to the Rust code
- Test locally with
cargo test
- Run LSP server in development mode:
cargo run --bin beancount-language-server
- Test with editor by configuring it to use the local binary
cd vscode
npm run build # Build extension
npm run watch # Watch for changes
npm run package # Package extension
The project uses cargo-dist for automated releases:
- Tag a release:
git tag v1.0.0 && git push --tags
- GitHub Actions automatically builds and publishes:
- Binaries for all supported platforms
- Crates.io release
- GitHub release with assets
Contributions are welcome! Here are some ways to help:
- Search existing issues first
- Include beancount file examples that trigger the bug
- Provide editor and OS information
- Check the planned features list
- Describe the use case and expected behavior
- Consider the LSP specification constraints
- Fork the repository
- Create a feature branch (
git checkout -b feature/amazing-feature
) - Make your changes with tests
- Ensure code quality:
cargo fmt && cargo clippy && cargo test
- Commit your changes (
git commit -m 'Add amazing feature'
) - Push to the branch (
git push origin feature/amazing-feature
) - Open a Pull Request
Look for issues labeled good-first-issue
:
- Add new completion types
- Improve error messages
- Add editor configuration examples
- Improve documentation
- Beancount Documentation
- Language Server Protocol Specification
- Tree-sitter Beancount Grammar
- VSCode Extension API
This project is licensed under the MIT License - see the LICENSE file for details.
- Beancount - The amazing double-entry bookkeeping language
- Tree-sitter - Incremental parsing framework
- LSP - Language Server Protocol specification
- Twemoji - Emoji graphics used in the icon
Happy Beancounting! 📊✨