config

Personal configuration.
git clone git://code.dwrz.net/config
Log | Files | Refs

magit-base.el (52671B)


      1 ;;; magit-base.el --- Early birds  -*- lexical-binding:t; coding:utf-8 -*-
      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 ;; This file contains code taken from GNU Emacs, which is
     24 ;; Copyright (C) 1976-2023 Free Software Foundation, Inc.
     25 
     26 ;;; Commentary:
     27 
     28 ;; This library defines utility functions, options and other things that
     29 ;; have to be available early on because they are used by several other
     30 ;; libraries, which cannot depend on one another, because that would lead
     31 ;; to circular dependencies.
     32 
     33 ;;; Code:
     34 
     35 (defconst magit--minimal-git "2.2.0")
     36 (defconst magit--minimal-emacs "26.1")
     37 
     38 (require 'cl-lib)
     39 (require 'compat)
     40 (require 'dash)
     41 (require 'eieio)
     42 (require 'subr-x)
     43 
     44 ;; For older Emacs releases we depend on an updated `seq' release from
     45 ;; GNU ELPA, for `seq-keep'.  Unfortunately something else may already
     46 ;; have required `seq', before `package' had a chance to put the more
     47 ;; recent version earlier on the `load-path'.
     48 (when (and (featurep 'seq)
     49            (not (fboundp 'seq-keep)))
     50   (unload-feature 'seq 'force))
     51 (require 'seq)
     52 
     53 (require 'crm)
     54 
     55 (require 'magit-section)
     56 
     57 (eval-when-compile (require 'info))
     58 (declare-function Info-get-token "info" (pos start all &optional errorstring))
     59 
     60 (eval-when-compile (require 'vc-git))
     61 (declare-function vc-git--run-command-string "vc-git" (file &rest args))
     62 
     63 (eval-when-compile (require 'which-func))
     64 (declare-function which-function "which-func" ())
     65 
     66 ;;; Options
     67 
     68 (defcustom magit-completing-read-function #'magit-builtin-completing-read
     69   "Function to be called when requesting input from the user.
     70 
     71 If you have enabled `ivy-mode' or `helm-mode', then you don't
     72 have to customize this option; `magit-builtin-completing-read'
     73 will work just fine.  However, if you use Ido completion, then
     74 you do have to use `magit-ido-completing-read', because Ido is
     75 less well behaved than the former, more modern alternatives.
     76 
     77 If you would like to use Ivy or Helm completion with Magit but
     78 not enable the respective modes globally, then customize this
     79 option to use `ivy-completing-read' or
     80 `helm--completing-read-default'.  If you choose to use
     81 `ivy-completing-read', note that the items may always be shown in
     82 alphabetical order, depending on your version of Ivy."
     83   :group 'magit-essentials
     84   :type '(radio (function-item magit-builtin-completing-read)
     85                 (function-item magit-ido-completing-read)
     86                 (function-item ivy-completing-read)
     87                 (function-item helm--completing-read-default)
     88                 (function :tag "Other function")))
     89 
     90 (defcustom magit-dwim-selection
     91   '((magit-stash-apply        nil t)
     92     (magit-ediff-resolve-all  nil t)
     93     (magit-ediff-resolve-rest nil t)
     94     (magit-stash-branch       nil t)
     95     (magit-stash-branch-here  nil t)
     96     (magit-stash-format-patch nil t)
     97     (magit-stash-drop         nil ask)
     98     (magit-stash-pop          nil ask))
     99   "When not to offer alternatives and ask for confirmation.
    100 
    101 Many commands by default ask the user to select from a list of
    102 possible candidates.  They do so even when there is a thing at
    103 point that they can act on, which is then offered as the default.
    104 
    105 This option can be used to tell certain commands to use the thing
    106 at point instead of asking the user to select a candidate to act
    107 on, with or without confirmation.
    108 
    109 The value has the form ((COMMAND nil|PROMPT DEFAULT)...).
    110 
    111 - COMMAND is the command that should not prompt for a choice.
    112   To have an effect, the command has to use the function
    113   `magit-completing-read' or a utility function which in turn uses
    114   that function.
    115 
    116 - If the command uses `magit-completing-read' multiple times, then
    117   PROMPT can be used to only affect one of these uses.  PROMPT, if
    118   non-nil, is a regular expression that is used to match against
    119   the PROMPT argument passed to `magit-completing-read'.
    120 
    121 - DEFAULT specifies how to use the default.  If it is t, then
    122   the DEFAULT argument passed to `magit-completing-read' is used
    123   without confirmation.  If it is `ask', then the user is given
    124   a chance to abort.  DEFAULT can also be nil, in which case the
    125   entry has no effect."
    126   :package-version '(magit . "2.12.0")
    127   :group 'magit-commands
    128   :type '(repeat
    129           (list (symbol :tag "Command") ; It might not be fboundp yet.
    130                 (choice (const  :tag "for all prompts" nil)
    131                         (regexp :tag "for prompts matching regexp"))
    132                 (choice (const  :tag "offer other choices" nil)
    133                         (const  :tag "require confirmation" ask)
    134                         (const  :tag "use default without confirmation" t)))))
    135 
    136 (defconst magit--confirm-actions
    137   '((const discard)
    138     (const reverse)
    139     (const stage-all-changes)
    140     (const unstage-all-changes)
    141     (const delete)
    142     (const trash)
    143     (const resurrect)
    144     (const untrack)
    145     (const rename)
    146     (const reset-bisect)
    147     (const abort-cherry-pick)
    148     (const abort-revert)
    149     (const abort-rebase)
    150     (const abort-merge)
    151     (const merge-dirty)
    152     (const delete-unmerged-branch)
    153     (const delete-branch-on-remote)
    154     (const delete-pr-remote)
    155     (const drop-stashes)
    156     (const set-and-push)
    157     (const amend-published)
    158     (const rebase-published)
    159     (const edit-published)
    160     (const remove-modules)
    161     (const remove-dirty-modules)
    162     (const trash-module-gitdirs)
    163     (const stash-apply-3way)
    164     (const kill-process)
    165     (const safe-with-wip)))
    166 
    167 (defcustom magit-no-confirm '(set-and-push)
    168   "A list of symbols for actions Magit should not confirm, or t.
    169 
    170 Many potentially dangerous commands by default ask the user for
    171 confirmation.  Each of the below symbols stands for an action
    172 which, when invoked unintentionally or without being fully aware
    173 of the consequences, could lead to tears.  In many cases there
    174 are several commands that perform variations of a certain action,
    175 so we don't use the command names but more generic symbols.
    176 
    177 Applying changes:
    178 
    179   `discard' Discarding one or more changes (i.e., hunks or the
    180   complete diff for a file) loses that change, obviously.
    181 
    182   `reverse' Reverting one or more changes can usually be undone
    183   by reverting the reversion.
    184 
    185   `stage-all-changes', `unstage-all-changes' When there are both
    186   staged and unstaged changes, then un-/staging everything would
    187   destroy that distinction.  Of course that also applies when
    188   un-/staging a single change, but then less is lost and one does
    189   that so often that having to confirm every time would be
    190   unacceptable.
    191 
    192 Files:
    193 
    194   `delete' When a file that isn't yet tracked by Git is deleted
    195   then it is completely lost, not just the last changes.  Very
    196   dangerous.
    197 
    198   `trash' Instead of deleting a file it can also be move to the
    199   system trash.  Obviously much less dangerous than deleting it.
    200 
    201   Also see option `magit-delete-by-moving-to-trash'.
    202 
    203   `resurrect' A deleted file can easily be resurrected by
    204   \"deleting\" the deletion, which is done using the same command
    205   that was used to delete the same file in the first place.
    206 
    207   `untrack' Untracking a file can be undone by tracking it again.
    208 
    209   `rename' Renaming a file can easily be undone.
    210 
    211 Sequences:
    212 
    213   `reset-bisect' Aborting (known to Git as \"resetting\") a
    214   bisect operation loses all information collected so far.
    215 
    216   `abort-cherry-pick' Aborting a cherry-pick throws away all
    217   conflict resolutions which has already been carried out by the
    218   user.
    219 
    220   `abort-revert' Aborting a revert throws away all conflict
    221   resolutions which has already been carried out by the user.
    222 
    223   `abort-rebase' Aborting a rebase throws away all already
    224   modified commits, but it's possible to restore those from the
    225   reflog.
    226 
    227   `abort-merge' Aborting a merge throws away all conflict
    228   resolutions which has already been carried out by the user.
    229 
    230   `merge-dirty' Merging with a dirty worktree can make it hard to
    231   go back to the state before the merge was initiated.
    232 
    233 References:
    234 
    235   `delete-unmerged-branch' Once a branch has been deleted it can
    236   only be restored using low-level recovery tools provided by
    237   Git.  And even then the reflog is gone.  The user always has
    238   to confirm the deletion of a branch by accepting the default
    239   choice (or selecting another branch), but when a branch has
    240   not been merged yet, also make sure the user is aware of that.
    241 
    242   `delete-branch-on-remote' Deleting a \"remote branch\" may mean
    243   deleting the (local) \"remote-tracking\" branch only, or also
    244   removing it from the remote itself.  The latter often makes more
    245   sense because otherwise simply fetching from the remote would
    246   restore the remote-tracking branch, but doing that can be
    247   surprising and hard to recover from, so we ask.
    248 
    249   `delete-pr-remote' When deleting a branch that was created from
    250   a pull-request and if no other branches still exist on that
    251   remote, then `magit-branch-delete' offers to delete the remote
    252   as well.  This should be safe because it only happens if no
    253   other refs exist in the remotes namespace, and you can recreate
    254   the remote if necessary.
    255 
    256   `drop-stashes' Dropping a stash is dangerous because Git stores
    257   stashes in the reflog.  Once a stash is removed, there is no
    258   going back without using low-level recovery tools provided by
    259   Git.  When a single stash is dropped, then the user always has
    260   to confirm by accepting the default (or selecting another).
    261   This action only concerns the deletion of multiple stashes at
    262   once.
    263 
    264 Publishing:
    265 
    266   `set-and-push' When pushing to the upstream or the push-remote
    267   and that isn't actually configured yet, then the user can first
    268   set the target.  If s/he confirms the default too quickly, then
    269   s/he might end up pushing to the wrong branch and if the remote
    270   repository is configured to disallow fixing such mistakes, then
    271   that can be quite embarrassing and annoying.
    272 
    273 Edit published history:
    274 
    275   Without adding these symbols here, you will be warned before
    276   editing commits that have already been pushed to one of the
    277   branches listed in `magit-published-branches'.
    278 
    279   `amend-published' Affects most commands that amend to `HEAD'.
    280 
    281   `rebase-published' Affects commands that perform interactive
    282   rebases.  This includes commands from the commit popup that
    283   modify a commit other than `HEAD', namely the various fixup
    284   and squash variants.
    285 
    286   `edit-published' Affects the commands `magit-edit-line-commit'
    287   and `magit-diff-edit-hunk-commit'.  These two commands make
    288   it quite easy to accidentally edit a published commit, so you
    289   should think twice before configuring them not to ask for
    290   confirmation.
    291 
    292   To disable confirmation completely, add all three symbols here
    293   or set `magit-published-branches' to nil.
    294 
    295 Removing modules:
    296 
    297   `remove-modules' When you remove the working directory of a
    298   module that does not contain uncommitted changes, then that is
    299   safer than doing so when there are uncommitted changes and/or
    300   when you also remove the gitdir.  Still, you don't want to do
    301   that by accident.
    302 
    303   `remove-dirty-modules' When you remove the working directory of
    304   a module that contains uncommitted changes, then those changes
    305   are gone for good.  It is better to go to the module, inspect
    306   these changes and only if appropriate discard them manually.
    307 
    308   `trash-module-gitdirs' When you remove the gitdir of a module,
    309   then all unpushed changes are gone for good.  It is very easy
    310   to forget that you have some unfinished work on an unpublished
    311   feature branch or even in a stash.
    312 
    313   Actually there are some safety precautions in place, that might
    314   help you out if you make an unwise choice here, but don't count
    315   on it.  In case of emergency, stay calm and check the stash and
    316   the `trash-directory' for traces of lost work.
    317 
    318 Various:
    319 
    320   `stash-apply-3way' When a stash cannot be applied using \"git
    321   stash apply\", then Magit uses \"git apply\" instead, possibly
    322   using the \"--3way\" argument, which isn't always perfectly
    323   safe.  See also `magit-stash-apply'.
    324 
    325   `kill-process' There seldom is a reason to kill a process.
    326 
    327 Global settings:
    328 
    329   Instead of adding all of the above symbols to the value of this
    330   option you can also set it to the atom `t', which has the same
    331   effect as adding all of the above symbols.  Doing that most
    332   certainly is a bad idea, especially because other symbols might
    333   be added in the future.  So even if you don't want to be asked
    334   for confirmation for any of these actions, you are still better
    335   of adding all of the respective symbols individually.
    336 
    337   When `magit-wip-before-change-mode' is enabled then these actions
    338   can fairly easily be undone: `discard', `reverse',
    339   `stage-all-changes', and `unstage-all-changes'.  If and only if
    340   this mode is enabled, then `safe-with-wip' has the same effect
    341   as adding all of these symbols individually."
    342   :package-version '(magit . "2.1.0")
    343   :group 'magit-essentials
    344   :group 'magit-commands
    345   :type `(choice (const :tag "Always require confirmation" nil)
    346                  (const :tag "Never require confirmation" t)
    347                  (set   :tag "Require confirmation except for"
    348                         ;; `remove-dirty-modules' and
    349                         ;; `trash-module-gitdirs' intentionally
    350                         ;; omitted.
    351                         ,@magit--confirm-actions)))
    352 
    353 (defcustom magit-slow-confirm '(drop-stashes)
    354   "Whether to ask user \"y or n\" or \"yes or no\" questions.
    355 
    356 When this is nil, then `y-or-n-p' is used when the user has to
    357 confirm a potentially destructive action.  When this is t, then
    358 `yes-or-no-p' is used instead.  If this is a list of symbols
    359 identifying actions, then `yes-or-no-p' is used for those,
    360 `y-or-no-p' for all others.  The list of actions is the same as
    361 for `magit-no-confirm' (which see)."
    362   :package-version '(magit . "2.9.0")
    363   :group 'magit-miscellaneous
    364   :type `(choice (const :tag "Always ask \"yes or no\" questions" t)
    365                  (const :tag "Always ask \"y or n\" questions" nil)
    366                  (set   :tag "Ask \"yes or no\" questions only for"
    367                         ,@magit--confirm-actions)))
    368 
    369 (defcustom magit-no-message nil
    370   "A list of messages Magit should not display.
    371 
    372 Magit displays most echo area messages using `message', but a few
    373 are displayed using `magit-message' instead, which takes the same
    374 arguments as the former, FORMAT-STRING and ARGS.  `magit-message'
    375 forgoes printing a message if any member of this list is a prefix
    376 of the respective FORMAT-STRING.
    377 
    378 If Magit prints a message which causes you grief, then please
    379 first investigate whether there is another option which can be
    380 used to suppress it.  If that is not the case, then ask the Magit
    381 maintainers to start using `magit-message' instead of `message'
    382 in that case.  We are not proactively replacing all uses of
    383 `message' with `magit-message', just in case someone *might* find
    384 some of these messages useless.
    385 
    386 Messages which can currently be suppressed using this option are:
    387 * \"Turning on magit-auto-revert-mode...\""
    388   :package-version '(magit . "2.8.0")
    389   :group 'magit-miscellaneous
    390   :type '(repeat string))
    391 
    392 (defcustom magit-verbose-messages nil
    393   "Whether to make certain prompts and messages more verbose.
    394 
    395 Occasionally a user suggests that a certain prompt or message
    396 should be more verbose, but I would prefer to keep it as-is
    397 because I don't think that the fact that that one user did not
    398 understand the existing prompt/message means that a large number
    399 of users would have the same difficulty, and that making it more
    400 verbose would actually do a disservice to users who understand
    401 the shorter prompt well enough.
    402 
    403 Going forward I will start offering both messages when I feel the
    404 suggested longer message is reasonable enough, and the value of
    405 this option decides which will be used.  Note that changing the
    406 value of this option affects all such messages and that I do not
    407 intend to add an option per prompt."
    408   :package-version '(magit . "4.0.0")
    409   :group 'magit-miscellaneous
    410   :type 'boolean)
    411 
    412 (defcustom magit-ellipsis
    413   '((margin (?… . ">"))
    414     (t      (?… . "...")))
    415   "Characters or strings used to abbreviate text in some buffers.
    416 
    417 Each element has the form (WHERE (FANCY . UNIVERSAL)).
    418 
    419 FANCY is a single character or nil whereas UNIVERSAL is a string
    420 of any length.  The ellipsis produced by `magit--ellipsis' will
    421 be FANCY if it's a non-nil character that can be displayed with
    422 the available fonts, otherwise UNIVERSAL will be used.  FANCY is
    423 meant to be a rich character like a horizontal ellipsis symbol or
    424 an emoji whereas UNIVERSAL something simpler available in a less
    425 rich environment like the CLI.  WHERE determines the use-case for
    426 the ellipsis definition.  Currently the only acceptable values
    427 for WHERE are `margin' or t (representing the default).
    428 
    429 Whether collapsed sections are indicated using ellipsis is
    430 controlled by `magit-section-visibility-indicator'."
    431   :package-version '(magit . "4.0.0")
    432   :group 'magit-miscellaneous
    433   :type '(repeat (list (symbol :tag "Where")
    434                        (cons (choice :tag "Fancy" character (const nil))
    435                              (string :tag "Universal")))))
    436 
    437 (defcustom magit-update-other-window-delay 0.2
    438   "Delay before automatically updating the other window.
    439 
    440 When moving around in certain buffers, then certain other
    441 buffers, which are being displayed in another window, may
    442 optionally be updated to display information about the
    443 section at point.
    444 
    445 When holding down a key to move by more than just one section,
    446 then that would update that buffer for each section on the way.
    447 To prevent that, updating the revision buffer is delayed, and
    448 this option controls for how long.  For optimal experience you
    449 might have to adjust this delay and/or the keyboard repeat rate
    450 and delay of your graphical environment or operating system."
    451   :package-version '(magit . "2.3.0")
    452   :group 'magit-miscellaneous
    453   :type 'number)
    454 
    455 (defcustom magit-view-git-manual-method 'info
    456   "How links to Git documentation are followed from Magit's Info manuals.
    457 
    458 `info'  Follow the link to the node in the `gitman' Info manual
    459         as usual.  Unfortunately that manual is not installed by
    460         default on some platforms, and when it is then the nodes
    461         look worse than the actual manpages.
    462 
    463 `man'   View the respective man-page using the `man' package.
    464 
    465 `woman' View the respective man-page using the `woman' package."
    466   :package-version '(magit . "2.9.0")
    467   :group 'magit-miscellaneous
    468   :type '(choice (const :tag "view info manual" info)
    469                  (const :tag "view manpage using `man'" man)
    470                  (const :tag "view manpage using `woman'" woman)))
    471 
    472 ;;; Section Classes
    473 
    474 (defclass magit-commit-section (magit-section)
    475   ((keymap :initform 'magit-commit-section-map)))
    476 
    477 (setf (alist-get 'commit magit--section-type-alist) 'magit-commit-section)
    478 
    479 (defclass magit-diff-section (magit-section)
    480   ((keymap :initform 'magit-diff-section-map))
    481   :abstract t)
    482 
    483 (defclass magit-file-section (magit-diff-section)
    484   ((keymap :initform 'magit-file-section-map)
    485    (source :initform nil :initarg :source)
    486    (header :initform nil :initarg :header)
    487    (binary :initform nil :initarg :binary)))
    488 
    489 (defclass magit-module-section (magit-file-section)
    490   ((keymap :initform 'magit-module-section-map)
    491    (range  :initform nil :initarg :range)))
    492 
    493 (defclass magit-hunk-section (magit-diff-section)
    494   ((keymap      :initform 'magit-hunk-section-map)
    495    (refined     :initform nil)
    496    (combined    :initform nil :initarg :combined)
    497    (from-range  :initform nil :initarg :from-range)
    498    (from-ranges :initform nil)
    499    (to-range    :initform nil :initarg :to-range)
    500    (about       :initform nil :initarg :about)))
    501 
    502 (setf (alist-get 'file   magit--section-type-alist) 'magit-file-section)
    503 (setf (alist-get 'module magit--section-type-alist) 'magit-module-section)
    504 (setf (alist-get 'hunk   magit--section-type-alist) 'magit-hunk-section)
    505 
    506 (defclass magit-log-section (magit-section)
    507   ((keymap :initform 'magit-log-section-map))
    508   :abstract t)
    509 (defclass magit-unpulled-section (magit-log-section) ())
    510 (defclass magit-unpushed-section (magit-log-section) ())
    511 (defclass magit-unmerged-section (magit-log-section) ())
    512 
    513 (setf (alist-get 'unpulled magit--section-type-alist) 'magit-unpulled-section)
    514 (setf (alist-get 'unpushed magit--section-type-alist) 'magit-unpushed-section)
    515 (setf (alist-get 'unmerged magit--section-type-alist) 'magit-unmerged-section)
    516 
    517 ;;; User Input
    518 
    519 (defvar helm-completion-in-region-default-sort-fn)
    520 (defvar helm-crm-default-separator)
    521 (defvar ivy-sort-functions-alist)
    522 (defvar ivy-sort-matches-functions-alist)
    523 (defvar vertico-sort-function)
    524 
    525 (defvar magit-completing-read--silent-default nil)
    526 
    527 (defvar magit-completing-read-default-prompt-predicate
    528   (lambda ()
    529     (and (eq magit-completing-read-function
    530              'magit-builtin-completing-read)
    531          (not (or (bound-and-true-p helm-mode)
    532                   (bound-and-true-p ivy-mode)
    533                   (bound-and-true-p selectrum-mode)
    534                   (bound-and-true-p vertico-mode)))))
    535   "Function used to determine whether to add default to prompt.
    536 
    537 This is used by `magit-completing-read' (which see).
    538 
    539 The default function returns nil, when a completion frameworks is used
    540 for which this is undesirable.  More precisely, it returns nil, when
    541 `magit-completing-read-function' is not `magit-builtin-completing-read',
    542 or one of `helm-mode', `ivy-mode', `selectrum-mode' or `vertico-mode'
    543 is enabled.  When this function returns nil, then nil is passed to
    544 `format-prompt' (which see), instead of the default (DEF or FALLBACK).")
    545 
    546 (defun magit-completing-read ( prompt collection &optional
    547                                predicate require-match initial-input
    548                                hist def fallback)
    549   "Read a choice in the minibuffer, or use the default choice.
    550 
    551 This is the function that Magit commands use when they need the
    552 user to select a single thing to act on.  The arguments have the
    553 same meaning as for `completing-read', except for FALLBACK, which
    554 is unique to this function and is described below.
    555 
    556 Instead of asking the user to choose from a list of possible
    557 candidates, this function may instead just return the default
    558 specified by DEF, with or without requiring user confirmation.
    559 Whether that is the case depends on PROMPT, `this-command' and
    560 `magit-dwim-selection'.  See the documentation of the latter for
    561 more information.
    562 
    563 If it does use the default without the user even having to
    564 confirm that, then `magit-completing-read--silent-default' is set
    565 to t, otherwise nil.
    566 
    567 If it does read a value in the minibuffer, then this function
    568 acts similarly to `completing-read', except for the following:
    569 
    570 - COLLECTION must be a list of choices.  A function is not
    571   supported.
    572 
    573 - If REQUIRE-MATCH is nil and the user exits without a choice,
    574   then nil is returned instead of an empty string.
    575 
    576 - If REQUIRE-MATCH is non-nil and the user exits without a
    577   choice, `user-error' is raised.
    578 
    579 - FALLBACK specifies a secondary default that is only used if
    580   the primary default DEF is nil.  The secondary default is not
    581   subject to `magit-dwim-selection' — if DEF is nil but FALLBACK
    582   is not, then this function always asks the user to choose a
    583   candidate, just as if both defaults were nil.
    584 
    585 - `format-prompt' is called on PROMPT and DEF (or FALLBACK if
    586   DEF is nil).  This appends \": \" to the prompt and may also
    587   add the default to the prompt, using the format specified by
    588   `minibuffer-default-prompt-format' and depending on
    589   `magit-completing-read-default-prompt-predicate'."
    590   (setq magit-completing-read--silent-default nil)
    591   (if-let ((dwim (and def
    592                       (nth 2 (seq-find (pcase-lambda (`(,cmd ,re ,_))
    593                                          (and (eq this-command cmd)
    594                                               (or (not re)
    595                                                   (string-match-p re prompt))))
    596                                        magit-dwim-selection)))))
    597       (if (eq dwim 'ask)
    598           (if (y-or-n-p (format "%s %s? " prompt def))
    599               def
    600             (user-error "Abort"))
    601         (setq magit-completing-read--silent-default t)
    602         def)
    603     (unless def
    604       (setq def fallback))
    605     (let ((command this-command)
    606           (reply (funcall
    607                   magit-completing-read-function
    608                   (magit--format-prompt prompt def)
    609                   (if (and (not (functionp collection))
    610                            def
    611                            (not (member def collection)))
    612                       (cons def collection)
    613                     collection)
    614                   predicate
    615                   require-match initial-input hist def)))
    616       (setq this-command command)
    617       ;; Note: Avoid `string=' to support `helm-comp-read-use-marked'.
    618       (if (equal reply "")
    619           (if require-match
    620               (user-error "Nothing selected")
    621             nil)
    622         reply))))
    623 
    624 (defun magit--format-prompt (prompt default)
    625   (format-prompt (if (string-suffix-p ": " prompt)
    626                      (substring prompt 0 -2)
    627                    prompt)
    628                  (and (funcall magit-completing-read-default-prompt-predicate)
    629                       default)))
    630 
    631 (defun magit--completion-table (collection)
    632   (lambda (string pred action)
    633     (if (eq action 'metadata)
    634         '(metadata (display-sort-function . identity))
    635       (complete-with-action action collection string pred))))
    636 
    637 (defun magit-builtin-completing-read
    638     (prompt choices &optional predicate require-match initial-input hist def)
    639   "Magit wrapper for standard `completing-read' function."
    640   (unless (or (bound-and-true-p helm-mode)
    641               (bound-and-true-p ivy-mode))
    642     (setq choices (magit--completion-table choices)))
    643   (let ((ivy-sort-functions-alist nil)
    644         (vertico-sort-function nil))
    645     (completing-read prompt choices
    646                      predicate require-match
    647                      initial-input hist def)))
    648 
    649 (define-obsolete-function-alias 'magit-completing-read-multiple*
    650   'magit-completing-read-multiple "Magit-Section 4.0.0")
    651 
    652 (defun magit-completing-read-multiple
    653     ( prompt table &optional predicate require-match initial-input
    654       hist def inherit-input-method
    655       no-split)
    656   "Read multiple strings in the minibuffer, with completion.
    657 Like `completing-read-multiple' but don't mess with order of
    658 TABLE and take an additional argument NO-SPLIT, which causes
    659 the user input to be returned as a single unmodified string.
    660 Also work around various incompatible features of various
    661 third-party completion frameworks."
    662   (cl-letf*
    663       (;; To implement NO-SPLIT we have to manipulate the respective
    664        ;; `split-string' invocation.  We cannot simply advice it to
    665        ;; return the input string because `SELECTRUM' would choke on
    666        ;; that string.  Use a variable to pass along the raw user
    667        ;; input string. aa5f098ab
    668        (input nil)
    669        (split-string (symbol-function #'split-string))
    670        ((symbol-function #'split-string)
    671         (lambda (string &optional separators omit-nulls trim)
    672           (when (and no-split
    673                      (equal separators crm-separator)
    674                      (equal omit-nulls t))
    675             (setq input string))
    676           (funcall split-string string separators omit-nulls trim)))
    677        ;; Prevent `BUILT-IN' completion from messing up our existing
    678        ;; order of the completion candidates. aa5f098ab
    679        (table (magit--completion-table table))
    680        ;; Prevent `IVY' from messing up our existing order. c7af78726
    681        (ivy-sort-matches-functions-alist nil)
    682        ;; Prevent `HELM' from messing up our existing order.  6fcf994bd
    683        (helm-completion-in-region-default-sort-fn nil)
    684        ;; Prevent `HELM' from automatically appending the separator,
    685        ;; which is counterproductive when NO-SPLIT is non-nil and/or
    686        ;; when reading commit ranges. 798aff564
    687        (helm-crm-default-separator
    688         (if no-split nil (bound-and-true-p helm-crm-default-separator)))
    689        ;; And now, the moment we have all been waiting for...
    690        (values (completing-read-multiple
    691                 (magit--format-prompt prompt def)
    692                 table predicate require-match initial-input
    693                 hist def inherit-input-method)))
    694     (if no-split input values)))
    695 
    696 (defun magit-ido-completing-read
    697     (prompt choices &optional predicate require-match initial-input hist def)
    698   "Ido-based `completing-read' almost-replacement.
    699 
    700 Unfortunately `ido-completing-read' is not suitable as a
    701 drop-in replacement for `completing-read', instead we use
    702 `ido-completing-read+' from the third-party package by the
    703 same name."
    704   (if (and (require 'ido-completing-read+ nil t)
    705            (fboundp 'ido-completing-read+))
    706       (ido-completing-read+ prompt choices predicate require-match
    707                             initial-input hist
    708                             (or def (and require-match (car choices))))
    709     (display-warning 'magit "ido-completing-read+ is not installed
    710 
    711 To use Ido completion with Magit you need to install the
    712 third-party `ido-completing-read+' packages.  Falling
    713 back to built-in `completing-read' for now." :error)
    714     (magit-builtin-completing-read prompt choices predicate require-match
    715                                    initial-input hist def)))
    716 
    717 (defvar-keymap magit-minibuffer-local-ns-map
    718   :parent minibuffer-local-map
    719   "SPC" #'magit-whitespace-disallowed
    720   "TAB" #'magit-whitespace-disallowed)
    721 
    722 (defun magit-whitespace-disallowed ()
    723   "Beep to tell the user that whitespace is not allowed."
    724   (interactive)
    725   (ding)
    726   (message "Whitespace isn't allowed here")
    727   (setq defining-kbd-macro nil)
    728   (force-mode-line-update))
    729 
    730 (defun magit-read-string ( prompt &optional initial-input history default-value
    731                            inherit-input-method no-whitespace)
    732   "Read a string from the minibuffer, prompting with string PROMPT.
    733 
    734 This is similar to `read-string', but
    735 * empty input is only allowed if DEFAULT-VALUE is non-nil in
    736   which case that is returned,
    737 * whitespace is not allowed and leading and trailing whitespace is
    738   removed automatically if NO-WHITESPACE is non-nil,
    739 * `format-prompt' is used internally.
    740 * an invalid DEFAULT-VALUE is silently ignored."
    741   (when default-value
    742     (when (consp default-value)
    743       (setq default-value (car default-value)))
    744     (unless (stringp default-value)
    745       (setq default-value nil)))
    746   (let* ((minibuffer-completion-table nil)
    747          (val (read-from-minibuffer
    748                (format-prompt prompt default-value)
    749                initial-input (and no-whitespace magit-minibuffer-local-ns-map)
    750                nil history default-value inherit-input-method))
    751          (trim (lambda (regexp string)
    752                  (save-match-data
    753                    (if (string-match regexp string)
    754                        (replace-match "" t t string)
    755                      string)))))
    756     (when (and (string= val "") default-value)
    757       (setq val default-value))
    758     (when no-whitespace
    759       (setq val (funcall trim "\\`\\(?:[ \t\n\r]+\\)"
    760                          (funcall trim "\\(?:[ \t\n\r]+\\)\\'" val))))
    761     (cond ((string= val "")
    762            (user-error "Need non-empty input"))
    763           ((and no-whitespace (string-match-p "[\s\t\n]" val))
    764            (user-error "Input contains whitespace"))
    765           (t val))))
    766 
    767 (defun magit-read-string-ns ( prompt &optional initial-input history
    768                               default-value inherit-input-method)
    769   "Call `magit-read-string' with non-nil NO-WHITESPACE."
    770   (magit-read-string prompt initial-input history default-value
    771                      inherit-input-method t))
    772 
    773 (defmacro magit-read-char-case (prompt verbose &rest clauses)
    774   (declare (indent 2)
    775            (debug (form form &rest (characterp form body))))
    776   `(prog1 (pcase (read-char-choice
    777                   (let ((parts (nconc (list ,@(mapcar #'cadr clauses))
    778                                       ,(and verbose '(list "[C-g] to abort")))))
    779                     (concat ,prompt
    780                             (string-join (butlast parts) ", ")
    781                             ", or "  (car (last parts)) " "))
    782                   ',(mapcar #'car clauses))
    783             ,@(--map `(,(car it) ,@(cddr it)) clauses))
    784      (message "")))
    785 
    786 (defun magit-y-or-n-p (prompt &optional action)
    787   "Ask user a \"y or n\" or a \"yes or no\" question using PROMPT.
    788 Which kind of question is used depends on whether
    789 ACTION is a member of option `magit-slow-confirm'."
    790   (if (or (eq magit-slow-confirm t)
    791           (and action (member action magit-slow-confirm)))
    792       (yes-or-no-p prompt)
    793     (y-or-n-p prompt)))
    794 
    795 (defvar magit--no-confirm-alist
    796   '((safe-with-wip magit-wip-before-change-mode
    797                    discard reverse stage-all-changes unstage-all-changes)))
    798 
    799 (cl-defun magit-confirm ( action &optional prompt prompt-n noabort
    800                           (items nil sitems) prompt-suffix)
    801   (declare (indent defun))
    802   (when (and prompt (listp prompt))
    803     (setq prompt
    804           (apply #'format (car prompt)
    805                  (mapcar (lambda (a) (if (stringp a) (string-replace "%" "%%" a) a))
    806                          (cdr prompt)))))
    807   (when (and prompt-n (listp prompt-n))
    808     (setq prompt-n
    809           (apply #'format (car prompt-n)
    810                  (mapcar (lambda (a) (if (stringp a) (string-replace "%" "%%" a) a))
    811                          (cdr prompt-n)))))
    812   (setq prompt-n (format (concat (or prompt-n prompt) "? ") (length items)))
    813   (setq prompt   (format (concat (or prompt (magit-confirm-make-prompt action))
    814                                  "? ")
    815                          (car items)))
    816   (when prompt-suffix
    817     (setq prompt (concat prompt prompt-suffix)))
    818   (or (cond ((and (not (eq action t))
    819                   (or (eq magit-no-confirm t)
    820                       (memq action magit-no-confirm)
    821                       (cl-member-if (pcase-lambda (`(,key ,var . ,sub))
    822                                       (and (memq key magit-no-confirm)
    823                                            (memq action sub)
    824                                            (or (not var)
    825                                                (and (boundp var)
    826                                                     (symbol-value var)))))
    827                                     magit--no-confirm-alist)))
    828              (or (not sitems) items))
    829             ((not sitems)
    830              (magit-y-or-n-p prompt action))
    831             ((length= items 1)
    832              (and (magit-y-or-n-p prompt action) items))
    833             ((length> items 1)
    834              (and (magit-y-or-n-p (concat (string-join items "\n")
    835                                           "\n\n" prompt-n)
    836                                   action)
    837                   items)))
    838       (if noabort nil (user-error "Abort"))))
    839 
    840 (defun magit-confirm-files (action files &optional prompt prompt-suffix noabort)
    841   (when files
    842     (unless prompt
    843       (setq prompt (magit-confirm-make-prompt action)))
    844     (magit-confirm action
    845       (concat prompt " \"%s\"")
    846       (concat prompt " %d files")
    847       noabort files prompt-suffix)))
    848 
    849 (defun magit-confirm-make-prompt (action)
    850   (let ((prompt (symbol-name action)))
    851     (string-replace "-" " "
    852                     (concat (upcase (substring prompt 0 1))
    853                             (substring prompt 1)))))
    854 
    855 (defun magit-read-number-string (prompt &optional default _history)
    856   "Like `read-number' but return value is a string.
    857 DEFAULT may be a number or a numeric string."
    858   (number-to-string
    859    (read-number prompt (if (stringp default)
    860                            (string-to-number default)
    861                          default))))
    862 
    863 ;;; Debug Utilities
    864 
    865 ;;;###autoload
    866 (defun magit-emacs-Q-command ()
    867   "Show a shell command that runs an uncustomized Emacs with only Magit loaded.
    868 See info node `(magit)Debugging Tools' for more information."
    869   (interactive)
    870   (let ((cmd (mapconcat
    871               #'shell-quote-argument
    872               `(,(concat invocation-directory invocation-name)
    873                 "-Q" "--eval" "(setq debug-on-error t)"
    874                 ,@(mapcan
    875                    (lambda (dir) (list "-L" dir))
    876                    (delete-dups
    877                     (mapcan
    878                      (lambda (lib)
    879                        (if-let ((path (locate-library lib)))
    880                            (list (file-name-directory path))
    881                          (error "Cannot find mandatory dependency %s" lib)))
    882                      '(;; Like `LOAD_PATH' in `default.mk'.
    883                        "compat"
    884                        "dash"
    885                        "transient"
    886                        "with-editor"
    887                        ;; Obviously `magit' itself is needed too.
    888                        "magit"
    889                        ;; While these are part of the Magit repository,
    890                        ;; they are distributed as separate packages.
    891                        "magit-section"
    892                        "git-commit"
    893                        ))))
    894                 ;; Avoid Emacs bug#16406 by using full path.
    895                 "-l" ,(file-name-sans-extension (locate-library "magit")))
    896               " ")))
    897     (message "Uncustomized Magit command saved to kill-ring, %s"
    898              "please run it in a terminal.")
    899     (kill-new cmd)))
    900 
    901 ;;; Text Utilities
    902 
    903 (defmacro magit-bind-match-strings (varlist string &rest body)
    904   "Bind variables to submatches according to VARLIST then evaluate BODY.
    905 Bind the symbols in VARLIST to submatches of the current match
    906 data, starting with 1 and incrementing by 1 for each symbol.  If
    907 the last match was against a string, then that has to be provided
    908 as STRING."
    909   (declare (indent 2) (debug (listp form body)))
    910   (let ((s (cl-gensym "string"))
    911         (i 0))
    912     `(let ((,s ,string))
    913        (let ,(save-match-data
    914                (mapcan (lambda (sym)
    915                          (cl-incf i)
    916                          (and (not (eq (aref (symbol-name sym) 0) ?_))
    917                               (list (list sym (list 'match-string i s)))))
    918                        varlist))
    919          ,@body))))
    920 
    921 (defun magit-delete-line ()
    922   "Delete the rest of the current line."
    923   (delete-region (point) (1+ (line-end-position))))
    924 
    925 (defun magit-delete-match (&optional num)
    926   "Delete text matched by last search.
    927 If optional NUM is specified, only delete that subexpression."
    928   (delete-region (match-beginning (or num 0))
    929                  (match-end (or num 0))))
    930 
    931 (defun magit-file-line (file)
    932   "Return the first line of FILE as a string."
    933   (when (file-regular-p file)
    934     (with-temp-buffer
    935       (insert-file-contents file)
    936       (buffer-substring-no-properties (point-min)
    937                                       (line-end-position)))))
    938 
    939 (defun magit-file-lines (file &optional keep-empty-lines)
    940   "Return a list of strings containing one element per line in FILE.
    941 Unless optional argument KEEP-EMPTY-LINES is t, trim all empty lines."
    942   (when (file-regular-p file)
    943     (with-temp-buffer
    944       (insert-file-contents file)
    945       (split-string (buffer-string) "\n" (not keep-empty-lines)))))
    946 
    947 (defun magit-set-header-line-format (string)
    948   "Set `header-line-format' in the current buffer based on STRING.
    949 Pad the left side of STRING so that it aligns with the text area."
    950   (setq header-line-format
    951         (concat (propertize " " 'display '(space :align-to 0))
    952                 string)))
    953 
    954 (defun magit--format-spec (format specification)
    955   "Like `format-spec' but preserve text properties in SPECIFICATION."
    956   (with-temp-buffer
    957     (insert format)
    958     (goto-char (point-min))
    959     (while (search-forward "%" nil t)
    960       (cond
    961        ;; Quoted percent sign.
    962        ((eq (char-after) ?%)
    963         (delete-char 1))
    964        ;; Valid format spec.
    965        ((looking-at "\\([-0-9.]*\\)\\([a-zA-Z]\\)")
    966         (let* ((num (match-string 1))
    967                (spec (string-to-char (match-string 2)))
    968                (val (assq spec specification)))
    969           (unless val
    970             (error "Invalid format character: `%%%c'" spec))
    971           (setq val (cdr val))
    972           ;; Pad result to desired length.
    973           (let ((text (format (concat "%" num "s") val)))
    974             ;; Insert first, to preserve text properties.
    975             (if (next-property-change 0 (concat " " text))
    976                 ;; If the inserted text has properties, then preserve those.
    977                 (insert text)
    978               ;; Otherwise preserve FORMAT's properties, like `format-spec'.
    979               (insert-and-inherit text))
    980             ;; Delete the specifier body.
    981             (delete-region (+ (match-beginning 0) (length text))
    982                            (+ (match-end 0) (length text)))
    983             ;; Delete the percent sign.
    984             (delete-region (1- (match-beginning 0)) (match-beginning 0)))))
    985        ;; Signal an error on bogus format strings.
    986        (t
    987         (error "Invalid format string"))))
    988     (buffer-string)))
    989 
    990 ;;; Missing from Emacs
    991 
    992 (defun magit-kill-this-buffer ()
    993   "Kill the current buffer."
    994   (interactive)
    995   (kill-buffer (current-buffer)))
    996 
    997 (defun magit--buffer-string (&optional min max trim)
    998   "Like `buffer-substring-no-properties' but the arguments are optional.
    999 
   1000 This combines the benefits of `buffer-string', `buffer-substring'
   1001 and `buffer-substring-no-properties' into one function that is
   1002 not as painful to use as the latter.  I.e., you can write
   1003   (magit--buffer-string)
   1004 instead of
   1005   (buffer-substring-no-properties (point-min)
   1006                                   (point-max))
   1007 
   1008 Optional MIN defaults to the value of `point-min'.
   1009 Optional MAX defaults to the value of `point-max'.
   1010 
   1011 If optional TRIM is non-nil, then all leading and trailing
   1012 whitespace is remove.  If it is the newline character, then
   1013 one trailing newline is added."
   1014   ;; Lets write that one last time and be done with it:
   1015   (let ((str (buffer-substring-no-properties (or min (point-min))
   1016                                              (or max (point-max)))))
   1017     (if trim
   1018         (concat (string-trim str)
   1019                 (and (eq trim ?\n) "\n"))
   1020       str)))
   1021 
   1022 (defun magit--version> (v1 v2)
   1023   "Return t if version V1 is higher (younger) than V2.
   1024 This function should be named `version>' and be part of Emacs."
   1025   (version-list-< (version-to-list v2) (version-to-list v1)))
   1026 
   1027 (defun magit--version>= (v1 v2)
   1028   "Return t if version V1 is higher (younger) than or equal to V2.
   1029 This function should be named `version>=' and be part of Emacs."
   1030   (version-list-<= (version-to-list v2) (version-to-list v1)))
   1031 
   1032 ;;; Kludges for Emacs Bugs
   1033 
   1034 (when (< emacs-major-version 27)
   1035   ;; Work around https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559.
   1036   ;; Fixed by cb55ccae8be946f1562d74718086a4c8c8308ee5 in Emacs 27.1.
   1037   (with-eval-after-load 'vc-git
   1038     (defun vc-git-conflicted-files (directory)
   1039       "Return the list of files with conflicts in DIRECTORY."
   1040       (let* ((status
   1041               (vc-git--run-command-string directory "diff-files"
   1042                                           "--name-status"))
   1043              (lines (when status (split-string status "\n" 'omit-nulls)))
   1044              files)
   1045         (dolist (line lines files)
   1046           (when (string-match "\\([ MADRCU?!]\\)[ \t]+\\(.+\\)" line)
   1047             (let ((state (match-string 1 line))
   1048                   (file (match-string 2 line)))
   1049               (when (equal state "U")
   1050                 (push (expand-file-name file directory) files)))))))))
   1051 
   1052 (when (< emacs-major-version 27)
   1053   (defun vc-git--call@bug21559 (fn buffer command &rest args)
   1054     "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
   1055     (let ((process-environment process-environment))
   1056       (when revert-buffer-in-progress-p
   1057         (push "GIT_OPTIONAL_LOCKS=0" process-environment))
   1058       (apply fn buffer command args)))
   1059   (advice-add 'vc-git--call :around 'vc-git--call@bug21559)
   1060 
   1061   (defun vc-git-command@bug21559
   1062       (fn buffer okstatus file-or-list &rest flags)
   1063     "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
   1064     (let ((process-environment process-environment))
   1065       (when revert-buffer-in-progress-p
   1066         (push "GIT_OPTIONAL_LOCKS=0" process-environment))
   1067       (apply fn buffer okstatus file-or-list flags)))
   1068   (advice-add 'vc-git-command :around 'vc-git-command@bug21559)
   1069 
   1070   (defun auto-revert-handler@bug21559 (fn)
   1071     "Backport https://debbugs.gnu.org/cgi/bugreport.cgi?bug=21559."
   1072     (let ((revert-buffer-in-progress-p t))
   1073       (funcall fn)))
   1074   (advice-add 'auto-revert-handler :around 'auto-revert-handler@bug21559)
   1075   )
   1076 
   1077 (defun magit-which-function ()
   1078   "Return current function name based on point.
   1079 
   1080 This is a simple wrapper around `which-function', that resets
   1081 Imenu's potentially outdated and therefore unreliable cache by
   1082 setting `imenu--index-alist' to nil before calling that function."
   1083   (setq imenu--index-alist nil)
   1084   (which-function))
   1085 
   1086 ;;; Kludges for Custom
   1087 
   1088 (defun magit-custom-initialize-reset (symbol exp)
   1089   "Initialize SYMBOL based on EXP.
   1090 Set the value of the variable SYMBOL, using `set-default'
   1091 \(unlike `custom-initialize-reset', which uses the `:set'
   1092 function if any).  The value is either the symbol's current
   1093 value (as obtained using the `:get' function), if any, or
   1094 the value in the symbol's `saved-value' property if any, or
   1095 \(last of all) the value of EXP."
   1096   (set-default-toplevel-value
   1097    symbol
   1098    (condition-case nil
   1099        (let ((def (default-toplevel-value symbol))
   1100              (getter (get symbol 'custom-get)))
   1101          (if getter (funcall getter symbol) def))
   1102      (error
   1103       (eval (let ((sv (get symbol 'saved-value)))
   1104               (if sv (car sv) exp)))))))
   1105 
   1106 (defun magit-hook-custom-get (symbol)
   1107   (if (symbol-file symbol 'defvar)
   1108       (default-toplevel-value symbol)
   1109     ;;
   1110     ;; Called by `custom-initialize-reset' on behalf of `symbol's
   1111     ;; `defcustom', which is being evaluated for the first time to
   1112     ;; set the initial value, but there's already a default value,
   1113     ;; which most likely was established by one or more `add-hook'
   1114     ;; calls.
   1115     ;;
   1116     ;; We combine the `standard-value' and the current value, while
   1117     ;; preserving the order established by `:options', and return
   1118     ;; the result of that to be used as the "initial" default value.
   1119     ;;
   1120     (let ((standard (eval (car (get symbol 'standard-value))))
   1121           (current (default-toplevel-value symbol))
   1122           (value nil))
   1123       (dolist (fn (get symbol 'custom-options))
   1124         (when (or (memq fn standard)
   1125                   (memq fn current))
   1126           (push fn value)))
   1127       (dolist (fn current)
   1128         (unless (memq fn value)
   1129           (push fn value)))
   1130       (nreverse value))))
   1131 
   1132 ;;; Kludges for Info Manuals
   1133 
   1134 ;;;###autoload
   1135 (define-advice Info-follow-nearest-node (:around (fn &optional fork) gitman)
   1136   (let ((node (Info-get-token
   1137                (point) "\\*note[ \n\t]+"
   1138                "\\*note[ \n\t]+\\([^:]*\\):\\(:\\|[ \n\t]*(\\)?")))
   1139     (if (and node (string-match "^(gitman)\\(.+\\)" node))
   1140         (pcase magit-view-git-manual-method
   1141           ('info  (funcall fn fork))
   1142           ('man   (require 'man)
   1143                   (man (match-string 1 node)))
   1144           ('woman (require 'woman)
   1145                   (woman (match-string 1 node)))
   1146           (_ (user-error "Invalid value for `magit-view-git-manual-method'")))
   1147       (funcall fn fork))))
   1148 
   1149 ;; When making changes here, then also adjust the copy in docs/Makefile.
   1150 ;;;###autoload
   1151 (define-advice org-man-export (:around (fn link description format) gitman)
   1152   (if (and (eq format 'texinfo)
   1153            (string-prefix-p "git" link))
   1154       (string-replace "%s" link "
   1155 @ifinfo
   1156 @ref{%s,,,gitman,}.
   1157 @end ifinfo
   1158 @ifhtml
   1159 @html
   1160 the <a href=\"http://git-scm.com/docs/%s\">%s(1)</a> manpage.
   1161 @end html
   1162 @end ifhtml
   1163 @iftex
   1164 the %s(1) manpage.
   1165 @end iftex
   1166 ")
   1167     (funcall fn link description format)))
   1168 
   1169 ;;; Kludges for Package Managers
   1170 
   1171 (defun magit--chase-links (filename)
   1172   "Chase links in FILENAME until a name that is not a link.
   1173 
   1174 This is the same as `file-chase-links', except that it also handles
   1175 fake symlinks that are created by some source based package managers
   1176 \(Elpaca and Straight) on Windows.
   1177 
   1178 See <https://github.com/raxod502/straight.el/issues/520>."
   1179   (when-let*
   1180       ((manager (cond ((bound-and-true-p straight-symlink-mode) 'straight)
   1181                       ((bound-and-true-p elpaca-no-symlink-mode) 'elpaca)))
   1182        (build (pcase manager
   1183                 ('straight (bound-and-true-p straight-build-dir))
   1184                 ('elpaca (bound-and-true-p elpaca-builds-directory))))
   1185        ((string-prefix-p build filename))
   1186        (repo (pcase manager
   1187                ('straight
   1188                 (and (bound-and-true-p straight-base-dir)
   1189                      (expand-file-name "repos/magit/lisp/" straight-base-dir)))
   1190                ('elpaca
   1191                 (and (bound-and-true-p elpaca-repos-directory)
   1192                      (expand-file-name "magit/lisp/" elpaca-repos-directory))))))
   1193     (setq filename (expand-file-name (file-name-nondirectory filename) repo)))
   1194   (file-chase-links filename))
   1195 
   1196 ;;; Kludges for older Emacs versions
   1197 
   1198 (if (fboundp 'with-connection-local-variables)
   1199     (defalias 'magit--with-connection-local-variables
   1200       #'with-connection-local-variables)
   1201   (defmacro magit--with-connection-local-variables (&rest body)
   1202     "Abridged `with-connection-local-variables' for pre Emacs 27 compatibility.
   1203 Bind shell file name and switch for remote execution.
   1204 `with-connection-local-variables' isn't available until Emacs 27.
   1205 This kludge provides the minimal functionality required by
   1206 Magit."
   1207     `(if (file-remote-p default-directory)
   1208          (pcase-let ((`(,shell-file-name ,shell-command-switch)
   1209                       (with-no-warnings ; about unknown tramp functions
   1210                         (require 'tramp)
   1211                         (let ((vec (tramp-dissect-file-name
   1212                                     default-directory)))
   1213                           (list (tramp-get-method-parameter
   1214                                  vec 'tramp-remote-shell)
   1215                                 (string-join (tramp-get-method-parameter
   1216                                               vec 'tramp-remote-shell-args)
   1217                                              " "))))))
   1218            ,@body)
   1219        ,@body)))
   1220 
   1221 (put 'magit--with-connection-local-variables 'lisp-indent-function 'defun)
   1222 
   1223 ;;; Miscellaneous
   1224 
   1225 (defun magit-message (format-string &rest args)
   1226   "Display a message at the bottom of the screen, or not.
   1227 Like `message', except that if the users configured option
   1228 `magit-no-message' to prevent the message corresponding to
   1229 FORMAT-STRING to be displayed, then don't."
   1230   (unless (--first (string-prefix-p it format-string) magit-no-message)
   1231     (apply #'message format-string args)))
   1232 
   1233 (defun magit-msg (format-string &rest args)
   1234   "Display a message at the bottom of the screen, but don't log it.
   1235 Like `message', except that `message-log-max' is bound to nil."
   1236   (let ((message-log-max nil))
   1237     (apply #'message format-string args)))
   1238 
   1239 (defmacro magit--with-temp-position (buf pos &rest body)
   1240   (declare (indent 2))
   1241   `(with-current-buffer ,buf
   1242      (save-excursion
   1243        (save-restriction
   1244          (widen)
   1245          (goto-char (or ,pos 1))
   1246          ,@body))))
   1247 
   1248 (defun magit--ellipsis (&optional where)
   1249   "Build an ellipsis always as string, depending on WHERE."
   1250   (if (stringp magit-ellipsis)
   1251       magit-ellipsis
   1252     (if-let ((pair (car (or
   1253                          (alist-get (or where t) magit-ellipsis)
   1254                          (alist-get t magit-ellipsis)))))
   1255         (pcase-let ((`(,fancy . ,universal) pair))
   1256           (let ((ellipsis (if (and fancy (char-displayable-p fancy))
   1257                               fancy
   1258                             universal)))
   1259             (if (characterp ellipsis)
   1260                 (char-to-string ellipsis)
   1261               ellipsis)))
   1262       (user-error "Variable magit-ellipsis is invalid"))))
   1263 
   1264 (defun magit--ext-regexp-quote (str)
   1265   "Like `reqexp-quote', but for Extended Regular Expressions."
   1266   (let ((special (string-to-list "[*.\\?+^$({"))
   1267         (quoted nil))
   1268     (mapc (lambda (c)
   1269             (when (memq c special)
   1270               (push ?\\ quoted))
   1271             (push c quoted))
   1272           str)
   1273     (concat (nreverse quoted))))
   1274 
   1275 ;;; _
   1276 (provide 'magit-base)
   1277 ;;; magit-base.el ends here