unofficial mirror of bug-gnu-emacs@gnu.org 
 help / color / mirror / code / Atom feed
* bug#18: Fine-grained revert-buffer
       [not found] <jwvpruii0xr.fsf@iro.umontreal.ca>
@ 2013-12-17  3:16 ` Dmitry Gutov
  2013-12-17 13:32   ` Stefan Monnier
  2018-04-12  6:21 ` Toon Claes
  2019-04-26 22:42 ` Mauro Aranda
  2 siblings, 1 reply; 24+ messages in thread
From: Dmitry Gutov @ 2013-12-17  3:16 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 18

The described functionality seems to be more or less available now.

Stefan Monnier <monnier@iro.umontreal.ca> writes:

> Write a revert-buffer that uses something like `diff' and then applies
> the patch to the buffer, so as to better preserve markers and undo
> info.

`revert-buffer' now preserves undo history.

> This would be used in places where a revert-buffer is needed but the
> changes are expected to be small, e.g. in VC.

`diff-hl' (in GNU ELPA) has command `diff-hl-revert-hunk' which reverts
only the diff hunk around point.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2013-12-17  3:16 ` bug#18: Fine-grained revert-buffer Dmitry Gutov
@ 2013-12-17 13:32   ` Stefan Monnier
  0 siblings, 0 replies; 24+ messages in thread
From: Stefan Monnier @ 2013-12-17 13:32 UTC (permalink / raw)
  To: Dmitry Gutov; +Cc: 18

>> Write a revert-buffer that uses something like `diff' and then applies
>> the patch to the buffer, so as to better preserve markers and undo
>> info.
> `revert-buffer' now preserves undo history.

It's still significantly coarser than using diff: revert-buffer is
treated as a single delete+insert, so only the markers before the first
modification or after the last modification are preserved.


        Stefan





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
       [not found] <jwvpruii0xr.fsf@iro.umontreal.ca>
  2013-12-17  3:16 ` bug#18: Fine-grained revert-buffer Dmitry Gutov
@ 2018-04-12  6:21 ` Toon Claes
  2018-04-12 12:18   ` Stefan Monnier
  2019-04-26 22:42 ` Mauro Aranda
  2 siblings, 1 reply; 24+ messages in thread
From: Toon Claes @ 2018-04-12  6:21 UTC (permalink / raw)
  To: Stefan Monnier, Dmitry Gutov; +Cc: 18

[-- Attachment #1: Type: text/plain, Size: 395 bytes --]

I was digging through some old bugs, in ran into this one.

> It's still significantly coarser than using diff: revert-buffer is
> treated as a single delete+insert, so only the markers before the first
> modification or after the last modification are preserved.

What does M-x diff-buffer-with-file not do what you are trying to
achieve?
Also M-x ediff-current-file might be usable.


-- Toon

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2018-04-12  6:21 ` Toon Claes
@ 2018-04-12 12:18   ` Stefan Monnier
  2018-04-14  7:00     ` Toon Claes
  0 siblings, 1 reply; 24+ messages in thread
From: Stefan Monnier @ 2018-04-12 12:18 UTC (permalink / raw)
  To: Toon Claes; +Cc: 18, Dmitry Gutov

Hi,

> I was digging through some old bugs, in ran into this one.
>> It's still significantly coarser than using diff: revert-buffer is
>> treated as a single delete+insert, so only the markers before the first
>> modification or after the last modification are preserved.
> What does M-x diff-buffer-with-file not do what you are trying to
> achieve?
> Also M-x ediff-current-file might be usable.

Not sure I understand the question: neither of those modifies the
current buffer, right?


        Stefan





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2018-04-12 12:18   ` Stefan Monnier
@ 2018-04-14  7:00     ` Toon Claes
  2018-04-14 14:14       ` Stefan Monnier
  0 siblings, 1 reply; 24+ messages in thread
From: Toon Claes @ 2018-04-14  7:00 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: 18, Dmitry Gutov

[-- Attachment #1: Type: text/plain, Size: 386 bytes --]

Stefan Monnier <monnier@IRO.UMontreal.CA> writes:

>> What does M-x diff-buffer-with-file not do what you are trying to
>> achieve?
>> Also M-x ediff-current-file might be usable.
>
> Not sure I understand the question: neither of those modifies the
> current buffer, right?

With ediff you can apply chunks, but I'm not sure what kind of an
interface you would like to have?


-- Toon

[-- Attachment #2: signature.asc --]
[-- Type: application/pgp-signature, Size: 832 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2018-04-14  7:00     ` Toon Claes
@ 2018-04-14 14:14       ` Stefan Monnier
  0 siblings, 0 replies; 24+ messages in thread
From: Stefan Monnier @ 2018-04-14 14:14 UTC (permalink / raw)
  To: Toon Claes; +Cc: 18, Dmitry Gutov

> With ediff you can apply chunks, but I'm not sure what kind of an
> interface you would like to have?

Something like

M-x revert-buffer-with-fine-grain RET


        Stefan





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
       [not found] <jwvpruii0xr.fsf@iro.umontreal.ca>
  2013-12-17  3:16 ` bug#18: Fine-grained revert-buffer Dmitry Gutov
  2018-04-12  6:21 ` Toon Claes
@ 2019-04-26 22:42 ` Mauro Aranda
  2019-04-27  7:34   ` Eli Zaretskii
                     ` (2 more replies)
  2 siblings, 3 replies; 24+ messages in thread
From: Mauro Aranda @ 2019-04-26 22:42 UTC (permalink / raw)
  To: 18


[-- Attachment #1.1: Type: text/plain, Size: 3416 bytes --]

Short story of how I got to this bug report:

For a while now, I've been wanting to contribute to Emacs by doing
something more than reporting bugs and try to provide trivial fixes for
the bugs I found.  So I looked into emacs-devel, to read about
recomendations for beginning to contribute.  Based on some of the mails
I found [1], it looks like working on some wishlist items or minor bugs
would be good.  So I said to myself: OK, let's see what is the oldest
one still open.  And here I am.


Now I'll make a summary of what I've understood from the bug report:

The wish is to have a command that would act like 'revert-buffer'
(e.g., modifying the buffer rightaway), but that tries to do a better job
preserving markers.  Also, it is desirable that undo info is preserved.
It is known that 'revert-buffer' preserves undo info nowadays, but what I
understand is that it would be good to keep undo info of parts of the
total reverted change, so the undo of the reverted action can be made by
steps, and not as a single undo operation.

I think that the alternatives proposed after the report [2] do not
fulfill the wish because they do not modify the buffer immediately.  I'm
not sure how they act in regards to preserving markers and the undo
info, though.

AFAIK, the functionality wanted is still not present, so I'd guess it's
still relevant to work in this matter.

So for a week or so now, I've been working in a command that does what I
think it is wanted.  The command is called 'revert-buffer-by-hunks'
(I've added 'rbbh' as a prefix for sending the file for you to
see/test), because it calls 'diff' and then with the output patches the
buffer.

At first, I wrote a command that used diff-mode under the hood, but I've
been having troubles with preserving markers.  So I took a step back,
and wrote a new function that patches the buffer with the contents of
the file visited on disk.  With that done, I think it is time for me to
show what I've written so far, in order to:

1) Know if the functionality is present (I don't think so, but I believe
this is the first thing to know in order to advance).
2) There's still interest in having this command.
3) Know if working on this subject would be appreciated, or should I
move on to other things.
4) Receieve feedback, suggestions, fixes on things I'm sure I'm missing.
5) Discuss some of the questions that have arisen while I've been
working on this.

I'll wait for answers regarding to 1-4.  With regards to 5, I would like
to read opinions about:
a) What variables would you think should be customizable?
b) After reverting by hunks, I think it would be desirable to navigate
through the hunks reverted and toggle their state (i.e., go back and
forth to the contents before the revert operation and the contens on
disk).  That is because I think it would be kinda annoying to want to
undo some of the reverted hunks, and to do that having to undo
sequentially from the Nth hunk reverted to the desired one.

I attach a first draft of my work.  I'm hoping to hear suggestions and
corrections to improve it.

Best regards,
Mauro.

[1]
http://lists.gnu.org/archive/html/emacs-devel/2018-07/msg00451.html
http://lists.gnu.org/archive/html/emacs-devel/2017-08/msg00675.html
http://lists.gnu.org/archive/html/emacs-devel/2013-10/msg00805.html

[2]
Command diff-hl-revert-hunk, from diff-hl package
Command diff-buffer-with-file
Command ediff-current-file

[-- Attachment #1.2: Type: text/html, Size: 4123 bytes --]

[-- Attachment #2: rbbh-bug18.el --]
[-- Type: text/x-emacs-lisp, Size: 9294 bytes --]

;;; rbbh.el --- Revert Buffer By Hunks -*- lexical-binding: t -*-

(require 'diff)

;; At least for now, this are defconst.

(defconst rbbh-diff-command "diff"
  "Name of the command to run diff")

(defconst rbbh-diff-switches "--normal"
  "Switches to pass to diff.")

(defconst rbbh-diff-change-command-regexp
  (let ((rng "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)"))
    (concat "^" rng "\\([acd]\\)" rng "$"))
  "Regular expression that matches the change commands for each hunk
Should be in synch with the switch used to call diff.")

(defconst rbbh-diff-buffer-name "*RBBH-Diff*"
  "The name of the diff buffer internally created by `rbbh--run-diff'.")

(defvar rbbh-current-diff-buffer-name nil
  "Name of the current diff buffer.")

(defvar rbbh-total-hunks 0
  "Total hunks in the diff output.")

;; If `diff' and `diff-mode' are not to be required, this function should be
;; changed to do a lot of what `diff-no-select' does.
(defun rbbh--run-diff (buf)
  "Compare contents of buffer BUF with those of the file it visits.
Runs `rbbh-diff-command' command to make the comparison, and puts its output
in a buffer, with basename `rbbh-diff-buffer-name'.
The command is run with the switches `rbbh-diff-switches'."
  (let ((diff-command rbbh-diff-command)
	(diff-use-labels nil)) ; Don't care about labels.
    (setq rbbh-current-diff-buffer-name (generate-new-buffer
					 rbbh-diff-buffer-name))
    (with-current-buffer buf
      (diff-no-select buf buffer-file-name rbbh-diff-switches
		      t rbbh-current-diff-buffer-name))))

;; With this, reverted hunks can be undone one by one.
(defsubst rbbh--split-undo-hunk (buf)
  "Force undo history to separate hunk replacements in buffer BUF."
  (with-current-buffer buf
    (undo-boundary)))

(defun rbbh-delete-line (&optional arg)
  "Delete ARG lines (or the current line, if ARG is 0).
Does not put the killed text in the `kill-ring'.  See `kill-whole-line' for
details on ARG."
  (setq arg (or arg 1))
  (if (and (> arg 0)
	   (eobp)
	   (save-excursion (forward-visible-line 0)
			   (eobp)))
      (signal 'end-of-buffer nil))
  (if (and (< arg 0)
	   (bobp)
	   (save-excursion (end-of-visible-line) (bobp)))
      (signal 'beginning-of-buffer nil))
  (cond ((zerop arg)
         (delete-region (progn (forward-visible-line 0) (point))
                        (progn (end-of-visible-line) (point))))
        ((< arg 0)
         (delete-region (progn (end-of-visible-line) (point))
                        (progn (forward-visible-line (1+ arg))
                               (unless (bobp)
                                 (backward-char))
                               (point))))
        (t
         (delete-region (progn (forward-visible-line 0) (point))
			(progn (forward-visible-line arg) (point))))))

(defsubst rbbh-count-total-hunks (diff-buf &optional change-command-re)
  (with-current-buffer diff-buf
    (save-excursion
      (goto-char (point-min))
      (let ((count 0)
	    (re (or change-command-re rbbh-diff-change-command-regexp)))
	(while (re-search-forward re nil t)
	  (setq count (1+ count)))
	count))))

(defsubst rbbh-get-hunk-contents (beg end)
  "Get the hunk contents from positions BEG to END.
Expects that a diff buffer is the current buffer."
  (let ((start (point)))
    (forward-line (1+ (- beg end)))
    (let ((text (buffer-substring start (point))))
      ;; Remember that we are using the --normal switch, hence the > and <
      ;; replacement.
      (setq text (replace-regexp-in-string "^[><] " "" text))
      text)))

(defun rbbh-patch-buffer (buf diff-buf)
  "Patch the buffer BUF according to the contents of the diff buffer DIFF-BUF.
It works with a diff buffer that contains a --normal output from diff."
  ;; line-offset keeps memory of the lines added and deleted to the buffer BUF,
  ;; and it is necessary because the diff output will stay the same (line
  ;; references will stay relative to the unpatched buffer).
  ;; Added lines decrements offset, and deleted lines increment it.
  (let ((line-offset 0)
	(column (current-column))) ; To restore point just right.
    (save-excursion
      (with-current-buffer diff-buf
	(goto-char (point-min))
	(save-excursion
	  (while (re-search-forward rbbh-diff-change-command-regexp nil t)
	    (rbbh--split-undo-hunk buf)  ; Make each change of hunk undoable.
	    (forward-line) ; skip the command.
	    ;; Get ranges and the action, from the previous match.
	    (let* ((action-cmd (match-string 4))
		   (old-from (string-to-number (match-string 1)))
		   (old-to (if (match-beginning 3)
			       (string-to-number (match-string 3))
			     old-from))
		   (new-from (string-to-number (match-string 5)))
		   (new-to (if (match-beginning 7)
			       (string-to-number (match-string 7))
			     new-from)))
	      (cond ((equal action-cmd "a")
		     ;; When adding, we take the text and remove > and <
		     ;; (diff was called with --normal switch).
		     ;; Then navigate to the line, accounting the offset,
		     ;; and insert the text.
		     (let ((text (rbbh-get-hunk-contents new-to new-from)))
		       (with-current-buffer buf
			 (goto-char (point-min))
			 (forward-line (- old-from line-offset))
			 (setq line-offset (- line-offset (1+ (- new-to
								 new-from))))
			 (insert text))))
		    ((equal action-cmd "d")
		     ;; When deleting, navigate to the correct line and kill
		     ;; as many lines as the range in the diff output says.
		     (with-current-buffer buf
		       (goto-char (point-min))
		       (forward-line (1- (- old-from line-offset)))
		       (setq line-offset (+ line-offset (1+
							 (- old-to old-from))))
		       (rbbh-delete-line (1+ (- old-to old-from)))))
		    ((equal action-cmd "c")
		     ;; When changing, is a combination of adding and deleting.
		     ;; Get the text after "---", and act similar as we would
		     ;; with adding.
		     ;; But before, kill the lines, as we do when deleting.
		     (re-search-forward "^---")
		     (forward-line)
		     (let ((text (rbbh-get-hunk-contents new-to new-from)))
		       (with-current-buffer buf
			 (goto-char (point-min))
			 (forward-line (1- (- old-from line-offset)))
			 (rbbh-delete-line (1+ (- old-to old-from)))
			 (setq line-offset (+ line-offset (- old-to old-from)
					      new-from (- new-to)))
			 (insert text))))
		    (t
		     (error "Unknown command action in diff output"))))))))
    (move-to-column column))) ; Restore column.

;; Not sure if the function would be a good candidate for
;; `revert-buffer-function'.
;; But just in case, make it take _ignore-auto as an argument.
;; Note that reverting with the contents of an auto save file is not supported.
;; It could be added, if suggested.
(defun rbbh-revert-buffer-by-hunks (&optional _ignore-auto noconfirm)
  "Revert buffer by hunks, instead of doing a single deletion plus insertion.
This action is useful when you want to revert a buffer (like you would do with
`revert-buffer'), but then would like to undo some of the reverting.
When the buffer hasn't been modified, nothing is done.
This function is only useful for buffers visting files.
After reverting, it marks the buffer as not modified.

When NOCONFIRM is non-nil, don't ask for confirmation before reverting.  The
other way of avoiding the query is provided by the variable 
`revert-without-query'.  Nevertheless, you will be always prompted, if the
file was changed externally.

The optional argument _IGNORE-AUTO is ignored and is provided only for
compatibility with `revert-buffer'.  Thus, it is a candidate for the variable
`revert-buffer-function'."
  (interactive)
  (with-current-buffer (or (buffer-base-buffer (current-buffer))
			   (current-buffer))
    (save-excursion
      (let ((file-name buffer-file-name)
	    (buf (current-buffer))
	    ;; Just in case we are not the revert-buffer-function.
	    (revert-buffer-in-progress-p t))
	;; Repeat some of what revert-buffer--default does, because it is not
	;; sure reverting by hunks is a candidate for revert-buffer-function.
	(cond ((null file-name)
	       (error "Buffer does not seem to be associated with any file"))
	      ((or (and (not (verify-visited-file-modtime buf))
			(yes-or-no-p
			 (format "File %s was modified outside of Emacs.  Really revert?"
				 file-name)))
		   noconfirm
		   ;; Respect user choice.
		   (catch 'found
		     (dolist (regexp revert-without-query)
		       (when (string-match regexp file-name)
			 (throw 'found t))))
		   (yes-or-no-p (format "Revert buffer from file %s? "
					file-name)))
	       (run-hooks 'before-revert-hook)
	       (rbbh--run-diff buf)
	       (rbbh-patch-buffer buf rbbh-current-diff-buffer-name)
	       ;; Mark the buffer as not modified, like it would happen with
	       ;; the default behavior of revert-buffer.
	       (set-buffer-modified-p nil)
	       ;; Report to the user (this could be made optional).
	       (setq rbbh-total-hunks (rbbh-count-total-hunks
				       rbbh-current-diff-buffer-name))
	       (message "%d %s reverted" rbbh-total-hunks
			(if (= rbbh-total-hunks 1)
			    "hunk"
			  "hunks"))
	       ;; Kill the diff buffer we used.
	       (kill-buffer rbbh-current-diff-buffer-name)
	       (run-hooks 'after-revert-hook))
	      (t
	       (message "Revert aborted")))))))

(provide 'rbbh)

;;; rbbh.el ends here

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-26 22:42 ` Mauro Aranda
@ 2019-04-27  7:34   ` Eli Zaretskii
  2019-04-27 15:10     ` Mauro Aranda
  2019-04-27  8:31   ` martin rudalics
  2019-04-28  2:47   ` Richard Stallman
  2 siblings, 1 reply; 24+ messages in thread
From: Eli Zaretskii @ 2019-04-27  7:34 UTC (permalink / raw)
  To: Mauro Aranda; +Cc: 18

> From: Mauro Aranda <maurooaranda@gmail.com>
> Date: Fri, 26 Apr 2019 19:42:02 -0300
> 
> For a while now, I've been wanting to contribute to Emacs by doing
> something more than reporting bugs and try to provide trivial fixes for
> the bugs I found.  So I looked into emacs-devel, to read about
> recomendations for beginning to contribute.  Based on some of the mails
> I found [1], it looks like working on some wishlist items or minor bugs
> would be good.  So I said to myself: OK, let's see what is the oldest
> one still open.  And here I am.

Thanks!

> The wish is to have a command that would act like 'revert-buffer'
> (e.g., modifying the buffer rightaway), but that tries to do a better job
> preserving markers.  Also, it is desirable that undo info is preserved.
> It is known that 'revert-buffer' preserves undo info nowadays, but what I
> understand is that it would be good to keep undo info of parts of the
> total reverted change, so the undo of the reverted action can be made by
> steps, and not as a single undo operation.
> 
> I think that the alternatives proposed after the report [2] do not
> fulfill the wish because they do not modify the buffer immediately.  I'm
> not sure how they act in regards to preserving markers and the undo
> info, though.
> 
> AFAIK, the functionality wanted is still not present, so I'd guess it's
> still relevant to work in this matter.

Sounds correct to me.

> So for a week or so now, I've been working in a command that does what I
> think it is wanted.  The command is called 'revert-buffer-by-hunks'
> (I've added 'rbbh' as a prefix for sending the file for you to
> see/test), because it calls 'diff' and then with the output patches the
> buffer.
> 
> At first, I wrote a command that used diff-mode under the hood, but I've
> been having troubles with preserving markers.  So I took a step back,
> and wrote a new function that patches the buffer with the contents of
> the file visited on disk.  With that done, I think it is time for me to
> show what I've written so far, in order to:
> 
> 1) Know if the functionality is present (I don't think so, but I believe
> this is the first thing to know in order to advance).
> 2) There's still interest in having this command.
> 3) Know if working on this subject would be appreciated, or should I
> move on to other things.
> 4) Receieve feedback, suggestions, fixes on things I'm sure I'm missing.

Please take a look at replace-buffer-contents, which is new with Emacs
26.  It might allow you to implement this functionality in a much
simpler way, as it already contains an internal implementation of a
Diff-like comparison algorithm, and doesn't require the Diff program
to be installed.

One caveat: replace-buffer-contents can be very slow when the buffer
is large and reverting it requires a large number of small changes.
It will fall back to a simpler algorithm for large numbers of changes,
and could give up entirely if making the changes takes too much time,
see its doc string.  Perhaps in those cases we should fall back to a
different code, like the one you wrote.

Did you time your code?  How long does it take to revert buffers of
different sizes with different amounts of changes?

> a) What variables would you think should be customizable?

The name of the Diff command should be customizable.  Or maybe just
use diff-command already provided by diff.el.  Same with Diff
switches.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-26 22:42 ` Mauro Aranda
  2019-04-27  7:34   ` Eli Zaretskii
@ 2019-04-27  8:31   ` martin rudalics
  2019-04-28  2:47   ` Richard Stallman
  2 siblings, 0 replies; 24+ messages in thread
From: martin rudalics @ 2019-04-27  8:31 UTC (permalink / raw)
  To: Mauro Aranda, 18

 > 4) Receieve feedback, suggestions, fixes on things I'm sure I'm missing.

What's IMHO urgently needed are better heuristics for restoring
markers after reverting their buffer.  Currently, most markers end up
at the beginning or end of a hunk that as been restored and thus
become useless.

What we probably need is an extra step to scan the buffer for markers
and save their textual context before reverting and a step to restore
them according to their textual context after reverting.  But if your
method allows to easily determine which hunks remain unchanged, we
could avoid such textual search for markers in unchanged hunks and,
depending on the approach used for replacing text, simply restore
these markers from their offsets from the beginning of the hunk they
belong to.

Many thanks for working on this, martin





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-27  7:34   ` Eli Zaretskii
@ 2019-04-27 15:10     ` Mauro Aranda
  2019-04-27 16:30       ` Eli Zaretskii
  2019-04-29 12:49       ` martin rudalics
  0 siblings, 2 replies; 24+ messages in thread
From: Mauro Aranda @ 2019-04-27 15:10 UTC (permalink / raw)
  To: 18

[-- Attachment #1: Type: text/plain, Size: 4416 bytes --]

Eli and Martin, thanks for your answers.

Eli Zaretskii <eliz@gnu.org> writes:

> Please take a look at replace-buffer-contents, which is new with Emacs
> 26.  It might allow you to implement this functionality in a much
> simpler way, as it already contains an internal implementation of a
> Diff-like comparison algorithm, and doesn't require the Diff program
> to be installed.

I didn't know of replace-buffer-contents, so I took a look at it.  Nice
that its documentation even mentions the problem when a marker is
inside a hunk, because of the delete + insert thing (just like Martin
mentions).  IMO, it does most of the things required, but here is one
problem I notice with respect to the expected functionality of
revert-buffer-by-hunks (as I've understood it):

It only calls Fundo_boundary before starting the whole set of
modifications, and thus after replacing the contents (in my tests, the
whole buffer), a single C-/ brings all the changes back, much like
revert-buffer.  And since it binds inhibit-modification-hooks to t, I
think I can't bind locally after-change-functions to an expression that
calls undo-boundary, to do the trick.

Perhaps an optional call to Fundo_boundary in the while loop could be
enough, but I'm not sure how much it will impact on the speed of
replace-buffer-contents.  Or more, if it is justified to add that call.
Please, point out to me if I'm not seeing this right.

Other than that, it looks like a perfect candidate to use (at least to me)
to get the functionality wanted.

> One caveat: replace-buffer-contents can be very slow when the buffer
> is large and reverting it requires a large number of small changes.
> It will fall back to a simpler algorithm for large numbers of changes,
> and could give up entirely if making the changes takes too much time,
> see its doc string.  Perhaps in those cases we should fall back to a
> different code, like the one you wrote.

> Did you time your code?  How long does it take to revert buffers of
> different sizes with different amounts of changes?

I haven't timed it yet.  I didn't know if it would be considered good
enough, to time it.  For a week, I've been testing it manually with some
of the changes in the Emacs sources, and the experience has been
satisfactory.  Are there, by any chance, such tests for
replace-buffer-contents?  I could use them, for comparison purposes.
I will try in the following days to define some parameters (such as
buffer size), and time revert-buffer-by-hunks, to provide some numbers.

Provided it is fast enough, I think something like replacing by hunks a
region would be a good fallback to replace-buffer-contents.  I sure hope
so.

>> a) What variables would you think should be customizable?
>
> The name of the Diff command should be customizable.  Or maybe just
> use diff-command already provided by diff.el.  Same with Diff
> switches.

I agree.  If using diff.el, it makes total sense to use those
variables.  Of course, that means the patch-buffer function should
be modified to work on the different diff output formats (I think --context
and --unified should be enough).  For the record, I don't propose to use
diff-apply-hunk and other diff-mode.el functions, because when I used
that, I ended up with markers at (point-min), I don't know why.  But if
it is desired to reuse those functions instead of repeating code, I
think I will need time (and help, perhaps), to understand why that
happened.


martin rudalics <rudalics@gmx.at> writes:

> What we probably need is an extra step to scan the buffer for markers
> and save their textual context before reverting and a step to restore
> them according to their textual context after reverting.  But if your

When I bumped into the problem of the marker being sent to the
beginning of the hunk, I started looking for something to get the
markers of the buffer, but didn't found anything at the Lisp level.

> method allows to easily determine which hunks remain unchanged, we
> could avoid such textual search for markers in unchanged hunks and,
> depending on the approach used for replacing text, simply restore
> these markers from their offsets from the beginning of the hunk they
> belong to.

Yes, I believe that by getting the diff output and with the line-offset
handling in the patch-buffer function, it would be easy to determine the
unchanged regions.


Thanks again to both of you.

Best regards,
Mauro.

[-- Attachment #2: Type: text/html, Size: 5232 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-27 15:10     ` Mauro Aranda
@ 2019-04-27 16:30       ` Eli Zaretskii
  2019-04-27 17:46         ` Mauro Aranda
  2019-04-29 12:49       ` martin rudalics
  1 sibling, 1 reply; 24+ messages in thread
From: Eli Zaretskii @ 2019-04-27 16:30 UTC (permalink / raw)
  To: Mauro Aranda; +Cc: 18

> From: Mauro Aranda <maurooaranda@gmail.com>
> Date: Sat, 27 Apr 2019 12:10:45 -0300
> Cc: Eli Zaretskii <eliz@gnu.org>, martin rudalics <rudalics@gmx.at>
> 
> I didn't know of replace-buffer-contents, so I took a look at it.  Nice
> that its documentation even mentions the problem when a marker is
> inside a hunk, because of the delete + insert thing (just like Martin
> mentions).  IMO, it does most of the things required, but here is one
> problem I notice with respect to the expected functionality of
> revert-buffer-by-hunks (as I've understood it):
> 
> It only calls Fundo_boundary before starting the whole set of
> modifications, and thus after replacing the contents (in my tests, the
> whole buffer), a single C-/ brings all the changes back, much like
> revert-buffer.

Is there a requirement to be able to undo the revert piecemeal? What
would be the use case for that?

> > Did you time your code?  How long does it take to revert buffers of
> > different sizes with different amounts of changes?
> 
> I haven't timed it yet.  I didn't know if it would be considered good
> enough, to time it.  For a week, I've been testing it manually with some
> of the changes in the Emacs sources, and the experience has been 
> satisfactory.  Are there, by any chance, such tests for
> replace-buffer-contents?

You can find one in bug#31888.

Also, this discussion:

  http://lists.gnu.org/archive/html/help-gnu-emacs/2019-02/msg00000.html

indicates that using JSON pretty-printer might produce a good test
case.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-27 16:30       ` Eli Zaretskii
@ 2019-04-27 17:46         ` Mauro Aranda
  0 siblings, 0 replies; 24+ messages in thread
From: Mauro Aranda @ 2019-04-27 17:46 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: 18

[-- Attachment #1: Type: text/plain, Size: 1359 bytes --]

Eli Zaretskii <eliz@gnu.org> writes:

> Is there a requirement to be able to undo the revert piecemeal? What
> would be the use case for that?

Your questions made me open my eyes, so thanks.  I originally thought
that it would be a good thing, for example if the user wants to revert some
of the changes but keep others.  But that use case is already covered by
using diff-buffer-with-file, for example, and applying (or not) each hunk
separately.  Even better, the undo process doesn't have to be from
the Nth hunk to the 1st, in order.  So please, ignore what I said about
that problem, using replace-buffer-contents seems to be a great choice
to address this wishlist item.

>> I haven't timed it yet.  I didn't know if it would be considered good
>> enough, to time it.  For a week, I've been testing it manually with some
>> of the changes in the Emacs sources, and the experience has been
>> satisfactory.  Are there, by any chance, such tests for
>> replace-buffer-contents?
>
> You can find one in bug#31888.
>
> Also, this discussion:
>
>   http://lists.gnu.org/archive/html/help-gnu-emacs/2019-02/msg00000.html
>
> indicates that using JSON pretty-printer might produce a good test
> case.

Thanks.

I'll keep working on the potential fallback for replace-buffer-contents,
and report back when I feel I've made some progress.

Best regards,
Mauro.

[-- Attachment #2: Type: text/html, Size: 1754 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-26 22:42 ` Mauro Aranda
  2019-04-27  7:34   ` Eli Zaretskii
  2019-04-27  8:31   ` martin rudalics
@ 2019-04-28  2:47   ` Richard Stallman
  2019-04-29 23:32     ` Mauro Aranda
  2 siblings, 1 reply; 24+ messages in thread
From: Richard Stallman @ 2019-04-28  2:47 UTC (permalink / raw)
  To: Mauro Aranda; +Cc: 18

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > So for a week or so now, I've been working in a command that does what I
  > think it is wanted.  The command is called 'revert-buffer-by-hunks'
  > (I've added 'rbbh' as a prefix for sending the file for you to
  > see/test), because it calls 'diff' and then with the output patches the
  > buffer.

It sounds like an improvement in functionality,
but wouldn't it be a lot slower?

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-27 15:10     ` Mauro Aranda
  2019-04-27 16:30       ` Eli Zaretskii
@ 2019-04-29 12:49       ` martin rudalics
  2019-05-02 15:54         ` Basil L. Contovounesios
  1 sibling, 1 reply; 24+ messages in thread
From: martin rudalics @ 2019-04-29 12:49 UTC (permalink / raw)
  To: Mauro Aranda, 18

 > When I bumped into the problem of the marker being sent to the
 > beginning of the hunk, I started looking for something to get the
 > markers of the buffer, but didn't found anything at the Lisp level.

We could introduce a function 'marker-list' based on BUF_MARKERS.

martin





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-28  2:47   ` Richard Stallman
@ 2019-04-29 23:32     ` Mauro Aranda
  2019-04-30  0:17       ` Mauro Aranda
  0 siblings, 1 reply; 24+ messages in thread
From: Mauro Aranda @ 2019-04-29 23:32 UTC (permalink / raw)
  To: rms; +Cc: 18

[-- Attachment #1: Type: text/plain, Size: 460 bytes --]

Richard Stallman <rms@gnu.org> writes:

> It sounds like an improvement in functionality,
> but wouldn't it be a lot slower?

Hello Richard.

Compared to revert-buffer, yes, I would expect it to be slower (not sure
if a lot).  But maybe the trade-off between time and preserving some
buffer information is worth it, let's see.

I'm finalizing some benchmarking, which I'll post in another email.
I'll wait for opinions about the results.

Best regards,
Mauro.

[-- Attachment #2: Type: text/html, Size: 639 bytes --]

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-29 23:32     ` Mauro Aranda
@ 2019-04-30  0:17       ` Mauro Aranda
  2019-05-15 23:10         ` Mauro Aranda
  0 siblings, 1 reply; 24+ messages in thread
From: Mauro Aranda @ 2019-04-30  0:17 UTC (permalink / raw)
  To: 18; +Cc: rms


[-- Attachment #1.1: Type: text/plain, Size: 2294 bytes --]

I've now written a similar function to revert the buffer, but using
replace-buffer-contents as I was suggested.  The new attached file
contains such function, which I called revert-buffer-with-fine-grain, to
honor a previous post.

I kept it as similar as I could to the revert-buffer-by-hunks
function, and went ahead to time both functions (I figure there will be
enough time to add functionality to them).  I additionally timed
revert-buffer.

For the files in Bug#31888, the results were:
revert-buffer: 0.122238819
revert-buffer-with-fine-grain: 2.85150876
rbbh-revert-buffer-by-hunks: 2.044583634

all times in seconds, substracting GC time.

To gather more data, I compared emacs-25.3 and emacs-26.2 C source
files (from the src/ directory), checking them out from the git
repository.  I did the test as if I was going back from emacs-26.2 to
emacs-25.3.  I think these files provided a good range of changes in
size and number of hunks, obtained from `diff --normal'.

I attach the data as ascii file.  Let me know if I should send it in
another format.  The tests are with the latest master, optimized build,
run as `emacs -Q'.

For the majority of files, revert-buffer and
revert-buffer-with-fine-grain spent a similar amount of time when the
buffers or changes are not too big, so I believe that's promising for
implementing this functionality.  On the contrary, reverting by hunks
(by calling diff), takes 1 to 4 times more than the other functions, in
these cases.

When there are many changes, replace-buffer-contents starts taking too
much time (as the docs warns).  In those situations, reverting by hunks
does a much better job than using replace-buffer-contents, but I'm not
sure if it does a good enough job.

Some problematic files:
doprnt.c:
revert-buffer-with-fine-grain took 28.6 times more than revert-buffer
and rbbh-revert-buffer-by-hunks took 1.4 times more.

alloc.c:
revert-buffer-with-fine-grain took 18 times more than revert-buffer
and rbbh-revert-buffer-by-hunks took 6.5 times more.

lisp.h:
lisp.h took almost 9 minutes to revert, using
revert-buffer-with-fine-grain.  It took 0.86 seconds to revert with
rbbh-revert-buffer-by-hunks.

I'll wait for opinions about the data I've collected.  At least it was
super fun writing these tests.

Best regards,
Mauro.

[-- Attachment #1.2: Type: text/html, Size: 2554 bytes --]

[-- Attachment #2: bug18-benchmark-report.txt --]
[-- Type: text/plain, Size: 16641 bytes --]

FILE 	OLD-SIZE	NEW-SIZE	HUNKS	REVERT-BUFFER	REVERT-BUFFER-WITH-FINE-GRAIN	RBBH-REVERT-BUFFER-BY-HUNKS	FASTEST
alloc.c	204520	210496	283	0.161867116	2.917511896	1.0552727629999983	REVERT-BUFFER
atimer.c	14123	14136	4	0.046020625	0.008248911	0.035602406	REVERT-BUFFER-WITH-FINE-GRAIN
atimer.h	2171	2172	2	0.038901494	0.002417523	0.035891824	REVERT-BUFFER-WITH-FINE-GRAIN
bidi.c	124786	125185	13	0.090656241	0.060416566	0.082401697	REVERT-BUFFER-WITH-FINE-GRAIN
blockinput.h	2323	2324	2	0.039307267	0.002411168	0.064317919	REVERT-BUFFER-WITH-FINE-GRAIN
buffer.c	210665	209044	61	0.143055337	0.968004578	0.230475029	REVERT-BUFFER
buffer.h	46356	47253	15	0.064973197	0.043159018	0.06992736	REVERT-BUFFER-WITH-FINE-GRAIN
bytecode.c	44508	34618	239	0.066613893	3.489142178	0.580011116	REVERT-BUFFER
callint.c	30845	31243	7	0.050251428	0.021774817	0.047426037	REVERT-BUFFER-WITH-FINE-GRAIN
callproc.c	52414	52325	43	0.071063717	0.075534267	0.151233955	REVERT-BUFFER
casefiddle.c	13530	21561	52	0.044178998	6.891051039	0.3841988560000007	REVERT-BUFFER
casetab.c	8641	8642	2	0.039043268	0.003929146	0.030014963	REVERT-BUFFER-WITH-FINE-GRAIN
category.c	16498	16463	3	0.041939418	0.00622836	0.084981038	REVERT-BUFFER-WITH-FINE-GRAIN
category.h	4605	4606	1	0.040482543	0.00345493	0.044889223	REVERT-BUFFER-WITH-FINE-GRAIN
ccl.c	64892	64909	9	0.070900427	0.030533628	0.055278961	REVERT-BUFFER-WITH-FINE-GRAIN
ccl.h	3378	3379	1	0.04588569	0.002691297	0.073536779	REVERT-BUFFER-WITH-FINE-GRAIN
character.c	30011	31460	12	0.052486605	0.029383777	0.066101361	REVERT-BUFFER-WITH-FINE-GRAIN
character.h	22260	22807	10	0.053830548	0.020876249	0.062192254	REVERT-BUFFER-WITH-FINE-GRAIN
charset.c	71099	71353	27	0.074962076	0.049489547	0.105611403	REVERT-BUFFER-WITH-FINE-GRAIN
charset.h	19497	19498	2	0.047235499	0.010008397	0.033422475	REVERT-BUFFER-WITH-FINE-GRAIN
chartab.c	40500	40477	3	0.049410545	0.015412012	0.078390896	REVERT-BUFFER-WITH-FINE-GRAIN
cm.c	12450	12497	8	0.043428069	0.007110303	0.071706401	REVERT-BUFFER-WITH-FINE-GRAIN
cm.h	6663	6664	2	0.041632887	0.005074109	0.027991964	REVERT-BUFFER-WITH-FINE-GRAIN
cmds.c	16526	16599	7	0.043464735	0.009443738	0.086922391	REVERT-BUFFER-WITH-FINE-GRAIN
coding.c	338973	339614	50	0.218918413	0.20157885	0.297149338	REVERT-BUFFER-WITH-FINE-GRAIN
coding.h	25135	25089	9	0.055920525	0.040492158	0.049116102	REVERT-BUFFER-WITH-FINE-GRAIN
commands.h	1777	1778	2	0.038333406	0.002256192	0.071216051	REVERT-BUFFER-WITH-FINE-GRAIN
composite.c	62207	62662	22	0.067281703	0.039474305	0.106152595	REVERT-BUFFER-WITH-FINE-GRAIN
composite.h	12841	12842	2	0.04446548	0.007651007	0.029858029	REVERT-BUFFER-WITH-FINE-GRAIN
conf_post.h	12219	13619	32	0.056242699	0.325693328	0.140425235	REVERT-BUFFER
cygw32.c	4097	4103	4	0.038842823	0.00265903	0.034148954	REVERT-BUFFER-WITH-FINE-GRAIN
cygw32.h	1114	1115	2	0.039210464	0.00220437	0.029955317	REVERT-BUFFER-WITH-FINE-GRAIN
data.c	105970	111859	173	0.094676814	2.734272166	0.507381162	REVERT-BUFFER
dbusbind.c	56717	56114	33	0.070243362	0.038362096	0.140484387	REVERT-BUFFER-WITH-FINE-GRAIN
decompress.c	5818	5816	6	0.041662218	0.004534383	0.041537439	REVERT-BUFFER-WITH-FINE-GRAIN
dired.c	33933	35264	46	0.05955782	0.12735283	0.171601777	REVERT-BUFFER
dispextern.h	125049	125599	27	0.10867112	0.132929509	0.103543911	RBBH-REVERT-BUFFER-BY-HUNKS
dispnew.c	192820	195002	40	0.135618902	0.124463047	0.195216281	REVERT-BUFFER-WITH-FINE-GRAIN
disptab.h	3792	3793	2	0.041407997	0.004072388	0.032621194	REVERT-BUFFER-WITH-FINE-GRAIN
doc.c	30787	30364	60	0.055455104	130.980132808	0.228207555	REVERT-BUFFER
doprnt.c	17440	17341	11	0.049479473	1.413627296	0.068775543	REVERT-BUFFER
dosfns.c	24023	24024	2	0.044187791	0.0100866	0.032939456	REVERT-BUFFER-WITH-FINE-GRAIN
dosfns.h	1354	1355	2	0.036047381	0.001917393	0.061623187	REVERT-BUFFER-WITH-FINE-GRAIN
dynlib.c	8204	8144	13	0.04292256	0.008997861	0.092730799	REVERT-BUFFER-WITH-FINE-GRAIN
dynlib.h	1236	1470	4	0.037027106	0.00447962	0.078199247	REVERT-BUFFER-WITH-FINE-GRAIN
editfns.c	163739	176696	168	0.133892647	249.14845578	0.639357485	REVERT-BUFFER
emacs-icon.h	11227	9741	5	0.043397265	0.947593158	0.048989477	REVERT-BUFFER
emacs-module.c	36141	41083	123	0.057575392	5.448007516	0.323307959	REVERT-BUFFER
emacs-module.h	5926	11403	39	0.040898578	0.334262565	0.142350932	REVERT-BUFFER
emacs.c	76609	82259	104	0.097632113	0.811961117	0.340363608	REVERT-BUFFER
emacsgtkfixed.c	7610	7593	7	0.041874879	0.005103421	0.053669061	REVERT-BUFFER-WITH-FINE-GRAIN
emacsgtkfixed.h	1232	1233	2	0.03706817	0.002075296	0.032083909	REVERT-BUFFER-WITH-FINE-GRAIN
eval.c	114120	124710	188	0.089566989	4.163804995	0.543824388	REVERT-BUFFER
fileio.c	193895	198534	178	0.151393717	3.270869109	0.571415459	REVERT-BUFFER
filelock.c	25123	24916	18	0.054632309	0.026390242	0.071153462	REVERT-BUFFER-WITH-FINE-GRAIN
firstfile.c	1174	1181	4	0.038884864	0.002030319	0.054904955	REVERT-BUFFER-WITH-FINE-GRAIN
floatfns.c	14301	14942	42	0.046528565	0.068516559	0.134085384	REVERT-BUFFER
fns.c	144297	152390	261	0.112902402	4.763480833	0.8085245519999985	REVERT-BUFFER
font.c	156759	158090	46	0.120129576	0.102900966	0.202384744	REVERT-BUFFER-WITH-FINE-GRAIN
font.h	32767	35111	41	0.055870162	0.079008903	0.12258099	REVERT-BUFFER
fontset.c	63806	66015	43	0.067408803	0.065290436	0.144917553	REVERT-BUFFER-WITH-FINE-GRAIN
fontset.h	1870	1871	2	0.036939103	0.002259604	0.028910569	REVERT-BUFFER-WITH-FINE-GRAIN
frame.c	169459	197035	197	0.136880697	17.696388657	0.627852532	REVERT-BUFFER
frame.h	51724	55829	35	0.080263033	0.199977879	0.126515027	REVERT-BUFFER
fringe.c	47107	47410	6	0.062076056	0.024579915	0.051500861	REVERT-BUFFER-WITH-FINE-GRAIN
ftcrfont.c	8522	8999	13	0.039701297	0.01527066	0.083322726	REVERT-BUFFER-WITH-FINE-GRAIN
ftfont.c	76531	74736	29	0.082245455	0.090350911	0.126542403	REVERT-BUFFER
ftfont.h	1477	1478	1	0.038361266	0.002254715	0.02978958	REVERT-BUFFER-WITH-FINE-GRAIN
ftxfont.c	9252	9817	19	0.04149208	0.020666429	0.075906864	REVERT-BUFFER-WITH-FINE-GRAIN
getpagesize.h	1542	1543	2	0.037269099	0.003826465	0.03385904	REVERT-BUFFER-WITH-FINE-GRAIN
gfilenotify.c	10356	11005	10	0.043120063	0.012297779	0.048409167	REVERT-BUFFER-WITH-FINE-GRAIN
gmalloc.c	59535	58736	86	0.070805079	0.298190959	0.260342754	REVERT-BUFFER
gnutls.c	57350	88381	133	0.073447007	19.254059013	0.400401295	REVERT-BUFFER
gnutls.h	2782	3146	7	0.040269379	0.005348837	0.042948345	REVERT-BUFFER-WITH-FINE-GRAIN
gtkutil.c	162240	167021	65	0.132784821	1.139196604	0.219520555	REVERT-BUFFER
gtkutil.h	7148	7669	7	0.043334682	0.012003472	0.041287122	REVERT-BUFFER-WITH-FINE-GRAIN
image.c	270253	272136	197	0.222032555	0.370422944	0.8085088219999983	REVERT-BUFFER
indent.c	68725	72439	39	0.068987895	0.189844833	0.14166647	REVERT-BUFFER
indent.h	2171	2172	2	0.036882879	0.002405779	0.034486274	REVERT-BUFFER-WITH-FINE-GRAIN
inotify.c	11744	16423	29	0.041117104	1.236744776	0.097514496	REVERT-BUFFER
insdel.c	65329	69314	21	0.068142124	0.320765927	0.171091341	REVERT-BUFFER
intervals.c	69906	69176	9	0.067788171	0.045596863	0.052912751	REVERT-BUFFER-WITH-FINE-GRAIN
intervals.h	11702	11604	11	0.043759032	0.009736534	0.07818114	REVERT-BUFFER-WITH-FINE-GRAIN
keyboard.c	368698	375297	99	0.252331138	0.473319963	0.467540015	REVERT-BUFFER
keyboard.h	18424	18469	6	0.046965622	0.010921091	0.038617819	REVERT-BUFFER-WITH-FINE-GRAIN
keymap.c	112662	113335	17	0.084216628	0.0564676	0.096714192	REVERT-BUFFER-WITH-FINE-GRAIN
keymap.h	2301	2302	2	0.035580001	0.002403334	0.038579687	REVERT-BUFFER-WITH-FINE-GRAIN
kqueue.c	15899	16543	10	0.044132049	0.013038431	0.059911105	REVERT-BUFFER-WITH-FINE-GRAIN
lastfile.c	1892	2053	5	0.036227284	0.002568087	0.065688231	REVERT-BUFFER-WITH-FINE-GRAIN
lisp.h	151532	154743	265	0.143883944	539.879098116	0.8634533129999992	REVERT-BUFFER
lread.c	141434	153962	184	0.118116822	4.274483568	0.593424343	REVERT-BUFFER
macfont.h	2712	2848	3	0.039706181	0.003210469	0.03218999	REVERT-BUFFER-WITH-FINE-GRAIN
macros.c	12297	12307	3	0.042433666	0.005070165	0.032922824	REVERT-BUFFER-WITH-FINE-GRAIN
macros.h	1664	1665	2	0.035834709	0.002103647	0.03417143	REVERT-BUFFER-WITH-FINE-GRAIN
macuvs.h	478710	478842	9	0.18810203	0.262799859	0.148847166	RBBH-REVERT-BUFFER-BY-HUNKS
marker.c	21655	22190	6	0.047513658	0.013568349	0.041712445	REVERT-BUFFER-WITH-FINE-GRAIN
menu.c	45442	45310	8	0.060652415	0.022808651	0.089105706	REVERT-BUFFER-WITH-FINE-GRAIN
menu.h	2291	2276	3	0.039220719	0.002727945	0.038526396	REVERT-BUFFER-WITH-FINE-GRAIN
minibuf.c	71348	73754	41	0.068853934	0.092206008	0.144308866	REVERT-BUFFER
msdos.c	117032	117570	9	0.112412518	1.851569699	0.231427752	REVERT-BUFFER
msdos.h	4227	4348	5	0.040463461	0.004204848	0.038048758	REVERT-BUFFER-WITH-FINE-GRAIN
nsgui.h	4938	4939	2	0.042022512	0.007001236	0.058944579	REVERT-BUFFER-WITH-FINE-GRAIN
nsterm.h	38626	44083	44	0.070987911	0.506200995	0.144655482	REVERT-BUFFER
print.c	70038	73841	45	0.075677775	4.026341206	0.156848703	REVERT-BUFFER
process.c	227582	247290	295	0.182520433	33.337351562	0.9778028859999983	REVERT-BUFFER
process.h	8234	9836	16	0.04248304	0.036471351	0.064195176	REVERT-BUFFER-WITH-FINE-GRAIN
profiler.c	18482	18457	11	0.043813782	0.010350546	0.055780528	REVERT-BUFFER-WITH-FINE-GRAIN
puresize.h	3442	3443	3	0.041209498	0.003895388	0.051523827	REVERT-BUFFER-WITH-FINE-GRAIN
ralloc.c	33444	33083	7	0.047300992	0.016545621	0.073236082	REVERT-BUFFER-WITH-FINE-GRAIN
regex.c	194305	193326	97	0.180956001	2.264050441	0.400853427	REVERT-BUFFER
regex.h	23762	23784	18	0.058010483	0.034349127	0.076792213	REVERT-BUFFER-WITH-FINE-GRAIN
region-cache.c	26621	26622	2	0.044657595	0.009893444	0.033125219	REVERT-BUFFER-WITH-FINE-GRAIN
region-cache.h	5278	5279	2	0.036583676	0.003085804	0.03729832	REVERT-BUFFER-WITH-FINE-GRAIN
scroll.c	32513	32479	6	0.048482135	0.011519456	0.085286059	REVERT-BUFFER-WITH-FINE-GRAIN
search.c	103513	103321	61	0.085247674	0.077743493	0.182840625	REVERT-BUFFER-WITH-FINE-GRAIN
sheap.c	2942	2140	14	0.03976631	0.026304623	0.063643714	REVERT-BUFFER-WITH-FINE-GRAIN
sound.c	40357	40413	8	0.052568714	0.018852641	0.047058373	REVERT-BUFFER-WITH-FINE-GRAIN
syntax.c	109738	113161	158	0.089811894	1.489718905	0.426571084	REVERT-BUFFER
syntax.h	7761	7762	2	0.038928851	0.00411685	0.030386009	REVERT-BUFFER-WITH-FINE-GRAIN
sysdep.c	102007	111582	99	0.125249134	2.063423282	0.327923863	REVERT-BUFFER
sysselect.h	2283	2556	3	0.041331227	0.004221959	0.032962908	REVERT-BUFFER-WITH-FINE-GRAIN
syssignal.h	2232	2367	4	0.040001951	0.003490596	0.075596891	REVERT-BUFFER-WITH-FINE-GRAIN
sysstdio.h	1022	2125	3	0.038915162	0.009336122	0.039278783	REVERT-BUFFER-WITH-FINE-GRAIN
systime.h	3186	3187	2	0.038973828	0.003105359	0.066136036	REVERT-BUFFER-WITH-FINE-GRAIN
systty.h	2774	2754	3	0.040932298	0.003340021	0.034051161	REVERT-BUFFER-WITH-FINE-GRAIN
syswait.h	1909	1910	3	0.039859197	0.003133225	0.073393498	REVERT-BUFFER-WITH-FINE-GRAIN
term.c	130082	131097	57	0.10612057	0.083380755	0.184314108	REVERT-BUFFER-WITH-FINE-GRAIN
termcap.c	15849	15950	2	0.04222735	0.007319496	0.029681039	REVERT-BUFFER-WITH-FINE-GRAIN
termchar.h	9306	9142	3	0.041454424	0.005502333	0.026602545	REVERT-BUFFER-WITH-FINE-GRAIN
termhooks.h	28047	28799	10	0.055398372	0.022180439	0.050718634	REVERT-BUFFER-WITH-FINE-GRAIN
terminal.c	18532	18842	5	0.044959233	0.011095597	0.122524728	REVERT-BUFFER-WITH-FINE-GRAIN
terminfo.c	1604	1605	2	0.038392055	0.001939383	0.067747881	REVERT-BUFFER-WITH-FINE-GRAIN
termopts.h	1064	1065	2	0.037703218	0.001817652	0.053488153	REVERT-BUFFER-WITH-FINE-GRAIN
textprop.c	72068	72885	10	0.064344458	0.038806236	0.066604872	REVERT-BUFFER-WITH-FINE-GRAIN
tparam.c	7296	7399	9	0.042007352	0.00485408	0.069073729	REVERT-BUFFER-WITH-FINE-GRAIN
tparam.h	1285	1340	3	0.039350756	0.002158401	0.055662214	REVERT-BUFFER-WITH-FINE-GRAIN
undo.c	15682	15683	2	0.041746287	0.0054818	0.055823056	REVERT-BUFFER-WITH-FINE-GRAIN
unexaix.c	15514	15515	2	0.043068718	0.007149366	0.052384256	REVERT-BUFFER-WITH-FINE-GRAIN
unexcoff.c	15156	15157	2	0.043126896	0.007356162	0.071640362	REVERT-BUFFER-WITH-FINE-GRAIN
unexcw.c	9107	8916	12	0.040893674	0.006148143	0.075921995	REVERT-BUFFER-WITH-FINE-GRAIN
unexec.h	116	116	0	0.037351221	0.001481792	0.030958977	REVERT-BUFFER-WITH-FINE-GRAIN
unexelf.c	23765	21299	11	0.055085973	0.148562502	0.062808698	REVERT-BUFFER
unexhp9k800.c	9817	9817	0	0.04090394	0.004780748	0.055412393	REVERT-BUFFER-WITH-FINE-GRAIN
unexmacosx.c	43220	42350	6	0.052798485	0.026658083	0.071571429	REVERT-BUFFER-WITH-FINE-GRAIN
unexsol.c	604	604	0	0.035208442	0.001662678	0.066238698	REVERT-BUFFER-WITH-FINE-GRAIN
unexw32.c	26998	27189	25	0.053305457	0.027633396	0.107577629	REVERT-BUFFER-WITH-FINE-GRAIN
vm-limit.c	5745	5907	4	0.04196384	0.005421668	0.03522741	REVERT-BUFFER-WITH-FINE-GRAIN
w16select.c	22279	22280	2	0.045085852	0.008935241	0.06498178	REVERT-BUFFER-WITH-FINE-GRAIN
w32.c	266005	273748	66	0.181078688	0.631921554	0.263125389	REVERT-BUFFER
w32.h	8949	8953	4	0.043348847	0.00587437	0.034955102	REVERT-BUFFER-WITH-FINE-GRAIN
w32common.h	1665	1666	2	0.039060357	0.002266443	0.03460604	REVERT-BUFFER-WITH-FINE-GRAIN
w32console.c	23538	24696	22	0.047447161	0.020676648	0.076545807	REVERT-BUFFER-WITH-FINE-GRAIN
w32fns.c	324499	362552	212	0.212798448	27.595457489	0.770541459	REVERT-BUFFER
w32font.c	88643	90842	29	0.084941621	0.06859754	0.098763561	REVERT-BUFFER-WITH-FINE-GRAIN
w32font.h	2977	2942	3	0.037340952	0.003320466	0.033899604	REVERT-BUFFER-WITH-FINE-GRAIN
w32gui.h	4020	4021	2	0.041229534	0.004631639	0.046801214	REVERT-BUFFER-WITH-FINE-GRAIN
w32heap.c	23905	26233	16	0.047937511	0.043124013	0.093855669	REVERT-BUFFER-WITH-FINE-GRAIN
w32heap.h	2267	2245	4	0.035817589	0.002581281	0.076106299	REVERT-BUFFER-WITH-FINE-GRAIN
w32inevt.c	23375	24193	21	0.046940675	0.031258921	0.092333287	REVERT-BUFFER-WITH-FINE-GRAIN
w32inevt.h	1176	1177	2	0.038647248	0.001856762	0.070286152	REVERT-BUFFER-WITH-FINE-GRAIN
w32menu.c	45595	45600	13	0.058873353	0.024461548	0.107591311	REVERT-BUFFER-WITH-FINE-GRAIN
w32notify.c	24003	25122	43	0.048051419	0.300758335	0.144071725	REVERT-BUFFER
w32proc.c	114140	115841	30	0.096755499	0.087098186	0.131805171	REVERT-BUFFER-WITH-FINE-GRAIN
w32reg.c	4458	4473	4	0.040345631	0.003157181	0.03868723	REVERT-BUFFER-WITH-FINE-GRAIN
w32select.c	32498	35683	8	0.050830723	0.115461966	0.08138574	REVERT-BUFFER
w32select.h	953	954	2	0.037606903	0.001802497	0.073433088	REVERT-BUFFER-WITH-FINE-GRAIN
w32term.c	208214	216804	128	0.145846281	0.415995904	0.452017838	REVERT-BUFFER
w32term.h	30113	30169	16	0.061621368	0.043722401	0.068545239	REVERT-BUFFER-WITH-FINE-GRAIN
w32uniscribe.c	37252	37858	11	0.057969405	0.027828457	0.065789409	REVERT-BUFFER-WITH-FINE-GRAIN
w32xfns.c	7429	8449	4	0.041098022	0.014167224	0.062755404	REVERT-BUFFER-WITH-FINE-GRAIN
widget.c	15235	15408	20	0.045095625	0.015303378	0.091998888	REVERT-BUFFER-WITH-FINE-GRAIN
widget.h	2839	2847	4	0.043457376	0.00456613	0.033656627	REVERT-BUFFER-WITH-FINE-GRAIN
widgetprv.h	2192	2193	4	0.037846944	0.002410173	0.039192732	REVERT-BUFFER-WITH-FINE-GRAIN
window.c	247029	263196	113	0.162939125	1.823741433	0.43306532	REVERT-BUFFER
window.h	40676	42531	57	0.066477449	0.689007909	0.222435668	REVERT-BUFFER
xdisp.c	1014261	1063760	413	0.5658512699999992	12.162937169	2.625628421999999	REVERT-BUFFER
xfaces.c	198840	200689	44	0.147763674	0.128634805	0.199569644	REVERT-BUFFER-WITH-FINE-GRAIN
xfns.c	219992	249068	142	0.171112274	18.407242761	0.485589351	REVERT-BUFFER
xfont.c	31984	31266	17	0.052815587	0.044323719	0.075378341	REVERT-BUFFER-WITH-FINE-GRAIN
xftfont.c	23858	24658	23	0.05207835	0.093080592	0.079839883	REVERT-BUFFER
xgselect.c	5244	5440	11	0.039750655	0.005741394	0.085163324	REVERT-BUFFER-WITH-FINE-GRAIN
xgselect.h	1006	987	3	0.036149538	0.002049381	0.034493591	REVERT-BUFFER-WITH-FINE-GRAIN
xmenu.c	67074	68801	15	0.082159859	0.048041154	0.076409883	REVERT-BUFFER-WITH-FINE-GRAIN
xml.c	8054	8039	6	0.041931077	0.005001231	0.061182661	REVERT-BUFFER-WITH-FINE-GRAIN
xrdb.c	17375	17498	5	0.044372074	0.010911289	0.063701872	REVERT-BUFFER-WITH-FINE-GRAIN
xselect.c	86814	87776	16	0.075834191	0.049218864	0.126307181	REVERT-BUFFER-WITH-FINE-GRAIN
xsettings.c	30659	30639	4	0.056285683	0.015475462	0.043668936	REVERT-BUFFER-WITH-FINE-GRAIN
xsettings.h	1134	1135	2	0.037998495	0.001986804	0.08228136	REVERT-BUFFER-WITH-FINE-GRAIN
xsmfns.c	17559	17605	5	0.044120298	0.00907457	0.086251086	REVERT-BUFFER-WITH-FINE-GRAIN
xterm.c	383015	402521	208	0.277790626	2.71448703	0.8819136090000014	REVERT-BUFFER
xterm.h	41373	43427	13	0.06702646	0.065484843	0.055296514	RBBH-REVERT-BUFFER-BY-HUNKS
xwidget.c	37193	38456	52	0.058702233	2.440097854	0.184362455	REVERT-BUFFER
xwidget.h	3739	3622	5	0.03663353	0.004050851	0.037721191	REVERT-BUFFER-WITH-FINE-GRAIN

[-- Attachment #3: rbbh-bug18.el --]
[-- Type: text/x-emacs-lisp, Size: 11389 bytes --]

;;; rbbh.el --- Revert Buffer By Hunks -*- lexical-binding: t -*-

(require 'diff)

;; At least for now, this are defconst.

(defconst rbbh-diff-command "diff"
  "Name of the command to run diff")

(defconst rbbh-diff-switches "--normal"
  "Switches to pass to diff.")

(defconst rbbh-diff-change-command-regexp
  (let ((rng "\\([0-9]+\\)\\(\\|,\\([0-9]+\\)\\)"))
    (concat "^" rng "\\([acd]\\)" rng "$"))
  "Regular expression that matches the change commands for each hunk
Should be in synch with the switch used to call diff.")

(defconst rbbh-diff-buffer-name "*RBBH-Diff*"
  "The name of the diff buffer internally created by `rbbh--run-diff'.")

(defvar rbbh-current-diff-buffer-name nil
  "Name of the current diff buffer.")

(defvar rbbh-total-hunks 0
  "Total hunks in the diff output.")

;; If `diff' and `diff-mode' are not to be required, this function should be
;; changed to do a lot of what `diff-no-select' does.
(defun rbbh--run-diff (buf)
  "Compare contents of buffer BUF with those of the file it visits.
Runs `rbbh-diff-command' command to make the comparison, and puts its output
in a buffer, with basename `rbbh-diff-buffer-name'.
The command is run with the switches `rbbh-diff-switches'."
  (let ((diff-command rbbh-diff-command)
	(diff-use-labels nil)) ; Don't care about labels.
    (setq rbbh-current-diff-buffer-name (generate-new-buffer
					 rbbh-diff-buffer-name))
    (with-current-buffer buf
      (diff-no-select buf buffer-file-name rbbh-diff-switches
		      t rbbh-current-diff-buffer-name))))

;; With this, reverted hunks can be undone one by one.
(defsubst rbbh--split-undo-hunk (buf)
  "Force undo history to separate hunk replacements in buffer BUF."
  (with-current-buffer buf
    (undo-boundary)))

(defun rbbh-delete-line (&optional arg)
  "Delete ARG lines (or the current line, if ARG is 0).
Does not put the killed text in the `kill-ring'.  See `kill-whole-line' for
details on ARG."
  (setq arg (or arg 1))
  (if (and (> arg 0)
	   (eobp)
	   (save-excursion (forward-visible-line 0)
			   (eobp)))
      (signal 'end-of-buffer nil))
  (if (and (< arg 0)
	   (bobp)
	   (save-excursion (end-of-visible-line) (bobp)))
      (signal 'beginning-of-buffer nil))
  (cond ((zerop arg)
         (delete-region (progn (forward-visible-line 0) (point))
                        (progn (end-of-visible-line) (point))))
        ((< arg 0)
         (delete-region (progn (end-of-visible-line) (point))
                        (progn (forward-visible-line (1+ arg))
                               (unless (bobp)
                                 (backward-char))
                               (point))))
        (t
         (delete-region (progn (forward-visible-line 0) (point))
			(progn (forward-visible-line arg) (point))))))

(defsubst rbbh-count-total-hunks (diff-buf &optional change-command-re)
  (with-current-buffer diff-buf
    (save-excursion
      (goto-char (point-min))
      (let ((count 0)
	    (re (or change-command-re rbbh-diff-change-command-regexp)))
	(while (re-search-forward re nil t)
	  (setq count (1+ count)))
	count))))

(defsubst rbbh-get-hunk-contents (beg end)
  "Get the hunk contents from positions BEG to END.
Expects that a diff buffer is the current buffer."
  (let ((start (point)))
    (forward-line (1+ (- beg end)))
    (let ((text (buffer-substring start (point))))
      ;; Remember that we are using the --normal switch, hence the > and <
      ;; replacement.
      (setq text (replace-regexp-in-string "^[><] " "" text))
      text)))

(defun rbbh-patch-buffer (buf diff-buf)
  "Patch the buffer BUF according to the contents of the diff buffer DIFF-BUF.
It works with a diff buffer that contains a --normal output from diff."
  ;; line-offset keeps memory of the lines added and deleted to the buffer BUF,
  ;; and it is necessary because the diff output will stay the same (line
  ;; references will stay relative to the unpatched buffer).
  ;; Added lines decrements offset, and deleted lines increment it.
  (let ((line-offset 0)
	(column (current-column))) ; To restore point just right.
    (save-excursion
      (with-current-buffer diff-buf
	(goto-char (point-min))
	(save-excursion
	  (while (re-search-forward rbbh-diff-change-command-regexp nil t)
	    (rbbh--split-undo-hunk buf)  ; Make each change of hunk undoable.
	    (forward-line) ; skip the command.
	    ;; Get ranges and the action, from the previous match.
	    (let* ((action-cmd (match-string 4))
		   (old-from (string-to-number (match-string 1)))
		   (old-to (if (match-beginning 3)
			       (string-to-number (match-string 3))
			     old-from))
		   (new-from (string-to-number (match-string 5)))
		   (new-to (if (match-beginning 7)
			       (string-to-number (match-string 7))
			     new-from)))
	      (cond ((equal action-cmd "a")
		     ;; When adding, we take the text and remove > and <
		     ;; (diff was called with --normal switch).
		     ;; Then navigate to the line, accounting the offset,
		     ;; and insert the text.
		     (let ((text (rbbh-get-hunk-contents new-to new-from)))
		       (with-current-buffer buf
			 (goto-char (point-min))
			 (forward-line (- old-from line-offset))
			 (setq line-offset (- line-offset (1+ (- new-to
								 new-from))))
			 (insert text))))
		    ((equal action-cmd "d")
		     ;; When deleting, navigate to the correct line and kill
		     ;; as many lines as the range in the diff output says.
		     (with-current-buffer buf
		       (goto-char (point-min))
		       (forward-line (1- (- old-from line-offset)))
		       (setq line-offset (+ line-offset (1+
							 (- old-to old-from))))
		       (rbbh-delete-line (1+ (- old-to old-from)))))
		    ((equal action-cmd "c")
		     ;; When changing, is a combination of adding and deleting.
		     ;; Get the text after "---", and act similar as we would
		     ;; with adding.
		     ;; But before, kill the lines, as we do when deleting.
		     (re-search-forward "^---")
		     (forward-line)
		     (let ((text (rbbh-get-hunk-contents new-to new-from)))
		       (with-current-buffer buf
			 (goto-char (point-min))
			 (forward-line (1- (- old-from line-offset)))
			 (rbbh-delete-line (1+ (- old-to old-from)))
			 (setq line-offset (+ line-offset (- old-to old-from)
					      new-from (- new-to)))
			 (insert text))))
		    (t
		     (error "Unknown command action in diff output"))))))))
    (move-to-column column))) ; Restore column.

;; Not sure if the function would be a good candidate for
;; `revert-buffer-function'.
;; But just in case, make it take _ignore-auto as an argument.
;; Note that reverting with the contents of an auto save file is not supported.
;; It could be added, if suggested.
(defun rbbh-revert-buffer-by-hunks (&optional _ignore-auto noconfirm)
  "Revert buffer by hunks, instead of doing a single deletion plus insertion.
This action is useful when you want to revert a buffer (like you would do with
`revert-buffer'), but then would like to undo some of the reverting.
When the buffer hasn't been modified, nothing is done.
This function is only useful for buffers visting files.
After reverting, it marks the buffer as not modified.

When NOCONFIRM is non-nil, don't ask for confirmation before reverting.  The
other way of avoiding the query is provided by the variable 
`revert-without-query'.  Nevertheless, you will be always prompted, if the
file was changed externally.

The optional argument _IGNORE-AUTO is ignored and is provided only for
compatibility with `revert-buffer'.  Thus, it is a candidate for the variable
`revert-buffer-function'."
  (interactive)
  (with-current-buffer (or (buffer-base-buffer (current-buffer))
			   (current-buffer))
    (save-excursion
      (let ((file-name buffer-file-name)
	    (buf (current-buffer))
	    ;; Just in case we are not the revert-buffer-function.
	    (revert-buffer-in-progress-p t))
	;; Repeat some of what revert-buffer--default does, because it is not
	;; sure reverting by hunks is a candidate for revert-buffer-function.
	(cond ((null file-name)
	       (error "Buffer does not seem to be associated with any file"))
	      ((or (and (not (verify-visited-file-modtime buf))
			(yes-or-no-p
			 (format "File %s was modified outside of Emacs.  Really revert? "
				 file-name)))
		   noconfirm
		   ;; Respect user choice.
		   (catch 'found
		     (dolist (regexp revert-without-query)
		       (when (string-match regexp file-name)
			 (throw 'found t))))
		   (yes-or-no-p (format "Revert buffer from file %s? "
					file-name)))
	       (run-hooks 'before-revert-hook)
	       (rbbh--run-diff buf)
	       (rbbh-patch-buffer buf rbbh-current-diff-buffer-name)
	       ;; Mark the buffer as not modified, like it would happen with
	       ;; the default behavior of revert-buffer.
	       (set-buffer-modified-p nil)
	       ;; Report to the user (this could be made optional).
	       ;; (setq rbbh-total-hunks (rbbh-count-total-hunks
	       ;; 			       rbbh-current-diff-buffer-name))
	       ;; (message "%d %s reverted" rbbh-total-hunks
	       ;; 		(if (= rbbh-total-hunks 1)
	       ;; 		    "hunk"
	       ;; 		  "hunks"))
	       ;; Kill the diff buffer we used.
	       (kill-buffer rbbh-current-diff-buffer-name)
	       (run-hooks 'after-revert-hook))
	      (t
	       (message "Revert aborted")))))))

;; The next function uses replace-buffer-contents:
(defun revert-buffer-with-fine-grain (&optional _ignore-auto noconfirm)
  "Replace current buffer text with the text of the visited file on disk.
Acts just like `revert-buffer', but tries to be as non-destructive as possible,
by preserving markers, properties and overlays.

In Lisp code, the first argument is IGNORE-AUTO: when nil, offers to revert
from the auto-save file.  It defaults to nil.

When NOCONFIRM is non-nil, don't ask for confirmation before reverting.  The
other way of avoiding the query is provided by the variable 
`revert-without-query'.  Nevertheless, the prompt can't be skipped if the file
was changed externally."
  (interactive)
  ;; Repeat some of what revert-buffer--default does, because it is not sure
  ;; this revert function is a good candidate for revert-buffer-function.
  (let ((buf (or (buffer-base-buffer (current-buffer))
		 (current-buffer)))
	(file-name buffer-file-name)
	(revert-buffer-in-progress-p t))
    (cond ((null file-name)
	   (error "Buffer does not seem to be associated with any file"))
	  ((or (and (not (verify-visited-file-modtime buf))
		    (yes-or-no-p
		     (format "File %s was modified outside of Emacs.  Really revert? "
			     file-name)))
	       noconfirm
	       ;; Respect user choice.
	       (catch 'found
		 (dolist (regexp revert-without-query)
		   (when (string-match regexp file-name)
		     (throw 'found t))))
	       (yes-or-no-p (format "Revert buffer from file %s? " file-name)))
	   (run-hooks 'before-revert-hook)
	   (save-excursion
	     ;; This action reverts the whole buffer.
	     (save-restriction
	       (widen)
	       (with-temp-buffer
		 (insert-file-contents file-name)
		 (let ((temp-buf (current-buffer)))
		   (set-buffer buf)
		   (replace-buffer-contents temp-buf)))))
	   ;; Mark the buffer as not modified, like it would happen with the
	   ;; default behavior of revert-buffer.
	   (set-buffer-modified-p nil)
	   (run-hooks 'after-revert-hook))
	  (t
	   (message "Revert aborted")))))


(provide 'rbbh)

;;; rbbh.el ends here

^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-29 12:49       ` martin rudalics
@ 2019-05-02 15:54         ` Basil L. Contovounesios
  2019-05-02 16:20           ` Glenn Morris
  2019-05-02 21:27           ` Richard Stallman
  0 siblings, 2 replies; 24+ messages in thread
From: Basil L. Contovounesios @ 2019-05-02 15:54 UTC (permalink / raw)
  To: martin rudalics; +Cc: 18, Mauro Aranda

martin rudalics <rudalics@gmx.at> writes:

>> When I bumped into the problem of the marker being sent to the
>> beginning of the hunk, I started looking for something to get the
>> markers of the buffer, but didn't found anything at the Lisp level.
>
> We could introduce a function 'marker-list' based on BUF_MARKERS.

I've opened a new ticket for this: https://debbugs.gnu.org/35536

[The acknowledgement email lists you as being CCed, but the copy of my
report does not.  So, were you successfully CCed?  If not, any ideas why?]

Thanks,

-- 
Basil





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-05-02 15:54         ` Basil L. Contovounesios
@ 2019-05-02 16:20           ` Glenn Morris
  2019-05-02 16:23             ` Basil L. Contovounesios
  2019-05-02 21:27           ` Richard Stallman
  1 sibling, 1 reply; 24+ messages in thread
From: Glenn Morris @ 2019-05-02 16:20 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: 18, Mauro Aranda

"Basil L. Contovounesios" wrote:

> I've opened a new ticket for this: https://debbugs.gnu.org/35536
>
> [The acknowledgement email lists you as being CCed, but the copy of my
> report does not.  So, were you successfully CCed?  If not, any ideas why?]

When you see this, it means the person is subscribed to bug-gnu-emacs
and has the Mailman option "no duplicates" enabled. Everything is
working fine.





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-05-02 16:20           ` Glenn Morris
@ 2019-05-02 16:23             ` Basil L. Contovounesios
  0 siblings, 0 replies; 24+ messages in thread
From: Basil L. Contovounesios @ 2019-05-02 16:23 UTC (permalink / raw)
  To: Glenn Morris; +Cc: 18, Mauro Aranda

Glenn Morris <rgm@gnu.org> writes:

> "Basil L. Contovounesios" wrote:
>
>> I've opened a new ticket for this: https://debbugs.gnu.org/35536
>>
>> [The acknowledgement email lists you as being CCed, but the copy of my
>> report does not.  So, were you successfully CCed?  If not, any ideas why?]
>
> When you see this, it means the person is subscribed to bug-gnu-emacs
> and has the Mailman option "no duplicates" enabled. Everything is
> working fine.

Good to hear, and sorry for the noise.

Thanks,

-- 
Basil





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-05-02 15:54         ` Basil L. Contovounesios
  2019-05-02 16:20           ` Glenn Morris
@ 2019-05-02 21:27           ` Richard Stallman
  2019-05-03 14:05             ` Basil L. Contovounesios
  1 sibling, 1 reply; 24+ messages in thread
From: Richard Stallman @ 2019-05-02 21:27 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: 18, maurooaranda

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > >> When I bumped into the problem of the marker being sent to the
  > >> beginning of the hunk, I started looking for something to get the
  > >> markers of the buffer, but didn't found anything at the Lisp level.
  > >
  > > We could introduce a function 'marker-list' based on BUF_MARKERS.

There is a reason why you can't get a copy of that list: if anything
else pointed to a copy of it, no marker in that buffer could be
garbage collected.  We should look for some other way to solve your
problem.

-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-05-02 21:27           ` Richard Stallman
@ 2019-05-03 14:05             ` Basil L. Contovounesios
  2019-05-05 22:41               ` Richard Stallman
  0 siblings, 1 reply; 24+ messages in thread
From: Basil L. Contovounesios @ 2019-05-03 14:05 UTC (permalink / raw)
  To: Richard Stallman; +Cc: 18, maurooaranda

Richard Stallman <rms@gnu.org> writes:

>   > >> When I bumped into the problem of the marker being sent to the
>   > >> beginning of the hunk, I started looking for something to get the
>   > >> markers of the buffer, but didn't found anything at the Lisp level.
>   > >
>   > > We could introduce a function 'marker-list' based on BUF_MARKERS.
>
> There is a reason why you can't get a copy of that list: if anything
> else pointed to a copy of it, no marker in that buffer could be
> garbage collected.

Isn't that true of all marker copying/manipulation at the Lisp level?
I think the manual already documents these pitfalls.

> We should look for some other way to solve your problem.

I think that would indeed be preferable.

-- 
Basil





^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-05-03 14:05             ` Basil L. Contovounesios
@ 2019-05-05 22:41               ` Richard Stallman
  0 siblings, 0 replies; 24+ messages in thread
From: Richard Stallman @ 2019-05-05 22:41 UTC (permalink / raw)
  To: Basil L. Contovounesios; +Cc: 18, maurooaranda

[[[ To any NSA and FBI agents reading my email: please consider    ]]]
[[[ whether defending the US Constitution against all enemies,     ]]]
[[[ foreign or domestic, requires you to follow Snowden's example. ]]]

  > > There is a reason why you can't get a copy of that list: if anything
  > > else pointed to a copy of it, no marker in that buffer could be
  > > garbage collected.

  > Isn't that true of all marker copying/manipulation at the Lisp level?

There is always the possibility if blocking some markers from GC
by saving pointers to them and not clearing those out.
However, getting a list of ALL the markers would make it trivially
easy to block ALL the buffer's markers from GC.
-- 
Dr Richard Stallman
President, Free Software Foundation (https://gnu.org, https://fsf.org)
Internet Hall-of-Famer (https://internethalloffame.org)







^ permalink raw reply	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-04-30  0:17       ` Mauro Aranda
@ 2019-05-15 23:10         ` Mauro Aranda
  2020-09-19 23:08           ` Lars Ingebrigtsen
  0 siblings, 1 reply; 24+ messages in thread
From: Mauro Aranda @ 2019-05-15 23:10 UTC (permalink / raw)
  To: 18


[-- Attachment #1.1: Type: text/plain, Size: 1953 bytes --]

I spent some time thinking on how to get this new revert command
integrated with the rest of revert-buffer functions, and I came up with
the attached patch.

Since the difference between revert-buffer and
revert-buffer-with-fine-grain lies at the insert-file-contents level, I
wrote an alternative to
revert-buffer-insert-file-contents--default-function, that uses
replace-buffer-contents, as Eli suggested.  I named it
revert-buffer-insert-file-contents-delicately.

Then, revert-buffer-with-fine-grain only needs to bind
revert-buffer-insert-file-contents-function to
revert-buffer-insert-file-contents-delicately to get the job done.

There are some more things that revert-buffer-with-fine-grain needs to
do:
1) Manipulate the current-prefix-arg, just like revert-buffer does.
2) Since replace-buffer-contents can fail to replace conservatively,
return that information could be useful.  But revert-buffer--default
always returns t after reverting, so I used a closure that then gets
called by revert-buffer-with-fine-grain.

To control how much time replace-buffer-contents spends trying to be
non-destructive, I introduced a new variable to pass as the MAX-SECS
argument.  2.0 secs looks like a good value, according to the previous
benchmark I posted, and the new one I post here.  I think it should be
an acceptable delay.

As I said above, I timed the command, and to compare I timed
revert-buffer too.  IMO, the results look good.  Some files fail and
take a lot of time, yes, but I think it's unlikely that a user will revert
so many changes.  And for those, at least the variable
revert-buffer-with-fine-grain-max-seconds helps to terminate the
execution earlier.

I also went ahead and wrote a test for revert-buffer-with-fine-grain,
because I figure it would be required, as well as the benchmarking.
As I was there, I wrote a similar test for revert-buffer.

Corrections and comments are welcome.  Better names too.

Best regards,
Mauro.

[-- Attachment #1.2: Type: text/html, Size: 2238 bytes --]

[-- Attachment #2: bug18-benchmark.txt --]
[-- Type: text/plain, Size: 9521 bytes --]

FILE	OLD SIZE	NEW SIZE	HUNKS	REVERT-BUFFER	REVERT-BUFFER-WITH-FINE-GRAIN
alloc.c	204520	209630	287	0.16885512700000097	2.52165405
atimer.c	14123	14136	4	0.045665537	0.010047017
atimer.h	2171	2172	2	0.037106671	0.00390519
bidi.c	124786	125185	13	0.092865676	0.062252294
blockinput.h	2323	2324	2	0.037787195	0.003917413
buffer.c	210665	209044	61	0.14611377900000155	0.937045737
buffer.h	46356	47253	15	0.068253374	0.045556969
bytecode.c	44508	34618	239	0.064439602	2.2386166
callint.c	30845	31243	7	0.049622551	0.022790706
callproc.c	52414	52325	43	0.070316457	0.080524749
casefiddle.c	13530	21561	52	0.04057578	4.619247387
casetab.c	8641	8642	2	0.038574295	0.005267704
category.c	16498	16463	3	0.037217646	0.007868557
category.h	4605	4606	1	0.040751777	0.005078507
ccl.c	64892	64909	9	0.074820042	0.034303878
ccl.h	3378	3379	1	0.040103519	0.004498693
character.c	30011	31460	12	0.046008242	0.03198511
character.h	22260	22807	10	0.051320439	0.023682425
charset.c	71099	71353	27	0.072188876	0.051697323
charset.h	19497	19498	2	0.045175674	0.01241516
chartab.c	40500	40477	3	0.046526946	0.016520792
cm.c	12450	12497	8	0.039806277	0.008985652
cm.h	6663	6664	2	0.040049252	0.007376253
cmds.c	16526	16599	7	0.042697529	0.010883493
coding.c	338973	339614	50	0.2216622490000007	0.201216524
coding.h	25135	25089	9	0.051864564	0.043502682
commands.h	1777	1778	2	0.037541285	0.003727237
composite.c	62207	62662	22	0.066043622	0.040960006
composite.h	12841	12842	2	0.043224544	0.01015017
conf_post.h	12219	13619	32	0.057944305	0.316720286
cygw32.c	4097	4103	4	0.034885675	0.00417603
cygw32.h	1114	1115	2	0.037897192	0.003836258
data.c	105970	111859	173	0.091105203	2.36943677
dbusbind.c	56717	56114	33	0.070967645	0.040514633
decompress.c	5818	5816	6	0.037711904	0.006254757
dired.c	33933	35264	46	0.054381819	0.129114725
dispextern.h	125049	125599	27	0.1125148320000024	0.137689716
dispnew.c	192820	195002	40	0.14034202000000218	0.126384317
disptab.h	3792	3793	2	0.038948776	0.005761964
doc.c	30787	30364	60	0.054206798	2.040920659
doprnt.c	17440	17341	11	0.045842997	1.418094702
dosfns.c	24023	24024	2	0.043931466	0.012107652
dosfns.h	1354	1355	2	0.036587962	0.00332782
dynlib.c	8204	8144	13	0.039442547	0.010899135
dynlib.h	1236	1470	4	0.034412925	0.006534886
editfns.c	163739	176696	168	0.133299667	21.842241128
emacs-icon.h	11227	9741	5	0.044211595	0.899394067
emacs-module.c	36141	41083	123	0.053157166	3.441990992
emacs-module.h	5926	11403	39	0.039310549	0.335723981
emacs.c	76609	82259	104	0.10241060499999777	0.782522409
emacsgtkfixed.c	7610	7593	7	0.038240874	0.006682527
emacsgtkfixed.h	1232	1233	2	0.036124012	0.00364657
eval.c	114120	124710	188	0.087589155	2.898722315
fileio.c	193895	198534	178	0.15175350999999848	2.107626342
filelock.c	25123	24916	18	0.0530457	0.0300633
firstfile.c	1174	1181	4	0.036274588	0.003423639
floatfns.c	14301	14942	42	0.043030942	0.070060678
fns.c	144297	152390	261	0.11314744	2.628062007
font.c	156759	158090	46	0.121857369	0.106117666
font.h	32767	35111	41	0.059272594	0.081385134
fontset.c	63806	66015	43	0.066742228	0.068749007
fontset.h	1870	1871	2	0.036201255	0.003774656
frame.c	169459	197035	197	0.14188052399999723	11.390826892
frame.h	51724	55829	35	0.084095598	0.1988903
fringe.c	47107	47410	6	0.058255718	0.025621315
ftcrfont.c	8522	8999	13	0.037593103	0.018471908
ftfont.c	76531	74736	29	0.084099509	0.099711345
ftfont.h	1477	1478	1	0.038385581	0.003884165
ftxfont.c	9252	9817	19	0.038092251	0.024402044
getpagesize.h	1542	1543	2	0.038198339	0.005960446
gfilenotify.c	10356	11005	10	0.039196636	0.014714363
gmalloc.c	59535	58736	86	0.074037819	0.298251602
gnutls.c	57350	88628	134	0.074161995	13.440509296
gnutls.h	2782	3146	7	0.039073927	0.007352292
gtkutil.c	162240	167021	65	0.137785641	1.102747434
gtkutil.h	7148	7669	7	0.042605124	0.014563785
image.c	270253	272136	197	0.24048663299999973	0.3771013260000001
indent.c	68725	72543	40	0.069655476	0.197957968
indent.h	2171	2172	2	0.037791099	0.003747767
inotify.c	11744	16423	29	0.040909679	1.174832033
insdel.c	65329	69314	21	0.066685515	0.325519413
intervals.c	69906	69176	9	0.067576748	0.050484365
intervals.h	11702	11604	11	0.045407397	0.011909646
keyboard.c	368698	375297	99	0.25862514299999695	0.465379164
keyboard.h	18424	18469	6	0.050166178	0.013732686
keymap.c	112662	113335	17	0.083695687	0.056851559
keymap.h	2301	2302	2	0.037595056	0.00372039
kqueue.c	15899	16543	10	0.044582652	0.015272174
lastfile.c	1892	2053	5	0.036237919	0.004087539
lisp.h	151532	154750	266	0.1509155469999975	35.897183584
lread.c	141434	153962	184	0.119046282	2.720143923
macfont.h	2712	2848	3	0.035859034	0.004644863
macros.c	12297	12307	3	0.041035809	0.006785675
macros.h	1664	1665	2	0.034252566	0.003497947
macuvs.h	478710	478842	9	0.208870107	0.281665641
marker.c	21655	22190	6	0.043885016	0.015349901
menu.c	45442	45310	8	0.060727013	0.025445792
menu.h	2291	2276	3	0.037475278	0.004453221
minibuf.c	71348	73754	41	0.070550615	0.094917805
msdos.c	117032	117570	9	0.11398439100000007	1.850454493
msdos.h	4227	4348	5	0.039840491	0.006227861
nsgui.h	4938	4939	2	0.041423981	0.010088069
nsterm.h	38626	44083	44	0.071184695	0.497490175
print.c	70038	73841	45	0.074963755	3.092901676
process.c	227582	247290	295	0.1890464100000002	22.090230694
process.h	8234	9836	16	0.041708021	0.039218551
profiler.c	18482	18457	11	0.045066153	0.012278255
puresize.h	3442	3443	3	0.04147238	0.005891998
ralloc.c	33444	33083	7	0.048564107	0.01934699
regex.c	194305	193326	97	0.18420549300000255	2.1140529800000034
regex.h	23762	23784	18	0.055106329	0.037439999
region-cache.c	26621	26622	2	0.040934119	0.011647109
region-cache.h	5278	5279	2	0.037751984	0.004508464
scroll.c	32513	32479	6	0.044252164	0.012821891
search.c	103513	103321	61	0.086465199	0.081540518
sheap.c	2942	2140	14	0.036889106	0.028218231
sound.c	40357	40413	8	0.05392959	0.021327448
syntax.c	109738	113161	158	0.087267454	1.434325523
syntax.h	7761	7762	2	0.037905493	0.005649024
sysdep.c	102007	111582	99	0.13289533099999673	1.989721573
sysselect.h	2283	2556	3	0.037274834	0.006309014
syssignal.h	2232	2367	4	0.038784503	0.00532734
sysstdio.h	1022	2125	3	0.03718488	0.013065842
systime.h	3186	3187	2	0.038469174	0.00488148
systty.h	2774	2754	3	0.039123787	0.005151832
syswait.h	1909	1910	3	0.039052899	0.004846281
term.c	130082	131097	57	0.109988258	0.086482128
termcap.c	15849	15950	2	0.04168113	0.009182658
termchar.h	9306	9142	3	0.03803749	0.007388463
termhooks.h	28047	28799	10	0.052728893	0.024784816
terminal.c	18532	18842	5	0.042489742	0.012637093
terminfo.c	1604	1605	2	0.037029904	0.003299949
termopts.h	1064	1065	2	0.037506564	0.00331266
textprop.c	72068	72885	10	0.062994933	0.039788584
tparam.c	7296	7399	9	0.039632713	0.006514832
tparam.h	1285	1340	3	0.036759551	0.003724787
undo.c	15682	15683	2	0.037444476	0.006994425
unexaix.c	15514	15515	2	0.041274868	0.009001772
unexcoff.c	15156	15157	2	0.042041924	0.009591851
unexcw.c	9107	8916	12	0.041075404	0.0078881
unexec.h	116	116	0	0.033408751	0.003039864
unexelf.c	23765	21299	11	0.053904654	0.148939647
unexhp9k800.c	9817	9817	0	0.036054582	0.006484522
unexmacosx.c	43220	42350	6	0.053606436	0.02987847
unexsol.c	604	604	0	0.035678632	0.00308533
unexw32.c	26998	27189	25	0.048881388	0.030160066
vm-limit.c	5745	5907	4	0.038113266	0.007256465
w16select.c	22279	22280	2	0.043059776	0.010776411
w32.c	266005	273748	66	0.18260096800000158	0.627642931
w32.h	8949	8953	4	0.042010636	0.007591838
w32common.h	1665	1666	2	0.036456443	0.003793719
w32console.c	23538	24696	22	0.048895075	0.023420836
w32fns.c	324499	362552	212	0.21937420400000068	18.248501324
w32font.c	88643	90842	29	0.081519657	0.072026383
w32font.h	2977	2942	3	0.039110585	0.004692282
w32gui.h	4020	4021	2	0.037496295	0.007041357
w32heap.c	23905	26233	16	0.049931017	0.050266279
w32heap.h	2267	2245	4	0.036854881	0.003951627
w32inevt.c	23375	24193	21	0.047331629	0.034662657
w32inevt.h	1176	1177	2	0.034336649	0.003406036
w32menu.c	45595	45600	13	0.060038168	0.027367082
w32notify.c	24003	25122	43	0.045228946	0.296313355
w32proc.c	114140	115841	30	0.098294186	0.089718993
w32reg.c	4458	4473	4	0.037260164	0.004628727
w32select.c	32498	35683	8	0.051822012	0.116391864
w32select.h	953	954	2	0.036962924	0.003246171
w32term.c	208214	216804	128	0.1463850479999982	0.415736768
w32term.h	30113	30169	16	0.060337364	0.048109823
w32uniscribe.c	37252	37858	11	0.054613041	0.030259303
w32xfns.c	7429	8449	4	0.037661536	0.016883024
widget.c	15235	15408	20	0.040981535	0.018154604
widget.h	2839	2847	4	0.039648354	0.00620097
widgetprv.h	2192	2193	4	0.034828463	0.003805451
window.c	247029	263196	113	0.1596132229999978	1.762098508
window.h	40676	42531	57	0.066522213	0.672974315
xdisp.c	1014261	1063910	413	0.5709538769999968	8.085211918999999
xfaces.c	198840	200689	44	0.15355596700000157	0.133174164
xfns.c	219992	249068	142	0.17801425699999682	11.777595139
xfont.c	31984	31266	17	0.04941573	0.045066529
xftfont.c	23858	24658	23	0.053319945	0.094962713
xgselect.c	5244	5440	11	0.038232549	0.007538058
xgselect.h	1006	987	3	0.034031095	0.003615276
xmenu.c	67074	68801	15	0.083512823	0.05330662
xml.c	8054	8039	6	0.038789874	0.007088776
xrdb.c	17375	17498	5	0.043487055	0.012977349
xselect.c	86814	87776	16	0.075765995	0.051242075
xsettings.c	30659	30639	4	0.056324614	0.018391707
xsettings.h	1134	1135	2	0.035387742	0.0035175
xsmfns.c	17559	17605	5	0.045125299	0.010618009
xterm.c	383015	402521	208	0.29099005199999517	2.1414645249999964
xterm.h	41373	43427	13	0.070231358	0.070234126
xwidget.c	37193	38456	52	0.05613786	2.158033152
xwidget.h	3739	3622	5	0.038403168	0.006243501

[-- Attachment #3: 0001-Add-a-new-functionality-for-reverting-visiting-file-.patch --]
[-- Type: text/x-patch, Size: 9941 bytes --]

From 50b1ce0185cd7b5f8be124eb4a612fd56e4e0657 Mon Sep 17 00:00:00 2001
From: Mauro Aranda <maurooaranda@gmail.com>
Date: Tue, 14 May 2019 22:23:17 -0300
Subject: [PATCH] Add a new functionality for reverting visiting-file buffers

* lisp/files.el (revert-buffer-with-fine-grain): New command.  Revert
a buffer trying to be non-destructive, by using replace-buffer-contents.
(revert-buffer-insert-file-contents-delicately): New function, alternative
to revert-buffer-insert-file-contents-function--default-function.
(revert-buffer-with-fine-grain-max-seconds): New variable.  Passed as
argument MAX-SECS of replace-buffer-contents.

* doc/emacs/files.texi (Reverting): Document the new command and the
new variable.

* etc/NEWS: Mention the new command and the new variable.

* test/lisp/files-tests.el (files-tests-lao files-tests-tzu): Helper
  variables, taken from diffutils manual, to test reverting a buffer.
  (files-tests-revert-buffer)
  (files-tests-revert-buffer-with-fine-grain): New tests.
---
 doc/emacs/files.texi     | 14 ++++++++++
 etc/NEWS                 | 10 +++++++
 lisp/files.el            | 71 ++++++++++++++++++++++++++++++++++++++++++++++++
 test/lisp/files-tests.el | 54 ++++++++++++++++++++++++++++++++++++
 4 files changed, 149 insertions(+)

diff --git a/doc/emacs/files.texi b/doc/emacs/files.texi
index 36ef1dc..3985124 100644
--- a/doc/emacs/files.texi
+++ b/doc/emacs/files.texi
@@ -916,6 +916,7 @@ Time Stamps
 @node Reverting
 @section Reverting a Buffer
 @findex revert-buffer
+@findex revert-buffer-with-fine-grain
 @cindex drastic changes
 @cindex reread a file
 
@@ -936,6 +937,19 @@ Reverting
 aliases to bring the reverted changes back, if you happen to change
 your mind.
 
+@vindex revert-buffer-with-fine-grain-max-seconds
+  To revert a buffer more conservatively, you can use the command
+@code{revert-buffer-with-fine-grain}.  This command acts like
+@code{revert-buffer}, but it tries to be as non-destructive as
+possible, making an effort to preserve all markers, properties and
+overlays in the buffer.  Since reverting this way can be very slow
+when you have made a large number of changes, you can modify the
+variable @code{revert-buffer-with-fine-grain-max-seconds} to
+specify a maximum amount of seconds that replacing the buffer
+contents this way should take.  Note that it is not ensured that the
+whole execution of @code{revert-buffer-with-fine-grain} won't take
+longer than this.
+
   Some kinds of buffers that are not associated with files, such as
 Dired buffers, can also be reverted.  For them, reverting means
 recalculating their contents.  Buffers created explicitly with
diff --git a/etc/NEWS b/etc/NEWS
index 699a04b..90b45b0 100644
--- a/etc/NEWS
+++ b/etc/NEWS
@@ -439,6 +439,16 @@ If the region is active, the command joins all the lines in the
 region.  When there's no active region, the command works on the
 current and the previous or the next line, as before.
 
++++
+** New command 'revert-buffer-with-fine-grain'.
+Revert a buffer trying to be as non-destructive as possible,
+preserving markers, properties and overlays.
+
++++
+** The new variable 'revert-buffer-with-fine-grain-max-seconds' specifies
+the maximum seconds that 'revert-buffer-with-fine-grain' should spend
+trying to be non-destructive.
+
 \f
 * Changes in Specialized Modes and Packages in Emacs 27.1
 
diff --git a/lisp/files.el b/lisp/files.el
index 8fa7f16..b672459 100644
--- a/lisp/files.el
+++ b/lisp/files.el
@@ -6076,6 +6076,77 @@ revert-buffer-insert-file-contents--default-function
         (insert-file-contents file-name (not auto-save-p)
                               nil nil t))))))
 
+(defvar revert-buffer-with-fine-grain-max-seconds 2.0
+  "Maximum time that `revert-buffer-with-fine-grain' should spend trying to
+preserve markers, properties and overlays.  If the operation takes more than
+this time, a single delete+insert is performed.
+Actually, this value is passed as the MAX-SECS argument to the function
+`replace-buffer-contents', so it is not ensured that the whole execution won't
+take longer.  See `replace-buffer-contents' for more details.")
+
+(defun revert-buffer-insert-file-contents-delicately (file-name _auto-save-p)
+  "Optional function for `revert-buffer-insert-file-contents-function'.
+The function `revert-buffer-with-fine-grain' uses this function by binding
+`revert-buffer-insert-file-contents-function' to it.
+As with revert-buffer-insert-file-contents--default-function, FILE-NAME is
+the name of the file and AUTO-SAVE-P is non-nil if this is an auto-save file.
+Since calling `replace-buffer-contents' can take a long time, depending of
+the number of changes made to the buffer, it uses the value of the variable
+`revert-buffer-with-fine-grain-max-seconds' as a maximum time to try delicately
+reverting the buffer.  If it fails, does a delete+insert.  For more details,
+see `replace-buffer-contents'."
+  (cond ((not (file-exists-p file-name))
+         (error (if buffer-file-number
+                    "File %s no longer exists"
+                  "Cannot revert nonexistent file %s")
+                file-name))
+        ((not (file-readable-p file-name))
+         (error (if buffer-file-number
+                    "File %s no longer readable"
+                  "Cannot revert unreadable file %s")
+                file-name))
+        (t
+         (let* ((buf (current-buffer)) ; current-buffer is the buffer to revert.
+                (success
+                 (save-excursion
+                   (save-restriction
+                     (widen)
+                     (with-temp-buffer
+                       (insert-file-contents file-name)
+                       (let ((temp-buf (current-buffer)))
+                         (set-buffer buf)
+                         (replace-buffer-contents
+                          temp-buf
+                          revert-buffer-with-fine-grain-max-seconds)))))))
+           ;; See comments in revert-buffer-with-fine-grain for an explanation.
+           (defun revert-buffer-with-fine-grain-success-p ()
+             success))
+         (set-buffer-modified-p nil))))
+
+(defun revert-buffer-with-fine-grain (&optional ignore-auto noconfirm)
+  "Revert buffer preserving markers, overlays, etc.
+This command is an alternative to `revert-buffer' because it tries to be as
+non-destructive as possible, preserving markers, properties and overlays.
+Binds `revert-buffer-insert-file-contents-function' to the function
+`revert-buffer-insert-file-contents-delicately'.
+With a prefix argument, offer to revert from latest auto-save file.  For more
+details on the arguments, see `revert-buffer'."
+  ;; See revert-buffer for an explanation of this.
+  (interactive (list (not current-prefix-arg)))
+  ;; Simply bind revert-buffer-insert-file-contents-function to the specialized
+  ;; function, and call revert-buffer.
+  (let ((revert-buffer-insert-file-contents-function
+         #'revert-buffer-insert-file-contents-delicately))
+    (revert-buffer ignore-auto noconfirm t)
+    ;; This closure is defined in revert-buffer-insert-file-contents-function.
+    ;; It is needed because revert-buffer--default always returns t after
+    ;; reverting, and it might be needed to report the success/failure of
+    ;; reverting delicately.
+    (when (fboundp 'revert-buffer-with-fine-grain-success-p)
+      (prog1
+          (revert-buffer-with-fine-grain-success-p)
+        (fmakunbound 'revert-buffer-with-fine-grain-success-p)))))
+
 (defun recover-this-file ()
   "Recover the visited file--get contents from its last auto-save file."
   (interactive)
diff --git a/test/lisp/files-tests.el b/test/lisp/files-tests.el
index fe2e958..9a6f35d 100644
--- a/test/lisp/files-tests.el
+++ b/test/lisp/files-tests.el
@@ -1259,5 +1259,59 @@ files-tests-file-attributes-equal
       (ignore-errors (advice-remove #'write-region advice))
       (ignore-errors (delete-file temp-file-name)))))
 
+(defvar files-tests-lao "The Way that can be told of is not the eternal Way;
+The name that can be named is not the eternal name.
+The Nameless is the origin of Heaven and Earth;
+The Named is the mother of all things.
+Therefore let there always be non-being,
+  so we may see their subtlety,
+And let there always be being,
+  so we may see their outcome.
+The two are the same,
+But after they are produced,
+  they have different names.
+")
+
+(defvar files-tests-tzu "The Nameless is the origin of Heaven and Earth;
+The named is the mother of all things.
+
+Therefore let there always be non-being,
+  so we may see their subtlety,
+And let there always be being,
+  so we may see their outcome.
+The two are the same,
+But after they are produced,
+  they have different names.
+They both may be called deep and profound.
+Deeper and more profound,
+The door of all subtleties!
+")
+
+(ert-deftest files-tests-revert-buffer ()
+  "Test that revert-buffer is succesful."
+  (files-tests--with-temp-file temp-file-name
+    (with-temp-buffer
+      (insert files-tests-lao)
+      (write-file temp-file-name)
+      (erase-buffer)
+      (insert files-tests-tzu)
+      (revert-buffer t t t)
+      (should (compare-strings files-tests-lao nil nil
+                               (buffer-substring (point-min) (point-max))
+                               nil nil)))))
+
+(ert-deftest files-tests-revert-buffer-with-fine-grain ()
+  "Test that revert-buffer-with-fine-grain is successful."
+  (files-tests--with-temp-file temp-file-name
+    (with-temp-buffer
+      (insert files-tests-lao)
+      (write-file temp-file-name)
+      (erase-buffer)
+      (insert files-tests-tzu)
+      (should (revert-buffer-with-fine-grain t t))
+      (should (compare-strings files-tests-lao nil nil
+                               (buffer-substring (point-min) (point-max))
+                               nil nil)))))
+
 (provide 'files-tests)
 ;;; files-tests.el ends here
-- 
2.7.4


^ permalink raw reply related	[flat|nested] 24+ messages in thread

* bug#18: Fine-grained revert-buffer
  2019-05-15 23:10         ` Mauro Aranda
@ 2020-09-19 23:08           ` Lars Ingebrigtsen
  0 siblings, 0 replies; 24+ messages in thread
From: Lars Ingebrigtsen @ 2020-09-19 23:08 UTC (permalink / raw)
  To: Mauro Aranda; +Cc: 18

Mauro Aranda <maurooaranda@gmail.com> writes:

> I spent some time thinking on how to get this new revert command
> integrated with the rest of revert-buffer functions, and I came up with
> the attached patch.
>
> Since the difference between revert-buffer and
> revert-buffer-with-fine-grain lies at the insert-file-contents level, I
> wrote an alternative to
> revert-buffer-insert-file-contents--default-function, that uses
> replace-buffer-contents, as Eli suggested.  I named it
> revert-buffer-insert-file-contents-delicately.

[...]

> Corrections and comments are welcome.  Better names too.

This was the final message in this thread (which is the oldest
still-open bug report in debbugs!).

I tried the patch out, and it almost worked flawlessly for me -- it did
the "really edit the buffer?" userlock thing, but that was easy enough
to disable, so I did that.

And I pushed the patch set to the trunk.  I agree that perhaps the
command name isn't the most intuitive, so somebody with stronger ideas
about what the name of the command should be should go ahead and change
it.

-- 
(domestic pets only, the antidote for overdose, milk.)
   bloggy blog: http://lars.ingebrigtsen.no





^ permalink raw reply	[flat|nested] 24+ messages in thread

end of thread, other threads:[~2020-09-19 23:08 UTC | newest]

Thread overview: 24+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
     [not found] <jwvpruii0xr.fsf@iro.umontreal.ca>
2013-12-17  3:16 ` bug#18: Fine-grained revert-buffer Dmitry Gutov
2013-12-17 13:32   ` Stefan Monnier
2018-04-12  6:21 ` Toon Claes
2018-04-12 12:18   ` Stefan Monnier
2018-04-14  7:00     ` Toon Claes
2018-04-14 14:14       ` Stefan Monnier
2019-04-26 22:42 ` Mauro Aranda
2019-04-27  7:34   ` Eli Zaretskii
2019-04-27 15:10     ` Mauro Aranda
2019-04-27 16:30       ` Eli Zaretskii
2019-04-27 17:46         ` Mauro Aranda
2019-04-29 12:49       ` martin rudalics
2019-05-02 15:54         ` Basil L. Contovounesios
2019-05-02 16:20           ` Glenn Morris
2019-05-02 16:23             ` Basil L. Contovounesios
2019-05-02 21:27           ` Richard Stallman
2019-05-03 14:05             ` Basil L. Contovounesios
2019-05-05 22:41               ` Richard Stallman
2019-04-27  8:31   ` martin rudalics
2019-04-28  2:47   ` Richard Stallman
2019-04-29 23:32     ` Mauro Aranda
2019-04-30  0:17       ` Mauro Aranda
2019-05-15 23:10         ` Mauro Aranda
2020-09-19 23:08           ` Lars Ingebrigtsen

Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).