update packages

This commit is contained in:
2025-02-26 20:16:44 +01:00
parent 59db017445
commit 45d49daef0
291 changed files with 16240 additions and 522600 deletions

View File

@@ -1,11 +1,11 @@
;;; diff-hl.el --- Highlight uncommitted changes using VC -*- lexical-binding: t -*-
;; Copyright (C) 2012-2023 Free Software Foundation, Inc.
;; Copyright (C) 2012-2024 Free Software Foundation, Inc.
;; Author: Dmitry Gutov <dgutov@yandex.ru>
;; Author: Dmitry Gutov <dmitry@gutov.dev>
;; URL: https://github.com/dgutov/diff-hl
;; Keywords: vc, diff
;; Version: 1.9.2
;; Version: 1.10.0
;; Package-Requires: ((cl-lib "0.2") (emacs "25.1"))
;; This file is part of GNU Emacs.
@@ -194,8 +194,30 @@ the NEW revision is not specified (meaning, the diff is against
the current version of the file)."
:type 'boolean)
(defcustom diff-hl-update-async nil
"When non-nil, `diff-hl-update' will run asynchronously.
This can help prevent Emacs from freezing, especially by a slow version
control (VC) backend. It's disabled in remote buffers, though, since it
didn't work reliably in such during testing."
:type 'boolean)
;; Threads are not reliable with remote files, yet.
(defcustom diff-hl-async-inhibit-functions (list #'diff-hl-with-editor-p
#'file-remote-p)
"Functions to call to check whether asychronous method should be disabled.
When `diff-hl-update-async' is non-nil, these functions are called in turn
and passed the value `default-directory'.
If any returns non-nil, `diff-hl-update' will run synchronously anyway."
:type '(repeat :tag "Predicate" function))
(defvar diff-hl-reference-revision nil
"Revision to diff against. nil means the most recent one.")
"Revision to diff against. nil means the most recent one.
It can be a relative expression as well, such as \"HEAD^\" with Git, or
\"-2\" with Mercurial.")
(defun diff-hl-define-bitmaps ()
(let* ((scale (if (and (boundp 'text-scale-mode-amount)
@@ -309,6 +331,8 @@ the current version of the file)."
diff-hl-reference-revision))))
(declare-function vc-git-command "vc-git")
(declare-function vc-git--rev-parse "vc-git")
(declare-function vc-hg-command "vc-hg")
(defun diff-hl-changes-buffer (file backend)
(diff-hl-with-diff-switches
@@ -384,6 +408,28 @@ the current version of the file)."
(nreverse res))))
(defun diff-hl-update ()
"Updates the diff-hl overlay."
(if (and diff-hl-update-async
(not
(run-hook-with-args-until-success 'diff-hl-async-inhibit-functions
default-directory)))
;; TODO: debounce if a thread is already running.
(make-thread 'diff-hl--update-safe "diff-hl--update-safe")
(diff-hl--update)))
(defun diff-hl-with-editor-p (_dir)
(bound-and-true-p with-editor-mode))
(defun diff-hl--update-safe ()
"Updates the diff-hl overlay. It handles and logs when an error is signaled."
(condition-case err
(diff-hl--update)
(error
(message "An error occurred in diff-hl--update: %S" err)
nil)))
(defun diff-hl--update ()
"Updates the diff-hl overlay."
(let ((changes (diff-hl-changes))
(current-line 1))
(diff-hl-remove-overlays)
@@ -460,13 +506,13 @@ the current version of the file)."
(run-with-idle-timer 0.01 nil #'diff-hl-after-undo (current-buffer)))))
(defun diff-hl-after-undo (buffer)
(with-current-buffer buffer
(unless (buffer-modified-p)
(diff-hl-update))))
(when (buffer-live-p buffer)
(with-current-buffer buffer
(unless (buffer-modified-p)
(diff-hl-update)))))
(defun diff-hl-after-revert ()
(defvar revert-buffer-preserve-modes)
(when revert-buffer-preserve-modes
(when (bound-and-true-p revert-buffer-preserve-modes)
(diff-hl-update)))
(defun diff-hl-diff-goto-hunk-1 (historic)
@@ -708,6 +754,21 @@ its end position."
(unless (eq backend 'Git)
(user-error "Only Git supports staging; this file is controlled by %s" backend))))
(defun diff-hl-stage-diff (orig-buffer)
(let ((patchfile (make-temp-file "diff-hl-stage-patch"))
success)
(write-region (point-min) (point-max) patchfile
nil 'silent)
(unwind-protect
(with-current-buffer orig-buffer
(with-output-to-string
(vc-git-command standard-output 0
patchfile
"apply" "--cached" )
(setq success t)))
(delete-file patchfile))
success))
(defun diff-hl-stage-current-hunk ()
"Stage the hunk at or near point.
@@ -741,17 +802,7 @@ Only supported with Git."
(insert (format "diff a/%s b/%s\n" file-base file-base))
(insert (format "--- a/%s\n" file-base))
(insert (format "+++ b/%s\n" file-base)))
(let ((patchfile (make-temp-file "diff-hl-stage-patch")))
(write-region (point-min) (point-max) patchfile
nil 'silent)
(unwind-protect
(with-current-buffer orig-buffer
(with-output-to-string
(vc-git-command standard-output 0
patchfile
"apply" "--cached" ))
(setq success t))
(delete-file patchfile))))
(setq success (diff-hl-stage-diff orig-buffer)))
(when success
(if diff-hl-show-staged-changes
(message (concat "Hunk staged; customize `diff-hl-show-staged-changes'"
@@ -773,6 +824,85 @@ Only supported with Git."
(unless diff-hl-show-staged-changes
(diff-hl-update)))
(defun diff-hl-stage-dwim (&optional with-edit)
"Stage the current hunk or choose the hunks to stage.
When called with the prefix argument, invokes `diff-hl-stage-some'."
(interactive "P")
(if (or with-edit (region-active-p))
(call-interactively #'diff-hl-stage-some)
(call-interactively #'diff-hl-stage-current-hunk)))
(defvar diff-hl-stage--orig nil)
(define-derived-mode diff-hl-stage-diff-mode diff-mode "Stage Diff"
"Major mode for editing a diff buffer before staging.
\\[diff-hl-stage-commit]"
(setq revert-buffer-function #'ignore))
(define-key diff-hl-stage-diff-mode-map (kbd "C-c C-c") #'diff-hl-stage-finish)
(defun diff-hl-stage-some (&optional beg end)
"Stage some or all of the current changes, interactively.
Pops up a diff buffer that can be edited to choose the changes to stage."
(interactive "r")
(diff-hl--ensure-staging-supported)
(let* ((line-beg (and beg (line-number-at-pos beg t)))
(line-end (and end (line-number-at-pos end t)))
(file buffer-file-name)
(dest-buffer (get-buffer-create "*diff-hl-stage-some*"))
(orig-buffer (current-buffer))
;; FIXME: If the file name has double quotes, these need to be quoted.
(file-base (file-name-nondirectory file)))
(with-current-buffer dest-buffer
(let ((inhibit-read-only t))
(erase-buffer)))
(diff-hl-diff-buffer-with-reference file dest-buffer nil 3)
(with-current-buffer dest-buffer
(let ((inhibit-read-only t))
(when end
(with-no-warnings
(let (diff-auto-refine-mode)
(diff-hl-diff-skip-to line-end)
(diff-hl-split-away-changes 3)
(diff-end-of-hunk)))
(delete-region (point) (point-max)))
(if beg
(with-no-warnings
(let (diff-auto-refine-mode)
(diff-hl-diff-skip-to line-beg)
(diff-hl-split-away-changes 3)
(diff-beginning-of-hunk)))
(goto-char (point-min))
(forward-line 3))
(delete-region (point-min) (point))
;; diff-no-select creates a very ugly header; Git rejects it
(insert (format "diff a/%s b/%s\n" file-base file-base))
(insert (format "--- a/%s\n" file-base))
(insert (format "+++ b/%s\n" file-base)))
(let ((diff-default-read-only t))
(diff-hl-stage-diff-mode))
(setq-local diff-hl-stage--orig orig-buffer))
(pop-to-buffer dest-buffer)
(message "Press %s and %s to navigate, %s to split, %s to kill hunk, %s to undo, and %s to stage the diff after editing"
(substitute-command-keys "\\`n'")
(substitute-command-keys "\\`p'")
(substitute-command-keys "\\[diff-split-hunk]")
(substitute-command-keys "\\[diff-hunk-kill]")
(substitute-command-keys "\\[diff-undo]")
(substitute-command-keys "\\[diff-hl-stage-finish]"))))
(defun diff-hl-stage-finish ()
(interactive)
(let ((count 0))
(when (diff-hl-stage-diff diff-hl-stage--orig)
(save-excursion
(goto-char (point-min))
(while (re-search-forward diff-hunk-header-re-unified nil t)
(cl-incf count)))
(message "Staged %d hunks" count)
(bury-buffer))))
(defvar diff-hl-command-map
(let ((map (make-sparse-keymap)))
(define-key map "n" 'diff-hl-revert-hunk)
@@ -781,7 +911,7 @@ Only supported with Git."
(define-key map "*" 'diff-hl-show-hunk)
(define-key map "{" 'diff-hl-show-hunk-previous)
(define-key map "}" 'diff-hl-show-hunk-next)
(define-key map "S" 'diff-hl-stage-current-hunk)
(define-key map "S" 'diff-hl-stage-dwim)
map))
(fset 'diff-hl-command-map diff-hl-command-map)
@@ -827,7 +957,7 @@ The value of this variable is a mode line template as in
(remove-hook 'after-save-hook 'diff-hl-update t)
(remove-hook 'after-change-functions 'diff-hl-edit t)
(remove-hook 'find-file-hook 'diff-hl-update t)
(remove-hook 'after-revert-hook 'diff-hl-update t)
(remove-hook 'after-revert-hook 'diff-hl-after-revert t)
(remove-hook 'magit-revert-buffer-hook 'diff-hl-update t)
(remove-hook 'magit-not-reverted-hook 'diff-hl-update t)
(remove-hook 'text-scale-mode-hook 'diff-hl-maybe-redefine-bitmaps t)
@@ -871,49 +1001,38 @@ The value of this variable is a mode line template as in
diff-hl-command-map)
(declare-function magit-toplevel "magit-git")
(declare-function magit-unstaged-files "magit-git")
(declare-function magit-git-items "magit-git")
(defvar diff-hl--magit-unstaged-files nil)
(defun diff-hl-magit-pre-refresh ()
(unless (and diff-hl-disable-on-remote
(file-remote-p default-directory))
(setq diff-hl--magit-unstaged-files (magit-unstaged-files t))))
(define-obsolete-function-alias 'diff-hl-magit-pre-refresh 'ignore "1.11.0")
(defun diff-hl-magit-post-refresh ()
(unless (and diff-hl-disable-on-remote
(file-remote-p default-directory))
(let* ((topdir (magit-toplevel))
(modified-files
(mapcar (lambda (file) (expand-file-name file topdir))
(delete-consecutive-dups
(sort
(nconc (magit-unstaged-files t)
diff-hl--magit-unstaged-files)
#'string<))))
(unmodified-states '(up-to-date ignored unregistered)))
(setq diff-hl--magit-unstaged-files nil)
(dolist (buf (buffer-list))
(when (and (buffer-local-value 'diff-hl-mode buf)
(not (buffer-modified-p buf))
;; Solve the "cloned indirect buffer" problem
;; (diff-hl-mode could be non-nil there, even if
;; buffer-file-name is nil):
(buffer-file-name buf)
(file-in-directory-p (buffer-file-name buf) topdir)
(file-exists-p (buffer-file-name buf)))
(with-current-buffer buf
(let* ((file buffer-file-name)
(backend (vc-backend file)))
(when backend
(cond
((member file modified-files)
(when (memq (vc-state file) unmodified-states)
(vc-state-refresh file backend))
(diff-hl-update))
((not (memq (vc-state file backend) unmodified-states))
(vc-state-refresh file backend)
(diff-hl-update)))))))))))
(let* ((topdir (magit-toplevel))
(modified-files
(magit-git-items "diff-tree" "-z" "--name-only" "-r" "HEAD~" "HEAD"))
(unmodified-states '(up-to-date ignored unregistered)))
(dolist (buf (buffer-list))
(when (and (buffer-local-value 'diff-hl-mode buf)
(not (buffer-modified-p buf))
;; Solve the "cloned indirect buffer" problem
;; (diff-hl-mode could be non-nil there, even if
;; buffer-file-name is nil):
(buffer-file-name buf)
(file-in-directory-p (buffer-file-name buf) topdir)
(file-exists-p (buffer-file-name buf)))
(with-current-buffer buf
(let* ((file buffer-file-name)
(backend (vc-backend file)))
(when backend
(cond
((member file modified-files)
(when (memq (vc-state file) unmodified-states)
(vc-state-refresh file backend))
(diff-hl-update))
((not (memq (vc-state file backend) unmodified-states))
(vc-state-refresh file backend)
(diff-hl-update)))))))))))
(defun diff-hl-dir-update ()
(dolist (pair (if (vc-dir-marked-files)
@@ -988,7 +1107,7 @@ CONTEXT-LINES is the size of the unified diff context, defaults to 0."
(let* ((dest-buffer (or dest-buffer "*diff-hl-diff-buffer-with-reference*"))
(backend (or backend (vc-backend file)))
(temporary-file-directory
(if (file-directory-p "/dev/shm/")
(if (and (eq system-type 'gnu/linux) (file-directory-p "/dev/shm/"))
"/dev/shm/"
temporary-file-directory))
(rev
@@ -1000,7 +1119,7 @@ CONTEXT-LINES is the size of the unified diff context, defaults to 0."
(diff-hl-git-index-object-name file))
(diff-hl-create-revision
file
(or diff-hl-reference-revision
(or (diff-hl-resolved-reference-revision backend)
(diff-hl-working-revision file backend)))))
(switches (format "-U %d --strip-trailing-cr" (or context-lines 0))))
(diff-no-select rev (current-buffer) switches 'noasync
@@ -1011,18 +1130,34 @@ CONTEXT-LINES is the size of the unified diff context, defaults to 0."
(delete-matching-lines "^Diff finished.*")))
(get-buffer-create dest-buffer))))
(defun diff-hl-resolved-reference-revision (backend)
(cond
((null diff-hl-reference-revision)
nil)
((eq backend 'Git)
(vc-git--rev-parse diff-hl-reference-revision))
((eq backend 'Hg)
(with-temp-buffer
(vc-hg-command (current-buffer) 0 nil
"identify" "-r" diff-hl-reference-revision
"-i")
(goto-char (point-min))
(buffer-substring-no-properties (point) (line-end-position))))
(t
diff-hl-reference-revision)))
;; TODO: Cache based on .git/index's mtime, maybe.
(defun diff-hl-git-index-object-name (file)
(with-temp-buffer
(vc-git-command (current-buffer) 0 file "ls-files" "-s")
(and
(goto-char (point-min))
(re-search-forward "^[0-9]+ \\([0-9a-f]+\\)")
(re-search-forward "^[0-9]+ \\([0-9a-f]+\\)" nil t)
(match-string-no-properties 1))))
(defun diff-hl-git-index-revision (file object-name)
(let ((filename (diff-hl-make-temp-file-name file
(concat ":" object-name)
(concat ";" object-name)
'manual))
(filebuf (get-file-buffer file)))
(unless (file-exists-p filename)