diff --git a/README.md b/README.md index c662ce3..46c4378 100644 --- a/README.md +++ b/README.md @@ -114,6 +114,12 @@ If committia.vim is in multi-columns mode, specifies the width of the edit windo Minimum height of a status window. +### `g:committia#git#use_verbose` (default: `0`) + +If the value is `1`, extract the diff and status from `COMMIT_EDITMSG` when the +`verbose` option is used with `git commit`, e.g. `git commit --verbose` or `git +config --global commit.verbose=true`. + ## Future - Cooperate with [vim-fugitive](https://github.com/tpope/vim-fugitive). diff --git a/autoload/committia/git.vim b/autoload/committia/git.vim index eabb4c5..69fa072 100644 --- a/autoload/committia/git.vim +++ b/autoload/committia/git.vim @@ -14,6 +14,10 @@ let g:committia#git#cmd = get(g:, 'committia#git#cmd', 'git') let g:committia#git#diff_cmd = get(g:, 'committia#git#diff_cmd', 'diff -u --cached --no-color --no-ext-diff') let g:committia#git#status_cmd = get(g:, 'committia#git#status_cmd', '-c color.status=false status -b') +" Experimental: extract diff and status from commit message template when +" using git commit --verbose, particularly useful when amending commits +let g:committia#git#use_verbose = get(g:, 'committia#git#use_verbose', 0) + try silent call vimproc#version() @@ -159,6 +163,13 @@ function! s:unset_index_file() abort endfunction function! committia#git#diff() abort + if g:committia#git#use_verbose + let line = s:diff_start_line() + if line > 0 + return getline(line, '$') + endif + endif + let diff = s:execute_git(g:committia#git#diff_cmd) if diff !=# '' @@ -170,14 +181,31 @@ function! committia#git#diff() abort return [''] endif + " Fugly hack to tell committia#git#status() to get the status from the + " commit message template too, otherwise status may not match with diff + " Could be removed if g:committia#git#use_verbose was enabled by default + let s:use_verbose_status = 1 + return getline(line, '$') endfunction function! s:diff_start_line() abort - let re_start_diff_line = '# -\+ >8 -\+\n\%(#.*\n\)\+diff --git' + let re_start_diff_line = '^[#;@!$%^&|:] -\+ >8 -\+\n\%([#;@!$%^&|:].*\n\)\+diff --git' return search(re_start_diff_line, 'cenW') endfunction +function! s:comment_char() abort + let line = s:diff_start_line() + if line == 0 + let line = line('$') + 1 + endif + if getline(line - 1) =~# '^[#;@!$%^&|:]' + return getline(line - 1)[0] + else + return '#' + endif +endfunction + function! committia#git#status() abort try let status = s:execute_git(g:committia#git#status_cmd) @@ -185,7 +213,30 @@ function! committia#git#status() abort " Leave status window empty when git-dir or work-tree not found return '' endtry - return map(split(status, '\n'), 'substitute(v:val, "^", "# ", "g")') + if g:committia#git#use_verbose || exists('s:use_verbose_status') + if exists('s:use_verbose_status') + unlet s:use_verbose_status + end + let scissors_line = search('^[#;@!$%^&|:] -\+ >8 -\+\n', 'cenW') + if scissors_line > 1 + " Localisation hack, find the start of the status in the commit + " message template using the first line of output from `git status` + " Search backwards to avoid match in message, and start search at + " scissors line to avoid potential match in diff, unlikely, but... + let status_start = scissors_line + let re_status_start = '^[#;@!$%^&|:] ' . split(status, '\n')[0] + while status_start > 1 + if getline(status_start - 1) =~# re_status_start + break + endif + let status_start -= 1 + endwhile + if status_start > 1 && status_start < scissors_line + return getline(status_start, scissors_line-1) + endif + endif + endif + return map(split(status, '\n'), 'substitute(v:val, "^", s:comment_char() . " ", "g")') endfunction function! committia#git#end_of_edit_region_line() abort @@ -197,7 +248,7 @@ function! committia#git#end_of_edit_region_line() abort let line = line('$') + 1 endif while line > 1 - if stridx(getline(line - 1), '#') != 0 + if stridx(getline(line - 1), s:comment_char()) != 0 break endif let line -= 1