Fast word count function in Vim

后端 未结 16 2032
后悔当初
后悔当初 2020-12-08 00:27

I am trying to display a live word count in the vim statusline. I do this by setting my status line in my .vimrc and inserting a function into it. The idea of this function

相关标签:
16条回答
  • 2020-12-08 01:18

    I really like Michael Dunn's answer above but I found that when I was editing it was causing me to be unable to access the last column. So I have a minor change for the function:

    function! WordCount()
       let s:old_status = v:statusmsg
       let position = getpos(".")
       exe ":silent normal g\<c-g>"
       let stat = v:statusmsg
       let s:word_count = 0
       if stat != '--No lines in buffer--'
         let s:word_count = str2nr(split(v:statusmsg)[11])
         let v:statusmsg = s:old_status
       end
       call setpos('.', position)
       return s:word_count 
    endfunction
    

    I've included it in my status line without any issues:

    :set statusline=wc:%{WordCount()}

    0 讨论(0)
  • 2020-12-08 01:20

    A variation of Guy Gur-Ari's refinement that

    • only counts words if spell checking is enabled,
    • counts the number of selected words in visual mode
    • keeps mute outside of insert and normal mode, and
    • hopefully is more agnostic to the system language (when different from english)
    function! StatuslineWordCount()
      if !&l:spell
        return ''
      endif
    
      if empty(getline(line('$')))
        return ''
      endif
      let mode = mode()
      if !(mode ==# 'v' || mode ==# 'V' || mode ==# "\<c-v>" || mode =~# '[ni]')
        return ''
      endif
    
      let s:old_status = v:statusmsg
      let position = getpos('.')
      let stat = v:statusmsg
      let s:word_count = 0
      exe ":silent normal g\<c-g>"
      try
        if mode ==# 'v' || mode ==# 'V'
          let s:word_count = split(split(v:statusmsg, ';')[1])[0]
        elseif mode ==# "\<c-v>"
          let s:word_count = split(split(v:statusmsg, ';')[2])[0]
        elseif mode =~# '[ni]'
          let s:word_count = split(split(v:statusmsg, ';')[2])[3]
        end
      " index out of range
      catch /^Vim\%((\a\+)\)\=:E\%(684\|116\)/
        return ''
      endtry
      let v:statusmsg = s:old_status
      call setpos('.', position)
    
      return "\ \|\ " . s:word_count . 'w'
    endfunction
    

    that can be appended to the statusline by, say,

        set statusline+=%.10{StatuslineWordCount()}     " wordcount
    
    0 讨论(0)
  • 2020-12-08 01:21

    I used a slightly different approach for this. Rather than make sure the word count function is especially fast, I only call it when the cursor stops moving. These commands will do it:

    :au CursorHold * exe "normal g\<c-g>"
    :au CursorHoldI * exe "normal g\<c-g>"
    

    Perhaps not quite what the questioner wanted, but much simpler than some of the answers here, and good enough for my use-case (glance down to see word count after typing a sentence or two).

    Setting updatetime to a smaller value also helps here:

    set updatetime=300
    

    There isn't a huge overhead polling for the word count because CursorHold and CursorHoldI only fire once when the cursor stops moving, not every updatetime ms.

    0 讨论(0)
  • 2020-12-08 01:22

    Since vim version 7.4.1042

    Since vim version 7.4.1042, one can simply alter the statusline as follows:

    set statusline+=%{wordcount().words}\ words
    set laststatus=2    " enables the statusline.
    

    Word count in vim-airline

    Word count is provided standard by vim-airline for a number of file types, being at the time of writing: asciidoc, help, mail, markdown, org, rst, tex ,text

    If word count is not shown in the vim-airline, more often this is due to an unrecognised file type. For example, at least for now, the compound file type markdown.pandoc is not being recognised by vim-airline for word count. This can easily be remedied by amending the .vimrc as follows:

    let g:airline#extensions#wordcount#filetypes = '\vasciidoc|help|mail|markdown|markdown.pandoc|org|rst|tex|text'
    set laststatus=2    " enables vim-airline.
    

    The \v statement overrides the default g:airline#extensions#wordcount#filetypes variable. The last line ensures vim-airline is enabled.

    In case of doubt, the &filetype of an opened file is returned upon issuing the following command:

    :echo &filetype
    

    Here is a meta-example:

    vim-airline word count

    0 讨论(0)
  • 2020-12-08 01:23

    Keep a count for the current line and a separate count for the rest of the buffer. As you type (or delete) words on the current line, update only that count, but display the sum of the current line count and the rest of the buffer count.

    When you change lines, add the current line count to the buffer count, count the words in the current line and a) set the current line count and b) subtract it from the buffer count.

    It would also be wise to recount the buffer periodically (note that you don't have to count the whole buffer at once, since you know where editing is occurring).

    0 讨论(0)
  • 2020-12-08 01:25

    This will recalculate the number of words whenever you stop typing for a while (specifically, updatetime ms).

    let g:word_count="<unknown>"
    fun! WordCount()
        return g:word_count
    endfun
    fun! UpdateWordCount()
        let s = system("wc -w ".expand("%p"))
        let parts = split(s, ' ')
        if len(parts) > 1
            let g:word_count = parts[0]
        endif
    endfun
    
    augroup WordCounter
        au! CursorHold * call UpdateWordCount()
        au! CursorHoldI * call UpdateWordCount()
    augroup END
    
    " how eager are you? (default is 4000 ms)
    set updatetime=500
    
    " modify as you please...
    set statusline=%{WordCount()}\ words
    

    Enjoy!

    0 讨论(0)
提交回复
热议问题