Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add undo-propose-marker-list #25

Merged
merged 4 commits into from
Oct 5, 2019
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions Readme.org
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,12 @@ add [[https://www.emacswiki.org/emacs/RedoMode][redo]], call ~(undo-propose-wrap
- ~undo-propose-done-hook~ is run after committing or squash
committing an undo-propose

*** Markers

Currently =undo-propose= does not correctly update markers in the
parent buffer after undo'ing. As a workaround, you can add markers to
=undo-propose-marker-list= to ensure they are updated after undo'ing.

*** Example configurations
**** Simple configuration

Expand Down
67 changes: 36 additions & 31 deletions undo-propose.el
Original file line number Diff line number Diff line change
Expand Up @@ -42,23 +42,23 @@

;;; Code:

(require 'cl-lib)

(defgroup undo-propose nil
"Simple and safe undo navigation"
:group 'convenience)

(defcustom undo-propose-done-hook nil
"Hook runs when initially entering the temporal buffer."
"Hook runs when leaving the temporal buffer."
:type 'hook
:group 'undo-propose)

(defcustom undo-propose-entry-hook nil
"Hook runs when leaving the temporal buffer."
"Hook runs when entering the temporal buffer."
:type 'hook
:group 'undo-propose)

(defvar undo-propose-parent nil "Parent buffer of ‘undo-propose’ buffer.")
(defvar undo-propose--org-clock-marker nil "Backup of `org-clock-marker'.")
(make-variable-buffer-local 'undo-propose--org-clock-marker)

(defun undo-propose--message (content)
"Message CONTENT, possibly with prefix \"undo-propose: \"."
Expand Down Expand Up @@ -99,14 +99,8 @@ If already inside an `undo-propose' buffer, this will simply call `undo'."
(setq-local buffer-undo-list list-copy)
(setq-local buffer-read-only t)
(setq-local undo-propose-parent orig-buffer)
(when (and (eq major-mode 'org-mode)
(org-clock-is-active)
(eq undo-propose-parent
(marker-buffer org-clock-marker)))
(setq undo-propose--org-clock-marker (make-marker))
(move-marker undo-propose--org-clock-marker
(marker-position org-clock-marker)))
(undo-propose-mode 1)
(undo-propose-copy-markers)
(run-hooks 'undo-propose-entry-hook)
(undo-propose--message "C-c C-c to commit, C-c C-s to squash commit, C-c C-k to cancel, C-c C-d to diff"))))

Expand Down Expand Up @@ -136,23 +130,15 @@ If already inside an `undo-propose' buffer, this will simply call `undo'."
(orig-buffer undo-propose-parent)
(list-copy (undo-copy-list buffer-undo-list))
(pos (point))
(win-start (window-start))
(org-clock-marker-pos
(when (and (eq major-mode 'org-mode)
(org-clock-is-active)
(eq undo-propose-parent
(marker-buffer org-clock-marker))
(marker-position undo-propose--org-clock-marker))
(marker-position undo-propose--org-clock-marker))))
(win-start (window-start)))
(copy-to-buffer orig-buffer 1 (buffer-end 1))
(with-current-buffer orig-buffer
(setq-local buffer-undo-list list-copy))
(undo-propose-update-markers)
(switch-to-buffer orig-buffer)
(kill-buffer tmp-buffer)
(goto-char pos)
(set-window-start (selected-window) win-start)
(when org-clock-marker-pos
(move-marker org-clock-marker org-clock-marker-pos))
(undo-propose--message "commit"))
(run-hooks 'undo-propose-done-hook))

Expand All @@ -166,25 +152,17 @@ buffer contents are copied."
(orig-buffer undo-propose-parent)
(orig-end (1+ (buffer-size orig-buffer)))
(first-diff (abs (compare-buffer-substrings
tmp-buffer 1 tmp-end orig-buffer 1 orig-end)))
(org-clock-marker-pos
(when (and (eq major-mode 'org-mode)
(org-clock-is-active)
(eq undo-propose-parent
(marker-buffer org-clock-marker))
(marker-position undo-propose--org-clock-marker))
(marker-position undo-propose--org-clock-marker))))
tmp-buffer 1 tmp-end orig-buffer 1 orig-end))))
;; copy from 1st diff, so we don't jump to top of buffer when redoing
(with-current-buffer orig-buffer
(when (/= first-diff 0)
(delete-region first-diff (point-max))
(goto-char (point-max))
(insert-buffer-substring tmp-buffer first-diff tmp-end)
(goto-char first-diff)))
(undo-propose-update-markers)
(switch-to-buffer orig-buffer)
(kill-buffer tmp-buffer)
(when org-clock-marker-pos
(move-marker org-clock-marker org-clock-marker-pos))
(undo-propose--message "squash commit"))
(run-hooks 'undo-propose-done-hook))
(define-obsolete-function-alias 'undo-propose-commit-buffer-only
Expand All @@ -208,6 +186,33 @@ buffer contents are copied."
(interactive)
(ediff-buffers undo-propose-parent (current-buffer)))

(defvar undo-propose-marker-list nil
"List of markers to update after running undo-propose.")

(defun undo-propose-copy-markers ()
"Copy markers registered in `undo-propose-marker-list'."
(setq-local undo-propose-marker-map
(cl-loop for orig-marker in undo-propose-marker-list
if (eq (marker-buffer orig-marker) undo-propose-parent)
Copy link
Contributor

@takaxp takaxp Sep 24, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMO, if we replace orig-marker with (symbol-value orig-marker) from line 196 to 200, then user can add any markers to undo-propose-marker-list like (add-to-list 'undo-propose-marker-list 'org-clock-hd-marker).

collect
(let ((new-marker (make-marker)))
(move-marker new-marker (marker-position orig-marker))
(cons new-marker orig-marker)))))

(defun undo-propose-update-markers ()
"Update marker positions in parent buffer."
(cl-loop for association in undo-propose-marker-map do
(let ((new-marker (car association))
(orig-marker (cdr association)))
;; only update if orig-marker still exists
(when (and (markerp orig-marker)
(eq (marker-buffer orig-marker) undo-propose-parent))
(move-marker orig-marker (marker-position new-marker)
undo-propose-parent)))))

(with-eval-after-load 'org
(add-to-list 'undo-propose-marker-list org-clock-marker))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I found an additional marker regarding org-clock. Could you add org-clock-hd-marker?


(provide 'undo-propose)

;;; undo-propose.el ends here