From 9112675ad8c069838f9584003fd3450226ad9085 Mon Sep 17 00:00:00 2001 From: Christian Brabandt Date: Wed, 24 Apr 2019 15:15:29 +0200 Subject: [PATCH] branch: display dirty state If the repository is considered dirty, do display the g:airline_symbols.dirty symbol right after the branch name. --- CHANGELOG.md | 2 + autoload/airline/async.vim | 73 ++++++++++++++++++++++++++ autoload/airline/extensions/branch.vim | 15 ++++-- autoload/airline/init.vim | 4 +- doc/airline.txt | 4 +- 5 files changed, 93 insertions(+), 5 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index bd1a38c..5535add 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -13,6 +13,8 @@ This is the Changelog for the vim-airline project. buffers directly (issue #1823) - Allow to use `random` as special theme name, which will switch to a random airline theme (at least if a random number can be generated :() + - The branch extensions now also displays whether the repository is in a clean state + (will append a ! or ⚡if the repository is considered dirty). ## [0.10] - 2018-12-15 - New features diff --git a/autoload/airline/async.vim b/autoload/airline/async.vim index fe5a999..052e0f4 100644 --- a/autoload/airline/async.vim +++ b/autoload/airline/async.vim @@ -6,6 +6,7 @@ scriptencoding utf-8 let s:untracked_jobs = {} let s:mq_jobs = {} let s:po_jobs = {} +let s:clean_jobs = {} " Generic functions handling on exit event of the various async functions function! s:untracked_output(dict, buf) @@ -63,6 +64,29 @@ function! airline#async#vcs_untracked(config, file, vcs) endif endfunction +function! s:on_exit_clean(...) dict abort + let buf=self.buf + if !empty(buf) + let var=getbufvar(self.file, 'buffer_vcs_config', {}) + let var[self.vcs].dirty=1 + call setbufvar(self.file, 'buffer_vcs_config', var) + unlet! b:airline_head + endif + if has_key(get(s:clean_jobs, 'self.vcs', {}), self.file) + call remove(s:clean_jobs[self.vcs], self.file) + endif +endfunction + +function! airline#async#vcs_clean(cmd, file, vcs) + if g:airline#init#vim_async + " Vim 8 with async support + noa call airline#async#vim_vcs_clean(a:cmd, a:file, a:vcs) + else + " nvim async or vim without job-feature + noa call airline#async#nvim_vcs_clean(a:cmd, a:file, a:vcs) + endif +endfunction + if v:version >= 800 && has("job") " Vim 8.0 with Job feature " TODO: Check if we need the cwd option for the job_start() functions @@ -133,6 +157,29 @@ if v:version >= 800 && has("job") let s:po_jobs[a:file] = id endfunction + function! airline#async#vim_vcs_clean(cmd, file, vcs) + if g:airline#init#is_windows && &shell =~ 'cmd' + let cmd = a:cmd + else + let cmd = ['sh', '-c', a:cmd] + endif + + let options = {'buf': '', 'vcs': a:vcs, 'file': a:file} + let jobs = get(s:clean_jobs, a:vcs, {}) + if has_key(jobs, a:file) + if job_status(get(jobs, a:file)) == 'run' + return + elseif has_key(jobs, a:file) + call remove(jobs, a:file) + endif + endif + let id = job_start(cmd, { + \ 'err_io': 'null', + \ 'out_cb': function('s:on_stdout', options), + \ 'close_cb': function('s:on_exit_clean', options)}) + let jobs[a:file] = id + endfunction + function! airline#async#vim_vcs_untracked(config, file) if g:airline#init#is_windows && &shell =~ 'cmd' let cmd = a:config['cmd'] . shellescape(a:file) @@ -208,6 +255,32 @@ elseif has("nvim") let s:mq_jobs[a:file] = id endfunction + function! airline#async#nvim_vcs_clean(cmd, file, vcs) + let config = { + \ 'buf': '', + \ 'vcs': a:vcs, + \ 'file': a:file, + \ 'cwd': s:valid_dir(fnamemodify(a:file, ':p:h')), + \ 'on_stdout': function('s:nvim_output_handler'), + \ 'on_stderr': function('s:nvim_output_handler'), + \ 'on_exit': function('s:on_exit_clean') + \ } + if g:airline#init#is_windows && &shell =~ 'cmd' + let cmd = a:cmd + else + let cmd = ['sh', '-c', a:cmd] + endif + + if !has_key(s:clean_jobs, a:vcs) + let s:clean_jobs[a:vcs] = {} + endif + if has_key(s:clean_jobs[a:vcs], a:file) + call remove(s:clean_jobs[a:vcs], a:file) + endif + let id = jobstart(cmd, config) + let s:clean_jobs[a:vcs][a:file] = id + endfunction + function! airline#async#nvim_get_msgfmt_stat(cmd, file) let config = { \ 'buf': '', diff --git a/autoload/airline/extensions/branch.vim b/autoload/airline/extensions/branch.vim index 33c4a6b..4b3a17d 100644 --- a/autoload/airline/extensions/branch.vim +++ b/autoload/airline/extensions/branch.vim @@ -17,6 +17,7 @@ let s:vcs_config = { \ 'git': { \ 'exe': 'git', \ 'cmd': 'git status --porcelain -- ', +\ 'dirty': 'git status --porcelain', \ 'untracked_mark': '??', \ 'exclude': '\.git', \ 'update_branch': 's:update_git_branch', @@ -27,6 +28,7 @@ let s:vcs_config = { \ 'mercurial': { \ 'exe': 'hg', \ 'cmd': 'hg status -u -- ', +\ 'dirty': 'hg status -muard', \ 'untracked_mark': '?', \ 'exclude': '\.hg', \ 'update_branch': 's:update_hg_branch', @@ -51,6 +53,7 @@ function! s:init_buffer() let b:buffer_vcs_config[vcs] = { \ 'branch': '', \ 'untracked': '', + \ 'dirty': 0, \ } endfor unlet! b:airline_head @@ -200,6 +203,8 @@ function! s:update_untracked() " result of the previous call, i.e. the head string is not updated. It " doesn't happen often in practice, so we let it be. call airline#async#vcs_untracked(config, file, vcs) + " Check clean state of repo + call airline#async#vcs_clean(config.dirty, file, vcs) endfor endfunction @@ -233,7 +238,11 @@ function! airline#extensions#branch#head() let b:airline_head .= s:vcs_config[vcs].exe .':' endif let b:airline_head .= s:format_name({s:vcs_config[vcs].display_branch}()) - let b:airline_head .= b:buffer_vcs_config[vcs].untracked + let additional = b:buffer_vcs_config[vcs].untracked + if empty(additional) && b:buffer_vcs_config[vcs].dirty + let additional = g:airline_symbols['dirty'] + endif + let b:airline_head .= additional endfor if empty(heads) @@ -269,10 +278,10 @@ function! airline#extensions#branch#get_head() let winwidth = get(airline#parts#get('branch'), 'minwidth', 120) let minwidth = empty(get(b:, 'airline_hunks', '')) ? 14 : 7 let head = airline#util#shorten(head, winwidth, minwidth) - let empty_message = get(g:, 'airline#extensions#branch#empty_message', '') let symbol = get(g:, 'airline#extensions#branch#symbol', g:airline_symbols.branch) + let dirty = get(b:, 'airline_branch_dirty', '') return empty(head) - \ ? empty_message + \ ? get(g:, 'airline#extensions#branch#empty_message', '') \ : printf('%s%s', empty(symbol) ? '' : symbol.(g:airline_symbols.space), head) endfunction diff --git a/autoload/airline/init.vim b/autoload/airline/init.vim index 40d7795..9cb9698 100644 --- a/autoload/airline/init.vim +++ b/autoload/airline/init.vim @@ -86,7 +86,7 @@ function! airline#init#bootstrap() call s:check_defined('g:airline_left_alt_sep', "\ue0b1") "  call s:check_defined('g:airline_right_sep', "\ue0b2") "  call s:check_defined('g:airline_right_alt_sep', "\ue0b3") "  - " ro=, ws=☲, lnr=☰, mlnr=, br=, nx=Ɇ, crypt=🔒 + " ro=, ws=☲, lnr=☰, mlnr=, br=, nx=Ɇ, crypt=🔒, dirty=⚡ call extend(g:airline_symbols, { \ 'readonly': "\ue0a2", \ 'whitespace': "\u2632", @@ -94,6 +94,7 @@ function! airline#init#bootstrap() \ 'maxlinenr': " \ue0a1", \ 'branch': "\ue0a0", \ 'notexists': "\u0246", + \ 'dirty': "\u26a1", \ 'crypt': nr2char(0x1F512), \ }, 'keep') elseif &encoding==?'utf-8' && !get(g:, "airline_symbols_ascii", 0) @@ -111,6 +112,7 @@ function! airline#init#bootstrap() \ 'branch': "\u16A0", \ 'notexists': "\u0246", \ 'crypt': nr2char(0x1F512), + \ 'dirty': '!', \ }, 'keep') else " Symbols for ASCII terminals diff --git a/doc/airline.txt b/doc/airline.txt index 2beb2d4..7304471 100644 --- a/doc/airline.txt +++ b/doc/airline.txt @@ -319,6 +319,7 @@ its contents. > let g:airline_symbols.readonly = '' let g:airline_symbols.linenr = '☰' let g:airline_symbols.maxlinenr = '' + let g:airline_symbols.dirty=⚡ " old vim-powerline symbols let g:airline_left_sep = '⮀' @@ -434,7 +435,8 @@ lawrencium vcscommand If a file is edited, that is not yet in the repository, the -notexists symbol will be displayed after the branch name. +notexists symbol will be displayed after the branch name. If the repository is +not clean, the dirty symbol will be displayed after the branch name. * enable/disable fugitive/lawrencium integration > let g:airline#extensions#branch#enabled = 1