Skip to content

feat: add async support. split code to separate files #9

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
dirvish_git.log
44 changes: 44 additions & 0 deletions autoload/dirvish_git.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
let dirvish_git#sep = exists('+shellslash') && !&shellslash ? '\' : '/'
let dirvish_git#escape_chars = '.#~'. dirvish_git#sep


function! dirvish_git#jump_to_next_file() abort
if len(b:git_files) <=? 0
return
endif

let l:current_line = line('.')
let l:git_files_line_number = sort(keys(b:git_files), 'N')

for l:line in l:git_files_line_number
if l:line > l:current_line
return cursor(l:line, 0)
endif
endfor

return cursor(l:git_files_line_number[0], 0)
endfunction


function! dirvish_git#jump_to_prev_file() abort
if len(b:git_files) <=? 0
return
endif

let l:current_line = line('.')
let l:git_files_line_number = reverse(sort(keys(b:git_files), 'N'))

for l:line in l:git_files_line_number
if l:line < l:current_line
return cursor(l:line, 0)
endif
endfor

return cursor(l:git_files_line_number[0], 0)
endfunction

function! dirvish_git#reload() abort
if &filetype ==? 'dirvish'
Dirvish %
endif
endfunction
109 changes: 109 additions & 0 deletions autoload/dirvish_git/async.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,109 @@
" This file is an copy of https://github.com/airblade/vim-gitgutter/blob/719d4ec06a0fb0aa9f1dfaebcf4f9691e8dc3f73/autoload/gitgutter/async.vim
"
let s:available = has('nvim') || (
\ has('job') && (
\ (has('patch-7-4-1826') && !has('gui_running')) ||
\ (has('patch-7-4-1850') && has('gui_running')) ||
\ (has('patch-7-4-1832') && has('gui_macvim'))
\ )
\ )

let s:jobs = {}

function! dirvish_git#async#available()
return s:available
endfunction


function! dirvish_git#async#execute(cmd, bufnr, handler) abort
call dirvish_git#debug#log('[async] '.a:cmd)

let options = {
\ 'stdoutbuffer': [],
\ 'buffer': a:bufnr,
\ 'handler': a:handler
\ }
let command = s:build_command(a:cmd)

if has('nvim')
call jobstart(command, extend(options, {
\ 'on_stdout': function('s:on_stdout_nvim'),
\ 'on_stderr': function('s:on_stderr_nvim'),
\ 'on_exit': function('s:on_exit_nvim')
\ }))
else
let job = job_start(command, {
\ 'out_cb': function('s:on_stdout_vim', options),
\ 'err_cb': function('s:on_stderr_vim', options),
\ 'close_cb': function('s:on_exit_vim', options)
\ })
let s:jobs[s:job_id(job)] = 1
endif
endfunction


function! s:build_command(cmd)
if has('unix')
return ['sh', '-c', a:cmd]
endif

if has('win32')
return has('nvim') ? ['cmd.exe', '/c', a:cmd] : 'cmd.exe /c '.a:cmd
endif

throw 'unknown os'
endfunction


function! s:on_stdout_nvim(_job_id, data, _event) dict abort
if empty(self.stdoutbuffer)
let self.stdoutbuffer = a:data
else
let self.stdoutbuffer = self.stdoutbuffer[:-2] +
\ [self.stdoutbuffer[-1] . a:data[0]] +
\ a:data[1:]
endif
endfunction

function! s:on_stderr_nvim(_job_id, data, _event) dict abort
if a:data != [''] " With Neovim there is always [''] reported on stderr.
call self.handler.err(self.buffer)
endif
endfunction

function! s:on_exit_nvim(_job_id, exit_code, _event) dict abort
if !a:exit_code
call self.handler.out(self.buffer, join(self.stdoutbuffer, "\n"))
endif
endfunction


function! s:on_stdout_vim(_channel, data) dict abort
call add(self.stdoutbuffer, a:data)
endfunction

function! s:on_stderr_vim(channel, _data) dict abort
call self.handler.err(self.buffer)
endfunction

function! s:on_exit_vim(channel) dict abort
let job = ch_getjob(a:channel)
let jobid = s:job_id(job)
if has_key(s:jobs, jobid) | unlet s:jobs[jobid] | endif
while 1
if job_status(job) == 'dead'
let exit_code = job_info(job).exitval
break
endif
sleep 5m
endwhile

if !exit_code
call self.handler.out(self.buffer, join(self.stdoutbuffer, "\n"))
endif
endfunction

function! s:job_id(job)
" Vim
return job_info(a:job).process
endfunction
45 changes: 45 additions & 0 deletions autoload/dirvish_git/debug.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
let s:plugin_dir = expand('<sfile>:p:h:h:h').'/'
let s:log_file = s:plugin_dir.'dirvish_git.log'
let s:channel_log = s:plugin_dir.'channel.log'
let s:new_log_session = 1"

" From vim-gitgutter
function dirvish_git#debug#log(message, ...) abort
if g:dirvish_git_debug
if s:new_log_session && dirvish_git#async#available()
if exists('*ch_logfile')
call ch_logfile(s:channel_log, 'w')
endif
endif

execute 'redir >> '.s:log_file
if s:new_log_session
let s:start = reltime()
silent echo "\n==== start log session ===="
endif

let elapsed = reltimestr(reltime(s:start)).' '
silent echo ''
" callers excluding this function
silent echo elapsed.expand('<sfile>')[:-22].':'
silent echo elapsed.s:format_for_log(a:message)
if a:0 && !empty(a:1)
for msg in a:000
silent echo elapsed.s:format_for_log(msg)
endfor
endif
redir END

let s:new_log_session = 0
endif
endfunction

function! s:format_for_log(data) abort
if type(a:data) == 1
return join(split(a:data,'\n'),"\n")
elseif type(a:data) == 3
return '['.join(a:data,"\n").']'
else
return a:data
endif
endfunction
93 changes: 93 additions & 0 deletions autoload/dirvish_git/highlight.vim
Original file line number Diff line number Diff line change
@@ -0,0 +1,93 @@
if !exists('g:dirvish_git_indicators')
let g:dirvish_git_indicators = {
\ 'Modified' : '✹',
\ 'Staged' : '✚',
\ 'Untracked' : '✭',
\ 'Renamed' : '➜',
\ 'Unmerged' : '═',
\ 'Ignored' : '☒',
\ 'Unknown' : '?'
\ }
endif

let s:dirvish_git_highlight_groups = {
\ 'Modified' : 'DirvishGitModified',
\ 'Staged' : 'DirvishGitStaged',
\ 'Untracked' : 'DirvishGitUntracked',
\ 'Renamed' : 'DirvishGitRenamed',
\ 'Unmerged' : 'DirvishGitUnmerged',
\ 'Ignored' : 'DirvishGitIgnored',
\ 'Unknown' : 'DirvishGitModified'
\ }

let s:sep = dirvish_git#sep
let s:escape_chars = dirvish_git#escape_chars

function dirvish_git#highlight#get_highlight_groups() abort
return s:dirvish_git_highlight_groups
endfunction

function! s:get_indicator_name(us, them) abort
if a:us ==# '?' && a:them ==# '?'
return 'Untracked'
elseif a:us ==# ' ' && a:them ==# 'M'
return 'Modified'
elseif a:us =~# '[MAC]'
return 'Staged'
elseif a:us ==# 'R'
return 'Renamed'
elseif a:us ==# 'U' || a:them ==# 'U' || a:us ==# 'A' && a:them ==# 'A' || a:us ==# 'D' && a:them ==# 'D'
return 'Unmerged'
elseif a:us ==# '!'
return 'Ignored'
else
return 'Unknown'
endif
endfunction

function! dirvish_git#highlight#get_indicator(us, them) abort
return get(g:dirvish_git_indicators, s:get_indicator_name(a:us, a:them), '')
endfunction

function! dirvish_git#highlight#get_highlight_group(us, them, is_directory) abort
let l:group = get(s:dirvish_git_highlight_groups, s:get_indicator_name(a:us, a:them), 'DirvishGitModified')
if !a:is_directory || l:group !=? 'DirvishGitUntracked'
return l:group
endif

return 'DirvishGitUntrackedDir'
endfunction

function! dirvish_git#highlight#highlight_file(dir, file_name, us, them, is_directory) abort
let l:file_rgx = escape(printf('\(%s\)\@<=%s%s', a:dir, s:sep, a:file_name), s:escape_chars)
let l:dir_rgx = escape(printf('%s\(%s%s\)\@=', a:dir, s:sep, a:file_name), s:escape_chars)
let l:slash_rgx = escape(printf('\(%s\)\@<=%s\(%s\)\@=', a:dir, s:sep, a:file_name), s:escape_chars)

call dirvish_git#debug#log('[l:file_rgx] '. l:file_rgx)
call dirvish_git#debug#log('[l:dir_rgx] '. l:dir_rgx)
" Check if icons should be shown
let l:conceal_char = g:dirvish_git_show_icons ? (' cchar=' . dirvish_git#highlight#get_indicator(a:us, a:them)) : ''
let l:conceal_last_folder_char = g:dirvish_git_show_icons ? ' cchar= ' : ''

silent exe 'syn match DirvishGitDir "'.l:dir_rgx.'" conceal ' . l:conceal_char
silent exe 'syn match '. dirvish_git#highlight#get_highlight_group(a:us, a:them, a:is_directory).' "'.l:file_rgx.'" contains=DirvishGitSlash'
silent exe 'syn match DirvishGitSlash "'.l:slash_rgx.'" conceal contained' . l:conceal_last_folder_char
endfunction

function! dirvish_git#highlight#setup_highlighting() abort
for l:highlight_group in values(s:dirvish_git_highlight_groups)
silent! exe 'syntax clear '.l:highlight_group
endfor

let l:modified = 'guifg=#fabd2f ctermfg=214'
let l:added = 'guifg=#b8bb26 ctermfg=142'
let l:unmerged = 'guifg=#fb4934 ctermfg=167'

silent exe 'hi default DirvishGitModified '.l:modified
silent exe 'hi default DirvishGitStaged '.l:added
silent exe 'hi default DirvishGitRenamed '.l:modified
silent exe 'hi default DirvishGitUnmerged '.l:unmerged
silent exe 'hi default link DirvishGitUntrackedDir DirvishPathTail'
silent exe 'hi default DirvishGitIgnored guifg=NONE guibg=NONE gui=NONE cterm=NONE ctermfg=NONE ctermbg=NONE'
silent exe 'hi default DirvishGitUntracked guifg=NONE guibg=NONE gui=NONE cterm=NONE ctermfg=NONE ctermbg=NONE'
endfunction
Loading