1

The context for this is that I was trying to write a function to help me write LaTeX, specifically I'd like to list all the future references, i.e. when you use a \ref{<something>} before \label{<something>}. I managed to write a regex that searches for this pattern, and my attempt is:

(defun get-forward-refs ()
  "List in an occur buffer all the future references of the current file."
  (interactive)
  (occur
   (rx (regex "\\ref{") (group (+ not-newline)) "}"
       (+ anything)
       (regex "\\label{") (backref 1) "}")
   ))

It works, but occur annoyingly displays ALL the match, which in this case could span several lines, so that I cannot quickly navigate the list (which was the purpose of this). The docstring of occur explicitly says "If a match spreads across multiple lines, all those lines are shown.". My question is: can I tweak this behavior, so that occur shows only the first line of the match? Thanks.

2 Answers 2

2
(add-hook 'occur-mode-hook
          (lambda ()
            (setq-local outline-regexp "^[[:blank:]]*[[:digit:]]+:"
                        outline-level (lambda ()
                                        1))
            (outline-minor-mode)

            ;; I believe you know how n/p works.
            (keymap-local-set "p"
                              (lambda (n)
                                (interactive "p")
                                (dotimes (_ n)
                                  (execute-kbd-macro (kbd "C-a"))
                                  (previous-error-no-select))))
            (keymap-local-set "n"
                              (lambda (n)
                                (interactive "p")
                                (dotimes (_ n)
                                  (execute-kbd-macro (kbd "C-e"))
                                  (next-error-no-select))))

            ;; To be honest, I don't know why 
            ;; `make-thread` is necessary here.
            (make-thread (lambda ()
                           (thread-yield)
                           (outline-hide-sublevels 1)))))
6
  • Thanks! So, IIUC, occur by itself doesn't feature this, but you can force this behavior by using outline-mode? Also, like this I need two presses of n/p to navigate the results: is this a feature of outline-mode? Is there a way to have only one key press needed? Aug 19, 2023 at 11:08
  • 1
    @AlessandroBertulli: "is this a feature of outline-mode?" -- The first n moves the cursor to the end of the first line, and the second one moves over the .... The ... is a feature of outline so you should press n twice. ||| "Is there a way to have only one key press needed?" -- See my updated answer.
    – shynur
    Aug 19, 2023 at 14:19
  • 1
    @AlessandroBertulli: "occur by itself doesn't feature this" -- I tried my best to find whether occur provides such a feature, but found nothing.
    – shynur
    Aug 19, 2023 at 14:25
  • It works! Thanks you very much! Btw this is a bit over my Elisp knowledge, I'll have a look at outline-mode, local keymaps and threads Aug 20, 2023 at 15:45
  • @AlessandroBertulli: BTW, are you sure it is correct to use "\\ref{"? I think you want "\\\\ref{". You might want to take a look at the elisp manual ;-)
    – shynur
    Aug 20, 2023 at 16:37
0

Without really looking into your problem, maybe this helps.

This is your regexp in Lisp, after removing the rx noise ;-):

"\\(?:\\ref{\\)\\(.+\\)}[^z-a]+\\(?:\\label{\\)\\1}"

[^z-a] matches newline chars. I guess that corresponds to your use of anything. If you don't want to match stuff over multiple lines, then you likely don't really want to match newline chars.

1
  • Thanks, but I do need to match over newlines, because in my document the \ref and the \label can be several lines away Aug 18, 2023 at 16:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.