Fix and docfix for the minibuffer-eldef-shorten-default feature.
[bpt/emacs.git] / lisp / minibuf-eldef.el
CommitLineData
a2e770db 1;;; minibuf-eldef.el --- Only show defaults in prompts when applicable -*- lexical-binding: t -*-
66d058c4 2;;
acaf905b 3;; Copyright (C) 2000-2012 Free Software Foundation, Inc.
66d058c4
MB
4;;
5;; Author: Miles Bader <miles@gnu.org>
6;; Keywords: convenience
7
8;; This file is part of GNU Emacs.
9
eb3fa2cf 10;; GNU Emacs is free software: you can redistribute it and/or modify
66d058c4 11;; it under the terms of the GNU General Public License as published by
eb3fa2cf
GM
12;; the Free Software Foundation, either version 3 of the License, or
13;; (at your option) any later version.
66d058c4
MB
14
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.
19
20;; You should have received a copy of the GNU General Public License
eb3fa2cf 21;; along with GNU Emacs. If not, see <http://www.gnu.org/licenses/>.
66d058c4
MB
22
23;;; Commentary:
24;;
25;; Defines the mode `minibuffer-electric-default-mode'.
26;;
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).
33
34;;; Code:
35
7d806bfe 36(defvar minibuffer-eldef-shorten-default)
a2e770db 37
7d806bfe 38(defun minibuffer-default--in-prompt-regexps ()
a2e770db
SM
39 `(("\\( (default\\(?: is\\)? \\(.*\\))\\):? \\'"
40 1 ,(if minibuffer-eldef-shorten-default " [\\2]"))
7d806bfe
CY
41 ("\\( \\[.*\\]\\):? *\\'" 1)))
42
43(defcustom minibuffer-eldef-shorten-default nil
44 "If non-nil, shorten \"(default ...)\" to \"[...]\" in minibuffer prompts."
45 :set (lambda (symbol value)
46 (set-default symbol value)
47 (setq-default minibuffer-default-in-prompt-regexps
48 (minibuffer-default--in-prompt-regexps)))
49 :type 'boolean
50 :group 'minibuffer
51 :version "24.3")
52
53(defvar minibuffer-default-in-prompt-regexps
54 (minibuffer-default--in-prompt-regexps)
fb7ada5f 55 "A list of regexps matching the parts of minibuffer prompts showing defaults.
66d058c4
MB
56When `minibuffer-electric-default-mode' is active, these regexps are
57used to identify the portions of prompts to elide.
58
a2e770db
SM
59Each entry is of the form (REGEXP MATCH-NUM &optional REWRITE),
60where REGEXP should match the default part of the prompt,
61MATCH-NUM is the subgroup that matched the actual default indicator,
62and REWRITE, if present, is a string to pass to `replace-match' that
63should be displayed in its place.")
66d058c4
MB
64
65\f
66;;; Internal variables
67
68;; A list of minibuffers to which we've added a post-command-hook.
69(defvar minibuf-eldef-frobbed-minibufs nil)
f1180544 70
66d058c4
MB
71;;; The following are all local variables in the minibuffer
72
73;; Input pre-inserted into the minibuffer before the user can edit it.
74(defvar minibuf-eldef-initial-input)
75(make-variable-buffer-local 'minibuf-eldef-initial-input)
76;; and the length of the buffer with it inserted.
77(defvar minibuf-eldef-initial-buffer-length)
78(make-variable-buffer-local 'minibuf-eldef-initial-buffer-length)
79
80;; True if the current minibuffer prompt contains the default spec.
81(defvar minibuf-eldef-showing-default-in-prompt)
82(make-variable-buffer-local 'minibuf-eldef-showing-default-in-prompt)
83
84;; An overlay covering the default portion of the prompt
85(defvar minibuf-eldef-overlay)
86(make-variable-buffer-local 'minibuf-eldef-overlay)
87
88\f
89;;; Hook functions
90
91;; This function goes on minibuffer-setup-hook
92(defun minibuf-eldef-setup-minibuffer ()
93 "Set up a minibuffer for `minibuffer-electric-default-mode'.
94The prompt and initial input should already have been inserted."
8bbb7c70 95 (let ((regexps minibuffer-default-in-prompt-regexps)
66d058c4
MB
96 (match nil)
97 (inhibit-point-motion-hooks t))
98 (save-excursion
99 (save-restriction
a2e770db 100 ;; Narrow to only the prompt.
66d058c4 101 (goto-char (point-min))
8bbb7c70 102 (narrow-to-region (point) (minibuffer-prompt-end))
a2e770db 103 ;; See if the prompt contains a default input indicator.
66d058c4
MB
104 (while regexps
105 (setq match (pop regexps))
a2e770db
SM
106 (cond
107 ((not (re-search-forward (if (stringp match) match (car match))
108 nil t))
109 ;; No match yet, try the next rule.
110 (setq match nil))
111 ((and (consp (cdr-safe match)) (nth 2 match))
112 ;; Matched a replacement rule.
113 (let* ((inhibit-read-only t)
114 (buffer-undo-list t)
115 (submatch (nth 1 match))
116 (replacement (nth 2 match))
117 (props (text-properties-at (match-beginning submatch))))
118 (replace-match replacement nil nil nil submatch)
119 (set-text-properties (match-beginning submatch)
120 (match-end submatch)
121 props)
122 ;; Replacement done, now keep trying with subsequent rules.
123 (setq match nil)
124 (goto-char (point-min))))
125 ;; Matched a non-replacement (i.e. electric hide) rule, no need to
126 ;; keep trying.
127 (t (setq regexps nil))))))
66d058c4 128 (if (not match)
a2e770db
SM
129 ;; No match for electric hiding, so just make sure our
130 ;; post-command-hook isn't left around.
66d058c4
MB
131 (remove-hook 'post-command-hook #'minibuf-eldef-update-minibuffer t)
132 ;; Yup; set things up so we can frob the prompt as the state of
133 ;; the input string changes.
134 (setq match (if (consp match) (cdr match) 0))
a2e770db 135 (setq match (if (consp match) (car match) match))
66d058c4
MB
136 (setq minibuf-eldef-overlay
137 (make-overlay (match-beginning match) (match-end match)))
138 (setq minibuf-eldef-showing-default-in-prompt t)
139 (setq minibuf-eldef-initial-input
8bbb7c70 140 (minibuffer-contents-no-properties))
66d058c4
MB
141 (setq minibuf-eldef-initial-buffer-length (point-max))
142 (add-to-list 'minibuf-eldef-frobbed-minibufs (current-buffer))
143 (add-hook 'post-command-hook #'minibuf-eldef-update-minibuffer nil t))))
144
145;; post-command-hook to swap prompts when necessary
146(defun minibuf-eldef-update-minibuffer ()
147 "Update a minibuffer's prompt to include a default only when applicable.
148This is intended to be used as a minibuffer post-command-hook for
149`minibuffer-electric-default-mode'; the minibuffer should have already
150been set up by `minibuf-eldef-setup-minibuffer'."
151 (unless (eq minibuf-eldef-showing-default-in-prompt
152 (and (= (point-max) minibuf-eldef-initial-buffer-length)
8bbb7c70 153 (string-equal (minibuffer-contents-no-properties)
66d058c4
MB
154 minibuf-eldef-initial-input)))
155 ;; swap state
156 (setq minibuf-eldef-showing-default-in-prompt
157 (not minibuf-eldef-showing-default-in-prompt))
158 (cond (minibuf-eldef-showing-default-in-prompt
159 (overlay-put minibuf-eldef-overlay 'invisible nil)
160 (overlay-put minibuf-eldef-overlay 'intangible nil))
161 (t
162 (overlay-put minibuf-eldef-overlay 'invisible t)
163 (overlay-put minibuf-eldef-overlay 'intangible t)))))
164
165\f
66d058c4
MB
166;;;###autoload
167(define-minor-mode minibuffer-electric-default-mode
35cd0213 168 "Toggle Minibuffer Electric Default mode.
06e21633
CY
169With a prefix argument ARG, enable Minibuffer Electric Default
170mode if ARG is positive, and disable it otherwise. If called
171from Lisp, enable the mode if ARG is omitted or nil.
172
173Minibuffer Electric Default mode is a global minor mode. When
174enabled, minibuffer prompts that show a default value only show
175the default when it's applicable -- that is, when hitting RET
176would yield the default value. If the user modifies the input
177such that hitting RET would enter a non-default value, the prompt
178is modified to remove the default indication."
66d058c4
MB
179 :global t
180 :group 'minibuffer
181 (if minibuffer-electric-default-mode
182 ;; Enable the mode
183 (add-hook 'minibuffer-setup-hook 'minibuf-eldef-setup-minibuffer)
184 ;; Disable the mode
185 (remove-hook 'minibuffer-setup-hook 'minibuf-eldef-setup-minibuffer)
186 ;; Remove our entry from any post-command-hook variable's it's still in
187 (dolist (minibuf minibuf-eldef-frobbed-minibufs)
188 (with-current-buffer minibuf
189 (remove-hook 'post-command-hook #'minibuf-eldef-update-minibuffer t)))
190 (setq minibuf-eldef-frobbed-minibufs nil)))
191
192
193(provide 'minibuf-eldef)
194
195;;; minibuf-eldef.el ends here