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