-
Notifications
You must be signed in to change notification settings - Fork 3
/
Copy pathcc-ediff-mode.el
142 lines (120 loc) · 5.77 KB
/
cc-ediff-mode.el
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
;;; cc-ediff-mode.el --- Ediff configuration -*- lexical-binding: t; -*-
;; Copyright (C) 2023-2024 Charles Choi
;; Author: Charles Choi <[email protected]>
;; Keywords: tools
;; This program 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.
;; This program 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 this program. If not, see <https://www.gnu.org/licenses/>.
;;; Commentary:
;;
(require 'ediff)
;;; Code:
;; these defvars are here to let cc-ediff-mode.el compile clean
(defvar ediff-buffer-A)
(defvar ediff-buffer-B)
(defvar ediff-buffer-C)
(defvar ediff-merge-job)
(defvar ediff-ancestor-buffer)
;; CC: I set my Ediff variables in `custom-set-variables'
;; Use your own preference.
;; '(ediff-keep-variants nil)
;; '(ediff-split-window-function 'split-window-horizontally)
;; '(ediff-window-setup-function 'ediff-setup-windows-plain)
(defvar cc/ediff-revision-session-p nil
"If t then `cc/ediff-revision-actual' has been called.
This state variable is used to insert added behavior to the overridden
function `ediff-janitor'.")
(defun cc/ediff-revision-from-menu (e)
"Invoke `ediff-revision' on E with variable `buffer-file-name'."
(interactive "e")
(ignore e)
(cc/ediff-revision))
(defun cc/ediff-revision ()
"Run Ediff on the current `buffer-file-name' provided that it is `vc-registered'.
This function handles the interactive concerns found in `ediff-revision'.
This function will also test if a diff should apply to the current buffer."
(interactive)
(when (and (bound-and-true-p buffer-file-name)
(vc-registered (buffer-file-name)))
(if (and (buffer-modified-p)
(y-or-n-p (format "Buffer %s is modified. Save buffer? "
(buffer-name))))
(save-buffer (current-buffer)))
(message buffer-file-name)
(cc/ediff-revision-actual))
(cond ((not (bound-and-true-p buffer-file-name))
(message (concat (buffer-name) " is not a file that can be diffed.")))
((not (vc-registered buffer-file-name))
(message (concat buffer-file-name " is not under version control.")))))
(defun cc/ediff-revision-actual ()
"Invoke Ediff logic to diff the modified repo file to its counterpart in the
current branch.
This function handles the actual diff behavior called by `ediff-revision'."
(let ((rev1 "")
(rev2 ""))
(setq cc/ediff-revision-session-p t)
(ediff-load-version-control)
(funcall
(intern (format "ediff-%S-internal" ediff-version-control-package))
rev1 rev2 nil)))
(defun ediff-janitor (ask keep-variants)
"Kill buffers A, B, and, possibly, C, if these buffers aren't modified.
In merge jobs, buffer C is not deleted here, but rather according to
`ediff-quit-merge-hook'.
ASK non-nil means ask the user whether to keep each unmodified buffer, unless
KEEP-VARIANTS is non-nil, in which case buffers are never killed.
A side effect of cleaning up may be that you should be careful when comparing
the same buffer in two separate Ediff sessions: quitting one of them might
delete this buffer in another session as well.
CC MODIFICATION: This method overrides the original Ediff function."
(let ((ask (if (and (boundp 'cc/ediff-revision-session-p)
cc/ediff-revision-session-p)
nil
ask)))
(ediff-dispose-of-variant-according-to-user
ediff-buffer-A 'A ask keep-variants)
;; !!!: CC Note: Test global state variable `cc/ediff-revision-session-p' to
;; determine if the modified repo file should be kept.
;; Guarding in place to hopefully avoid side-effects when `ediff-janitor' is
;; called from other Ediff functions. Informal testing has not revealed any
;; side-effects but YOLO.
(if (and (boundp 'cc/ediff-revision-session-p)
cc/ediff-revision-session-p)
(ediff-dispose-of-variant-according-to-user
;; CC Note: keep-variants argument is hard-coded to t to keep
;; buffer holding modified repo file around.
ediff-buffer-B 'B t t)
(ediff-dispose-of-variant-according-to-user
ediff-buffer-B 'B ask keep-variants))
(if ediff-merge-job ; don't del buf C if merging--del ancestor buf instead
(ediff-dispose-of-variant-according-to-user
ediff-ancestor-buffer 'Ancestor ask keep-variants)
(ediff-dispose-of-variant-according-to-user
ediff-buffer-C 'C ask keep-variants))
;; CC Note: Reset global state variable `cc/ediff-revision-session-p'.
(if (and (boundp 'cc/ediff-revision-session-p)
cc/ediff-revision-session-p)
(setq cc/ediff-revision-session-p nil))))
(defun cc/stash-window-configuration-for-ediff ()
"Store window configuration to register 🧊.
Use of emoji is to avoid potential use of keyboard character to reference
the register."
(window-configuration-to-register ?🧊))
(defun cc/restore-window-configuration-for-ediff ()
"Restore window configuration from register 🧊.
Use of emoji is to avoid potential use of keyboard character to reference
the register."
(jump-to-register ?🧊))
(add-hook 'ediff-before-setup-hook #'cc/stash-window-configuration-for-ediff)
;; !!!: CC Note: Why this is not `ediff-quit-hook' I do not know. But this works
;; for cleaning up ancillary buffers on quitting an Ediff session.
(add-hook 'ediff-after-quit-hook-internal #'cc/restore-window-configuration-for-ediff)
(provide 'cc-ediff-mode)
;;; cc-ediff-mode.el ends here