-
Notifications
You must be signed in to change notification settings - Fork 6
Expand file tree
/
Copy path_ediff.el
More file actions
276 lines (232 loc) · 11.8 KB
/
_ediff.el
File metadata and controls
276 lines (232 loc) · 11.8 KB
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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
;; -*-emacs-lisp-*-
;;;
;;; diff & ediff customization
;;;
(eval-when-compile
(require 'diff-mode)
(require 'ediff)
(require 'ediff-ptch))
;;
;; Whenever I had tried to modified ediff-make-wide-display, I always
;; forgot how it works. Currently, ediff uses its function,
;; `ediff-toggle-wide-display' to toggle wide mode. (A) Assuming that
;; currently in no wide mode, it will call function stored in the
;; variable, `ediff-make-wide-display-function'. This variable is
;; also permenent buffer local variable, and it's default value is set
;; to the function `ediff-make-wide-display'. This function will save
;; some of the current frame parameteres (specifically `left and
;; `width) in to another buffer local variable,
;; `ediff-wide-display-orig-parameters', then change the frame to the
;; wide display. (B) Assuming that currently in the wide mode,
;; `ediff-toggle-wide-display' will restore the frame by the saved
;; setting in the `ediff-wide-display-orig-parameters'.
;;
;; My configuration is very dirty. First, it activates the around
;; advice to `ediff-toggle-wide-display'. It calculate the desired
;; window (not frame!) width for the wide display, then set the (not
;; buffer local) local variable `cinsk/ediff-wide-window-width'.
;; Then, I redefine the default variable of
;; `ediff-make-wide-display-function', so that
;; `ediff-make-wide-display' will call my function, stored in
;; `ediff-make-wide-display-function' named
;; `cinsk/ediff-make-wide-display'. (Currently, only frame width
;; information is passed.) The funciton,
;; `cinsk/ediff-make-wide-display' will accept the desired window with
;; from `cinsk/ediff-wide-window-width', and calculate the desired
;; frame `left and `width based on the current ediff-mode. (i,e,
;; whether the ediff session currently in 2way or 3way.)
;;
;; Note. Remember that restoring from the wide mode is totally upto
;; the `ediff-toggle-wide-display' which we cannot modify. It reads
;; the saved frame parameters from
;; `ediff-wide-dispay-orig-parameters'. It turns out that any frame
;; configuration saved in the variable will be used.
;;
;; Note. If you quit ediff session in the wide mode, the default
;; implementation will leave the frame as in wide mode. I added one
;; lambda in `ediff-cleanup-hook', so that it will restore to the
;; non-wide mode if the frame is in the wide mode.
;; Note that some external packages loads 'ediff by themselves, such
;; as magit and color-theme. Since `ediff-make-wide-display-function'
;; should be set before loading `ediff, ediff customization should be
;; placed in the first place. -- cinsk
(setq-default ediff-make-wide-display-function 'cinsk/ediff-make-wide-display)
(let ((kmap (make-sparse-keymap)))
(define-key kmap [?f]
(lambda (arg) (interactive "P")
(cinsk/select-command arg 'ediff-files 'ediff-files3)))
(define-key kmap [?b]
(lambda (arg) (interactive "P")
(cinsk/select-command arg 'ediff-buffers 'ediff-buffers3)))
(define-key kmap [?d]
(lambda (arg) (interactive "P")
(cinsk/select-command arg 'ediff-directories
'ediff-directories3)))
(define-key kmap [?v] 'ediff-revision)
(define-key kmap [?r]
(lambda (arg) (interactive "P")
(cinsk/select-command arg 'ediff-regions-wordwise
'ediff-regions-linewise)))
(define-key kmap [?w]
(lambda (arg) (interactive "P")
(cinsk/select-command arg 'ediff-windows-wordwise
'ediff-windows-linewise)))
(define-key kmap [?p] 'ediff-patch-file)
(define-key kmap [?P] 'ediff-patch-buffer)
(define-key kmap [?m]
(lambda (arg) (interactive "P")
(cinsk/select-command arg 'ediff-merge-revisions
'ediff-merge-revisions-with-ancestor)))
(define-key kmap [(meta ?D)] 'ediff-show-registry)
(global-set-key [(meta ?D)] kmap))
(defun cinsk/select-command (arg func1 func2)
"call interactively FUNC1 if ARG is nil, otherwise call FUNC2."
(call-interactively (if arg func2 func1)))
(defun cinsk/ediff-revision-buffer-p (buf)
"Return non-nil if BUF is the temporary revision file from `ediff-revision'."
(and (buffer-file-name buf)
(string-match "\\`.*~.*~\\'" (file-name-nondirectory
(buffer-file-name buf)))))
(defun cinsk/ediff-janitor ()
"Delete ediff-related buffers if it is a VC related files."
(let ((ediff-buffer-A (and (cinsk/ediff-revision-buffer-p ediff-buffer-A)
ediff-buffer-A))
(ediff-buffer-B (and (cinsk/ediff-revision-buffer-p ediff-buffer-B)
ediff-buffer-B)))
;; TODO: What about ediff-buffer-C?
(ediff-janitor nil nil)))
;; no effect here
;;(setq ediff-make-wide-display-function 'cinsk/ediff-make-wide-display)
(with-eval-after-load "ediff"
;; I haven't digged much, but restoring the frame is not working
;; (esp. on merge session) if `ediff-toggle-wide-display' is
;; registered in `ediff-quit-hook'. Registering
;; `ediff-cleanup-hook' solves the problem. -- cinsk
(add-hook 'ediff-cleanup-hook (lambda ()
(if ediff-wide-display-p
(ediff-toggle-wide-display))))
;; Change the algorithm perhaps find a smaller set of changes.
;; This makes `diff' slower.
(setq ediff-diff-options "-d")
;; ignore whitespaces and newlines. (can be toggled on/off via `##')
(setq ediff-ignore-similar-regions t)
;; do not create new frame for the control panel
(setq ediff-window-setup-function 'ediff-setup-windows-plain)
;; If nil, ask the user to kill the buffers on exit.
;; (setq ediff-keep-variants nil)
;; Delete the buffer for the revision files on `ediff-quit'.
(add-to-list 'ediff-cleanup-hook #'cinsk/ediff-janitor)
;; no effect
;; (setq ediff-make-wide-display-function 'cinsk/ediff-make-wide-display)
)
(defun diff-ediff-patch2 (&optional arg)
"Call `ediff-patch-file' on the current buffer.
With a prefix argument, ask the user of the option to the patch
command."
(interactive "P")
(require 'ediff-ptch) ; required for `ediff-patch-options'
(let ((new-ediff-patch-options
(if (and arg (= (prefix-numeric-value arg) 4))
(read-from-minibuffer (format "patch options [%s]: "
ediff-patch-options)
ediff-patch-options nil nil nil
ediff-patch-options)
ediff-patch-options)))
(let ((ediff-patch-options new-ediff-patch-options))
(call-interactively #'diff-ediff-patch))))
(with-eval-after-load "diff-mode"
(define-key diff-mode-map [(control ?c) (control ?e)] 'diff-ediff-patch2))
(defvar cinsk/ediff-wide-display-policy 'center
"Policy of the ediff frame resizing
Set to 'center so that `ediff-toggle-wide-display' will expand
the frame with the pivot in the center of the original frame.
\\='left causes `ediff-toggle-wide-display' will try to keep the
right corder of the original frame. 'right causes to resize with
the left corder unchanged.
In addition to this, it can be either \\='maximize or \\='fullscreen")
(with-eval-after-load "ediff-util"
(defadvice ediff-toggle-wide-display (around cinsk/ad-ediff-toggle-wide-display
())
(interactive)
(let ((w (prefix-numeric-value current-prefix-arg))
(min-width (cond ((window-live-p ediff-window-A)
(if (eq ediff-split-window-function
'split-window-vertically)
;; ediff windows splitted like A/B
(window-width ediff-window-A)
;; ediff windows splitted like A|B
(frame-width (window-frame ediff-window-A))))
((buffer-live-p ediff-buffer-A)
(buffer-local-value 'fill-column
ediff-buffer-A))
(t (max fill-column 70)))))
(setq w (max min-width w))
;;(message "width: %S" w)
(let ((cinsk/ediff-wide-window-width w))
ad-do-it)))
(ad-activate 'ediff-toggle-wide-display))
(defun cinsk/ediff-make-wide-display ()
"Construct an alist of parameters for the wide display.
Saves the old frame parameters in `ediff-wide-display-orig-parameters'.
The frame to be resized is kept in `ediff-wide-display-frame'.
This function modifies only the left margin and the width of the display.
It assumes that it is called from within the control buffer."
;; TODO: try to use `wfu/widen-info' instead of calculate desired coordinate.
(if (memq cinsk/ediff-wide-display-policy '(maximize fullscreen))
(cinsk/ediff-make-huge-display)
(if (not (fboundp 'ediff-display-pixel-width))
(error "Can't determine display width"))
(let* ((frame-A (window-frame ediff-window-A))
(frame-A-params (frame-parameters frame-A))
(fw (frame-width frame-A))
(fpw (frame-pixel-width frame-A))
(cw (frame-char-width frame-A)) ; `ediff-frame-char-width' obsolete
(febw cw) ; frame external border width
(fibw (- fpw (* fw cw))) ; frame internal border width
desired-fw desired-fpw desired-left)
(setq ediff-wide-display-orig-parameters
(list (cons 'left (max 0 (eval (cdr (assoc 'left frame-A-params)))))
(cons 'width (cdr (assoc 'width frame-A-params))))
ediff-wide-display-frame frame-A)
;;(message "ediff-wide-display-orig-parameters: %S"
;; ediff-wide-display-orig-parameters)
;;(message "wide window width: %S" cinsk/ediff-wide-window-width)
;;(message "split function: %S" ediff-split-window-function)
(setq desired-fw (* cinsk/ediff-wide-window-width
(if (and (boundp 'ediff-3way-job) ediff-3way-job)
3 2)))
;; ensure that DESIRED-FW is smaller than the screen size
(if (> (+ (* desired-fw cw) febw fibw) (ediff-display-pixel-width))
(setq desired-fw (/ (- (ediff-display-pixel-width) fibw febw) cw)))
;;(setq desired-fpw (+ (* desired-fw cw) fbw))
(setq desired-fpw (* desired-fw cw))
(let ((left (eval (cdr (assoc 'left frame-A-params)))))
(cond ((eq cinsk/ediff-wide-display-policy 'left)
(setq desired-left (- left (* (- desired-fw fw) cw))))
((eq cinsk/ediff-wide-display-policy 'right)
(setq desired-left left))
(t ; center
(setq desired-left (- left (/ (* (- desired-fw fw) cw) 2)))))
;; ensure that the frame will be inside of the display border.
(if (< (- desired-left (/ febw 2)) 0)
(setq desired-left (/ febw 2)))
(if (> (+ desired-left (+ (* desired-fw cw) fibw (/ febw 2)))
(ediff-display-pixel-width))
(setq desired-left (- (display-pixel-width) ; `ediff-display-pixel-width' obsolete
(+ (* desired-fw cw) fibw (/ febw 2))))))
;; (message "resizing WIDTH to %S where LEFT to %S" desired-fw
;; desired-left)
(modify-frame-parameters
frame-A `((left . ,desired-left) (width . ,desired-fw)
(user-position . t))))))
(defun cinsk/ediff-make-huge-display ()
(let ((frame (window-frame ediff-window-A)))
;; TODO: originally, `ediff-wide-display-orig-parameters' only
;; keep frame parameters such as 'left and 'width. For now,
;; I'll store all parameters, but need to store parameters
;; that actually matter.
(setq ediff-wide-display-orig-parameters (frame-parameters frame))
;; (with-selected-frame frame
(if (eq cinsk/ediff-wide-display-policy 'maximize)
(toggle-frame-maximized)
(toggle-frame-fullscreen))))