340

So I work in a PHP shop, and we all use different editors, and we all have to work on Windows. I use vim, and everyone in the shop keeps complaining that whenever I edit a file there is a newline at the bottom. I've searched around and found that this is a documented behavior of vi & vim... but I was wondering if there was some way to disable this feature. (It would be best if I could disable it for specific file extensions).

If anyone knows about this, that would be great!

codeforester
  • 39,467
  • 16
  • 112
  • 140
Boushley
  • 6,816
  • 4
  • 27
  • 29
  • 41
    you should tell them they're being silly -- there's actually a good reason why vim does that: http://stackoverflow.com/questions/729692/why-should-files-end-with-a-newline . I guess it's only relevant if you're deploying on unix-like servers, though. – hdgarrood Mar 04 '13 at 16:46
  • 7
    The official PHP recommended practice is to omit the last `?>` closing tag, just for this reason. – Sebastián Grignoli Apr 15 '13 at 18:58
  • this question probably predates superuser... but it should be there. – gcb Oct 22 '13 at 00:03
  • 35
    The question really should be: How do we tell all of the other editors that people in your shop are using to ensure the last line of the file *does* end with an EOL. ;-) – T.J. Crowder Jul 15 '14 at 11:21

14 Answers14

498

And for vim 7.4+ you can use either of these (preferably on your .vimrc) (thanks to 罗泽轩 for that last bit of news!):

:set nofixeol
:set nofixendofline

Now regarding older versions of vim.

Even if the file was already saved with new lines at the end:

vim -b file and once in vim:

:set noeol
:wq

done.

alternatively you can open files in vim with :e ++bin file

Yet another alternative:

:set binary
:set noeol
:wq

see more details at Why do I need vim in binary mode for 'noeol' to work?

wisbucky
  • 33,218
  • 10
  • 150
  • 101
gcb
  • 13,901
  • 7
  • 67
  • 92
  • 8
    You also can add `set binary` and `set noeol` in your .vimrc – Rey0bs Sep 04 '14 at 12:59
  • 22
    **Beware**: `binary` overrides `expandtab`, which will lead you to get literal tabs in your source. – Ciro Santilli OurBigBook.com Feb 13 '15 at 10:32
  • 5
    @CiroSantilli thank you! i've been looking for side effects of binary forever and wondering why it is not the default! since i love my tabs, i think i will consider that added benefit :) – gcb Mar 13 '15 at 18:09
  • 13
    Now you could add `set nofixendofline` to solve the problem in Vim 7.4+ – 罗泽轩 Jun 24 '17 at 16:38
  • @gcb so let me get this right... for clarification. you are saying that vim always makes sure there is a newline character at the end of the file. even when it doesn't visually display the newline character? – Trevor Boyd Smith Oct 05 '18 at 16:27
  • 1
    @TrevorBoydSmith yes, because historically POSIX (i might be wrong on the actual standard) expect a new line at the end of a line, in a text file. That's why most solutions required treating it as a binary. It probably was very convenient then, and It's backward today, that's why now there's the convenient setting. Just add it to your vimrc. There are worse problems in other editors anyway :) – gcb May 02 '19 at 01:42
  • I'm confused; why set `binary` _and_` noeol`? – Kyle Strand Oct 30 '19 at 15:36
  • ...ah, I see, `nofixendofline` preserves but does not add eof newlines, but `noeol` will remove eof newlines from text files but _not_ binary files. – Kyle Strand Oct 30 '19 at 15:38
  • On my Ubuntu's *vim 8.1*, on an existing file, just doing `set noeol` had no effect, had to also do `set binary`, like your last suggestion. – Nagev Feb 13 '20 at 10:28
  • Also tried adding just one or both to "~/.vimrc" but none of the combinations worked for new files... – Nagev Feb 13 '20 at 10:50
24

Add the following command to your .vimrc to turn off the end-of-line option:

autocmd FileType php setlocal noeol binary fileformat=dos

However, PHP itself will ignore that last end-of-line - it shouldn't be an issue. I am almost certain that in your case there is something else which is adding the last newline character, or possibly there is a mix-up with Windows/Unix line ending types (\n or \r\n, etc).

Update:

An alternative solution might be to just add this line to your .vimrc:

set fileformats+=dos
Jens
  • 69,818
  • 15
  • 125
  • 179
too much php
  • 88,666
  • 34
  • 128
  • 138
  • I know that php isn't parsing it wrong... I've shown that to my coworkers, but winmerge sees them as being different... I'll try that and let you know how it turns out. – Boushley Jul 02 '09 at 02:35
  • Doing this has the desired affect of no final line, but it also converts the file to unix line endings... (even on a windows box)... So I had done that before by switching into binary mode... but then the line endings don't show up write in notepad... everything is just one line. – Boushley Jul 02 '09 at 02:39
  • Unfortunately neither of those suggestions work. Adding the fileformat=dos to the autocmd has no effect, and set filetype+=dos still adds the trailing \n – Boushley Jul 02 '09 at 15:52
  • Sorry, I got that wrong, use 'set filetypes+=dos', not 'set fileformats...' – too much php Jul 02 '09 at 23:35
20

There is another way to approach this if you are using Git for source control. Inspired by an answer here, I wrote my own filter for use in a gitattributes file.

To install this filter, save it as noeol_filter somewhere in your $PATH, make it executable, and run the following commands:

git config --global filter.noeol.clean noeol_filter
git config --global filter.noeol.smudge cat

To start using the filter only for yourself, put the following line in your $GIT_DIR/info/attributes:

*.php filter=noeol

This will make sure you do not commit any newline at eof in a .php file, no matter what Vim does.

And now, the script itself:

#!/usr/bin/python

# a filter that strips newline from last line of its stdin
# if the last line is empty, leave it as-is, to make the operation idempotent
# inspired by: https://stackoverflow.com/questions/1654021/how-can-i-delete-a-newline-if-it-is-the-last-character-in-a-file/1663283#1663283

import sys

if __name__ == '__main__':
    try:
        pline = sys.stdin.next()
    except StopIteration:
        # no input, nothing to do
        sys.exit(0)

    # spit out all but the last line
    for line in sys.stdin:
        sys.stdout.write(pline)
        pline = line

    # strip newline from last line before spitting it out
    if len(pline) > 2 and pline.endswith("\r\n"):
        sys.stdout.write(pline[:-2])
    elif len(pline) > 1 and pline.endswith("\n"):
        sys.stdout.write(pline[:-1])
    else:
        sys.stdout.write(pline)
Community
  • 1
  • 1
Amir
  • 631
  • 6
  • 17
  • That's a great solution... although unfortunately I was not using git. I was using svn, although I suspect a similar approach could have been taken. Anyways, I've moved on from that position and don't have to worry about that anymore :) – Boushley Jul 14 '11 at 03:42
13

I have not tried this option, but the following information is given in the vim help system (i.e. help eol):

'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 option. 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 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.

You may be interested in the answer to a previous question as well: "Why should files end with a newline".

Community
  • 1
  • 1
Tim Henigan
  • 60,452
  • 11
  • 85
  • 78
  • I also had come across the eol setting... but it does not accomplish this task. It is more of a variable that determines whether one has already been placed at the end of the file or not. Also, it has no effect on text files, but only on binary files. – Boushley Jun 26 '09 at 21:18
  • 3
    The vim help also says "When 'binary' is off the value is not used when writing the file." about eol – Boushley Jun 27 '09 at 02:28
  • 1
    +1 for VonC's answer on that question, which highlights that "newline" and EOL are being conflated. Inferior editors *incorrectly display* an extra newline because of an EOL, vim is not adding a "newline"! – ches May 28 '12 at 08:38
10

I've added a tip on the Vim wiki for a similar (though different) problem:

http://vim.wikia.com/wiki/Do_not_auto-add_a_newline_at_EOF

Jo Liss
  • 30,333
  • 19
  • 121
  • 170
  • 5
    “Vim 7.4.785 adds the `fixeol` option that can be disabled to automatically preserve any missing EOL at the end of the file. This script becomes uneccessary for Vim 7.4.785 and later.” (Source: the same wiki page.) Thanks, I was not aware of that new option. – Amir Aug 04 '16 at 09:21
  • 3
    I had to set both `noeol` and `nofixeol` to achieve the desirable result. – selurvedu Sep 08 '16 at 21:51
8

OK, you being on Windows complicates things ;)

As the 'binary' option resets the 'fileformat' option (and writing with 'binary' set always writes with unix line endings), let's take out the big hammer and do it externally!

How about defining an autocommand (:help autocommand) for the BufWritePost event? This autocommand is executed after every time you write a whole buffer. In this autocommand call a small external tool (php, perl or whatever script) that strips off the last newline of the just written file.

So this would look something like this and would go into your .vimrc file:

autocmd!   "Remove all autocmds (for current group), see below"
autocmd BufWritePost *.php !your-script <afile>

Be sure to read the whole vim documentation about autocommands if this is your first time dealing with autocommands. There are some caveats, e.g. it's recommended to remove all autocmds in your .vimrc in case your .vimrc might get sourced multiple times.

Blixtor
  • 337
  • 1
  • 3
  • Well... I was hoping that there was a better solution than this... but this definitely works! – Boushley Jul 03 '09 at 04:41
  • 3
    This works great! Yay! However I have one question... is there a way to make it so I don't have to hit enter twice after each save. I have to hit enter in the cmd window that popped up and then again because vim is telling me the script returned successful... Any way to just make them all go away? – Boushley Jul 08 '09 at 21:02
  • 2
    To avoid the prompts just prefix the command with `silent`. E.g. `silent !your-script `. – dash-tom-bang Jan 08 '13 at 06:41
6

I've implemented Blixtor's suggestions with Perl and Python post-processing, either running inside Vim (if it is compiled with such language support), or via an external Perl script. It's available as the PreserveNoEOL plugin on vim.org.

Ingo Karkat
  • 167,457
  • 16
  • 250
  • 324
  • I haven't tested it thoroughly, but that does seem like a better solution. – Boushley Aug 17 '13 at 11:06
  • Plugin works, but after installation I had to put `let g:PreserveNoEOL = 1` into my `.vimrc` file! Had to learn vimscript to figure that out from plugin description! :D – DarthVanger Oct 05 '16 at 07:37
  • 1
    @DarthVanger: `:help PreserveNoEOL-usage` would have told you, too. RTFM :-) – Ingo Karkat Oct 05 '16 at 10:08
  • @IngoKarkat Oh, sorry. Was looking for this under `INSTALLATION` and `CONFIGURATION`. Didn't even notice the `USAGE` section in description, because it's above the installation :) – DarthVanger Oct 05 '16 at 11:06
6

Starting with vim v7.4 you can use

:set nofixendofline

There is some information about that change here: http://ftp.vim.org/vim/patches/7.4/7.4.785 .

Victor Yarema
  • 1,183
  • 13
  • 15
3

Maybe you could look at why they are complaining. If a php file has a newline after the ending ?>, php will output it as part of the page. This is not a problem unless you try to send headers after the file is included.

However, the ?> at the end of a php file is optional. No ending ?>, no problem with a newline at the end of the file.

Ken
  • 111
  • 5
  • 2
    You are correct, but we as a shop decided that it looks better to have the ending ?> I know we could stop using it... but I'ld prefer to adjust my editor to fit my coding style than the other way around. – Boushley Jun 28 '09 at 20:50
  • 1
    Also, so you know php will automatically parse your ending tag as ?> or as ?>\n (because in linux all valid files should end with a \n)... So my code doesn't cause these problems... they just don't like the look. – Boushley Feb 05 '10 at 19:42
2

Try to add in .vimrc

set binary
IvanM
  • 2,913
  • 2
  • 30
  • 30
2

I think I've found a better solution than the accepted answer. The alternative solutions weren't working for me and I didn't want to have to work in binary mode all the time. Fortunately this seems to get the job done and I haven't encountered any nasty side-effects yet: preserve missing end-of-line at end of text files. I just added the whole thing to my ~/.vimrc.

Jay Paroline
  • 2,487
  • 1
  • 22
  • 27
1

Would it be possible for you to use a special command for saving these files?

If you do :set binary, :w and :set nobinary the file will be written without newline if there was none to start with.

This sequence of commands could be put into a user defined command or a mapping, of course.

Blixtor
  • 337
  • 1
  • 3
  • Unfortunately because I'm working with windows, if I save it in binary mode, it forces the save to be in unix mode. Even when I do :set binary :set fileformat=dos :w :set nobinary Once I quit, it saved the file in unix format... I can't believe that there isn't some way to just turn this off. – Boushley Jul 01 '09 at 16:05
0

I found this vimscript plugin is helpful for this situation.

Plugin 'vim-scripts/PreserveNoEOL'

Or read more at github

Alan Dong
  • 3,981
  • 38
  • 35
0

in neovim, you can use

vim.opt.fixendofline = false

in lua config file

Fedor
  • 17,146
  • 13
  • 40
  • 131