mirror of https://github.com/Chizi123/.emacs.d.git

Chizi123
2018-11-17 5cb5f70b1872a757e93ea333b0e2dca50c6c8957
commit | author | age
5cb5f7 1 ;;; magit-margin.el --- margins in Magit buffers  -*- lexical-binding: t -*-
C 2
3 ;; Copyright (C) 2010-2018  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 ;; Magit is free software; you can redistribute it and/or modify it
12 ;; under the terms of the GNU General Public License as published by
13 ;; the Free Software Foundation; either version 3, or (at your option)
14 ;; any later version.
15 ;;
16 ;; Magit is distributed in the hope that it will be useful, but WITHOUT
17 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
18 ;; or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public
19 ;; License for more details.
20 ;;
21 ;; You should have received a copy of the GNU General Public License
22 ;; along with Magit.  If not, see http://www.gnu.org/licenses.
23
24 ;;; Commentary:
25
26 ;; This library implements support for showing additional information
27 ;; in the margins of Magit buffers.  Currently this is only used for
28 ;; commits, for which the committer date or age, and optionally the
29 ;; author name are shown.
30
31 ;;; Code:
32
33 (require 'dash)
34
35 (eval-when-compile
36   (require 'subr-x))
37
38 (require 'magit-section)
39 (require 'magit-mode)
40
41 (defgroup magit-margin nil
42   "Information Magit displays in the margin.
43
44 You can change the STYLE and AUTHOR-WIDTH of all `magit-*-margin'
45 options to the same values by customizing `magit-log-margin'
46 *before* `magit' is loaded.  If you do that, then the respective
47 values for the other options will default to what you have set
48 for that variable.  Likewise if you set `magit-log-margin's INIT
49 to nil, then that is used in the default of all other options.  But
50 setting it to t, i.e. re-enforcing the default for that option,
51 does not carry to other options."
52   :link '(info-link "(magit)Log Margin")
53   :group 'magit-log)
54
55 (defvar-local magit-buffer-margin nil)
56 (put 'magit-buffer-margin 'permanent-local t)
57
58 (defvar-local magit-set-buffer-margin-refresh nil)
59
60 (defvar magit--age-spec)
61
62 ;;; Commands
63
64 (magit-define-popup magit-margin-popup
65   "Popup console for changing appearance of the margin."
66   :actions '("Margin"
67              (?L "Toggle visibility" magit-toggle-margin)
68              (?l "Cycle style"       magit-cycle-margin-style)
69              (?d "Toggle details"    magit-toggle-margin-details)
70              (lambda ()
71                (and (with-current-buffer magit-pre-popup-buffer
72                       (derived-mode-p 'magit-refs-mode))
73                     (propertize "Left edge" 'face 'magit-popup-heading)))
74              (?v "Change verbosity" magit-refs-set-show-commit-count))
75   :max-action-columns 1)
76
77 (defun magit-toggle-margin ()
78   "Show or hide the Magit margin."
79   (interactive)
80   (unless (magit-margin-option)
81     (user-error "Magit margin isn't supported in this buffer"))
82   (setcar magit-buffer-margin (not (magit-buffer-margin-p)))
83   (magit-set-buffer-margin))
84
85 (defun magit-cycle-margin-style ()
86   "Cycle style used for the Magit margin."
87   (interactive)
88   (unless (magit-margin-option)
89     (user-error "Magit margin isn't supported in this buffer"))
90   ;; This is only suitable for commit margins (there are not others).
91   (setf (cadr magit-buffer-margin)
92         (pcase (cadr magit-buffer-margin)
93           (`age 'age-abbreviated)
94           (`age-abbreviated
95            (let ((default (cadr (symbol-value (magit-margin-option)))))
96              (if (stringp default) default "%Y-%m-%d %H:%M ")))
97           (_ 'age)))
98   (magit-set-buffer-margin nil t))
99
100 (defun magit-toggle-margin-details ()
101   "Show or hide details in the Magit margin."
102   (interactive)
103   (unless (magit-margin-option)
104     (user-error "Magit margin isn't supported in this buffer"))
105   (setf (nth 3 magit-buffer-margin)
106         (not (nth 3 magit-buffer-margin)))
107   (magit-set-buffer-margin nil t))
108
109 ;;; Core
110
111 (defun magit-buffer-margin-p ()
112   (car magit-buffer-margin))
113
114 (defun magit-margin-option ()
115   (pcase major-mode
116     (`magit-cherry-mode     'magit-cherry-margin)
117     (`magit-log-mode        'magit-log-margin)
118     (`magit-log-select-mode 'magit-log-select-margin)
119     (`magit-reflog-mode     'magit-reflog-margin)
120     (`magit-refs-mode       'magit-refs-margin)
121     (`magit-stashes-mode    'magit-stashes-margin)
122     (`magit-status-mode     'magit-status-margin)))
123
124 (defun magit-set-buffer-margin (&optional reset refresh)
125   (when-let ((option (magit-margin-option)))
126     (let* ((default (symbol-value option))
127            (default-width (nth 2 default)))
128       (when (or reset (not magit-buffer-margin))
129         (setq magit-buffer-margin (copy-sequence default)))
130       (pcase-let ((`(,enable ,style ,_width ,details ,details-width)
131                    magit-buffer-margin))
132         (when (functionp default-width)
133           (setf (nth 2 magit-buffer-margin)
134                 (funcall default-width style details details-width)))
135         (dolist (window (get-buffer-window-list nil nil 0))
136           (with-selected-window window
137             (magit-set-window-margin window)
138             (if enable
139                 (add-hook  'window-configuration-change-hook
140                            'magit-set-window-margin nil t)
141               (remove-hook 'window-configuration-change-hook
142                            'magit-set-window-margin t))))
143         (when (and enable (or refresh magit-set-buffer-margin-refresh))
144           (magit-refresh-buffer))))))
145
146 (defun magit-set-window-margin (&optional window)
147   (when (or window (setq window (get-buffer-window)))
148     (with-selected-window window
149       (set-window-margins
150        nil (car (window-margins))
151        (and (magit-buffer-margin-p)
152             (nth 2 magit-buffer-margin))))))
153
154 (defun magit-make-margin-overlay (&optional string previous-line)
155   (if previous-line
156       (save-excursion
157         (forward-line -1)
158         (magit-make-margin-overlay string))
159     ;; Don't put the overlay on the complete line to work around #1880.
160     (let ((o (make-overlay (1+ (line-beginning-position))
161                            (line-end-position)
162                            nil t)))
163       (overlay-put o 'evaporate t)
164       (overlay-put o 'before-string
165                    (propertize "o" 'display
166                                (list (list 'margin 'right-margin)
167                                      (or string " ")))))))
168
169 (defun magit-maybe-make-margin-overlay ()
170   (when (or (magit-section-match
171              '(unpulled unpushed recent stashes local cherries)
172              magit-insert-section--current)
173             (and (eq major-mode 'magit-refs-mode)
174                  (magit-section-match
175                   '(remote commit tags)
176                   magit-insert-section--current)))
177     (magit-make-margin-overlay nil t)))
178
179 ;;; Custom Support
180
181 (defun magit-margin-set-variable (mode symbol value)
182   (set-default symbol value)
183   (message "Updating margins in %s buffers..." mode)
184   (dolist (buffer (buffer-list))
185     (with-current-buffer buffer
186       (when (eq major-mode mode)
187         (magit-set-buffer-margin t)
188         (magit-refresh))))
189   (message "Updating margins in %s buffers...done" mode))
190
191 (defconst magit-log-margin--custom-type
192   '(list (boolean :tag "Show margin initially")
193          (choice  :tag "Show committer"
194                   (string :tag "date using time-format" "%Y-%m-%d %H:%M ")
195                   (const  :tag "date's age" age)
196                   (const  :tag "date's age (abbreviated)" age-abbreviated))
197          (const   :tag "Calculate width using magit-log-margin-width"
198                   magit-log-margin-width)
199          (boolean :tag "Show author name by default")
200          (integer :tag "Show author name using width")))
201
202 ;;; Time Utilities
203
204 (defvar magit--age-spec
205   `((?Y "year"   "years"   ,(round (* 60 60 24 365.2425)))
206     (?M "month"  "months"  ,(round (* 60 60 24 30.436875)))
207     (?w "week"   "weeks"   ,(* 60 60 24 7))
208     (?d "day"    "days"    ,(* 60 60 24))
209     (?h "hour"   "hours"   ,(* 60 60))
210     (?m "minute" "minutes" 60)
211     (?s "second" "seconds" 1))
212   "Time units used when formatting relative commit ages.
213
214 The value is a list of time units, beginning with the longest.
215 Each element has the form (CHAR UNIT UNITS SECONDS).  UNIT is the
216 time unit, UNITS is the plural of that unit.  CHAR is a character
217 abbreviation.  And SECONDS is the number of seconds in one UNIT.
218
219 This is defined as a variable to make it possible to use time
220 units for a language other than English.  It is not defined
221 as an option, because most other parts of Magit are always in
222 English.")
223
224 (defun magit--age (date &optional abbreviate)
225   (cl-labels ((fn (age spec)
226                   (pcase-let ((`(,char ,unit ,units ,weight) (car spec)))
227                     (let ((cnt (round (/ age weight 1.0))))
228                       (if (or (not (cdr spec))
229                               (>= (/ age weight) 1))
230                           (list cnt (cond (abbreviate char)
231                                           ((= cnt 1) unit)
232                                           (t units)))
233                         (fn age (cdr spec)))))))
234     (fn (abs (- (float-time)
235                 (if (stringp date)
236                     (string-to-number date)
237                   date)))
238         magit--age-spec)))
239
240 ;;; _
241 (provide 'magit-margin)
242 ;;; magit-margin.el ends here