From 6358c2a435f2eb86822172bea2a33131b121a391 Mon Sep 17 00:00:00 2001 From: Eric Wong Date: Fri, 13 Dec 2024 00:56:32 +0800 Subject: [PATCH] feat(git.vim): complete git push command --- bundle/git.vim/autoload/git/push.vim | 184 ++++++++++++------------ bundle/git.vim/lua/git/command/push.lua | 39 ++++- 2 files changed, 133 insertions(+), 90 deletions(-) diff --git a/bundle/git.vim/autoload/git/push.vim b/bundle/git.vim/autoload/git/push.vim index 5ab60a53c..27e628441 100644 --- a/bundle/git.vim/autoload/git/push.vim +++ b/bundle/git.vim/autoload/git/push.vim @@ -4,104 +4,110 @@ " Author: Wang Shidong < wsdjeg@outlook.com > " License: GPLv3 "============================================================================= +if has('nvim-0.9.0') + function! git#push#complete(ArgLead, CmdLine, CursorPos) abort + return luaeval('require("git.command.push").complete(vim.api.nvim_eval("a:ArgLead"), vim.api.nvim_eval("a:CmdLine"), vim.api.nvim_eval("a:CursorPos"))') + endfunction +else -let s:JOB = SpaceVim#api#import('job') -let s:NOTI = SpaceVim#api#import('notify') + let s:JOB = SpaceVim#api#import('job') + let s:NOTI = SpaceVim#api#import('notify') -let s:push_jobid = 0 - -function! git#push#run(...) abort - - if s:push_jobid != 0 - call s:NOTI.notify('previous push not finished') - return - endif - - let s:NOTI.notify_max_width = float2nr( &columns * 0.3) - let s:std_data = { - \ 'stderr' : [], - \ 'stdout' : [], - \ } - let cmd = ['git', 'push'] - if len(a:1) > 0 - let cmd += a:1 - endif - let s:push_jobid = s:JOB.start(cmd, { - \ 'on_stdout' : function('s:on_stdout'), - \ 'on_stderr' : function('s:on_stderr'), - \ 'on_exit' : function('s:on_exit'), - \ } - \ ) - - if s:push_jobid == -1 - call s:NOTI.notify('`git` is not executable') - let s:push_jobid = 0 - endif - -endfunction - -function! s:on_exit(id, data, event) abort - if a:data != 0 - for line in s:std_data.stderr - let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width]) - call s:NOTI.notify(line, 'WarningMsg') - endfor - else - for line in s:std_data.stderr - let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width]) - call s:NOTI.notify(line) - endfor - endif let s:push_jobid = 0 -endfunction + + function! git#push#run(...) abort + + if s:push_jobid != 0 + call s:NOTI.notify('previous push not finished') + return + endif + + let s:NOTI.notify_max_width = float2nr( &columns * 0.3) + let s:std_data = { + \ 'stderr' : [], + \ 'stdout' : [], + \ } + let cmd = ['git', 'push'] + if len(a:1) > 0 + let cmd += a:1 + endif + let s:push_jobid = s:JOB.start(cmd, { + \ 'on_stdout' : function('s:on_stdout'), + \ 'on_stderr' : function('s:on_stderr'), + \ 'on_exit' : function('s:on_exit'), + \ } + \ ) + + if s:push_jobid == -1 + call s:NOTI.notify('`git` is not executable') + let s:push_jobid = 0 + endif + + endfunction + + function! s:on_exit(id, data, event) abort + if a:data != 0 + for line in s:std_data.stderr + let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width]) + call s:NOTI.notify(line, 'WarningMsg') + endfor + else + for line in s:std_data.stderr + let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width]) + call s:NOTI.notify(line) + endfor + endif + let s:push_jobid = 0 + endfunction -function! s:on_stdout(id, data, event) abort - for line in filter(a:data, '!empty(v:val) && v:val !~# "^remote:"') - let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width]) - call s:NOTI.notify(line, 'Normal') - endfor -endfunction + function! s:on_stdout(id, data, event) abort + for line in filter(a:data, '!empty(v:val) && v:val !~# "^remote:"') + let s:NOTI.notify_max_width = max([strwidth(line) + 5, s:NOTI.notify_max_width]) + call s:NOTI.notify(line, 'Normal') + endfor + endfunction -" https://stackoverflow.com/questions/57016157/how-to-stop-git-from-writing-non-errors-to-stderr -" -" why git push normal info to stderr + " https://stackoverflow.com/questions/57016157/how-to-stop-git-from-writing-non-errors-to-stderr + " + " why git push normal info to stderr -function! s:on_stderr(id, data, event) abort - call extend(s:std_data.stderr, filter(a:data, '!empty(v:val) && v:val !~# "^remote:"')) -endfunction + function! s:on_stderr(id, data, event) abort + call extend(s:std_data.stderr, filter(a:data, '!empty(v:val) && v:val !~# "^remote:"')) + endfunction -function! s:options() abort - return [ - \ '-u', - \ '--set-upstream', - \ '-d', '--delete' - \ ] -endfunction + function! s:options() abort + return [ + \ '-u', + \ '--set-upstream', + \ '-d', '--delete' + \ ] + endfunction -function! git#push#complete(ArgLead, CmdLine, CursorPos) abort - let str = a:CmdLine[:a:CursorPos-1] - if str =~# '^Git\s\+push\s\+-$' - return join(s:options(), "\n") - elseif str =~# '^Git\s\+push\s\+[^ ]*$' || str =~# '^Git\s\+push\s\+-u\s\+[^ ]*$' - return join(s:remotes(), "\n") - else - let remote = matchstr(str, '\(Git\s\+push\s\+\)\@<=[^ ]*') - return s:remote_branch(remote) - endif -endfunction + function! git#push#complete(ArgLead, CmdLine, CursorPos) abort + let str = a:CmdLine[:a:CursorPos-1] + if str =~# '^Git\s\+push\s\+-$' + return join(s:options(), "\n") + elseif str =~# '^Git\s\+push\s\+[^ ]*$' || str =~# '^Git\s\+push\s\+-u\s\+[^ ]*$' + return join(s:remotes(), "\n") + else + let remote = matchstr(str, '\(Git\s\+push\s\+\)\@<=[^ ]*') + return s:remote_branch(remote) + endif + endfunction -function! s:remotes() abort - return map(systemlist('git remote'), 'trim(v:val)') -endfunction + function! s:remotes() abort + return map(systemlist('git remote'), 'trim(v:val)') + endfunction -function! s:remote_branch(remote) abort - let branchs = systemlist('git branch -a') - if v:shell_error - return '' - else - let branchs = join(map(filter(branchs, 'v:val =~ "\s*remotes/" . a:remote . "/[^ ]*$"'), 'trim(v:val)[len(a:remote) + 9:]'), "\n") - return branchs - endif -endfunction + function! s:remote_branch(remote) abort + let branchs = systemlist('git branch -a') + if v:shell_error + return '' + else + let branchs = join(map(filter(branchs, 'v:val =~ "\s*remotes/" . a:remote . "/[^ ]*$"'), 'trim(v:val)[len(a:remote) + 9:]'), "\n") + return branchs + endif + endfunction +endif diff --git a/bundle/git.vim/lua/git/command/push.lua b/bundle/git.vim/lua/git/command/push.lua index cda6cb62e..135366293 100644 --- a/bundle/git.vim/lua/git/command/push.lua +++ b/bundle/git.vim/lua/git/command/push.lua @@ -71,6 +71,43 @@ function M.run(argv) end end -function M.complete(ArgLead, CmdLine, CursorPos) end +local options = { '-u', '--set-upstream', '-d', '--delete' } + +local function remotes() + return vim.tbl_map(function(t) + return vim.fn.trim(t) + end, vim.fn.systemlist('git remote')) +end + +local function remote_branch(r) + local branchs = vim.fn.systemlist('git branch -a') + if vim.v.shell_error then + return '' + else + branchs = table.concat( + vim.fn.map( + vim.fn.filter(branchs, [[v:val =~ "\s*remotes/" . a:remote . "/[^ ]*$"]]), + 'trim(v:val)[len(a:remote) + 9:]' + ), + '\n' + ) + return branchs + end +end + +function M.complete(ArgLead, CmdLine, CursorPos) + local str = string.sub(CmdLine, 1, CursorPos) + if vim.regex([[^Git\s\+push\s\+-$]]):match_str(str) then + return table.concat(options, '\n') + elseif + vim.regex([[^Git\s\+push\s\+[^ ]*$]]):match_str(str) + or vim.regex([[^Git\s\+push\s\+-u\s\+[^ ]*$]]):match_str(str) + then + return table.concat(remotes(), '\n') + else + local remote = vim.fn.matchstr(str, [[\(Git\s\+push\s\+\)\@<=[^ ]*]]) + return remote_branch(remote) + end +end return M