diff options
Diffstat (limited to 'lisp/vc/diff-mode.el')
-rw-r--r-- | lisp/vc/diff-mode.el | 185 |
1 files changed, 108 insertions, 77 deletions
diff --git a/lisp/vc/diff-mode.el b/lisp/vc/diff-mode.el index 4652afa1f92..e68aa2257d2 100644 --- a/lisp/vc/diff-mode.el +++ b/lisp/vc/diff-mode.el @@ -55,6 +55,7 @@ ;;; Code: (eval-when-compile (require 'cl-lib)) (eval-when-compile (require 'subr-x)) +(require 'easy-mmode) (autoload 'vc-find-revision "vc") (autoload 'vc-find-revision-no-save "vc") @@ -162,57 +163,55 @@ and hunk-based syntax highlighting otherwise as a fallback." ;;;; keymap, menu, ... ;;;; -(easy-mmode-defmap diff-mode-shared-map - '(("n" . diff-hunk-next) - ("N" . diff-file-next) - ("p" . diff-hunk-prev) - ("P" . diff-file-prev) - ("\t" . diff-hunk-next) - ([backtab] . diff-hunk-prev) - ("k" . diff-hunk-kill) - ("K" . diff-file-kill) - ("}" . diff-file-next) ; From compilation-minor-mode. - ("{" . diff-file-prev) - ("\C-m" . diff-goto-source) - ([mouse-2] . diff-goto-source) - ("W" . widen) - ("o" . diff-goto-source) ; other-window - ("A" . diff-ediff-patch) - ("r" . diff-restrict-view) - ("R" . diff-reverse-direction) - ([remap undo] . diff-undo)) - "Basic keymap for `diff-mode', bound to various prefix keys." - :inherit special-mode-map) - -(easy-mmode-defmap diff-mode-map - `(("\e" . ,(let ((map (make-sparse-keymap))) - ;; We want to inherit most bindings from diff-mode-shared-map, - ;; but not all since they may hide useful M-<foo> global - ;; bindings when editing. - (set-keymap-parent map diff-mode-shared-map) - (dolist (key '("A" "r" "R" "g" "q" "W" "z")) - (define-key map key nil)) - map)) - ;; From compilation-minor-mode. - ("\C-c\C-c" . diff-goto-source) - ;; By analogy with the global C-x 4 a binding. - ("\C-x4A" . diff-add-change-log-entries-other-window) - ;; Misc operations. - ("\C-c\C-a" . diff-apply-hunk) - ("\C-c\C-e" . diff-ediff-patch) - ("\C-c\C-n" . diff-restrict-view) - ("\C-c\C-s" . diff-split-hunk) - ("\C-c\C-t" . diff-test-hunk) - ("\C-c\C-r" . diff-reverse-direction) - ("\C-c\C-u" . diff-context->unified) - ;; `d' because it duplicates the context :-( --Stef - ("\C-c\C-d" . diff-unified->context) - ("\C-c\C-w" . diff-ignore-whitespace-hunk) - ;; `l' because it "refreshes" the hunk like C-l refreshes the screen - ("\C-c\C-l" . diff-refresh-hunk) - ("\C-c\C-b" . diff-refine-hunk) ;No reason for `b' :-( - ("\C-c\C-f" . next-error-follow-minor-mode)) - "Keymap for `diff-mode'. See also `diff-mode-shared-map'.") +(defvar-keymap diff-mode-shared-map + :parent special-mode-map + "n" #'diff-hunk-next + "N" #'diff-file-next + "p" #'diff-hunk-prev + "P" #'diff-file-prev + ["TAB"] #'diff-hunk-next + [backtab] #'diff-hunk-prev + "k" #'diff-hunk-kill + "K" #'diff-file-kill + "}" #'diff-file-next ; From compilation-minor-mode. + "{" #'diff-file-prev + ["RET"] #'diff-goto-source + [mouse-2] #'diff-goto-source + "W" #'widen + "o" #'diff-goto-source ; other-window + "A" #'diff-ediff-patch + "r" #'diff-restrict-view + "R" #'diff-reverse-direction + [remap undo] #'diff-undo) + +(defvar-keymap diff-mode-map + :doc "Keymap for `diff-mode'. See also `diff-mode-shared-map'." + ["ESC"] (let ((map (define-keymap :parent diff-mode-shared-map))) + ;; We want to inherit most bindings from + ;; `diff-mode-shared-map', but not all since they may hide + ;; useful `M-<foo>' global bindings when editing. + (dolist (key '("A" "r" "R" "g" "q" "W" "z")) + (define-key map key nil)) + map) + ;; From compilation-minor-mode. + ["C-c C-c"] #'diff-goto-source + ;; By analogy with the global C-x 4 a binding. + ["C-x 4 A"] #'diff-add-change-log-entries-other-window + ;; Misc operations. + ["C-c C-a"] #'diff-apply-hunk + ["C-c C-e"] #'diff-ediff-patch + ["C-c C-n"] #'diff-restrict-view + ["C-c C-s"] #'diff-split-hunk + ["C-c C-t"] #'diff-test-hunk + ["C-c C-r"] #'diff-reverse-direction + ["C-c C-u"] #'diff-context->unified + ;; `d' because it duplicates the context :-( --Stef + ["C-c C-d"] #'diff-unified->context + ["C-c C-w"] #'diff-ignore-whitespace-hunk + ;; `l' because it "refreshes" the hunk like C-l refreshes the screen + ["C-c C-l"] #'diff-refresh-hunk + ["C-c C-b"] #'diff-refine-hunk ;No reason for `b' :-( + ["C-c C-f"] #'next-error-follow-minor-mode) (easy-menu-define diff-mode-menu diff-mode-map "Menu for `diff-mode'." @@ -269,9 +268,9 @@ and hunk-based syntax highlighting otherwise as a fallback." "Prefix key for `diff-minor-mode' commands." :type '(choice (string "\e") (string "C-c=") string)) -(easy-mmode-defmap diff-minor-mode-map - `((,diff-minor-mode-prefix . ,diff-mode-shared-map)) - "Keymap for `diff-minor-mode'. See also `diff-mode-shared-map'.") +(defvar-keymap diff-minor-mode-map + :doc "Keymap for `diff-minor-mode'. See also `diff-mode-shared-map'." + diff-minor-mode-prefix diff-mode-shared-map) (define-minor-mode diff-auto-refine-mode "Toggle automatic diff hunk finer highlighting (Diff Auto Refine mode). @@ -357,6 +356,18 @@ well." :foreground "green" :extend t)) "`diff-mode' face used to highlight added lines.") +(defface diff-changed-unspecified + '((default + :inherit diff-changed) + (((class color) (min-colors 88) (background light)) + :background "grey90" :extend t) + (((class color) (min-colors 88) (background dark)) + :background "grey20" :extend t) + (((class color)) + :foreground "grey" :extend t)) + "`diff-mode' face used to highlight changed lines." + :version "28.1") + (defface diff-changed '((t nil)) "`diff-mode' face used to highlight changed lines." @@ -436,9 +447,10 @@ well." (defvar diff-use-changed-face (and (face-differs-from-default-p 'diff-changed) (not (face-equal 'diff-changed 'diff-added)) (not (face-equal 'diff-changed 'diff-removed))) - "If non-nil, use the face `diff-changed' for changed lines in context diffs. -Otherwise, use the face `diff-removed' for removed lines, -and the face `diff-added' for added lines.") + "Controls how changed lines are fontified in context diffs. +If non-nil, use the face `diff-changed-unspecified'. Otherwise, +use the face `diff-removed' for removed lines, and the face +`diff-added' for added lines.") (defvar diff-font-lock-keywords `((,(concat "\\(" diff-hunk-header-re-unified "\\)\\(.*\\)$") @@ -470,7 +482,7 @@ and the face `diff-added' for added lines.") diff-indicator-added-face diff-indicator-removed-face))))) (2 (if diff-use-changed-face - 'diff-changed + 'diff-changed-unspecified ;; Otherwise, use the same method as above. (save-match-data (let ((limit (save-excursion (diff-beginning-of-hunk)))) @@ -881,6 +893,9 @@ data such as \"Index: ...\" and such." ;; Fix the original hunk-header. (diff-fixup-modifs start pos)))) +(defun diff--outline-level () + (if (string-match-p diff-hunk-header-re (match-string 0)) + 2 1)) ;;;; ;;;; jump to other buffers @@ -956,11 +971,11 @@ If the OLD prefix arg is passed, tell the file NAME of the old file." (list (match-string 1))) header-files ;; this assumes that there are no spaces in filenames - (when (re-search-backward - "^diff \\(-\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?" - nil t) - (list (if old (match-string 2) (match-string 4)) - (if old (match-string 4) (match-string 2))))))))) + (and (re-search-backward "^diff " nil t) + (looking-at + "^diff \\(-[^ \t\nL]+ +\\)*\\(-L +\\S-+ +\\)*\\(\\S-+\\)\\( +\\(\\S-+\\)\\)?") + (list (if old (match-string 3) (match-string 5)) + (if old (match-string 4) (match-string 3))))))))) (defun diff-find-file-name (&optional old noprompt prefix) "Return the file corresponding to the current patch. @@ -1342,7 +1357,11 @@ else cover the whole buffer." (pcase (char-after) (?\s (cl-incf space)) (?+ (cl-incf plus)) - (?- (cl-incf minus)) + (?- (unless ;; In git format-patch "^-- $" signifies + ;; the end of the patch. + (and (eq diff-buffer-type 'git) + (looking-at "^-- $")) + (cl-incf minus))) (?! (cl-incf bang)) ((or ?\\ ?#) nil) (?\n (if diff-valid-unified-empty-line @@ -1466,7 +1485,7 @@ Supports unified and context diffs as well as (to a lesser extent) normal diffs. When the buffer is read-only, the ESC prefix is not necessary. -If you edit the buffer manually, diff-mode will try to update the hunk +If you edit the buffer manually, `diff-mode' will try to update the hunk headers for you on-the-fly. You can also switch between context diff and unified diff with \\[diff-context->unified], @@ -1477,7 +1496,6 @@ a diff with \\[diff-reverse-direction]. (setq-local font-lock-defaults diff-font-lock-defaults) (add-hook 'font-lock-mode-hook #'diff--font-lock-cleanup nil 'local) - (setq-local outline-regexp diff-outline-regexp) (setq-local imenu-generic-expression diff-imenu-generic-expression) ;; These are not perfect. They would be better done separately for @@ -1522,11 +1540,7 @@ a diff with \\[diff-reverse-direction]. #'diff--filter-substring) (unless buffer-file-name (hack-dir-local-variables-non-file-buffer)) - (save-excursion - (setq-local diff-buffer-type - (if (re-search-forward "^diff --git" nil t) - 'git - nil)))) + (diff-setup-buffer-type)) ;;;###autoload (define-minor-mode diff-minor-mode @@ -1562,6 +1576,21 @@ modified lines of the diff." "^[-+!] .*?\\([\t ]+\\)$" "^[-+!<>].*?\\([\t ]+\\)$")))) +(defun diff-setup-buffer-type () + "Try to guess the `diff-buffer-type' from content of current Diff mode buffer. +`outline-regexp' is updated accordingly." + (save-excursion + (goto-char (point-min)) + (setq-local diff-buffer-type + (if (re-search-forward "^diff --git" nil t) + 'git + nil))) + (when (eq diff-buffer-type 'git) + (setq diff-outline-regexp + (concat "\\(^diff --git.*\n\\|" diff-hunk-header-re "\\)")) + (setq-local outline-level #'diff--outline-level)) + (setq-local outline-regexp diff-outline-regexp)) + (defun diff-delete-if-empty () ;; An empty diff file means there's no more diffs to integrate, so we ;; can just remove the file altogether. Very handy for .rej files if we @@ -2586,13 +2615,15 @@ fixed, visit it in a buffer." (or (match-beginning 2) (match-beginning 1)) 'display (propertize (cond - ((null (match-beginning 1)) "new file ") - ((null (match-beginning 2)) "deleted ") - (t "modified ")) + ((null (match-beginning 1)) + (concat "new file " (match-string 2))) + ((null (match-beginning 2)) + (concat "deleted " (match-string 1))) + (t + (concat "modified " (match-string 1)))) 'face '(diff-file-header diff-header))) - (unless (match-beginning 2) - (put-text-property (match-end 1) (1- (match-end 0)) - 'display ""))))) + (put-text-property (match-end 1) (1- (match-end 0)) + 'display "")))) nil) ;;; Syntax highlighting from font-lock |