# Beancount Language Server ![License](https://img.shields.io/github/license/polarmutex/beancount-language-server) ![GitHub release (latest by date)](https://img.shields.io/github/v/release/polarmutex/beancount-language-server) ![Crates.io](https://img.shields.io/crates/v/beancount-language-server) A [Language Server Protocol](https://microsoft.github.io/language-server-protocol/) (LSP) implementation for [Beancount](https://beancount.github.io/), the double-entry bookkeeping language. This provides rich editing features like completions, diagnostics, formatting, and more for Beancount files in your favorite editor. ![nixos](https://socialify.git.ci/polarmutex/beancount-language-server/image?description=1&font=Source%20Code%20Pro&owner=1&pattern=Circuit%20Board&stargazers=1&theme=Dark) ## âœĻ Features ### 🚀 Currently Implemented | 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. | ✅ | | **Semantic Highlighting** | Advanced syntax highlighting with semantic information | ✅ | | **Inlay Hints** | Show calculated balancing amounts and unbalanced transaction warnings | ✅ | ### 📋 Completion Types - **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. ### ðŸ’Ą Inlay Hints Non-intrusive inline annotations that help visualize implicit information: - **Calculated Balancing Amounts**: When a posting omits an amount, shows the implicit balancing amount at the end of that posting line, aligned with other amounts - **Unbalanced Transaction Warnings**: When all postings have explicit amounts but don't balance to zero, shows a warning with the unbalanced total on the transaction line **Examples:** ```beancount 2024-01-15 * "Grocery Store" Expenses:Food:Groceries 45.23 USD Assets:Bank:Checking -45.23 USD ; ← Shown as inlay hint 2024-01-15 * "Unbalanced Transfer" /* = 500.00 USD ⚠ */ ; ← Warning shown Assets:Savings 1000.00 USD Assets:Checking -500.00 USD ``` ### ðŸ”Ū Planned Features | 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 | | **Code Actions** | Quick fixes, refactoring, auto-balance transactions | Medium | | **Signature Help** | Help with transaction syntax and directive parameters | Low | | **Workspace Symbols** | Find accounts, payees, commodities across all files | Low | ## ðŸ“Ķ Installation ### Method 1: Cargo (Recommended) ```bash cargo install beancount-language-server ``` ### Method 2: GitHub Releases (Pre-built Binaries) Download the latest release for your platform from the [releases page](https://github.com/polarmutex/beancount-language-server/releases). **Supported Platforms:** - Linux (x86_64, aarch64, loongarch64) - macOS (x86_64, aarch64) - Windows (x86_64) ### Method 3: Homebrew (macOS/Linux) ```bash brew install beancount-language-server ``` ### Method 4: Nix ```bash # Using nix-env nix-env -iA nixpkgs.beancount-language-server # Using nix shell nix shell nixpkgs#beancount-language-server # Development environment nix develop ``` ### Method 5: Build from Source ```bash git clone https://github.com/polarmutex/beancount-language-server.git cd beancount-language-server # Standard build (includes PyO3 embedded Python support by default) cargo build --release # Build without PyO3 (minimal binary, requires external bean-check/python) cargo build --release --no-default-features ``` The binary will be available at `target/release/beancount-language-server`. ## 🔧 Requirements ### For Diagnostics (Bean-check) The language server requires **one** of the following for validation and diagnostics: **Option 1: PyO3 Embedded (Default - Recommended)** - **Python 3.8+** installed on your system - **beancount** Python package ```bash pip install beancount ``` - **Pre-built binaries** from GitHub releases include PyO3 support by default - **Performance**: 60-66x faster than subprocess-based methods (~838Ξs vs ~50ms per check) - **Note**: If beancount is not available, automatically falls back to other methods #### Python Environment Compatibility The PyO3 embedded checker (recommended) works seamlessly with: - ✅ **System Python 3.8+** (any minor version) - ✅ **Virtual environments** (venv, virtualenv) - ✅ **Conda environments** - ✅ **pyenv-managed Python** - ✅ **Multiple Python versions** (uses abi3 stable ABI - one binary works with all Python 3.8+) - ✅ **Project-local .venv** (automatically detected) **No special configuration needed** - the binary automatically detects and uses available Python installations. #### Python Discovery Order The language server searches for Python in this order: 1. `BEANCOUNT_LSP_PYTHON` environment variable (if set) 2. User-configured `python_cmd` in LSP settings 3. Project-local `.venv/bin/python` (or `.venv/Scripts/python.exe` on Windows) 4. System `python3` in PATH 5. System `python` in PATH #### Advanced: Explicit Python Override For edge cases or custom Python installations, set the environment variable: ```bash # Unix/Linux/macOS export BEANCOUNT_LSP_PYTHON=/path/to/python beancount-language-server # Windows (PowerShell) $env:BEANCOUNT_LSP_PYTHON = "C:\path\to\python.exe" beancount-language-server # Windows (CMD) set BEANCOUNT_LSP_PYTHON=C:\path\to\python.exe beancount-language-server ``` Or configure via LSP settings: ```json { "bean_check": { "python_cmd": "/path/to/python" } } ``` **Option 2: System Python (Fallback)** - **Python** with beancount library - Used automatically if PyO3 checker is unavailable - Invokes Python via subprocess for validation **Option 3: Bean-check Binary (Fallback)** - Traditional `bean-check` command-line tool - Install via: `pip install beancount` (includes bean-check) - Used if Python methods are unavailable ### Performance Comparison Based on comprehensive benchmarks with a 30-line beancount file: | Method | Average Time | Relative Speed | Availability | | --------------------------- | ------------ | ----------------- | -------------------------------- | | **PyO3 Embedded** (default) | **~838Ξs** | **1x (baseline)** | Requires Python 3.8+ + beancount | | System Python | ~50.1ms | 60x slower | Requires Python + beancount | | Bean-check Binary | ~55.2ms | 66x slower | Requires bean-check binary | **Recommendation**: Use PyO3 embedded checker (default in pre-built binaries) for optimal performance. ## ⚙ïļ Configuration The language server accepts configuration via LSP initialization options: ```json { // Optional: Only needed for multi-file projects with include directives "journal_file": "/path/to/main.beancount", "formatting": { "prefix_width": 30, "num_width": 10, "currency_column": 60, "account_amount_spacing": 2, "number_currency_spacing": 1 }, "completion": { "fuzzy_match_accounts": true // Optional: cross-segment fuzzy matching (default: false) }, "diagnostic_flags": ["!"] // Optional: flags that generate warnings (default: ["!"]) } ``` **Note**: All configuration is optional. The language server will auto-detect the best checker method (PyO3 → System Python → Bean-check). ### Configuration Options | Option | Type | Description | Default | | -------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- | | `journal_file` | string | Path to the main beancount journal file. **Optional**: Only required if your beancount files use `include` directives to span multiple files. Single-file projects work without this setting. | None | ### Workspace-Specific Configuration The `journal_file` setting is **workspace-specific**. Each editor workspace (project folder) can have its own journal file configured. This means: - **Completions are scoped**: Account names, payees, currencies, tags, and links are loaded only from the configured journal and its included files - **Separate ledgers**: If you work on multiple beancount projects (personal finances, business, etc.), each workspace uses its own configuration - **No cross-contamination**: Accounts from one ledger won't appear as completions in another **Example workflow with multiple ledgers:** ``` ~/finances/personal/ # Workspace 1: journal_file = "main.beancount" ├── main.beancount # Includes accounts/*.beancount └── accounts/ └── assets.beancount ~/finances/business/ # Workspace 2: journal_file = "ledger.beancount" ├── ledger.beancount # Includes 2024/*.beancount └── 2024/ └── transactions.beancount ``` When editing files in `~/finances/personal/`, completions only show accounts like `Assets:Personal:Checking`. When editing in `~/finances/business/`, completions show `Assets:Business:Operating`. ### Bean-check Configuration | Option | Type | Description | Default | | --------------------------- | ------ | ------------------------------------------------------------------ | ------- | | `bean_check.method` | string | Validation method: "system", "python-system", or "python-embedded" | None | | `bean_check.bean_check_cmd` | string | Path to bean-check binary (for "system" method) | None | | `bean_check.python_cmd` | string | Path to Python executable (for Python methods) | None | **Preferred checker order (when `bean_check.method` is not set):** 1. `python-embedded` (if built with the feature and available) 2. `python-system` (if a compatible Python with beancount is available) 3. `system` (if bean-check is available) #### Configuration Examples **Default (no configuration needed):** The language server automatically selects the best available checker method: 1. PyO3 Embedded (if Python 3.8+ with beancount is available) 2. System Python (if Python with beancount is available) 3. System Call (if bean-check binary is available) No configuration required! Just install Python and beancount. **Override to force a specific method:** Only configure `bean_check.method` if you need to override auto-detection: ```json { "bean_check": { "method": "system", // Force bean-check binary "bean_check_cmd": "/usr/local/bin/bean-check" } } ``` ```json { "bean_check": { "method": "python-system", // Force Python subprocess "python_cmd": "/usr/bin/python3" } } ``` ```json { "bean_check": { "method": "python-embedded" // Force PyO3 (already default) } } ``` #### Troubleshooting PyO3 Checker If the PyO3 embedded checker is not working: 1. **Verify Python installation**: ```bash python3 --version # Should be 3.8 or higher ``` 2. **Verify beancount installation**: ```bash python3 -c "import beancount.loader; print('Beancount OK')" ``` 3. **Check language server logs** for PyO3-related messages: - VSCode: View → Output → Select "Beancount Language Server" - Neovim: `:LspLog` - Look for messages like "PyO3EmbeddedChecker: failed to import beancount.loader" 4. **Install beancount if missing**: ```bash # System-wide pip3 install beancount # User installation (no sudo required) pip3 install --user beancount # Virtual environment (recommended) python3 -m venv ~/.beancount-env source ~/.beancount-env/bin/activate pip install beancount ``` 5. **Override Python detection** (if you have multiple Python installations): ```bash # Set environment variable to use specific Python export BEANCOUNT_LSP_PYTHON=/path/to/python3 # Or configure in LSP settings { "bean_check": { "python_cmd": "/path/to/python3" } } ``` 6. **Fallback methods**: If PyO3 checker fails, the language server automatically tries: - System Python method (python -c with beancount) - System Call method (bean-check binary) Check your configuration if you need to explicitly set a method. ### Diagnostic Flags Configuration By default, the language server generates warnings for all flagged transactions (entries with flags like `!`, `P`, etc.). You can configure which flags should generate diagnostics to reduce noise from intentional flags. | Option | Type | Description | Default | | ------------------ | -------- | ---------------------------------------------------------------- | ------- | | `diagnostic_flags` | string[] | List of transaction flags that should generate warning diagnostics | `["!"]` | **Default behavior** (only `!` flag generates warnings): ```json { "diagnostic_flags": ["!"] } ``` This means padding transactions with `P` flag, or other custom flags, won't generate warnings. **Include multiple flags:** ```json { "diagnostic_flags": ["!", "P"] } ``` This generates warnings for both `!` (needs attention) and `P` (padding) flags. **Disable all flag diagnostics:** ```json { "diagnostic_flags": [] } ``` This completely disables warnings for flagged transactions. **Use case**: Some users intentionally use flags like `P` for padding transactions that will persist forever in the ledger. With the default configuration, these won't generate noise in your diagnostics panel, while `!` flags (which typically indicate transactions needing review) will still show warnings. ### Formatting Options | 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 | #### Formatting Modes **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` #### Examples **Basic formatting with auto-detection:** ```json { "formatting": {} } ``` **Fixed prefix width (like `bean-format -w 25`):** ```json { "formatting": { "prefix_width": 25 } } ``` **Currency column alignment (like `bean-format -c 60`):** ```json { "formatting": { "currency_column": 60 } } ``` **Number-currency spacing control:** ```json { "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`) - default - `2`: Two spaces (`100.00 USD`) **Combined options:** ```json { "formatting": { "prefix_width": 30, "currency_column": 65, "account_amount_spacing": 3, "number_currency_spacing": 1 } } ``` ### Completion Options | Option | Type | Description | Default | | ----------------------------------- | ------- | ------------------------------------------------------------------------------------------------------------ | ------- | | `completion.fuzzy_match_accounts` | boolean | Enable cross-segment fuzzy matching for account completions. When enabled, typing "BankCheck" can match "Assets:US:Bank:Checking" without typing each segment hierarchically. | `false` | **Disable cross-segment fuzzy matching:** ```json { "completion": { "fuzzy_match_accounts": false } } ``` When disabled, account completions use standard prefix matching only (e.g., you must type "Assets:US:Bank" to match accounts under that path). ## ðŸ–Ĩïļ Editor Setup ### Visual Studio Code 1. Install the [Beancount extension](https://marketplace.visualstudio.com/items?itemName=polarmutex.beancount-langserver) from the marketplace 2. Configure in `settings.json` (optional): ```json { // Optional: Only needed for multi-file projects with include directives "beancountLangServer.journalFile": "/path/to/main.beancount", "beancountLangServer.formatting": { "prefix_width": 30, "currency_column": 60, "number_currency_spacing": 1 }, // Optional: flags that generate warnings (default: ["!"]) "beancountLangServer.diagnosticFlags": ["!"] } ``` **Workspace-specific configuration**: Create a `.vscode/settings.json` in each project folder: ```json { "beancountLangServer.journalFile": "${workspaceFolder}/main.beancount" } ``` This ensures each workspace uses its own journal file for completions and diagnostics. ### Neovim Using `nvim.lsp` (nvim > 0.11) `lsp/beancount.lua` ```lua return { commands = { "beancount-language-server", "--stdio" }, root_markers = { "main.bean", ".git" }, -- init_options are optional init_options = { -- Optional: Only needed for multi-file projects with include directives journal_file = "main.bean", -- Optional: flags that generate warnings (default: ["!"]) diagnostic_flags = { "!" }, -- Optional: completion behavior completion = { fuzzy_match_accounts = true, -- cross-segment fuzzy matching (default: false) }, }, settings = { beancount = { formatting = { prefix_width = 30, currency_column = 60, number_currency_spacing = 1, } } } } ``` Using [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig): ```lua local lspconfig = require('lspconfig') lspconfig.beancount.setup({ -- All init_options are optional init_options = { -- Optional: Only needed for multi-file projects with include directives -- journal_file = "/path/to/main.beancount", formatting = { prefix_width = 30, currency_column = 60, number_currency_spacing = 1, }, -- Optional: completion behavior -- completion = { -- fuzzy_match_accounts = true, -- cross-segment fuzzy matching (default: false) -- }, -- Optional: flags that generate warnings (default: {"!"}) diagnostic_flags = { "!" }, }, }) -- To override auto-detected checker method: -- lspconfig.beancount.setup({ -- init_options = { -- bean_check = { -- method = "system", -- Force specific method: "python-embedded", "python-system", or "system" -- }, -- }, -- }) ``` **File type detection**: Ensure beancount files are detected. Add to your config: ```lua vim.filetype.add({ extension = { beancount = "beancount", bean = "beancount", }, }) ``` **Workspace-specific configuration**: Use `.nvim.lua` or `exrc` for per-project settings: ```lua -- .nvim.lua in your beancount project root vim.lsp.config.beancount = { init_options = { journal_file = vim.fn.getcwd() .. "/main.beancount", }, } ``` Or with nvim-lspconfig, use `on_new_config` to dynamically set the journal file: ```lua lspconfig.beancount.setup({ on_new_config = function(new_config, new_root_dir) new_config.init_options = new_config.init_options or {} new_config.init_options.journal_file = new_root_dir .. "/main.beancount" end, }) ``` ### Helix Add to your `languages.toml`: ```toml [language-server.beancount-language-server] command = "beancount-language-server" args = ["--stdio"] # Configuration is optional [language-server.beancount-language-server.config] # Optional: Only needed for multi-file projects with include directives # journal_file = "/path/to/main.beancount" # Optional: bean_check config (uses python-embedded by default) # [language-server.beancount-language-server.config.bean_check] # method = "python-embedded" # or "python-system" or "system" # Optional: completion behavior # [language-server.beancount-language-server.config.completion] # fuzzy_match_accounts = true # cross-segment fuzzy matching (default: false) # Optional: formatting configuration [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" }] ``` ### Zed Add to your `settings.json` (access via `Zed > Settings > Open Settings`): ```json { "lsp": { "beancount-language-server": { "binary": { "path": "beancount-language-server", "arguments": ["--stdio"] }, "initialization_options": { // Optional: Only needed for multi-file projects with include directives "journal_file": "/path/to/main.beancount", "formatting": { "prefix_width": 30, "currency_column": 60, "number_currency_spacing": 1 }, // Optional: completion behavior "completion": { "fuzzy_match_accounts": true // cross-segment fuzzy matching (default: true) } } } }, "languages": { "Beancount": { "language_servers": ["beancount-language-server"] } } } ``` For **workspace-specific configuration**, create a `.zed/settings.json` in your project root: ```json { "lsp": { "beancount-language-server": { "initialization_options": { "journal_file": "main.beancount" } } } } ``` **Note**: Zed may require a [Beancount extension](https://zed.dev/extensions) for syntax highlighting. The language server provides completions, diagnostics, and formatting regardless of syntax highlighting support. ### Emacs Using [lsp-mode](https://github.com/emacs-lsp/lsp-mode): ```elisp (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 ;; All options are optional (lambda () (list ;; Optional: Only needed for multi-file projects with include directives ;; :journal_file "/path/to/main.beancount" ;; Optional: bean_check config (uses python-embedded by default) ;; :bean_check '(:method "python-embedded") ;; Optional: completion behavior ;; :completion '(:fuzzy_match_accounts t) :formatting '(:prefix_width 30 :currency_column 60 :number_currency_spacing 1)))))) ``` **Workspace-specific configuration**: Use `.dir-locals.el` in your project root: ```elisp ;; .dir-locals.el ((beancount-mode . ((lsp-clients-beancount-langserver-init-options . (:journal_file "./main.beancount"))))) ``` Or dynamically set based on project root: ```elisp (defun my/beancount-lsp-init-options () "Generate init options with project-local journal file." (let ((journal-file (expand-file-name "main.beancount" (project-root (project-current))))) (when (file-exists-p journal-file) (list :journal_file journal-file)))) ;; Use in lsp-register-client with :initialization-options #'my/beancount-lsp-init-options ``` ### Vim Using [vim-lsp](https://github.com/prabirshrestha/vim-lsp): ```vim 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': { \ 'formatting': { \ 'prefix_width': 30, \ 'currency_column': 60, \ 'number_currency_spacing': 1 \ } \ } \ }) " Optional: For multi-file projects with include directives, add: " \ 'journal_file': '/path/to/main.beancount', " Optional: To override default checker method, add: " \ 'bean_check': {'method': 'python-embedded'}, endif ``` ### Sublime Text Using [LSP](https://packagecontrol.io/packages/LSP): Add to LSP settings: ```json { "clients": { "beancount-language-server": { "enabled": true, "command": ["beancount-language-server"], "selector": "source.beancount", // All initializationOptions are optional "initializationOptions": { // Optional: Only needed for multi-file projects with include directives // "journal_file": "/path/to/main.beancount", "formatting": { "prefix_width": 30, "currency_column": 60, "number_currency_spacing": 1 }, // Optional: completion behavior // "completion": { // "fuzzy_match_accounts": true // } } } } } ``` ## 🏗ïļ Architecture ### High-Level Overview ``` ┌─────────────────┐ ┌─────────────────┐ ┌─────────────────┐ │ Editor │◄──▹│ LSP Server │◄──▹│ Beancount │ │ │ │ │ │ (Python) │ │ - VSCode │ │ - Completion │ │ - Validation │ │ - Neovim │ │ - Formatting │ │ - Parsing │ │ - Helix │ │ - Diagnostics │ │ - Bean-check │ │ - Emacs │ │ - Tree-sitter │ │ │ └─────────────────┘ └─────────────────┘ └─────────────────┘ ``` ### Core Components - **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**: Multi-method validation system with pluggable checkers - **Bean-check Integration**: Three validation methods (system, python-embedded) - **Formatter**: Code formatting fully compatible with bean-format, supporting prefix-width, num-width, and currency-column options ### Project Structure ``` beancount-language-server/ ├── crates/lsp/ # Main LSP server implementation │ ├── src/ │ │ ├── handlers.rs # LSP request/notification handlers │ │ ├── providers/ # Feature providers (completion, diagnostics, etc.) │ │ ├── checkers/ # Bean-check validation implementations │ │ │ ├── mod.rs # Strategy trait and factory pattern │ │ │ ├── system_call.rs # Traditional bean-check binary │ │ │ ├── pyo3_embedded.rs # PyO3 embedded Python │ │ │ └── types.rs # Shared data structures │ │ └── server.rs # Core LSP server logic ├── vscode/ # VS Code extension └── flake.nix # Nix development environment ``` ## 🛠ïļ Development ### Prerequisites - **Rust** (stable toolchain) - **Python** with beancount - **Node.js** (for VS Code extension) ### Development Environment **Using Nix (Recommended):** ```bash nix develop ``` **Manual Setup:** ```bash # Install Rust dependencies cargo build # Install Node.js dependencies (for VS Code extension) cd vscode && pnpm install # Install development tools cargo install cargo-watch ``` ### Running Tests ```bash # Run all tests cargo test # Run with coverage cargo llvm-cov --all-features --locked --workspace --lcov --output-path lcov.info # Run tests with PyO3 feature cargo test --features python-embedded # Run specific test cargo test test_completion ``` ### Code Quality ```bash # Format code cargo fmt # Lint code cargo clippy --all-targets --all-features # Check formatting cargo fmt -- --check ``` ### Development Workflow 1. **Make changes** to the Rust code 2. **Test locally** with `cargo test` 3. **Run LSP server** in development mode: ```bash cargo run --bin beancount-language-server ``` 4. **Test with editor** by configuring it to use the local binary ### VS Code Extension Development ```bash cd vscode pnpm run build # Build extension pnpm run watch # Watch for changes pnpm run package # Package extension ``` ### Release Process 1. **Tag a release**: `git tag v1.0.0 && git push --tags` 2. **GitHub Actions** automatically builds and publishes: - Binaries for all supported platforms - Crates.io release - GitHub release with assets ## ðŸĪ Contributing Contributions are welcome! Here are some ways to help: ### 🐛 Bug Reports - Search existing issues first - Include beancount file examples that trigger the bug - Provide editor and OS information ### ðŸ’Ą Feature Requests - Check the [planned features](#-planned-features) list - Describe the use case and expected behavior - Consider the LSP specification constraints ### 🔧 Code Contributions 1. **Fork** the repository 2. **Create** a feature branch (`git checkout -b feature/amazing-feature`) 3. **Make** your changes with tests 4. **Ensure** code quality: `cargo fmt && cargo clippy && cargo test` 5. **Commit** your changes (`git commit -m 'Add amazing feature'`) 6. **Push** to the branch (`git push origin feature/amazing-feature`) 7. **Open** a Pull Request ### ðŸŽŊ Good First Issues Look for issues labeled `good-first-issue`: - Add new completion types - Improve error messages - Add editor configuration examples - Improve documentation ## 📚 Resources - **[Beancount Documentation](https://beancount.github.io/)** - **[Language Server Protocol Specification](https://microsoft.github.io/language-server-protocol/)** - **[Tree-sitter Beancount Grammar](https://github.com/polarmutex/tree-sitter-beancount)** - **[VSCode Extension API](https://code.visualstudio.com/api)** ## 📄 License This project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details. ## 🙏 Acknowledgments - **[Beancount](https://github.com/beancount/beancount)** - The amazing double-entry bookkeeping language - **[Tree-sitter](https://tree-sitter.github.io/)** - Incremental parsing framework - **[LSP](https://microsoft.github.io/language-server-protocol/)** - Language Server Protocol specification - **[Twemoji](https://github.com/twitter/twemoji)** - Emoji graphics used in the icon ---

Happy Beancounting! 📊âœĻ