12

I'm trying to have a highlighted undo in Vim, like spacemacs default config. Sometimes when I want quick undo's, I can't realize what changed because it's instantaneous. So I am trying to have something like this when a press undo:

highlighted undo

Anyone have an idea how to do this in Vim?

(I already have Gundo plugin, i just want to make the default undo more smooth)

Edit: The undotree plugin does the work (Gundo doesn't highlight the changes), just use the UndotreeToggle command and all future changes on the file will be highlighted.

  • Nice idea. You can create a highlight with matchadd(), but slightly more tricky is working out which parts of the file have changed. – joeytwiddle Aug 18 '15 at 0:57
  • Perhaps saving to a temporary buffer/file before the undo, then to a 2nd buffer/file after the undo, and highlighting the new diffs after cleaning (or changing the color of) the previous ones. Could get slow for large files. – VanLaser Aug 18 '15 at 9:55
  • UndoTree does actually highlight changed lines, but it doesn't do it in realtime. I think it uses GNU diff. Getting word granularity would be an extra step (e.g. split lines at word breaks, diff, recombine lines). – joeytwiddle Aug 22 '15 at 3:08
  • These plugins come close, but they are still line-based: smeargle can highlight lines changed since the last save. changesPlugin marks changed lines (including deletions) in the gutter on the left. – joeytwiddle Aug 22 '15 at 3:36
  • 1
    @joeytwiddle, changesPlugin can also highlight the last change region – Christian Brabandt Aug 22 '15 at 11:26
6

New solution

You can view your last changes with the :changes command. So you can fecth your most recent line change with a regex and then apply the line to matchadd() as suggested by @joeytwiddle.

Here is the code :

function! DiffWithPrevious()
  call clearmatches()
  redir => message
  silent changes
  redir END
  let line = matchstr(message, '\v\n\s{4}1[^0-9]*\zs\d+\ze')
  highlight TemporalDiff ctermbg=green guibg=green
  let m = matchadd('TemporalDiff', '\%'.line.'l')
endfunction

Note :

  • This function only add a new highlight without removing the old one, so you'd have to remove the old one first. With the clearmatches function you can remove the matches before adding a new one. Careful, it will remove ALL matches. If you want more granularity, you can save your match and remove it manually :

e.g.

function! DiffWithPrevious()
  call matchdelete(m)
  ... 
  let m = matchadd('TemporalDiff', '\%'.line.'l')
endfunction
  • After some tests, I found out it only works for one-line change.

References :


Old solution

Here is a possible solution, mainly inspired by Diff current buffer and the original file :

function! DiffWithPrevious()
  undo
  write
  redo
  let filetype=&ft
  diffthis
  vnew | r # | normal! 1Gdd
  diffthis
  exe "setlocal bt=nofile bh=wipe nobl noswf ro ft=" . filetype
endfunction

The idea is to diff the file with the file on the system, so you undo your last change, write it, redo the las change and execute the diff.

I think this should do the job for time-to-time temporal diff visualisations.

  • there is a way to clear the message "buffer" on DiffWithPrevious() ? I wish the function highlighted just the last changes,but highlight is accumulating over time, im trying something like message = 0 or message = "" but no sucess. – tjbrn Aug 19 '15 at 22:29
  • Of course yeah, let me update my answer. – nobe4 Aug 20 '15 at 4:15
3

Check my changes plugin and be sure to set the variable g:changes_linehi_diff to 1

2

For someone who is trying the same of me, that is closest that i reached thanks to the answers.

function! DiffWithPrevious()
  call clearmatches()
  undo
  redir => message
  silent changes
  redir END
  let line = matchstr(message, '\v\n\s{4}1[^0-9]*\zs\d+\ze')
  highlight TemporalDiff ctermbg=black guibg=black
  let m = matchadd('TemporalDiff', '\%'.line.'l')
  redraw
  let gchar = getchar()
  highlight TemporalDiff ctermbg=none guibg=none
  let m = matchadd('TemporalDiff', '\%'.line.'l')
endfunction

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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