14

Context

When emacs detects that a file was changed outside of an editing buffer.

Observed

emacs will ask:

somefilename changed in disk; really edit the buffer? (y, n, r or C-h)

(Incidentally, sometimes it happens even when there is no actual change, e.g. remote file on a server with drifted clock, but the question is interesting in all cases.)

Wished

emacs would ask:

somefilename changed in disk; really edit the buffer? (y, n, r, d or C-h)

Pressing d would show the difference between versions, e.g. ediff-current-file which allows to walk the differences interactively.

Additional information

That would be similar to what Debian package management does when it detects that a config file locally customized gets updated by a newer version of its owning package. For an example see A new version of configuration file /etc/default/grub is available, but the version installed currently has been locally modified - Unix & Linux Stack Exchange

Search before you ask

I usually find my way to solutions (e.g. emacsclient - From an external script, open file and run some simple expression whether emacs already running or not - Emacs Stack Exchange) but after searching on this I could not find any pre-existing solution.

I'd consider adjusting this myself but am not proficient enough in emacs-lisp and emacs internals.

Sketch of solution

  • Pressing C-g then 'M-x ediff-current-file` does the job, at the cost of some keystrokes.
  • The goal here would be to run ediff-current-file on one keypress at the above prompt.
2

1 Answer 1

4

grepping for "really edit the buffer" in emacs source I found function ask-user-about-supersession-threat in file userlock.el.

It seems straightforward to add a d choice for calling ediff-current-file. I haven't tested this extensively, though (edits marked with ;;- comments).

(defun ask-user-about-supersession-threat (fn)
  "Ask a user who is about to modify an obsolete buffer what to do.
This function has two choices: it can return, in which case the modification
of the buffer will proceed, or it can (signal 'file-supersession (file)),
in which case the proposed buffer modification will not be made.

You can rewrite this to use any criterion you like to choose which one to do.
The buffer in question is current when this function is called."
  (discard-input)
  (save-window-excursion
    (let ((prompt
       (format "%s changed on disk; \
really edit the buffer? (y, n, r, d or C-h) " ;;- changed
           (file-name-nondirectory fn)))
      (choices '(?y ?n ?r ?d ?? ?\C-h))       ;;- changed
      answer)
      (while (null answer)
    (setq answer (read-char-choice prompt choices))
    (cond ((memq answer '(?? ?\C-h))
           (ask-user-about-supersession-help)
           (setq answer nil))
          ((eq answer ?r)
           ;; Ask for confirmation if buffer modified
           (revert-buffer nil (not (buffer-modified-p)))
           (signal 'file-supersession
               (list "File reverted" fn)))
          ((eq answer ?d)                     ;;- added
           (ediff-current-file))              ;;- added
          ((eq answer ?n)
           (signal 'file-supersession
               (list "File changed on disk" fn)))))
      (message
       "File on disk now will become a backup file if you save these changes.")
      (setq buffer-backed-up nil))))
3
  • Seems to work well on emacs 46.1 on Ubuntu 16.04. Thanks! Oct 23, 2016 at 7:34
  • @StéphaneGourichon you shouldn't reveal that you're a time traveler so casually, but glad to know it'll keep working all the way to 46.1 (and that Emacs is still going strong in your time)!
    – mtraceur
    May 24 at 20:03
  • @mtraceur thanks for noticing. Indeed, after a few trips to The Restaurant at the End of the Universe you're less careful about such details. ;-D May 25 at 21:40

Your Answer

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

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