From: Andreas Gerler Date: Wed, 21 May 2025 12:41:45 +0000 (+0200) Subject: update git-timemachine X-Git-Url: http://git.bundesbrandschatzamt.de/?a=commitdiff_plain;h=99661f09a3cfedeede8edcf8125e5f5d73faf3c9;p=emacsconfig.git update git-timemachine --- diff --git a/elpa/git-timemachine-20241125.750/git-timemachine-autoloads.el b/elpa/git-timemachine-20241125.750/git-timemachine-autoloads.el deleted file mode 100644 index 11db8b1c..00000000 --- a/elpa/git-timemachine-20241125.750/git-timemachine-autoloads.el +++ /dev/null @@ -1,36 +0,0 @@ -;;; git-timemachine-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- -;; Generated by the `loaddefs-generate' function. - -;; This file is part of GNU Emacs. - -;;; Code: - -(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) - - - -;;; Generated autoloads from git-timemachine.el - -(autoload 'git-timemachine-toggle "git-timemachine" "\ -Toggle git timemachine mode." t) -(autoload 'git-timemachine "git-timemachine" "\ -Enable git timemachine for file of current buffer." t) -(autoload 'git-timemachine-switch-branch "git-timemachine" "\ -Enable git timemachine for current buffer, switching to GIT-BRANCH. - -(fn GIT-BRANCH)" t) -(register-definition-prefixes "git-timemachine" '("git-timemachine-")) - -;;; End of scraped data - -(provide 'git-timemachine-autoloads) - -;; Local Variables: -;; version-control: never -;; no-byte-compile: t -;; no-update-autoloads: t -;; no-native-compile: t -;; coding: utf-8-emacs-unix -;; End: - -;;; git-timemachine-autoloads.el ends here diff --git a/elpa/git-timemachine-20241125.750/git-timemachine-pkg.el b/elpa/git-timemachine-20241125.750/git-timemachine-pkg.el deleted file mode 100644 index fa271a2f..00000000 --- a/elpa/git-timemachine-20241125.750/git-timemachine-pkg.el +++ /dev/null @@ -1,11 +0,0 @@ -;; -*- no-byte-compile: t; lexical-binding: nil -*- -(define-package "git-timemachine" "20241125.750" - "Walk through git revisions of a file." - '((emacs "24.3") - (transient "0.1.0")) - :url "https://codeberg.org/pidu/git-timemachine" - :commit "62ebb0c6588d848b1b7b90bf1a3aa4c04e873822" - :revdesc "62ebb0c6588d" - :keywords '("vc") - :authors '(("Peter Stiernström" . "peter@stiernstrom.se")) - :maintainers '(("Peter Stiernström" . "peter@stiernstrom.se"))) diff --git a/elpa/git-timemachine-20241125.750/git-timemachine.el b/elpa/git-timemachine-20241125.750/git-timemachine.el deleted file mode 100755 index 30e23e28..00000000 --- a/elpa/git-timemachine-20241125.750/git-timemachine.el +++ /dev/null @@ -1,496 +0,0 @@ -;;; git-timemachine.el --- Walk through git revisions of a file - -;; Copyright (C) 2014 Peter Stiernström - -;; Author: Peter Stiernström -;; Package-Version: 20241125.750 -;; Package-Revision: 62ebb0c6588d -;; URL: https://codeberg.org/pidu/git-timemachine -;; Keywords: vc -;; Package-Requires: ((emacs "24.3") (transient "0.1.0")) - -;; This file is not part of GNU Emacs - -;; 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 . - -;;; Commentary: - -;;; Use git-timemachine to browse historic versions of a file with p -;;; (previous) and n (next). - -;;; Code: - -(require 'vc-git) -(require 'cl-lib) -(require 'transient) - -(defgroup git-timemachine nil - "Walk through git revisions of a file." - :link '(url-link "https://codeberg.org/pidu/git-timemachine") - :group 'tools) - -(defcustom git-timemachine-abbreviation-length 12 - "Number of chars from the full sha1 hash to use for abbreviation." - :type 'integer - :group 'git-timemachine) - -(defcustom git-timemachine-show-minibuffer-details t - "Non-nil means that details of the commit (its hash and date) -will be shown in the minibuffer while navigating commits." - :type 'boolean - :group 'git-timemachine) - -(defface git-timemachine-commit - '((default :weight bold)) - "Face for git timemachine commit sha." - :group 'git-timemachine) - -(defface git-timemachine-minibuffer-detail-face - '((((class color) (background dark)) - :foreground "yellow") - (((class color) (background light)) - :foreground "yellow4")) - "How to display the minibuffer detail." - :group 'git-timemachine) - -(defface git-timemachine-minibuffer-author-face - '((((class color) (background dark)) - :foreground "orange") - (((class color) (background light)) - :foreground "DarkOrange4")) - "How to display the author in minibuffer." - :group 'git-timemachine) - -(defcustom git-timemachine-minibuffer-detail - 'subject - "What to display when `git-timemachine-show-minibuffer-details` is t. -Available values are: -`commit` : The SHA hash of the commit -`subject`: The subject of the commit message" - :type '(radio (const :tag "Commit SHA" commit) (const :tag "Commit Subject" subject)) - :group 'git-timemachine) - -(defcustom git-timemachine-show-author - t - "Prepend author to minibuffer details." - :type 'boolean - :group 'git-timemachine) - -(defcustom git-timemachine-global-git-arguments - '("-c" "log.showSignature=false" "--no-pager") - "Common arguments for all git commands." - :type 'list - :group 'git-timemachine) - -(defcustom git-timemachine-quit-to-invoking-buffer - t - "Switch to invoking buffer on `git-timemachine-quit`." - :type 'boolean - :group 'git-timemachine) - -(defvar-local git-timemachine-directory nil) -(defvar-local git-timemachine-revision nil) -(defvar-local git-timemachine-file nil) -(defvar-local git-timemachine--revisions-cache nil) - -(defun git-timemachine--process-file (&rest args) - "Run `process-file` with ARGS and `git-timemachine-global-git-arguments` applied." - (apply #'process-file vc-git-program nil t nil (append git-timemachine-global-git-arguments args))) - -(defun git-timemachine--revisions (&optional git-branch) - "List git revisions of current buffers file. - -When passed a GIT-BRANCH, lists revisions from that branch." - (if git-timemachine--revisions-cache - git-timemachine--revisions-cache - (setq git-timemachine--revisions-cache - (prog2 - (message "Fetching Revisions...") - (let ((default-directory git-timemachine-directory) - (file git-timemachine-file)) - (with-temp-buffer - - (unless (zerop (if git-branch - (git-timemachine--process-file "log" git-branch "--name-only" "--follow" "--pretty=format:%H%x00%ar%x00%ad%x00%s%x00%an" "--" file) - (git-timemachine--process-file "log" "--name-only" "--follow" "--pretty=format:%H%x00%ar%x00%ad%x00%s%x00%an" "--" file))) - (error "Git log command exited with non-zero exit status for file: %s" file)) - - (goto-char (point-min)) - (let ((lines) - (commit-number (/ (1+ (count-lines (point-min) (point-max))) 3))) - (while (not (eobp)) - (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) - (string-match "\\([^\0]*\\)\0\\([^\0]*\\)\0\\([^\0]*\\)\0\\(.*\\)\0\\(.*\\)" line) - (let ((commit (match-string 1 line)) - (date-relative (match-string 2 line)) - (date-full (match-string 3 line)) - (subject (match-string 4 line)) - (author (match-string 5 line))) - (forward-line 1) - (let ((file-name (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) - (push (list commit file-name commit-number date-relative date-full subject author) lines)))) - (setq commit-number (1- commit-number)) - (forward-line 2)) - (nreverse lines)))) - (message "Fetching Revisions...done"))))) - -(defun git-timemachine-show-current-revision () - "Show last (current) revision of file." - (interactive) - (git-timemachine-show-revision (car (git-timemachine--revisions)))) - -(defun git-timemachine-show-latest-revision-in-branch (git-branch) - "Show last (current) revision of file in GIT-BRANCH." - (interactive "MGit branch: ") - (git-timemachine-show-revision (car (git-timemachine--revisions git-branch)))) - -(defun git-timemachine--next-revision (revisions) - "Return the revision following the current revision in REVISIONS." - (or (cadr (cl-member (car git-timemachine-revision) revisions :key #'car :test #'string=)) - (car (reverse revisions)))) - -(defun git-timemachine-show-previous-revision () - "Show previous revision of file." - (interactive) - (let ((new-line nil) - (curr-revision git-timemachine-revision) - (new-revision (git-timemachine--next-revision (git-timemachine--revisions))) - (cursor-win-pos (git-timemachine--get-cursor-position))) - (setq new-line (git-timemachine--find-new-current-line curr-revision new-revision (line-number-at-pos))) - (git-timemachine-show-revision new-revision) - (forward-line (- new-line (line-number-at-pos))) - (git-timemachine--set-cursor-position cursor-win-pos))) - -(defun git-timemachine-show-next-revision () - "Show next revision of file." - (interactive) - (let ((new-line nil) - (curr-revision git-timemachine-revision) - (new-revision (git-timemachine--next-revision (reverse (git-timemachine--revisions)))) - (cursor-win-pos (git-timemachine--get-cursor-position))) - (setq new-line (git-timemachine--find-new-current-line curr-revision new-revision (line-number-at-pos))) - (git-timemachine-show-revision new-revision) - (forward-line (- new-line (line-number-at-pos))) - (git-timemachine--set-cursor-position cursor-win-pos))) - -(defun git-timemachine-show-revision-fuzzy () - "Show the revision with the chosen commit message." - (interactive) - (let* ((revisions (git-timemachine--revisions)) - (wanted - (funcall #'completing-read "Commit message: " - (mapcar (apply-partially #'nth 5) revisions)))) - (git-timemachine-show-revision - (cl-find wanted revisions - :key (apply-partially #'nth 5) - :test #'equal)))) - -(defun git-timemachine-show-nth-revision (rev-number) - "Show the REV-NUMBER revision." - (interactive "nEnter revision number: ") - (let* ((revisions (reverse (git-timemachine--revisions))) - (num-revisions (length revisions)) - (curr-revision git-timemachine-revision) - (new-revision (nth (1- rev-number) revisions)) - (new-line nil) - (cursor-win-pos (git-timemachine--get-cursor-position))) - (if (not new-revision) - (message "Only %d revisions exist." num-revisions) - (setq new-line (git-timemachine--find-new-current-line curr-revision new-revision (line-number-at-pos))) - (git-timemachine-show-revision new-revision) - (forward-line (- new-line (line-number-at-pos))) - (git-timemachine--set-cursor-position cursor-win-pos)))) - -(defun git-timemachine-show-nearest-revision (&optional relative-hash) - "Show last revision of the current file nearest to RELATIVE-HASH." - (interactive "sEnter commit hash: ") - (let* ((abs-file-name (buffer-file-name (current-buffer))) - (root-directory - (expand-file-name - (vc-call-backend - (vc-responsible-backend abs-file-name) - 'root abs-file-name))) - (default-directory root-directory) - (file-name (string-remove-prefix root-directory abs-file-name)) - (line - (with-temp-buffer - (process-file vc-git-program nil t nil "log" "--max-count" "1" relative-hash "--pretty=format:%H%x00%ar%x00%ad%x00%s%x00%an" "--" file-name) - (buffer-substring-no-properties (point-min) (point-max)))) - (line-list (unless (string-prefix-p "fatal" line t) (string-split line "\0"))) - (hash (nth 0 line-list)) - (date-relative (nth 1 line-list)) - (date-full (nth 2 line-list)) - (subject (nth 3 line-list)) - (author (nth 4 line-list)) - (revision (list hash file-name -1 date-relative date-full subject author))) - (if line-list - (git-timemachine-show-revision revision) - (message "No such commit %s" relative-hash)))) - -(defun git-timemachine-show-revision (revision) - "Show a REVISION (commit hash) of the current file." - (when revision - (let ((current-position (point)) - (commit (car revision)) - (revision-file-name (nth 1 revision)) - (commit-index (nth 2 revision)) - (date-relative (nth 3 revision)) - (date-full (nth 4 revision)) - (subject (nth 5 revision))) - (when (bound-and-true-p magit-blame-mode) (magit-blame-quit)) - (setq buffer-read-only nil) - (erase-buffer) - (let ((default-directory git-timemachine-directory) - (process-coding-system-alist (list (cons "" (cons buffer-file-coding-system default-process-coding-system))))) - (git-timemachine--process-file "show" (concat commit ":" revision-file-name))) - (setq buffer-read-only t) - (set-buffer-modified-p nil) - (let* ((revisions (git-timemachine--revisions)) - (n-of-m (format "(%d/%d %s)" commit-index (length revisions) date-relative))) - (setq mode-line-buffer-identification - (list (propertized-buffer-identification "%12b") "@" - (propertize (git-timemachine-abbreviate commit) 'face 'git-timemachine-commit) " name:" revision-file-name" " n-of-m))) - (setq git-timemachine-revision revision) - (goto-char current-position) - (when git-timemachine-show-minibuffer-details - (git-timemachine--show-minibuffer-details revision)) - (git-timemachine--erm-workaround)))) - -(declare-function erm-reset-buffer "ext:enh-ruby-mode") - -(defun git-timemachine--erm-workaround () - "Workaround for enhanced ruby mode not detecting revision change." - (when (eq major-mode 'enh-ruby-mode) - (ignore-errors (erm-reset-buffer)))) - -(defun git-timemachine--show-minibuffer-details (revision) - "Show details for REVISION in minibuffer." - (let* ((date-relative (nth 3 revision)) - (date-full (nth 4 revision)) - (author (if git-timemachine-show-author (concat (nth 6 revision) ": ") "")) - (sha-or-subject (if (eq git-timemachine-minibuffer-detail 'commit) (car revision) (nth 5 revision)))) - (message "%s%s [%s (%s)]" - (propertize author 'face 'git-timemachine-minibuffer-author-face) - (propertize sha-or-subject 'face 'git-timemachine-minibuffer-detail-face) date-full date-relative))) - -(defun git-timemachine--find-new-current-line (curr-revision new-revision current-line) - "Return the new current line after a revision jump. - -Given CURR-REVISION and NEW-REVISION determine if we need to -updated CURRENT-LINE." - (let* ((revisions (reverse (git-timemachine--revisions))) - (current-commit (car curr-revision)) - (curr-rev-number (+ (or (cl-position curr-revision revisions) 0) 1)) - (new-commit (car new-revision)) - (new-rev-number (+ (or (cl-position new-revision revisions) 0) 1)) - (new-line nil) - (file git-timemachine-file) - (reverse (< curr-rev-number new-rev-number))) - ;; If no commit change, do nothing - (if (= curr-rev-number new-rev-number) - current-line - ;; Get new current line number using `git-blame` - (with-temp-buffer - (if reverse - (git-timemachine--process-file "blame" "--reverse" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" current-commit new-commit)) - (git-timemachine--process-file "blame" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" new-commit current-commit))) - (goto-char (point-min)) - ;; If end-of-buffer problem - (when (search-forward-regexp "^fatal: file .+ has only .+ lines" nil t) - (setq current-line (- current-line 1)) - (erase-buffer) - (if reverse - (git-timemachine--process-file "blame" "--reverse" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" current-commit new-commit)) - (git-timemachine--process-file "blame" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" new-commit current-commit)))) - (goto-char (point-min)) - (search-forward-regexp "^[^ ]+ \\([^ ]+\\)") - (setq new-line (string-to-number (match-string 1))) - ;; In case git blame doesn't give what we expect - (when (= new-line 0) (setq new-line current-line)) - new-line)))) - -(defun git-timemachine--get-cursor-position () - "Return the cursor visual line number with respect to the current window first line." - (let* ((win-point-min (save-excursion (move-to-window-line 0) (point))) - (cur-pos (count-screen-lines win-point-min (point)))) - cur-pos)) - -(defun git-timemachine--set-cursor-position (POS) - "Set the cursor position to the POS visual line with respect to the window first line." - (recenter POS)) - -(defun git-timemachine-abbreviate (revision) - "Return REVISION abbreviated to `git-timemachine-abbreviation-length' chars." - (substring revision 0 git-timemachine-abbreviation-length)) - -(defun git-timemachine-quit () - "Exit the timemachine." - (interactive) - (let ((parent-buffer-name buffer-file-name)) - (kill-buffer) - (let ((parent-buffer (find-buffer-visiting parent-buffer-name))) - (when (and parent-buffer git-timemachine-quit-to-invoking-buffer) - (switch-to-buffer parent-buffer nil t))))) - -(defun git-timemachine-blame () - "Call `magit-blame` on current revision." - (interactive) - (if (fboundp 'magit-blame) - (let ((magit-buffer-revision (car git-timemachine-revision))) - (magit-blame)) - (message "You need to install magit for blame capabilities"))) - -(defun git-timemachine-kill-revision () - "Kill the current revision's full commit hash." - (interactive) - (let ((revision (car git-timemachine-revision))) - (message revision) - (kill-new revision))) - -(defun git-timemachine-kill-abbreviated-revision () - "Kill the current revision's abbreviated commit hash." - (interactive) - (let ((revision (git-timemachine-abbreviate (car git-timemachine-revision)))) - (message revision) - (kill-new revision))) - -(defun git-timemachine-show-commit () - "Show commit for current revision." - (interactive) - (let ((rev (car git-timemachine-revision))) - (if (fboundp 'magit-show-commit) - (magit-show-commit rev) - (message "You need to install magit to show commit")))) - -(defun git-timemachine-show-revision-introducing (text) - "Show the revision introducing TEXT to the file." - (interactive "sShow revision introducing text: ") - (let ((has-text? (lambda () - (save-excursion - (goto-char (point-min)) - (search-forward text nil t)))) - (buffer-name (format "timemachine:%s" (buffer-name))) - (at-revision nil)) - (if (not (funcall has-text?)) - (message "Buffer does not contain: %s" text) - (progn - (setq at-revision (car git-timemachine-revision)) - (while (funcall has-text?) - (git-timemachine-show-previous-revision) - (when (string= at-revision (car git-timemachine-revision)) - (throw :not-found text)) - (setq at-revision (car git-timemachine-revision))) - (git-timemachine-show-next-revision))))) - -(transient-define-prefix git-timemachine-help () - "Show online help." - ["Navigate" - [("p" "show previous revision" git-timemachine-show-previous-revision) - ("n" "show next revision" git-timemachine-show-next-revision) - ("g" "show nth revision" git-timemachine-show-nth-revision) - ("h" "show nearest revision" git-timemachine-show-nearest-revision) - ("t" "show fuzzy revision" git-timemachine-show-revision-fuzzy) - ("i" "show revision introducing" git-timemachine-show-revision-introducing)]] - ["Kill current revision" - [("w" "kill abbreviated revision" git-timemachine-kill-abbreviated-revision) - ("W" "kill revision" git-timemachine-kill-revision)]] - ["Misc" - [("b" "blame current revision" git-timemachine-blame) - ("c" "show commit" git-timemachine-show-commit) - ("?" "show help" git-timemachine-help) - ("q" "quit" git-timemachine-quit)]]) - -(define-minor-mode git-timemachine-mode - "Git Timemachine, feel the wings of history." - :init-value nil - :lighter " Timemachine" - :keymap - '(("p" . git-timemachine-show-previous-revision) - ("n" . git-timemachine-show-next-revision) - ("g" . git-timemachine-show-nth-revision) - ("h" . git-timemachine-show-nearest-revision) - ("t" . git-timemachine-show-revision-fuzzy) - ("i" . git-timemachine-show-revision-introducing) - ("q" . git-timemachine-quit) - ("w" . git-timemachine-kill-abbreviated-revision) - ("W" . git-timemachine-kill-revision) - ("b" . git-timemachine-blame) - ("c" . git-timemachine-show-commit) - ("?" . git-timemachine-help)) - :group 'git-timemachine) - -(defun git-timemachine-validate (file) - "Validate that there is a FILE and that it belongs to a git repository. -Call with the value of 'buffer-file-name." - (unless file - (error "This buffer is not visiting a file")) - (unless (vc-git-registered file) - (error "This file is not git tracked"))) - -(defun git-timemachine--start (get-revision-fn) - "Setup a timemachine buffer and populate it from the result of GET-REVISION-FN." - (setq git-timemachine--revisions-cache nil) - (git-timemachine-validate (buffer-file-name)) - (let ((git-directory (expand-file-name (vc-git-root (buffer-file-name)))) - (file-name (buffer-file-name)) - (timemachine-buffer (format "timemachine:%s" (buffer-name))) - (cur-line (line-number-at-pos)) - (cursor-position (git-timemachine--get-cursor-position)) - (new-line nil) - (mode major-mode) - (coding-system buffer-file-coding-system) - (font-lock-mode-enabled (bound-and-true-p font-lock-mode))) - (with-current-buffer (get-buffer-create timemachine-buffer) - (switch-to-buffer timemachine-buffer) - (setq buffer-file-name file-name) - (setq buffer-file-coding-system coding-system) - (delay-mode-hooks (funcall mode)) - (setq git-timemachine-directory git-directory - git-timemachine-file (file-relative-name file-name git-directory) - git-timemachine-revision nil) - (funcall get-revision-fn) - (setq new-line (git-timemachine--find-new-current-line git-timemachine-revision (list "HEAD" "" 0 "" "" "" "") cur-line)) ;; Allow to stay on the same line - (goto-char (point-min)) - (forward-line (- new-line 1)) - (git-timemachine--set-cursor-position cursor-position) - (git-timemachine-mode) - (when font-lock-mode-enabled - (if (fboundp 'font-lock-update) - (font-lock-update) - (with-no-warnings - (font-lock-fontify-buffer))))))) - -;;;###autoload -(defun git-timemachine-toggle () - "Toggle git timemachine mode." - (interactive) - (if (bound-and-true-p git-timemachine-mode) - (git-timemachine-quit) - (git-timemachine))) - -;;;###autoload -(defun git-timemachine () - "Enable git timemachine for file of current buffer." - (interactive) - (git-timemachine--start #'git-timemachine-show-current-revision)) - -;;;###autoload -(defun git-timemachine-switch-branch (git-branch) - "Enable git timemachine for current buffer, switching to GIT-BRANCH." - (interactive (list (completing-read "Branch to switch to: "(vc-git-branches)))) - (git-timemachine--start (lambda () (git-timemachine-show-latest-revision-in-branch git-branch)))) - -(provide 'git-timemachine) - -;;; git-timemachine.el ends here diff --git a/elpa/git-timemachine-20250128.940/git-timemachine-autoloads.el b/elpa/git-timemachine-20250128.940/git-timemachine-autoloads.el new file mode 100644 index 00000000..11db8b1c --- /dev/null +++ b/elpa/git-timemachine-20250128.940/git-timemachine-autoloads.el @@ -0,0 +1,36 @@ +;;; git-timemachine-autoloads.el --- automatically extracted autoloads (do not edit) -*- lexical-binding: t -*- +;; Generated by the `loaddefs-generate' function. + +;; This file is part of GNU Emacs. + +;;; Code: + +(add-to-list 'load-path (or (and load-file-name (directory-file-name (file-name-directory load-file-name))) (car load-path))) + + + +;;; Generated autoloads from git-timemachine.el + +(autoload 'git-timemachine-toggle "git-timemachine" "\ +Toggle git timemachine mode." t) +(autoload 'git-timemachine "git-timemachine" "\ +Enable git timemachine for file of current buffer." t) +(autoload 'git-timemachine-switch-branch "git-timemachine" "\ +Enable git timemachine for current buffer, switching to GIT-BRANCH. + +(fn GIT-BRANCH)" t) +(register-definition-prefixes "git-timemachine" '("git-timemachine-")) + +;;; End of scraped data + +(provide 'git-timemachine-autoloads) + +;; Local Variables: +;; version-control: never +;; no-byte-compile: t +;; no-update-autoloads: t +;; no-native-compile: t +;; coding: utf-8-emacs-unix +;; End: + +;;; git-timemachine-autoloads.el ends here diff --git a/elpa/git-timemachine-20250128.940/git-timemachine-pkg.el b/elpa/git-timemachine-20250128.940/git-timemachine-pkg.el new file mode 100644 index 00000000..edfd41cc --- /dev/null +++ b/elpa/git-timemachine-20250128.940/git-timemachine-pkg.el @@ -0,0 +1,11 @@ +;; -*- no-byte-compile: t; lexical-binding: nil -*- +(define-package "git-timemachine" "20250128.940" + "Walk through git revisions of a file." + '((emacs "24.3") + (transient "0.1.0")) + :url "https://codeberg.org/pidu/git-timemachine" + :commit "d1346a76122595aeeb7ebb292765841c6cfd417b" + :revdesc "d1346a761225" + :keywords '("vc") + :authors '(("Peter Stiernström" . "peter@stiernstrom.se")) + :maintainers '(("Peter Stiernström" . "peter@stiernstrom.se"))) diff --git a/elpa/git-timemachine-20250128.940/git-timemachine.el b/elpa/git-timemachine-20250128.940/git-timemachine.el new file mode 100755 index 00000000..d1259ba7 --- /dev/null +++ b/elpa/git-timemachine-20250128.940/git-timemachine.el @@ -0,0 +1,496 @@ +;;; git-timemachine.el --- Walk through git revisions of a file -*- lexical-binding: t; -*- + +;; Copyright (C) 2014 Peter Stiernström + +;; Author: Peter Stiernström +;; Package-Version: 20250128.940 +;; Package-Revision: d1346a761225 +;; URL: https://codeberg.org/pidu/git-timemachine +;; Keywords: vc +;; Package-Requires: ((emacs "24.3") (transient "0.1.0")) + +;; This file is not part of GNU Emacs + +;; 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 . + +;;; Commentary: + +;;; Use git-timemachine to browse historic versions of a file with p +;;; (previous) and n (next). + +;;; Code: + +(require 'vc-git) +(require 'cl-lib) +(require 'transient) + +(defgroup git-timemachine nil + "Walk through git revisions of a file." + :link '(url-link "https://codeberg.org/pidu/git-timemachine") + :group 'tools) + +(defcustom git-timemachine-abbreviation-length 12 + "Number of chars from the full sha1 hash to use for abbreviation." + :type 'integer + :group 'git-timemachine) + +(defcustom git-timemachine-show-minibuffer-details t + "Non-nil means that details of the commit (its hash and date) +will be shown in the minibuffer while navigating commits." + :type 'boolean + :group 'git-timemachine) + +(defface git-timemachine-commit + '((default :weight bold)) + "Face for git timemachine commit sha." + :group 'git-timemachine) + +(defface git-timemachine-minibuffer-detail-face + '((((class color) (background dark)) + :foreground "yellow") + (((class color) (background light)) + :foreground "yellow4")) + "How to display the minibuffer detail." + :group 'git-timemachine) + +(defface git-timemachine-minibuffer-author-face + '((((class color) (background dark)) + :foreground "orange") + (((class color) (background light)) + :foreground "DarkOrange4")) + "How to display the author in minibuffer." + :group 'git-timemachine) + +(defcustom git-timemachine-minibuffer-detail + 'subject + "What to display when `git-timemachine-show-minibuffer-details` is t. +Available values are: +`commit` : The SHA hash of the commit +`subject`: The subject of the commit message" + :type '(radio (const :tag "Commit SHA" commit) (const :tag "Commit Subject" subject)) + :group 'git-timemachine) + +(defcustom git-timemachine-show-author + t + "Prepend author to minibuffer details." + :type 'boolean + :group 'git-timemachine) + +(defcustom git-timemachine-global-git-arguments + '("-c" "log.showSignature=false" "--no-pager") + "Common arguments for all git commands." + :type '(repeat string) + :group 'git-timemachine) + +(defcustom git-timemachine-quit-to-invoking-buffer + t + "Switch to invoking buffer on `git-timemachine-quit`." + :type 'boolean + :group 'git-timemachine) + +(defvar-local git-timemachine-directory nil) +(defvar-local git-timemachine-revision nil) +(defvar-local git-timemachine-file nil) +(defvar-local git-timemachine--revisions-cache nil) + +(defun git-timemachine--process-file (&rest args) + "Run `process-file` with ARGS and `git-timemachine-global-git-arguments` applied." + (apply #'process-file vc-git-program nil t nil (append git-timemachine-global-git-arguments args))) + +(defun git-timemachine--revisions (&optional git-branch) + "List git revisions of current buffers file. + +When passed a GIT-BRANCH, lists revisions from that branch." + (if git-timemachine--revisions-cache + git-timemachine--revisions-cache + (setq git-timemachine--revisions-cache + (prog2 + (message "Fetching Revisions...") + (let ((default-directory git-timemachine-directory) + (file git-timemachine-file)) + (with-temp-buffer + + (unless (zerop (if git-branch + (git-timemachine--process-file "log" git-branch "--name-only" "--follow" "--pretty=format:%H%x00%ar%x00%ad%x00%s%x00%an" "--" file) + (git-timemachine--process-file "log" "--name-only" "--follow" "--pretty=format:%H%x00%ar%x00%ad%x00%s%x00%an" "--" file))) + (error "Git log command exited with non-zero exit status for file: %s" file)) + + (goto-char (point-min)) + (let ((lines) + (commit-number (/ (1+ (count-lines (point-min) (point-max))) 3))) + (while (not (eobp)) + (let ((line (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) + (string-match "\\([^\0]*\\)\0\\([^\0]*\\)\0\\([^\0]*\\)\0\\(.*\\)\0\\(.*\\)" line) + (let ((commit (match-string 1 line)) + (date-relative (match-string 2 line)) + (date-full (match-string 3 line)) + (subject (match-string 4 line)) + (author (match-string 5 line))) + (forward-line 1) + (let ((file-name (buffer-substring-no-properties (line-beginning-position) (line-end-position)))) + (push (list commit file-name commit-number date-relative date-full subject author) lines)))) + (setq commit-number (1- commit-number)) + (forward-line 2)) + (nreverse lines)))) + (message "Fetching Revisions...done"))))) + +(defun git-timemachine-show-current-revision () + "Show last (current) revision of file." + (interactive) + (git-timemachine-show-revision (car (git-timemachine--revisions)))) + +(defun git-timemachine-show-latest-revision-in-branch (git-branch) + "Show last (current) revision of file in GIT-BRANCH." + (interactive "MGit branch: ") + (git-timemachine-show-revision (car (git-timemachine--revisions git-branch)))) + +(defun git-timemachine--next-revision (revisions) + "Return the revision following the current revision in REVISIONS." + (or (cadr (cl-member (car git-timemachine-revision) revisions :key #'car :test #'string=)) + (car (reverse revisions)))) + +(defun git-timemachine-show-previous-revision () + "Show previous revision of file." + (interactive) + (let ((new-line nil) + (curr-revision git-timemachine-revision) + (new-revision (git-timemachine--next-revision (git-timemachine--revisions))) + (cursor-win-pos (git-timemachine--get-cursor-position))) + (setq new-line (git-timemachine--find-new-current-line curr-revision new-revision (line-number-at-pos))) + (git-timemachine-show-revision new-revision) + (forward-line (- new-line (line-number-at-pos))) + (git-timemachine--set-cursor-position cursor-win-pos))) + +(defun git-timemachine-show-next-revision () + "Show next revision of file." + (interactive) + (let ((new-line nil) + (curr-revision git-timemachine-revision) + (new-revision (git-timemachine--next-revision (reverse (git-timemachine--revisions)))) + (cursor-win-pos (git-timemachine--get-cursor-position))) + (setq new-line (git-timemachine--find-new-current-line curr-revision new-revision (line-number-at-pos))) + (git-timemachine-show-revision new-revision) + (forward-line (- new-line (line-number-at-pos))) + (git-timemachine--set-cursor-position cursor-win-pos))) + +(defun git-timemachine-show-revision-fuzzy () + "Show the revision with the chosen commit message." + (interactive) + (let* ((revisions (git-timemachine--revisions)) + (wanted + (funcall #'completing-read "Commit message: " + (mapcar (apply-partially #'nth 5) revisions)))) + (git-timemachine-show-revision + (cl-find wanted revisions + :key (apply-partially #'nth 5) + :test #'equal)))) + +(defun git-timemachine-show-nth-revision (rev-number) + "Show the REV-NUMBER revision." + (interactive "nEnter revision number: ") + (let* ((revisions (reverse (git-timemachine--revisions))) + (num-revisions (length revisions)) + (curr-revision git-timemachine-revision) + (new-revision (nth (1- rev-number) revisions)) + (new-line nil) + (cursor-win-pos (git-timemachine--get-cursor-position))) + (if (not new-revision) + (message "Only %d revisions exist." num-revisions) + (setq new-line (git-timemachine--find-new-current-line curr-revision new-revision (line-number-at-pos))) + (git-timemachine-show-revision new-revision) + (forward-line (- new-line (line-number-at-pos))) + (git-timemachine--set-cursor-position cursor-win-pos)))) + +(defun git-timemachine-show-nearest-revision (&optional relative-hash) + "Show last revision of the current file nearest to RELATIVE-HASH." + (interactive "sEnter commit hash: ") + (let* ((abs-file-name (buffer-file-name (current-buffer))) + (root-directory + (expand-file-name + (vc-call-backend + (vc-responsible-backend abs-file-name) + 'root abs-file-name))) + (default-directory root-directory) + (file-name (string-remove-prefix root-directory abs-file-name)) + (line + (with-temp-buffer + (process-file vc-git-program nil t nil "log" "--max-count" "1" relative-hash "--pretty=format:%H%x00%ar%x00%ad%x00%s%x00%an" "--" file-name) + (buffer-substring-no-properties (point-min) (point-max)))) + (line-list (unless (string-prefix-p "fatal" line t) (string-split line "\0"))) + (hash (nth 0 line-list)) + (date-relative (nth 1 line-list)) + (date-full (nth 2 line-list)) + (subject (nth 3 line-list)) + (author (nth 4 line-list)) + (revision (list hash file-name -1 date-relative date-full subject author))) + (if line-list + (git-timemachine-show-revision revision) + (message "No such commit %s" relative-hash)))) + +(defun git-timemachine-show-revision (revision) + "Show a REVISION (commit hash) of the current file." + (when revision + (let ((current-position (point)) + (commit (car revision)) + (revision-file-name (nth 1 revision)) + (commit-index (nth 2 revision)) + (date-relative (nth 3 revision)) + (date-full (nth 4 revision)) + (subject (nth 5 revision))) + (when (bound-and-true-p magit-blame-mode) (magit-blame-quit)) + (setq buffer-read-only nil) + (erase-buffer) + (let ((default-directory git-timemachine-directory) + (process-coding-system-alist (list (cons "" (cons buffer-file-coding-system default-process-coding-system))))) + (git-timemachine--process-file "show" (concat commit ":" revision-file-name))) + (setq buffer-read-only t) + (set-buffer-modified-p nil) + (let* ((revisions (git-timemachine--revisions)) + (n-of-m (format "(%d/%d %s)" commit-index (length revisions) date-relative))) + (setq mode-line-buffer-identification + (list (propertized-buffer-identification "%12b") "@" + (propertize (git-timemachine-abbreviate commit) 'face 'git-timemachine-commit) " name:" revision-file-name" " n-of-m))) + (setq git-timemachine-revision revision) + (goto-char current-position) + (when git-timemachine-show-minibuffer-details + (git-timemachine--show-minibuffer-details revision)) + (git-timemachine--erm-workaround)))) + +(declare-function erm-reset-buffer "ext:enh-ruby-mode") + +(defun git-timemachine--erm-workaround () + "Workaround for enhanced ruby mode not detecting revision change." + (when (eq major-mode 'enh-ruby-mode) + (ignore-errors (erm-reset-buffer)))) + +(defun git-timemachine--show-minibuffer-details (revision) + "Show details for REVISION in minibuffer." + (let* ((date-relative (nth 3 revision)) + (date-full (nth 4 revision)) + (author (if git-timemachine-show-author (concat (nth 6 revision) ": ") "")) + (sha-or-subject (if (eq git-timemachine-minibuffer-detail 'commit) (car revision) (nth 5 revision)))) + (message "%s%s [%s (%s)]" + (propertize author 'face 'git-timemachine-minibuffer-author-face) + (propertize sha-or-subject 'face 'git-timemachine-minibuffer-detail-face) date-full date-relative))) + +(defun git-timemachine--find-new-current-line (curr-revision new-revision current-line) + "Return the new current line after a revision jump. + +Given CURR-REVISION and NEW-REVISION determine if we need to +updated CURRENT-LINE." + (let* ((revisions (reverse (git-timemachine--revisions))) + (current-commit (car curr-revision)) + (curr-rev-number (+ (or (cl-position curr-revision revisions) 0) 1)) + (new-commit (car new-revision)) + (new-rev-number (+ (or (cl-position new-revision revisions) 0) 1)) + (new-line nil) + (file git-timemachine-file) + (reverse (< curr-rev-number new-rev-number))) + ;; If no commit change, do nothing + (if (= curr-rev-number new-rev-number) + current-line + ;; Get new current line number using `git-blame` + (with-temp-buffer + (if reverse + (git-timemachine--process-file "blame" "--reverse" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" current-commit new-commit)) + (git-timemachine--process-file "blame" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" new-commit current-commit))) + (goto-char (point-min)) + ;; If end-of-buffer problem + (when (search-forward-regexp "^fatal: file .+ has only .+ lines" nil t) + (setq current-line (- current-line 1)) + (erase-buffer) + (if reverse + (git-timemachine--process-file "blame" "--reverse" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" current-commit new-commit)) + (git-timemachine--process-file "blame" "-n" (format "-L %s,%s" current-line current-line) file (format "%s..%s" new-commit current-commit)))) + (goto-char (point-min)) + (search-forward-regexp "^[^ ]+ \\([^ ]+\\)") + (setq new-line (string-to-number (match-string 1))) + ;; In case git blame doesn't give what we expect + (when (= new-line 0) (setq new-line current-line)) + new-line)))) + +(defun git-timemachine--get-cursor-position () + "Return the cursor visual line number with respect to the current window first line." + (let* ((win-point-min (save-excursion (move-to-window-line 0) (point))) + (cur-pos (count-screen-lines win-point-min (point)))) + cur-pos)) + +(defun git-timemachine--set-cursor-position (POS) + "Set the cursor position to the POS visual line with respect to the window first line." + (recenter POS)) + +(defun git-timemachine-abbreviate (revision) + "Return REVISION abbreviated to `git-timemachine-abbreviation-length' chars." + (substring revision 0 git-timemachine-abbreviation-length)) + +(defun git-timemachine-quit () + "Exit the timemachine." + (interactive) + (let ((parent-buffer-name buffer-file-name)) + (kill-buffer) + (let ((parent-buffer (find-buffer-visiting parent-buffer-name))) + (when (and parent-buffer git-timemachine-quit-to-invoking-buffer) + (switch-to-buffer parent-buffer nil t))))) + +(defun git-timemachine-blame () + "Call `magit-blame` on current revision." + (interactive) + (if (fboundp 'magit-blame) + (let ((magit-buffer-revision (car git-timemachine-revision))) + (magit-blame)) + (message "You need to install magit for blame capabilities"))) + +(defun git-timemachine-kill-revision () + "Kill the current revision's full commit hash." + (interactive) + (let ((revision (car git-timemachine-revision))) + (message revision) + (kill-new revision))) + +(defun git-timemachine-kill-abbreviated-revision () + "Kill the current revision's abbreviated commit hash." + (interactive) + (let ((revision (git-timemachine-abbreviate (car git-timemachine-revision)))) + (message revision) + (kill-new revision))) + +(defun git-timemachine-show-commit () + "Show commit for current revision." + (interactive) + (let ((rev (car git-timemachine-revision))) + (if (fboundp 'magit-show-commit) + (magit-show-commit rev) + (message "You need to install magit to show commit")))) + +(defun git-timemachine-show-revision-introducing (text) + "Show the revision introducing TEXT to the file." + (interactive "sShow revision introducing text: ") + (let ((has-text? (lambda () + (save-excursion + (goto-char (point-min)) + (search-forward text nil t)))) + (buffer-name (format "timemachine:%s" (buffer-name))) + (at-revision nil)) + (if (not (funcall has-text?)) + (message "Buffer does not contain: %s" text) + (progn + (setq at-revision (car git-timemachine-revision)) + (while (funcall has-text?) + (git-timemachine-show-previous-revision) + (when (string= at-revision (car git-timemachine-revision)) + (throw :not-found text)) + (setq at-revision (car git-timemachine-revision))) + (git-timemachine-show-next-revision))))) + +(transient-define-prefix git-timemachine-help () + "Show online help." + ["Navigate" + [("p" "show previous revision" git-timemachine-show-previous-revision) + ("n" "show next revision" git-timemachine-show-next-revision) + ("g" "show nth revision" git-timemachine-show-nth-revision) + ("h" "show nearest revision" git-timemachine-show-nearest-revision) + ("t" "show fuzzy revision" git-timemachine-show-revision-fuzzy) + ("i" "show revision introducing" git-timemachine-show-revision-introducing)]] + ["Kill current revision" + [("w" "kill abbreviated revision" git-timemachine-kill-abbreviated-revision) + ("W" "kill revision" git-timemachine-kill-revision)]] + ["Misc" + [("b" "blame current revision" git-timemachine-blame) + ("c" "show commit" git-timemachine-show-commit) + ("?" "show help" git-timemachine-help) + ("q" "quit" git-timemachine-quit)]]) + +(define-minor-mode git-timemachine-mode + "Git Timemachine, feel the wings of history." + :init-value nil + :lighter " Timemachine" + :keymap + '(("p" . git-timemachine-show-previous-revision) + ("n" . git-timemachine-show-next-revision) + ("g" . git-timemachine-show-nth-revision) + ("h" . git-timemachine-show-nearest-revision) + ("t" . git-timemachine-show-revision-fuzzy) + ("i" . git-timemachine-show-revision-introducing) + ("q" . git-timemachine-quit) + ("w" . git-timemachine-kill-abbreviated-revision) + ("W" . git-timemachine-kill-revision) + ("b" . git-timemachine-blame) + ("c" . git-timemachine-show-commit) + ("?" . git-timemachine-help)) + :group 'git-timemachine) + +(defun git-timemachine-validate (file) + "Validate that there is a FILE and that it belongs to a git repository. +Call with the value of 'buffer-file-name." + (unless file + (error "This buffer is not visiting a file")) + (unless (vc-git-registered file) + (error "This file is not git tracked"))) + +(defun git-timemachine--start (get-revision-fn) + "Setup a timemachine buffer and populate it from the result of GET-REVISION-FN." + (setq git-timemachine--revisions-cache nil) + (git-timemachine-validate (buffer-file-name)) + (let ((git-directory (expand-file-name (vc-git-root (buffer-file-name)))) + (file-name (buffer-file-name)) + (timemachine-buffer (format "timemachine:%s" (buffer-name))) + (cur-line (line-number-at-pos)) + (cursor-position (git-timemachine--get-cursor-position)) + (new-line nil) + (mode major-mode) + (coding-system buffer-file-coding-system) + (font-lock-mode-enabled (bound-and-true-p font-lock-mode))) + (with-current-buffer (get-buffer-create timemachine-buffer) + (switch-to-buffer timemachine-buffer) + (setq buffer-file-name file-name) + (setq buffer-file-coding-system coding-system) + (delay-mode-hooks (funcall mode)) + (setq git-timemachine-directory git-directory + git-timemachine-file (file-relative-name file-name git-directory) + git-timemachine-revision nil) + (funcall get-revision-fn) + (setq new-line (git-timemachine--find-new-current-line git-timemachine-revision (list "HEAD" "" 0 "" "" "" "") cur-line)) ;; Allow to stay on the same line + (goto-char (point-min)) + (forward-line (- new-line 1)) + (git-timemachine--set-cursor-position cursor-position) + (git-timemachine-mode) + (when font-lock-mode-enabled + (if (fboundp 'font-lock-update) + (font-lock-update) + (with-no-warnings + (font-lock-fontify-buffer))))))) + +;;;###autoload +(defun git-timemachine-toggle () + "Toggle git timemachine mode." + (interactive) + (if (bound-and-true-p git-timemachine-mode) + (git-timemachine-quit) + (git-timemachine))) + +;;;###autoload +(defun git-timemachine () + "Enable git timemachine for file of current buffer." + (interactive) + (git-timemachine--start #'git-timemachine-show-current-revision)) + +;;;###autoload +(defun git-timemachine-switch-branch (git-branch) + "Enable git timemachine for current buffer, switching to GIT-BRANCH." + (interactive (list (completing-read "Branch to switch to: "(vc-git-branches)))) + (git-timemachine--start (lambda () (git-timemachine-show-latest-revision-in-branch git-branch)))) + +(provide 'git-timemachine) + +;;; git-timemachine.el ends here