branch: externals/cursor-undo
commit 2264853e77872122a085fb2733b43c80337c44ca
Author: Luke Lee <luke@gauss>
Commit: Luke Lee <luke@gauss>

    * cursor-undo.el: Fix cursor-undo for read-only buffers.
    (cundo-track-screen-start, cundo-track-prev-point): new functions to
    make `def-cursor-undo' more clean, also fix read-only buffer issues.
    (def-cursor-undo): use the above functions to fix the issue.
    * README.org: Newly added README file to provide more info.
---
 README.org     | 112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 cursor-undo.el |  18 +++++++---
 2 files changed, 126 insertions(+), 4 deletions(-)

diff --git a/README.org b/README.org
new file mode 100644
index 0000000000..d192a5a4b4
--- /dev/null
+++ b/README.org
@@ -0,0 +1,112 @@
+# Cursor Undo Mode    -*- mode: org; -*-
+
+* _About_
+
+Cursor-undo allows you to undo cursor movement commands using the
+Emacs standard `undo' command.
+
+For frequent cursor movements such as up/down/left/right, it combines
+the movements of the same direction into a single undo entry.  This
+prevents the undo command from reversing each individual character
+movement separately.  For example, if you move the cursor 20
+characters to the right and then 10 lines up, the first undo will go
+down 10 lines back, and the next undo move back 20 characters left.
+On the other hand, for search commands that often jump across multiple
+pages, each search command has its own undo entry, allowing you to
+undo them one at a time rather than as a combined operation.
+
+* _A "Brief" History_
+
+This cursor-undo functionality has existed in my local Emacs init file
+for over 11+ years, since version 0 on 2013-06-26.  It was originally
+intended to support my ELPA package 
[[https://elpa.gnu.org/packages/brief.html][BriefMode]] only, but I later found
+it would be more useful if implemented in a more generalized way.  For
+years I have hoped for an official implementation of this feature,
+which is commonly seen among various editors.  Considering my
+implementation using advice functions a bit inelegant so I have always
+hesitated to release it till recently.
+
+Until there is official support for the cursor undo feature, this
+package serves most common daily needs.  The core design is to align
+with Emacs's native `undo' function by recording cursor positions and
+screen-relative position undo entries in the `buffer-undo-list' in
+accordance with its documentation.
+
+As this package primarily consists of advice functions to wrap cursor
+movement commands, each cursor movement command needs to be manually
+wrapped with `def-cursor-undo'.  For interactive functions that
+heavily invoke advised cursor movement commands, you may even need to
+advise them with `disable-cursor-tracking' to prevent generating
+numerous distinct cursor undo entries from a single command.  For user
+convenience, I have prepared ready `def-cursor-undo' advice sets for
+standard Emacs cursor movement commands, Brief Editor mode, Viper
+mode, and EVIL mode.
+
+* _Usage_
+
+This package is released as a standard 
[[https://elpa.gnu.org/packages/cursor-undo.html][ELPA package]].  Just go to 
Emacs
+main menu -> "Options" -> "Manage Emacs Packages" and install it.
+Once this package is installed, you only need to enable cursor-undo
+mode by adding the following line into your Emacs init file .emacs or
+init.el:
+
+#+begin_src
+  (cursor-undo 1)
+#+end_src
+
+That's all.  You can now move your cursor around and use stand Emacs
+`undo' (C-_, C-/ or C-x u) to move it back.  Even in read-only buffers
+you can still undo cursor movements.  This is convenient especially
+when browsing a huge file.
+
+* _Notes for read-only buffers_
+
+Notice that the original `undo' cannot be performed in read-only
+buffers.  Here, I also advised the undo operation in read-only buffers
+as long as the pending undo list is still a cursor movement.
+
+This also enables a editing trick: If you are just editing a big file
+and moving the cursor to browse other parts but forgot where you were,
+you can undo cursor movements to go back to your last edited position
+by long-holding <undo> until the last editing command.  However, by
+doing so you risk missing your last edited operation as it might flash
+by so quickly that you don't even notice but keep undoing other cursor
+commands you don't want to undo.
+
+In this case, you can switch the buffer to read-only mode (by setting
+`buffer-read-only' to t), then long press <undo> until the undo
+command warns you that you're trying to edit a read-only buffer.  At
+this point, you're exactly at the latest editing position you are
+looking for.  You can then safely set `buffer-read-only' flag back to
+NIL and continue your editing.
+
+* _Notes for EVIL mode user_
+
+If you choose to use the default Emacs `undo' system, you should be
+able to use `evil-undo' to undo cursor movements.  If your choice is
+tree-undo or another undo system, you might need to use Emacs default
+`undo' (C-_, C-/ or C-x u ...) to undo cursor movements.
+
+
+* _Notes for Viper mode user_
+
+The default `viper-undo' is advised to allow cursor-undo.  If you find
+the advised function not working properly, consider comment out the
+following source code `(define-advice viper-undo ...' to restore the
+original `viper-undo' function and use Emacs default `undo' (C-_, C-/
+or C-x u ...)  to undo cursor movements.
+
+* _Technical notes_
+
+Why do I use advice functions instead of the more generalized pre/post
+command hooks?  I bet you wouldn't like all the cursor movements in
+your debugging session being recorded as undo entries; when you start
+`undo'ing you will find the cursor replaying your previous debugging
+session in reverse order.  Similar effects happens in `semantic' mode
+and many others.  If it record *every* movement you will soon find it
+difficult to use in many situations.  Therefore, only the chosen
+editing key commands are advised with `def-cursor-undo'.  If you find
+something missing, just advise it with your own `def-cursor-undo'.
+
+
+Luke Lee
diff --git a/cursor-undo.el b/cursor-undo.el
index aafa26957b..b16175d81b 100644
--- a/cursor-undo.el
+++ b/cursor-undo.el
@@ -5,7 +5,7 @@
 ;; Author:       Luke Lee <luke.yx....@gmail.com>
 ;; Maintainer:   Luke Lee <luke.yx....@gmail.com>
 ;; Keywords:     undo, cursor
-;; Version:      1.1.2
+;; Version:      1.1.3
 
 ;; GNU Emacs is free software: you can redistribute it and/or modify
 ;; it under the terms of the GNU General Public License as published by
@@ -135,6 +135,17 @@
 ;; "Warning: Unused lexical variable ‘prev-screen-start’".
 (defvar prev-screen-start)
 
+(defun cundo-track-screen-start (prv-screen-start)
+  (let ((entry (list 'apply 'cundo-restore-win prv-screen-start)))
+    (if (eq buffer-undo-list 't)
+        (setq buffer-undo-list entry)
+      (push entry buffer-undo-list))))
+
+(defun cundo-track-prev-point (prev-point)
+  (if (eq buffer-undo-list 't)
+      (setq buffer-undo-list (list prev-point))
+    (push prev-point buffer-undo-list)))
+
 ;;;###autoload
 (defmacro def-cursor-undo (func-sym &optional no-combine screen-pos no-move)
   "Define an advice for FUNC-SYM to track cursor movements in the undo buffer.
@@ -227,10 +238,9 @@ relative screen position (screen-pos=NIL) nor `point' 
position (no-move=t)."))
                       (numberp (cadr buffer-undo-list))
                       (= prev-point (cadr buffer-undo-list))))
            ,@(if screen-pos
-                 '((push `(apply cundo-restore-win ,prev-screen-start)
-                         buffer-undo-list)))
+                 '((cundo-track-screen-start prev-screen-start)))
            ,@(unless no-move
-               '((push prev-point buffer-undo-list)))
+               '((cundo-track-prev-point prev-point)))
            ;;(abbrevmsg (format "c=%S,%S b=%S" last-command this-command
            ;;                   buffer-undo-list) 128) ;; DBG
            (undo-boundary))

Reply via email to