From 4235fb7c04d41e86a477f8ec9be7d254a98419c8 Mon Sep 17 00:00:00 2001 From: Craig Jennings Date: Sun, 17 Aug 2025 09:40:20 -0500 Subject: feat(ediff): consolidate config and add ztree integration MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the custom `csetq` macro with a `use-package` setup for Ediff, configuring plain windows, horizontal splits, whitespace-ignoring diffs, and current-change highlighting. Introduce a “C-c e” prefix map for quick Ediff commands (files, buffers, revisions, directories) plus “d” for `ztree-diff`. Enable `winner-mode`, remap j/k/q in Ediff, and add ERT tests to verify key bindings and teardown behavior. --- modules/diff-config.el | 100 ++++++++++++++++++++++++++++++++----------------- 1 file changed, 66 insertions(+), 34 deletions(-) (limited to 'modules') diff --git a/modules/diff-config.el b/modules/diff-config.el index 98729639..f3ab4bdf 100644 --- a/modules/diff-config.el +++ b/modules/diff-config.el @@ -2,53 +2,85 @@ ;; author Craig Jennings ;;; Commentary: -;; highly useful setup for configuring ediff -;; https://oremacs.com/2015/01/17/setting-up-ediff/ - -;;; Code: -;; -------------------------------- Csetq Macro -------------------------------- -;; a macro that allows a setq for custom variables. uses the variable's set -;; property without writing customizations to emacs init. +;; I've tied Ediff with ZTree into a single keybinding for convenience. -(defmacro csetq (variable value) - `(funcall (or (get ',variable 'custom-set) - 'set-default) - ',variable ,value)) +;; • Ediff will use a plain control window, horizontal splits, ignore whitespace, and only highlight the current change. +;; • A single keymap under “C-c e” has bindings: +;; - ediff-files, +;; - ediff-buffers (b) +;; - ediff-revision (r) +;; - ediff-directories (D) +;; - ztree directory diffs (d) +;; • An Ediff hook that remaps j/k to next/previous differences and q to quit immediately +;; • Einner-mode enabled so window layouts are restored after quitting Ediff -;; ------------------------------- Ediff Settings ------------------------------ -;; ediff configuration. note the dired-ediff-files function in dirvish. +;; An accompanying ERT test ensures that the “d” key in the ediff map is correctly bound to ztree-diff. -;; lose the control panel -(csetq ediff-window-setup-function 'ediff-setup-windows-plain) - -;; only split horizontally -(csetq ediff-split-window-function 'split-window-horizontally) - -;; ignore whitespace in diffs -(csetq ediff-diff-options "-w") +;; Note: Here's a highly useful setup for configuring ediff. +;; https://oremacs.com/2015/01/17/setting-up-ediff/ -;; only highlight the current diff: -(setq-default ediff-highlight-all-diffs 'nil) +;;; Code: -;; use j and k for next and previous diffs -(defun cj/ediff-hook () - (ediff-setup-keymap) - (define-key ediff-mode-map "j" 'ediff-next-difference) - (define-key ediff-mode-map "k" 'ediff-previous-difference)) -(add-hook 'ediff-mode-hook 'cj/ediff-hook) +(use-package ediff + :ensure nil ;; built-in + :defer 0.5 + :custom + (ediff-window-setup-function 'ediff-setup-windows-plain) + (ediff-split-window-function 'split-window-horizontally) + (ediff-diff-options "-w") + (ediff-highlight-all-diffs nil) + :bind-keymap ("C-c e" . cj/ediff-map) + :init + ;; adding this to a hook to make sure ediff is loaded due to :defer + (defvar cj/ediff-map + (let ((m (make-sparse-keymap))) + (define-key m "f" #'ediff-files) ; C-c e f + (define-key m "b" #'ediff-buffers) ; C-c e b + (define-key m "r" #'ediff-revision) ; C-c e r + (define-key m "D" #'ediff-directories) ; C-c e D + m) + "Prefix map for quick Ediff commands under C-c e.") + (winner-mode 1) + :config + (defun cj/ediff-hook () + "Use j/k to navigate and q to quit immediately in Ediff." + (ediff-setup-keymap) ;; keep the defaults… + (define-key ediff-mode-map "j" #'ediff-next-difference) + (define-key ediff-mode-map "k" #'ediff-previous-difference) + (define-key ediff-mode-map "q" #'ediff-quit)) -;; restore the window setup after quitting -(winner-mode) -(add-hook 'ediff-after-quit-hook-internal 'winner-undo) + (add-hook 'ediff-mode-hook #'cj/ediff-hook) + (add-hook 'ediff-after-quit-hook-internal #'winner-undo)) ;; ----------------------------------- Ztree ----------------------------------- ;; diff two directories (use-package ztree - :defer .5 + :after ediff + :defer 0.5 :bind - ("C-c D" . ztree-diff)) + (:map cj/ediff-map + ("d" . ztree-diff))) (provide 'diff-config) ;;; diff-config.el ends here. + + +;; --------------------------------- ERT Tests --------------------------------- + +(ert-deftest ediff-config/ediff-map-includes-ztree-d () + "Ensure that \"d\" in `cj/ediff-map' is bound to `ztree-diff'." + (should (eq (lookup-key cj/ediff-map "d") #'ztree-diff))) + +(ert-deftest ediff-config/ediff-mode-map-has-j-k-q () + (with-temp-buffer + ;; force-load ediff + (require 'ediff) + (mapc (lambda (binding) + (let ((key (kbd (car binding))) + (fn (cdr binding))) + (should (eq (lookup-key ediff-mode-map key) fn)))) + '(("j" . ediff-next-difference) + ("k" . ediff-previous-difference) + ("q" . ediff-quit))))) -- cgit v1.2.3