Subject: Re: bug#19102: 24.4; outline-move-subtree-up/down error at last and second-last subtree

From: Paul Rankin <[email-masked]>
Date: Thu, 20 Nov 2014 23:43:10 +1000

Stephen Berman <[email-masked]> writes:

> This basically does the same thing as the patch I proposed -- adding a
> newline if necessary to ensure forward movement -- except that if there
> was no empty line after the last subtree, your code leaves the added
> newline dangling.  If you add that bit then there is effectively no
> difference between your version and mine.

For my package's purposes I think it might be better to have that
dangling newline created it's not already there, but yeah, not for
outline-mode. (This may be a faux pas on my part.)

However, how about this for the dangling line code?

--8<---------------cut here---------------start------------->8---
(unless empty-last-line
  (save-excursion
    (goto-char (point-max))
    (if (and (bolp) (eolp))
        (delete-char -1)))))
--8<---------------cut here---------------end--------------->8---

That way it doesn't execute if it doesn't need to. Or am I over-thinking
it?

> However, yours is slightly shorter and slightly cleaner, since it
> avoids a couple of setq's of let-bound variables, so maybe it's the
> better fix (after adding the line deletion bit; also, it's not
> necessary and AFAIK stylistically discouraged to quote a lambda form;
> and finally, I'm not sure if open-line is more or less appropriate
> here than newline -- maybe both are too heavyweight and (insert "\n")
> or even (terpri) would suffice?

Awesome, thanks. I'm not proposing any of my code go into Emacs, so go
with whatever you think is best.

>> The only thing I'm not sure about is the line marked above. This is not
>> intended for Emacs, just wanna see if I'm on the right track :)
>
> The line you marked tests whether we're moving the subtree down
> (positive arg) and if so ensures we find the insertion point after it.
> Or are you asking about something else?

Thanks. Yes that was all, please do not be under any impression that I
have any idea what I'm doing.

I did find some problems with saving match data though, so just for the
heck of it, I've pasted the function I ended up going with for my
package (it probably looks like I rewrote things from your patch just to
be contrary, but it's just to fit with the internal style of the
package):

--8<---------------cut here---------------start------------->8---
(defun fountain-outline-shift-down (&optional n)
  (interactive "p")
  (outline-back-to-heading)
  (let* ((move-func
          (if (< 0 n)
              'outline-get-next-sibling
            'outline-get-last-sibling))
         (end-point-func
          (lambda ()
            (outline-end-of-subtree)
            (if (and (eobp)
                     (eolp)
                     (not (bolp)))
                (insert-char ?\n))
            (unless (eobp)
              (forward-char 1))
            (point)))
         (beg (point))
         (folded
          (save-match-data
            (outline-end-of-heading)
            (outline-invisible-p)))
         (end
          (save-match-data
            (funcall end-point-func)))
         (insert-point (make-marker))
         (i (abs n)))
    (goto-char beg)
    (while (< 0 i)
      (or (funcall move-func)
          (progn (goto-char beg)
                 (message "Cannot shift past higher level")))
      (setq i (1- i)))
    (if (< 0 n)
        (funcall end-point-func))
    (move-marker insert-point (point))
    (insert (delete-and-extract-region beg end))
    (goto-char insert-point)
    (if folded
        (hide-subtree))
    (set-marker insert-point nil)))
--8<---------------cut here---------------end--------------->8---

-- 
Paul W. Rankin
http://www.paulwrankin.com