emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Various simple.el patches


From: Luc Teirlinck
Subject: Re: Various simple.el patches
Date: Tue, 20 May 2003 22:12:04 -0500 (CDT)

There are still problems with the present version of `kill-whole-line'.
Start out with:

word1 word2

and place point between word1 and word2.
Now S-<backspace> C-y yields:
 word2 (followed by a newline)
M-0 S-<backspace> C-y yields:
 word2 (without newline)
and M--1 S-<backspace> C-y yields:
word1 (without trailing space or newline)

Makes no sense.

The problem is that kill-region sets this-command to 'kill-region, but
only when the command returns to the command loop will this result in
last-command being set to 'kill-region and kill-region checks
last-command to figure out whether to append or not.  So we have to
bind last-command to the appropriate value explicitly.  The:

     ((< arg 0)
      (forward-visible-line 1)

which I suggested to add has to be removed, since it moves point
without killing, potentially messing up the kill ring.  There goes the
M-- S-<backspace> C-x z z z z fun.  Not the end of the problems.
Things need to work out OK in read-only buffers.  But there killed
text does not really get removed and, as a result, it winds up getting
copied twice in certain situations.  Hence the need for
save-excursion's.  After all of this we wind up with version 1 of
kill-whole-line below.

That version works more or less OK, but some things seem less than
ideal:  

1.  As already mentioned, the possibility of killing backward with M--
    S-<backspace> C-x z z z is gone.

2.  The now more complex function gets very vulnerable to any possible
    future changes (including possible customization variables) in the
    not very primitive function kill-line.  So on second thought, it
    might actually be better to write the function entirely in terms
    of kill-region after all.

3.  Killing in read-only buffers turns out not to be either terribly
    convenient or terribly intuitive.

Version 2 of the function (see below) seems to take care of all three
problems.  Maybe somewhat strange at first is that S-<backspace> with
a negative argument leaves point at the *end* of the preceding non
killed line.  But M-0 S-<backspace> already leaves point at the end of
a line in read-only buffers, even in version 1.  I believe that the
behavior of version 2 can easily be understood, by the user, in the
following terms: with zero argument, point first moves to the
beginning of the line and then the line gets killed without killing
the newline.  With positive argument, point also first moves to the
beginning of the line and then a number of lines and the following
newline are killed.  With negative argument, point first moves to the
end of the line and the killing ends with the kill of the last
*preceding* newline.  This way, the resulting behavior seems intuitive,
even in read-only buffers.  We can not really implement the function
in this straightforward way, because that could severely mess up the
kill ring.  (This is what makes the actual implementation somewhat
complicated.)  But except for the fact that the kill ring gets handled
correctly, the behavior is equivalent.

I include below the two versions.  They differ in behavior for
negative arguments.  Version 2 does not use kill-line.  Once we decide
on which version to use (1 or 2 or some other one), I will still do
some further checking of that version in other situations, such as in
the presence of invisible text, just to make sure.  Personally, I
prefer version 2.

Version 1:

===File ~/kwlversion1=======================================
(defun kill-whole-line (&optional arg)
  "Kill current line.
With prefix arg, kill that many lines from point.
If arg is negative, kill backwards.
If arg is zero, kill current line but exclude the trailing newline."
  (interactive "P")
  (setq arg (prefix-numeric-value arg))
  (cond ((zerop arg)
         (save-excursion
           (kill-region (point) (progn (forward-visible-line 0) (point))))
         (let ((last-command
                (if (eq this-command 'kill-region)
                    'kill-region
                  last-command)))
           (kill-region (point) (progn (end-of-visible-line) (point)))))
        ((< arg 0)
         (save-excursion
           (kill-line 1))
         (let ((last-command
                (if (eq this-command 'kill-region)
                    'kill-region
                  last-command)))
           (kill-line (1+ arg))))
        (t
         (save-excursion
           (kill-line 0))
         (if (eobp) (signal 'end-of-buffer nil))
         (let ((last-command
                (if (eq this-command 'kill-region)
                    'kill-region
                  last-command)))
           (kill-line arg)))))

============================================================

Version 2:

===File ~/kwlversion2=======================================
(defun kill-whole-line (&optional arg)
  "Kill current line.
With prefix arg, kill that many lines from point.
If arg is negative, kill backwards.
If arg is zero, kill current line but exclude the trailing newline."
  (interactive "P")
  (setq arg (prefix-numeric-value arg))
  (cond ((zerop arg)
         (save-excursion
           (kill-region (point) (progn (forward-visible-line 0) (point))))
         (let ((last-command
                (if (eq this-command 'kill-region)
                    'kill-region
                  last-command)))
           (kill-region (point) (progn (end-of-visible-line) (point)))))
        ((< arg 0)
         (save-excursion
           (kill-region (point) (progn (end-of-visible-line) (point))))
         (let ((last-command
                (if (eq this-command 'kill-region)
                    'kill-region
                  last-command)))
           (kill-region (point)
                        (progn (forward-visible-line (1+ arg))
                               (unless (bobp) (backward-char))
                               (point)))))
        (t
         (if (and (bolp) (eobp)) (signal 'end-of-buffer nil))
         (save-excursion
           (kill-region (point) (progn (forward-visible-line 0) (point))))
         (let ((last-command
                (if (eq this-command 'kill-region)
                    'kill-region
                  last-command)))
           (kill-region (point)
                        (progn (forward-visible-line arg) (point)))))))

============================================================




reply via email to

[Prev in Thread] Current Thread [Next in Thread]