Fix undo of changes in cloned indirect buffers

* lisp/simple.el (primitive-undo): If the visited-modtime of the
indirect buffer's file is bogus, use the modtime of the file
visited by its base buffer.

* src/undo.c (record_first_change): Call
'buffer_visited_file_modtime' with the correct buffer, instead of
always calling 'Fvisited_file_modtime', which returns possibly
bogus values for indirect buffers.
* src/fileio.c (Fset_visited_file_modtime): Signal a meaningful
error for indirect buffers.
(buffer_visited_file_modtime): New function, with implementation
taken from 'Fvisited_file_modtime'.
(Fvisited_file_modtime): Call 'buffer_visited_file_modtime'.
* src/lisp.h: Add prototype for 'buffer_visited_file_modtime'.
(Bug#56397)
This commit is contained in:
Eli Zaretskii 2022-07-07 11:56:31 +03:00
parent b075a59a1a
commit 74f43f82e6
4 changed files with 30 additions and 11 deletions

View file

@ -3525,12 +3525,22 @@ Return what remains of the list."
;; If this records an obsolete save
;; (not matching the actual disk file)
;; then don't mark unmodified.
(when (or (equal time (visited-file-modtime))
(and (consp time)
(equal (list (car time) (cdr time))
(visited-file-modtime))))
(unlock-buffer)
(set-buffer-modified-p nil)))
(let ((visited-file-time (visited-file-modtime)))
;; Indirect buffers don't have a visited file, so their
;; file-modtime can be bogus. In that case, use the
;; modtime of the base buffer instead.
(if (and (numberp visited-file-time)
(= visited-file-time 0)
(buffer-base-buffer))
(setq visited-file-time
(with-current-buffer (buffer-base-buffer)
(visited-file-modtime))))
(when (or (equal time visited-file-time)
(and (consp time)
(equal (list (car time) (cdr time))
visited-file-time)))
(unlock-buffer)
(set-buffer-modified-p nil))))
;; Element (nil PROP VAL BEG . END) is property change.
(`(nil . ,(or `(,prop ,val ,beg . ,end) pcase--dontcare))
(when (or (> (point-min) beg) (< (point-max) end))

View file

@ -5832,6 +5832,15 @@ See Info node `(elisp)Modification Time' for more details. */)
return Qnil;
}
Lisp_Object
buffer_visited_file_modtime (struct buffer *buf)
{
int ns = buf->modtime.tv_nsec;
if (ns < 0)
return make_fixnum (UNKNOWN_MODTIME_NSECS - ns);
return make_lisp_time (buf->modtime);
}
DEFUN ("visited-file-modtime", Fvisited_file_modtime,
Svisited_file_modtime, 0, 0, 0,
doc: /* Return the current buffer's recorded visited file modification time.
@ -5841,10 +5850,7 @@ visited file doesn't exist.
See Info node `(elisp)Modification Time' for more details. */)
(void)
{
int ns = current_buffer->modtime.tv_nsec;
if (ns < 0)
return make_fixnum (UNKNOWN_MODTIME_NSECS - ns);
return make_lisp_time (current_buffer->modtime);
return buffer_visited_file_modtime (current_buffer);
}
DEFUN ("set-visited-file-modtime", Fset_visited_file_modtime,
@ -5871,6 +5877,8 @@ in `current-time' or an integer flag as returned by `visited-file-modtime'. */)
current_buffer->modtime = mtime;
current_buffer->modtime_size = -1;
}
else if (current_buffer->base_buffer)
error ("An indirect buffer does not have a visited file");
else
{
register Lisp_Object filename;

View file

@ -4733,6 +4733,7 @@ extern bool internal_delete_file (Lisp_Object);
extern Lisp_Object check_emacs_readlinkat (int, Lisp_Object, char const *);
extern bool file_directory_p (Lisp_Object);
extern bool file_accessible_directory_p (Lisp_Object);
extern Lisp_Object buffer_visited_file_modtime (struct buffer *);
extern void init_fileio (void);
extern void syms_of_fileio (void);

View file

@ -218,7 +218,7 @@ record_first_change (void)
base_buffer = base_buffer->base_buffer;
bset_undo_list (current_buffer,
Fcons (Fcons (Qt, Fvisited_file_modtime ()),
Fcons (Fcons (Qt, buffer_visited_file_modtime (base_buffer)),
BVAR (current_buffer, undo_list)));
}