1
0
mirror of https://github.com/SpaceVim/SpaceVim.git synced 2025-04-14 15:19:12 +08:00

feat(git): implement git.lua

This commit is contained in:
wsdjeg 2023-07-23 23:36:52 +08:00 committed by Eric Wong
parent b785aaa8ed
commit f57c84f138
18 changed files with 1061 additions and 126 deletions

View File

@ -13,125 +13,137 @@
" >
" :Git branch
" <
if has('nvim-0.9.0')
function! git#branch#current(...) abort
let prefix = get(a:000, 0, '')
return luaeval("require('git.command.branch').current(vim.api.nvim_eval('prefix'))")
endfunction
""
" update the branch info manually.
function! git#branch#detect() abort
lua require('git.command.branch').detect()
endfunction
else
let s:JOB = SpaceVim#api#import('job')
let s:STR = SpaceVim#api#import('data#string')
let s:JOB = SpaceVim#api#import('job')
let s:STR = SpaceVim#api#import('data#string')
function! git#branch#run(args) abort
if len(a:args) == 0
call git#branch#manager#open()
return
else
let cmd = ['git', 'branch'] + a:args
endif
call git#logger#debug('git-branch cmd:' . string(cmd))
call s:JOB.start(cmd,
\ {
function! git#branch#run(args) abort
if len(a:args) == 0
call git#branch#manager#open()
return
else
let cmd = ['git', 'branch'] + a:args
endif
call git#logger#debug('git-branch cmd:' . string(cmd))
call s:JOB.start(cmd,
\ {
\ 'on_stderr' : function('s:on_stderr'),
\ 'on_stdout' : function('s:on_stdout'),
\ 'on_exit' : function('s:on_exit'),
\ }
\ )
endfunction
endfunction
function! s:on_stdout(id, data, event) abort
for line in filter(a:data, '!empty(v:val)')
exe 'Echo ' . line
endfor
endfunction
function! s:on_stdout(id, data, event) abort
for line in filter(a:data, '!empty(v:val)')
exe 'Echo ' . line
endfor
endfunction
function! s:on_stderr(id, data, event) abort
for line in filter(a:data, '!empty(v:val)')
exe 'Echoerr ' . line
endfor
endfunction
function! s:on_exit(id, data, event) abort
call git#logger#debug('git-branch exit data:' . string(a:data))
if a:data ==# 0
call git#branch#manager#update()
echo 'done!'
else
echo 'failed!'
endif
endfunction
function! s:on_stderr(id, data, event) abort
for line in filter(a:data, '!empty(v:val)')
exe 'Echoerr ' . line
endfor
endfunction
function! s:on_exit(id, data, event) abort
call git#logger#debug('git-branch exit data:' . string(a:data))
if a:data ==# 0
call git#branch#manager#update()
echo 'done!'
else
echo 'failed!'
endif
endfunction
function! git#branch#complete(ArgLead, CmdLine, CursorPos) abort
function! git#branch#complete(ArgLead, CmdLine, CursorPos) abort
return "%\n" . join(getcompletion(a:ArgLead, 'file'), "\n")
return "%\n" . join(getcompletion(a:ArgLead, 'file'), "\n")
endfunction
endfunction
let s:branch = ''
let s:branch_info = {}
" {
" branch_name : 'xxx',
" last_update_done : 111111, ms
" }
let s:job_pwds = {}
let s:branch = ''
let s:branch_info = {}
" {
" branch_name : 'xxx',
" last_update_done : 111111, ms
" }
let s:job_pwds = {}
function! s:update_branch_name(pwd, ...) abort
let force = get(a:000, 0, 0)
let cmd = 'git rev-parse --abbrev-ref HEAD'
if force || get(get(s:branch_info, a:pwd, {}), 'last_update_done', 0) >= localtime() - 1
let jobid = s:JOB.start(cmd,
\ {
function! s:update_branch_name(pwd, ...) abort
let force = get(a:000, 0, 0)
let cmd = 'git rev-parse --abbrev-ref HEAD'
if force || get(get(s:branch_info, a:pwd, {}), 'last_update_done', 0) >= localtime() - 1
let jobid = s:JOB.start(cmd,
\ {
\ 'on_stdout' : function('s:on_stdout_show_branch'),
\ 'on_exit' : function('s:on_exit_show_branch'),
\ 'cwd' : a:pwd,
\ }
\ )
if jobid > 0
call extend(s:job_pwds, {'jobid' . jobid : a:pwd})
if jobid > 0
call extend(s:job_pwds, {'jobid' . jobid : a:pwd})
endif
endif
endif
endfunction
function! s:on_stdout_show_branch(id, data, event) abort
let b = s:STR.trim(join(a:data, ''))
if !empty(b)
let pwd = get(s:job_pwds, 'jobid' . a:id, '')
if !empty(pwd)
let s:branch_info[pwd] = {
\ 'name' : b,
\ }
endfunction
function! s:on_stdout_show_branch(id, data, event) abort
let b = s:STR.trim(join(a:data, ''))
if !empty(b)
let pwd = get(s:job_pwds, 'jobid' . a:id, '')
if !empty(pwd)
let s:branch_info[pwd] = {
\ 'name' : b,
\ }
endif
endif
endif
endfunction
endfunction
function! s:on_exit_show_branch(id, data, event) abort
let pwd = get(s:job_pwds, 'jobid' . a:id, '')
if !has_key(s:branch_info, pwd) && !empty(pwd)
let s:branch_info[pwd] = {}
endif
if !empty(pwd)
call extend(s:branch_info[pwd], {
\ 'last_update_done' : localtime(),
\ })
endif
" when the pwd is same as current directory, redraw statueline
if pwd == getcwd()
redrawstatus
endif
endfunction
""
" return the current branch info. this function can be used in statusline.
function! git#branch#current(...) abort
let pwd = getcwd()
let branch = get(s:branch_info, pwd, {})
if empty(branch)
call s:update_branch_name(pwd)
endif
let branch_name = get(branch, 'name', '')
let prefix = get(a:000, 0 , '')
if !empty(branch_name)
return ' ' . prefix . ' ' . branch_name . ' '
else
return ''
endif
endfunction
""
" update the branch info manually.
function! git#branch#detect() abort
call s:update_branch_name(getcwd(), 1)
endfunction
function! s:on_exit_show_branch(id, data, event) abort
let pwd = get(s:job_pwds, 'jobid' . a:id, '')
if !has_key(s:branch_info, pwd) && !empty(pwd)
let s:branch_info[pwd] = {}
endif
if !empty(pwd)
call extend(s:branch_info[pwd], {
\ 'last_update_done' : localtime(),
\ })
endif
" when the pwd is same as current directory, redraw statueline
if pwd == getcwd()
redrawstatus
endif
endfunction
""
" return the current branch info. this function can be used in statusline.
function! git#branch#current(...) abort
let pwd = getcwd()
let branch = get(s:branch_info, pwd, {})
if empty(branch)
call s:update_branch_name(pwd)
endif
let branch_name = get(branch, 'name', '')
let prefix = get(a:000, 0 , '')
if !empty(branch_name)
return ' ' . prefix . ' ' . branch_name . ' '
else
return ''
endif
endfunction
""
" update the branch info manually.
function! git#branch#detect() abort
call s:update_branch_name(getcwd(), 1)
endfunction
endif

View File

@ -75,6 +75,8 @@ endfunction
function! s:options() abort
return [
\ '-u',
\ '--set-upstream',
\ '-d', '--delete'
\ ]
endfunction

View File

@ -6,12 +6,11 @@ CONTENTS *git-contents*
1. Introduction..................................................|git-intro|
2. Commands...................................................|git-commands|
1. git-add.....................................................|git-add|
2. git-branch...............................................|git-branch|
3. git-cherry-pick.....................................|git-cherry-pick|
4. git-clean.................................................|git-clean|
5. git-mv.......................................................|git-mv|
6. git-rm.......................................................|git-rm|
7. git-stash.................................................|git-stash|
2. git-cherry-pick.....................................|git-cherry-pick|
3. git-clean.................................................|git-clean|
4. git-mv.......................................................|git-mv|
5. git-rm.......................................................|git-rm|
6. git-stash.................................................|git-stash|
3. Functions.................................................|git-functions|
==============================================================================
@ -35,14 +34,6 @@ file to the index.
:Git add %
<
==============================================================================
GIT-BRANCH *git-branch*
This commands is to open branch manager.
>
:Git branch
<
==============================================================================
GIT-CHERRY-PICK *git-cherry-pick*
@ -88,6 +79,9 @@ This commands is to manage git stash.
==============================================================================
FUNCTIONS *git-functions*
git#branch#detect() *git#branch#detect()*
update the branch info manually.
git#branch#current() *git#branch#current()*
return the current branch info. this function can be used in statusline.

39
bundle/git.vim/lua/git/command/add.lua vendored Normal file
View File

@ -0,0 +1,39 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local function replace_argvs(argvs)
local rst = {}
for _, v in ipairs(argvs) do
if v == '%' then
table.insert(rst, vim.fn.expand('%'))
else
table.insert(rst, v)
end
end
return rst
end
local function on_exit(id, code, single)
log.debug('git-add exit code:' .. code .. ' single:' .. single)
if code == 0 and single == 0 then
nt.notify('stage files done!')
else
nt.notify('stage files failed!')
end
end
function M.run(argv)
log.debug('argv is:' .. vim.inspect(argv))
local cmd = { 'git', 'add' }
for _, v in ipairs(replace_argvs(argv)) do
table.insert(cmd, v)
end
job.start(cmd, { on_exit = on_exit })
end
return M

View File

@ -0,0 +1,73 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local str = require('spacevim.api.data.string')
local branch = ''
local branch_info = {}
local job_pwds = {}
local function on_stdout_show_branch(id, data)
local b = str.trim(table.concat(data, ''))
if #b > 0 then
local pwd = job_pwds['jobid' .. id] or ''
if #pwd > 0 then
branch_info[pwd] = { name = b }
end
end
end
local function on_exit_show_branch(id, code, single)
local pwd = job_pwds['jobid' .. id] or ''
if branch_info[pwd] == nil and #pwd > 0 then
branch_info[pwd] = {}
end
if #pwd > 0 then
branch_info[pwd]['last_update_done'] = vim.fn.localtime()
end
if pwd == vim.fn.getcwd() then
vim.cmd('redrawstatus')
end
end
local function update_branch_name(pwd, ...)
local force = select(1, ...)
local cmd = { 'git', 'rev-parse', '--abbrev-ref', 'HEAD' }
if
force
or vim.fn.get(vim.fn.get(branch_info, pwd, {}), 'last_update_done', 0)
>= vim.fn.localtime() - 1
then
local jobid = job.start(cmd, {
on_stdout = on_stdout_show_branch,
on_exit = on_exit_show_branch,
cwd = pwd,
})
if jobid > 0 then
job_pwds['jobid' .. jobid] = pwd
end
end
end
function M.current(...)
local pwd = vim.fn.getcwd()
local b = branch_info[pwd] or {}
if vim.fn.empty(b) == 1 then
update_branch_name(pwd)
end
local bname = b['name'] or ''
local prefix = select(1, ...) or ''
if #bname > 0 then
return ' ' .. prefix .. ' ' .. bname .. ' '
else
return ''
end
end
function M.detect()
update_branch_name(vim.fn.getcwd(), true)
end
return M

View File

@ -0,0 +1,27 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local branch = require('git.command.branch')
local function on_exit(id, code, single)
log.debug('git-checkout exit code:' .. code .. ' single:' .. single)
if code == 0 and single == 0 then
vim.cmd('silent! checktime')
branch.detect()
nt.notify('checkout done.')
else
nt.notify('checkout failed.', 'WarningMsg')
end
end
function M.run(argv)
local cmd = { 'git', 'checkout' }
for _, v in ipairs(argv) do
table.insert(cmd, v)
end
job.start(cmd, { on_exit = on_exit })
end
return M

View File

@ -0,0 +1,201 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local commit_bufnr = -1
local commit_context = {}
local commit_jobid = -1
local function on_stdout(id, data)
if id ~= commit_jobid then
return
end
for _, d in ipairs(data) do
log.debug(d)
table.insert(commit_context, d)
end
end
local function on_stderr(id, data)
if id ~= commit_jobid then
return
end
for _, d in ipairs(data) do
log.debug(d)
end
end
local function on_exit(id, code, single)
if id ~= commit_jobid then
return
end
if commit_bufnr ~= -1 and vim.api.nvim_buf_is_valid(commit_bufnr) then
vim.api.nvim_buf_set_lines(commit_bufnr, 0, -1, false, commit_context)
end
end
local function BufWriteCmd()
commit_context = vim.fn.getline(1, '$')
vim.bo.modified = false
end
local function QuitPre()
vim.b.git_commit_quitpre = true
end
local function on_commit_exit(id, code, single)
log.debug('git-commit exit code:' .. code .. ' single:' .. single)
if code == 0 and single == 0 then
nt.notify('commit done!')
else
nt.notify('commit failed!' , 'WarningMsg')
end
end
local function filter(t, f)
local rst = {}
for _, v in ipairs(t) do
if f(v) then
table.insert(rst, v)
end
end
return rst
end
local function WinLeave()
if vim.b.git_commit_quitpre then
local cmd = { 'git', 'commit', '-F', '-' }
local id = job.start(cmd, {
on_exit = on_commit_exit,
})
job.send(
id,
filter(commit_context, function(var)
return not string.find(var, '^%s*#')
end)
)
job.stop(id)
end
end
local function openCommitBuffer()
vim.cmd([[
10split git://commit
normal! "_dd
setlocal nobuflisted
setlocal buftype=acwrite
setlocal bufhidden=wipe
setlocal noswapfile
setlocal modifiable
setf git-commit
nnoremap <buffer><silent> q :bd!<CR>
let b:git_commit_quitpre = 0
]])
local bufid = vim.fn.bufnr('%')
local id = vim.api.nvim_create_augroup('git_commit_buffer', { clear = true })
vim.api.nvim_create_autocmd({ 'BufWriteCmd' }, {
group = id,
buffer = bufid,
callback = BufWriteCmd,
})
vim.api.nvim_create_autocmd({ 'QuitPre' }, {
group = id,
buffer = bufid,
callback = QuitPre,
})
vim.api.nvim_create_autocmd({ 'WinLeave' }, {
group = id,
buffer = bufid,
callback = WinLeave,
})
vim.api.nvim_create_autocmd({ 'WinEnter' }, {
group = id,
buffer = bufid,
callback = function()
vim.b.git_commit_quitpre = false
end,
})
return bufid
end
local function index(t, v)
if not t then return -1 end
return vim.fn.index(t, v)
end
function M.run(...)
local a1 = select(1, ...)
if index(a1, '-m') == -1 then
if
vim.api.nvim_buf_is_valid(commit_bufnr)
and vim.fn.index(vim.fn.tabpagebuflist(), commit_bufnr) ~= -1
then
local winnr = vim.fn.bufwinnr(commit_bufnr)
vim.cmd(winnr .. 'wincmd w')
else
commit_bufnr = openCommitBuffer()
end
else
commit_bufnr = -1
end
local cmd
commit_context = {}
if vim.fn.empty(a1) == 1 then
cmd = {
'git',
'--no-pager',
'-c',
'core.editor=cat',
'-c',
'color.status=always',
'-C',
vim.fn.expand(vim.fn.getcwd(), ':p'),
'commit',
'--edit',
}
elseif index(a1, '-m') ~= -1 then
cmd = {
'git',
'--no-pager',
'-c',
'core.editor=cat',
'-c',
'color.status=always',
'-C',
vim.fn.expand(vim.fn.getcwd(), ':p'),
'commit',
}
for _, v in ipairs(a1) do
table.insert(cmd, v)
end
else
cmd = {
'git',
'--no-pager',
'-c',
'core.editor=cat',
'-c',
'color.status=always',
'-C',
vim.fn.expand(vim.fn.getcwd(), ':p'),
'commit',
}
for _, v in ipairs(a1) do
table.insert(cmd, v)
end
end
commit_jobid = job.start(cmd, {
on_stdout = on_stdout,
on_exit = on_exit,
on_stderr = on_stderr,
})
end
return M

88
bundle/git.vim/lua/git/command/diff.lua vendored Normal file
View File

@ -0,0 +1,88 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local diff_lines = {}
local jobid = -1
local bufnr = -1
local function on_stdout(id, data)
if id ~= jobid then
return
end
for _, v in ipairs(data) do
log.debug('git-diff stdout:' .. v)
table.insert(diff_lines, v)
end
end
local function on_stderr(id, data)
if id ~= jobid then
return
end
for _, v in ipairs(data) do
log.debug('git-diff stderr:' .. v)
table.insert(diff_lines, v)
end
end
local function close_diff_win()
if vim.fn.winnr('$') > 1 then
vim.cmd('close')
else
vim.cmd('bd!')
end
end
local function open_diff_buffer()
if vim.api.nvim_buf_is_valid(bufnr) then
return bufnr
end
vim.cmd([[
exe printf('%s git://diff', get(g:, 'git_diff_position', '10split'))
normal! "_dd
setl nobuflisted
setl nomodifiable
setl nonumber norelativenumber
setl buftype=nofile
setl bufhidden=wipe
setf git-diff
setl syntax=diff
]])
bufnr = vim.fn.bufnr()
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'q', '', {
callback = close_diff_win,
})
return bufnr
end
local function on_exit(id, code, single)
log.debug('git-diff exit code:' .. code .. ' single:' .. single)
bufnr = open_diff_buffer()
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, diff_lines)
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
end
function M.run(argv)
local cmd = { 'git', 'diff' }
if #argv == 1 and argv[1] == '%' then
table.insert(cmd, vim.fn.expand('%'))
else
for _, v in ipairs(argv) do
table.insert(cmd, v)
end
end
diff_lines = {}
log.debug('git-dff cmd:' .. vim.inspect(cmd))
jobid = job.start(cmd, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
end
return M

155
bundle/git.vim/lua/git/command/log.lua vendored Normal file
View File

@ -0,0 +1,155 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local str = require('spacevim.api.data.string')
local git_log_pretty = 'tformat:%Cred%h%Creset - %s %Cgreen(%an %ad)%Creset'
local bufnr = -1
local jobid = -1
local commit_bufnr = -1
local show_lines = {}
local function close_commit_win()
if vim.api.nvim_buf_is_valid(commit_bufnr) then
vim.cmd('bd ' .. commit_bufnr)
end
end
local function close_log_win()
local ok = pcall(function()
vim.cmd('bp')
end)
if not ok then
vim.cmd('bd')
end
end
local function openShowCommitBuffer()
vim.cmd([[
rightbelow vsplit git://show_commit
normal! "_dd
setl nobuflisted
setl nomodifiable
setl nonumber norelativenumber
setl buftype=nofile
setl bufhidden=wipe
setf git-diff
setl syntax=diff
nnoremap <buffer><silent> q :q<CR>
]])
return vim.fn.bufnr()
end
local function on_show_stdout(id, data)
for _,v in ipairs(data) do
log.debug('git-show stdout:' .. v)
table.insert(show_lines, v)
end
end
local function on_show_stderr(id, data)
for _,v in ipairs(data) do
log.debug('git-show stderr:' .. v)
table.insert(show_lines, v)
end
end
local function on_show_exit(id, code, single)
log.debug('git-show exit code:' .. code .. ' single:' .. single)
vim.api.nvim_buf_set_option(commit_bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(commit_bufnr, 0, -1, false, show_lines)
vim.api.nvim_buf_set_option(commit_bufnr, 'modifiable', false)
end
local function show_commit()
local commit = vim.fn.matchstr(vim.fn.getline('.'), [[^[* |\\\/_]\+\zs[a-z0-9A-Z]\+]])
if vim.fn.empty(commit) == 1 then
return
end
if not vim.api.nvim_buf_is_valid(commit_bufnr) then
commit_bufnr = openShowCommitBuffer()
end
local cmd = { 'git', 'show', commit }
show_lines = {}
job.start(cmd, {
on_stdout = on_show_stdout,
on_stderr = on_show_stderr,
on_exit = on_show_exit,
})
end
local function openLogBuffer()
vim.cmd([[
edit git://log
normal! "_dd
setl nobuflisted
setl nomodifiable
setl nonumber norelativenumber
setl buftype=nofile
setl bufhidden=wipe
setf git-log
]])
-- nnoremap <buffer><silent> <Cr> :call <SID>show_commit()<CR>
-- nnoremap <buffer><silent> q :call <SID>close_log_win()<CR>
bufnr = vim.fn.bufnr()
vim.api.nvim_buf_set_keymap(bufnr, 'n', 'q', '', {
callback = close_log_win,
})
vim.api.nvim_buf_set_keymap(bufnr, 'n', '<Cr>', '', {
callback = show_commit,
})
return bufnr
end
local function on_stdout(id, data)
if id ~= jobid then
return
end
if not vim.api.nvim_buf_is_valid(bufnr) then
bufnr = openLogBuffer()
end
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
if vim.api.nvim_buf_line_count(bufnr) == 1 and vim.fn.getline('$') == '' then
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, data)
else
vim.api.nvim_buf_set_lines(bufnr, -1, -1, false, data)
end
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
end
local function on_stderr(id, data)
nt.notify(data, 'WarningMsg')
end
local function on_exit(id, code, single)
log.debug('git-log exit code:' .. code .. ' single:' .. single)
end
function M.run(argv)
local cmd = { 'git', 'log', '--graph', '--date=relative', '--pretty=' .. git_log_pretty }
if #argv == 1 and argv[1] == '%' then
table.insert(cmd, vim.fn.expand('%'))
else
for _, v in ipairs(argv) do
table.insert(cmd, v)
end
end
log.debug('git-log cmd:' .. vim.inspect(cmd))
if vim.api.nvim_buf_is_valid(bufnr) then
vim.api.nvim_buf_set_option(bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, {})
vim.api.nvim_buf_set_option(bufnr, 'modifiable', false)
end
jobid = job.start(cmd, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
end
return M

View File

@ -0,0 +1,62 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local conflict_files = {}
local function on_stdout(id, data)
for _, v in ipairs(data) do
log.debug('git-merge stdout:' .. v)
if vim.startswith(v, 'CONFLICT (content): Merge conflict in') then
table.insert(conflict_files, string.sub(v, 39))
end
end
end
local function on_stderr(id, data)
for _, v in ipairs(data) do
log.debug('git-merge stderr:' .. v)
end
end
local function list_conflict_files()
if #conflict_files > 0 then
local rst = {}
for _, file in ipairs(conflict_files) do
table.insert(rst, {
filename = vim.fn.fnamemodify(file, ':p'),
})
end
vim.fn.setqflist({}, 'r', { title = ' ' .. #rst .. ' items', items = rst })
vim.cmd('botright copen')
end
end
local function on_exit(id, code, single)
log.debug('git-merge exit code:' .. code .. ' single:' .. single)
if code == 0 and single == 0 then
nt.notify('merged done!')
else
list_conflict_files()
nt.notify('merged failed!')
end
end
function M.run(argv)
local cmd = { 'git', 'merge' }
if #argv == 0 then
return
else
for _, v in ipairs(argv) do
table.insert(cmd, v)
end
end
job.start(cmd, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
end
return M

66
bundle/git.vim/lua/git/command/pull.lua vendored Normal file
View File

@ -0,0 +1,66 @@
--=============================================================================
-- pull.lua --- Git pull command
-- Copyright (c) 2016-2023 Wang Shidong & Contributors
-- Author: Wang Shidong < wsdjeg@outlook.com >
-- URL: https://spacevim.org
-- License: GPLv3
--=============================================================================
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local conflict_files = {}
local function on_stdout(id, data)
for _, v in ipairs(data) do
log.debug('git-pull stdout:' .. v)
if vim.startswith(v, 'CONFLICT (content): Merge conflict in') then
table.insert(conflict_files, string.sub(v, 39))
end
end
end
local function on_stderr(id, data)
for _, v in ipairs(data) do
log.debug('git-pull stderr:' .. v)
end
end
local function list_conflict_files()
if #conflict_files > 0 then
local rst = {}
for _, file in ipairs(conflict_files) do
table.insert(rst, {
filename = vim.fn.fnamemodify(file, ':p'),
})
end
vim.fn.setqflist({}, 'r', { title = ' ' .. #rst .. ' items', items = rst })
vim.cmd('botright copen')
end
end
local function on_exit(id, code, single)
log.debug('git-pull exit code:' .. code .. ' single:' .. single)
if code == 0 and single == 0 then
nt.notify('pulled done!')
else
list_conflict_files()
nt.notify('pulled failed!')
end
end
function M.run(argv)
local cmd = { 'git', 'pull' }
for _, v in ipairs(argv) do
table.insert(cmd, v)
end
log.debug('git-pull cmd:' .. vim.inspect(cmd))
job.start(cmd, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
end
return M

76
bundle/git.vim/lua/git/command/push.lua vendored Normal file
View File

@ -0,0 +1,76 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local push_jobid = -1
local stderr_data = {}
local function on_stdout(id, data)
if id ~= push_jobid then
return
end
for _, line in pairs(data) do
nt.notify_max_width = vim.fn.max({ vim.fn.strwidth(line) + 5, nt.notify_max_width })
nt.notify(line)
end
end
local function on_stderr(id, data)
if id ~= push_jobid then
return
end
for _, line in pairs(data) do
table.insert(stderr_data, line)
end
end
local function on_exit(id, code, single)
log.debug('push code:' .. code .. ' single:' .. single)
if id ~= push_jobid then
return
end
if code == 0 and single == 0 then
for _, line in ipairs(stderr_data) do
nt.notify(line)
end
else
for _, line in ipairs(stderr_data) do
nt.notify(line, 'WarningMsg')
end
end
push_jobid = -1
end
function M.run(argv)
if push_jobid ~= -1 then
nt.notify('previous push not finished')
end
nt.notify_max_width = vim.fn.float2nr(vim.o.columns * 0.3)
stderr_data = {}
local cmd = { 'git', 'push' }
if argv then
for _, v in ipairs(argv) do
table.insert(cmd, v)
end
end
log.debug(vim.inspect(cmd))
push_jobid = job.start(cmd, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
if push_jobid == -1 then
nt.notify('`git` is not executable')
end
end
function M.complete(ArgLead, CmdLine, CursorPos) end
return M

View File

@ -0,0 +1,77 @@
local M = {}
local job = require('spacevim.api.job')
local nt = require('spacevim.api.notify')
local log = require('git.log')
local status_bufnr = -1
local lines = {}
local function close_status_window()
if vim.fn.winnr('$') > 1 then
vim.cmd('close')
else
vim.cmd('bd!')
end
end
local function openStatusBuffer()
vim.cmd([[
10split git://status
normal! "_dd
setl nobuflisted
setl nomodifiable
setl nonumber norelativenumber
setl buftype=nofile
setl bufhidden=wipe
setf git-status
]])
status_bufnr = vim.fn.bufnr()
-- nnoremap <buffer><silent> q :call <SID>close_status_window()<CR>
vim.api.nvim_buf_set_keymap(status_bufnr, 'n', 'q', '', {
callback = close_status_window,
})
return status_bufnr
end
local function on_stdout(id, data)
for _, v in ipairs(data) do
log.debug('git-status stdout:' .. v)
table.insert(lines, v)
end
end
local function on_stderr(id, data)
for _, v in ipairs(data) do
log.debug('git-status stderr:' .. v)
table.insert(lines, v)
end
end
local function on_exit(id, code, single)
log.debug('git-status exit code:' .. code .. ' single:' .. single)
vim.api.nvim_buf_set_option(status_bufnr, 'modifiable', true)
vim.api.nvim_buf_set_lines(status_bufnr, 0, -1, false, lines)
vim.api.nvim_buf_set_option(status_bufnr, 'modifiable', false)
end
function M.run(...)
if
vim.api.nvim_buf_is_valid(status_bufnr)
and vim.fn.index(vim.fn.tabpagebuflist(), status_bufnr) ~= -1
then
local winnr = vim.fn.bufwinnr(status_bufnr)
vim.cmd(winnr .. 'wincmd w')
else
status_bufnr = openStatusBuffer()
end
local cmd = { 'git', 'status', '.' }
lines = {}
job.start(cmd, {
on_stdout = on_stdout,
on_stderr = on_stderr,
on_exit = on_exit,
})
end
return M

15
bundle/git.vim/lua/git/init.lua vendored Normal file
View File

@ -0,0 +1,15 @@
local M = {}
local log = require('git.log')
function M.run(command, ...)
local argv = {...}
local ok, cmd = pcall(require, 'git.command.' .. command)
if ok and type(cmd.run) == "function" then
cmd.run(argv)
else
error(cmd)
end
end
return M

10
bundle/git.vim/lua/git/log.lua vendored Normal file
View File

@ -0,0 +1,10 @@
local logger = require('spacevim.logger').derive('git')
return {
info = logger.info,
warn = logger.warn,
debug = logger.debug
}

View File

@ -8,8 +8,13 @@
let g:loaded_git = 1
""
" Run git command asynchronously
command! -nargs=+ -complete=custom,git#complete Git call git#run(<f-args>)
if has('nvim-0.9.0')
command! -nargs=+ -complete=custom,git#complete Git lua require('git').run(<f-args>)
else
""
" Run git command asynchronously
command! -nargs=+ -complete=custom,git#complete Git call git#run(<f-args>)
endif
call SpaceVim#plugins#projectmanager#reg_callback(function('git#branch#detect'))

View File

@ -10,9 +10,31 @@ local M = {}
local uv = vim.loop
local logger = require('spacevim.logger').derive('job')
local _jobs = {}
local _jobid = 0
local function buffered_data(eof, data)
data = data:gsub('\r', '')
local std_data = vim.split(data, '\n')
if #std_data > 1 and std_data[#std_data] == '' then
std_data[1] = eof .. std_data[1]
table.remove(std_data, #std_data)
eof = ''
elseif #std_data > 1 then
std_data[1] = eof .. std_data[1]
eof = std_data[#std_data]
table.remove(std_data, #std_data)
elseif #std_data == 1 and std_data[1] == '' and eof ~= '' then
std_data = { eof }
eof = ''
elseif #std_data == 1 and std_data[#std_data] ~= '' then
eof = std_data[#std_data]
end
return eof, std_data
end
local function new_job_obj(id, handle, opt, state)
local jobobj = {
id = id,
@ -123,25 +145,32 @@ function M.start(cmd, opts)
stderr = stderr,
stdin = stdin,
pid = pid,
stderr_eof = '',
stdout_eof = '',
})
-- logger.debug(vim.inspect(_jobs['jobid_' .. _jobid]))
if opts.on_stdout then
-- define on_stdout function based on stdout's nparams
local nparams = debug.getinfo(opts.on_stdout).nparams
if nparams == 2 then
uv.read_start(stdout, function(err, data)
if data then
data = data:gsub('\r', '')
local stdout_data
_jobs['jobid_' .. current_id].state.stdout_eof, stdout_data =
buffered_data(_jobs['jobid_' .. current_id].state.stdout_eof, data)
vim.schedule(function()
opts.on_stdout(current_id, vim.split(data, '\n'))
opts.on_stdout(current_id, stdout_data)
end)
end
end)
else
uv.read_start(stdout, function(err, data)
if data then
data = data:gsub('\r', '')
local stdout_data
_jobs['jobid_' .. current_id].state.stdout_eof, stdout_data =
buffered_data(_jobs['jobid_' .. current_id].state.stdout_eof, data)
vim.schedule(function()
opts.on_stdout(current_id, vim.split(data, '\n'), 'stdout')
opts.on_stdout(current_id, stdout_data, 'stdout')
end)
end
end)
@ -153,18 +182,22 @@ function M.start(cmd, opts)
if nparams == 2 then
uv.read_start(stderr, function(err, data)
if data then
data = data:gsub('\r', '')
local stderr_data
_jobs['jobid_' .. current_id].state.stderr_eof, stderr_data =
buffered_data(_jobs['jobid_' .. current_id].state.stderr_eof, data)
vim.schedule(function()
opts.on_stderr(current_id, vim.split(data, '\n'))
opts.on_stderr(current_id, stderr_data)
end)
end
end)
else
uv.read_start(stderr, function(err, data)
if data then
data = data:gsub('\r', '')
local stderr_data
_jobs['jobid_' .. current_id].state.stderr_eof, stderr_data =
buffered_data(_jobs['jobid_' .. current_id].state.stderr_eof, data)
vim.schedule(function()
opts.on_stderr(current_id, vim.split(data, '\n'), 'stderr')
opts.on_stderr(current_id, stderr_data, 'stderr')
end)
end
end)

View File

@ -41,8 +41,8 @@ M.notification_color = 'Normal'
---@param msg string|table<string> notification messages
---@param opts table notify options
--- - title: string, the notify title
function M.notify(msg, opts) -- {{{
opts = opts or {}
function M.notify(msg, ...) -- {{{
local opts = select(1, ...) or {}
if M.is_list_of_string(msg) then
extend(M.message, msg)
elseif type(msg) == 'string' then
@ -81,7 +81,7 @@ end
local function msg_real_len(msg)
local l = 0
for _, m in pairs(msg) do
l = l + vim.fn.len(vim.fn.split(m, '\n'))
l = l + #vim.split(m, '\n')
end
return l
end