Frage
Ich versuche, eine Live-Wortanzahl in der vim Statuszeile angezeigt werden soll. Ich tue dies, meine Statuszeile in meinem .vimrc durch Setzen und eine Funktion in sie eingefügt wird. Die Idee dieser Funktion ist es, die Anzahl der Wörter in den aktuellen Puffer zurückzukehren. Diese Zahl wird dann in der Statuszeile angezeigt. Dies sollte gut funktionieren wie die Statuszeile bei fast jeder Gelegenheit aktualisiert, so die Zählung immer ‚live‘ bleiben wird.
Das Problem ist, dass die Funktion, die ich zur Zeit definiert habe, ist langsam und so vim ist offensichtlich träge, wenn es für alle, aber die kleinsten Dateien verwendet wird; Durch diese Funktion so häufig ausgeführt wird.
Insgesamt hat jemand einen cleveren Trick für eine Funktion erzeugen, die sekundenschnell und ist die Anzahl der Worte in den aktuellen Puffern bei der Berechnung und die Rückkehr des Ergebnisses?
Lösung
Hier ist eine brauchbare Version von Rodrigo Queiro Idee. Es ist nicht die Statusleiste ändern, und es wird für die Behandlung statusmsg Variable.
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
Dies scheint schnell genug zu sein, direkt in der Statuszeile umfassen z.
:set statusline=wc:%{WordCount()}
Andere Tipps
Ich mag Michael Dunn Antwort oben, aber ich fand, dass, wenn ich bearbeite es verursachte mich nicht in der Lage sein, die letzte Spalte zuzugreifen. Also ich habe eine kleine Änderung für die Funktion:
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
ich eingeschlossen habe es in meiner Statuszeile ohne Probleme:
:set statusline=wc:%{WordCount()}
eine Zählung für die aktuelle Zeile halten und eine separate Zählung für den Rest des Puffers. Wie Sie (oder löschen) Wörter auf der aktuellen Zeile eingeben, aktualisieren Sie die zählen nur, sondern die Summe der aktuellen Zeilenzahl und den Rest der Pufferanzahl angezeigt werden soll.
Wenn Sie Zeilen ändern, die aktuelle Zeilenzahl in die Pufferzahl hinzufügen, die Worte in der aktuellen Zeile zählen und a) setzten die aktuelle Zeilenzahl und b) subtrahieren sie von der Pufferzählwert.
Es wäre auch ratsam, den Puffer zu erzählen in regelmäßigen Abständen (beachten Sie, dass Sie nicht über den gesamten Puffer auf einmal zählen müssen, da Sie wissen, wo die Bearbeitung auftritt).
Damit wird die Anzahl der Wörter neu zu berechnen, wenn Sie für eine Weile aufhören Eingabe (genauer gesagt, 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
Genießen Sie!
So habe ich geschrieben:
func CountWords() exe "normal g\" let words = substitute(v:statusmsg, "^.*Word [^ ]* of ", "", "") let words = substitute(words, ";.*", "", "") return words endfunc
Aber es druckt Informationen zum statusbar, so dass ich glaube nicht, dass es für Ihren Anwendungsfall geeignet ist. Es ist sehr schnell, aber!
Ich habe einen etwas anderen Ansatz dafür. Anstatt sicherstellen, dass die Wortzahl Funktion besonders schnell ist, kann ich nur nennen, wenn der Cursor nicht mehr bewegt. Diese Befehle werden es tun:
:au CursorHold * exe "normal g\<c-g>"
:au CursorHoldI * exe "normal g\<c-g>"
Vielleicht nicht ganz, was die Fragesteller wollten, aber viel einfacher als einige der Antworten hier, und gut genug für meinen Anwendungsfall (Blick nach unten Wort nach, um zu sehen zählt einen oder zwei Sätze eingeben).
Einstellung updatetime
auf einen kleineren Wert hilft auch hier:
set updatetime=300
Es ist kein großer Aufwand Polling für das Wort zählen, weil CursorHold
und CursorHoldI
nur Feuer einmal , wenn der Cursor nicht mehr bewegt, nicht alle updatetime
ms.
Hier ist eine Verfeinerung der Abslom Daak Antwort, die auch im visuellen Modus arbeitet.
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
In der Statuszeile enthält wie zuvor. Hier ist eine rechtsbündig Statuszeile:
set statusline=%=%{WordCount()}\ words\
Ich habe den Großteil davon aus den vim Hilfeseite zum Schreiben von Funktionen.
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
Natürlich, wie die anderen, die Sie benötigen, um:
:set statusline=wc:%{WordCount()}
Ich bin sicher, dass dies von jemandem gereinigt werden kann es vimmy zu machen (s:? N statt nur n)., Aber ich glaube, die grundlegende Funktionalität gibt es
Edit:
bei dieser Suche wieder, ich wie Mikael Jansson Lösung wirklich. Ich mag es nicht Beschuss aus wc
(nicht tragbar und vielleicht langsam). Wenn wir seine UpdateWordCount
Funktion mit dem Code ersetzen ich oben haben (meine Funktion UpdateWordCount
Umbenennen), dann denke ich, dass wir eine bessere Lösung haben.
Mein Vorschlag:
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)}'
Ich bin mir nicht sicher, wie dies einige der anderen Lösungen in der Geschwindigkeit vergleicht, aber es ist sicherlich viel einfacher als die meisten.
Ich bin neu in Vim Scripting, aber ich könnte darauf hindeuten,
function WordCount()
redir => l:status
exe "silent normal g\<c-g>"
redir END
return str2nr(split(l:status)[11])
endfunction
als etwas sauberer sein, da es nicht die bestehende Statuszeile nicht überschrieben werden.
Mein Grund für die Buchung ist darauf hinzuweisen, dass diese Funktion einen rätselhaften Fehler hat: nämlich, es bricht den append-Befehl. Schlagen A sollten Sie in den Einfügemodus mit dem Cursor rechts von dem letzten Zeichen auf der Linie positioniert fallen. Doch mit dieser Bar benutzerdefinierten Status aktivieren, damit Sie sie links von dem letzten Zeichen setzen.
Wer noch keine Ahnung, was das verursacht?
Dies ist eine Verbesserung auf Michael Dunn Version , Caching das Wort zählt so noch weniger Verarbeitung benötigt wird.
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
Das Verfahren unter Verwendung in der Antwort zur Verfügung gestellt von Steve Moyer konnte ich die folgende Lösung herzustellen. Es ist ein ziemlich unelegant Hack, den ich habe Angst, und ich fühle, dass es eine sauberere Lösung, aber es funktioniert, und ist viel schneller als einfach alle Worte in einem Puffer in der Statuszeile aktualisiert wird, jedes Mal zu zählen. Ich sollte auch beachten, dass diese Lösung plattformunabhängig ist und nicht davon ausgehen, ein System hat ‚WC‘ oder etwas ähnliches.
Meine Lösung nicht aktualisiert periodisch den Puffer, aber die Antwort von Mikael Jansson vorgesehen wäre in der Lage, diese Funktionalität zu bieten. Ich habe nicht, als der noch, fand eine Instanz, wo meine Lösung nicht synchron wird. Allerdings habe ich nur diese kurz als eine genaue Live-Wortzahl getestet, um meine Bedürfnisse nicht wesentlich ist. Das Muster ich für geschriebene Wörter ist auch einfach und ist für einfache Textdokumente vorgesehen. Wenn jemand eine bessere Idee für ein Muster oder andere Vorschläge hat wenden Sie sich bitte eine Antwort oder bearbeiten diesen Beitrag zu schreiben.
Meine Lösung:
"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
Dies wird dann in der Statuszeile hinzugefügt von:
:set statusline=wc:%{WordCount()}
Ich hoffe, das jemand für eine Live-Wortanzahl in Vim sucht hilft. Allerdings ist das nicht immer exakt. Alternativ natürlich g ctrl-g werden Sie mit Vim Wort bieten zählen!
Falls jemand anderes hier von Google kommt, modifizierte ich Abslom Daak Antwort auf die Arbeit mit Airline . Ich speicherte die folgenden als
~/.vim/bundle/vim-airline/autoload/airline/extensions/pandoc.vim
und hinzugefügt
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
Eine Variation von Guy Gur-Ari Verfeinerung dass
- zählt nur Worte, wenn die Rechtschreibprüfung aktiviert ist,
- zählt die Anzahl der ausgewählten Wörter im visuellen Modus
- hält stumm außerhalb des Einsatzes und Normalmodus und
- hoffentlich ist Agnostiker auf die Systemsprache (wenn verschieden von Englisch)
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
, die auf die Statuszeile angehängt werden kann, sagen wir,
set statusline+=%.10{StatuslineWordCount()} " wordcount