Klimi's new dotfiles with stow.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

241 lines
9.0 KiB

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