From 28f17e54691def71d5f0bf3aa448fe5bd68b70de Mon Sep 17 00:00:00 2001 From: Fabian Wermelinger Date: Mon, 2 Dec 2024 21:41:01 +0100 Subject: [PATCH] Add support for multi-file edits Git send-email by default uses multi-file edit mode (sendemail.multiEdit) when more than one patch file requires editing an associated email message and/or cover-letters. Multi edit mode spawns one editor instance with multiple files in argument list. This behavior is supported by creating multiple splits for a running vim instance when `:G send-email` is called. When the user sets sendemail.multiEdit to false in the local or global config, if multiple files need editing then they are processed sequentially in a single split at a time. Closes #2352 --- autoload/fugitive.vim | 69 ++++++++++++++++++++++++++----------------- 1 file changed, 42 insertions(+), 27 deletions(-) diff --git a/autoload/fugitive.vim b/autoload/fugitive.vim index 5e6910286..125f3d51a 100644 --- a/autoload/fugitive.vim +++ b/autoload/fugitive.vim @@ -3443,33 +3443,37 @@ function! s:RunEdit(state, tmp, job) abort endif call remove(a:state, 'request') let sentinel = a:state.file . '.edit' - let file = FugitiveVimPath(readfile(sentinel, '', 1)[0]) - try - if !&equalalways && a:state.mods !~# '\<\d*tab\>' && 3 > (a:state.mods =~# '\', '-tab', 'g') 'keepalt split' s:fnameescape(file) - finally - if exists('l:noequalalways') - setglobal noequalalways - endif - endtry - set bufhidden=wipe - call s:InitializeBuffer(a:state) - let bufnr = bufnr('') - let s:edit_jobs[bufnr] = [a:state, a:tmp, a:job, sentinel] - call fugitive#DidChange(a:state.git_dir) - if bufnr == bufnr('') && !exists('g:fugitive_event') + let files = readfile(sentinel, '') + call writefile([len(files)], sentinel) + for file in reverse(files) + let file = FugitiveVimPath(file) try - let g:fugitive_event = a:state.git_dir - let g:fugitive_result = a:state - exe s:DoAutocmd('User FugitiveEditor') + if !&equalalways && a:state.mods !~# '\<\d*tab\>' && 3 > (a:state.mods =~# '\', '-tab', 'g') 'keepalt split' s:fnameescape(file) finally - unlet! g:fugitive_event g:fugitive_result + if exists('l:noequalalways') + setglobal noequalalways + endif endtry - endif + set bufhidden=wipe + call s:InitializeBuffer(a:state) + let bufnr = bufnr('') + let s:edit_jobs[bufnr] = [a:state, a:tmp, a:job, sentinel] + call fugitive#DidChange(a:state.git_dir) + if bufnr == bufnr('') && !exists('g:fugitive_event') + try + let g:fugitive_event = a:state.git_dir + let g:fugitive_result = a:state + exe s:DoAutocmd('User FugitiveEditor') + finally + unlet! g:fugitive_event g:fugitive_result + endtry + endif + endfor return 1 endfunction @@ -3623,6 +3627,9 @@ if !exists('s:edit_jobs') endif function! s:RunWait(state, tmp, job, ...) abort if a:0 && filereadable(a:1) + if a:0 > 1 && a:2 > 0 + return '' + endif call delete(a:1) endif try @@ -3725,8 +3732,16 @@ function! s:RunBufDelete(bufnr) abort endif if has_key(s:edit_jobs, a:bufnr) | call add(s:resume_queue, remove(s:edit_jobs, a:bufnr)) - call feedkeys("\\:redraw!|call delete(" . string(s:resume_queue[-1][0].file . '.edit') . - \ ")|call fugitive#Resume()|checktime\r", 'n') + let sentinel = s:resume_queue[-1][0].file . '.edit' + let active_buffers = str2nr(readfile(sentinel, '', 1)[0]) - 1 + call add(s:resume_queue[-1], active_buffers) + if active_buffers < 1 + call feedkeys("\\:redraw!|call delete(" . string(sentinel) . + \ ")|call fugitive#Resume()|checktime\r", 'n') + else + call writefile([active_buffers], sentinel) + call fugitive#Resume() + endif endif endfunction @@ -3940,7 +3955,7 @@ function! fugitive#Command(line1, line2, range, bang, mods, arg, ...) abort let env.FUGITIVE = state.file let editor = 'sh ' . s:TempScript( \ '[ -f "$FUGITIVE.exit" ] && cat "$FUGITIVE.exit" >&2 && exit 1', - \ 'echo "$1" > "$FUGITIVE.edit"', + \ 'for arg; do echo "$arg" >> "$FUGITIVE.edit"; done', \ 'printf "\033]51;fugitive:edit\007" >&2', \ 'while [ -f "$FUGITIVE.edit" -a ! -f "$FUGITIVE.exit" ]; do sleep 0.05 2>/dev/null || sleep 1; done', \ 'exit 0')