rickhowe / diffchar.vim

Highlight the exact differences, based on characters and words
http://www.vim.org/scripts/script.php?script_id=4932
MIT License
216 stars 10 forks source link

Work on a single file containing diff output? #14

Closed jakwings closed 5 years ago

jakwings commented 5 years ago

I want to highlight the word/char-diff inside each section of the diff output. Could you provide a special mode or function for this purpose? It doesn't have to update the highlight.

At the same time, I'm modifying dwdiff for the same effect (only for unified context, not copied context). But a pure vimscript solution would be great too!

rickhowe commented 5 years ago

If you want to compare different 2 sections in a single file, such as diff output, my another plugin https://github.com/rickhowe/spotdiff.vim might be useful. Please let me know if that would not help you.

jakwings commented 5 years ago

No, that plugin also makes use of diffthis and needs two window. I want to edit the diff output in place with the help from the highlight, then simply save and apply the patch.

I forgot to mention the expected output format.

e.g. original diff section

-A bad day.
+A good day.

e.g. modified (deletion and insertion on separate lines)

-A [-bad-] day.
+A {+good+} day.

then after my edit it becomes

-A [-bad-] day.
+A {+nice+} day.

finally, when the file is saved the concealed tags should get removed.

rickhowe commented 5 years ago

Both my plugins are intended to make vim's diff mode more useful. If you would need something other than the diff mode in vim, those plugins can not be enhanced to meet your needs.

jakwings commented 5 years ago

No problem. I can try to implement it myself. I was interested by that auto-update after modification and wondered if those functions can be easily reused for implementing this new feature. 😃

rickhowe commented 5 years ago

This is just FYI but I made a simple vim script which might be useful for you. Steps are described in the file. Please try it if necessary. dout_diff.zip

jakwings commented 5 years ago

Clever solution! I feel so meta now.

I customized it a bit so it can mark the change in the original file. The only downside is that vim slows down a lot, even if the texts are trimmed down to 2000 lines (no empty lines).

Here is the new script (edit: fixed && support git-diff):

" Steps
" 1. open a diff output file (unified format: both "diff -u" and "git diff")
" 2. execute this script (:so dout_diff.vim)
"    - appear a dummy window on right side
"    - show the file and change '-' lines with correspponding '+' lines
"    - show the file and change '+' lines with correspponding '-' lines
"    - do diffthis on both windows
" 3. edit the file as required and save it
" 4. do diffoff!
" 5. quit the dummy window

let s:lines = []
let s:starting = 1
let s:changes = []
let s:i = 1
let s:n = line('$')
while s:i <= s:n
    let s:line = getline(s:i)

    if s:starting
        if s:line[0] == '@'
            let s:starting = 0
            let s:changes = []
        endif
        let s:lines += [s:line]
        let s:i += 1
        continue
    endif

    if !empty(s:line) && s:line[0] !~ '^[-+ @]'
        let s:starting = 1
        let s:lines += [s:line]
        let s:i += 1
        continue
    endif

    if s:line[0] == '+'
        if !empty(s:changes)
            let s:m = len(s:changes)
            for s:j in range(s:i, s:i + s:m - 1, 1)
                let s:line = getline(s:j)
                if s:line[0] == '+'
                    let s:lines += ['-' . s:line[1:]]
                    let s:i = s:j
                    let s:m -= 1
                else
                    break
                endif
            endfor
            if s:m > 0
                let s:lines += s:changes[(-s:m):]
            endif
            let s:lines += s:changes
            let s:changes = []
        else
            let s:lines += ['-' . s:line[1:]]
        endif
    elseif s:line[0] == '-'
        let s:changes += ['+' . s:line[1:]]
    else "if line[0] == ' ' || line[0] == '@'
        let s:changes = []
        let s:lines += [s:line]
    endif

    let s:i += 1
endwhile

if !empty(s:lines)
    let s:wid = bufwinid('%')

    aboveleft 1new
    call setline(1, s:lines)
    let &l:modifiable = 0
    let &l:buftype = 'nofile'
    let &l:bufhidden = 'wipe'
    let &l:buflisted = 0
    let &l:swapfile = 0
    diffthis

    call win_gotoid(s:wid)
    diffthis
endif