* doc/emacs/maintaining.texi: Fix one more occurrence of `next-file`
[emacs.git] / lisp / minibuf-eldef.el
bloba81e66358942d9ea94d79694f73aec329f08f71f
1 ;;; minibuf-eldef.el --- Only show defaults in prompts when applicable -*- lexical-binding: t -*-
2 ;;
3 ;; Copyright (C) 2000-2018 Free Software Foundation, Inc.
4 ;;
5 ;; Author: Miles Bader <miles@gnu.org>
6 ;; Keywords: convenience
8 ;; This file is part of GNU Emacs.
10 ;; GNU Emacs is free software: you can redistribute it and/or modify
11 ;; it 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.
15 ;; GNU Emacs is distributed in the hope that it will be useful,
16 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;; GNU General Public License for more details.
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs. If not, see <https://www.gnu.org/licenses/>.
23 ;;; Commentary:
25 ;; Defines the mode `minibuffer-electric-default-mode'.
27 ;; When active, minibuffer prompts that show a default value only show
28 ;; the default when it's applicable -- that is, when hitting RET would
29 ;; yield the default value. If the user modifies the input such that
30 ;; hitting RET would enter a non-default value, the prompt is modified
31 ;; to remove the default indication (which is restored if the input is
32 ;; ever restore to the match the initial input).
34 ;;; Code:
36 (defvar minibuffer-eldef-shorten-default)
38 (defun minibuffer-default--in-prompt-regexps ()
39 `(("\\( (default\\(?: is\\)? \\(.*\\))\\):? \\'"
40 1 ,(if minibuffer-eldef-shorten-default " [\\2]"))
41 ("([^(]+?\\(, default\\(?: is\\)? \\(.*\\)\\)):? \\'" 1)
42 ("\\( \\[.*\\]\\):? *\\'" 1)))
44 (defcustom minibuffer-eldef-shorten-default nil
45 "If non-nil, shorten \"(default ...)\" to \"[...]\" in minibuffer prompts."
46 :set (lambda (symbol value)
47 (set-default symbol value)
48 (setq-default minibuffer-default-in-prompt-regexps
49 (minibuffer-default--in-prompt-regexps)))
50 :type 'boolean
51 :group 'minibuffer
52 :version "24.3")
54 (defvar minibuffer-default-in-prompt-regexps
55 (minibuffer-default--in-prompt-regexps)
56 "A list of regexps matching the parts of minibuffer prompts showing defaults.
57 When `minibuffer-electric-default-mode' is active, these regexps are
58 used to identify the portions of prompts to elide.
60 Each entry is of the form (REGEXP MATCH-NUM &optional REWRITE),
61 where REGEXP should match the default part of the prompt,
62 MATCH-NUM is the subgroup that matched the actual default indicator,
63 and REWRITE, if present, is a string to pass to `replace-match' that
64 should be displayed in its place.")
67 ;;; Internal variables
69 ;; A list of minibuffers to which we've added a post-command-hook.
70 (defvar minibuf-eldef-frobbed-minibufs nil)
72 ;;; The following are all local variables in the minibuffer
74 ;; Input pre-inserted into the minibuffer before the user can edit it.
75 (defvar minibuf-eldef-initial-input)
76 (make-variable-buffer-local 'minibuf-eldef-initial-input)
77 ;; and the length of the buffer with it inserted.
78 (defvar minibuf-eldef-initial-buffer-length)
79 (make-variable-buffer-local 'minibuf-eldef-initial-buffer-length)
81 ;; True if the current minibuffer prompt contains the default spec.
82 (defvar minibuf-eldef-showing-default-in-prompt)
83 (make-variable-buffer-local 'minibuf-eldef-showing-default-in-prompt)
85 ;; An overlay covering the default portion of the prompt
86 (defvar minibuf-eldef-overlay)
87 (make-variable-buffer-local 'minibuf-eldef-overlay)
90 ;;; Hook functions
92 ;; This function goes on minibuffer-setup-hook
93 (defun minibuf-eldef-setup-minibuffer ()
94 "Set up a minibuffer for `minibuffer-electric-default-mode'.
95 The prompt and initial input should already have been inserted."
96 (let ((regexps minibuffer-default-in-prompt-regexps)
97 (match nil)
98 (inhibit-point-motion-hooks t))
99 (save-excursion
100 (save-restriction
101 ;; Narrow to only the prompt.
102 (goto-char (point-min))
103 (narrow-to-region (point) (minibuffer-prompt-end))
104 ;; See if the prompt contains a default input indicator.
105 (while regexps
106 (setq match (pop regexps))
107 (cond
108 ((not (re-search-forward (if (stringp match) match (car match))
109 nil t))
110 ;; No match yet, try the next rule.
111 (setq match nil))
112 ((and (consp (cdr-safe match)) (nth 2 match))
113 ;; Matched a replacement rule.
114 (let* ((inhibit-read-only t)
115 (buffer-undo-list t)
116 (submatch (nth 1 match))
117 (replacement (nth 2 match))
118 (props (text-properties-at (match-beginning submatch))))
119 (replace-match replacement nil nil nil submatch)
120 (set-text-properties (match-beginning submatch)
121 (match-end submatch)
122 props)
123 ;; Replacement done, now keep trying with subsequent rules.
124 (setq match nil)
125 (goto-char (point-min))))
126 ;; Matched a non-replacement (i.e. electric hide) rule, no need to
127 ;; keep trying.
128 (t (setq regexps nil))))))
129 (if (not match)
130 ;; No match for electric hiding, so just make sure our
131 ;; post-command-hook isn't left around.
132 (remove-hook 'post-command-hook #'minibuf-eldef-update-minibuffer t)
133 ;; Yup; set things up so we can frob the prompt as the state of
134 ;; the input string changes.
135 (setq match (if (consp match) (cdr match) 0))
136 (setq match (if (consp match) (car match) match))
137 (setq minibuf-eldef-overlay
138 (make-overlay (match-beginning match) (match-end match)))
139 (setq minibuf-eldef-showing-default-in-prompt t)
140 (setq minibuf-eldef-initial-input
141 (minibuffer-contents-no-properties))
142 (setq minibuf-eldef-initial-buffer-length (point-max))
143 (add-to-list 'minibuf-eldef-frobbed-minibufs (current-buffer))
144 (add-hook 'post-command-hook #'minibuf-eldef-update-minibuffer nil t))))
146 ;; post-command-hook to swap prompts when necessary
147 (defun minibuf-eldef-update-minibuffer ()
148 "Update a minibuffer's prompt to include a default only when applicable.
149 This is intended to be used as a minibuffer post-command-hook for
150 `minibuffer-electric-default-mode'; the minibuffer should have already
151 been set up by `minibuf-eldef-setup-minibuffer'."
152 (unless (eq minibuf-eldef-showing-default-in-prompt
153 (and (= (point-max) minibuf-eldef-initial-buffer-length)
154 (string-equal (minibuffer-contents-no-properties)
155 minibuf-eldef-initial-input)))
156 ;; Swap state.
157 (setq minibuf-eldef-showing-default-in-prompt
158 (not minibuf-eldef-showing-default-in-prompt))
159 (overlay-put minibuf-eldef-overlay 'invisible
160 (not minibuf-eldef-showing-default-in-prompt))))
163 ;;;###autoload
164 (define-minor-mode minibuffer-electric-default-mode
165 "Toggle Minibuffer Electric Default mode.
167 Minibuffer Electric Default mode is a global minor mode. When
168 enabled, minibuffer prompts that show a default value only show
169 the default when it's applicable -- that is, when hitting RET
170 would yield the default value. If the user modifies the input
171 such that hitting RET would enter a non-default value, the prompt
172 is modified to remove the default indication."
173 :global t
174 :group 'minibuffer
175 (if minibuffer-electric-default-mode
176 ;; Enable the mode
177 (add-hook 'minibuffer-setup-hook 'minibuf-eldef-setup-minibuffer)
178 ;; Disable the mode
179 (remove-hook 'minibuffer-setup-hook 'minibuf-eldef-setup-minibuffer)
180 ;; Remove our entry from any post-command-hook variable's it's still in
181 (dolist (minibuf minibuf-eldef-frobbed-minibufs)
182 (with-current-buffer minibuf
183 (remove-hook 'post-command-hook #'minibuf-eldef-update-minibuffer t)))
184 (setq minibuf-eldef-frobbed-minibufs nil)))
187 (provide 'minibuf-eldef)
189 ;;; minibuf-eldef.el ends here