有没有一种方法可以配置vimdiff以忽略所有空格?

81

我使用vim -d file1 file2来查看它们之间的差异。这很好用,但我想忽略空格变化-对于源代码文件来说它们是无关紧要的。

Vim帮助文档说明以下命令可以实现这一点:

set diffopt+=iwhite
但不幸的是,这个命令只在 diff 工具的命令行中添加-b,而且只忽略行末空格。正确的命令行关键字应该是-w,以忽略所有空格更改。但我找不到如何直接从 Vim 修改diff 命令行。当然,我可以编译自定义 diff,或者用 diff.sh 替换 diff,但那看起来有点丑 :(

有没有更好的方法修改 Vim 与 diff 工具交互以显示文件之间的差异?

6个回答

43
更新:截至补丁8.1.0393(2018-09-15),diffopt可以忽略所有空白字符。
set diffopt+=iwhiteall

如果你想要完全的向后兼容性,就按照这样的方式实现:
if exists('&diffopt')
  if has("patch-8.1.0393")
    set diffopt+=iwhiteall
  else
    set diffopt+=iwhite
    function DiffW()
      let opt = ""
       if &diffopt =~ "icase"
         let opt = opt . "-i "
       endif
       if &diffopt =~ "iwhite"
         let opt = opt . "-w "
       endif
       silent execute "!diff -a --binary " . opt .
         \ v:fname_in . " " . v:fname_new .  " > " . v:fname_out
       redraw
    endfunction
    set diffexpr=DiffW()
  endif
endif

我从diffexpr文档中借用了这个函数,将-b改为-w并添加了一个redraw命令,以确保屏幕立即重绘,而不是等待用户按下Enter键。
在我努力改进vim的差异功能的相关任务中,我发现了耐心差异支持,我一直想玩弄diffchar插件

10
这个答案应该被接受,因为目前它是唯一正确的。很遗憾vim没有一个简单的选项可以在“diff -b”和“diff -w”之间切换,这两者都不太有用。 - farnsy
1
我的 vim(版本8,Debian Stretch)在执行 :diffupdate 后会闪烁并显示空白屏幕,只有在执行 PageUpPagDown 后才会重新绘制正确的屏幕。非常奇怪... - DrBeco
@DrBeco:这不是解决问题的正确场所,但我建议您首先尝试在gvim中查看是否存在该问题(假设您有GUI)。如果没有,请尝试使用其他终端仿真器或不同的$TERM定义(如“xterm-color”或“xterm-256color”甚至只是“xterm”)。否则,我建议您搜索网络,如果仍无法解决问题,则可以在vi.SE上搜索并提问。对于解决方法,Ctrl+L可能有效。也可以尝试更改语法高亮设置。 - Adam Katz
它在我的vimdiff中没有起作用。结果就像只执行了set diffopt+=iwhite一样。 - ka3ak
@ka3ak - 确保你能够从命令行运行 diff -a --binary -i -w FILE1 FILE2 并且它可以按照你的意愿处理空格。如果可以,或许尝试使用该 diff 命令的绝对路径。如果你需要进一步帮助,在 vi.SE 上提出详细问题将更有助于你得到所需的帮助;在这类网站上缺乏详细信息的评论是无法帮助你解决问题的,你需要提问。 - Adam Katz

32

是的。像你所做的那样设置iwhite选项,但另外将diffexpr设为空。

vim文档的相关部分:

iwhite

忽略空格数量的变化。如果diffexpr为空,则向“diff”命令添加“-b”标志。有关此操作的详细信息,请参阅“diff”命令的文档。它应该忽略添加尾随空格,而不是前导空格。

还要注意,您可以通过设置diffexpr来提供自定义的diff命令行。请参见vimdiff手册中的讨论,特别是:

diffexpr为空时,Vim使用此命令查找文件1和文件2之间的差异:

diff file1 file2 > outfile

10
这不会忽略所有的空格(diff 中的 -w),而是实现了对空格变化的忽略(diff 中的 -b)。 - Dave Johansen

21

谢谢ire,这很有帮助。我现在只需要将以下内容(比Adam K建议的更简单)添加到我的~/.vimrc文件中:

set diffopt+=iwhite

set diffexpr=""

它可以做到这一点......这仍然是我知道的最强大的差异工具,比任何其他工具都要好得多。


7
不,这个实现是 diff -b,而不是问题所要求的 diff -w。Adam K 的回答是唯一正确的答案。 - farnsy
谢谢!只需“set diffopt+=iwhite”即可有用,因为它可以从vimdiff本身交互式地发出。 - Alexey Polonsky

12

我知道这是一个古老的问题,但对于像我这样不知道的人,现在可以使用以下命令:

:set diffopt+=iwhiteall

如果'diffexpr'为空,则向"diff"命令添加"-w"标志。

请参见:h 'diffopt'


+= 运算符会简单地将内容添加到现有内容中,而不管它是否为空(参见 :help +=)。它不要求值在之前为空。我认为 vim 没有像 ||= 这样的运算符,所以根据您描述的逻辑,应该使用 if (&diffopt == "") | set diffopt=iwhiteall | endif - Adam Katz
@AdamKatz 确实,+= 无条件地将 "iwhiteall" 添加到 'diffopt' 中,但根据 :h 'diffopt' 的说明,只有当 "diffexpr" 为空时,"iwhiteall" 才会将 "-w" 添加到 "diff" 命令中。 - undefined
如果diffexpr不为空,则它是一个自定义函数,并且不能保证它将遵守diffopt的任何值。我的回答中的备用实现演示了一个能够识别一些diffopt值的diffexpr。然而,你是对的:我误读了你对diffexpr的引用,以为是diffopt - undefined

2

如果您在执行set diffopt+=iwhite时遇到“无效参数”的问题,请尝试不带+,像这样:

set diffopt=iwhite

然而,更加健壮的方法是在保留现有选项的同时设置忽略空格。但要注意,"无效参数"错误很可能是由于其中一个现有选项不受支持所引起的。在我的情况下,是"internal"选项导致了这个问题,因此我需要按照以下顺序设置选项:
set diffopt-=internal
set diffopt+=iwhite

或者将以下内容添加到您的 .vimrc 文件中:

if &diff
    set diffopt-=internal
    set diffopt+=iwhite
endif

Credit to https://www.micahsmith.com/blog/2019/11/fixing-vim-invalid-argument-diffopt-iwhite/

0

针对Adam Katz解决方案评论中提出的问题:

根据用户的vim版本和设置,silent命令在发出后可能会忽略重新绘制屏幕。我也遇到了这个问题,每当我在使用建议的diffexpr后执行:diffo时就会出现这个问题。我的解决方案是将静默执行命令更改为以下内容:

silent execute "!diff -a --binary " . opt .
 \ v:fname_in . " " . v:fname_new .  " > " . v:fname_out | redraw!

该命令被执行后会强制重新绘制。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接