I use point-undo to jump between positions in the cursor history. However, point-undo uses every previous position of the cursor, and I often experience that what I actually want is to jump just to the last/next line where my cursor was. So I don't want to jump around within one line. In other words, I would like the cursor history to store only the last position per line.

How to do this?

  • You might want to check avy it allows you to quickly jump to any lines in the visible text with avy-goto-lines command. Commented Oct 21, 2016 at 12:41
  • 1
    You could give emacswiki.org/emacs/download/pointhistory.el a try. This is not on a per-line basis but it only saves "large jumps" as introduced by scroll-up and so on. Since multiple next-line commands also cause a scroll-up those line-commands are also covered in some sense.
    – Tobias
    Commented Oct 21, 2016 at 15:05
  • @Tobias Thanks for the hint! Unfortunately, jumps seem to be too large with pointhistory. And the way it jumps is somewhat enigmatic, as to the positions that go into the ring. Maybe the code of pointhistory could be modified to also include line-based jumps?
    – Timm
    Commented Oct 22, 2016 at 8:42
  • ace-jump-mode is a nice alternative to avy. Demoed here.
    – mcp
    Commented Oct 4, 2021 at 15:50

1 Answer 1


I've tried to modify point-undo. It seems to work. However I included the first jump on the current line. That's intended behaviour.

(defvar point-undo-ring-length 20)

(defvar point-undo-ring (make-ring point-undo-ring-length))
(make-variable-buffer-local 'point-undo-ring)

(defvar point-redo-ring (make-ring point-undo-ring-length))
(make-variable-buffer-local 'point-redo-ring)

(defun point-undo-pre-command-hook ()
  "Save positions before command."
  (unless (or (eq this-command 'point-undo)
              (eq this-command 'point-redo))
    (let ((line (line-number-at-pos)))
      (when (eq line (cdr (nth 0 (ring-elements point-undo-ring))))
        (ring-remove point-undo-ring 0))
      (ring-insert point-undo-ring (cons (point) line))
      (setq point-redo-ring (make-ring point-undo-ring-length)))))
(add-hook 'pre-command-hook 'point-undo-pre-command-hook)

(defun point-undo-doit (ring1 ring2)
  "ring1, ring2 = {point-undo-ring, point-redo-ring}"
  (condition-case nil
        (goto-char (car (nth 0 (ring-elements ring1)))) 
        (ring-insert ring2 (ring-remove ring1 0)))
    (error nil)))

(defun point-undo ()
  "Undo position."
  (point-undo-doit point-undo-ring point-redo-ring))

(defun point-redo ()
  "Redo position."
  (when (or (eq last-command 'point-undo)
            (eq last-command 'point-redo))
    (point-undo-doit point-redo-ring point-undo-ring)))

(define-key global-map [f9] 'point-undo)
(define-key global-map [f10] 'point-redo)
  • Great! Maybe you could add a variable to set the size of the ring?
    – Timm
    Commented Oct 24, 2016 at 17:44

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.