Skip to content
rputikarPublic

About

Rust language server that puts a live Zotero library into an editor alongside whichever server already owns the document.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Latest commit

Β 

History

3 Commits

Folders and files

Repository files navigation

ibid β€” Fast Citation Language Server for Zotero & Better BibTeX

ibid is a high-performance, editor-agnostic Language Server Protocol (LSP) daemon written in Rust. It integrates your live Zotero library directly into your text editor alongside whichever language server already understands your document, providing lightning-fast autocompletion, rich hover cards, citekey diagnostics with quickfix imports, and native Zotero Citation-As-You-Write (CAYW) picker dialogs.


🌟 Why ibid?

  1. True Coexistence, Zero UI Clutter: ibid is designed as an auxiliary language server. It coexists cleanly with primary language servers like tinymist (Typst), texlab (LaTeX), and marksman (Markdown). When an incumbent server manages local .bib completion, ibid seamlessly defers local items and provides your live remote Zotero library candidates without duplicate completion entries.
  2. Sub-Millisecond Speed: In-memory bibliography indexing and token-based search provide autocompletion responses in $< 50\text{ ms}$ under live editing, and instant $0\text{ ms}$ fast-path responses when offline.
  3. Resilient & Idempotent: A fault-tolerant BibTeX parser with boundary chunk recovery ensures that malformed syntax in draft documents does not take down your completion engine.
  4. Clean Import Pipeline: When you accept a Zotero completion candidate or trigger a quickfix code action, ibid fetches the full BibLaTeX entry via Better BibTeX's export translator and atomically appends it to your workspace .bib file with collision avoidance.
  5. Universal Client Support: First-class support for Zed (zed-ibid), Neovim (ibid.nvim), Helix, and standard LSP clients.

πŸ“– Supported Languages & Citation Syntaxes

ibid includes dedicated, zero-dependency syntactic parsers for all major academic writing formats:

Language Recognized Citation Patterns Supported Incumbents
Markdown / Pandoc / Quarto / RMarkdown [@key], @key, [-@key; @key2, p. 42], key: [@value] marksman
Typst @key, <key>, #cite(<key>), #bibliography("refs.bib") tinymist
LaTeX \cite{key}, \citep{key}, \parencite[42]{key}, \addbibresource{refs.bib} texlab
Plain Text @key None (Owned)

πŸš€ Key Features

1. Hybrid In-Memory & Live Zotero Autocompletion

  • Combines local workspace .bib citations with live search results from Better BibTeX (BBT).
  • Implements AND token filtering with smart prefix matching across citekeys, titles, authors, and publication years.
  • If Zotero is closed or unreachable, autocompletion falls back instantaneously to local files with zero latency penalties.

2. Rich CSL Hover Previews

  • Hovering over @citekey displays a beautifully formatted Markdown card with Title, Authors, Year, Journal/Container, DOI, and Citation Count.
  • Remote Zotero items indicate their library origin.

3. Diagnostics & 1-Click Code Action Imports

  • Unresolved citekeys are flagged with descriptive diagnostics:
    • "Unknown citation '@citekey' (available in Zotero library)" (if present in Zotero).
    • "Unknown citation '@citekey'" (if unknown everywhere).
  • Provides an LSP Code Action (quickfix) to immediately import the entry into your workspace bibliography.

4. Native Zotero CAYW (Citation-As-You-Write)

  • Trigger :ZoteroCite / zotero.cayw to open Zotero’s native red citation picker dialog.
  • Selected citations are formatted per your document's language and inserted at your cursor.
  • Citekeys present in the returned citation are automatically imported into your workspace .bib file in the background.
  • Built-in single-flight concurrency lock prevents duplicate picker windows from wedging Zotero.

5. Go-to-Definition

  • Pressing gd on a citation key in Markdown or Plain Text jumps directly to the corresponding entry definition inside your workspace .bib file.

βš™οΈ Incumbent Coexistence Model (ADR-05)

To prevent UI duplication (e.g. duplicate completion entries or competing diagnostics), ibid implements a 3-tier deferral resolution ladder for each document language:

Layer 1 (Highest): Explicit user array in settings (e.g. "deferToIncumbent": ["typst"])
        β”‚ (if absent or "auto")
Layer 2: Adaptive client detection (Neovim LspAttach / Zed which probe)
        β”‚ (if detection yields no attached incumbents)
Layer 3 (Fallback): Static default fallback ["typst", "latex"]

Feature Behavior by Language Tier:

Feature Owned Languages (Markdown, Text) Deferred Languages (tinymist / texlab present)
Local .bib Completion βœ… Served by ibid ⏭️ Deferred to incumbent
Remote Zotero Completion βœ… Served by ibid βœ… Served by ibid
Hover on Local Key βœ… Served by ibid ⏭️ Deferred to incumbent
Hover on Remote Zotero Key βœ… Served by ibid βœ… Served by ibid
Unknown Citekey Diagnostic βœ… Emitted by ibid ⏭️ Deferred to incumbent
Code Action (quickfix import) βœ… Provided by ibid ⏭️ Deferred (use :ZoteroImport or accept completion)
Go-to-Definition (gd) βœ… Jump to .bib ⏭️ Handled by incumbent
Write Operations (CAYW / Import) βœ… Unconditional βœ… Unconditional (always active)

πŸ› οΈ Installation

Pre-built Binaries

Download the matching binary for your platform from GitHub Releases:

Platform Target Asset
macOS (Apple Silicon) ibid-aarch64-apple-darwin
macOS (Intel) ibid-x86_64-apple-darwin
Linux (x86_64) ibid-x86_64-unknown-linux-gnu
Linux (ARM64) ibid-aarch64-unknown-linux-gnu
Windows (x86_64) ibid-x86_64-pc-windows-msvc.exe

Place the binary on your system $PATH as ibid (or ibid.exe).

Build from Source

git clone https://github.com/r11r/ibid.git
cd ibid
cargo install --path crates/ibid --locked

πŸ”§ Editor Configuration

1. Zed Editor

Install the "Ibid β€” Zotero citations" extension from the Zed extensions gallery (or use zed-ibid).

Add to your Zed settings.json:

{
  "lsp": {
    "ibid": {
      "settings": {
        "bbt": {
          "host": "127.0.0.1",
          "port": 23119
        },
        "bibFile": "references.bib",
        "deferToIncumbent": "auto",
        "unknownCitekeySeverity": "warning"
      }
    }
  }
}

Optional CAYW keybinding in keymap.json:

[
  {
    "context": "Editor && (mode == full)",
    "bindings": {
      "ctrl-alt-z": [
        "editor::ExecuteCommand",
        {
          "command": "zotero.cayw"
        }
      ]
    }
  }
]

2. Neovim

Use ibid.nvim with your favorite plugin manager (e.g. lazy.nvim):

{
  "r11r/ibid.nvim",
  ft = { "markdown", "quarto", "rmd", "typst", "tex", "plaintex", "text" },
  opts = {
    settings = {
      bibFile = "references.bib",
      deferToIncumbent = "auto",
      unknownCitekeySeverity = "warning",
    },
  },
  keys = {
    { "<C-A-z>", "<Plug>(ibid-cite)", mode = { "n", "i" }, desc = "Zotero CAYW Cite" },
  },
}

Run :checkhealth ibid to verify server status, Better BibTeX port connectivity, and completion engine capability.


3. Helix Editor

Add ibid as an auxiliary language server in ~/.config/helix/languages.toml:

[language-server.ibid]
command = "ibid"

[[language]]
name = "markdown"
language-servers = ["marksman", "ibid"]

[[language]]
name = "typst"
language-servers = ["tinymist", "ibid"]

[[language]]
name = "latex"
language-servers = ["texlab", "ibid"]

To import a citekey under your cursor in Helix, use Space + a (Code Actions) on the unknown citation diagnostic.


βš™οΈ LSP Settings Reference

All settings can be forwarded under the ibid initialization options or via workspace/didChangeConfiguration:

Key Type Default Description
bibFile string null Primary target .bib filename (e.g. "references.bib", "main.bib"). If null, ibid scans the workspace.
bbt.host string "127.0.0.1" Better BibTeX JSON-RPC host.
bbt.port number 23119 Better BibTeX JSON-RPC port.
bbt.searchTimeoutMs number 150 Maximum wait time for live Zotero autocompletion requests.
bbt.exportTimeoutMs number 2000 Timeout for BibLaTeX item exports during import.
bbt.probeTimeoutMs number 150 Timeout for health checks.
bbt.translator string "Better BibLaTeX" Export translator ("Better BibLaTeX" or "Better BibTeX").
caywFormat string "auto" CAYW output format ("auto", "typst", "latex", "pandoc", "citekey").
deferToIncumbent string | string[] "auto" Incumbent deferral policy ("auto", [], or explicit language list like ["typst"]).
unknownCitekeySeverity string "warning" Severity for unknown citekeys ("warning", "error", "information", "hint", "off").

πŸ—οΈ Architecture & Codebase Layout

The project is structured as a pure-library / async-server workspace:

ibid/
β”œβ”€β”€ crates/
β”‚   β”œβ”€β”€ ibid-core/       # Pure, zero-IO domain crate (WebAssembly/no-std ready)
β”‚   β”‚   β”œβ”€β”€ src/bib/     # Hayagriva-backed resilient parser, search index, atomic writer
β”‚   β”‚   β”œβ”€β”€ src/context/ # Syntactic citation context detection (Typst, LaTeX, Markdown, Text)
β”‚   β”‚   └── src/policy/  # Incumbent deferral logic (ADR-05)
β”‚   └── ibid/            # Async LSP binary crate (tower-lsp, tokio, reqwest)
β”‚       β”œβ”€β”€ src/bbt/     # Better BibTeX JSON-RPC client, health FSM, version gate
β”‚       β”œβ”€β”€ src/backend/ # LSP request handlers, document position mapping, CAYW runner
β”‚       └── src/main.rs  # Stdio server entry point
β”œβ”€β”€ projects/
β”‚   β”œβ”€β”€ zed-ibid/        # Zed WASM extension (zed_extension_api = "0.7.0")
β”‚   └── ibid.nvim/       # Neovim Lua plugin (0.10+ / 0.11+)
└── docs/                # Architecture Decision Records (ADRs) & PRDs

Invariants:

  • ibid-core Purity Gate: ibid-core has zero dependencies on async runtimes (tokio), networking (reqwest), or LSP transport (tower-lsp). All business logic, parsing, and data models remain purely synchronous and unit-testable.
  • Fast-Path Offline Bail: In steady-state offline mode, the health state machine guarantees that autocompletion never performs synchronous I/O or blocks the editor thread.

πŸ§ͺ Development & Testing

Run all unit and integration test suites:

# Format check
cargo fmt --all -- --check

# Strict lint check
cargo clippy --workspace --all-targets -- -D warnings

# Run all 40 workspace tests (includes stdio wiremock integration tests)
cargo test --workspace

# Check core crate purity gate
cargo tree -p ibid-core -e normal | grep -E '(tokio|reqwest|tower-lsp)' && exit 1 || echo "Purity gate OK"

πŸ“„ License

Licensed under either of:

at your option.

About

Rust language server that puts a live Zotero library into an editor alongside whichever server already owns the document.

Resources

Stars

0 stars

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages