Skip to content

Instantly share code, notes, and snippets.

@LorenRiccie
Created June 11, 2026 19:39
Show Gist options
  • Select an option

  • Save LorenRiccie/59424c6646cfd7f1f01ac98ca49261a5 to your computer and use it in GitHub Desktop.

Select an option

Save LorenRiccie/59424c6646cfd7f1f01ac98ca49261a5 to your computer and use it in GitHub Desktop.
Fix for org-cite-overlay: locator label dropped when rendering citations with page suffix
#+begin_src emacs-lisp
;;; org-cite-overlay-locator-fix.el --- Fix locator rendering in org-cite-overlay
;; This patch fixes a rendering issue in org-cite-overlay' where citations ;; with locators (e.g. [cite:@dupont2012 p. 45]) are rendered without the ;; page label (e.g. "(Dupont 2012, 45)" instead of "(Dupont 2012, p. 45)"). ;; ;; The issue is in org-cite-overlay--citation-to-citeproc': the suffix is
;; passed as a raw string to citeproc, bypassing CSL formatting. Citeproc
;; never receives a structured locator, so the page label is dropped.
;;
;; This fix extracts the locator label and value from the suffix string,
;; normalizes them to the canonical English labels expected by citeproc,
;; and passes them as proper :label' and :locator' arguments to
;; `citeproc-citation-create', so that the CSL style can render them
;; correctly (e.g. "p." in French locales).
;;
;; Reported to the maintainer at ~swflint/emacs-utilities@lists.sr.ht.
(defun my/org-cite-overlay--parse-locator (suffix)
"Extract locator label and value from SUFFIX string.
Returns a plist with :label and :locator, or nil if no locator found.
Custom addition to org-cite-overlay' to fix locator rendering: without this, suffixes like p. 1' are passed as raw strings to citeproc, which
skips CSL formatting and omits the page label. This function normalizes
locator prefixes (e.g. p.', pp.', page') to the canonical English labels expected by citeproc (e.g. page'), so that the CSL style can
render them correctly (e.g. `p. 1' in French locales)."
(when suffix
(let ((locator-regexp
(rx string-start
(* space)
(group (or "p." "pp." "page" "pages" "col." "figure"
"fig." "folio" "number" "no." "line" "l."
"note" "n." "opus" "op." "paragraph" "para."
"part" "section" "sec." "sub verbo" "verse"
"vol."))
(* space)
(group (+ (any digit "-–—")))))
(label-map '(("p." . "page")
("pp." . "page")
("page" . "page")
("pages" . "page")
("col." . "column")
("figure" . "figure")
("fig." . "figure")
("folio" . "folio")
("number" . "number")
("no." . "number")
("line" . "line")
("l." . "line")
("note" . "note")
("n." . "note")
("opus" . "opus")
("op." . "opus")
("paragraph" . "paragraph")
("para." . "paragraph")
("part" . "part")
("section" . "section")
("sec." . "section")
("sub verbo" . "sub verbo")
("verse" . "verse")
("vol." . "volume"))))
(when (string-match locator-regexp suffix)
(list :label (cdr (assoc (match-string 1 suffix) label-map))
:locator (match-string 2 suffix))))))
(defun my/org-cite-overlay--citation-to-citeproc (citation)
"Like `org-cite-overlay--citation-to-citeproc' but with locator extraction."
(apply #'citeproc-citation-create
(append
(list
:cites
(org-element-map citation 'citation-reference
(lambda (cite)
(let* ((suffix
(and (org-element-property :suffix cite)
(org-element-interpret-data
(org-element-property :suffix cite))))
(parsed
(my/org-cite-overlay--parse-locator suffix))
(clean-suffix
(if parsed nil suffix)))
(cl-remove-if
#'null
(list
(cons 'id (org-element-property :key cite))
(and (org-element-property :prefix cite)
(cons 'prefix
(org-element-interpret-data
(org-element-property :prefix cite))))
(and clean-suffix
(cons 'suffix clean-suffix))
(and parsed
(cons 'label (plist-get parsed :label)))
(and parsed
(cons 'locator (plist-get parsed :locator))))
:key #'cdr)))))
(org-cite-csl--create-structure-params citation nil))))
(advice-add 'org-cite-overlay--citation-to-citeproc
:override #'my/org-cite-overlay--citation-to-citeproc)
;;; org-cite-overlay-locator-fix.el ends here
#+end_src
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment