Function: org-cite-adjust-note

org-cite-adjust-note is a byte-compiled function defined in oc.el.gz.

Signature

(org-cite-adjust-note CITATION INFO &optional RULE PUNCT)

Documentation

Adjust note number location for CITATION object, and punctuation around it.

INFO is the export state, as a property list.

Optional argument RULE is the punctuation rule used, as a triplet. When nil, rule is determined according to org-cite-note-rules, which see.

Optional argument PUNCT is a list of punctuation marks to be considered. When nil, it defaults to org-cite-punctuation-marks.

Parse tree is modified by side-effect.

Note: when calling both org-cite-adjust-note and org-cite-wrap-citation on the same object, call org-cite-adjust-note first.

Source Code

;; Defined in /usr/src/emacs/lisp/org/oc.el.gz
(defun org-cite-adjust-note (citation info &optional rule punct)
  "Adjust note number location for CITATION object, and punctuation around it.

INFO is the export state, as a property list.

Optional argument RULE is the punctuation rule used, as a triplet.  When nil,
rule is determined according to `org-cite-note-rules', which see.

Optional argument PUNCT is a list of punctuation marks to be considered.
When nil, it defaults to `org-cite-punctuation-marks'.

Parse tree is modified by side-effect.

Note: when calling both `org-cite-adjust-note' and `org-cite-wrap-citation' on
the same object, call `org-cite-adjust-note' first."
  (when org-cite-adjust-note-numbers
    (pcase-let* ((rule (or rule (org-cite--get-note-rule info)))
                 (punct-re (regexp-opt (or punct org-cite-punctuation-marks)))
                 ;; with Emacs <27.1. Argument of `regexp' form (PUNCT-RE this case)
                 ;; must be a string literal.
                 (previous-punct-re
                  (rx-to-string `(seq (opt (group (regexp ,(rx (0+ (any blank ?\n))))
                                                  (regexp ,punct-re)))
                                      (regexp ,(rx (opt (0+ (any blank ?\n)) (group ?\"))
                                                   (opt (group (1+ (any blank ?\n))))
                                                   string-end)))
                                t))
                 (next-punct-re
                  (rx-to-string `(seq string-start
                                      (group (0+ (any blank ?\n)) (regexp ,punct-re)))
                                t))
                 (next (org-export-get-next-element citation info))
                 (final-punct
                  (and (stringp next)
                       (string-match next-punct-re next)
                       (match-string 1 next)))
                 (previous
                  ;; Find the closest terminal object.  Consider
                  ;; citation, subscript and superscript objects as
                  ;; terminal.
                  (org-last
                   (org-element-map (org-export-get-previous-element citation info)
                       '(citation code entity export-snippet footnote-reference
                                  line-break latex-fragment link plain-text
                                  radio-target statistics-cookie timestamp
                                  verbatim)
                     #'identity info nil '(citation subscript superscript))))
                 (`(,punct ,quote ,spacing)
                  (and (stringp previous)
                       (string-match previous-punct-re previous)
                       (list (match-string 1 previous)
                             (match-string 2 previous)
                             (match-string 3 previous)))))
      ;; Bail you when there is no quote and either no punctuation, or
      ;; punctuation on both sides.
      (when (or quote (org-xor punct final-punct))
        ;; Phase 1: handle punctuation rule.
        (pcase rule
          ((guard (not quote)) nil)
          ;; Move punctuation inside.
          (`(,(or `inside (and `adaptive (guard (not spacing)))) . ,_)
           ;; This only makes sense if there is a quotation before the
           ;; citation that does not end with some punctuation.
           (when (and (not punct) final-punct)
             ;; Quote guarantees there is a string object before
             ;; citation.  Likewise, any final punctuation guarantees
             ;; there is a string object following citation.
             (let ((new-prev
                    (replace-regexp-in-string
                     previous-punct-re
                     (concat final-punct "\"") previous nil nil 2))
                   (new-next
                    (replace-regexp-in-string
                     ;; Before Emacs-27.1 `literal' `rx' form with a variable
                     ;; as an argument is not available.
                     (rx-to-string `(seq string-start ,final-punct) t)
                     "" next)))
               (org-element-set-element previous new-prev)
               (org-element-set-element next new-next)
               (setq previous new-prev)
               (setq next new-next)
               (setq punct final-punct)
               (setq final-punct nil))))
          ;; Move punctuation outside.
          (`(,(or `outside (and `adaptive (guard spacing))) . ,_)
           ;; This is only meaningful if there is some inner
           ;; punctuation and no final punctuation already.
           (when (and punct (not final-punct))
             ;; Inner punctuation guarantees there is text object
             ;; before the citation.  However, there is no information
             ;; about the object following citation, if any.
             ;; Therefore, we handle all the possible cases (string,
             ;; other type, or none).
             (let ((new-prev
                    (replace-regexp-in-string
                     previous-punct-re "" previous nil nil 1))
                   (new-next (if (stringp next) (concat punct next) punct)))
               (org-element-set-element previous new-prev)
               (cond
                ((stringp next)
                 (org-element-set-element next new-next))
                (next
                 (org-element-insert-before new-next next))
                (t
                 (org-element-adopt-elements
                     (org-element-property :parent citation)
                   new-next)))
               (setq previous new-prev)
               (setq next new-next)
               (setq final-punct punct)
               (setq punct nil))))
          (_
           (error "Invalid punctuation rule: %S" rule))))
      ;; Phase 2: move citation to its appropriate location.
      ;;
      ;; First transform relative citation location into a definitive
      ;; location, according to the surrounding punctuation.
      (pcase rule
        (`(,punctuation same ,order)
         (setf rule
               (list punctuation
                     (cond
                      ;; When there is punctuation on both sides, the
                      ;; citation is necessarily on the outside.
                      ((and punct final-punct) 'outside)
                      (punct 'inside)
                      (final-punct 'outside)
                      ;; No punctuation: bail out on next step.
                      (t nil))
                     order))))
      (pcase rule
        (`(,_ nil ,_) nil)
        (`(,_ inside after)
         ;; Citation has to be moved after punct, if there is
         ;; a quotation mark, or after final punctuation.
         (cond
          (quote
           (org-cite--insert-at-split previous citation 2 previous-punct-re))
          (final-punct
           (org-cite--move-punct-before final-punct citation next info))
          ;; There is only punct, and we're already after it.
          (t nil)))
        (`(,_ inside before)
         ;; Citation is already behind final-punct, so only consider
         ;; other locations.
         (when (or punct quote)
           (org-cite--insert-at-split previous citation 0 previous-punct-re)))
        (`(,_ outside after)
         ;; Citation is already after any punct or quote.  It can only
         ;; move past final punctuation, if there is one.
         (when final-punct
           (org-cite--move-punct-before final-punct citation next info)))
        (`(,_ outside before)
         ;; The only non-trivial case is when citation follows punct
         ;; without a quote.
         (when (and punct (not quote))
           (org-cite--insert-at-split previous citation 0 previous-punct-re)))
        (_
         (error "Invalid punctuation rule: %S" rule))))))