aboutsummaryrefslogtreecommitdiffstats
path: root/elpa/magit-20220503.1245/magit-bookmark.el
blob: 0a42741b83c89bba7cc8fca7a3054d03fd45f7e6 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
;;; magit-bookmark.el --- Bookmark support for Magit  -*- lexical-binding:t -*-

;; Copyright (C) 2008-2022 The Magit Project Contributors

;; Inspired by an earlier implementation by Yuri Khan.

;; Author: Jonas Bernoulli <jonas@bernoul.li>
;; Maintainer: Jonas Bernoulli <jonas@bernoul.li>

;; SPDX-License-Identifier: GPL-3.0-or-later

;; Magit 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.
;;
;; Magit 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 Magit.  If not, see <https://www.gnu.org/licenses/>.

;;; Commentary:

;; Support for bookmarks for most Magit buffers.

;;; Code:

(require 'magit)
(require 'bookmark)

;;; Core

(defun magit--make-bookmark ()
  "Create a bookmark for the current Magit buffer.
Input values are the major-mode's `magit-bookmark-name' method,
and the buffer-local values of the variables referenced in its
`magit-bookmark-variables' property."
  (if (plist-member (symbol-plist major-mode) 'magit-bookmark-variables)
      ;; `bookmark-make-record-default's return value does not match
      ;; (NAME . ALIST), even though it is used as the default value
      ;; of `bookmark-make-record-function', which states that such
      ;; functions must do that.  See #4356.
      (let ((bookmark (cons nil (bookmark-make-record-default 'no-file))))
        (bookmark-prop-set bookmark 'handler  #'magit--handle-bookmark)
        (bookmark-prop-set bookmark 'mode     major-mode)
        (bookmark-prop-set bookmark 'filename (magit-toplevel))
        (bookmark-prop-set bookmark 'defaults (list (magit-bookmark-name)))
        (dolist (var (get major-mode 'magit-bookmark-variables))
          (bookmark-prop-set bookmark var (symbol-value var)))
        (bookmark-prop-set
         bookmark 'magit-hidden-sections
         (--keep (and (oref it hidden)
                      (cons (oref it type)
                            (if (derived-mode-p 'magit-stash-mode)
                                (string-replace magit-buffer-revision
                                                magit-buffer-revision-hash
                                                (oref it value))
                              (oref it value))))
                 (oref magit-root-section children)))
        bookmark)
    (user-error "Bookmarking is not implemented for %s buffers" major-mode)))

;;;###autoload
(defun magit--handle-bookmark (bookmark)
  "Open a bookmark created by `magit--make-bookmark'.
Call the `magit-*-setup-buffer' function of the the major-mode
with the variables' values as arguments, which were recorded by
`magit--make-bookmark'.  Ignore `magit-display-buffer-function'."
  (let ((buffer (let ((default-directory (bookmark-get-filename bookmark))
                      (mode (bookmark-prop-get bookmark 'mode))
                      (magit-display-buffer-function #'identity)
                      (magit-display-buffer-noselect t))
                  (apply (intern (format "%s-setup-buffer"
                                         (substring (symbol-name mode) 0 -5)))
                         (--map (bookmark-prop-get bookmark it)
                                (get mode 'magit-bookmark-variables))))))
    (set-buffer buffer) ; That is the interface we have to adhere to.
    (when-let ((hidden (bookmark-prop-get bookmark 'magit-hidden-sections)))
      (with-current-buffer buffer
        (dolist (child (oref magit-root-section children))
          (if (member (cons (oref child type)
                            (oref child value))
                      hidden)
              (magit-section-hide child)
            (magit-section-show child)))))
    ;; Compatibility with `bookmark+' package.  See #4356.
    (when (bound-and-true-p bmkp-jump-display-function)
      (funcall bmkp-jump-display-function (current-buffer)))
    nil))

(cl-defgeneric magit-bookmark-name ()
  "Return name for bookmark to current buffer."
  (format "%s%s"
          (substring (symbol-name major-mode) 0 -5)
          (if-let ((vars (get major-mode 'magit-bookmark-variables)))
              (cl-mapcan (lambda (var)
                           (let ((val (symbol-value var)))
                             (if (and val (atom val))
                                 (list val)
                               val)))
                         vars)
            "")))

;;; Diff
;;;; Diff

(put 'magit-diff-mode 'magit-bookmark-variables
     '(magit-buffer-range-hashed
       magit-buffer-typearg
       magit-buffer-diff-args
       magit-buffer-diff-files))

(cl-defmethod magit-bookmark-name (&context (major-mode magit-diff-mode))
  (format "magit-diff(%s%s)"
          (pcase (magit-diff-type)
            ('staged "staged")
            ('unstaged "unstaged")
            ('committed magit-buffer-range)
            ('undefined
             (delq nil (list magit-buffer-typearg magit-buffer-range-hashed))))
          (if magit-buffer-diff-files
              (concat " -- " (mapconcat #'identity magit-buffer-diff-files " "))
            "")))

;;;; Revision

(put 'magit-revision-mode 'magit-bookmark-variables
     '(magit-buffer-revision-hash
       magit-buffer-diff-args
       magit-buffer-diff-files))

(cl-defmethod magit-bookmark-name (&context (major-mode magit-revision-mode))
  (format "magit-revision(%s %s)"
          (magit-rev-abbrev magit-buffer-revision)
          (if magit-buffer-diff-files
              (mapconcat #'identity magit-buffer-diff-files " ")
            (magit-rev-format "%s" magit-buffer-revision))))

;;;; Stash

(put 'magit-stash-mode 'magit-bookmark-variables
     '(magit-buffer-revision-hash
       magit-buffer-diff-args
       magit-buffer-diff-files))

(cl-defmethod magit-bookmark-name (&context (major-mode magit-stash-mode))
  (format "magit-stash(%s %s)"
          (magit-rev-abbrev magit-buffer-revision)
          (if magit-buffer-diff-files
              (mapconcat #'identity magit-buffer-diff-files " ")
            (magit-rev-format "%s" magit-buffer-revision))))

;;; Log
;;;; Log

(put 'magit-log-mode 'magit-bookmark-variables
     '(magit-buffer-revisions
       magit-buffer-log-args
       magit-buffer-log-files))

(cl-defmethod magit-bookmark-name (&context (major-mode magit-log-mode))
  (format "magit-log(%s%s)"
          (mapconcat #'identity magit-buffer-revisions " ")
          (if magit-buffer-log-files
              (concat " -- " (mapconcat #'identity magit-buffer-log-files " "))
            "")))

;;;; Cherry

(put 'magit-cherry-mode 'magit-bookmark-variables
     '(magit-buffer-refname
       magit-buffer-upstream))

(cl-defmethod magit-bookmark-name (&context (major-mode magit-cherry-mode))
  (format "magit-cherry(%s > %s)"
          magit-buffer-refname
          magit-buffer-upstream))

;;;; Reflog

(put 'magit-reflog-mode 'magit-bookmark-variables
     '(magit-buffer-refname))

(cl-defmethod magit-bookmark-name (&context (major-mode magit-reflog-mode))
  (format "magit-reflog(%s)" magit-buffer-refname))

;;; Misc

(put 'magit-status-mode 'magit-bookmark-variables nil)

(put 'magit-refs-mode 'magit-bookmark-variables
     '(magit-buffer-upstream
       magit-buffer-arguments))

(put 'magit-stashes-mode 'magit-bookmark-variables nil)

(cl-defmethod magit-bookmark-name (&context (major-mode magit-stashes-mode))
  (format "magit-states(%s)" magit-buffer-refname))

;;; _
(provide 'magit-bookmark)
;;; magit-bookmark.el ends here