From 44da0a476169815f9536f43a05f859b6553dfbbe Mon Sep 17 00:00:00 2001 From: Liam Fleming Date: Sat, 30 Jun 2018 18:34:12 +0100 Subject: [PATCH] wordcount: Replace formatter interface Currently the formatter, and not the wordcount plugin, is responsible for providing the wordcount as well as formatting it. The default formatter allows visual mode word counting, although this is not documented. The new interface - a transform() function, allows the main wordcount plugin to internalise this logic. Providing the wordcount simplifies formatter implementations: - All formatters can display the visual wordcount. - Formatters do not have to worry about compatibility with different vim versions. The old format() function can now be deprecated, although the wordcount plugin retains compatibility with formatters using it. The default formatter will also be used as a fallback if no suitable function is found. The default formatter is rewritten to use the new interface. --- autoload/airline/extensions/wordcount.vim | 64 +++++++++++++++++-- .../wordcount/formatters/default.vim | 54 ++++------------ 2 files changed, 71 insertions(+), 47 deletions(-) diff --git a/autoload/airline/extensions/wordcount.vim b/autoload/airline/extensions/wordcount.vim index 0a8988c..e2eb305 100644 --- a/autoload/airline/extensions/wordcount.vim +++ b/autoload/airline/extensions/wordcount.vim @@ -1,12 +1,59 @@ " 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(type) + return string(wordcount()[a:type]) + endfunction +else + function! s:get_wordcount(type) + " index to retrieve from whitespace-separated output of g_CTRL-G + " 11 - words, 5 - visual words (in visual mode) + let idx = (a:type == 'words') ? 11 : 5 + 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(type) + return airline#extensions#wordcount#formatters#{s:formatter}#transform( + \ s:get_wordcount(a:type)) +endfunction + +" check user-defined formatter exists and has 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}#transform') + if !exists('*airline#extensions#wordcount#formatters#{s:formatter}#format') + let s:formatter = 'default' + else + " redefine for backwords compatibility + function! s:format_wordcount(type) + if a:type !=# 'visual_words' + return airline#extensions#wordcount#formatters#{s:formatter}#format() + endif + endfunction + endif + endif +endif + +" update {{{1 function! s:wordcount_update() if empty(bufname('')) return @@ -14,7 +61,7 @@ function! s:wordcount_update() 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_wordcount = s:format_wordcount('visual_words') let b:airline_change_tick = b:changedtick else if get(b:, 'airline_wordcount_cache', '') is# '' || @@ -22,7 +69,7 @@ function! s:wordcount_update() \ 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 = s:format_wordcount('words') let b:airline_wordcount_cache = b:airline_wordcount let b:airline_change_tick = b:changedtick let b:airline_winwidth = winwidth(0) @@ -31,6 +78,11 @@ function! s:wordcount_update() endif endfunction +" autocmds & airline functions {{{1 +" default filetypes +let g:airline#extensions#wordcount#filetypes = get(g:, 'airline#extensions#wordcount#filetypes', + \ '\vhelp|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", "")}') diff --git a/autoload/airline/extensions/wordcount/formatters/default.vim b/autoload/airline/extensions/wordcount/formatters/default.vim index d7b5fae..846b4e0 100644 --- a/autoload/airline/extensions/wordcount/formatters/default.vim +++ b/autoload/airline/extensions/wordcount/formatters/default.vim @@ -3,59 +3,30 @@ 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) +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) + +function! airline#extensions#wordcount#formatters#default#transform(text) + if empty(a:text) 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:text > 999 && !empty(separator) " Format number according to locale, e.g. German: 1.245 or English: 1,245 - let words = substitute(words, '\d\@<=\(\(\d\{3\}\)\+\)$', separator.'&', 'g') + let text = substitute(a:text, '\d\@<=\(\(\d\{3\}\)\+\)$', separator.'&', 'g') + else + let text = a:text endif - let result = printf(fmt, words). result + let result = printf(s:fmt, a:text). result else - let result = printf(fmt_short, words). result + let result = printf(s:fmt_short, a:text). 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 - else - return wordcount()['words'] - endif - elseif mode() =~? 's' - return - 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 - endif -endfunction - function! s:get_decimal_group() if match(get(v:, 'lang', ''), '\v\cC|en') > -1 return ',' @@ -64,3 +35,4 @@ function! s:get_decimal_group() endif return '' endfunction +