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

From: "Paul D. Nelson" <[email-masked]>
Date: Thu, 03 Apr 2025 20:35:29 +0200

Hi Arash,

OK, sounds good.  I just finished polishing the patch (also for indirect
buffers) and testing it out a bit, so as far as I'm concerned, it's OK
to push to master, unless Stefan or others have further comments.

Well, I guess this could benefit from a NEWS entry, but I'll leave that
for now.

Thanks, best,

Paul

>From ecdb46947b6668566da9a730415038e74e925943 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-directory, reftex--abbreviate-name)
(reftex--get-basename, reftex--get-truename): New helper
functions that handle both files and buffer objects.
(reftex--remove-buffer-from-master-index): New helper function.
(reftex-tie-multifile-symbols): Support non-file buffers, using
the above.
(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.  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.
(reftex-isearch-switch-to-next-file): Use equal rather than
string= to compare strings/buffers.
* lisp/textmodes/reftex-index.el (reftex-display-index)
(reftex-index-change-entry): Use new helper functions.
(reftex-index-visit-phrases-buffer): Add error handling for
non-file buffers.  Leave phrases unsupported in non-file
buffers.
* lisp/textmodes/reftex-parse.el (reftex-do-parse)
(reftex-parse-from-file): 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, reftex-label)
(reftex-replace-prefix-escapes, reftex-offer-label-menu): 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.
* lisp/textmodes/reftex-cite.el (reftex-bib-or-thebib)
(reftex-get-bibfile-list): Use new helper functions.

RefTeX historically assumed that the buffers it operates on
visit files.  To handle non-file buffers:

Modify reftex-TeX-master-file so that it returns the buffer
object itself (as suggested by Stefan Monnier).  Modify each
caller to handle buffer objects, aided by some helper functions
added to reftex.el.  Replace 'string=' by 'equal' in places.

Use buffer-base-buffer, where appropriate, to handle indirect
buffers (file and non-file).

TAGS files and phrases buffers remain unsupported for non-file
buffers.
---
 lisp/textmodes/reftex-cite.el   |   9 +-
 lisp/textmodes/reftex-global.el |  28 ++--
 lisp/textmodes/reftex-index.el  |  25 ++--
 lisp/textmodes/reftex-parse.el  |  48 ++++---
 lisp/textmodes/reftex-ref.el    |  25 ++--
 lisp/textmodes/reftex-sel.el    |   2 +-
 lisp/textmodes/reftex-toc.el    |  11 +-
 lisp/textmodes/reftex.el        | 234 +++++++++++++++++++++-----------
 8 files changed, 237 insertions(+), 145 deletions(-)

diff --git a/lisp/textmodes/reftex-cite.el b/lisp/textmodes/reftex-cite.el
index fe6751a13f6..8830f188c93 100644
--- a/lisp/textmodes/reftex-cite.el
+++ b/lisp/textmodes/reftex-cite.el
@@ -76,7 +76,8 @@ reftex-bib-or-thebib
   "Test if BibTeX or \\begin{thebibliography} should be used for the citation.
 Find the bof of the current file."
   (let* ((docstruct (symbol-value reftex-docstruct-symbol))
-         (rest (or (member (list 'bof (buffer-file-name)) docstruct)
+         (rest (or (member (list 'bof (reftex--get-buffer-identifier))
+                           docstruct)
                    docstruct))
          (bib (assq 'bib rest))
          (thebib (assq 'thebib rest))
@@ -104,11 +105,11 @@ reftex-get-bibfile-list
   (or
    ;; Try inside this file (and its includes)
    (cdr (reftex-last-assoc-before-elt
-         'bib (list 'eof (buffer-file-name))
-         (member (list 'bof (buffer-file-name))
+         'bib (list 'eof (reftex--get-buffer-identifier))
+         (member (list 'bof (reftex--get-buffer-identifier))
                  (symbol-value reftex-docstruct-symbol))))
    ;; Try after the beginning of this file
-   (cdr (assq 'bib (member (list 'bof (buffer-file-name))
+   (cdr (assq 'bib (member (list 'bof (reftex--get-buffer-identifier))
                            (symbol-value reftex-docstruct-symbol))))
    ;; Anywhere in the entire document
    (cdr (assq 'bib (symbol-value reftex-docstruct-symbol)))
diff --git a/lisp/textmodes/reftex-global.el b/lisp/textmodes/reftex-global.el
index 20abd36192d..e211b10451a 100644
--- a/lisp/textmodes/reftex-global.el
+++ b/lisp/textmodes/reftex-global.el
@@ -37,16 +37,18 @@ reftex-create-tags-file
 The TAGS file is also immediately visited with `visit-tags-table'."
   (interactive)
   (reftex-access-scan-info current-prefix-arg)
-  (let* ((master (reftex-TeX-master-file))
-         (files  (reftex-all-document-files))
-         (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"))))
+  (let ((master (reftex-TeX-master-file)))
+    (if (bufferp master)
+        (user-error "Cannot create TAGS file for non-file buffers")
+      (let* ((files  (reftex-all-document-files))
+             (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"))))))
 
 ;; 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-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
@@ -464,7 +466,7 @@ reftex-isearch-switch-to-next-file
 	    (setq flist (last flist)))
 	(unless isearch-forward
 	  (setq flist (reverse flist)))
-	(while (not (string= (car flist) cb))
+	(while (not (equal (car flist) cb))
 	  (setq flist (cdr flist)))
 	(setq flist (cdr flist)))
       (when flist
diff --git a/lisp/textmodes/reftex-index.el b/lisp/textmodes/reftex-index.el
index db6ebb4caf8..1d18d6047b5 100644
--- a/lisp/textmodes/reftex-index.el
+++ b/lisp/textmodes/reftex-index.el
@@ -475,7 +475,7 @@ reftex-display-index
          (docstruct-symbol reftex-docstruct-symbol)
          (index-tag (or tag (reftex-index-select-tag)))
          (master (reftex-TeX-master-file))
-         (calling-file (buffer-file-name))
+         (calling-file (reftex--get-buffer-identifier))
          (restriction
           (or overriding-restriction
               (and (not redo)
@@ -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-name master)
                (if (eq (car (car reftex-index-restriction-data)) 'toc)
                    (nth 2 (car reftex-index-restriction-data))
                  reftex-index-restriction-indicator)))
@@ -1107,7 +1107,8 @@ reftex-index-change-entry
       (when (and (re-search-forward (reftex-everything-regexp) nil t)
                  (match-end 10)
                  (< (abs (- (match-beginning 10) beg)) (length new))
-                 (setq info (reftex-index-info-safe buffer-file-name)))
+                 (setq info (reftex-index-info-safe
+                             (reftex--get-buffer-identifier))))
         (setcdr data (cdr info))))
     (let ((buffer-read-only nil))
       (save-excursion
@@ -1281,14 +1282,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"))
+    (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..3d1849f618d 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 master))
+         (master-dir (file-name-as-directory (reftex--get-directory master)))
+         (file (or file (reftex--get-buffer-identifier)))
+         (true-file (reftex--get-truename file))
          (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 (reftex-TeX-master-file)))
          (re (concat "\\`" (regexp-quote master-dir)))
         file-list tmp file)
     (while (setq tmp (assoc 'bof all))
@@ -228,7 +228,7 @@ reftex-parse-from-file
                 (not (eq t reftex-keep-temporary-buffers)))))
 
         ;; Begin of file mark
-        (setq file (buffer-file-name))
+        (setq file (reftex--get-buffer-identifier))
         (push (list 'bof file) docstruct)
 
         (reftex-with-special-syntax
@@ -275,7 +275,8 @@ reftex-parse-from-file
                  (when (and toc-entry
                             (eq ;; Either both are t or both are nil.
                              (= (char-after bound) ?%)
-                             (string-suffix-p ".dtx" file)))
+                             (and (stringp file)
+                                  (string-suffix-p ".dtx" file))))
                    ;; It can happen that section info returns nil
                    (setq level (nth 5 toc-entry))
                    (setq highest-level (min highest-level level))
@@ -638,7 +639,8 @@ 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,15 +651,16 @@ 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)
-                                      (nth 3 (car list))))
+                             (equal buffile
+                                    (nth 3 (car list))))
                         (cond
                          ((equal (point)
                                  (or (and (markerp (nth 4 (car list)))
@@ -685,10 +688,13 @@ reftex-where-am-I
                 (when reftex-support-index
                   (let* ((index-info (save-excursion
                                        (reftex-index-info-safe nil)))
-                         (list (member (list 'bof (buffer-file-name))
-                                       docstruct))
-                         (endelt (car (member (list 'eof (buffer-file-name))
-                                              list)))
+                         (list (member
+                                (list 'bof (reftex--get-buffer-identifier))
+                                docstruct))
+                         (endelt
+                          (car (member
+                                (list 'eof (reftex--get-buffer-identifier))
+                                list)))
                          dist last-dist last (n 0))
                     ;; Check all index entries with equal text
                     (while (and list (not (eq endelt (car list))))
@@ -758,12 +764,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))
@@ -795,7 +802,8 @@ reftex-notice-new
             ((match-end 10)
              ;; Index entry
              (and reftex-support-index
-                  (setq entry (reftex-index-info-safe buffer-file-name))
+                  (setq entry (reftex-index-info-safe
+                               (reftex--get-buffer-identifier)))
                   ;; FIXME: (add-to-list 'reftex--index-tags (nth 1 index-entry))
                   (push entry (cdr tail))))))))))
 
diff --git a/lisp/textmodes/reftex-ref.el b/lisp/textmodes/reftex-ref.el
index 30e9968a8e5..8aa34ec942a 100644
--- a/lisp/textmodes/reftex-ref.el
+++ b/lisp/textmodes/reftex-ref.el
@@ -73,8 +73,10 @@ 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 (if (bufferp file)
+                  file
+                (reftex-get-file-buffer-force
+                 file (not (eq t reftex-keep-temporary-buffers))))))
     (if (not buf)
         (list label typekey "" file comment "LOST LABEL.  RESCAN TO FIX.")
       (with-current-buffer buf
@@ -102,7 +104,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
@@ -249,7 +251,7 @@ reftex-label
              (note (if (cdr here-I-am-info)
                        ""
                      "POSITION UNCERTAIN.  RESCAN TO FIX."))
-             (file (buffer-file-name))
+             (file (reftex--get-buffer-identifier))
              ;; (text nil)
              (tail (memq here-I-am (symbol-value reftex-docstruct-symbol))))
 
@@ -314,19 +316,21 @@ reftex-replace-prefix-escapes
               (save-match-data
                 (cond
                  ((equal letter "f")
-                  (file-name-base (buffer-file-name)))
+                  (file-name-base (reftex--get-buffer-identifier)))
                  ((equal letter "F")
-                  (let ((masterdir (file-name-directory (reftex-TeX-master-file)))
-                        (file (file-name-sans-extension (buffer-file-name))))
+                  (let ((masterdir (reftex--get-directory
+                                    (reftex-TeX-master-file)))
+                        (file (file-name-sans-extension
+                               (reftex--get-buffer-identifier))))
                     (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 (reftex-TeX-master-file)))
                  ((equal letter "M")
                   (file-name-nondirectory
-                   (substring (file-name-directory (reftex-TeX-master-file))
+                   (substring (reftex--get-directory (reftex-TeX-master-file))
                               0 -1)))
                  ((equal letter "u")
                   (or (user-login-name) ""))
@@ -536,7 +540,8 @@ reftex-offer-label-menu
   ;; Offer a menu with the appropriate labels.
   (let* ((buf (current-buffer))
          (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)))
          (xr-index 0)
          (here-I-am (car (reftex-where-am-I)))
          (here-I-am1 here-I-am)
diff --git a/lisp/textmodes/reftex-sel.el b/lisp/textmodes/reftex-sel.el
index 1f1c74550a5..6e65ad4786c 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 (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..2e3be51c87c 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,8 @@ 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 +262,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-name reftex-last-toc-master)))
 
       (if reftex-use-fonts
           (put-text-property (point-min) (point) 'font-lock-face reftex-toc-header-face))
@@ -997,7 +998,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..d72b1ba7315 100644
--- a/lisp/textmodes/reftex.el
+++ b/lisp/textmodes/reftex.el
@@ -251,6 +251,53 @@ LaTeX-label-function
 (defvar tex-main-file)
 (defvar outline-minor-mode)
 
+;;; =========================================================================
+;;;
+;;; Helper functions for handling both file names and buffer objects.
+;;;
+
+(defun reftex--get-buffer-identifier (&optional buffer)
+  "Return the base buffer's file name or buffer identifier.
+For file buffers, returns the file name of the base buffer.
+For non-file buffers, return the base buffer object itself.
+When BUFFER is nil, use the current buffer."
+  (let* ((buffer (or buffer (current-buffer)))
+         (buffer (or (buffer-base-buffer buffer) buffer)))
+    (or (buffer-local-value 'buffer-file-name buffer)
+        buffer)))
+
+(defun reftex--get-directory (file-or-buffer)
+  "Get the directory associated with FILE-OR-BUFFER.
+FILE-OR-BUFFER can be a file name or a buffer object."
+  (if (bufferp file-or-buffer)
+      (buffer-local-value 'default-directory file-or-buffer)
+    (file-name-directory file-or-buffer)))
+
+(defun reftex--abbreviate-name (file-or-buffer)
+  "Get a nice display name for FILE-OR-BUFFER.
+For files, returns the abbreviated file name.
+For buffers, returns the buffer name."
+  (if (bufferp file-or-buffer)
+      (prin1-to-string file-or-buffer)
+    (abbreviate-file-name file-or-buffer)))
+
+(defun reftex--get-basename (file-or-buffer)
+  "Get the base name (without extension) for FILE-OR-BUFFER.
+For file names, 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."
+  (if (bufferp file-or-buffer)
+      (file-name-base (buffer-name file-or-buffer))
+    (file-name-base file-or-buffer)))
+
+(defun reftex--get-truename (file-or-buffer)
+  "Get the canonical form of FILE-OR-BUFFER's identity.
+For files, returns the result of file-truename.
+For buffer objects, returns the buffer object itself."
+  (if (bufferp file-or-buffer)
+      file-or-buffer
+    (file-truename file-or-buffer)))
+
 ;;; =========================================================================
 ;;;
 ;;; Multibuffer Variables
@@ -279,10 +326,16 @@ reftex-next-multifile-index
   ;; Return the next free index for multifile symbols.
   (incf reftex-multifile-index))
 
+(defun reftex--remove-buffer-from-master-index ()
+  "Remove current buffer from `reftex-master-index-list'."
+  (setq reftex-master-index-list
+        (assq-delete-all (current-buffer) reftex-master-index-list)))
+
 (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)))
+  (let* ((master (reftex-TeX-master-file))
+         (master (reftex--get-truename master))
          (index (assoc master reftex-master-index-list))
          (symlist reftex-multifile-symbols)
          symbol symname newflag)
@@ -293,7 +346,11 @@ 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 index) reftex-master-index-list)
+      (when (bufferp master)
+        (with-current-buffer master
+          (add-hook 'kill-buffer-hook
+                    #'reftex--remove-buffer-from-master-index nil t))))
 
     ;; Get/create symbols and tie them.
     (while symlist
@@ -326,70 +383,73 @@ reftex-TeX-master-file
   ;; When AUCTeX is loaded, we will use it's more sophisticated method.
   ;; We also support the default TeX and LaTeX modes by checking for a
   ;; variable tex-main-file.
-  (let
-      ((master
-        (cond
-	 ;; Test if we're in a subfile using the subfiles document
-	 ;; class, e.g., \documentclass[main.tex]{subfiles}.  It's
-	 ;; argument is the main file, however it's not really the
-	 ;; master file in `TeX-master-file' or `tex-main-file's
-	 ;; sense.  It should be used for references but not for
-	 ;; compilation, thus subfiles use a setting of
-	 ;; `TeX-master'/`tex-main-file' being themselves.
-	 ((save-excursion
-            (goto-char (point-min))
-            (re-search-forward
-             "^[[:space:]]*\\\\documentclass\\[\\([^]]+\\)\\]{subfiles}"
-             nil t))
-          (match-string-no-properties 1))
-         ;; AUCTeX is loaded.  Use its mechanism.
-         ((fboundp 'TeX-master-file)
-          (condition-case nil
-              (TeX-master-file t)
-            (error (buffer-file-name))))
-         ;; Emacs LaTeX mode
-         ((fboundp 'tex-main-file) (tex-main-file))
-         ;; Check the `TeX-master' variable.
-         ((boundp 'TeX-master)
+  (with-current-buffer (or (buffer-base-buffer) (current-buffer))
+    (let
+        ;; Set master to a file name (possibly non-existent), or nil:
+        ((master
           (cond
-           ((eq TeX-master t)
-            (buffer-file-name))
-           ((eq TeX-master 'shared)
-            (setq TeX-master (read-file-name "Master file: "
-                                             nil nil t nil)))
-           (TeX-master)
+	   ;; Test if we're in a subfile using the subfiles document
+	   ;; class, e.g., \documentclass[main.tex]{subfiles}.  It's
+	   ;; argument is the main file, however it's not really the
+	   ;; master file in `TeX-master-file' or `tex-main-file's
+	   ;; sense.  It should be used for references but not for
+	   ;; compilation, thus subfiles use a setting of
+	   ;; `TeX-master'/`tex-main-file' being themselves.
+	   ((save-excursion
+              (goto-char (point-min))
+              (re-search-forward
+               "^[[:space:]]*\\\\documentclass\\[\\([^]]+\\)\\]{subfiles}"
+               nil t))
+            (match-string-no-properties 1))
+           ;; AUCTeX is loaded.  Use its mechanism.
+           ((fboundp 'TeX-master-file)
+            (condition-case nil
+                (TeX-master-file t)
+              (error (buffer-file-name))))
+           ;; Emacs LaTeX mode
+           ((fboundp 'tex-main-file) (tex-main-file))
+           ;; Check the `TeX-master' variable.
+           ((boundp 'TeX-master)
+            (cond
+             ((eq TeX-master t)
+              (buffer-file-name))
+             ((eq TeX-master 'shared)
+              (setq TeX-master (read-file-name "Master file: "
+                                               nil nil t nil)))
+             (TeX-master)
+             (t
+              (setq TeX-master (read-file-name "Master file: "
+                                               nil nil t nil)))))
+           ;; Check the `tex-main-file' variable.
+           ((boundp 'tex-main-file)
+            ;; This is the variable from the default TeX modes.
+            (cond
+             ((stringp tex-main-file)
+              ;; ok, this must be it
+              tex-main-file)
+             (t
+              ;; In this case, the buffer is its own master.
+              (buffer-file-name))))
+           ;; We know nothing about master file.  Assume this is a
+           ;; master file.
            (t
-            (setq TeX-master (read-file-name "Master file: "
-                                             nil nil t nil)))))
-         ;; Check the `tex-main-file' variable.
-         ((boundp 'tex-main-file)
-          ;; This is the variable from the default TeX modes.
-          (cond
-           ((stringp tex-main-file)
-            ;; ok, this must be it
-            tex-main-file)
-           (t
-            ;; In this case, the buffer is its own master.
-            (buffer-file-name))))
-         ;; We know nothing about master file.  Assume this is a
-         ;; master file.
-         (t
-          (buffer-file-name)))))
-    (cond
-     ((null master)
-      (error "Need a filename for this buffer, please save it first"))
-     ((or (file-exists-p (concat master ".tex"))
-          (find-buffer-visiting (concat master ".tex")))
-      ;; Ahh, an extra .tex was missing...
-      (setq master (concat master ".tex")))
-     ((or (file-exists-p master)
-          (find-buffer-visiting master))
-      ;; We either see the file, or have a buffer on it.  OK.
-      )
-     (t
-      ;; Use buffer file name.
-      (setq master (buffer-file-name))))
-    (expand-file-name master)))
+            (buffer-file-name)))))
+      (cond
+       ((null master))
+       ((or (file-exists-p (concat master ".tex"))
+            (find-buffer-visiting (concat master ".tex")))
+        ;; Ahh, an extra .tex was missing...
+        (setq master (concat master ".tex")))
+       ((or (file-exists-p master)
+            (find-buffer-visiting master))
+        ;; We either see the file, or have a buffer on it.  OK.
+        )
+       (t
+        ;; Use buffer file name.
+        (setq master (buffer-file-name))))
+      (if master
+          (expand-file-name master)
+        (current-buffer)))))
 
 (defun reftex-is-multi ()
   ;; Tell if this is a multifile document.  When not sure, say yes.
@@ -712,7 +772,7 @@ reftex-reset-mode
 (defun reftex-reset-scanning-information ()
   "Reset the symbols containing information from buffer scanning.
 This enforces rescanning the buffer on next use."
-  (if (string= reftex-last-toc-master (reftex-TeX-master-file))
+  (if (equal reftex-last-toc-master (reftex-TeX-master-file))
       (reftex-erase-buffer "*toc*"))
   (let ((symlist reftex-multifile-symbols)
         symbol)
@@ -1105,11 +1165,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,16 +1212,26 @@ 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))))
+         (non-file (bufferp master))
+         (file (if non-file
+                   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.
+     (non-file (cond ((eq action 'readable) nil)
+                     ((eq action 'read) nil)
+                     ((eq action 'kill) t)
+                     ((eq action 'restore)
+                      (error "Cannot restore for non-file buffer"))))
      ((eq action 'readable)
       (file-readable-p file))
      ((eq action 'restore)
@@ -1240,7 +1305,9 @@ 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))
+    ;; Skip this check for buffer objects.
+    (unless (equal (reftex--get-truename real-master)
+                   (reftex--get-truename parsed-master))
       (message "Master file name in load file is different: %s versus %s"
                parsed-master real-master)
       (error "Master file name error")))
@@ -1281,7 +1348,7 @@ reftex-select-external-document
                   (mapconcat
                    (lambda (x)
                      (format fmt (incf n) (or (car x) "")
-                             (abbreviate-file-name (cdr x))))
+                             (reftex--abbreviate-name (cdr x))))
                    xr-alist ""))
                  nil t))
           (cond
@@ -1299,8 +1366,11 @@ 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)))
+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 "\\("
@@ -1335,7 +1405,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.
@@ -1742,7 +1812,9 @@ reftex-get-file-buffer-force
   ;; initializations according to `reftex-initialize-temporary-buffers',
   ;; and mark the buffer to be killed after use.
 
-  (let ((buf (find-buffer-visiting file)))
+  (let ((buf (if (bufferp file)
+                 file
+               (find-buffer-visiting file))))
 
     (cond (buf
            ;; We have it already as a buffer - just return it
-- 
2.39.3 (Apple Git-145)