Empty line at EOB

Frank Fischer frank-fischer at shadow-soft.de
Sat Oct 27 14:19:27 CEST 2012


Hi friends of evil,

recently there have been a lot of issues related to the
final-newline/empty-line-at-eob behavior of Emacs. Before I try to fix
those issue and provoke further issues, I would like to discuss the
problem in public.

When Vegard and I discussed this topic some time ago, we pointed out
several advantages and disadvantages of certain approaches to this
problem (see below) and decided for one of them. However, the latest
bug reports make clear this may not be so easy (I had somehow the
feeling at that time that sooner or later someone *will* come up with
bug reports but I hoped that they would be easy to solve -- now I'm
not so sure about the latter anymore). The purpose of this post is to
initiate a discussion about how the problem should be handled in evil.

Let me start with a description of the problem. In the unix world a
line is usually defined as a sequence of characters followed by a
newline character \n. In other words, the newline character is the
termination character of a line. Sequences of characters that do not
end in a newline are therefore *incomplete* or non-proper lines (some
programs even used to refuse working correctly on incomplete lines).
This is also visible in text editors like vim. In vim (in standard
configuration) each line is automatically terminated by newline (when
saved to disk). Furthermore the number of lines in a file is exactly
the number of newlines. If vim opens a file with an incomplete last
line then it appends that newline when saving the file back to disk
(and showing [noeol] in the status bar). But more importantly, it is
*impossible* to move the cursor beyond that last newline. This means
if a file contains "abc\n" vim shows one line and the cursor cannot be
moved to the second line.

Emacs is different. Emacs can also append a missing newline to a
buffer depending on the value of `require-final-newline'. The
difference is that in Emacs it is possible to move point *visually* to
a position after the final newline (point-max) and Emacs shows point
on the next line. Thus, in Emacs one has the *visual* impression that
the file contains one additional line. In some sense, in Emacs the
newline character is rather a line-separator than a line terminator (at
least for the visual impression).

The trouble for evil are commands like "G". Vim moves point to the
last real line, i.e. to a position not behind the final newline. But
Emacs would move point to a position after that final newline, giving
a slightly different impression.

For evil this means that we have two general approaches:

1. Do it the Vim way. This is what we try currently.

   In this approach we do not allow point to be moved to (point-max).
   This is done by adjusting point to the previous line if it is moved
   to point-max (the function `evil-adjust-point' is responsible for
   this). As a result the behavior is closer to Vim's. The downside is
   that a) the behavior is different to Emacs-state and b) it causes
   trouble some modes like eshell, that somehow exploit that the final
   line does not need to end in a newline. Furthermore it is not
   trivial to do the right thing in all cases. In particular some
   Emacs non-evil commands may have problems with evil's
   point-adjustment.

2. Do it the Emacs way.

   In this approach we ignore completely the special handling of the
   final newline. We allow that point is placed on that "additional"
   line. This is of course a lot easier to implement. But it also
   breaks compatibility with vim in a not-so-uncommon situation (e.g.,
   the G command behaves differently and the file always looks as if
   it contains one line more in evil than in vim).

Both approaches have their advantages and disadvantages. But the real
question is, what users want. Is vim compatibility significant in this
situation or can you live with Emacs' behavior?

Please feel free to comment and discuss.

Best regards,
Frank




More information about the implementations-list mailing list