我试图来显示一个活的字数在vim状态栏。我这样做是通过设置我的状态线在我的。vimrc并插入一个功能进入它。这个想法的这一功能是为返回的数字在目前的缓冲器。这个数字后显示在地位线。这应该很好地工作作为的状态栏更新在几乎每一个可能的机会,所以计数将永远是"活"。

问题是,这一功能的,我们目前的定义是缓慢的,所以vim显然是缓慢的,当它用于所有,但最小的文件;由于此功能正在执行的那么频繁。

总之,没有任何人有一个聪明的招生产功能,这是极快在计算数字在目前的缓冲器并返回的结果?

有帮助吗?

解决方案

这是罗德里戈奎罗的想法的可用版本。它不会更改状态栏,而是还原statusmsg变量。

function WordCount()
  let s:old_status = v:statusmsg
  exe "silent normal g\<c-g>"
  let s:word_count = str2nr(split(v:statusmsg)[11])
  let v:statusmsg = s:old_status
  return s:word_count
endfunction

这似乎足够快,可以直接包含在状态行中,例如:

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

其他提示

我真的很喜欢迈克尔邓恩上面的回答,但我发现当我编辑时,它导致我无法访问最后一列。所以我对这个功能进行了一些小改动:

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

我已将其包含在我的状态行中而没有任何问题:

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

保持当前行的计数以及其余缓冲区的单独计数。当您在当前行上键入(或删除)单词时,仅更新该计数,但显示当前行数和剩余缓冲区计数的总和。

当您更改行时,将当前行计数添加到缓冲区计数,计算当前行中的单词,a)设置当前行计数,b)从缓冲区计数中减去它。

定期重新计算缓冲区也是明智的(请注意,您不必一次计算整个缓冲区,因为您知道正在进行编辑的位置)。

这会在您停止输入一段时间后重新计算字数(具体来说, 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

享受!

所以我写了:

func CountWords()
    exe "normal g\"
    let words = substitute(v:statusmsg, "^.*Word [^ ]* of ", "", "")
    let words = substitute(words, ";.*", "", "")
    return words
endfunc

但它将信息打印到状态栏,所以我认为它不适合您的用例。但速度非常快!

我使用了稍微不同的方法。而不是确保单词计数功能特别快,我只在光标停止移动时调用它。这些命令将执行此操作:

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

也许并不是提问者想要的,但比这里的一些答案简单得多,而且对我的用例来说足够好了(在输入一两句话之后看一下字数统计)。

updatetime 设置为较小的值也有帮助:

set updatetime=300

对于字数没有巨大的开销轮询,因为当光标停止移动时, CursorHold CursorHoldI 只会激活一次,而不是每个 updatetime ms。

以下是对Abslom Daak的回答的改进,该回答也适用于视觉模式。

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--'
    if stat =~ "^Selected"
      let s:word_count = str2nr(split(v:statusmsg)[5])
    else
      let s:word_count = str2nr(split(v:statusmsg)[11])
    end
    let v:statusmsg = s:old_status
  end
  call setpos('.', position)
  return s:word_count 
endfunction

像以前一样包含在状态行中。这是一个右对齐状态行:

set statusline =%=%{WordCount()} \ words \

我从写作功能的vim帮助页面中获取了大部分内容。

function! WordCount()
  let lnum = 1
  let n = 0
  while lnum <= line('

当然,和其他人一样,你需要:

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

我确信有人可以清理这个以使其更具vimmy(s:n而不仅仅是n?),但我相信基本功能就在那里。

编辑:

再看一遍,我真的很喜欢Mikael Jansson的解决方案。我不喜欢炮轰 wc (不可移植,也许很慢)。如果我们用上面的代码替换他的 UpdateWordCount 函数(将我的函数重命名为 UpdateWordCount ),那么我认为我们有更好的解决方案。

) let n = n + len(split(getline(lnum))) let lnum = lnum + 1 endwhile return n endfunction

当然,和其他人一样,你需要:

<*>

我确信有人可以清理这个以使其更具vimmy(s:n而不仅仅是n?),但我相信基本功能就在那里。

编辑:

再看一遍,我真的很喜欢Mikael Jansson的解决方案。我不喜欢炮轰 wc (不可移植,也许很慢)。如果我们用上面的代码替换他的 UpdateWordCount 函数(将我的函数重命名为 UpdateWordCount ),那么我认为我们有更好的解决方案。

我的建议:

function! UpdateWordCount()
  let b:word_count = eval(join(map(getline("1", "<*>quot;), "len(split(v:val, '\\s\\+'))"), "+"))
endfunction

augroup UpdateWordCount
  au!
  autocmd BufRead,BufNewFile,BufEnter,CursorHold,CursorHoldI,InsertEnter,InsertLeave * call UpdateWordCount()
augroup END

let &statusline='wc:%{get(b:, "word_count", 0)}'

我不确定这与其他一些解决方案的速度相比如何,但它肯定比大多数解决方案简单得多。

我是Vim脚本的新手,但我可能会建议

function WordCount()
    redir => l:status
    exe "silent normal g\<c-g>"
    redir END
    return str2nr(split(l:status)[11])
endfunction

因为它不会覆盖现有的状态行而更加清洁。

我发布的理由是指出这个函数有一个令人费解的错误:即它会破坏append命令。点击 A 会让你进入插入模式,光标位于行上最后一个字符的右边。但是,启用此自定义状态栏后,它会将您置于最终字符的左侧。

任何人都知道是什么原因造成的?

这是对 Michael Dunn的版本的改进,缓存了字数,因此需要更少的处理。

function! WC()
    if &modified || !exists("b:wordcount") 
            let l:old_status = v:statusmsg  
            execute "silent normal g\<c-g>"
            let b:wordcount = str2nr(split(v:statusmsg)[11])
            let v:statusmsg = l:old_status  
            return b:wordcount
    else
            return b:wordcount
    endif
endfunction 

使用Steve Moyer提供的答案中的方法,我能够生成以下解决方案。这是一个相当不优雅的黑客,我害怕,我觉得必须有一个更简洁的解决方案,但它的工作原理,并且比每次更新状态行时简单计算缓冲区中的所有单词要快得多。我还应该注意,这个解决方案是独立于平台的,并不假设系统有'wc'或类似的东西。

我的解决方案不会定期更新缓冲区,但Mikael Jansson提供的答案将能够提供此功能。到目前为止,我还没有找到一个我的解决方案不同步的实例。但是我只是简单地对此进行了测试,因为准确的实时字数对我的需求并不重要。我用于匹配单词的模式也很简单,适用于简单的文本文档。如果有人对模式或任何其他建议有更好的想法,请随时发布答案或编辑此帖子。

我的解决方案:

"returns the count of how many words are in the entire file excluding the current line 
"updates the buffer variable Global_Word_Count to reflect this
fu! OtherLineWordCount() 
    let data = []
    "get lines above and below current line unless current line is first or last
    if line(".") > 1
        let data = getline(1, line(".")-1)
    endif   
    if line(".") < line("
:set statusline=wc:%{WordCount()}
quot;) let data = data + getline(line(".")+1, "<*>quot;) endif let count_words = 0 let pattern = "\\<\\(\\w\\|-\\|'\\)\\+\\>" for str in data let count_words = count_words + NumPatternsInString(str, pattern) endfor let b:Global_Word_Count = count_words return count_words endf "returns the word count for the current line "updates the buffer variable Current_Line_Number "updates the buffer variable Current_Line_Word_Count fu! CurrentLineWordCount() if b:Current_Line_Number != line(".") "if the line number has changed then add old count let b:Global_Word_Count = b:Global_Word_Count + b:Current_Line_Word_Count endif "calculate number of words on current line let line = getline(".") let pattern = "\\<\\(\\w\\|-\\|'\\)\\+\\>" let count_words = NumPatternsInString(line, pattern) let b:Current_Line_Word_Count = count_words "update buffer variable with current line count if b:Current_Line_Number != line(".") "if the line number has changed then subtract current line count let b:Global_Word_Count = b:Global_Word_Count - b:Current_Line_Word_Count endif let b:Current_Line_Number = line(".") "update buffer variable with current line number return count_words endf "returns the word count for the entire file using variables defined in other procedures "this is the function that is called repeatedly and controls the other word "count functions. fu! WordCount() if exists("b:Global_Word_Count") == 0 let b:Global_Word_Count = 0 let b:Current_Line_Word_Count = 0 let b:Current_Line_Number = line(".") call OtherLineWordCount() endif call CurrentLineWordCount() return b:Global_Word_Count + b:Current_Line_Word_Count endf "returns the number of patterns found in a string fu! NumPatternsInString(str, pat) let i = 0 let num = -1 while i != -1 let num = num + 1 let i = matchend(a:str, a:pat, i) endwhile return num endf

然后通过以下方式将其添加到状态行:

<*>

我希望这可以帮助任何在Vim中寻找实时字数的人。虽然一个并不总是准确的。或者当然g ctrl-g会为你提供Vim的字数!

如果其他人从谷歌来到这里,我修改了Abslom Daak的答案,与航空公司。我将以下内容保存为

<代码>〜/的.vim /束/ VIM-航空公司/自动加载/航空公司/扩展/ pandoc.vim

并添加了

call airline#extensions #pandoc #init(s:ext)

extensions.vim

let s:spc = g:airline_symbols.space

function! airline#extensions#pandoc#word_count()
if mode() == "s"
    return 0
else
    let s:old_status = v:statusmsg
    let position = getpos(".")
    let s:word_count = 0
    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 
end
endfunction

function! airline#extensions#pandoc#apply(...)
if &ft == "pandoc"
    let w:airline_section_x = "%{airline#extensions#pandoc#word_count()} Words"
endif
endfunction

function! airline#extensions#pandoc#init(ext)
call a:ext.add_statusline_func('airline#extensions#pandoc#apply')
endfunction

一个变化的家伙古尔-阿里 改进

  • 只计算的话,如果拼写检查启用,
  • 计算数量的选定的词语视模式
  • 保持静音之外的插入件和正常的模式,
  • 希望是更无关的系统语言(当不同于英文)
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

可以附加的状态栏,说,

    set statusline+=%.10{StatuslineWordCount()}     " wordcount
许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top