Hello all:

I know I am entering a minor quagmire by asking about vim "adding" a newline at 
the EOF when saving a file. I'll mention that I know the POSIX standard states 
that a line is "A sequence of zero or more non- <newline> characters plus a 
terminating <newline> character." (from: 
http://pubs.opengroup.org/onlinepubs/9699919799/basedefs/V1_chap03.html#tag_03_206).
 This isn't another post asking why vim writes the newline on save.

The background for my question is that I am trying to submit a pull request for 
the vim-lsp plugin (https://github.com/prabirshrestha/vim-lsp), which provides 
Language Server Protocol support to vim. I was getting some linting errors 
about "no newline at end of file" when using this plugin in vim, but not when 
sending the file directly to the linter and skipping vim in the middle. 

I tracked the issue down to how vim-lsp is sending the contents of the file to 
the Language Server. The Language Server specification has a "didChange" 
message that expects you to send the contents of the file/buffer inside of the 
message. I'm pretty sure you send the contents of the buffer instead of just a 
file path so that you can have linting performed on your buffer even if it 
hasn't been saved to disk.

Ultimately the issue comes down to how we can grab the full contents of a 
buffer. The original code in vim-lsp looks like this:

function! s:get_text_document_text(buf) abort
    let l:buf_fileformat = getbufvar(a:buf, '&fileformat')
    let l:line_ending = {'unix': "\n", 'dos': "\r\n", 
'mac':"\r"}[l:buf_fileformat]
    return join(getbufline(a:buf, 1, '$'), l:line_ending)
endfunction

getbufline is grabbing all of the contents of the buffer and returning a list 
of the lines. Each one of the items in the list does not contain the newline 
character that would be found in the file. This is why the join function is 
used, to insert a fileformat-dependent newline in between each of the lines. 
As-is, the join doesn't append a newline on the last item, which led to the 
linter complaining.

My pull request to fix this attempts to inspect and respect the eol, binary, 
and fixeol options to recreate what would be found on disk:

function! s:requires_eol_at_eof(buf) abort
    let l:file_ends_with_eol = getbufvar(a:buf, '&eol')
    let l:vim_will_save_with_eol = !getbufvar(a:buf, '&binary') &&
                \ getbufvar(a:buf, '&fixeol')
    return l:file_ends_with_eol || l:vim_will_save_with_eol
endfunction

function! s:get_text_document_text(buf) abort
    let l:buf_fileformat = getbufvar(a:buf, '&fileformat')
    let l:eol = {'unix': "\n", 'dos': "\r\n", 'mac': "\r"}[l:buf_fileformat]
    return join(getbufline(a:buf, 1, '$'), l:eol).(s:requires_eol_at_eof(a:buf) 
? l:eol : '')
endfunction 

After staring at :help eol, :help fixeol, and :help binary, I *think* I'm 
recreating the logic that vim uses when deciding to put the newline in the 
file. Basically, eol is set if the file contained the eol on load. The user can 
unset this if they want, but they need to be aware of fixeol as well. Vim will 
attempt to fix a file missing eol at EOF unless the file is loaded with binary 
or the user has set nofixeol. If the user has disabled fixing eol or loaded a 
file as binary, but the file contained the eol at EOF then vim will obviously 
put the eol back.

Does this logic match what we expect vim to do? Is there a different way to get 
the contents of the buffer that includes the newline characters?

Adam

-- 
-- 
You received this message from the "vim_use" maillist.
Do not top-post! Type your reply below the text you are replying to.
For more information, visit http://www.vim.org/maillist.php

--- 
You received this message because you are subscribed to the Google Groups 
"vim_use" group.
To unsubscribe from this group and stop receiving emails from it, send an email 
to [email protected].
For more options, visit https://groups.google.com/d/optout.

Reply via email to