문제

vim 상태 표시줄에 실시간 단어 수를 표시하려고 합니다..vimrc에 상태 표시줄을 설정하고 거기에 함수를 삽입하면 됩니다.이 함수의 아이디어는 현재 버퍼에 있는 단어 수를 반환하는 것입니다.그러면 이 번호가 상태 표시줄에 표시됩니다.가능한 모든 기회에 상태 표시줄이 업데이트되어 카운트가 항상 '실시간'으로 유지되므로 이는 잘 작동합니다.

문제는 제가 현재 정의한 함수가 느리기 때문에 vim이 가장 작은 파일을 제외한 모든 파일에 사용될 때 확실히 느리다는 것입니다.이 기능이 너무 자주 실행되기 때문입니다.

요약하자면, 현재 버퍼의 단어 수를 계산하고 결과를 반환하는 데 엄청나게 빠른 함수를 생성하는 영리한 트릭을 가진 사람이 있습니까?

도움이 되었습니까?

해결책

다음은 Rodrigo Queiro의 아이디어를 활용한 버전입니다.상태 표시줄은 변경되지 않으며 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()}

다른 팁

위의 Michael Dunn의 답변이 정말 마음에 들었지만 편집할 때 마지막 열에 액세스할 수 없다는 사실을 발견했습니다.그래서 함수에 약간의 변경 사항이 있습니다.

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]) 그렇지 않으면 s : word_count = str2nr (split (v : stertatsmsg) [11]) 끝
    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('$')
    let n = n + len(split(getline(lnum)))
    let lnum = lnum + 1
  endwhile
  return n
endfunction

물론 다른 사람들과 마찬가지로 다음을 수행해야 합니다.

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

누군가가 이를 정리하여 더 활기차게 만들 수 있다고 확신하지만(n 대신 s:n?) 기본 기능은 거기에 있다고 믿습니다.

편집하다:

이것을 다시 보면 Mikael Jansson의 솔루션이 정말 마음에 듭니다.나는 밖으로 껍질을 벗기는 것을 좋아하지 않는다 wc (휴대용이 아니며 속도가 느릴 수도 있음)우리가 그를 대체한다면 UpdateWordCount 위에 있는 코드로 함수를 실행합니다(함수 이름을 다음으로 변경). UpdateWordCount) 그렇다면 더 나은 해결책이 있다고 생각합니다.

나의 제안:

function! UpdateWordCount()
  let b:word_count = eval(join(map(getline("1", "$"), "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

기존 상태 줄을 덮어쓰지 않기 때문에 좀 더 깔끔해졌습니다.

내가 포스팅하는 이유는 이 함수에 수수께끼 같은 버그가 있다는 점을 지적하기 위해서입니다.즉, 추가 명령이 중단됩니다.타격 줄의 마지막 문자 오른쪽에 커서가 위치한 삽입 모드로 들어가야 합니다.그러나 이 사용자 정의 상태 표시줄을 활성화하면 최종 문자의 왼쪽에 표시됩니다.

이 문제의 원인이 무엇인지 아는 사람이 있나요?

이는 다음과 같은 개선 사항입니다. 마이클 던 버전, 단어 수를 캐싱하므로 처리가 더 적게 필요합니다.

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("$")
        let data = data + getline(line(".")+1, "$") 
    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

그런 다음 다음과 같이 상태 줄에 추가됩니다.

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

Vim에서 실제 단어 수를 찾는 사람에게 이것이 도움이 되기를 바랍니다.항상 정확하지는 않지만.물론 g ctrl-g를 누르면 Vim의 단어 수를 확인할 수 있습니다!

다른 사람이 Google에서 여기에 오는 경우를 대비하여 Abslom Daak의 답변을 수정했습니다. 공기 호스.다음과 같이 저장했습니다.

~/.vim/bundle/vim-airline/autoload/airline/extensions/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

Guy Gur-Ari의 변형 정제 저것

  • 맞춤법 검사가 활성화된 경우에만 단어 수를 계산합니다.
  • 시각적 모드에서 선택한 단어 수를 계산합니다.
  • 삽입 및 일반 모드 밖에서는 음소거를 유지합니다.
  • 시스템 언어에 더 불가지론적이길 바랍니다(영어와 다른 경우).
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