{"id":13522989,"url":"https://github.com/polarmutex/beancount-language-server","last_synced_at":"2026-02-12T02:41:57.456Z","repository":{"id":36973847,"uuid":"265094440","full_name":"polarmutex/beancount-language-server","owner":"polarmutex","description":"A Language Server Protocol (LSP) for beancount files","archived":false,"fork":false,"pushed_at":"2025-05-01T04:56:36.000Z","size":1437,"stargazers_count":167,"open_issues_count":25,"forks_count":21,"subscribers_count":4,"default_branch":"main","last_synced_at":"2025-05-08T21:34:40.685Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Rust","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/polarmutex.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":"CONTRIBUTING.md","funding":".github/FUNDING.yml","license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":"SECURITY.md","support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null},"funding":{"github":"polarmutex"}},"created_at":"2020-05-19T00:07:10.000Z","updated_at":"2025-05-07T11:10:59.000Z","dependencies_parsed_at":"2023-10-14T23:13:26.448Z","dependency_job_id":"52806703-9591-4eb2-9886-f65a70ac7d39","html_url":"https://github.com/polarmutex/beancount-language-server","commit_stats":{"total_commits":506,"total_committers":19,"mean_commits":26.63157894736842,"dds":0.5553359683794467,"last_synced_commit":"e0aff37c276e41c520b20672aa8edf917522977d"},"previous_names":["bryall/beancount-language-server"],"tags_count":21,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polarmutex%2Fbeancount-language-server","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polarmutex%2Fbeancount-language-server/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polarmutex%2Fbeancount-language-server/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/polarmutex%2Fbeancount-language-server/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/polarmutex","download_url":"https://codeload.github.com/polarmutex/beancount-language-server/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":254384989,"owners_count":22062422,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-08-01T06:00:54.373Z","updated_at":"2026-02-12T02:41:57.450Z","avatar_url":"https://github.com/polarmutex.png","language":"Rust","funding_links":["https://github.com/sponsors/polarmutex"],"categories":["Editor Support"],"sub_categories":["Misc"],"readme":"# Beancount Language Server\n\n![License](https://img.shields.io/github/license/polarmutex/beancount-language-server)\n![GitHub release (latest by date)](https://img.shields.io/github/v/release/polarmutex/beancount-language-server)\n![Crates.io](https://img.shields.io/crates/v/beancount-language-server)\n\nA [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.\n\n![nixos](https://socialify.git.ci/polarmutex/beancount-language-server/image?description=1\u0026font=Source%20Code%20Pro\u0026owner=1\u0026pattern=Circuit%20Board\u0026stargazers=1\u0026theme=Dark)\n\n## ✨ Features\n\n### 🚀 Currently Implemented\n\n| LSP Feature               | Description                                                                                                              | Status |\n| ------------------------- | ------------------------------------------------------------------------------------------------------------------------ | ------ |\n| **Completions**           | Smart autocompletion for accounts, payees, dates, narration, tags, links, and transaction types                          | ✅     |\n| **Diagnostics**           | Real-time error checking and validation via beancount Python integration                                                 | ✅     |\n| **Formatting**            | Document formatting compatible with `bean-format`, with support for prefix-width, num-width, and currency-column options | ✅     |\n| **Rename**                | Rename symbols across files                                                                                              | ✅     |\n| **References**            | Find all references to accounts, payees, etc.                                                                            | ✅     |\n| **Semantic Highlighting** | Advanced syntax highlighting with semantic information                                                                   | ✅     |\n| **Inlay Hints**           | Show calculated balancing amounts and unbalanced transaction warnings                                                    | ✅     |\n\n### 📋 Completion Types\n\n- **Accounts**: Autocomplete account names with hierarchy support (`Assets:Checking`)\n- **Payees**: Previously used payee names\n- **Dates**: Smart date completion (today, this month, previous month, next month)\n- **Narration**: Previously used transaction descriptions\n- **Tags**: Complete hashtags (`#vacation`)\n- **Links**: Complete links (`^receipt-123`)\n- **Transaction Types**: `txn`, `balance`, `open`, `close`, etc.\n\n### 💡 Inlay Hints\n\nNon-intrusive inline annotations that help visualize implicit information:\n\n- **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\n- **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\n\n**Examples:**\n\n```beancount\n2024-01-15 * \"Grocery Store\"\n  Expenses:Food:Groceries              45.23 USD\n  Assets:Bank:Checking                         -45.23 USD  ; ← Shown as inlay hint\n\n2024-01-15 * \"Unbalanced Transfer\"  /* = 500.00 USD ⚠ */  ; ← Warning shown\n  Assets:Savings                     1000.00 USD\n  Assets:Checking                    -500.00 USD\n```\n\n### 🔮 Planned Features\n\n| LSP Feature           | Description                                                    | Priority |\n| --------------------- | -------------------------------------------------------------- | -------- |\n| **Hover**             | Show account balances, transaction details, account metadata   | High     |\n| **Go to Definition**  | Jump to account/payee/commodity definitions                    | High     |\n| **Document Symbols**  | Outline view showing accounts, transactions, and structure     | High     |\n| **Folding Ranges**    | Fold transactions, account hierarchies, and multi-line entries | Medium   |\n| **Code Actions**      | Quick fixes, refactoring, auto-balance transactions            | Medium   |\n| **Signature Help**    | Help with transaction syntax and directive parameters          | Low      |\n| **Workspace Symbols** | Find accounts, payees, commodities across all files            | Low      |\n\n## 📦 Installation\n\n### Method 1: Cargo (Recommended)\n\n```bash\ncargo install beancount-language-server\n```\n\n### Method 2: GitHub Releases (Pre-built Binaries)\n\nDownload the latest release for your platform from the [releases page](https://github.com/polarmutex/beancount-language-server/releases).\n\n**Supported Platforms:**\n\n- Linux (x86_64, aarch64, loongarch64)\n- macOS (x86_64, aarch64)\n- Windows (x86_64)\n\n### Method 3: Homebrew (macOS/Linux)\n\n```bash\nbrew install beancount-language-server\n```\n\n### Method 4: Nix\n\n```bash\n# Using nix-env\nnix-env -iA nixpkgs.beancount-language-server\n\n# Using nix shell\nnix shell nixpkgs#beancount-language-server\n\n# Development environment\nnix develop\n```\n\n### Method 5: Build from Source\n\n```bash\ngit clone https://github.com/polarmutex/beancount-language-server.git\ncd beancount-language-server\n\n# Standard build (includes PyO3 embedded Python support by default)\ncargo build --release\n\n# Build without PyO3 (minimal binary, requires external bean-check/python)\ncargo build --release --no-default-features\n```\n\nThe binary will be available at `target/release/beancount-language-server`.\n\n## 🔧 Requirements\n\n### For Diagnostics (Bean-check)\n\nThe language server requires **one** of the following for validation and diagnostics:\n\n**Option 1: PyO3 Embedded (Default - Recommended)**\n\n- **Python 3.8+** installed on your system\n- **beancount** Python package\n  ```bash\n  pip install beancount\n  ```\n- **Pre-built binaries** from GitHub releases include PyO3 support by default\n- **Performance**: 60-66x faster than subprocess-based methods (~838μs vs ~50ms per check)\n- **Note**: If beancount is not available, automatically falls back to other methods\n\n#### Python Environment Compatibility\n\nThe PyO3 embedded checker (recommended) works seamlessly with:\n\n- ✅ **System Python 3.8+** (any minor version)\n- ✅ **Virtual environments** (venv, virtualenv)\n- ✅ **Conda environments**\n- ✅ **pyenv-managed Python**\n- ✅ **Multiple Python versions** (uses abi3 stable ABI - one binary works with all Python 3.8+)\n- ✅ **Project-local .venv** (automatically detected)\n\n**No special configuration needed** - the binary automatically detects and uses available Python installations.\n\n#### Python Discovery Order\n\nThe language server searches for Python in this order:\n\n1. `BEANCOUNT_LSP_PYTHON` environment variable (if set)\n2. User-configured `python_cmd` in LSP settings\n3. Project-local `.venv/bin/python` (or `.venv/Scripts/python.exe` on Windows)\n4. System `python3` in PATH\n5. System `python` in PATH\n\n#### Advanced: Explicit Python Override\n\nFor edge cases or custom Python installations, set the environment variable:\n\n```bash\n# Unix/Linux/macOS\nexport BEANCOUNT_LSP_PYTHON=/path/to/python\nbeancount-language-server\n\n# Windows (PowerShell)\n$env:BEANCOUNT_LSP_PYTHON = \"C:\\path\\to\\python.exe\"\nbeancount-language-server\n\n# Windows (CMD)\nset BEANCOUNT_LSP_PYTHON=C:\\path\\to\\python.exe\nbeancount-language-server\n```\n\nOr configure via LSP settings:\n```json\n{\n  \"bean_check\": {\n    \"python_cmd\": \"/path/to/python\"\n  }\n}\n```\n\n**Option 2: System Python (Fallback)**\n\n- **Python** with beancount library\n- Used automatically if PyO3 checker is unavailable\n- Invokes Python via subprocess for validation\n\n**Option 3: Bean-check Binary (Fallback)**\n\n- Traditional `bean-check` command-line tool\n- Install via: `pip install beancount` (includes bean-check)\n- Used if Python methods are unavailable\n\n### Performance Comparison\n\nBased on comprehensive benchmarks with a 30-line beancount file:\n\n| Method                      | Average Time | Relative Speed    | Availability                     |\n| --------------------------- | ------------ | ----------------- | -------------------------------- |\n| **PyO3 Embedded** (default) | **~838μs**   | **1x (baseline)** | Requires Python 3.8+ + beancount |\n| System Python               | ~50.1ms      | 60x slower        | Requires Python + beancount      |\n| Bean-check Binary           | ~55.2ms      | 66x slower        | Requires bean-check binary       |\n\n**Recommendation**: Use PyO3 embedded checker (default in pre-built binaries) for optimal performance.\n\n## ⚙️ Configuration\n\nThe language server accepts configuration via LSP initialization options:\n\n```json\n{\n  // Optional: Only needed for multi-file projects with include directives\n  \"journal_file\": \"/path/to/main.beancount\",\n  \"formatting\": {\n    \"prefix_width\": 30,\n    \"num_width\": 10,\n    \"currency_column\": 60,\n    \"account_amount_spacing\": 2,\n    \"number_currency_spacing\": 1\n  },\n  \"diagnostic_flags\": [\"!\"]  // Optional: flags that generate warnings (default: [\"!\"])\n}\n```\n\n**Note**: All configuration is optional. The language server will auto-detect the best checker method (PyO3 → System Python → Bean-check).\n\n### Configuration Options\n\n| Option         | Type   | Description                                                                                                                                                                                   | Default |\n| -------------- | ------ | --------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | ------- |\n| `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    |\n\n### Workspace-Specific Configuration\n\nThe `journal_file` setting is **workspace-specific**. Each editor workspace (project folder) can have its own journal file configured. This means:\n\n- **Completions are scoped**: Account names, payees, currencies, tags, and links are loaded only from the configured journal and its included files\n- **Separate ledgers**: If you work on multiple beancount projects (personal finances, business, etc.), each workspace uses its own configuration\n- **No cross-contamination**: Accounts from one ledger won't appear as completions in another\n\n**Example workflow with multiple ledgers:**\n\n```\n~/finances/personal/     # Workspace 1: journal_file = \"main.beancount\"\n  ├── main.beancount     # Includes accounts/*.beancount\n  └── accounts/\n      └── assets.beancount\n\n~/finances/business/     # Workspace 2: journal_file = \"ledger.beancount\"\n  ├── ledger.beancount   # Includes 2024/*.beancount\n  └── 2024/\n      └── transactions.beancount\n```\n\nWhen editing files in `~/finances/personal/`, completions only show accounts like `Assets:Personal:Checking`. When editing in `~/finances/business/`, completions show `Assets:Business:Operating`.\n\n### Bean-check Configuration\n\n| Option                      | Type   | Description                                                        | Default |\n| --------------------------- | ------ | ------------------------------------------------------------------ | ------- |\n| `bean_check.method`         | string | Validation method: \"system\", \"python-system\", or \"python-embedded\" | None    |\n| `bean_check.bean_check_cmd` | string | Path to bean-check binary (for \"system\" method)                    | None    |\n| `bean_check.python_cmd`     | string | Path to Python executable (for Python methods)                     | None    |\n\n**Preferred checker order (when `bean_check.method` is not set):**\n\n1. `python-embedded` (if built with the feature and available)\n2. `python-system` (if a compatible Python with beancount is available)\n3. `system` (if bean-check is available)\n\n#### Configuration Examples\n\n**Default (no configuration needed):**\n\nThe language server automatically selects the best available checker method:\n\n1. PyO3 Embedded (if Python 3.8+ with beancount is available)\n2. System Python (if Python with beancount is available)\n3. System Call (if bean-check binary is available)\n\nNo configuration required! Just install Python and beancount.\n\n**Override to force a specific method:**\n\nOnly configure `bean_check.method` if you need to override auto-detection:\n\n```json\n{\n  \"bean_check\": {\n    \"method\": \"system\", // Force bean-check binary\n    \"bean_check_cmd\": \"/usr/local/bin/bean-check\"\n  }\n}\n```\n\n```json\n{\n  \"bean_check\": {\n    \"method\": \"python-system\", // Force Python subprocess\n    \"python_cmd\": \"/usr/bin/python3\"\n  }\n}\n```\n\n```json\n{\n  \"bean_check\": {\n    \"method\": \"python-embedded\" // Force PyO3 (already default)\n  }\n}\n```\n\n#### Troubleshooting PyO3 Checker\n\nIf the PyO3 embedded checker is not working:\n\n1. **Verify Python installation**:\n\n   ```bash\n   python3 --version  # Should be 3.8 or higher\n   ```\n\n2. **Verify beancount installation**:\n\n   ```bash\n   python3 -c \"import beancount.loader; print('Beancount OK')\"\n   ```\n\n3. **Check language server logs** for PyO3-related messages:\n   - VSCode: View → Output → Select \"Beancount Language Server\"\n   - Neovim: `:LspLog`\n   - Look for messages like \"PyO3EmbeddedChecker: failed to import beancount.loader\"\n\n4. **Install beancount if missing**:\n\n   ```bash\n   # System-wide\n   pip3 install beancount\n\n   # User installation (no sudo required)\n   pip3 install --user beancount\n\n   # Virtual environment (recommended)\n   python3 -m venv ~/.beancount-env\n   source ~/.beancount-env/bin/activate\n   pip install beancount\n   ```\n\n5. **Override Python detection** (if you have multiple Python installations):\n\n   ```bash\n   # Set environment variable to use specific Python\n   export BEANCOUNT_LSP_PYTHON=/path/to/python3\n\n   # Or configure in LSP settings\n   {\n     \"bean_check\": {\n       \"python_cmd\": \"/path/to/python3\"\n     }\n   }\n   ```\n\n6. **Fallback methods**: If PyO3 checker fails, the language server automatically tries:\n   - System Python method (python -c with beancount)\n   - System Call method (bean-check binary)\n\n   Check your configuration if you need to explicitly set a method.\n\n### Diagnostic Flags Configuration\n\nBy 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.\n\n| Option             | Type     | Description                                                      | Default |\n| ------------------ | -------- | ---------------------------------------------------------------- | ------- |\n| `diagnostic_flags` | string[] | List of transaction flags that should generate warning diagnostics | `[\"!\"]` |\n\n**Default behavior** (only `!` flag generates warnings):\n\n```json\n{\n  \"diagnostic_flags\": [\"!\"]\n}\n```\n\nThis means padding transactions with `P` flag, or other custom flags, won't generate warnings.\n\n**Include multiple flags:**\n\n```json\n{\n  \"diagnostic_flags\": [\"!\", \"P\"]\n}\n```\n\nThis generates warnings for both `!` (needs attention) and `P` (padding) flags.\n\n**Disable all flag diagnostics:**\n\n```json\n{\n  \"diagnostic_flags\": []\n}\n```\n\nThis completely disables warnings for flagged transactions.\n\n**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.\n\n### Formatting Options\n\n| Option                    | Type   | Description                                                 | Default            | Bean-format Equivalent     |\n| ------------------------- | ------ | ----------------------------------------------------------- | ------------------ | -------------------------- |\n| `prefix_width`            | number | Fixed width for account names (overrides auto-detection)    | Auto-calculated    | `--prefix-width` (`-w`)    |\n| `num_width`               | number | Fixed width for number alignment (overrides auto-detection) | Auto-calculated    | `--num-width` (`-W`)       |\n| `currency_column`         | number | Align currencies at this specific column                    | None (right-align) | `--currency-column` (`-c`) |\n| `account_amount_spacing`  | number | Minimum spaces between account names and amounts            | 2                  | N/A                        |\n| `number_currency_spacing` | number | Number of spaces between number and currency                | 1                  | N/A                        |\n\n#### Formatting Modes\n\n**Default Mode** (no `currency_column` specified):\n\n- Accounts are left-aligned\n- Numbers are right-aligned with consistent end positions\n- Behaves like `bean-format` with no special options\n\n**Currency Column Mode** (`currency_column` specified):\n\n- Currencies are aligned at the specified column\n- Numbers are positioned to place currencies at the target column\n- Equivalent to `bean-format --currency-column N`\n\n#### Examples\n\n**Basic formatting with auto-detection:**\n\n```json\n{\n  \"formatting\": {}\n}\n```\n\n**Fixed prefix width (like `bean-format -w 25`):**\n\n```json\n{\n  \"formatting\": {\n    \"prefix_width\": 25\n  }\n}\n```\n\n**Currency column alignment (like `bean-format -c 60`):**\n\n```json\n{\n  \"formatting\": {\n    \"currency_column\": 60\n  }\n}\n```\n\n**Number-currency spacing control:**\n\n```json\n{\n  \"formatting\": {\n    \"number_currency_spacing\": 2\n  }\n}\n```\n\nThis controls the whitespace between numbers and currency codes:\n\n- `0`: No space (`100.00USD`)\n- `1`: Single space (`100.00 USD`) - default\n- `2`: Two spaces (`100.00  USD`)\n\n**Combined options:**\n\n```json\n{\n  \"formatting\": {\n    \"prefix_width\": 30,\n    \"currency_column\": 65,\n    \"account_amount_spacing\": 3,\n    \"number_currency_spacing\": 1\n  }\n}\n```\n\n## 🖥️ Editor Setup\n\n### Visual Studio Code\n\n1. Install the [Beancount extension](https://marketplace.visualstudio.com/items?itemName=polarmutex.beancount-langserver) from the marketplace\n2. Configure in `settings.json` (optional):\n   ```json\n   {\n     // Optional: Only needed for multi-file projects with include directives\n     \"beancountLangServer.journalFile\": \"/path/to/main.beancount\",\n     \"beancountLangServer.formatting\": {\n       \"prefix_width\": 30,\n       \"currency_column\": 60,\n       \"number_currency_spacing\": 1\n     },\n     // Optional: flags that generate warnings (default: [\"!\"])\n     \"beancountLangServer.diagnosticFlags\": [\"!\"]\n   }\n   ```\n\n**Workspace-specific configuration**: Create a `.vscode/settings.json` in each project folder:\n\n```json\n{\n  \"beancountLangServer.journalFile\": \"${workspaceFolder}/main.beancount\"\n}\n```\n\nThis ensures each workspace uses its own journal file for completions and diagnostics.\n\n### Neovim\n\nUsing `nvim.lsp` (nvim \u003e 0.11)\n\n`lsp/beancount.lua`\n\n```lua\nreturn {\n    commands = { \"beancount-language-server\", \"--stdio\" },\n    root_markers = { \"main.bean\", \".git\" },\n    -- init_options are optional\n    init_options = {\n        -- Optional: Only needed for multi-file projects with include directives\n        journal_file = \"main.bean\",\n        -- Optional: flags that generate warnings (default: [\"!\"])\n        diagnostic_flags = { \"!\" },\n    },\n    settings = {\n        beancount = {\n            formatting = {\n                prefix_width = 30,\n                currency_column = 60,\n                number_currency_spacing = 1,\n            }\n        }\n    }\n}\n```\n\nUsing [nvim-lspconfig](https://github.com/neovim/nvim-lspconfig):\n\n```lua\nlocal lspconfig = require('lspconfig')\n\nlspconfig.beancount.setup({\n  -- All init_options are optional\n  init_options = {\n    -- Optional: Only needed for multi-file projects with include directives\n    -- journal_file = \"/path/to/main.beancount\",\n    formatting = {\n      prefix_width = 30,\n      currency_column = 60,\n      number_currency_spacing = 1,\n    },\n    -- Optional: flags that generate warnings (default: {\"!\"})\n    diagnostic_flags = { \"!\" },\n  },\n})\n\n-- To override auto-detected checker method:\n-- lspconfig.beancount.setup({\n--   init_options = {\n--     bean_check = {\n--       method = \"system\",  -- Force specific method: \"python-embedded\", \"python-system\", or \"system\"\n--     },\n--   },\n-- })\n```\n\n**File type detection**: Ensure beancount files are detected. Add to your config:\n\n```lua\nvim.filetype.add({\n  extension = {\n    beancount = \"beancount\",\n    bean = \"beancount\",\n  },\n})\n```\n\n**Workspace-specific configuration**: Use `.nvim.lua` or `exrc` for per-project settings:\n\n```lua\n-- .nvim.lua in your beancount project root\nvim.lsp.config.beancount = {\n  init_options = {\n    journal_file = vim.fn.getcwd() .. \"/main.beancount\",\n  },\n}\n```\n\nOr with nvim-lspconfig, use `on_new_config` to dynamically set the journal file:\n\n```lua\nlspconfig.beancount.setup({\n  on_new_config = function(new_config, new_root_dir)\n    new_config.init_options = new_config.init_options or {}\n    new_config.init_options.journal_file = new_root_dir .. \"/main.beancount\"\n  end,\n})\n```\n\n### Helix\n\nAdd to your `languages.toml`:\n\n```toml\n[language-server.beancount-language-server]\ncommand = \"beancount-language-server\"\nargs = [\"--stdio\"]\n\n# Configuration is optional\n[language-server.beancount-language-server.config]\n# Optional: Only needed for multi-file projects with include directives\n# journal_file = \"/path/to/main.beancount\"\n\n# Optional: bean_check config (uses python-embedded by default)\n# [language-server.beancount-language-server.config.bean_check]\n# method = \"python-embedded\"  # or \"python-system\" or \"system\"\n\n# Optional: formatting configuration\n[language-server.beancount-language-server.config.formatting]\nprefix_width = 30\ncurrency_column = 60\nnumber_currency_spacing = 1\n\n[[language]]\nname = \"beancount\"\nlanguage-servers = [{ name = \"beancount-language-server\" }]\n```\n\n### Zed\n\nAdd to your `settings.json` (access via `Zed \u003e Settings \u003e Open Settings`):\n\n```json\n{\n  \"lsp\": {\n    \"beancount-language-server\": {\n      \"binary\": {\n        \"path\": \"beancount-language-server\",\n        \"arguments\": [\"--stdio\"]\n      },\n      \"initialization_options\": {\n        // Optional: Only needed for multi-file projects with include directives\n        \"journal_file\": \"/path/to/main.beancount\",\n        \"formatting\": {\n          \"prefix_width\": 30,\n          \"currency_column\": 60,\n          \"number_currency_spacing\": 1\n        }\n      }\n    }\n  },\n  \"languages\": {\n    \"Beancount\": {\n      \"language_servers\": [\"beancount-language-server\"]\n    }\n  }\n}\n```\n\nFor **workspace-specific configuration**, create a `.zed/settings.json` in your project root:\n\n```json\n{\n  \"lsp\": {\n    \"beancount-language-server\": {\n      \"initialization_options\": {\n        \"journal_file\": \"main.beancount\"\n      }\n    }\n  }\n}\n```\n\n**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.\n\n### Emacs\n\nUsing [lsp-mode](https://github.com/emacs-lsp/lsp-mode):\n\n```elisp\n(use-package lsp-mode\n  :hook (beancount-mode . lsp-deferred)\n  :config\n  (lsp-register-client\n   (make-lsp-client\n    :new-connection (lsp-stdio-connection \"beancount-language-server\")\n    :major-modes '(beancount-mode)\n    :server-id 'beancount-language-server\n    :initialization-options\n    ;; All options are optional\n    (lambda () (list\n                ;; Optional: Only needed for multi-file projects with include directives\n                ;; :journal_file \"/path/to/main.beancount\"\n                ;; Optional: bean_check config (uses python-embedded by default)\n                ;; :bean_check '(:method \"python-embedded\")\n                :formatting '(:prefix_width 30 :currency_column 60 :number_currency_spacing 1))))))\n```\n\n**Workspace-specific configuration**: Use `.dir-locals.el` in your project root:\n\n```elisp\n;; .dir-locals.el\n((beancount-mode\n  . ((lsp-clients-beancount-langserver-init-options\n      . (:journal_file \"./main.beancount\")))))\n```\n\nOr dynamically set based on project root:\n\n```elisp\n(defun my/beancount-lsp-init-options ()\n  \"Generate init options with project-local journal file.\"\n  (let ((journal-file (expand-file-name \"main.beancount\" (project-root (project-current)))))\n    (when (file-exists-p journal-file)\n      (list :journal_file journal-file))))\n\n;; Use in lsp-register-client with :initialization-options #'my/beancount-lsp-init-options\n```\n\n### Vim\n\nUsing [vim-lsp](https://github.com/prabirshrestha/vim-lsp):\n\n```vim\nif executable('beancount-language-server')\n    au User lsp_setup call lsp#register_server({\n        \\ 'name': 'beancount-language-server',\n        \\ 'cmd': {server_info-\u003e['beancount-language-server']},\n        \\ 'allowlist': ['beancount'],\n        \\ 'initialization_options': {\n        \\   'formatting': {\n        \\     'prefix_width': 30,\n        \\     'currency_column': 60,\n        \\     'number_currency_spacing': 1\n        \\   }\n        \\ }\n    \\ })\n    \" Optional: For multi-file projects with include directives, add:\n    \" \\   'journal_file': '/path/to/main.beancount',\n    \" Optional: To override default checker method, add:\n    \" \\   'bean_check': {'method': 'python-embedded'},\nendif\n```\n\n### Sublime Text\n\nUsing [LSP](https://packagecontrol.io/packages/LSP):\n\nAdd to LSP settings:\n\n```json\n{\n  \"clients\": {\n    \"beancount-language-server\": {\n      \"enabled\": true,\n      \"command\": [\"beancount-language-server\"],\n      \"selector\": \"source.beancount\",\n      // All initializationOptions are optional\n      \"initializationOptions\": {\n        // Optional: Only needed for multi-file projects with include directives\n        // \"journal_file\": \"/path/to/main.beancount\",\n        \"formatting\": {\n          \"prefix_width\": 30,\n          \"currency_column\": 60,\n          \"number_currency_spacing\": 1\n        }\n      }\n    }\n  }\n}\n```\n\n## 🏗️ Architecture\n\n### High-Level Overview\n\n```\n┌─────────────────┐    ┌─────────────────┐    ┌─────────────────┐\n│     Editor      │◄──►│  LSP Server     │◄──►│   Beancount     │\n│                 │    │                 │    │   (Python)      │\n│ - VSCode        │    │ - Completion    │    │ - Validation    │\n│ - Neovim        │    │ - Formatting    │    │ - Parsing       │\n│ - Helix         │    │ - Diagnostics   │    │ - Bean-check    │\n│ - Emacs         │    │ - Tree-sitter   │    │                 │\n└─────────────────┘    └─────────────────┘    └─────────────────┘\n```\n\n### Core Components\n\n- **LSP Server**: Main Rust application handling LSP protocol\n- **Tree-sitter Parser**: Fast, incremental parsing of Beancount syntax\n- **Completion Engine**: Smart autocompletion with context awareness\n- **Diagnostic Provider**: Multi-method validation system with pluggable checkers\n- **Bean-check Integration**: Three validation methods (system, python-embedded)\n- **Formatter**: Code formatting fully compatible with bean-format, supporting prefix-width, num-width, and currency-column options\n\n### Project Structure\n\n```\nbeancount-language-server/\n├── crates/lsp/           # Main LSP server implementation\n│   ├── src/\n│   │   ├── handlers.rs   # LSP request/notification handlers\n│   │   ├── providers/    # Feature providers (completion, diagnostics, etc.)\n│   │   ├── checkers/     # Bean-check validation implementations\n│   │   │   ├── mod.rs    # Strategy trait and factory pattern\n│   │   │   ├── system_call.rs     # Traditional bean-check binary\n│   │   │   ├── pyo3_embedded.rs   # PyO3 embedded Python\n│   │   │   └── types.rs           # Shared data structures\n│   │   └── server.rs     # Core LSP server logic\n├── vscode/               # VS Code extension\n└── flake.nix            # Nix development environment\n```\n\n## 🛠️ Development\n\n### Prerequisites\n\n- **Rust** (stable toolchain)\n- **Python** with beancount\n- **Node.js** (for VS Code extension)\n\n### Development Environment\n\n**Using Nix (Recommended):**\n\n```bash\nnix develop\n```\n\n**Manual Setup:**\n\n```bash\n# Install Rust dependencies\ncargo build\n\n# Install Node.js dependencies (for VS Code extension)\ncd vscode \u0026\u0026 pnpm install\n\n# Install development tools\ncargo install cargo-watch\n```\n\n### Running Tests\n\n```bash\n# Run all tests\ncargo test\n\n# Run with coverage\ncargo llvm-cov --all-features --locked --workspace --lcov --output-path lcov.info\n\n# Run tests with PyO3 feature\ncargo test --features python-embedded\n\n# Run specific test\ncargo test test_completion\n```\n\n### Code Quality\n\n```bash\n# Format code\ncargo fmt\n\n# Lint code\ncargo clippy --all-targets --all-features\n\n# Check formatting\ncargo fmt -- --check\n```\n\n### Development Workflow\n\n1. **Make changes** to the Rust code\n2. **Test locally** with `cargo test`\n3. **Run LSP server** in development mode:\n   ```bash\n   cargo run --bin beancount-language-server\n   ```\n4. **Test with editor** by configuring it to use the local binary\n\n### VS Code Extension Development\n\n```bash\ncd vscode\npnpm run build      # Build extension\npnpm run watch      # Watch for changes\npnpm run package    # Package extension\n```\n\n### Release Process\n\n1. **Tag a release**: `git tag v1.0.0 \u0026\u0026 git push --tags`\n2. **GitHub Actions** automatically builds and publishes:\n   - Binaries for all supported platforms\n   - Crates.io release\n   - GitHub release with assets\n\n## 🤝 Contributing\n\nContributions are welcome! Here are some ways to help:\n\n### 🐛 Bug Reports\n\n- Search existing issues first\n- Include beancount file examples that trigger the bug\n- Provide editor and OS information\n\n### 💡 Feature Requests\n\n- Check the [planned features](#-planned-features) list\n- Describe the use case and expected behavior\n- Consider the LSP specification constraints\n\n### 🔧 Code Contributions\n\n1. **Fork** the repository\n2. **Create** a feature branch (`git checkout -b feature/amazing-feature`)\n3. **Make** your changes with tests\n4. **Ensure** code quality: `cargo fmt \u0026\u0026 cargo clippy \u0026\u0026 cargo test`\n5. **Commit** your changes (`git commit -m 'Add amazing feature'`)\n6. **Push** to the branch (`git push origin feature/amazing-feature`)\n7. **Open** a Pull Request\n\n### 🎯 Good First Issues\n\nLook for issues labeled `good-first-issue`:\n\n- Add new completion types\n- Improve error messages\n- Add editor configuration examples\n- Improve documentation\n\n## 📚 Resources\n\n- **[Beancount Documentation](https://beancount.github.io/)**\n- **[Language Server Protocol Specification](https://microsoft.github.io/language-server-protocol/)**\n- **[Tree-sitter Beancount Grammar](https://github.com/polarmutex/tree-sitter-beancount)**\n- **[VSCode Extension API](https://code.visualstudio.com/api)**\n\n## 📄 License\n\nThis project is licensed under the MIT License - see the [LICENSE](LICENSE) file for details.\n\n## 🙏 Acknowledgments\n\n- **[Beancount](https://github.com/beancount/beancount)** - The amazing double-entry bookkeeping language\n- **[Tree-sitter](https://tree-sitter.github.io/)** - Incremental parsing framework\n- **[LSP](https://microsoft.github.io/language-server-protocol/)** - Language Server Protocol specification\n- **[Twemoji](https://github.com/twitter/twemoji)** - Emoji graphics used in the icon\n\n---\n\n\u003cp align=\"center\"\u003e\n  \u003cstrong\u003eHappy Beancounting! 📊✨\u003c/strong\u003e\n\u003c/p\u003e\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolarmutex%2Fbeancount-language-server","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fpolarmutex%2Fbeancount-language-server","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fpolarmutex%2Fbeancount-language-server/lists"}