Subject: bug#76615: 14.0.9; error with amsmath style hooks

From: "Paul D. Nelson" <[email-masked]>
Date: Wed, 02 Apr 2025 22:29:31 +0200

Stefan Monnier <[email-masked]> writes:
>> @@ -389,7 +396,9 @@ reftex-TeX-master-file
>>       (t
>>        ;; Use buffer file name.
>>        (setq master (buffer-file-name))))
>> -    (expand-file-name master)))
>> +    (if reftex--suppress-nonfile-error
>> +        "<none>.tex"
>> +      (expand-file-name master))))
>
> I think TRT would be to return the buffer when in a non-file buffer and
> then to adjust callers accordingly.

I agree that the right approach is to make RefTeX work properly in
non-file buffers.  To explore this, I implemented the approach you
suggested (see the attached patch).  It's a big change that I'm unlikely
to stress-test in my "day job", where for many years I've used a cheap
substitute [1] for RefTeX that I find more efficient for my purposes.
(Any feedback, either on the patch or on how I might better integrate
[1] into the ecosystem, would of course be welcome.)

This bug report arose from a simpler issue: C-x v v C-c C-w in a tex
document (with AUCTeX installed) makes vc activate LaTeX-mode in a
temporary non-file buffer, where AUCTeX style hooks attempt to load
RefTeX (catastrophically).  For this narrow issue, the workaround
provided by Ikumi suffices.

[1] https://github.com/ultronozm/czm-tex-ref.el

>From 55258242ed336880d4578737622ddb5ef851fb44 Mon Sep 17 00:00:00 2001
From: Paul Nelson <[email-masked]>
Date: Wed, 2 Apr 2025 21:38:48 +0200
Subject: [PATCH] Add RefTeX support for non-file buffers

* lisp/textmodes/reftex.el (reftex-get-buffer-identifier)
(reftex-get-buffer-for-master, reftex-get-directory-for-master)
(reftex-file-or-buffer-name, reftex-abbreviate-or-get-name)
(reftex-get-basename-for-master, reftex-get-truename-for-master):
New helper functions that handle both files and buffer objects.
(reftex-tie-multifile-symbols): Support non-file buffers.
(reftex-TeX-master-file): Return current buffer when no file.
(reftex-access-scan-info): Remove check requiring file buffers.
(reftex-access-parse-file, reftex-check-parse-consistency): Skip
for non-file buffers.
(reftex-select-external-document): Use new helper function.
(reftex-locate-file): Return buffer objects directly.
(reftex-get-file-buffer-force): Handle buffer objects and
special 'buffer:' strings.
* lisp/textmodes/reftex-global.el (reftex-create-tags-file): Add
error handling for non-file buffers.  We leave TAGS unsupported
in non-file buffers.
(reftex-find-duplicate-labels)
(reftex-isearch-switch-to-next-file): Use new helper functions
that handle both files and buffer objects.
* lisp/textmodes/reftex-index.el (reftex-display-index): Use new
helper functions.
(reftex-index-visit-phrases-buffer): Add error handling for
non-file buffers.  We leave phrases unsupported in non-file
buffers.
* lisp/textmodes/reftex-parse.el (reftex-do-parse): Add support
for non-file buffers.
(reftex-all-document-files, reftex-where-am-I)
(reftex-notice-new): Use new helper functions.
* lisp/textmodes/reftex-ref.el (reftex-label-info-update):
Support non-file buffers.
(reftex-label-info, reftex-replace-prefix-escapes): Use new
helper functions.
* lisp/textmodes/reftex-sel.el (reftex-insert-docstruct): Use
new helper function.
* lisp/textmodes/reftex-toc.el (reftex-toc)
(reftex-recenter-toc-when-idle): Support non-file buffers.

RefTeX historically assumed that the buffers it operates on
visit files.  For non-file buffers, we follow Stefan Monnier's
suggestion of modifying reftex-TeX-master-file so that it
returns the buffer object itself.  We then modify each caller to
handle buffer objects, aided by some helper functions added to
reftex.el.
---
 lisp/textmodes/reftex-global.el |  20 +-
 lisp/textmodes/reftex-index.el  |  20 +-
 lisp/textmodes/reftex-parse.el  |  26 +--
 lisp/textmodes/reftex-ref.el    |  17 +-
 lisp/textmodes/reftex-sel.el    |   2 +-
 lisp/textmodes/reftex-toc.el    |  10 +-
 lisp/textmodes/reftex.el        | 365 +++++++++++++++++++++-----------
 7 files changed, 291 insertions(+), 169 deletions(-)

diff --git a/lisp/textmodes/reftex-global.el b/lisp/textmodes/reftex-global.el
index 20abd36192d..d706d3e9fd2 100644
--- a/lisp/textmodes/reftex-global.el
+++ b/lisp/textmodes/reftex-global.el
@@ -38,15 +38,17 @@ reftex-create-tags-file
   (interactive)
   (reftex-access-scan-info current-prefix-arg)
   (let* ((master (reftex-TeX-master-file))
-         (files  (reftex-all-document-files))
-         (cmd    (format "%s %s"
+         (files  (reftex-all-document-files)))
+    (if (bufferp master)
+        (user-error "Cannot create TAGS file for non-file buffers")
+      (let ((cmd (format "%s %s"
                          etags-program-name
                          (mapconcat #'shell-quote-argument
-				    files " "))))
-    (with-current-buffer (reftex-get-file-buffer-force master)
-      (message "Running etags to create TAGS file...")
-      (shell-command cmd)
-      (visit-tags-table "TAGS"))))
+                                    files " "))))
+        (with-current-buffer (reftex-get-file-buffer-force master)
+          (message "Running etags to create TAGS file...")
+          (shell-command cmd)
+          (visit-tags-table "TAGS"))))))
 
 ;; History of grep commands.
 (defvar reftex-grep-history nil)
@@ -144,7 +146,7 @@ reftex-find-duplicate-labels
                 (if (< 1 (length x1))
                     (append (list (car x))
                             (mapcar (lambda(x)
-                                      (abbreviate-file-name (nth 3 x)))
+                                      (reftex-abbreviate-or-get-name (nth 3 x)))
                                     x1))
                   (list nil))))))
           (reftex-uniquify-by-car (symbol-value reftex-docstruct-symbol)))))
@@ -456,7 +458,7 @@ reftex-isearch-isearch-search
 ;; beginning/end of the file list, depending of the search direction.
 (defun reftex-isearch-switch-to-next-file (crt-buf &optional wrapp)
   (reftex-access-scan-info)
-  (let ((cb (buffer-file-name crt-buf))
+  (let ((cb (reftex-get-buffer-identifier crt-buf))
 	(flist (reftex-all-document-files)))
     (when flist
       (if wrapp
diff --git a/lisp/textmodes/reftex-index.el b/lisp/textmodes/reftex-index.el
index db6ebb4caf8..47a389500f1 100644
--- a/lisp/textmodes/reftex-index.el
+++ b/lisp/textmodes/reftex-index.el
@@ -531,7 +531,7 @@ reftex-display-index
 SPC=view TAB=goto RET=goto+hide [e]dit [q]uit [r]escan [f]ollow [?]Help
 ------------------------------------------------------------------------------
 "
-               index-tag (abbreviate-file-name master)
+               index-tag (reftex-abbreviate-or-get-name master)
                (if (eq (car (car reftex-index-restriction-data)) 'toc)
                    (nth 2 (car reftex-index-restriction-data))
                  reftex-index-restriction-indicator)))
@@ -1281,14 +1281,16 @@ reftex-index-visit-phrases-buffer
   (interactive)
   (reftex-access-scan-info)
   (set-marker reftex-index-return-marker (point))
-  (let* ((master (reftex-TeX-master-file))
-         (name (concat (file-name-sans-extension master)
-                       reftex-index-phrase-file-extension)))
-    (find-file name)
-    (unless (eq major-mode 'reftex-index-phrases-mode)
-      (reftex-index-phrases-mode))
-    (if (= (buffer-size) 0)
-        (reftex-index-initialize-phrases-buffer master))))
+  (let* ((master (reftex-TeX-master-file)))
+    (when (bufferp master)
+      (user-error "RefTeX phrases buffer requires a file buffer.  Cannot create phrases for non-file buffers"))
+    (let ((name (concat (file-name-sans-extension master)
+                        reftex-index-phrase-file-extension)))
+      (find-file name)
+      (unless (eq major-mode 'reftex-index-phrases-mode)
+        (reftex-index-phrases-mode))
+      (if (= (buffer-size) 0)
+          (reftex-index-initialize-phrases-buffer master)))))
 
 (defun reftex-index-initialize-phrases-buffer (&optional master)
   "Initialize the phrases buffer by creating the header.
diff --git a/lisp/textmodes/reftex-parse.el b/lisp/textmodes/reftex-parse.el
index 7795c583076..f089536c40a 100644
--- a/lisp/textmodes/reftex-parse.el
+++ b/lisp/textmodes/reftex-parse.el
@@ -74,10 +74,10 @@ reftex-do-parse
 
   (let* ((old-list (symbol-value reftex-docstruct-symbol))
          (master (reftex-TeX-master-file))
-         (true-master (file-truename master))
-         (master-dir (file-name-as-directory (file-name-directory master)))
-         (file (or file (buffer-file-name)))
-         (true-file (file-truename file))
+         (true-master (reftex-get-truename-for-master master))
+         (master-dir (file-name-as-directory (reftex-get-directory-for-master master)))
+         (file (or file (reftex-get-buffer-identifier)))
+         (true-file (if file (file-truename file) (buffer-name)))
          (bibview-cache (assq 'bibview-cache old-list))
          (reftex--index-tags (cdr (assq 'index-tags old-list)))
          from-file appendix docstruct tmp)
@@ -88,7 +88,7 @@ reftex-do-parse
                          (member (list 'eof file) old-list))))
       ;; Scan whole document because no such file section exists
       (setq rescan 1))
-    (when (string= true-file true-master)
+    (when (equal true-file true-master)
       ;; Scan whole document because this file is the master
       (setq rescan 1))
 
@@ -186,7 +186,7 @@ reftex-all-document-files
 When RELATIVE is non-nil, give file names relative to directory
 of master file."
   (let* ((all (symbol-value reftex-docstruct-symbol))
-         (master-dir (file-name-directory (reftex-TeX-master-file)))
+         (master-dir (reftex-get-directory-for-master (reftex-TeX-master-file)))
          (re (concat "\\`" (regexp-quote master-dir)))
         file-list tmp file)
     (while (setq tmp (assoc 'bof all))
@@ -638,7 +638,7 @@ reftex-where-am-I
                ((not found)
                 ;; no match
                 (or
-                 (car (member (list 'bof (buffer-file-name)) docstruct))
+                 (car (member (list 'bof (reftex-get-buffer-identifier)) docstruct))
                  (not (setq cnt 2))
                  (assq 'bof docstruct)  ;; for safety reasons
                  'corrupted))
@@ -649,14 +649,15 @@ reftex-where-am-I
                ((match-end 3)
                 ;; Section
                 (goto-char (1- (match-beginning 3)))
-                (let* ((list (member (list 'bof (buffer-file-name))
+                (let* ((buffile (reftex-get-buffer-identifier))
+                       (list (member (list 'bof buffile)
                                      docstruct))
-                       (endelt (car (member (list 'eof (buffer-file-name))
+                       (endelt (car (member (list 'eof buffile)
                                             list)))
                        rtn1)
                   (while (and list (not (eq endelt (car list))))
                     (if (and (eq (car (car list)) 'toc)
-                             (string= (buffer-file-name)
+                             (string= buffile
                                       (nth 3 (car list))))
                         (cond
                          ((equal (point)
@@ -758,12 +759,13 @@ reftex-notice-new
          (when (re-search-forward (reftex-everything-regexp) nil t)
            (cond
             ((match-end 1)
-             (push (reftex-label-info (reftex-match-string 1) buffer-file-name)
+             (push (reftex-label-info (reftex-match-string 1)
+                                  (reftex-get-buffer-identifier))
                    (cdr tail)))
 
             ((match-end 3)
              (setq star (= ?* (char-after (match-end 3)))
-                   entry (reftex-section-info (buffer-file-name))
+                   entry (reftex-section-info (reftex-get-buffer-identifier))
                    level (nth 5 entry))
              ;; Insert the section info
              (push entry (cdr tail))
diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el
index 30e9968a8e5..a1b9ab084ba 100644
--- a/lisp/textmodes/reftex-ref.el
+++ b/lisp/textmodes/reftex-ref.el
@@ -73,8 +73,13 @@ reftex-label-info-update
          (file    (nth 3 cell))
          (comment (nth 4 cell))
          (note    (nth 5 cell))
-         (buf (reftex-get-file-buffer-force
-               file (not (eq t reftex-keep-temporary-buffers)))))
+         (buf (cond
+               ((and (stringp file)
+                     (string-match "\\`buffer:\\(.*\\)" file))
+                (get-buffer (match-string 1 file)))
+               (file (reftex-get-file-buffer-force
+                      file (not (eq t reftex-keep-temporary-buffers))))
+               (t nil))))
     (if (not buf)
         (list label typekey "" file comment "LOST LABEL.  RESCAN TO FIX.")
       (with-current-buffer buf
@@ -102,7 +107,7 @@ reftex-label-info
   (let* ((prefix (if (string-match "^[a-zA-Z0-9]+:" label)
                      (match-string 0 label)))
          (typekey (cdr (assoc prefix reftex-prefix-to-typekey-alist)))
-         (file (or file (buffer-file-name)))
+         (file (or file (reftex-get-buffer-identifier)))
          (trust reftex-trust-label-prefix)
          (in-comment (reftex-in-comment)))
     (if (and typekey
@@ -316,17 +321,17 @@ reftex-replace-prefix-escapes
                  ((equal letter "f")
                   (file-name-base (buffer-file-name)))
                  ((equal letter "F")
-                  (let ((masterdir (file-name-directory (reftex-TeX-master-file)))
+                  (let ((masterdir (reftex-get-directory-for-master (reftex-TeX-master-file)))
                         (file (file-name-sans-extension (buffer-file-name))))
                     (if (string-match (concat "\\`" (regexp-quote masterdir))
                                       file)
                         (substring file (length masterdir))
                       file)))
                  ((equal letter "m")
-                  (file-name-base (reftex-TeX-master-file)))
+                  (reftex-get-basename-for-master (reftex-TeX-master-file)))
                  ((equal letter "M")
                   (file-name-nondirectory
-                   (substring (file-name-directory (reftex-TeX-master-file))
+                   (substring (reftex-get-directory-for-master (reftex-TeX-master-file))
                               0 -1)))
                  ((equal letter "u")
                   (or (user-login-name) ""))
diff --git a/lisp/textmodes/reftex-sel.el b/lisp/textmodes/reftex-sel.el
index 1f1c74550a5..813a9b17532 100644
--- a/lisp/textmodes/reftex-sel.el
+++ b/lisp/textmodes/reftex-sel.el
@@ -234,7 +234,7 @@ reftex-insert-docstruct
             reftex-active-toc nil
             master-dir-re
             (concat "\\`" (regexp-quote
-                           (file-name-directory (reftex-TeX-master-file))))))
+                           (reftex-get-directory-for-master (reftex-TeX-master-file))))))
 
     (setq-local reftex-docstruct-symbol docstruct-symbol)
     (setq-local reftex-prefix
diff --git a/lisp/textmodes/reftex-toc.el b/lisp/textmodes/reftex-toc.el
index d8d09da5ed0..3a1bc2d3d10 100644
--- a/lisp/textmodes/reftex-toc.el
+++ b/lisp/textmodes/reftex-toc.el
@@ -184,14 +184,14 @@ reftex-toc
 
   (interactive)
 
-  (if (or (not (string= reftex-last-toc-master (reftex-TeX-master-file)))
+  (if (or (not (equal reftex-last-toc-master (reftex-TeX-master-file)))
           ;; FIXME: use (interactive "P") to receive current-prefix-arg as
           ;; an argument instead of using the var here, which forces us to set
           ;; current-prefix-arg in the callers.
           current-prefix-arg)
       (reftex-erase-buffer "*toc*"))
 
-  (setq reftex-last-toc-file   (buffer-file-name))
+  (setq reftex-last-toc-file   (reftex-get-buffer-identifier))
   (setq reftex-last-toc-master (reftex-TeX-master-file))
 
   (set-marker reftex-toc-return-marker (point))
@@ -211,7 +211,7 @@ reftex-toc
   (let* ((this-buf (current-buffer))
          (docstruct-symbol reftex-docstruct-symbol)
          (xr-data (assq 'xr (symbol-value reftex-docstruct-symbol)))
-         (xr-alist (cons (cons "" (buffer-file-name)) (nth 1 xr-data)))
+         (xr-alist (cons (cons "" (reftex-get-buffer-identifier)) (nth 1 xr-data)))
          (here-I-am (if reftex--rebuilding-toc
                         (get 'reftex-toc :reftex-data)
                       (car (reftex-where-am-I))))
@@ -261,7 +261,7 @@ reftex-toc
 "TABLE-OF-CONTENTS on %s
 SPC=view TAB=goto RET=goto+hide [q]uit [r]escan [l]abels [f]ollow [x]r [?]Help
 ------------------------------------------------------------------------------
-" (abbreviate-file-name reftex-last-toc-master)))
+" (reftex-abbreviate-or-get-name reftex-last-toc-master)))
 
       (if reftex-use-fonts
           (put-text-property (point-min) (point) 'font-lock-face reftex-toc-header-face))
@@ -997,7 +997,7 @@ reftex-recenter-toc-when-idle
        (not (active-minibuffer-window))
        (fboundp 'reftex-toc-mode)
        (get-buffer-window "*toc*" 'visible)
-       (string= reftex-last-toc-master (reftex-TeX-master-file))
+       (equal reftex-last-toc-master (reftex-TeX-master-file))
        (let (current-prefix-arg)
          (reftex-toc-recenter))))
 
diff --git a/lisp/textmodes/reftex.el b/lisp/textmodes/reftex.el
index fda506a6d87..ffc34b98106 100644
--- a/lisp/textmodes/reftex.el
+++ b/lisp/textmodes/reftex.el
@@ -251,6 +251,78 @@ LaTeX-label-function
 (defvar tex-main-file)
 (defvar outline-minor-mode)
 
+;;; =========================================================================
+;;;
+;;; Helper functions for handling both file paths and buffer objects
+;;;
+
+(defun reftex-get-buffer-identifier (&optional buffer)
+  "Return a buffer file name or a buffer identifier.
+For file buffers, returns `buffer-file-name'.
+For non-file buffers, returns a string with format
+\"buffer:BUFFER-NAME\".  When BUFFER is nil, use the current buffer."
+  (with-current-buffer (or buffer (current-buffer))
+    (or buffer-file-name (concat "buffer:" (buffer-name)))))
+
+(defun reftex-get-buffer-for-master (master)
+  "Get the buffer associated with MASTER.
+MASTER can be a file path or a buffer object."
+  (cond
+   ((bufferp master) master)
+   ((stringp master) (find-file-noselect master))
+   (t nil)))
+
+(defun reftex-get-directory-for-master (master)
+  "Get the directory associated with MASTER.
+MASTER can be a file path or a buffer object."
+  (cond
+   ((bufferp master) (with-current-buffer master default-directory))
+   ((stringp master) (file-name-directory master))
+   (t default-directory)))
+
+(defun reftex-file-or-buffer-name (master)
+  "Get a display name for MASTER.
+Returns the filename for file masters, or the buffer name for buffer
+masters."
+  (cond
+   ((bufferp master) (buffer-name master))
+   ((stringp master) (file-name-nondirectory master))
+   (t "")))
+
+(defun reftex-abbreviate-or-get-name (master)
+  "Get a nice display name for MASTER.
+For files, returns the abbreviated file name.
+For buffers, returns the buffer name."
+  (cond
+   ((bufferp master) (buffer-name master))
+   ((stringp master) (abbreviate-file-name master))
+   (t "")))
+
+(defun reftex-get-basename-for-master (master)
+  "Get the base name (without extension) for MASTER.
+For file masters, returns the file name without directory and extension.
+For buffer objects, returns a sanitized version of the buffer name
+suitable for use in LaTeX labels."
+  (cond
+   ((bufferp master)
+    (let ((name (buffer-name master)))
+      ;; Remove extension if present
+      (if (string-match "\\(.*\\)\\.[^.]*\\'" name)
+          (match-string 1 name)
+        name)))
+   ((stringp master)
+    (file-name-base master))
+   (t "buffer")))
+
+(defun reftex-get-truename-for-master (master)
+  "Get the canonical form of MASTER's identity.
+For file masters, returns the result of file-truename.
+For buffer objects, returns the buffer object itself."
+  (cond
+   ((bufferp master) master)
+   ((stringp master) (file-truename master))
+   (t nil)))
+
 ;;; =========================================================================
 ;;;
 ;;; Multibuffer Variables
@@ -282,8 +354,11 @@ reftex-next-multifile-index
 (defun reftex-tie-multifile-symbols ()
   "Tie the buffer-local symbols to globals connected with the master file.
 If the symbols for the current master file do not exist, they are created."
-  (let* ((master (file-truename (reftex-TeX-master-file)))
-         (index (assoc master reftex-master-index-list))
+  (let* ((master (reftex-TeX-master-file))
+         (master-key (if (bufferp master)
+                         master
+                       (file-truename master)))
+         (index (assoc master-key reftex-master-index-list))
          (symlist reftex-multifile-symbols)
          symbol symname newflag)
     ;; Find the correct index.
@@ -293,7 +368,7 @@ reftex-tie-multifile-symbols
       ;; Get a new index and add info to the alist.
       (setq index (reftex-next-multifile-index)
             newflag t)
-      (push (cons master index) reftex-master-index-list))
+      (push (cons master-key index) reftex-master-index-list))
 
     ;; Get/create symbols and tie them.
     (while symlist
@@ -377,7 +452,7 @@ reftex-TeX-master-file
           (buffer-file-name)))))
     (cond
      ((null master)
-      (error "Need a filename for this buffer, please save it first"))
+      (current-buffer))
      ((or (file-exists-p (concat master ".tex"))
           (find-buffer-visiting (concat master ".tex")))
       ;; Ahh, an extra .tex was missing...
@@ -389,7 +464,9 @@ reftex-TeX-master-file
      (t
       ;; Use buffer file name.
       (setq master (buffer-file-name))))
-    (expand-file-name master)))
+    (if master
+        (expand-file-name master)
+      (current-buffer))))
 
 (defun reftex-is-multi ()
   ;; Tell if this is a multifile document.  When not sure, say yes.
@@ -1105,11 +1182,6 @@ reftex-access-scan-info
   ;; But, when RESCAN is -1, don't rescan even if docstruct is empty.
   ;; When FILE is non-nil, parse only from that file.
 
-  ;; Error out in a buffer without a file.
-  (if (and reftex-mode
-	   (not (buffer-file-name)))
-      (error "RefTeX works only in buffers visiting a file"))
-
   ;; Make sure we have the symbols tied
   (if (eq reftex-docstruct-symbol nil)
       ;; Symbols are not yet tied: Tie them.
@@ -1157,81 +1229,103 @@ reftex-silence-toc-markers
 
 (defun reftex-access-parse-file (action)
   "Perform ACTION on the parse file (the .rel file).
-Valid actions are: readable, restore, read, kill, write."
+Valid actions are: readable, restore, read, kill, write.
+For non-file buffers, persistence operations are skipped."
   (let* ((list (symbol-value reftex-docstruct-symbol))
          (docstruct-symbol reftex-docstruct-symbol)
          (master (reftex-TeX-master-file))
          (enable-local-variables nil)
-         (file (if (string-match "\\.[a-zA-Z]+\\'" master)
-                   (concat (substring master 0 (match-beginning 0))
-                           reftex-parse-file-extension)
-                 (concat master reftex-parse-file-extension))))
+         (is-buffer (bufferp master))
+         (file (if is-buffer
+                   nil
+                 (if (string-match "\\.[a-zA-Z]+\\'" master)
+                     (concat (substring master 0 (match-beginning 0))
+                             reftex-parse-file-extension)
+                   (concat master reftex-parse-file-extension)))))
     (cond
+     ;; For non-file buffers, skip file operations but allow initialization
+     ((and is-buffer (memq action '(readable read kill)))
+      ;; Return appropriate values for buffer objects
+      (cond ((eq action 'readable) nil)
+            ((eq action 'read) nil)
+            ((eq action 'kill) t)))
+
      ((eq action 'readable)
-      (file-readable-p file))
+      (and file (file-readable-p file)))
+
      ((eq action 'restore)
       (put reftex-docstruct-symbol 'modified nil)
       (if (eq reftex-docstruct-symbol nil)
           ;; Symbols are not yet tied: Tie them.
           (reftex-tie-multifile-symbols))
-      (if (file-exists-p file)
-          ;; load the file and return t for success
-          (condition-case nil
-              (progn (load-file file) t)
-            (error (set reftex-docstruct-symbol nil)
-                   (error "Error while loading file %s" file)))
+      (cond
+       (is-buffer
+        (error "Cannot restore for non-file buffer"))
+       ((file-exists-p file)
+        ;; load the file and return t for success
+        (condition-case nil
+            (progn (load-file file) t)
+          (error (set reftex-docstruct-symbol nil)
+                 (error "Error while loading file %s" file))))
+       (t
         ;; Throw an exception if the file does not exist
-        (error "No restore file %s" file)))
+        (error "No restore file %s" file))))
+
      ((eq action 'read)
       (put reftex-docstruct-symbol 'modified nil)
-      (if (file-exists-p file)
-          ;; load the file and return t for success
-          (condition-case nil
-              (progn
-                (load-file file)
-                (reftex-check-parse-consistency)
-                t)
-            (error (message "Error while restoring file %s" file)
-                   (set reftex-docstruct-symbol nil)
-                   nil))
-        ;; return nil for failure, but no exception
-        nil))
+      (cond
+       (is-buffer nil)
+       ((file-exists-p file)
+        ;; load the file and return t for success
+        (condition-case nil
+            (progn
+              (load-file file)
+              (reftex-check-parse-consistency)
+              t)
+          (error (message "Error while restoring file %s" file)
+                 (set reftex-docstruct-symbol nil)
+                 nil)))
+       (t nil))) ; return nil for failure, but no exception
+
      ((eq action 'kill)
       ;; Remove the file
-      (when (and (file-exists-p file) (file-writable-p file))
+      (when (and file (file-exists-p file) (file-writable-p file))
         (message "Unlinking file %s" file)
         (delete-file file)))
-     (t
+
+     (t ; write
       (put docstruct-symbol 'modified nil)
-      (save-excursion
-        (if (file-writable-p file)
-            (with-temp-file file
-              (message "Writing parse file %s" (abbreviate-file-name file))
-              (insert ";; RefTeX parse info file\n")
-              (insert (format ";; File: %s\n" master))
-              (insert (format ";; User: %s (%s)\n\n"
-                              (user-login-name) (user-full-name)))
-              (insert "(set reftex-docstruct-symbol '(\n\n")
-              (let ((standard-output (current-buffer)))
-                (mapc
-                 (lambda (x)
-                   (cond ((eq (car x) 'toc)
-                          ;; A toc entry. Do not save the marker.
-                          ;; Save the markers  position at position 8
-                          (print (list 'toc "toc" (nth 2 x) (nth 3 x)
-                                       nil (nth 5 x) (nth 6 x) (nth 7 x)
-                                       (or (and (markerp (nth 4 x))
-                                                (marker-position (nth 4 x)))
-                                           (nth 8 x)))))
-                         ((and (not (eq t reftex-support-index))
-                               (eq (car x) 'index))
-                          ;; Don't save index entries
-                          )
-                         (t (print x))))
-                 list))
-              (insert "))\n\n"))
-          (error "Cannot write to file %s" file)))
-      t))))
+      (if is-buffer
+          t
+        (save-excursion
+          (if (and file (file-writable-p file))
+              (with-temp-file file
+                (message "Writing parse file %s" (abbreviate-file-name file))
+                (insert ";; RefTeX parse info file\n")
+                (insert (format ";; File: %s\n" master))
+                (insert (format ";; User: %s (%s)\n\n"
+                                (user-login-name) (user-full-name)))
+                (insert "(set reftex-docstruct-symbol '(\n\n")
+                (let ((standard-output (current-buffer)))
+                  (mapc
+                   (lambda (x)
+                     (cond ((eq (car x) 'toc)
+                            ;; A toc entry. Do not save the marker.
+                            ;; Save the markers  position at position 8
+                            (print (list 'toc "toc" (nth 2 x) (nth 3 x)
+                                         nil (nth 5 x) (nth 6 x) (nth 7 x)
+                                         (or (and (markerp (nth 4 x))
+                                                  (marker-position (nth 4 x)))
+                                             (nth 8 x)))))
+                           ((and (not (eq t reftex-support-index))
+                                 (eq (car x) 'index))
+                            ;; Don't save index entries
+                            )
+                           (t (print x))))
+                   list))
+                (insert "))\n\n"))
+            (error "Cannot write to file %s" file)))
+        t)))))
 
 (defun reftex-check-parse-consistency ()
   ;; Check if parse file is consistent, throw an error if not.
@@ -1240,10 +1334,13 @@ reftex-check-parse-consistency
   (let* ((real-master (reftex-TeX-master-file))
          (parsed-master
           (nth 1 (assq 'bof (symbol-value reftex-docstruct-symbol)))))
-    (unless (string= (file-truename real-master) (file-truename parsed-master))
-      (message "Master file name in load file is different: %s versus %s"
-               parsed-master real-master)
-      (error "Master file name error")))
+    ;; Skip this check for buffer objects since they don't need saved parse info
+    (when (and (stringp real-master) (stringp parsed-master))
+      (unless (string= (file-truename real-master)
+                       (file-truename parsed-master))
+        (message "Master file name in load file is different: %s versus %s"
+                 parsed-master real-master)
+        (error "Master file name error"))))
 
   ;; Check for the existence of all document files
 ;;;  (let* ((all (symbol-value reftex-docstruct-symbol)))
@@ -1281,7 +1378,7 @@ reftex-select-external-document
                   (mapconcat
                    (lambda (x)
                      (format fmt (incf n) (or (car x) "")
-                             (abbreviate-file-name (cdr x))))
+                             (reftex-abbreviate-or-get-name (cdr x))))
                    xr-alist ""))
                  nil t))
           (cond
@@ -1299,21 +1396,24 @@ reftex-locate-file
   "Find FILE of type TYPE in MASTER-DIR or on the path associated with TYPE.
 If the file does not have any of the valid extensions for TYPE,
 try first the default extension and only then the naked file name.
-When DIE is non-nil, throw an error if file not found."
-  (let* ((rec-values (if reftex-search-unrecursed-path-first '(nil t) '(t)))
-         (extensions (cdr (assoc type reftex-file-extensions)))
-         (def-ext (car extensions))
-         (ext-re (concat "\\("
-                         (mapconcat #'regexp-quote extensions "\\|")
-                         "\\)\\'"))
-         (files (if (string-match ext-re file)
-                    (cons file nil)
-		  (if reftex-try-all-extensions
-		      (append (mapcar (lambda (x) (concat file x))
-				      extensions)
-			      (list file))
-		    (list (concat file def-ext) file))))
-         path old-path file1 f fs)
+When DIE is non-nil, throw an error if file not found.
+When FILE is a buffer object, return that buffer."
+  (if (bufferp file)
+      file
+    (let* ((rec-values (if reftex-search-unrecursed-path-first '(nil t) '(t)))
+           (extensions (cdr (assoc type reftex-file-extensions)))
+           (def-ext (car extensions))
+           (ext-re (concat "\\("
+                          (mapconcat #'regexp-quote extensions "\\|")
+                          "\\)\\'"))
+           (files (if (string-match ext-re file)
+                     (cons file nil)
+                   (if reftex-try-all-extensions
+                       (append (mapcar (lambda (x) (concat file x))
+                                      extensions)
+                              (list file))
+                     (list (concat file def-ext) file))))
+           path old-path file1 f fs)
     (cond
      ((file-name-absolute-p file)
       (while (setq f (pop files))
@@ -1335,7 +1435,7 @@ reftex-locate-file
 	    (setq file1 (reftex-find-file-on-path f path master-dir)))))))
     (cond (file1 file1)
           (die (error "No such file: %s" file) nil)
-          (t (message "No such file: %s (ignored)" file) nil))))
+          (t (message "No such file: %s (ignored)" file) nil)))))
 
 (defun reftex-find-file-externally (file type &optional master-dir)
   ;; Use external program to find FILE.
@@ -1741,47 +1841,58 @@ reftex-get-file-buffer-force
   ;; If MARK-TO-KILL is t and there is no live buffer, visit the file with
   ;; initializations according to `reftex-initialize-temporary-buffers',
   ;; and mark the buffer to be killed after use.
+  ;; If FILE is actually a buffer object, just return that buffer.
+  ;; If FILE is a string starting with "buffer:", get the buffer with that name.
 
-  (let ((buf (find-buffer-visiting file)))
-
-    (cond (buf
-           ;; We have it already as a buffer - just return it
-           buf)
-
-          ((file-readable-p file)
-           ;; At least there is such a file and we can read it.
-
-           (if (or (not mark-to-kill)
-                   (eq t reftex-initialize-temporary-buffers))
-
-               ;; Visit the file with full magic
-               (setq buf (find-file-noselect file))
-
-             ;; Else: Visit the file just briefly, without or
-             ;;       with limited Magic
-
-             ;; The magic goes away
-             (cl-letf ((format-alist nil)
-                       (auto-mode-alist (reftex-auto-mode-alist))
-                       ((default-value 'major-mode) 'fundamental-mode)
-                       (enable-local-variables nil)
-                       (after-insert-file-functions nil))
-               (setq buf (find-file-noselect file)))
-
-             ;; Is there a hook to run?
-             (when (listp reftex-initialize-temporary-buffers)
-               (with-current-buffer buf
-                 (run-hooks 'reftex-initialize-temporary-buffers))))
-
-           ;; Let's see if we got a license to kill :-|
-           (and mark-to-kill
-                (cl-pushnew buf reftex-buffers-to-kill))
-
-           ;; Return the new buffer
-           buf)
-
-          ;; If no such file exists, return nil
-          (t nil))))
+  (cond
+   ((bufferp file) file)
+
+   ((and (stringp file) (string-match "\\`buffer:\\(.*\\)" file))
+    (get-buffer (match-string 1 file)))
+
+   ;; Normal file path handling
+   ((stringp file)
+    (let ((buf (find-buffer-visiting file)))
+      (cond (buf
+             ;; We have it already as a buffer - just return it
+             buf)
+
+            ((file-readable-p file)
+             ;; At least there is such a file and we can read it.
+
+             (if (or (not mark-to-kill)
+                     (eq t reftex-initialize-temporary-buffers))
+
+                 ;; Visit the file with full magic
+                 (setq buf (find-file-noselect file))
+
+               ;; Else: Visit the file just briefly, without or
+               ;;       with limited Magic
+
+               ;; The magic goes away
+               (cl-letf ((format-alist nil)
+                         (auto-mode-alist (reftex-auto-mode-alist))
+                         ((default-value 'major-mode) 'fundamental-mode)
+                         (enable-local-variables nil)
+                         (after-insert-file-functions nil))
+                 (setq buf (find-file-noselect file)))
+
+               ;; Is there a hook to run?
+               (when (listp reftex-initialize-temporary-buffers)
+                 (with-current-buffer buf
+                   (run-hooks 'reftex-initialize-temporary-buffers))))
+
+             ;; Let's see if we got a license to kill :-|
+             (and mark-to-kill
+                  (cl-pushnew buf reftex-buffers-to-kill))
+
+             ;; Return the new buffer
+             buf)
+
+            ;; If no such file exists, return nil
+            (t nil))))
+   ;;
+   (t nil)))
 
 (defun reftex-kill-temporary-buffers (&optional buffer)
   ;; Kill all buffers in the list reftex-kill-temporary-buffers.
-- 
2.39.3 (Apple Git-145)