-
Notifications
You must be signed in to change notification settings - Fork 23
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
diff support with marked ranges and custom diff buffer
vundo-diff adds support for computing the diff between a marked and the current node, displaying in a custom vundo-diff buffer with color-matched timestamped modifications. Minor associated improvements to timestamp calculation are included.
- Loading branch information
Showing
4 changed files
with
251 additions
and
33 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,177 @@ | ||
;;; vundo-diff.el --- buffer diff for vundo -*- lexical-binding: t; -*- | ||
|
||
;; Copyright (C) 2023 Free Software Foundation, Inc. | ||
;; | ||
;; Author: JD Smith <[email protected]> | ||
;; Maintainer: Yuan Fu <[email protected]> | ||
;; URL: https://github.com/casouri/vundo | ||
;; Version: 0.1 | ||
;; Package-Requires: ((emacs "28.1")) | ||
;; | ||
;; This file is part of GNU Emacs. | ||
;; | ||
;; 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 | ||
;; the Free Software Foundation, either version 3 of the License, or | ||
;; (at your option) any later version. | ||
;; | ||
;; GNU Emacs is distributed in the hope that it will be useful, | ||
;; but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
;; GNU General Public License for more details. | ||
;; | ||
;; You should have received a copy of the GNU General Public License | ||
;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>. | ||
|
||
;;; Commentary: | ||
|
||
;; vundo-diff provides simple on-demand diff between arbitray undo | ||
;; states in the vundo tree. | ||
|
||
;;; Code: | ||
(require 'vundo) | ||
(require 'diff) | ||
(require 'diff-mode) | ||
(eval-when-compile (require 'cl-lib)) | ||
|
||
(defface vundo-diff-highlight | ||
'((((background light)) . | ||
(:inherit vundo-highlight :foreground "DodgerBlue4")) | ||
(((background dark)) . | ||
(:inherit vundo-highlight :foreground "DodgerBlue1"))) | ||
"Face for nodes marked for diff in the undo tree.") | ||
|
||
(defvar-local vundo-diff--marked-node nil) | ||
(defvar-local vundo-diff--highlight-overlay nil | ||
"Overlay used to highlight the selected node.") | ||
|
||
(defun vundo-diff--cleanup-diff-buffer (orig-name buf current from to) | ||
"Update diff headers in BUF. | ||
Headers are updated to indicate the diff in the contents of | ||
buffer named ORIG-NAME, between nodes FROM and TO, and given the | ||
CURRENT node." | ||
(let ((inhibit-read-only t) | ||
(info (cl-loop for x in (list from to) | ||
for idx = (vundo-m-idx x) | ||
for ts = (vundo--node-timestamp vundo--prev-mod-list x) | ||
for stat = (if (eq x current) "Current" | ||
(if vundo-diff--marked-node "Marked" "Parent")) | ||
collect | ||
(list (format "[%d]" idx) | ||
(format "<%s> [mod %d] (%s)" orig-name idx stat) | ||
(when (consp ts) (format-time-string "%F %r" ts)))))) | ||
(with-current-buffer buf | ||
(vundo-diff-mode) | ||
(goto-char (point-min)) | ||
(insert (concat (propertize "vundo-diff: " 'font-lock-face 'diff-header) | ||
(propertize orig-name 'font-lock-face | ||
'(diff-file-header diff-header)) | ||
"\n")) | ||
(let* ((change-files | ||
(cl-loop for (name fullname ts) in info | ||
for pat in '("---" "+++") | ||
if (re-search-forward | ||
(rx-to-string `(and bol ,pat (+ space) | ||
(group (group (+ (not ?\t))) | ||
(* any)) | ||
eol)) | ||
nil t) | ||
collect (cons (match-string-no-properties 2) name) | ||
and do (replace-match | ||
(if ts (concat fullname "\t" ts) fullname) | ||
t t nil 1))) | ||
(lim (point))) | ||
(when (eq (length change-files) 2) | ||
(goto-char (point-min)) | ||
(dolist (c change-files) ; change the file names in the diff | ||
(when (search-forward (car c) lim t) | ||
(replace-match (cdr c))))))))) | ||
|
||
;;;###autoload | ||
(defun vundo-diff-mark (&optional node) | ||
"Mark NODE for vundo diff. | ||
NODE defaults to the current node." | ||
(interactive) | ||
(let* ((mod-list vundo--prev-mod-list) | ||
(node (or node (vundo--current-node mod-list)))) | ||
(setq vundo-diff--marked-node node) | ||
(unless vundo-diff--highlight-overlay | ||
(setq vundo-diff--highlight-overlay | ||
(make-overlay (1- (vundo-m-point node)) (vundo-m-point node))) | ||
(overlay-put vundo-diff--highlight-overlay | ||
'display (vundo--translate "●")) | ||
(overlay-put vundo-diff--highlight-overlay | ||
'face 'vundo-diff-highlight) | ||
(overlay-put vundo-diff--highlight-overlay 'priority 2)) | ||
(move-overlay vundo-diff--highlight-overlay | ||
(1- (vundo-m-point node)) | ||
(vundo-m-point node)))) | ||
|
||
;;;###autoload | ||
(defun vundo-diff-unmark () | ||
"Unmark the node marked for vundo diff." | ||
(interactive) | ||
(when vundo-diff--marked-node | ||
(setq vundo-diff--marked-node nil) | ||
(when vundo-diff--highlight-overlay | ||
(delete-overlay vundo-diff--highlight-overlay) | ||
(setq vundo-diff--highlight-overlay nil)))) | ||
|
||
;;;###autoload | ||
(defun vundo-diff () | ||
"Perform diff between marked and current buffer state. | ||
Displays in a separate diff buffer with name based on | ||
the original buffer name." | ||
(interactive) | ||
(let* ((orig vundo--orig-buffer) | ||
(oname (buffer-name orig)) | ||
(current (vundo--current-node vundo--prev-mod-list)) | ||
(marked (or vundo-diff--marked-node (vundo-m-parent current))) | ||
(swapped (> (vundo-m-idx marked) (vundo-m-idx current))) | ||
mrkbuf) | ||
(if (or (not current) (not marked) (eq current marked)) | ||
(message "vundo diff not available.") | ||
(setq mrkbuf (get-buffer-create | ||
(make-temp-name (concat oname "-vundo-diff-marked")))) | ||
(unwind-protect | ||
(progn | ||
(vundo--check-for-command | ||
(vundo--move-to-node current marked orig vundo--prev-mod-list) | ||
(with-current-buffer mrkbuf | ||
(insert-buffer-substring-no-properties orig)) | ||
(vundo--refresh-buffer orig (current-buffer) 'incremental) | ||
(vundo--move-to-node marked current orig vundo--prev-mod-list) | ||
(vundo--trim-undo-list orig current vundo--prev-mod-list) | ||
(vundo--refresh-buffer orig (current-buffer) 'incremental)) | ||
(let* ((a (if swapped current marked)) | ||
(b (if swapped marked current)) | ||
(abuf (if swapped orig mrkbuf)) | ||
(bbuf (if swapped mrkbuf orig)) | ||
(dbuf (diff-no-select | ||
abuf bbuf nil t | ||
(get-buffer-create | ||
(concat "*vundo-diff-" oname "*"))))) | ||
(vundo-diff--cleanup-diff-buffer oname dbuf current a b) | ||
(display-buffer dbuf))) | ||
(kill-buffer mrkbuf))))) | ||
|
||
(defconst vundo-diff-font-lock-keywords | ||
`((,(rx bol (or "---" "+++") (* nonl) "[mod " (group (+ num)) ?\] | ||
(+ ?\s) ?\((group (or "Parent" "Current")) ?\)) | ||
(1 'diff-index t) | ||
(2 'vundo-highlight t)) | ||
(,(rx bol (or "---" "+++") (* nonl) "[mod " (group (+ num)) ?\] | ||
(+ ?\s) ?\((group "Marked") ?\)) | ||
(1 'diff-index t) | ||
(2 'vundo-diff-highlight t))) | ||
"Additional font-lock keyword to fontify Parent/Current/Marked.") | ||
|
||
(define-derived-mode vundo-diff-mode diff-mode "Vundo Diff" | ||
:syntax-table nil | ||
:abbrev-table nil | ||
(setcar font-lock-defaults | ||
(append diff-font-lock-keywords vundo-diff-font-lock-keywords))) | ||
|
||
(provide 'vundo-diff) | ||
|
||
;;; vundo-diff.el ends here |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters