Функция быстрого подсчета слов в Vim - PullRequest
34 голосов
/ 22 сентября 2008

Я пытаюсь отобразить количество живых слов в строке состояния vim. Я делаю это, устанавливая мою строку состояния в моем .vimrc и вставляя в нее функцию. Идея этой функции - вернуть количество слов в текущем буфере. Этот номер затем отображается в строке состояния. Это должно работать хорошо, так как строка состояния обновляется практически при каждой возможной возможности, поэтому счетчик всегда будет оставаться «живым».

Проблема в том, что функция, которую я сейчас определил, медленная, и поэтому vim явно медлительн, когда используется для всех, кроме самых маленьких файлов; из-за того, что эта функция выполняется так часто.

Итак, есть ли у кого-нибудь умный способ создать функцию, которая невероятно быстро вычисляет количество слов в текущем буфере и возвращает результат?

Ответы [ 13 ]

1 голос
/ 09 мая 2010

Я взял большую часть этого на страницах справки 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()}

Я уверен, что это может быть кем-то исправлено, чтобы сделать его более vimmy (s: n вместо просто n?), Но я считаю, что базовая функциональность есть.

Edit:

Глядя на это снова, мне очень нравится решение Микаэля Янссона. Я не люблю обстреливать wc (не переносимый и, возможно, медленный). Если мы заменим его UpdateWordCount функцию на код, который я имел выше (переименовав мою функцию в UpdateWordCount), то я думаю, что у нас есть лучшее решение.

0 голосов
/ 03 июля 2014

В случае, если кто-то еще приходит сюда из Google, я изменил ответ Абслома Даака для работы с Авиакомпания . Я сохранил следующее как

~/.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
0 голосов
/ 23 сентября 2008

Используя метод в ответе Стива Мойера, я смог найти следующее решение. Боюсь, это довольно нелегкий взлом, и я чувствую, что должно быть более точное решение, но оно работает и намного быстрее, чем просто подсчет всех слов в буфере каждый раз, когда строка состояния обновляется. Следует также отметить, что это решение не зависит от платформы и не предполагает наличие в системе «wc» или чего-то подобного.

Мое решение не обновляет буфер периодически, но ответ, предоставленный Микаэлем Янссоном, сможет обеспечить эту функциональность. Я еще не нашел случая, когда мое решение стало не синхронизированным. Однако я только кратко проверил это, поскольку точное количество слов в реальном времени не является необходимым для моих нужд. Шаблон, который я использую для сопоставления слов, также прост и предназначен для простых текстовых документов. Если у кого-то есть идея для шаблона или любые другие предложения, пожалуйста, не стесняйтесь оставлять ответ или редактировать это сообщение.

Мое решение:

"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!

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...