help-gnu-emacs
[Top][All Lists]
Advanced

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

A strange issue with buffer-undo-list


From: Marcin Borkowski
Subject: A strange issue with buffer-undo-list
Date: Tue, 23 Feb 2021 06:19:43 +0100
User-agent: mu4e 1.1.0; emacs 28.0.50

Hi all,

I was writing a command to move the current line past the next one (for
educational purposes), and I encountered a strange issue.

Here is my function:

--8<---------------cut here---------------start------------->8---
(defun move-line-down (count)
  "Move the current line down."
  (interactive "p")
  (let ((position-in-line (current-column)))
    (line-move 1)
    (transpose-lines count)
    (line-move -1)
    (move-to-column position-in-line)))
--8<---------------cut here---------------end--------------->8---

(It is definitely far from optimal, and I know that - the next version
will get rid of `transpose-lines' dependency and will just delete the
line below and recreate it above within a `save-excursion', which will
render the `position-in-line' stuff unnecessary.  But never mind this.)

So, my problem is that if I say M-x move-line-down, everything works,
but after undoing that change, the point lands at the bol of the next
line instead if where it had been at the beginning.  (I suppose this is
because only the `(transpose-lines count)' is effectively undone, so
`(line-move 1)` is not undone - that makes sense.)

So, I changed the code to this:

--8<---------------cut here---------------start------------->8---
(defun move-line-down (count)
  "Move the current line down."
  (interactive "p")
  (let ((position-in-line (current-column)))
    (push (point) buffer-undo-list)
    (line-move 1)
    (transpose-lines count)
    (line-move -1)
    (move-to-column position-in-line)))
--8<---------------cut here---------------end--------------->8---

which triggers an error.

Now, I did (of course) M-x toggle-debug-on-error, and so I learned about
"change groups".  I haven't heard about them before, so I consulted the
docs, and they seem cool (much like transactions in databases).  But
I have questions.

1. Why did my code confuse the change group mechanism?

2. How do I use `undo-amalgamate-change-group'?  The manual does not
provide any examples, and I only found one occurrence in the Emacs
source, and frankly, it didn't help a lot.  (Well, once I know the
answer to my next question, this will most probably be easy.)

3. Also, I am not even sure how the change group mechanism is supposed
to be used.  The docs tell me to use `unwind-protect', but this:

--8<---------------cut here---------------start------------->8---
(defun move-line-down (count)
  "Move the current line down."
  (interactive "p")
  (let ((position-in-line (current-column))
        (change-group (prepare-change-group)))
    (unwind-protect
        (progn
          (activate-change-group change-group)
          (line-move 1)
          (transpose-lines count)
          (line-move -1)
          (move-to-column position-in-line)
          (accept-change-group change-group))
      (cancel-change-group change-group))))
--8<---------------cut here---------------end--------------->8---

of course doesn't work, since both `accept-change-group' and
`cancel-change-group' are evaluated.  Is there a way to get the "state"
of the change group to only cancel it if it was not finished?

Anyway, it seems that this whole machinery is an overkill for the
purpose of just moving a line down - but as I said, I want to learn and
teach here, so this is kind of intentionally a toy example.

TIA,

-- 
Marcin Borkowski
http://mbork.pl



reply via email to

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