dgutov/diff-hl

Extraneous `diff-hl-edit` runs per a single char modification in the buffer

andrelkin opened this issue · 9 comments

diff-hl-edit hook's idea must be to invoke diff-hl-update when the user is running undo to reach non-modified buffer state.

But I did not understand why the undoing should be tracked at all.
While the buffer gets modified and not saved diff-hl-update is not run (except the on-fly "submode" which I do not involve for simpler description), so undoing the modification should not be concerned with diff-hl-update either.

I'd be glad to be corrected I am missing something.
Otherwise

@@ -561,7 +561,6 @@ The value of this variable is a mode line template as in
       (progn
         (diff-hl-maybe-define-bitmaps)
         (add-hook 'after-save-hook 'diff-hl-update nil t)
-        (add-hook 'after-change-functions 'diff-hl-edit nil t)
         (add-hook (if vc-mode
                       ;; Defer until the end of this hook, so that its
                       ;; elements can modify the update behavior.

would do a good job of relaxing emacs from calling the hook per any kind of change, a single char change, not just undo one.

The hunk overlays that are inserted in the buffer call diff-hl-overlay-modified in their modification-hooks. As a result, hunk overlay that encompasses a recent, unsaved buffer change is removed. In order not to present outdated information (a lot of the time it will become plainly wrong) in an unsaved buffer.

One big exception to that is when the buffer is undo-ne into a state which is already saved on disk. Meaning, we can show the indicators again. But since after-save-hook obviously doesn't run in this case, we need another mechanism, and diff-hl-edit is the best I could find.

All in all, the design constraint here was to always show correct diff indicators when the buffer is up to date. At the outset, we couldn't compute them at all when the buffer is unsaved. Now we can (with the approach used in diff-hl-flydiff-mode, but I personally still don't use it). Force of habit plus CPU/disk usage tradeoffs, let's say.

Howdy, Dmitry!

Thanks for explaining which makes a lot easier for me to grasp it all!
I understood the big exception, and sadly there's no reverse first-change-hook (makes sense to request one?).
Still it's about undo maybe cheaper would
to handle this use case it through undo 's advice?
Also, it's only undo that is in an overlay region that is of interest, is not?
When true, perhaps a specific to the region hook could be designed.

To another subject,
I am just a newcomer to the project, so forgive me if it was suggested, but how about
highlight the base of the code in a separated color? Then the saved text color to remain and non-saved-yet to be without any highlight.
[Naturally, this can be generalized into objects/colors customization, where object is hunk in any of unsaved, saved, staged, committed state.]

Cheers,

Andrei

Also, it's only undo that is in an overlay region that is of interest, is not?

Or inside one of the overlays that have been removed previously due to edits.

maybe cheaper would to handle this use case it through undo 's advice?

That would probably fail to affect undo-tree-undo, while the current solution does. Also, that would trigger a synchronous update, whereas diff-hl-edit basically runs diff-hl-after-undo asynchronously, and it will not do extra work if there is pending user input which will overshoot the "unmodified" buffer state again into a modified one.

All in all, I think the current solution has pretty good performance, and whatever code is run directly on after-change-functions, is very fast. Try this benchmark, for example:

(benchmark-run 10000 (diff-hl-edit 1 2 3))

but about highlight the base of the code in a separated color?

The unchanged lines?

IDK, it sounds a fair bit more difficult to implement. git diff (or equivalent) that the code is using now is unlikely to provide the needed information.

Highlighting the changed lines with some special color instead might be easier, though it'll need some change tracking implemented in Lisp. Give it a try sometime, maybe.

but about highlight the base of the code in a separated color?

The unchanged lines?

Yes, and more specifically the committed ones.

IDK, it sounds a fair bit more difficult to implement. git diff (or equivalent) that the code is using now is unlikely to provide the needed information.

Highlighting the changed lines with some special color instead might be easier,

That feels a better approach.

though it'll need some change tracking implemented in Lisp. Give it a try sometime, maybe.

So I think of editted-not-saved, saved-but-not-yet-staged and staged-not-committed objects and separate colors for each.

So I think of editted-not-saved, saved-but-not-yet-staged and staged-not-committed objects and separate colors for each.

The first step toward this I would suggest it try implementing highlighting for staged lines. Also consider that there can be lines that contain both staged and unstaged changes (though they can simply be considered "unstaged").

Another challenge is how to choose presentation for all these options that would also look fine in different color themes. The red-green-blue combination coming from diff-mode was a trivial choice, but the colors to pick for the other options seem less obvious (as well as indicator chars, for diff-hl-margin-mode). Some research into other editors could help.

The first step toward this I would suggest it try implementing highlighting for staged lines.

That's the easiest, right.
I might take on that.

To the unsaved text marking and general colorization, I've not extensively looked around, but already liked https://github.com/jisaacks/GitGutter.

I've not extensively looked around, but already liked https://github.com/jisaacks/GitGutter.

Thanks. But does it show staged line status? I don't see that in README. Likewise, for changed and unsaved lines.

Anyway, the original question seems to have been answered.

Please post new issues or PRs when you have some progress.