magit-imenu.el (8684B)
1 ;;; magit-imenu.el --- Integrate Imenu in magit major modes -*- 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: Damien Cassou <damien@cassou.me> 9 ;; Maintainer: Jonas Bernoulli <jonas@bernoul.li> 10 11 ;; SPDX-License-Identifier: GPL-3.0-or-later 12 13 ;; Magit is free software; you can redistribute it and/or modify it 14 ;; under the terms of the GNU General Public License as published by 15 ;; the Free Software Foundation; either version 3, or (at your option) 16 ;; any later version. 17 ;; 18 ;; Magit is distributed in the hope that it will be useful, but WITHOUT 19 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 20 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 21 ;; License for more details. 22 ;; 23 ;; You should have received a copy of the GNU General Public License 24 ;; along with Magit. If not, see http://www.gnu.org/licenses. 25 26 ;;; Commentary: 27 28 ;; Emacs' major modes can facilitate navigation in their buffers by 29 ;; supporting Imenu. In such major modes, launching Imenu (M-x imenu) 30 ;; makes Emacs display a list of items (e.g., function definitions in 31 ;; a programming major mode). Selecting an item from this list moves 32 ;; point to this item. 33 34 ;; magit-imenu.el adds Imenu support to every major mode in Magit. 35 36 ;;; Code: 37 38 (require 'magit) 39 (require 'git-rebase) 40 41 ;;; Core 42 43 (defun magit-imenu--index-function (entry-types menu-types) 44 "Return an alist of imenu entries in current buffer. 45 46 ENTRY-TYPES is a list of section types to be selected through 47 `imenu'. 48 49 MENU-TYPES is a list of section types containing elements of 50 ENTRY-TYPES. Elements of MENU-TYPES are used to categorize 51 elements of ENTRY-TYPES. 52 53 This function is used as a helper for functions set as 54 `imenu-create-index-function'." 55 ;; If `which-function-mode' is active, then the create-index 56 ;; function is called at the time the major-mode is being enabled. 57 ;; Modes that derive from `magit-mode' have not populated the buffer 58 ;; at that time yet, so we have to abort. 59 (when-let ((section (magit-current-section)) 60 (entries (make-hash-table :test 'equal))) 61 (goto-char (point-max)) 62 (unless (oref section parent) 63 (forward-line -1)) 64 (while (magit-section--backward-find 65 (lambda () 66 (let* ((section (magit-current-section)) 67 (type (oref section type)) 68 (parent (oref section parent)) 69 (parent-type (oref parent type))) 70 (and (memq type entry-types) 71 (memq parent-type menu-types))))) 72 (let* ((section (magit-current-section)) 73 (name (buffer-substring-no-properties 74 (line-beginning-position) 75 (line-end-position))) 76 (parent (oref section parent)) 77 (parent-title (buffer-substring-no-properties 78 (oref parent start) 79 (1- (oref parent content))))) 80 (when (string-match " ([0-9]*)\\'" parent-title) 81 (setq parent-title (substring parent-title 0 (match-beginning 0)))) 82 (puthash parent-title 83 (cons (cons name (point)) 84 (gethash parent-title entries (list))) 85 entries))) 86 (mapcar (lambda (menu-title) 87 (cons menu-title (gethash menu-title entries))) 88 (hash-table-keys entries)))) 89 90 ;;; Log mode 91 92 ;;;###autoload 93 (defun magit-imenu--log-prev-index-position-function () 94 "Move point to previous line in current buffer. 95 This function is used as a value for 96 `imenu-prev-index-position-function'." 97 (magit-section--backward-find 98 (lambda () 99 (-contains-p '(commit stash) 100 (oref (magit-current-section) type))))) 101 102 ;;;###autoload 103 (defun magit-imenu--log-extract-index-name-function () 104 "Return imenu name for line at point. 105 This function is used as a value for 106 `imenu-extract-index-name-function'. Point should be at the 107 beginning of the line." 108 (save-match-data 109 (looking-at "\\([^ ]+\\)[ *|]+\\(.+\\)$") 110 (format "%s: %s" 111 (match-string-no-properties 1) 112 (match-string-no-properties 2)))) 113 114 ;;; Diff mode 115 116 ;;;###autoload 117 (defun magit-imenu--diff-prev-index-position-function () 118 "Move point to previous file line in current buffer. 119 This function is used as a value for 120 `imenu-prev-index-position-function'." 121 (magit-section--backward-find 122 (lambda () 123 (let ((section (magit-current-section))) 124 (and (magit-file-section-p section) 125 (not (equal (oref (oref section parent) type) 126 'diffstat))))))) 127 128 ;;;###autoload 129 (defun magit-imenu--diff-extract-index-name-function () 130 "Return imenu name for line at point. 131 This function is used as a value for 132 `imenu-extract-index-name-function'. Point should be at the 133 beginning of the line." 134 (buffer-substring-no-properties (line-beginning-position) 135 (line-end-position))) 136 137 ;;; Status mode 138 139 ;;;###autoload 140 (defun magit-imenu--status-create-index-function () 141 "Return an alist of all imenu entries in current buffer. 142 This function is used as a value for 143 `imenu-create-index-function'." 144 (magit-imenu--index-function 145 '(file commit stash pullreq issue) 146 '(unpushed unstaged unpulled untracked staged stashes pullreqs issues))) 147 148 ;;; Refs mode 149 150 ;;;###autoload 151 (defun magit-imenu--refs-create-index-function () 152 "Return an alist of all imenu entries in current buffer. 153 This function is used as a value for 154 `imenu-create-index-function'." 155 (magit-imenu--index-function 156 '(branch commit tag) 157 '(local remote tags))) 158 159 ;;; Cherry mode 160 161 ;;;###autoload 162 (defun magit-imenu--cherry-create-index-function () 163 "Return an alist of all imenu entries in current buffer. 164 This function is used as a value for 165 `imenu-create-index-function'." 166 (magit-imenu--index-function 167 '(commit) 168 '(cherries))) 169 170 ;;; Submodule list mode 171 172 ;;;###autoload 173 (defun magit-imenu--submodule-prev-index-position-function () 174 "Move point to previous line in magit-submodule-list buffer. 175 This function is used as a value for 176 `imenu-prev-index-position-function'." 177 (unless (bobp) 178 (forward-line -1))) 179 180 ;;;###autoload 181 (defun magit-imenu--submodule-extract-index-name-function () 182 "Return imenu name for line at point. 183 This function is used as a value for 184 `imenu-extract-index-name-function'. Point should be at the 185 beginning of the line." 186 (elt (tabulated-list-get-entry) 0)) 187 188 ;;; Repolist mode 189 190 ;;;###autoload 191 (defun magit-imenu--repolist-prev-index-position-function () 192 "Move point to previous line in magit-repolist buffer. 193 This function is used as a value for 194 `imenu-prev-index-position-function'." 195 (unless (bobp) 196 (forward-line -1))) 197 198 ;;;###autoload 199 (defun magit-imenu--repolist-extract-index-name-function () 200 "Return imenu name for line at point. 201 This function is used as a value for 202 `imenu-extract-index-name-function'. Point should be at the 203 beginning of the line." 204 (let ((entry (tabulated-list-get-entry))) 205 (format "%s (%s)" 206 (elt entry 0) 207 (elt entry (1- (length entry)))))) 208 209 ;;; Process mode 210 211 ;;;###autoload 212 (defun magit-imenu--process-prev-index-position-function () 213 "Move point to previous process in magit-process buffer. 214 This function is used as a value for 215 `imenu-prev-index-position-function'." 216 (magit-section--backward-find 217 (lambda () 218 (eq (oref (magit-current-section) type) 'process)))) 219 220 ;;;###autoload 221 (defun magit-imenu--process-extract-index-name-function () 222 "Return imenu name for line at point. 223 This function is used as a value for 224 `imenu-extract-index-name-function'. Point should be at the 225 beginning of the line." 226 (buffer-substring-no-properties (line-beginning-position) 227 (line-end-position))) 228 229 ;;; Rebase mode 230 231 ;;;###autoload 232 (defun magit-imenu--rebase-prev-index-position-function () 233 "Move point to previous commit in git-rebase buffer. 234 This function is used as a value for 235 `imenu-prev-index-position-function'." 236 (catch 'found 237 (while (not (bobp)) 238 (git-rebase-backward-line) 239 (when (git-rebase-line-p) 240 (throw 'found t))))) 241 242 ;;;###autoload 243 (defun magit-imenu--rebase-extract-index-name-function () 244 "Return imenu name for line at point. 245 This function is used as a value for 246 `imenu-extract-index-name-function'. Point should be at the 247 beginning of the line." 248 (buffer-substring-no-properties (line-beginning-position) 249 (line-end-position))) 250 251 ;;; _ 252 (provide 'magit-imenu) 253 ;;; magit-imenu.el ends here