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.
This commit is contained in:
Liam Fleming 2018-06-30 18:34:12 +01:00
parent 781c40bb3d
commit 44da0a4761
2 changed files with 71 additions and 47 deletions

View File

@ -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\<cn-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", "")}')

View File

@ -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\<c-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