为什么我需要在二进制模式下使用vim才能使'noeol'生效?

52
这个问题是针对我用于“在vim中保存文件时不强制添加文件末尾的换行符”的解决方法的后续问题。
基本上,我不能在我的.vimrc中使用set noeol,因为它什么也没有做!
但是如果我在二进制模式下编辑文件(vim -b file而不是vim file),它会按照它应该做的去执行。
为什么呢?
有没有办法在.vimrc中设置一个简单的首选项,以便在编辑每个文件时都不添加新行?
另外,如果我开始在二进制模式下编辑每个文件,会遇到什么问题?到目前为止,我还没有看到任何区别。
4个回答

118

Vim在文件末尾添加的是“newline”字符,它不应该与“new line”混淆。

“newline”字符或更精确地说是“行尾”字符(<EOL>),意思是“这个点之后的所有内容都应被视为另一行”。按照这种解释方式,<EOL>是一行的终止符,因此文件的最后一行实际上是具有<EOL>的最后一行。

问题在于,大多数编辑器和 IDE 有不同的解释方式——<EOL>是一行的分隔符——并且逻辑上默认在新文件的最后一行不加<EOL>,而且当它们遇到<EOL>时,在真正的最后一行之后添加一个多余的“new line”。

简言之,Vim没有添加“new line”,其他编辑器将它错误地解释为“new line”。

但您可以通过以下方法解决这个问题:在编写文件之前,使用:set binary noeol命令,如果您希望它保持“<EOL>”的状态,则可以实现无"<EOL>"。

然而,:h 'binary'详细讲述了:set binary的危险性,因此我认为始终打开它听起来不是一个好主意。

为了说明不同的行为,当您尝试连接两个带有<EOL>的文件时会发生什么:

$ cat file1    $ cat file2         $ cat file1 file2

lorem ipsum    Le tramway jaune    lorem ipsum
dolor sit      avance lentement    dolor sit
amet           dans le             amet
                                   Le tramway jaune
                                   avance lentement 
                                   dans le

当您尝试连接两个文件而没有使用<EOL>时,会发生以下情况:

$ cat file1    $ cat file2         $ cat file1 file2

lorem ipsum    Le tramway jaune    lorem ipsum
dolor sit      avance lentement    dolor sit
amet           dans le             ametLe tramway jaune
                                   avance lentement 
                                   dans le

第一种行为是某种程度上预期的行为,这也是Vim和许多(如果不是大多数)UNIX-style程序默认采用“结束符”解释并在最后一行添加一个<EOL>字符的原因。

下面的图片显示了一个使用nano创建并含有<EOL>的简单文件(在Vim中也是相同的),并在Eclipse、TextMate、Sublime Text、Vim、Xcode和TextEdit中打开。

<EOL>

(编辑) 这个文件中没有第4行,而且唯一正确显示该文件的编辑器是Vim。行号列的唯一目的是提供缓冲区信息。在只有3行的地方显示4行是一个严重的错误。(编辑结束)

这张图片展示了另一个简单的没有<EOL>的文件,使用Sublime Text创建并在相同的编辑器/IDE中打开。

No <EOL>


12
感谢你对EOL出色解释的点赞。但问题在于如何控制它。我希望自己做决定,而不是让vim来处理。 - gcb
2
比“set binary noeol”更好的是“setl binary noeol”。 - bdesham
3
根据上下文,我会倾向于将其视为某种类型的数据流或格式不正确的文件。 - romainl
3
有没有相反的问题:为什么一些编辑器在文件末尾显示空白行? - Nathan Hinchey
3
我坚定地认为在EOF时需要EOL作为行终止符(经常使用Vim)。然而,为了扮演魔鬼的代言人:如果其他编辑器在最后一个EOL之后没有显示空行,用户如何定位光标以添加该EOL之后的行呢?这对于TextEdit尤其如此。对于TextMate,如果文件只有3行,可能会在“3”下方出现一个灰色方块,直到用户开始输入,此时它变成“4”,第四个EOL将自动添加。 - Kelvin
显示剩余13条评论

25
从版本7.4.785开始,Vim具有fixendofline设置。您可以避免使用binary(它具有一些副作用),并简单地设置。
set noendofline
set nofixendofline

5
根据vimdoc的说明,noeol在未开启binary模式时不起作用。
            *'endofline'* *'eol'* *'noendofline'* *'noeol'*
'endofline' 'eol'   boolean (default on)
            local to buffer
            {not in Vi}
    When writing a file and this option is off and the 'binary' option
    is on, no <EOL> will be written for the last line in the file.  This
    option is automatically set when starting to edit a new file, unless
    the file does not have an <EOL> for the last line in the file, in
    which case it is reset.  Normally you don't have to set or reset this
    voption.  When 'binary' is off the value is not used when writing the
    file.  When 'binary' is on it is used to remember the presence of a
    <EOL> for the last line in the file, so that when you write the file
    the situation from the original file can be kept.  But you can change
    it if you want to.

唯一的实际答案。虽然@mrajner的回答更有用 :) - akostadinov

3

我在 .vimrc 文件中设置了一个简单的偏好,不会在我编辑每个文件时添加新行

您可以使用我的PreserveNoEOL插件来实现这一点。 通过这个简单的设置,您就完成了;或者,您也可以根据需要影响每个缓冲区:

:let g:PreserveNoEOL = 1

有趣的想法,但是你的代码不是很容易添加到我的vimrc中 :) 而且我也不太喜欢它的工作方式。它仍然不能给我实用的控制。我可能会尝试让它更简单,并且只在文件有EOL时添加一个新行,在缓冲区带有换行符时才保存它。你的代码整洁并且注释充分,将是一个不错的起点! - gcb
好的,你只需要像安装其他插件一样安装它。我不完全理解你的批评;如果你设置 let g:PreserveNoEOL = 1,它应该“只是工作”,即保留没有尾随 EOL 的现有文件,并将所有其他(常规)文件保持不变。无论如何,它是开源的,所以你可以自由地(重新)使用任何你认为合适的东西。我也乐意接受通过电子邮件的一般反馈和建议。 - Ingo Karkat
1
当你只在一台机器上工作时,一切都很好。但是我每天在工作中使用2到12台不同的机器。即使复制我的bashrcvimrc也已经很麻烦了 :/ 我只能学会没有插件的生活。这并不是对你工作的批评,只是说我不幸不能拥有这种奢侈。 - gcb

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