magit-bookmark.el (7949B)
1 ;;; magit-bookmark.el --- bookmark support for Magit -*- lexical-binding: t -*- 2 3 ;; Copyright (C) 2010-2021 The Magit Project Contributors 4 ;; 5 ;; You should have received a copy of the AUTHORS.md file which 6 ;; lists all contributors. If not, see http://magit.vc/authors. 7 8 ;; Author: Jonas Bernoulli <jonas@bernoul.li> 9 ;; Maintainer: Jonas Bernoulli <jonas@bernoul.li> 10 11 ;; Inspired by an earlier implementation by Yuri Khan. 12 13 ;; SPDX-License-Identifier: GPL-3.0-or-later 14 15 ;; Magit is free software; you can redistribute it and/or modify it 16 ;; under the terms of the GNU General Public License as published by 17 ;; the Free Software Foundation; either version 3, or (at your option) 18 ;; any later version. 19 ;; 20 ;; Magit is distributed in the hope that it will be useful, but WITHOUT 21 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 22 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 23 ;; License for more details. 24 ;; 25 ;; You should have received a copy of the GNU General Public License 26 ;; along with Magit. If not, see http://www.gnu.org/licenses. 27 28 ;;; Commentary: 29 30 ;; Support for bookmarks for most Magit buffers. 31 32 ;;; Code: 33 34 (require 'magit) 35 (require 'bookmark) 36 37 ;;; Core 38 39 (defun magit--make-bookmark () 40 "Create a bookmark for the current Magit buffer. 41 Input values are the major-mode's `magit-bookmark-name' method, 42 and the buffer-local values of the variables referenced in its 43 `magit-bookmark-variables' property." 44 (if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables) 45 ;; `bookmark-make-record-default's return value does not match 46 ;; (NAME . ALIST), even though it is used as the default value 47 ;; of `bookmark-make-record-function', which states that such 48 ;; functions must do that. See #4356. 49 (let ((bookmark (cons nil (bookmark-make-record-default 'no-file)))) 50 (bookmark-prop-set bookmark 'handler 'magit--handle-bookmark) 51 (bookmark-prop-set bookmark 'mode major-mode) 52 (bookmark-prop-set bookmark 'filename (magit-toplevel)) 53 (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name))) 54 (dolist (var (get major-mode 'magit-bookmark-variables)) 55 (bookmark-prop-set bookmark var (symbol-value var))) 56 (bookmark-prop-set 57 bookmark 'magit-hidden-sections 58 (--keep (and (oref it hidden) 59 (cons (oref it type) 60 (if (derived-mode-p 'magit-stash-mode) 61 (replace-regexp-in-string 62 (regexp-quote magit-buffer-revision) 63 magit-buffer-revision-hash 64 (oref it value)) 65 (oref it value)))) 66 (oref magit-root-section children))) 67 bookmark) 68 (user-error "Bookmarking is not implemented for %s buffers" major-mode))) 69 70 ;;;###autoload 71 (defun magit--handle-bookmark (bookmark) 72 "Open a bookmark created by `magit--make-bookmark'. 73 Call the `magit-*-setup-buffer' function of the the major-mode 74 with the variables' values as arguments, which were recorded by 75 `magit--make-bookmark'. Ignore `magit-display-buffer-function'." 76 (let ((buffer (let ((default-directory (bookmark-get-filename bookmark)) 77 (mode (bookmark-prop-get bookmark 'mode)) 78 (magit-display-buffer-function #'identity) 79 (magit-display-buffer-noselect t)) 80 (apply (intern (format "%s-setup-buffer" 81 (substring (symbol-name mode) 0 -5))) 82 (--map (bookmark-prop-get bookmark it) 83 (get mode 'magit-bookmark-variables)))))) 84 (set-buffer buffer) ; That is the interface we have to adhere to. 85 (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections))) 86 (with-current-buffer buffer 87 (dolist (child (oref magit-root-section children)) 88 (if (member (cons (oref child type) 89 (oref child value)) 90 hidden) 91 (magit-section-hide child) 92 (magit-section-show child))))) 93 ;; Compatibility with `bookmark+' package. See #4356. 94 (when (bound-and-true-p bmkp-jump-display-function) 95 (funcall bmkp-jump-display-function (current-buffer))) 96 nil)) 97 98 (cl-defgeneric magit-bookmark-name () 99 "Return name for bookmark to current buffer." 100 (format "%s%s" 101 (substring (symbol-name major-mode) 0 -5) 102 (if-let ((vars (get major-mode 'magit-bookmark-variables))) 103 (cl-mapcan (lambda (var) 104 (let ((val (symbol-value var))) 105 (if (and val (atom val)) 106 (list val) 107 val))) 108 vars) 109 ""))) 110 111 ;;; Diff 112 ;;;; Diff 113 114 (put 'magit-diff-mode 'magit-bookmark-variables 115 '(magit-buffer-range-hashed 116 magit-buffer-typearg 117 magit-buffer-diff-args 118 magit-buffer-diff-files)) 119 120 (cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode)) 121 (format "magit-diff(%s%s)" 122 (pcase (magit-diff-type) 123 (`staged "staged") 124 (`unstaged "unstaged") 125 (`committed magit-buffer-range) 126 (`undefined 127 (delq nil (list magit-buffer-typearg magit-buffer-range-hashed)))) 128 (if magit-buffer-diff-files 129 (concat " -- " (mapconcat #'identity magit-buffer-diff-files " ")) 130 ""))) 131 132 ;;;; Revision 133 134 (put 'magit-revision-mode 'magit-bookmark-variables 135 '(magit-buffer-revision-hash 136 magit-buffer-diff-args 137 magit-buffer-diff-files)) 138 139 (cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode)) 140 (format "magit-revision(%s %s)" 141 (magit-rev-abbrev magit-buffer-revision) 142 (if magit-buffer-diff-files 143 (mapconcat #'identity magit-buffer-diff-files " ") 144 (magit-rev-format "%s" magit-buffer-revision)))) 145 146 ;;;; Stash 147 148 (put 'magit-stash-mode 'magit-bookmark-variables 149 '(magit-buffer-revision-hash 150 magit-buffer-diff-args 151 magit-buffer-diff-files)) 152 153 (cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode)) 154 (format "magit-stash(%s %s)" 155 (magit-rev-abbrev magit-buffer-revision) 156 (if magit-buffer-diff-files 157 (mapconcat #'identity magit-buffer-diff-files " ") 158 (magit-rev-format "%s" magit-buffer-revision)))) 159 160 ;;; Log 161 ;;;; Log 162 163 (put 'magit-log-mode 'magit-bookmark-variables 164 '(magit-buffer-revisions 165 magit-buffer-log-args 166 magit-buffer-log-files)) 167 168 (cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode)) 169 (format "magit-log(%s%s)" 170 (mapconcat #'identity magit-buffer-revisions " ") 171 (if magit-buffer-log-files 172 (concat " -- " (mapconcat #'identity magit-buffer-log-files " ")) 173 ""))) 174 175 ;;;; Cherry 176 177 (put 'magit-cherry-mode 'magit-bookmark-variables 178 '(magit-buffer-refname 179 magit-buffer-upstream)) 180 181 (cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode)) 182 (format "magit-cherry(%s > %s)" 183 magit-buffer-refname 184 magit-buffer-upstream)) 185 186 ;;;; Reflog 187 188 (put 'magit-reflog-mode 'magit-bookmark-variables 189 '(magit-buffer-refname)) 190 191 (cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode)) 192 (format "magit-reflog(%s)" magit-buffer-refname)) 193 194 ;;; Misc 195 196 (put 'magit-status-mode 'magit-bookmark-variables nil) 197 198 (put 'magit-refs-mode 'magit-bookmark-variables 199 '(magit-buffer-upstream 200 magit-buffer-arguments)) 201 202 (put 'magit-stashes-mode 'magit-bookmark-variables nil) 203 204 (cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode)) 205 (format "magit-states(%s)" magit-buffer-refname)) 206 207 ;;; _ 208 (provide 'magit-bookmark) 209 ;;; magit-bookmark.el ends here