Closed PythonNut closed 9 years ago
Not a priority, as far as I'm concerned. Even if someone implements it, it'll likely be too slow on large files, and clash with the "staged hunks" display, if that's ever implemented.
I'd look at a patch, though.
I'm currently experimenting. I think I might arrive at a patch not too far in the future (as in weeks, not years). Here's something that mostly works. (occasionally it gets hunks confused). It's just a snippet (uncommited) from my init.el
. The code is truly terrible. I redefine other people's functions and the code is a DRY as an ocean.
Rather surprisingly, the performance already seems acceptable. (But then, this does come from a person who uses diff-hl
and git-gutter+-mode
at the same time).
(defun diff-buffer-with-file-unified ()
"View the differences between BUFFER and its associated file.
This requires the external program `diff' to be in your `exec-path'."
(interactive)
(with-current-buffer (get-buffer (current-buffer))
(diff-custom buffer-file-name (current-buffer) "-U 0" 'noasync)))
;; diff, but do not open a window for the buffer
(defun diff-custom (old new &optional switches no-async)
"Find and display the differences between OLD and NEW files.
When called interactively, read NEW, then OLD, using the
minibuffer. The default for NEW is the current buffer's file
name, and the default for OLD is a backup file for NEW, if one
exists. If NO-ASYNC is non-nil, call diff synchronously.
When called interactively with a prefix argument, prompt
interactively for diff switches. Otherwise, the switches
specified in the variable `diff-switches' are passed to the diff command."
(interactive
(let* ((newf (if (and buffer-file-name (file-exists-p buffer-file-name))
(read-file-name
(concat "Diff new file (default "
(file-name-nondirectory buffer-file-name) "): ")
nil buffer-file-name t)
(read-file-name "Diff new file: " nil nil t)))
(oldf (file-newest-backup newf)))
(setq oldf (if (and oldf (file-exists-p oldf))
(read-file-name
(concat "Diff original file (default "
(file-name-nondirectory oldf) "): ")
(file-name-directory oldf) oldf t)
(read-file-name "Diff original file: "
(file-name-directory newf) nil t)))
(list oldf newf (diff-switches))))
(diff-no-select old new switches no-async))
(with-eval-after-load 'diff-hl
(defun diff-hl-changes ()
(let* ((file buffer-file-name)
(backend (vc-backend file)))
(when backend
(let ((state (vc-state file backend)))
(cond
((or (eq state 'edited)
(and (eq state 'up-to-date)
;; VC state is stale in after-revert-hook.
(or revert-buffer-in-progress-p
;; Diffing against an older revision.
diff-hl-reference-revision)))
(let* ((buf-name " *diff-hl* ")
diff-auto-refine-mode
res)
(diff-hl-with-diff-switches
(vc-call-backend backend 'diff (list file)
diff-hl-reference-revision nil
buf-name))
(with-current-buffer buf-name
(goto-char (point-min))
(unless (eobp)
(ignore-errors
(diff-beginning-of-hunk t))
(while (looking-at diff-hunk-header-re-unified)
(let ((line (string-to-number (match-string 3)))
(len (let ((m (match-string 4)))
(if m (string-to-number m) 1)))
(beg (point)))
(diff-end-of-hunk)
(let* ((inserts (diff-count-matches "^\\+" beg (point)))
(deletes (diff-count-matches "^-" beg (point)))
(type (cond ((zerop deletes) 'insert)
((zerop inserts) 'delete)
(t 'change))))
(when (eq type 'delete)
(setq len 1)
(cl-incf line))
(push (list line len type) res))))))
(diff-buffer-with-file-unified)
(with-current-buffer "*Diff*"
(goto-char (point-min))
(unless (eobp)
(ignore-errors
(diff-beginning-of-hunk t))
(while (looking-at diff-hunk-header-re-unified)
(let ((line (string-to-number (match-string 3)))
(len (let ((m (match-string 4)))
(if m (string-to-number m) 1)))
(beg (point)))
(diff-end-of-hunk)
(let* ((inserts (diff-count-matches "^\\+" beg (point)))
(deletes (diff-count-matches "^-" beg (point)))
(type (cond ((zerop deletes) 'insert)
((zerop inserts) 'delete)
(t 'change))))
(when (eq type 'delete)
(setq len 1)
(cl-incf line))
(push (list line len type) res)
(setq res (mapcar
(lambda (item)
(if (> (first item) line)
(list (+ (first item) (- inserts deletes)) (second item) (third item))
item)) res)))))))
(nreverse res)))
((eq state 'added)
`((1 ,(line-number-at-pos (point-max)) insert)))
((eq state 'removed)
`((1 ,(line-number-at-pos (point-max)) delete))))))))
;; (add-hook 'post-command-hook 'diff-hl-update)
(run-with-idle-timer 1 t 'diff-hl-update))
You can avoid using a temporary file, see the second option in this answer: http://stackoverflow.com/a/18174051/615245
While making a patch, keep in mind that this project also requires copyright assignment to FSF. I could make the relevant behavior more customizable, though.
Well, there are larger problems. This fails when an unsaved diff modified the result of an unstaged diff. The current program just starts marking huge sections as modified.
To fix this, we need line-precision diffing.
I don't think you need two diffs at the same time. Just diff the buffer contents against the current repository version.
I tried that, although not very hard in theory, vc
doesn't support it, and I don't know enough to make a version that works in all systems that vc
does.
You should look at the source of vc-revision-other-window
. Apparently, all we need is vc-working-revision
and vc-find-revision
(or just the backend command, if we'd like to choose the output buffer).
The other question is whether or not we want to highlight unsaved changes with different markers as well.
Obviously, that would be nice, but it would cost us one diff over the straight revision ==> buffer method.
Err, probably not. That's a lot of highlighting already.
But note that "changed lines" can be an entirely different highlighter. It doesn't need to call the external process at all, and it can work either through post-command-hook
(and recording where changes happen), or by parsing buffer-undo-list
. See highlight-changes-mode
.
I never figured out how to get highlight-changes-mode
to work by lines. Also, it doesn't have a very good way to determine what has been deleted.
Perhaps we can use both, highlight-changes-mode
to tell us which hunks are not synchronized, and the buffer ==> revision diff to actually get the hunks.
How would process substitution work in Emacs' case? I don't know of any command that causes Emacs to print a buffer to a pipe/stream.
Actually, I don't think that would be too hard, we can just have emacs "save" to a FIFO, and pass it to diff
.
git diff :0:<buffer-relative-file-name> /tmp/diff-hl-fifo
However this doesn't fix the case for other vcs systems. Or did you want to pay the one-time overhead of vc-find-revision
for the sake of generality? After which we do
diff <(buffer-file-name)>.~<(vc-working-revision buffer-file-name)>~ /tmp/diff-hl-fifo
Does this program work on Windows? Is windows support a concern?
Here's a working version that uses vc-find-revision
. Current problems:
*Diff*
buffer a different name so it doesn't clobber diffs the user is using, and we also want it to be hidden.(defun vc-show-working-revision ()
(interactive)
(vc-ensure-vc-buffer)
(let* ((file buffer-file-name)
(revision (vc-working-revision file)))
;; hide the buffer and pass it on
(with-current-buffer (vc-find-revision file revision)
(rename-buffer (concat " " (buffer-name)))
(current-buffer))))
(defun diff-buffer-with-head-unified ()
"View the differences between BUFFER and its associated file.
This requires the external program `diff' to be in your `exec-path'."
(interactive)
(with-current-buffer (get-buffer (current-buffer))
(with-current-buffer
(diff-no-select
(vc-show-working-revision)
(current-buffer)
"-U 0" 'noasync)
(concat " " (buffer-name))
(current-buffer))))
(with-eval-after-load 'diff-hl
(setq diff-hl-draw-borders nil)
(defun diff-hl-changes ()
(let* ((file buffer-file-name)
(backend (vc-backend file)))
(when backend
(let ((state (vc-state file backend)))
(cond
((or (eq state 'edited)
(and (eq state 'up-to-date)
;; VC state is stale in after-revert-hook.
(or revert-buffer-in-progress-p
;; Diffing against an older revision.
diff-hl-reference-revision)))
(let* ((buf-name " *diff-hl* ")
diff-auto-refine-mode
res)
(diff-buffer-with-head-unified)
(with-current-buffer "*Diff*"
(goto-char (point-min))
(unless (eobp)
(ignore-errors
(diff-beginning-of-hunk t))
(while (looking-at diff-hunk-header-re-unified)
(let ((line (string-to-number (match-string 3)))
(len (let ((m (match-string 4)))
(if m (string-to-number m) 1)))
(beg (point)))
(diff-end-of-hunk)
(let* ((inserts (diff-count-matches "^\\+" beg (point)))
(deletes (diff-count-matches "^-" beg (point)))
(type (cond ((zerop deletes) 'insert)
((zerop inserts) 'delete)
(t 'change))))
(when (eq type 'delete)
(setq len 1)
(cl-incf line))
(push (list line len type) res))))))
(nreverse res)))
((eq state 'added)
`((1 ,(line-number-at-pos (point-max)) insert)))
((eq state 'removed)
`((1 ,(line-number-at-pos (point-max)) delete))))))))
;; (add-hook 'post-command-hook 'diff-hl-update)
(run-with-idle-timer 1 t 'diff-hl-update))
We need give the Diff buffer a different name so it doesn't clobber diffs the user is using, and we also want it to be hidden.
Any variation on *diff*
would solve both those problems.
We need to cleanup the working revision files (messy and bad), or make them in a location that requires no cleanup (clean, good).
Somewhere in /tmp
, I guess. We should also not retrieve them every time, but rather only do that when the file is opened, or the user does a commit. Maybe also monitor the current repository version in a timer, to catch commits made by external tools or unanticipated packages.
Also note that the name vc-show-working-revision
is no good: this code isn't part of the VC
package.
Any variation on diff would solve both those problems.
The problem is that the buffer name is hardcoded.
Somewhere in /tmp, I guess.
Or /dev/shm
on Linux, which is guaranteed to be a ramdisk.
We should also not retrieve them every time, but rather only do that when the file is opened, or the user does a commit.
vc
already tracks when the file already exists and returns it instead of creating a new one. I don't know if it also checks if said file is out of date.
Also note that the name vc-show-working-revision is no good: this code isn't part of the VC package.
Noted. It's a bad habit of mine to experiment by copying definitions and editing them.
vc already tracks when the file already exists and returns it instead of creating a new one. I don't know if it also checks if said file is out of date.
Ah, so it does (and it ensures the match by having the revision a part of the filename). However, that logic is tied to having the checked out file in the same directory as the current one. So you'll probably need to write a different version of vc-find-revision
, using a temporary directory.
Any variation on diff would solve both those problems.
The problem is that the buffer name is hardcoded.
Wait no, apparently I can't read. It's not hardcoded at all.
How would process substitution work in Emacs' case? I don't know of any command that causes Emacs to print a buffer to a pipe/stream.
shell-command-on-region
?
I suppose I learn new things every day. We've stopped needing to do that, right? (as diff does it automatically).
diff-no-select
writes a copy of the buffer to disk, so maybe we could do better. Or not; someone would have to measure the performance impact.
We could potentially have it write to a ramdisk, which would be very fast. I know it writes to /tmp
by default, which is often a randisk.
Sure. But we'll still need to measure it. :)
Okay, so I have almost working code. The last problem is that vc-find-revision does not check if the revision has changed. If I'm on a branch dev
and I push commits to dev
emacs doesn't refresh the revision file.
Why would it check for a change in revision? It takes revision as an argument.
Suppose I'm on branch dev
with file test.el
. vc
creates the working revision file as test.el.~dev~
. If I add more commits to dev
it has no way of knowing that test.el.~dev~
is out of date.
Right, that would be a problem. Without us having to re-implement each working-revision
function to return non-symbolic refs, maybe add a function to vc-checkin-hook
that would delete all the working revision files for the repo. But that won't account for commits or other history manipulations made from the command line.
Or/and put it at the end of find-file-hook
(after vc-find-file-hook
). That was, it'll run when the buffer is reverted.
Or maybe we could ask the core to provide a variable, setting which to t would force working-revision
implementations to return non-symbolic refs.
After all, your example shows that vc-revision-other-window
can return a stale result. And it could be fixed likewise by using that variable.
Hmm... would this be considered a bug in vc
itself? I'd consider it a bug in git
if git diff @ dev
showed stale diffs for dev
for example.
Indeed.
How do we intend to fix it? I've never encountered this before. Obviously, we do want it to work in current versions. Do we advise it conditionally on the version?
Obviously, we do want it to work in current versions
Only if it's not too much trouble. Emacs releases come and go. Not everyone has to have access to the latest goodies. :)
Do we advise it conditionally on the version?
Probably. First we'll have to fix it in the core, and the advice could be based on that fix.
For git
:
(defadvice vc-git-working-revision
(around use-hashes-only (file) activate preactivate compile)
"Git-specific version of `vc-working-revision'."
(vc-git--rev-parse "HEAD"))
I haven't used the other vc
systems to the point where I can intelligently comprehend their code, and checking them all seems to be a daunting task.
Yes, the above should work. But doing just this will make VC show Git-ffafafafafaf
in the mode-line where it now shows Git-master
, which would be a step back in functionality.
Maybe the working-revision
VC command needs a new optional "literal" argument.
Hm... I suppose the question is what we mean by revision. In my mind, a revision must be immutable. master
is not a revision, but ffafafafafaf
is. master
is a branch. That might just be me, but I suspect I'm not the only one...
It's probably a little late to fix this without breaking tons of stuff.
Maybe the
working-revision
VC command needs a new optional "literal" argument.
That would require us to update all of the backends, right? That would require quite a few people (unless we know someone who knows a ton of vc systems. monotone
, anyone?).
I suppose the question is what we mean by revision... It's probably a little late to fix this without breaking tons of stuff.
Yes, now what VC means by "revision" is defined by the places it's used in.
That would require us to update all of the backends, right? That would require quite a few people (unless we know someone who knows a ton of vc systems).
Not if the argument is optional, then the backends can be updated gradually. And the backends that alreay return a "concrete" revision would be unaffected.
Handling this is a half step more delicate than I planned because vc
also caches the revisions as lisp attributes.
Also, it struck me that this will cost one more disk access per diff (for the index).
vc also caches the revisions as lisp attributes
Where? I can't see that in vc-git-find-revision
or vc-find-revision
.
Also, it struck me that this will cost one more disk access per diff (for the index).
At what point?
(defun vc-working-revision (file &optional backend)
"Return the repository version from which FILE was checked out.
If FILE is not registered, this function always returns nil."
(or (vc-file-getprop file 'vc-working-revision)
(progn
(setq backend (or backend (vc-responsible-backend file)))
(when backend
(vc-file-setprop file 'vc-working-revision
(vc-call-backend backend 'working-revision file))))))
HEAD
is out-of-date. This costs us one rev-parse
in git's case.Also, I just noticed that the indentation in vc
is a horrible mess of both tabs and spaces (with no rhyme or reason).
Oh, right. I was looking at wrong functions.
Every time we diff, we need to check if the current cached file from HEAD is out-of-date.
When does that happen? Emacs does not cache the git diff
output, so maybe passing HEAD
verbatim into various commands should work just as well.
By the way, you should feel free to bring up various problems either at emacs-devel, or via M-x report-emacs-bug
.
I just noticed that the indentation in vc is a horrible mess of both tabs and spaces
Let's not go there. :)
When does that happen? Emacs does not cache the git diff output, so maybe passing HEAD verbatim into various commands should work just as well.
Here's how my code works (currently)
/dev/shm
(or /tmp
if no /dev/shm
is found). This is very cheap as we prefer a ramdisk./dev/shm
). This is cheap too.On further diffs
The rev-parse
, which is one of the more expensive operations in this system, costs 0.002s on my system, which I doubt will be a problem.
maybe passing HEAD verbatim into various commands should work just as well.
I would like to. Ultimately, I wish there were some sort of (vc-diff (vc-working-revision buffer-file-name) (current-buffer))
magic that would simplify this, but I haven't found it.The difficulty arises from diffing with the current buffer (i.e. not a file). We need to manually write it out somewhere. When we do, we can no longer rely on vc
for diffing, because our temp file is not under version control. Without vc
, HEAD
loses its meaning.
By the way, you should feel free to bring up various problems either at emacs-devel, or via M-x report-emacs-bug.
Yes. I'm looking into just becoming an emacs developer outright and contributing. First, I'm cooking up a ton of advice to prove that everything works (before I start breaking things).
All of my ingredients are together now. My code works, as far as I can tell. Now I need to make it pretty and fast.
The rev-parse, which is one of the more expensive operations in this system, costs 0.002s on my system, which I doubt will be a problem.
I'm pretty sure the diff operation will become the most expensive, at least on some files.
Ultimately, I wish there were some sort of ... magic that would simplify this
git diff
can use stdin: http://stackoverflow.com/a/18174051/615245. Until VC supports this kind of operation, this probably won't help us, though, but diff
can do that as well.
Yes. I'm looking into just becoming an emacs developer outright and contributing.
That's great, but filing some bugs and starting a discussion or two would be good starting steps in this direction.
Now I need to make it pretty and fast.
And then, I guess, we'll have to make diff-hl
somehow flexible in when/how to diff. That's not trivial, too.
I'm pretty sure the diff operation will become the most expensive, at least on some files.
Probably. I just checked with some medium source files (~4000 lines) and the diff took about 0.002s, so there is room for it to outstrip the rev-parse
, but not by terribly much.
git diff can use stdin: http://stackoverflow.com/a/18174051/615245. Until VC supports this kind of operation, this probably won't help us, though, but diff can do that as well.
That's interesting. We'd need to forgo diff-no-select
and write our own diffing procedure.
That's great, but filing some bugs and starting a discussion or two would be good starting steps in this direction.
I have in the past. One bug was fixed quickly, and the other has not yet been touched by anyone. (And I can't fix it myself). I don't really know what to discuss, so I haven't done any of that.
And then, I guess, we'll have to make diff-hl somehow flexible in when/how to diff. That's not trivial, too.
Right now, I've advised dif-hl-changes
, and I run diff-hl-update
with an idle-timer (it was actually working fine in the post-command-hook
, but I chickened out of that). It's working pretty well so far, but if you have better ideas, I'm all ears.
We'd need to forgo diff-no-select and write our own diffing procedure.
Or update diff-no-select
to use stdin when it can. You should measure the performance first, though: the temp file solution is probably fast enough anyway, especially if the user has an SSD.
and the other has not yet been touched by anyone
What's the number? I can look at it, if it's within my competence (and interesting enough :)).
I don't really know what to discuss, so I haven't done any of that.
If you intend to become an Emacs developer, surely you have some improvement to Emacs in mind? Or will you stop at this package?
I've advised dif-hl-changes
That could be generalized with a diff-hl-changes-function
variable...
I run diff-hl-update with an idle-timer (it was actually working fine in the post-command-hook, but I chickened out of that)
Yeah, an idle timer is safer anyway.
It's working pretty well so far, but if you have better ideas, I'm all ears.
Sounds like it might work fine as a new minor mode. Not sure yet if I want this to be the default behavior. But if that's all you needed to change, overall the necessary changes look pretty simple, which is good.
@dgutov Sorry, I meant to add the bug #, but I never got around to it. It's #19455, and it deals with some special zsh
syntax that breaks sh-mode
highlighting.
If you intend to become an Emacs developer, surely you have some improvement to Emacs in mind? Or will you stop at this package?
I usually do, but I generally just go and write code and, when I get stuck, ask specific questions on emacs.stackexchange to help me along.
Sounds like it might work fine as a new minor mode. Not sure yet if I want this to be the default behavior. But if that's all you needed to change, overall the necessary changes look pretty simple, which is good.
I have no problem with it being a custom variable or a minor mode.
That could be generalized with a diff-hl-changes-function variable...
Yes please.
The one other thing that I've found is that diff-hl
removes highlighting during editing only to have it restored later when my idle-timer fires. This makes for some blinking that is a little distracting. Obviously this makes sense without flydiffs but with them, it just gets in the way. How can I disable this? (Or am I misunderstanding something?)
19455
I see, yeah it looks pretty niche to me. But if you'd like a pointer, sh-syntax-propertize-function
should be the function to improve.
How can I disable this?
With (remove-hook 'after-change-functions 'diff-hl-edit t)
?
Okay, so summer is flying by. Here's my code, taken direct from my config. It's a bit of a mess, and I will clean it up, but I also don't want to let my absent-mindedness produce the possibility that I will forget this entirely.
(defun diff-hl-make-temp-file-name (file rev &optional manual)
"Return a backup file name for REV or the current version of FILE.
If MANUAL is non-nil it means that a name for backups created by
the user should be returned."
(let* ((auto-save-file-name-transforms
`((".*" ,temporary-file-directory t))))
(expand-file-name
(concat (make-auto-save-file-name)
".~" (subst-char-in-string
?/ ?_ rev)
(unless manual ".") "~")
temporary-file-directory)))
(defun diff-hl-create-revision (file revision)
"Read REVISION of FILE into a buffer and return the buffer."
(let ((automatic-backup (diff-hl-make-temp-file-name file revision))
(filebuf (get-file-buffer file))
(filename (diff-hl-make-temp-file-name file revision 'manual)))
(unless (file-exists-p filename)
(if (file-exists-p automatic-backup)
(rename-file automatic-backup filename nil)
(with-current-buffer filebuf
(let ((failed t)
(coding-system-for-read 'no-conversion)
(coding-system-for-write 'no-conversion))
(unwind-protect
(with-temp-file filename
(let ((outbuf (current-buffer)))
;; Change buffer to get local value of
;; vc-checkout-switches.
(with-current-buffer filebuf
(vc-call find-revision file revision outbuf))))
(setq failed nil)
(when (and failed (file-exists-p filename))
(delete-file filename)))))))
filename))
(defun diff-hl-diff-buffer-with-head ()
"View the differences between BUFFER and its associated file.
This requires the external program `diff' to be in your `exec-path'."
(interactive)
(vc-ensure-vc-buffer)
(with-current-buffer (get-buffer (current-buffer))
(let ((rev (diff-hl-create-revision
buffer-file-name
(vc-working-revision buffer-file-name
(vc-responsible-backend buffer-file-name)
t)))
(temporary-file-directory
(if (file-directory-p "/dev/shm/")
"/dev/shm/"
temporary-file-directory)))
(diff-no-select rev (current-buffer) "-U 0" 'noasync
(get-buffer-create " *diff-hl-diff*")))))
(with-eval-after-load 'vc
(defadvice vc-working-revision
(around concrete-revision (file &optional backend concrete) activate preactivate compile)
(setq ad-return-value
(if concrete
(vc-call-backend backend 'working-revision file t)
(or (vc-file-getprop file 'vc-working-revision)
(progn
(setq backend (or backend (vc-responsible-backend file)))
(when backend
(vc-file-setprop file 'vc-working-revision
(vc-call-backend backend 'working-revision file)))))))))
(with-eval-after-load 'vc-git
(defadvice vc-git-working-revision
(around use-hashes-only (file &optional concrete) activate preactivate compile)
"Git-specific version of `vc-working-revision'."
(if concrete
(setq ad-return-value (vc-git--rev-parse ad-do-it))
ad-do-it)))
(with-eval-after-load 'diff-hl
(defvar diff-hl-modified-tick 0)
(make-variable-buffer-local 'diff-hl-modified-tick)
(defadvice diff-hl-update
(around flydiff (&optional auto) activate preactivate compile)
(unless (and auto
(or
(= diff-hl-modified-tick (buffer-modified-tick))
(file-remote-p default-directory)
(not (buffer-modified-p))))
ad-do-it))
(defadvice diff-hl-changes
(around flydiff activate preactivate compile)
(setq ad-return-value
(let* ((file buffer-file-name)
(backend (vc-backend file)))
(when backend
(let ((state (vc-state file backend)))
(cond
((or
(buffer-modified-p)
(eq state 'edited)
(and (eq state 'up-to-date)
;; VC state is stale in after-revert-hook.
(or revert-buffer-in-progress-p
;; Diffing against an older revision.
diff-hl-reference-revision)))
(let (diff-auto-refine-mode res)
(with-current-buffer (diff-hl-diff-buffer-with-head)
(goto-char (point-min))
(unless (eobp)
(ignore-errors
(diff-beginning-of-hunk t))
(while (looking-at diff-hunk-header-re-unified)
(let ((line (string-to-number (match-string 3)))
(len (let ((m (match-string 4)))
(if m (string-to-number m) 1)))
(beg (point)))
(diff-end-of-hunk)
(let* ((inserts (diff-count-matches "^\\+" beg (point)))
(deletes (diff-count-matches "^-" beg (point)))
(type (cond ((zerop deletes) 'insert)
((zerop inserts) 'delete)
(t 'change))))
(when (eq type 'delete)
(setq len 1)
(cl-incf line))
(push (list line len type) res))))))
(setq diff-hl-modified-tick (buffer-modified-tick))
(nreverse res)))
((eq state 'added)
`((1 ,(line-number-at-pos (point-max)) insert)))
((eq state 'removed)
`((1 ,(line-number-at-pos (point-max)) delete)))))))))
(defadvice diff-hl-overlay-modified
(around preserve-overlays activate preactivate compile))
(add-hook 'diff-hl-mode-hook
(lambda ()
(remove-hook 'after-change-functions #'diff-hl-edit t)))
(run-with-idle-timer 0.3 t #'diff-hl-update t))
Thanks for the update. It looks fine overall, but you've duplicated the temp-directory-finding logic once, and the (called-interactively-p 'any)
bit is odd.
the
(called-interactively-p 'any)
bit is odd.
Ah yep, that's a side effect of some debugging I was doing a while ago. I've updated the code.
What should I do now?
Should I send you the copyright assignment form now?
@dgutov sure, what do I need to do for that? Will it hold for the Emacs source tree too?
Actually, forget about me sending, just follow these instructions:
http://git.savannah.gnu.org/cgit/gnulib.git/tree/doc/Copyright/request-assign.future
Put in "Emacs" as the name of the program. It covers the packages in GNU ELPA as well.
The README indicates that showing accurate diffs even if the buffer has been modified, but not saved is a possible feature. This is an issue to track the discussion and development of this feature, if this is deemed worthwhile to implement.