6

From the Vim User Manual: 02.5:

There's a special version of the undo command, the "U" (undo line) command. The undo line command undoes all the changes made on the last line that was edited. Typing this command twice cancels the preceding "U".

How can I get this functionality when using evil-mode in Emacs? U currently does nothing.

achalk
  • 579
  • 4
  • 16
  • 1
    Well, for starters, study the exact behavior. "Undo all changes on the last line" sounds rather vague to me. Next step would be looking into how undo-tree works and augmenting it for this feature, then you could just bind it to a key. – wasamasa Jan 21 '17 at 17:19

3 Answers3

3

undo (bound to C-/, C-_, and C-x u by default) will restrict its action to the active region, if there is one:

In Transient Mark mode when the mark is active, only undo changes within the current region. Similarly, when not in Transient Mark mode, just C-u as an argument limits undo to changes within the current region.

(from C-h undo)

That allows to you undo changes in any arbitrary contiguous block of text. Emacs includes mark-paragraph out of the box, bound to M-h by default. That means M-h C-/ (followed by as many repetitions of C-/ as you need) will progressively undo changes to the highlighted paragraph.

We don't have a mark-line function by default. You can mark the line 'by-hand' with: C-a C-space C-e, and then use C-/ (or C-x u etc) to undo changes to just that line.

Moving to the beginning (C-a) or end (C-e) of the line, and setting the mark (C-space) are things that you do so frequently in Emacs that after a while it just becomes part of your muscle memory. Meaning, I wouldn't gain much by wrapping this up in a special-purpose function. However, you certainly could do that, and you might want to use the mark-line function from misc-cmds that @Charles mentioned to do that.

Tyler
  • 21,719
  • 1
  • 52
  • 92
0

Typing C-x u undoes one change on the last line edited. If you follow that with a command that breaks the undo sequence, like C-f, then hitting C-x u again will cancel that undo.

If you're looking to undo a change made to any arbitrary line, though, regardless of whether it is the last line edited, you can try out "selective undo". Type M-x mark-line, then hit C-x u: hitting it repeatedly will take you through previous states of the line in the undo history, without touching the rest of the buffer.

Charles
  • 76
  • 5
  • 3
    `C-x u` is bound to `undo-tree-visualize` when using Evil, please describe the command you mean. – wasamasa Jan 21 '17 at 21:21
  • I don't think Emacs comes with a `mark-line` command. You probably wrote one yourself and forgot you had done it. (I wrote my own `mark-line` too: pretty useful!) – Omar Jun 21 '17 at 02:21
  • Hm, sorry for misleading. I don't use `evil` (didn't realize the question was asking about it), and `mark-line` is available in Drew Adams' `misc-cmds` package, which I've had installed for a while. Maybe somebody else can provide a better answer for `evil`. – Charles Aug 20 '17 at 08:09
  • 1
    On my system `C-x u` is bound to `undo`. Selecting a region before calling `undo` provides more fine-grained control over what changes to undo. – Caterpillar Sep 20 '17 at 21:14
0

Here's a quick first attempt that leverages how undo behaves when the buffer is narrowed:

(defun undo-line ()
  (interactive)
  (progn
    (when (buffer-modified-p) (undo))
    (save-restriction
      (narrow-to-region (line-beginning-position) (line-end-position))
      (while (buffer-modified-p)
        (undo-more 1)))))

Edit: This doesn't use evil / undo-tree, just the basic undo command. You can do the same but using undo-tree-undo instead:

(defun undo-line ()
  "Undo the previous change and any other changes made at the same time to the same line."
  (interactive)
  (progn
    (when (buffer-modified-p) (undo-tree-undo))
    (save-restriction
      (narrow-to-region (line-beginning-position) (line-end-position))
      (while (buffer-modified-p)
        (undo-tree-undo)))))
glucas
  • 20,175
  • 1
  • 51
  • 83