- html - 出于某种原因,IE8 对我的 Sass 文件中继承的 html5 CSS 不友好?
- JMeter 在响应断言中使用 span 标签的问题
- html - 在 :hover and :active? 上具有不同效果的 CSS 动画
- html - 相对于居中的 html 内容固定的 CSS 重复背景?
我一直在努力寻找这个并且无法找到我想要的东西。
在我的状态行上,我想要计算当前文件中出现的匹配数。下面的 vim 命令返回我想要的。我需要返回的号码显示在我的状态行中。
:%s/^I^I//n
:set statusline+= %{s/^I^I//n}
最佳答案
这里首先要提到的是,对于大文件,此功能完全不切实际。原因是状态行在每次光标移动后、每个命令完成后以及可能在我什至不知道的其他事件之后重新绘制。对整个缓冲区执行正则表达式搜索,而且,不仅是当前缓冲区,而且是每个可见窗口(因为每个窗口都有自己的状态行),会显着减慢速度。不要误会我的意思;这个功能背后的想法是一个很好的想法,因为它可以立即和全自动地指示您剩余的工作,但计算机的性能并不是无限的(不幸的是),因此这很容易成为一个问题。我已经编辑过包含数百万行文本的文件,并且在此类缓冲区上进行一次正则表达式搜索可能需要几秒钟的时间。
但是如果您的文件仍然很小,我已经想出了三种可能的解决方案来实现这一目标。
解决方案#1:exe :s 和重定向输出
您可以使用函数中的 :exe
以参数化模式运行 :s
命令,并使用 :redir
将输出重定向到局部变量。
不幸的是,这有两个不受欢迎的副作用,在此功能的上下文中,这将完全破坏交易,因为每次重绘状态行时都会发生它们:
:s
还是通过在 vim 命令行上手动输入它。)getcurpos()
和
setpos()
保存和恢复光标位置来修复光标问题。请注意,它必须是
getcurpos()
而不是
getpos()
因为后者不返回
curswant
字段,这是保留光标“想要”驻留的列所必需的,这可能与光标“实际”所在的列不同(例如,如果光标移动到较短的行中)。不幸的是,
getcurpos()
是 vim 的一个相当新的补充,即 7.4.313,根据我的测试,它甚至似乎无法正常工作。幸运的是,有较旧的
winsaveview()
和
winrestview()
函数可以完美且兼容地完成任务。所以现在,我们将使用这些。
gv
来解决视觉选择问题,但是由于某种原因,在执行此操作时视觉选择会完全损坏。我已经在 Cygwin CLI 和 Windows gvim 上对此进行了测试,但我没有解决方案(关于恢复视觉选择)。
fun! MatchCount(pat,...)
"" return the number of matches for pat in the active buffer, by executing an :s call and redirecting the output to a local variable
"" saves and restores both the cursor position and the visual selection, which are clobbered by the :s call, although the latter restoration doesn't work very well for some reason as of vim-7.4.729
"" supports global matching (/g flag) by taking an optional second argument appended to :s flags
if (a:0 > 1)| throw 'too many arguments'| endif
let flags = a:0 == 1 ? a:000[0] : ''
let mode = mode()
let pos = winsaveview()
redir => output| sil exe '%s/'.a:pat.'//ne'.flags| redir END
call winrestview(pos)
if (mode == 'v' || mode == 'V' || mode == nr2char(22))
exe 'norm!gv'
endif
if (match(output,'Pattern not found') != -1)
return 0
else
return str2nr(substitute(output,'^[\s\n]*\(\d\+\).*','\1',''))
endif
return
endfun
set statusline+=\ [%{MatchCount('\\t\\t')}]
^[\s\n]*
是必要的,以通过重定向期间捕获的前导换行符(不知道为什么会发生这种情况)。另一种方法是使用点原子上的非贪婪乘数跳过任何字符直到第一个数字,即 ^.\{-}
。 statusline
选项值中的反斜杠加倍是必要的,因为在解析选项值本身期间会发生反斜杠插值/删除。一般来说,单引号字符串不会导致反斜杠插值/删除,我们的 pat
字符串一旦被解析,最终会直接与传递给 :s
的 :exe
字符串连接,因此在这些点没有反斜杠插值/删除(至少不是之前的) :s
命令的评估,当我们的反斜杠的反斜杠插值确实发生时,这是我们想要的)。我觉得这有点令人困惑,因为在 %{}
构造中,您希望它是一个普通的纯 VimScript 表达式,但这就是它的工作方式。 /e
命令添加了 :s
标志。这对于处理零匹配的缓冲区的情况是必要的。通常,如果匹配项为零,:s
实际上会抛出错误。对于状态行调用,这是一个大问题,因为在尝试重绘状态行时抛出的任何错误都会导致 vim 取消 statusline
选项,作为防止重复错误的防御措施。我最初寻找涉及捕获错误的解决方案,例如 :try
和 :catch
,但没有任何效果;一旦抛出错误,就会在 vim 源代码 ( called_emsg
) 中设置一个我们无法取消设置的标志,因此 statusline
在那一刻注定要失败。幸运的是,我发现了 /e
标志,它完全防止了错误的抛出。 MatchCount()
函数不会干扰视觉模式:
fun! MatchCount(pat,...)
if (a:0 > 1)| throw 'too many arguments'| endif
let flags = a:0 == 1 ? a:000[0] : ''
let pos = winsaveview()
redir => output| sil exe '%s/'.a:pat.'//ne'.flags| redir END
call winrestview(pos)
if (match(output,'Pattern not found') != -1)
return 0
else
return str2nr(substitute(output,'^[\s\n]*\(\d\+\).*','\1',''))
endif
return
endfun
:s
命令是安全的:
fun! IsVisualMode(mode)
return a:mode == 'v' || a:mode == 'V' || a:mode == nr2char(22)
endfun
fun! BufferCallCache(buf,callName,callArgs,callElseCache)
let callCache = getbufvar(a:buf,'callCache')
if (type(callCache) != type({}))
unlet callCache
let callCache = {}
call UnletBufVar(a:buf,'callCache')
call setbufvar(a:buf,'callCache',callCache)
endif
if (a:callElseCache)
let newValue = call(a:callName,a:callArgs)
if (!has_key(callCache,a:callName.':Args') || !has_key(callCache,a:callName.':Value'))
let callCache[a:callName.':Args'] = []
let callCache[a:callName.':Value'] = []
endif
let i = len(callCache[a:callName.':Args'])-1
while (i >= 0)
let args = callCache[a:callName.':Args'][i]
if (args == a:callArgs)
let callCache[a:callName.':Value'][i] = newValue
return newValue
endif
let i -= 1
endwhile
let callCache[a:callName.':Args'] += [a:callArgs]
let callCache[a:callName.':Value'] += [newValue]
return newValue
else
if (has_key(callCache,a:callName.':Args') && has_key(callCache,a:callName.':Value'))
let i = len(callCache[a:callName.':Args'])-1
while (i >= 0)
let args = callCache[a:callName.':Args'][i]
if (args == a:callArgs)
return callCache[a:callName.':Value'][i]
endif
let i -= 1
endwhile
endif
return ''
endif
endfun
fun! UnletBufVar(bufExpr, varName )
"" source: <http://vim.1045645.n5.nabble.com/unlet-ing-variables-in-buffers-td5714912.html>
call filter(getbufvar(a:bufExpr,''), 'v:key != '''.a:varName.'''' )
endfun
statusline
:
set statusline+=\ [%{BufferCallCache('','MatchCount',['\\t\\t'],!IsVisualMode(mode()))}]
match()
match()
:
fun! MatchCount(pat)
"" return the number of matches for pat in the active buffer, by iterating over all lines and calling match() on them
"" does not support global matching (normally achieved with the /g flag on :s)
let i = line('$')
let c = 0
while (i >= 1)
let c += match(getline(i),a:pat) != -1
let i -= 1
endwhile
return c
endfun
set statusline+=\ [%{MatchCount('\\t\\t')}]
search()
/
searchpos()
searchpos()
和
search()
构建。我还包括对可选开始和结束边界的支持。
fun! GlobalMatchCount(pat,...)
"" searches for pattern matches in the active buffer, with optional start and end [line,col] specifications
"" useful command-line for testing against last-used pattern within last-used visual selection: echo GlobalMatchCount(@/,getpos("'<")[1:2],getpos("'>")[1:2])
if (a:0 > 2)| echoerr 'too many arguments for function: GlobalMatchCount()'| return| endif
let start = a:0 >= 1 ? a:000[0] : [1,1]
let end = a:0 >= 2 ? a:000[1] : [line('$'),2147483647]
"" validate args
if (type(start) != type([]) || len(start) != 2 || type(start[0]) != type(0) || type(start[1]) != type(0))| echoerr 'invalid type of argument: start'| return| endif
if (type(end) != type([]) || len(end) != 2 || type(end[0]) != type(0) || type(end[1]) != type(0))| echoerr 'invalid type of argument: end'| return| endif
if (end[0] < start[0] || end[0] == start[0] && end[1] < start[1])| echoerr 'invalid arguments: end < start'| return| endif
"" allow degenerate case of end == start; just return zero immediately
if (end == start)| return [0,0]| endif
"" save current cursor position
let wsv = winsaveview()
"" set cursor position to start (defaults to start-of-buffer)
call setpos('.',[0,start[0],start[1],0])
"" accumulate match count and line count in local vars
let matchCount = 0
let lineCount = 0
"" also must keep track of the last line number in which we found a match for lineCount
let lastMatchLine = 0
"" add one if a match exists right at start; must treat this case specially because the main loop must avoid matching at the cursor position
if (searchpos(a:pat,'cn',start[0])[1] == start[1])
let matchCount += 1
let lineCount += 1
let lastMatchLine = 1
endif
"" keep searching until we hit end-of-buffer
let ret = searchpos(a:pat,'W')
while (ret[0] != 0)
"" break if the cursor is now at or past end; must do this prior to incrementing for most recent match, because if the match start is at or past end, it's not a valid match for the caller
if (ret[0] > end[0] || ret[0] == end[0] && ret[1] >= end[1])
break
endif
let matchCount += 1
if (ret[0] != lastMatchLine)
let lineCount += 1
let lastMatchLine = ret[0]
endif
let ret = searchpos(a:pat,'W')
endwhile
"" restore original cursor position
call winrestview(wsv)
"" return result
return [matchCount,lineCount]
endfun
fun! LineMatchCount(pat,...)
"" searches for pattern matches in the active buffer, with optional start and end line number specifications
"" useful command-line for testing against last-used pattern within last-used visual selection: echo LineMatchCount(@/,getpos("'<")[1],getpos("'>")[1])
if (a:0 > 2)| echoerr 'too many arguments for function: LineMatchCount()'| return| endif
let start = a:0 >= 1 ? a:000[0] : 1
let end = a:0 >= 2 ? a:000[1] : line('$')
"" validate args
if (type(start) != type(0))| echoerr 'invalid type of argument: start'| return| endif
if (type(end) != type(0))| echoerr 'invalid type of argument: end'| return| endif
if (end < start)| echoerr 'invalid arguments: end < start'| return| endif
"" save current cursor position
let wsv = winsaveview()
"" set cursor position to start (defaults to start-of-buffer)
call setpos('.',[0,start,1,0])
"" accumulate line count in local var
let lineCount = 0
"" keep searching until we hit end-of-buffer
let ret = search(a:pat,'cW')
while (ret != 0)
"" break if the latest match was past end; must do this prior to incrementing lineCount for it, because if the match start is past end, it's not a valid match for the caller
if (ret > end)
break
endif
let lineCount += 1
"" always move the cursor to the start of the line following the latest match; also, break if we're already at end; otherwise next search would be unnecessary, and could get stuck in an infinite loop if end == line('$')
if (ret == end)
break
endif
call setpos('.',[0,ret+1,1,0])
let ret = search(a:pat,'cW')
endwhile
"" restore original cursor position
call winrestview(wsv)
"" return result
return lineCount
endfun
关于search - Vim 状态行 : Word search,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/30769614/
我有 虚拟机 在 马克 & CentOS .所以,我看到人们在写 -xterm_clipboard , -lua , ... 有没有一种简单的方法来安装它?或者我们必须一个一个地启用选项并编译/重新编
默认情况下,Vim 在 ~/.vim 中寻找插件和其他东西。 有没有办法告诉 Vim 在 ~/.other_folder 中搜索插件等,并强制它完全忽略 ~/.vim? 最佳答案 Vim 使用来自 '
我正在尝试处理一系列文件。我注意到从命令行(即 ex 模式)运行特定命令时存在差异。例如。 $cat poo.txt big red dog small black cat $vim -c "2,$g
我正在尝试将所有与 vim 相关的文件/插件整合到 ~/.vim 中文件夹,以便我可以将其转储到 github 并开始使用病原体。但是,现在我所有的 vim 插件都散落在各处。 例如,语法插件在 /u
所以我的 ~/.vimrc 文件中的设置正确设置 set mouse=a set ttymouse=xterm2 但是,当我使用 vim 并尝试使用鼠标滚轮滚动时,命令提示符上的滚动条会移动,而不是
我试图尝试 vim 在启动时加载的自动加载文件。我将 example.vim 文件保存在: ~/.vim/autoload/ 目录并编写了一个非常简单的函数: echom "Autoloading..
这个问题已经有答案了: How can you check which options vim was compiled with? (3 个回答) 已关闭 7 年前。 我在多台计算机上使用相同的 V
我需要将一些设置和变量写入一些文本文件以供以后检索。检索文件可以是一个简单的源命令。那么从 vimscript 写入文件的最简单方法是什么? 我只想存储一些全局变量。全局的,因为它们将被多个缓冲区使用
如何使 vim 列(:set 光标列)具有不同的颜色?这是我现在看到的: 请注意,列颜色与 vim 用于标记我的身份等的颜色相同(我认为是背景颜色)。我想选择不同的颜色。 干杯:) 最佳答案 使用这个
我试图尝试 vim 在启动时加载的自动加载文件。我将 example.vim 文件保存在: ~/.vim/autoload/ 目录并编写了一个非常简单的函数: echom "Autoloading..
我正在修改已安装的 VIM 插件,并在另一个终端选项卡中测试结果。每次我想测试更改时,我都必须重新启动 VIM。 有没有更快的方法来完成这个过程?如何在 VIM 启动后重新加载 VIM 插件? 插件是
一个简单的例子: function! Foo() echom 'Starting Foo' let x = Bar(123) " Function does not exist so
有没有办法让 Vim 像带有 explorer 插件的 notepad++ 或 pspad、ultraedit 和 editplus 等其他文本编辑器一样工作? 也就是 保持文件浏览器始终在左侧(左侧
经过多次谷歌搜索后,我无法使 Vim 的代码隐藏功能与 Javascript 和 Typescript 一起使用(无需插件)。 我一直在尝试在我的 .vimrc 中使用如下行来隐藏我的代码,但没有任何
我有以下问题:在 Pycharm 中试验 vim 宏时(我使用的是 Idea Vim 插件)- 我输入了一个简单的宏并让编辑器运行它 100 次。执行速度非常慢,我无法使用 these 中的任何一个来
如何在 vim 中将字符串(4000 到 4200)替换为(5000 到 5200).. 最佳答案 另一种可能性: :%s/\v/5\1/g 这个也能做 200 次,而且由于使用了 \v switch
示例:我有一些文本,比如这个 php 代码 if(empty($condition)) { // work here... } 我的默认寄存器包含字符串“$NewCondition”。 我想将
有时我想在当前缓冲区上应用一些自定义的额外语法突出显示。 如何使用内置的 vim 语法/高亮系统来完成(我不想使用 Highlight 插件) 例如,我想突出显示当前缓冲区中的所有断言语句。 最佳答案
我有一个ora文件,它的长度为200,000行,但最后60,000行的某些行都是空白回车/空格。 我知道G会跳到文件末尾,但是我是否将vim配置为跳到非空格和非回车符的最后一行或字符? 最佳答案 G?
我想在退出vim后看到屏幕原来的内容就像打开文件之前一样,我的文件不是退出而是原始显示不存在 谢谢 最佳答案 在运行全屏应用程序后返回屏幕内容与将内容保留在那里的功能并不特定于 vi,而是特定于您的终
我是一名优秀的程序员,十分优秀!