Bug Description
The end-of-line character (lcs-eol
, $
by default) is displayed at the end of file (EOF), no matter if the file actually ends with a newline.
To Reproduce
echo -n foo > bar
vim --clean bar
:set list
Neither disabling the fixeol
setting (:set nofixeol
), nor starting Vim in binary mode (vim --clean -b bar
) affects this behavior.
Expected behavior
There should be no EOL character (i.e. $
) being displayed.
Environment (please complete the following information):
$ vim --version
VIM - Vi IMproved 8.2 (2019 Dec 12, compiled May 12 2020 02:37:13)
Included patches: 1-716
Modified by team...@tracker.debian.org
Compiled by team...@tracker.debian.org
Huge version with GTK3 GUI. Features included (+) or not (-):
+acl -farsi +mouse_sgr +tag_binary
+arabic +file_in_path -mouse_sysmouse -tag_old_static
+autocmd +find_in_path +mouse_urxvt -tag_any_white
+autochdir +float +mouse_xterm +tcl
-autoservername +folding +multi_byte +termguicolors
+balloon_eval -footer +multi_lang +terminal
+balloon_eval_term +fork() -mzscheme +terminfo
+browse +gettext +netbeans_intg +termresponse
++builtin_terms -hangul_input +num64 +textobjects
+byte_offset +iconv +packages +textprop
+channel +insert_expand +path_extra +timers
+cindent +ipv6 +perl +title
+clientserver +job +persistent_undo +toolbar
+clipboard +jumplist +popupwin +user_commands
+cmdline_compl +keymap +postscript +vartabs
+cmdline_hist +lambda +printer +vertsplit
+cmdline_info +langmap +profile +virtualedit
+comments +libcall -python +visual
+conceal +linebreak +python3 +visualextra
+cryptv +lispindent +quickfix +viminfo
+cscope +listcmds +reltime +vreplace
+cursorbind +localmap +rightleft +wildignore
+cursorshape +lua +ruby +wildmenu
+dialog_con_gui +menu +scrollbind +windows
+diff +mksession +signs +writebackup
+digraphs +modify_fname +smartindent +X11
+dnd +mouse +sound -xfontset
-ebcdic +mouseshape +spell +xim
+emacs_tags +mouse_dec +startuptime +xpm
+eval +mouse_gpm +statusline +xsmp_interact
+ex_extra -mouse_jsbterm -sun_workshop +xterm_clipboard
+extra_search +mouse_netterm +syntax -xterm_save
system vimrc file: "$VIM/vimrc"
user vimrc file: "$HOME/.vimrc"
2nd user vimrc file: "~/.vim/vimrc"
user exrc file: "$HOME/.exrc"
system gvimrc file: "$VIM/gvimrc"
user gvimrc file: "$HOME/.gvimrc"
2nd user gvimrc file: "~/.vim/gvimrc"
defaults file: "$VIMRUNTIME/defaults.vim"
system menu file: "$VIMRUNTIME/menu.vim"
fall-back for $VIM: "/usr/share/vim"
Compilation: gcc -c -I. -Iproto -DHAVE_CONFIG_H -DFEAT_GUI_GTK -pthread -I/usr/include/gtk-3.0 -I/usr/include/at-spi2-atk/2.0 -I/usr/include/at-spi-2.0 -I/usr/include/dbus-1.0 -I/usr/lib/x86_64-linux-gnu/dbus-1.0/include -I/usr/include/gtk-3.0 -I/usr/include/gio-unix-2.0 -I/usr/include/cairo -I/usr/include/pango-1.0 -I/usr/include/fribidi -I/usr/include/harfbuzz -I/usr/include/atk-1.0 -I/usr/include/cairo -I/usr/include/pixman-1 -I/usr/include/uuid -I/usr/include/freetype2 -I/usr/include/libpng16 -I/usr/include/gdk-pixbuf-2.0 -I/usr/include/libmount -I/usr/include/blkid -I/usr/include/glib-2.0 -I/usr/lib/x86_64-linux-gnu/glib-2.0/include -Wdate-time -g -O2 -fdebug-prefix-map=/build/vim-RuXSEA/vim-8.2.0716=. -fstack-protector-strong -Wformat -Werror=format-security -D_REENTRANT -U_FORTIFY_SOURCE -D_FORTIFY_SOURCE=1
Linking: gcc -L. -Wl,-z,relro -Wl,-z,now -fstack-protector-strong -rdynamic -Wl,-export-dynamic -Wl,-E -Wl,-z,relro -Wl,-z,now -Wl,--as-needed -o vim -lgtk-3 -lgdk-3 -lpangocairo-1.0 -lpango-1.0 -lharfbuzz -latk-1.0 -lcairo-gobject -lcairo -lgdk_pixbuf-2.0 -lgio-2.0 -lgobject-2.0 -lglib-2.0 -lSM -lICE -lXpm -lXt -lX11 -lXdmcp -lSM -lICE -lm -ltinfo -lselinux -lcanberra -lacl -lattr -lgpm -ldl -L/usr/lib -llua5.2 -Wl,-E -fstack-protector-strong -L/usr/local/lib -L/usr/lib/x86_64-linux-gnu/perl/5.30/CORE -lperl -ldl -lm -lpthread -lcrypt -L/usr/lib/python3.8/config-3.8-x86_64-linux-gnu -lpython3.8 -lcrypt -lpthread -ldl -lutil -lm -lm -L/usr/lib/x86_64-linux-gnu -ltcl8.6 -ldl -lz -lpthread -lm -lruby-2.7 -lm
$ uname -a
Linux laptop 5.6.0-1-amd64 #1 SMP Debian 5.6.7-1 (2020-04-29) x86_64 GNU/Linux
$ urxvt -h
rxvt-unicode (urxvt) v9.22 - released: 2016-01-23
...
Additional context
The presence of a trailing newline character can be of importance especially in binary mode.
—
You are receiving this because you are subscribed to this thread.
Reply to this email directly, view it on GitHub, or unsubscribe.
P.S. One possible way to have Vim display if a given editfiles ends with an EOL or not is by means of a custom 'statusline' (q.v.) — e.g. by having somewhere in the value of the 'statusline' option something like
%{&eol?"":"[noeol]"}
FWIW, my own 'statusline' is
%<%f %h%m%r%=%k[%{(&fenc==''?&enc:&fenc)}%{(&bomb?',BOM':'')}][U+%04B] %-14.(%l,%c%V%) %P
You may want to use only part of it, and remember that in a :set
command, any space (or vertical bar or backslash) in the option value must be backslash-escaped.
Best regards,
Tony.
—
You are receiving this because you commented.
Thank you both for your fast response!
Gary wrote:
It says that the eol character appears at the end of the line;
it does not say that the eol character represents the EOL sequence.
My point is that the line does not end, but the file. Therefore, the behavior does - to my understanding - not comply to :help lcs-eol
.
Gary wrote:
In the case of the last line of a file that does not end with an EOL sequence, the eol character shows where the text of that line, including white space, ends. By not having the eol character at the end of the last line, the user would lose that information. So I think it's a feature and the intended behavior, not a bug.
Is not the lcs-trail
setting responsible for indicating trailing spaces?
*lcs-trail*
trail:c Character to show for trailing spaces. When omitted,
trailing spaces are blank. Overrides the "space"
setting for trailing spaces.
E.g. setting it to a dot :set listchars:eol:$,trail:.
gives:
My (maybe wrong?) intention is that the window content should represent what will be written to disk, when one executes the write
command. Hence, the lcs-eol
character should be displayed, iff it would be written to disk (i.e. if it is present or if the fixeol
setting is set).
Best, dirdi
—
You are receiving this because you commented.
I want to add two more thoughts:
Gary wrote:
I think there's more than one way to present this information.
Currently there is no representation of this information at all. Always and independent of a buffer's state displaying the lcs-eol
character, does not provide any information to the user. But of course you are right: Not representing it, is in some way a representation.
If one wants to have a character at each EOL, the ~
character - which is already used to represent the EOF - would be a more consistent choice. However, I would prefer to just not display the lcs-eof
character.
Tony wrote:
One possible way to have Vim display if a given editfiles ends with an EOL or not is by means of a custom 'statusline'
In my eyes, the right place to indicate how a file ends, would not be the statusline, but the end of the file. Further, Tony's proposed statusline enhancement would not reflect what will be written, but what was read.
On the other hand, changing the current behavior to the behavior I suggested (and to the documented behavior, as I read it), would most probable not break anything, since - to the best of my knowledge - it is currently not possible to query the presence of the lcs-eol
character at the EOF and hence no vimscript/plugin/etc. is able to rely on it.
Best, dirdi
—
You are receiving this because you commented.
One thing to keep in mind is that Vim is a product of the Unix world, where every line of a file, including the last one, should have an end-of-line marker. This is why the normal behaviour of Vim is to add an end-of-line at the end of a non-binary file if it is missing, and why it will sometimes display a ^M at the end of every line except the last one if every line except the last one end in a CR+LF pair.
Similarly, the cat
(concatenate) program will concatenate the files just as they are, and if one of the files (other than the last one) lacks an EOL on its last line, that line and the first line of the following file will become a single line in the output.
Some programs, and in particular some programs stemming from the DOS/Windows world, regard (erroneously IMHO but I'm not going to enter a flame war about it) the end-of-line sequence not as a line terminator but as a line separator, and if they get a file whose last line is properly terminated they will add an empty line just after that. This is in any case IMHO a lesser evil than failing to separate the last line of one file and the first line of the next file in case of concatenation because the last line of the first file wasn't properly ended.
In any case, it is possible to query Vim for the presence of a proper end-of-line terminator at the end of the present file:
'endofline'
(or 'eol'
) local option is unset, no EOL character was found on the last line when reading the file. This can be tested with if !&eol …
.'binary'
is off and 'fixeol'
on for that file, both of which are the default) Vim will disregard the 'eol'
setting when writing and add a proper EOL anyway. The opposite condition can be tested with if &bin || !&fixeol …
.++bin
modifier (see :help ++opt
) to set 'binary'
locally for this file, thus telling Vim that it is a binary file and that it must not add an EOL at the very end if there isn't one there yet.'fixeol'
option was defined) was to declare that file as binary but that was regarded as "abusing the system". Nowadays it is possible to use :setlocal nofixeol
on that file to tell Vim that a possible missing EOL should not be "fixed".'listchars'
character: the $ (or other character) representing the end of a line cannot be checked for by if
something
== "$"
; but the fact that Vim won't write an EOL at the end of the file can be tested by if !&eol && (&bin || !&fixeol) …
; or the fact that Vim will only write an EOL at the end of the file if it was already there is the condition inside the parenthesis in this last if
statement.Best regards,
Tony.
—
You are receiving this because you commented.
The main purpose of showing $ after the line is to be able to spot any trailing white space. That's an old vi mechanism, it's not going to change.
Since many users find the $ look bad, Vim has added other ways to show trailing spaces.
Having a file not end in a line break is uncommon, Vim considers this a special case and has the 'endofline' option for that. That doesn't show in the text though. Perhaps we can add an item in 'listchars' to show a different character instead of "eol:" when 'endofline' is set.
—
You are receiving this because you commented.
The main purpose of showing $ after the line is to be able to spot any trailing white space. That's an old vi mechanism, it's not going to change.
Since many users find the $ look bad, Vim has added other ways to show trailing spaces.
Having a file not end in a line break is uncommon, Vim considers this a special case and has the 'endofline' option for that. That doesn't show in the text though. Perhaps we can add an item in 'listchars' to show a different character instead of "eol:" when 'endofline' is set.
…or perhaps rather when it is unset, since with 'eol'
set the last line ends just the same way as any other line of that file.
—
You are receiving this because you commented.
Bram wrote:
The main purpose of showing $ after the line is to be able to spot any trailing white space. That's an old vi mechanism, it's not going to change.
Since many users find the $ look bad, Vim has added other ways to show trailing spaces.
Having a file not end in a line break is uncommon, Vim considers this a special case and has the 'endofline' option for that. That doesn't show in the text though. Perhaps we can add an item in 'listchars' to show a different character instead of "eol:" when 'endofline' is set.
I understand that - and please correct me if I am wrong - it is not possible to change the default behavior, because this would "break userspace", so to speak. But it would be possible to add an option to customize the default behavior.
How about this:
lcs-eof
item (eof:c
) to listchars
eol:c
character on a file's incomplete last line,eof:c
was set (e.g. ~
) andeol
option is false and
fixeol
option is false, orbinary
option is trueThis would not conflict with current behavior nor break anything, but enable one to visualize a missing EOL sequence at EOF by configuring the to be implemented lcs-eof
item. Would that be acceptable? If so, I would propose to add the "feature-request" label to this thread.
—
You are receiving this because you commented.
so basically there is no way in Vim to display the actual newline characters that exist in the file
seems like an awful limitation
—
Reply to this email directly, view it on GitHub.
You are receiving this because you commented.
this is basically the same as the previous comment #6119 (comment)
Perhaps propose a PR then?
—
Reply to this email directly, view it on GitHub.
You are receiving this because you commented.
not exactly the same... that comment is proposing to add an extra character to visualize a missing EOF EOL sequence
i'm proposing no visualization at all for a missing EOF EOL sequence. only visually display what actually exists in the data
—
Reply to this email directly, view it on GitHub.
You are receiving this because you commented.
@mmikeww regarding linefeeds, one is already able to "visually display what actually exists in the data" via eol:c
, except for the very last line. If an eof:c
item was implemented, like it was suggested by me earlier (#6119 (comment)), this would also enable one to resemble the behavior you are asking for, by just setting eof:c
to a blank or any other non-printing character.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.
—
Reply to this email directly, view it on GitHub, or unsubscribe.
You are receiving this because you commented.
I have no comment on the EOF character CTRL+Z (from a quick google, ascii 26?). I didn't even know that existed, and don't care how that is handled. Most text files dont have a trailing CTRL+Z from what I've seen.
As far as adding 'noeol' to 'fillchars', here is the problem: Vim does not keep track of the eol status as the file is edited. It only checks it once upon file open. Simply open up a noeol file, use :set eol?
and you'll see 'noendofline', edit the file, save it, Vim auto adds the eol, then use :set eol?
again and Vim will incorrectly report noeol still, even though it was changed and added. I believe Vim needs to keep track of the original eol state of the file, so that it can determine what to do for the existing 'fixeol/nofixeol' setting, and so that shouldn't be changed either I guess
If the 'eol' listchar cannot be changed for backwards compatibility with Vi, thats fine. My point is that then there is no visual way inside Vim to consistently display \n (LF) chars. And the only way to display \r (CR) is to set ff=unix and then you will see ^M
displayed.
It just seems like the easiest and most non intrusive solution is to simply add CR and LF options to listchars and then people can visually see this data, independent of the chosen fileformat
—
Reply to this email directly, view it on GitHub.
You are receiving this because you commented.