【问题标题】:No more messing up whitespace in VIM不再在 VIM 中弄乱空格
【发布时间】:2012-01-09 14:08:10
【问题描述】:

我有一个BufWritePre 钩子添加到我的.vimrc 中,它在保存缓冲区之前修剪尾随空格。在编辑我自己的代码或其他也有始终删除尾随空格的策略的其他人的代码时,这对我来说非常方便。但是,这让我有时会弄乱其他人的空白,这在版本控制中看起来不太好。

我有两个想法,一般来说如何解决这个问题,我都有具体的问题:

选项 1

打开文件后(可能使用BufReadPost钩子),检测文件中是否有尾随空格。如果是,则设置一个缓冲区本地标志来发出信号。如果设置了标志,请在保存前禁用修剪。

这种方法的问题是我似乎不知道如何检测缓冲区中是否有尾随空格。我知道=~,但是如何将缓冲区内容作为字符串获取?或者更好的是,我可以使用/\s+$<cr> 进行搜索,但是如何检查搜索是否成功(如果有命中)?

选项 2(更智能)

如果空白修剪只发生在实际修改的行上会更好。这样我就可以不必关心代码中的尾随空格,但仍然不会弄乱文件的其余部分。这就提出了一个问题:我能否以某种方式获得我添加或修改的行的行号?

我是 Vimscript 的新手,如果有任何提示或提示,我将不胜感激 :)

更新:我现在选择了选项 1:

" configure list facility
highlight SpecialKey term=standout ctermbg=yellow guibg=yellow
set listchars=tab:>-,trail:~

" determine whether the current file has trailing whitespace
function! SetWhitespaceMode()
  let b:has_trailing_whitespace=!!search('\v\s+$', 'cwn')
  if b:has_trailing_whitespace
    " if yes, we want to enable list for this file
    set list
  else
    set nolist
  endif
endfunction

" trim trailing whitespace in the current file
function! RTrim()
  %s/\v\s+$//e
  noh
endfunction

" trim trailing whitespace in the given range
function! RTrimRange() range
  exec a:firstline.",".a:lastline."substitute /\\v\\s+$//e"
endfunction

" after opening and saving files, check the whitespace mode
autocmd BufReadPost  * call SetWhitespaceMode()
autocmd BufWritePost * call SetWhitespaceMode()
" on save, remove trailing whitespace if there was already trailing whitespace
" in the file before
autocmd BufWritePre  * if !b:has_trailing_whitespace | call RTrim() | endif

" strip whitespace manually
nmap <silent> <leader>W :call RTrim()<cr>
vmap <silent> <leader>W :call RTrimRange()<cr>

【问题讨论】:

    标签: linux editor vim


    【解决方案1】:

    选项 1 可以从 search() 函数中受益,如下所示:

    let b:has_trailing_spaces=!!search('\v\s+$', 'cwn')
    

    search() 函数返回匹配的行数(它们从 1 开始),如果没有找到则返回 0,!! 将其变为 1 或 0,删除关于在哪一行 search() 找到尾随空格的信息。没有n 标志search() 移动光标,我猜这是不希望的。如果没有w,它可能只搜索光标之后的缓冲区部分(实际上取决于'wrapscan' 选项)。

    提议的选项 2 实现是使用 InsertLeave'['] 标记的 hack:

    augroup CleanInsertedTrailingSpaces
        autocmd!
        autocmd InsertLeave * let wv=winsaveview() | keepjumps lockmarks '[,']s/\s\+$//e | call winrestview(wv)
    augroup END
    

    它假定您只在键入后添加尾随空格。如果您在插入模式下将光标移过行,它将中断。您也可以尝试添加

        autocmd CursorHold * if getpos("'.")[1]!=0 | let wv=winsaveview() | keepjumps lockmarks '.s/\s\+$//e | call winrestview(wv) | endif
    

    ,这应该删除最后更改行的尾随空格(只有一行,'['] 不能在这里使用,因为它们指向第一行和最后一行通常很有用)。两个自动命令都应该向撤消树添加信息。

    选项 2 有第二个选项:git annotate 能够注释文件的当前状态,因此您可以使用 grep 过滤掉包含尾随空格和未提交更改的行,并使用挂钩清除在提交之前从他们那里得到不需要的空格。很遗憾,但hg annotate 无法做到这一点,因此您将不得不编写更复杂的东西,可能在 python 中。关于其他 VC 系统,我无话可说。

    我想如果您使用set list listchars+=trail:- 来查看此类空格并因此能够在它们意外出现时手动删除它们会更好(我个人不记得自己经常意外添加尾随空格,尽管在 cmets 和我故意使用它们来表明该段继续)。你是怎么做才会出现这个问题的?

    【讨论】:

    • 您对选项 1 的解决方案似乎很好,非常感谢。我认为这暂时就足够了。至于选项 2,您的信息似乎也很方便,也许我可以用它来破解一些东西。我通常不会在插入模式下移动光标(我认为这是 VIM 哲学的一部分)。至于动机:我见过许多开源项目对尾随空格的使用非常不一致。有时它会从文件中完全删除,有时只有部分文件有尾随空格,等等......
    • 我不想在编码时关心空格,我认为这是编辑器处理的任务。但我也不想提交多余的空白更改(特别是如果像你说的那样,它实际上是有意义的)。我会接受这个答案,但首先我想等一下,看看其他人是否对此有任何想法,至少如果你不介意的话。
    • @NiklasBaumstark 你有没有想过在选项 2 中使用 git 钩子(更多信息在最后一段,但我在几分钟前添加了一段)?我个人更喜欢 mercurial,但使用 git this 工作更简单。
    • ZyX:Git hooks 绝对是我用于自己项目的一个选项,但我不希望它依赖于版本控制。
    【解决方案2】:

    我倾向于不让 vim 自动修剪任何东西。正如您所说,如果处理其他人的代码,这可能是一场噩梦,并且可能导致不必要的冲突。为了保持我自己的代码整洁,我采取的方法是让空白可见。使用 vim 可以通过将以下内容添加到您的 ~/.vimrc 文件中来实现:

    highlight SpecialKey ctermfg=DarkGray
    set listchars=tab:>-,trail:~
    set list
    

    结果是这样显示空白:

    这允许我在编写文件时保持文件清洁。大多数其他 (GUI) 编辑器也能够显示空白。

    【讨论】:

    • 我认为这主要是一个品味问题。在我看来,处理空白是一项实际上可以由编辑器执行的任务,从而为我节省了一些不必要的编辑。我知道 listchars 并已启用它,但我不喜欢编辑空格。
    • @NiklasBaumstark:有些人会说这不是品味问题,但是自动执行此操作会将样式更改与其他更改混合在一起,从而弄乱您的提交历史。在某些环境中,这可能违反政策。
    • @honk:这正是我的问题。我希望 VIM 为 我自己的 代码自动处理这个问题,但不要弄乱其余的代码。这样做的效果是我的提交中不会有与空格相关的更改。
    【解决方案3】:
    " Show trailing whitepace and spaces before a tab:
    :highlight ExtraWhitespace ctermbg=red guibg=red
    :match ExtraWhitespace /\s\+$\| \+\ze\t/
    :autocmd ColorScheme * highlight ExtraWhitespace ctermbg=red guibg=red
    

    这样,任何不好的空白都会以红色发光。很难错过。

    【讨论】:

    • 我可以使用 listchars 更轻松,但这不是问题。
    • @NiklasBaumstark:很抱歉。我只是想展示另一种方法。这样您就可以保留列表用于其他目的。如果您一开始就没有在代码中放置任何不需要的空格,则不需要自动修剪。相信我,如果你将它设置为高度可见的颜色,你会自动纠正自己,并很快学会避免它。 ;)
    • 我明白你的意思。感谢您对此的其他想法:)
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-01-13
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多