diff --git a/autoload/airline.vim b/autoload/airline.vim index 549c2a9..208fa2c 100644 --- a/autoload/airline.vim +++ b/autoload/airline.vim @@ -196,6 +196,7 @@ function! airline#check_mode(winnr) if get(w:, 'airline_lastmode', '') != mode_string call airline#highlighter#highlight_modified_inactive(context.bufnr) call airline#highlighter#highlight(l:mode, context.bufnr) + silent doautocmd User AirlineModeChanged let w:airline_lastmode = mode_string endif diff --git a/autoload/airline/extensions/wordcount.vim b/autoload/airline/extensions/wordcount.vim index 0a8988c..7486929 100644 --- a/autoload/airline/extensions/wordcount.vim +++ b/autoload/airline/extensions/wordcount.vim @@ -1,43 +1,114 @@ " MIT License. Copyright (c) 2013-2018 Bailey Ling et al. -" vim: et ts=2 sts=2 sw=2 +" vim: et ts=2 sts=2 sw=2 fdm=marker scriptencoding utf-8 -let s:formatter = get(g:, 'airline#extensions#wordcount#formatter', 'default') -let g:airline#extensions#wordcount#filetypes = get(g:, 'airline#extensions#wordcount#filetypes', - \ '\vhelp|markdown|rst|org|text|asciidoc|tex|mail') +" get wordcount {{{1 +if exists('*wordcount') + function! s:get_wordcount(visual_mode_active) + let query = a:visual_mode_active ? 'visual_words' : 'words' + return string(wordcount()[query]) + endfunction +else + function! s:get_wordcount(visual_mode_active) + " index to retrieve from whitespace-separated output of g_CTRL-G + " 11 : words, 5 : visual words (in visual mode) + let idx = a:visual_mode_active ? 5 : 11 -function! s:wordcount_update() - if empty(bufname('')) - return - endif - if match(&ft, get(g:, 'airline#extensions#wordcount#filetypes')) > -1 - let l:mode = mode() - if l:mode ==# 'v' || l:mode ==# 'V' || l:mode ==# 's' || l:mode ==# 'S' - let b:airline_wordcount = airline#extensions#wordcount#formatters#{s:formatter}#format() - let b:airline_change_tick = b:changedtick - else - if get(b:, 'airline_wordcount_cache', '') is# '' || - \ b:airline_wordcount_cache isnot# get(b:, 'airline_wordcount', '') || - \ get(b:, 'airline_change_tick', 0) != b:changedtick || - \ get(b:, 'airline_winwidth', 0) != winwidth(0) - " cache data - let b:airline_wordcount = airline#extensions#wordcount#formatters#{s:formatter}#format() - let b:airline_wordcount_cache = b:airline_wordcount - let b:airline_change_tick = b:changedtick - let b:airline_winwidth = winwidth(0) - endif + let save_status = v:statusmsg + execute "silent normal! g\" + let stat = v:statusmsg + let v:statusmsg = save_status + + let parts = split(stat) + if len(parts) > idx + return parts[idx] endif + endfunction +endif + +" format {{{1 +let s:formatter = get(g:, 'airline#extensions#wordcount#formatter', 'default') + +" wrapper function for compatibility; redefined below for old-style formatters +function! s:format_wordcount(wordcount) + return airline#extensions#wordcount#formatters#{s:formatter}#to_string(a:wordcount) +endfunction + +" check user-defined formatter exists with appropriate functions, otherwise +" fall back to default +if s:formatter !=# 'default' + execute 'runtime! autoload/airline/extensions/wordcount/formatters/'.s:formatter + if !exists('*airline#extensions#wordcount#formatters#{s:formatter}#to_string') + if !exists('*airline#extensions#wordcount#formatters#{s:formatter}#format') + let s:formatter = 'default' + else + " redefine for backwords compatibility + function! s:format_wordcount(_) + if mode() ==? 'v' + return b:airline_wordcount + else + return airline#extensions#wordcount#formatters#{s:formatter}#format() + endif + endfunction + endif + endif +endif + +" update {{{1 +let s:wordcount_cache = 0 " cache wordcount for performance when force_update=0 +function! s:update_wordcount(force_update) + let wordcount = s:get_wordcount(0) + if wordcount != s:wordcount_cache || a:force_update + let s:wordcount_cache = wordcount + let b:airline_wordcount = s:format_wordcount(wordcount) endif endfunction +let s:visual_active = 0 " Boolean: for when to get visual wordcount +function airline#extensions#wordcount#get() + if s:visual_active + return s:format_wordcount(s:get_wordcount(1)) + else + if b:airline_changedtick != b:changedtick + call s:update_wordcount(0) + let b:airline_changedtick = b:changedtick + endif + return b:airline_wordcount + endif +endfunction + +" airline functions {{{1 +" default filetypes: +let s:filetypes = ['help', 'markdown', 'rst', 'org', 'text', 'asciidoc', 'tex', 'mail'] function! airline#extensions#wordcount#apply(...) - if match(&ft, get(g:, 'airline#extensions#wordcount#filetypes')) > -1 - call airline#extensions#prepend_to_section('z', '%{get(b:, "airline_wordcount", "")}') + let filetypes = get(g:, 'airline#extensions#wordcount#filetypes', s:filetypes) + + " Check if filetype needs testing + if did_filetype() || filetypes isnot s:filetypes + let s:filetypes = filetypes + + " Select test based on type of "filetypes": new=list, old=string + if type(filetypes) == v:t_list + \ ? index(filetypes, &filetype) > -1 || index(filetypes, 'all') > -1 + \ : match(&filetype, filetypes) > -1 + let b:airline_changedtick = -1 + call s:update_wordcount(1) " force update: ensures initial worcount exists + elseif exists('b:airline_wordcount') " cleanup when filetype is removed + unlet b:airline_wordcount + endif + endif + + if exists('b:airline_wordcount') + call airline#extensions#prepend_to_section( + \ 'z', '%{airline#extensions#wordcount#get()}') endif endfunction function! airline#extensions#wordcount#init(ext) + augroup airline_wordcount + autocmd! User AirlineModeChanged nested + \ let s:visual_active = (mode() ==? 'v' || mode() ==? 's') + augroup END call a:ext.add_statusline_func('airline#extensions#wordcount#apply') - autocmd BufReadPost,CursorMoved,CursorMovedI * call s:wordcount_update() endfunction diff --git a/autoload/airline/extensions/wordcount/formatters/default.vim b/autoload/airline/extensions/wordcount/formatters/default.vim index d7b5fae..a2b3935 100644 --- a/autoload/airline/extensions/wordcount/formatters/default.vim +++ b/autoload/airline/extensions/wordcount/formatters/default.vim @@ -3,64 +3,39 @@ scriptencoding utf-8 -function! airline#extensions#wordcount#formatters#default#format() - let fmt = get(g:, 'airline#extensions#wordcount#formatter#default#fmt', '%s words') - let fmt_short = get(g:, 'airline#extensions#wordcount#formatter#default#fmt_short', fmt == '%s words' ? '%sW' : fmt) - let words = string(s:wordcount()) - if empty(words) +function s:update_fmt(...) + let s:fmt = get(g:, 'airline#extensions#wordcount#formatter#default#fmt', '%s words') + let s:fmt_short = get(g:, 'airline#extensions#wordcount#formatter#default#fmt_short', s:fmt == '%s words' ? '%sW' : s:fmt) +endfunction + +" Reload format when statusline is rebuilt +call s:update_fmt() +call airline#add_statusline_funcref(function('s:update_fmt')) + +if match(get(v:, 'lang', ''), '\v\cC|en') > -1 + let s:decimal_group = ',' +elseif match(get(v:, 'lang', ''), '\v\cde|dk|fr|pt') > -1 + let s:decimal_group = '.' +else + let s:decimal_group = '' +endif + +function! airline#extensions#wordcount#formatters#default#to_string(wordcount) + if empty(a:wordcount) return endif - let result = g:airline_symbols.space . g:airline_right_alt_sep . g:airline_symbols.space + if winwidth(0) >= 80 - let separator = s:get_decimal_group() - if words > 999 && !empty(separator) + if a:wordcount > 999 " Format number according to locale, e.g. German: 1.245 or English: 1,245 - let words = substitute(words, '\d\@<=\(\(\d\{3\}\)\+\)$', separator.'&', 'g') - endif - let result = printf(fmt, words). result - else - let result = printf(fmt_short, words). result - endif - return result -endfunction - -function! s:wordcount() - if exists("*wordcount") - let l:mode = mode() - if l:mode ==# 'v' || l:mode ==# 'V' || l:mode ==# 's' || l:mode ==# 'S' - let l:visual_words = wordcount()['visual_words'] - if l:visual_words != '' - return l:visual_words - else - return 0 - endif + let wordcount = substitute(a:wordcount, '\d\@<=\(\(\d\{3\}\)\+\)$', s:decimal_group.'&', 'g') else - return wordcount()['words'] + let wordcount = a:wordcount endif - elseif mode() =~? 's' - return + let str = printf(s:fmt, wordcount) else - let old_status = v:statusmsg - let position = getpos(".") - exe "silent normal! g\" - let stat = v:statusmsg - call setpos('.', position) - let v:statusmsg = old_status - - let parts = split(stat) - if len(parts) > 11 - return str2nr(parts[11]) - else - return - endif + let str = printf(s:fmt_short, a:wordcount) endif + return str . g:airline_symbols.space . g:airline_right_alt_sep . g:airline_symbols.space endfunction -function! s:get_decimal_group() - if match(get(v:, 'lang', ''), '\v\cC|en') > -1 - return ',' - elseif match(get(v:, 'lang', ''), '\v\cde|dk|fr|pt') > -1 - return '.' - endif - return '' -endfunction