magit-notes.el (6874B)
1 ;;; magit-notes.el --- Notes support -*- lexical-binding:t -*- 2 3 ;; Copyright (C) 2008-2024 The Magit Project Contributors 4 5 ;; Author: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> 6 ;; Maintainer: Jonas Bernoulli <emacs.magit@jonas.bernoulli.dev> 7 8 ;; SPDX-License-Identifier: GPL-3.0-or-later 9 10 ;; Magit is free software: you can redistribute it and/or modify it 11 ;; under the terms of the GNU General Public License as published by 12 ;; the Free Software Foundation, either version 3 of the License, or 13 ;; (at your option) any later version. 14 ;; 15 ;; Magit is distributed in the hope that it will be useful, but WITHOUT 16 ;; ANY WARRANTY; without even the implied warranty of MERCHANTABILITY 17 ;; or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public 18 ;; License for more details. 19 ;; 20 ;; You should have received a copy of the GNU General Public License 21 ;; along with Magit. If not, see <https://www.gnu.org/licenses/>. 22 23 ;;; Commentary: 24 25 ;; This library implements support for `git-notes'. 26 27 ;;; Code: 28 29 (require 'magit) 30 31 ;;; Commands 32 33 ;;;###autoload (autoload 'magit-notes "magit" nil t) 34 (transient-define-prefix magit-notes () 35 "Edit notes attached to commits." 36 :man-page "git-notes" 37 ["Configure local settings" 38 ("c" magit-core.notesRef) 39 ("d" magit-notes.displayRef)] 40 ["Configure global settings" 41 ("C" magit-global-core.notesRef) 42 ("D" magit-global-notes.displayRef)] 43 ["Arguments for prune" 44 :if-not magit-notes-merging-p 45 ("-n" "Dry run" ("-n" "--dry-run"))] 46 ["Arguments for edit and remove" 47 :if-not magit-notes-merging-p 48 (magit-notes:--ref)] 49 ["Arguments for merge" 50 :if-not magit-notes-merging-p 51 (magit-notes:--strategy)] 52 ["Actions" 53 :if-not magit-notes-merging-p 54 ("T" "Edit" magit-notes-edit) 55 ("r" "Remove" magit-notes-remove) 56 ("m" "Merge" magit-notes-merge) 57 ("p" "Prune" magit-notes-prune)] 58 ["Actions" 59 :if magit-notes-merging-p 60 ("c" "Commit merge" magit-notes-merge-commit) 61 ("a" "Abort merge" magit-notes-merge-abort)]) 62 63 (defun magit-notes-merging-p () 64 (let ((dir (expand-file-name "NOTES_MERGE_WORKTREE" (magit-gitdir)))) 65 (and (file-directory-p dir) 66 (directory-files dir nil "\\`[^.]")))) 67 68 (transient-define-infix magit-core.notesRef () 69 :class 'magit--git-variable 70 :variable "core.notesRef" 71 :reader #'magit-notes-read-ref 72 :prompt "Set local core.notesRef") 73 74 (transient-define-infix magit-notes.displayRef () 75 :class 'magit--git-variable 76 :variable "notes.displayRef" 77 :multi-value t 78 :reader #'magit-notes-read-refs 79 :prompt "Set local notes.displayRef") 80 81 (transient-define-infix magit-global-core.notesRef () 82 :class 'magit--git-variable 83 :variable "core.notesRef" 84 :global t 85 :reader #'magit-notes-read-ref 86 :prompt "Set global core.notesRef") 87 88 (transient-define-infix magit-global-notes.displayRef () 89 :class 'magit--git-variable 90 :variable "notes.displayRef" 91 :global t 92 :multi-value t 93 :reader #'magit-notes-read-refs 94 :prompt "Set global notes.displayRef") 95 96 (transient-define-argument magit-notes:--ref () 97 :description "Manipulate ref" 98 :class 'transient-option 99 :key "-r" 100 :argument "--ref=" 101 :reader #'magit-notes-read-ref) 102 103 (transient-define-argument magit-notes:--strategy () 104 :description "Merge strategy" 105 :class 'transient-option 106 :shortarg "-s" 107 :argument "--strategy=" 108 :choices '("manual" "ours" "theirs" "union" "cat_sort_uniq")) 109 110 (defun magit-notes-edit (commit &optional ref) 111 "Edit the note attached to COMMIT. 112 REF is the notes ref used to store the notes. 113 114 Interactively or when optional REF is nil use the value of Git 115 variable `core.notesRef' or \"refs/notes/commits\" if that is 116 undefined." 117 (interactive (magit-notes-read-args "Edit notes")) 118 (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref)) 119 "edit" commit)) 120 121 (defun magit-notes-remove (commit &optional ref) 122 "Remove the note attached to COMMIT. 123 REF is the notes ref from which the note is removed. 124 125 Interactively or when optional REF is nil use the value of Git 126 variable `core.notesRef' or \"refs/notes/commits\" if that is 127 undefined." 128 (interactive (magit-notes-read-args "Remove notes")) 129 (magit-run-git-with-editor "notes" (and ref (concat "--ref=" ref)) 130 "remove" commit)) 131 132 (defun magit-notes-merge (ref) 133 "Merge the notes ref REF into the current notes ref. 134 135 The current notes ref is the value of Git variable 136 `core.notesRef' or \"refs/notes/commits\" if that is undefined. 137 138 When there are conflicts, then they have to be resolved in the 139 temporary worktree \".git/NOTES_MERGE_WORKTREE\". When 140 done use `magit-notes-merge-commit' to finish. To abort 141 use `magit-notes-merge-abort'." 142 (interactive (list (magit-read-string-ns "Merge reference"))) 143 (magit-run-git-with-editor "notes" "merge" ref)) 144 145 (defun magit-notes-merge-commit () 146 "Commit the current notes ref merge. 147 Also see `magit-notes-merge'." 148 (interactive) 149 (magit-run-git-with-editor "notes" "merge" "--commit")) 150 151 (defun magit-notes-merge-abort () 152 "Abort the current notes ref merge. 153 Also see `magit-notes-merge'." 154 (interactive) 155 (magit-run-git-with-editor "notes" "merge" "--abort")) 156 157 (defun magit-notes-prune (&optional dry-run) 158 "Remove notes about unreachable commits." 159 (interactive (list (and (member "--dry-run" (transient-args 'magit-notes)) t))) 160 (when dry-run 161 (magit-process-buffer)) 162 (magit-run-git-with-editor "notes" "prune" (and dry-run "--dry-run"))) 163 164 ;;; Readers 165 166 (defun magit-notes-read-ref (prompt _initial-input history) 167 (and-let* ((ref (magit-completing-read 168 prompt (magit-list-notes-refnames) nil nil 169 (and-let* ((def (magit-get "core.notesRef"))) 170 (if (string-prefix-p "refs/notes/" def) 171 (substring def 11) 172 def)) 173 history))) 174 (if (string-prefix-p "refs/" ref) 175 ref 176 (concat "refs/notes/" ref)))) 177 178 (defun magit-notes-read-refs (prompt &optional _initial-input _history) 179 (mapcar (lambda (ref) 180 (if (string-prefix-p "refs/" ref) 181 ref 182 (concat "refs/notes/" ref))) 183 (completing-read-multiple 184 (concat prompt ": ") 185 (magit-list-notes-refnames) nil nil 186 (mapconcat (lambda (ref) 187 (if (string-prefix-p "refs/notes/" ref) 188 (substring ref 11) 189 ref)) 190 (magit-get-all "notes.displayRef") 191 ",")))) 192 193 (defun magit-notes-read-args (prompt) 194 (list (magit-read-branch-or-commit prompt (magit-stash-at-point)) 195 (and-let* ((str (--first (string-match "^--ref=\\(.+\\)" it) 196 (transient-args 'magit-notes)))) 197 (match-string 1 str)))) 198 199 ;;; _ 200 (provide 'magit-notes) 201 ;;; magit-notes.el ends here