Open6
gitgutter内製化したい

gitgutter本家は「なるべくプラグインが処理しないようにgrepが使えるならgrepを使います」とある
たしかにそう なるべく非同期でやれるならそっちのほうがよい
(vimの処理をブロックしたくない)

こんな感じにすればを変更範囲を得られる
❯ git --no-pager diff -U0 --no-color --no-ext-diff {fname} | grep '^@@.*@@$'
@@ -60 +60 @@
@@ -79,0 +80,2 @@
あとはなんとかしてパース
変更が1行のときに省略されるのがちょっと厄介(0のときは表示される)

- 現在のファイルのdiffを表示
- 変更範囲に関係する行をgrep
- 「1行」が省略されている部分を補完
- 関係ない部分を削除
git --no-pager diff -U0 --no-color --no-ext-diff README.md
| grep '^@@'
| sed -r 's/[-+]([0-9]+) /\1,1,/g'
| sed -r 's/^[-@ ]*([0-9]+,[0-9]+)[ ,+]+([0-9]+,[0-9]+)[, ].*/\1,\2/'
これで得られるのは
-
変更前の開始行番号 old_start
-
変更前のハンクの行数 old_lines
-
変更後の開始行番号 new_start
-
変更後のハンクの行数 new_lines
-
old_lines == 0
- 追加
- new_startからnew_linesの数だけ追加マーカー
+
-
new_lines ==0
- 削除
- new_startの位置に削除マーカー
-
-
old_lines > 0 && new_lines > 0
- old_lines == new_lines
- 対応する行の変更
- new_startからnew_linesの数だけ変更マーカー
~
- old_lines > new_lines
- 変更した結果、行数が減った
- new_startからnew_linesの数だけ変更マーカー
- その後、
old_lines - new_linesの数1行 だけ削除マーカー
- old_lines < new_lines
- 変更した結果、行数が増えた
- new_startからnew_linesの数だけ変更マーカー
- その後、new_lines - old_linesの数だけ追加マーカー
- old_lines == new_lines

だいたいできた
cursorcolumnに色がついてないけど

コード
let s:sign_def = 0
function ShowHunk() abort
if !s:sign_def
call SignDef()
set signcolumn=auto
endif
let cmd = 'git --no-pager diff -U0 --no-color --no-ext-diff ' .. expand('%')
\ .. ' | grep ''^@@'' '
\ .. ' | sed -r ''s/[-+]([0-9]+) /\1,1,/g'' '
\ .. ' | sed -r ''s/^[-@ ]*([0-9]+,[0-9]+)[ ,+]+([0-9]+,[0-9]+)[, ].*/\1,\2/'' '
let output = systemlist(cmd)
let bn = bufnr()
for line in output
call s:put_signs(split(line, ','))
endfor
endfunction
highlight HunkSignAdd ctermfg=red guifg=red
highlight HunkSignDel ctermfg=blue guifg=blue
highlight HunkSignUpd ctermfg=magenta guifg=magenta
function SignDef() abort
call sign_define([{
\ 'name' : 'HunkSignAdd',
\ 'culhl' : 'HunkSignAdd',
\ 'text' : '+',
\ }, {
\ 'name' : 'HunkSignDel',
\ 'culhl' : 'HunkSignDel',
\ 'text' : '-',
\ }, {
\ 'name' : 'HunkSignUpd',
\ 'culhl' : 'HunkSignUpd',
\ 'text' : '~',
\ }])
let s:sign_def = 1
endfunction
function s:put_signs(list) abort
let [old_start, old_lines, new_start, new_lines] = a:list
echomsg a:list
let bn = bufnr()
let list = []
if old_lines == 0
let name = 'HunkSignAdd'
let new_end = new_start + new_lines - 1
for lnum in range(new_start, new_end)
call add(list, {'buffer': bn, 'lnum': lnum, 'name': name})
endfor
elseif new_lines == 0
let name = 'HunkSignDel'
call add(list, {'buffer': bn, 'lnum': new_start, 'name': name})
else
let name = 'HunkSignUpd'
let new_end = new_start + min([old_lines, new_lines]) - 1
for lnum in range(new_start, new_end)
call add(list, {'buffer': bn, 'lnum': lnum, 'name': name})
endfor
if old_lines > new_lines
let name = 'HunkSignDel'
call add(list, {'buffer': bn, 'lnum': new_start, 'name': name})
elseif old_lines < new_lines
let name = 'HunkSignAdd'
let line_dif = new_lines - old_lines
for lnum in range(new_end + 1, new_end + line_dif)
call add(list, {'buffer': bn, 'lnum': lnum, 'name': name})
endfor
endif
endif
call sign_placelist(list)
endfunction
なんでculhlがつかないんだろう
→ gitgutterのコードを見たらtexthlが正しいようだ