feat(citations): add Org 9.5 citation support with BibTeX source, completions, and go-to-source#1113
feat(citations): add Org 9.5 citation support with BibTeX source, completions, and go-to-source#1113NickHu wants to merge 4 commits intonvim-orgmode:masterfrom
Conversation
|
I created a new release of the TS parser (https://github.com/nvim-orgmode/tree-sitter-org/releases/tag/2.0.3). |
|
@kristijanhusak rebased onto master and tests passing |
There was a problem hiding this comment.
Pull request overview
Adds Org mode 9.5 citation support to the Neovim orgmode plugin, including BibTeX-backed key discovery, omnifunc completion, syntax highlighting, and “go to bibliography entry” behavior via the existing org_open_at_point mapping.
Changes:
- Introduces a new
OrgCitationssubsystem with a built-in BibTeX source and extensible custom source API. - Adds citation key omnifunc completion plus
#+bibliographydirective completion. - Adds citation highlighting, documentation, tests/fixtures, and bumps the required tree-sitter-org grammar version.
Reviewed changes
Copilot reviewed 18 out of 18 changed files in this pull request and generated 5 comments.
Show a summary per file
| File | Description |
|---|---|
lua/orgmode/org/citations/init.lua |
New citations manager (source registration, item aggregation, follow, at-cursor resolution). |
lua/orgmode/org/citations/bibtex.lua |
Built-in BibTeX citation source (path discovery, parsing, mtime caching, follow-to-entry). |
lua/orgmode/org/citations/_meta.lua |
Type metadata for citation items/sources. |
lua/orgmode/org/autocompletion/sources/citations.lua |
Omnifunc completion source for citation keys inside [cite...]. |
lua/orgmode/org/autocompletion/sources/directives.lua |
Adds #+bibliography to directive completions. |
lua/orgmode/org/autocompletion/init.lua |
Wires citations into completion and registers the new completion source. |
lua/orgmode/org/mappings.lua |
Extends org_open_at_point to follow citation keys under cursor. |
lua/orgmode/init.lua |
Instantiates OrgCitations and passes it into mappings/completion. |
lua/orgmode/config/defaults.lua |
Adds default citations config keys (sources, org_cite_global_bibliography). |
queries/org/highlights.scm |
Adds highlight captures for citation nodes. |
lua/orgmode/colors/highlights.lua |
Maps new citation captures to existing highlight groups. |
lua/orgmode/utils/treesitter/install.lua |
Bumps required tree-sitter-org grammar version. |
docs/configuration.org |
Documents citation syntax, bibliography configuration, and custom sources (incl. Zotero example). |
tests/plenary/org/citations/citations_spec.lua |
Tests citations source registration, aggregation, and follow dispatch. |
tests/plenary/org/citations/bibtex_spec.lua |
Tests BibTeX parsing, bibliography discovery, follow behavior, and completion regex. |
tests/plenary/org/autocompletion_spec.lua |
Updates directive completion expectations for #+bibliography. |
tests/plenary/fixtures/citations/refs.bib |
BibTeX fixture used by tests. |
tests/plenary/fixtures/citations/extra.bib |
Additional BibTeX fixture used by tests. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
You can also share your feedback on Copilot code review. Take the survey.
| if raw:sub(1, 1) ~= '/' then | ||
| local base = base_dir or vim.fn.getcwd() | ||
| return vim.fn.fnamemodify(base .. '/' .. raw, ':p') | ||
| end |
| local file = self.files:load_file_sync(current_filename) | ||
| if file then | ||
| local file_dir = vim.fn.fnamemodify(file.filename, ':p:h') | ||
| local directives = file:_get_directive('bibliography', true) | ||
| if directives then | ||
| if type(directives) == 'string' then | ||
| directives = { directives } | ||
| end | ||
| for _, raw in ipairs(directives) do | ||
| add(raw, file_dir) | ||
| end |
| --- Build a simple in-memory citation source for testing. | ||
| ---@param name string | ||
| ---@param items OrgCitationItem[] | ||
| ---@param follow_handler? fun(key: string): boolean |
| for i, source in ipairs(config.citations.sources) do | ||
| if type(source.get_name) == 'function' then | ||
| self:add_source(source) | ||
| else | ||
| vim.notify(('Citation source at index %d must have a get_name method'):format(i), vim.log.levels.ERROR) |
| local function parse_file(path) | ||
| local stat = vim.uv.fs_stat(path) | ||
| if not stat then | ||
| return {} | ||
| end | ||
| local mtime_sec = stat.mtime.sec | ||
| local cached = _cache[path] | ||
| if cached and cached.mtime_sec == mtime_sec then | ||
| return cached.items | ||
| end | ||
| local lines = vim.fn.readfile(path) | ||
| local items = parse_bibtex(table.concat(lines, '\n')) | ||
| _cache[path] = { mtime_sec = mtime_sec, items = items } | ||
| return items |
Summary
This PR adds support for Citations, introduced by orgmode 9.5.
Related Issues
Depends on nvim-orgmode/tree-sitter-org#7 (this is why the tests fail)
Closes #718
Changes
lua/orgmode/org/citations/init.lua—OrgCitationsclass: registers sources, aggregatesget_items(), dispatchesfollow(key), and resolves the citation key at cursor via tree-sittercitation_referencenodelua/orgmode/org/citations/bibtex.lua— built-inOrgCitationBibtexsource; parses.bibfiles (mtime-cached), resolves paths fromcitations.org_cite_global_bibliographyconfig and file-local#+bibliography:directives, implementsfollow(key)to open the file at the entry linelua/orgmode/org/autocompletion/sources/citations.lua—omnifunccompletion source; matches[cite:@/[cite/style:@prefix and returns keys from all registered sourceslua/orgmode/config/defaults.lua— addscitations.org_cite_global_bibliographyandcitations.sourcesdefaultslua/orgmode/colors/highlighter/markup/citation.lua+queries/org/markup.scm— syntax highlighting for citation nodeslua/orgmode/org/mappings.lua—org_open_at_pointnow delegates tocitations:follow()when on a citation keydocs/configuration.org— newCitationssection covering syntax, bibliography config, custom source API, and Zotero Local API exampleChecklist
I confirm that I have:
Conventional Commits
specification (e.g.,
feat: add new feature,fix: correct bug,docs: update documentation).make test.Warning
The bulk of this PR is AI-generated, although I have combed over it extensively and cleaned it up by hand and fixed things.
It is basically exactly the changes you would expect to see from the PR title, except for the following design considerations:
lua/orgmode/org/citations/_meta.luaadds two fieldslabelanddescriptiontoOrgCitationItem, which currently aren't used anywhere; the hope is that these items can be utilised in the completion popup, but it seems like support for ancillary information in completion items is not fleshed out in nvim-orgmode yet as a whole. The intended use-case is so that the completion call/popup can show or react to something likeDoe, John 2026 Some Article(label) while still completing the key@doe2026, and LSP hover can display extra information (like an article abstract) from thedescriptionfield.I have tested it extensively, and I think it is ready for upstream review, but I am marking it as draft for the above reasons.