[lice @ .darcsignore: put ignore file under control, and ignore fasl files.]
[lice.git] / minibuffer.lisp
blob64156ffe8a67bd6a5ab4c6f1e3ea209438faaa23
1 (in-package :lice)
3 (defvar *history-length* 30
4 "Maximum length for history lists before truncation takes place.
5 A number means that length; t means infinite. Truncation takes place
6 just after a new element is inserted. Setting the :HISTORY-LENGTH
7 property of a history variable overrides this default.")
9 (defvar *minibuffer-text-before-history* nil
10 "Text that was in this minibuffer before any history commands.
11 This is nil if there have not yet been any history commands
12 in this use of the minibuffer.")
14 (defclass minibuffer-window (window)
15 ())
17 (define-major-mode minibuffer-read-mode
18 (:name "minibuffer mode"
19 :map (let ((m (make-sparse-keymap)))
20 (define-key m (make-instance 'key :char #\m :control t) 'exit-minibuffer)
21 (define-key m (make-instance 'key :char #\Newline) 'exit-minibuffer)
22 (define-key m (make-instance 'key :char #\Return) 'exit-minibuffer)
23 (define-key m (make-instance 'key :char #\j :control t) 'exit-minibuffer)
24 (define-key m (make-instance 'key :char #\p :meta t) 'previous-history-element)
25 (define-key m (make-instance 'key :char #\n :meta t) 'next-history-element)
26 (define-key m (make-instance 'key :char #\g :control t) 'abort-recursive-edit)
27 m))
28 "minibuffer read mode"
29 ;; empty init
32 (define-major-mode minibuffer-complete-mode
33 (:name "minibuffer mode"
34 :map (let ((m (make-sparse-keymap)))
35 (define-key m (make-instance 'key :char #\m :control t) 'minibuffer-complete-and-exit)
36 (define-key m (make-instance 'key :char #\Newline) 'minibuffer-complete-and-exit)
37 (define-key m (make-instance 'key :char #\Return) 'minibuffer-complete-and-exit)
38 (define-key m (make-instance 'key :char #\j :control t) 'minibuffer-complete-and-exit)
39 (define-key m (make-instance 'key :char #\p :meta t) 'previous-history-element)
40 (define-key m (make-instance 'key :char #\n :meta t) 'next-history-element)
41 (define-key m (make-instance 'key :char #\i :control t) 'minibuffer-complete)
42 (define-key m (make-instance 'key :char #\Tab) 'minibuffer-complete)
43 (define-key m (make-instance 'key :char #\g :control t) 'abort-recursive-edit)
44 m))
45 "minibuffer complete mode"
46 ;; empty init
49 (defun make-minibuffer (major-mode)
50 "Return a fresh minibuffer with major mode, MAJOR-MODE."
51 ;; FIXME: Emacs prefixes it with a space so it doesn't show up in
52 ;; buffer listings. How are we gonna do this?
53 (let ((mb (get-buffer-create (generate-new-buffer-name " *minibuffer*"))))
54 (setf (buffer-major-mode mb) major-mode
55 (buffer-mode-line mb) nil)
56 mb))
58 (defun make-minibuffer-window (height cols)
59 (let* ((w (make-instance 'minibuffer-window
60 :x 0 :y (- height 1) :w cols :h 1
61 :line-state (make-array 1 :fill-pointer 1
62 :element-type 'integer :initial-element -1)
63 :cache (make-instance 'line-cache :valid t)
64 :top-line 0
65 :bottom-line 0
66 :point-col 0
67 :point-line 0
68 :buffer (make-minibuffer minibuffer-read-mode)
69 :top (make-marker)
70 :bottom (make-marker)
71 :bpoint (make-marker)
72 :point-col 0
73 :point-line 0)))
74 (set-marker (window-top w) 0 (window-buffer w))
75 (set-marker (window-bottom w) 0 (window-buffer w))
76 w))
78 ;; (defun clear-minibuffer ()
79 ;; "Erase the contents of the minibuffer when it isn't active."
80 ;; (let ((minibuffer (window-buffer (frame-minibuffer-window (selected-frame)))))
81 ;; (erase-buffer minibuffer)))
83 (defun minibuffer-window (&optional (frame (selected-frame)))
84 "Return the window used now for minibuffers.
85 If the optional argument FRAME is specified, return the minibuffer window
86 used by that frame."
87 (frame-minibuffer-window frame))
89 (defun message (string &rest arguments)
90 "Print a one-line message at the bottom of the screen."
91 ;; FIXME: properly implement the echo area
92 (when (zerop (frame-minibuffers-active (selected-frame)))
93 (let ((minibuffer (window-buffer (frame-minibuffer-window (selected-frame))))
94 (msg (apply #'format nil string arguments)))
95 (erase-buffer minibuffer)
96 (buffer-insert minibuffer msg)
97 (with-current-buffer (get-buffer-create "*messages*")
98 (goto-char (point-max))
99 (insert msg #\Newline)))))
101 (defun clear-minibuffer ()
102 "Erase the text in the minibuffer, unless it's active."
103 (when (zerop (frame-minibuffers-active (selected-frame)))
104 (erase-buffer (window-buffer (frame-minibuffer-window (selected-frame))))))
106 (defun show-minibuffer-prompt (frame prompt)
107 "Show PROMPT in the minibuffer. Flip a bit in FRAME to allow
108 switching to the minibuffer."
109 (declare (type string prompt))
110 (let ((minibuffer (window-buffer (frame-minibuffer-window (selected-frame))))
111 (field (npropertize prompt 'field 't 'front-sticky t 'rear-nonsticky t)))
112 (dformat +debug-v+ "~a~%" field)
113 (erase-buffer minibuffer)
114 (buffer-insert minibuffer field)))
116 (defun minibuffer-prompt-end (&optional (minibuf (current-buffer)))
117 "Return the buffer position of the end of the minibuffer prompt.
118 Return (point-min) if current buffer is not a mini-buffer."
119 (let ((beg (begv minibuf)))
120 (multiple-value-bind (start end) (find-field beg nil :beg t :end t :buf minibuf)
121 (dformat +debug-v+ "exit-mb: ~a ~a ~a~%" start end (buffer-size minibuf))
122 (if (and (= end (zv minibuf))
123 (null (get-char-property beg 'field minibuf)))
125 end))))
127 (defun minibuffer-contents (&optional (minibuf (current-buffer)))
128 "Return the user input in a minbuffer as a string.
129 If MINIBUF is omitted, default to the current buffer.
130 MINIBUF must be a minibuffer."
131 (buffer-substring (minibuffer-prompt-end minibuf) (zv minibuf) minibuf))
133 (defun minibuffer-contents-no-properties (&optional (minibuf (current-buffer)))
134 "Return the user input in a minbuffer as a string.
135 If MINIBUF is omitted, default to the current buffer.
136 MINIBUF must be a minibuffer."
137 (buffer-substring-no-properties (minibuffer-prompt-end minibuf) (zv minibuf) minibuf))
139 (defun delete-minibuffer-contents (&optional (minibuf (current-buffer)))
140 "Delete all user input in a minibuffer.
141 MINIBUF must be a minibuffer."
142 (let ((end (minibuffer-prompt-end minibuf)))
143 (when (< end (zv minibuf))
144 (delete-region end (zv minibuf)))))
146 (defun setup-minibuffer-for-read (major-mode prompt initial-contents history)
147 (save-window-excursion
148 ;; Create a new minibuffer
149 (let* ((frame (selected-frame))
150 (*minibuffer-history-variable* history)
151 (*minibuffer-history-position* 0)
152 (*minibuffer-text-before-history* nil)
153 (old-minibuffer (window-buffer (frame-minibuffer-window frame)))
154 (new-minibuffer (make-minibuffer major-mode)))
155 (window-save-point (get-current-window))
156 ;; attach it to the current frame
157 (set-window-buffer (frame-minibuffer-window frame) new-minibuffer)
158 (select-window (frame-minibuffer-window frame))
159 ;; Show the prompt
160 (show-minibuffer-prompt frame prompt)
161 ;; move to the end of input
162 (setf (marker-position (buffer-point new-minibuffer)) (buffer-size new-minibuffer))
163 ;; enter recursive edit
164 (dformat +debug-v+ "ya ohoe~%")
165 (incf (frame-minibuffers-active frame))
166 (unwind-protect
167 (progn
168 (recursive-edit)
169 (let* ((val (minibuffer-contents new-minibuffer))
170 (hist-string (when (> (length val) 0)
171 val)))
172 (when (and *minibuffer-history-variable* hist-string)
173 (let ((hist-val (symbol-value *minibuffer-history-variable*)))
174 ;; If the caller wanted to save the value read on a history list,
175 ;; then do so if the value is not already the front of the list.
176 (when (or (null hist-val)
177 (and (consp hist-val)
178 (not (equal hist-string (car hist-val)))))
179 (push hist-string hist-val)
180 (set *minibuffer-history-variable* hist-val))
181 ;; truncate if requested
182 (let ((len (or (get *minibuffer-history-variable* :history-length)
183 *history-length*)))
184 (when (integerp len)
185 (if (< len 0)
186 (set *minibuffer-history-variable* nil)
187 (let ((tmp (nthcdr len hist-val)))
188 (when tmp
189 (rplacd tmp nil))))))))
190 ;; return the value
191 val))
192 ;; Restore the buffer
193 (dformat +debug-v+ "minibuffer~%")
194 (set-window-buffer (frame-minibuffer-window frame) old-minibuffer)
195 (kill-buffer new-minibuffer)
196 (decf (frame-minibuffers-active frame))))))
198 (defun read-from-minibuffer (prompt &key initial-contents keymap read (history '*minibuffer-history*) default-value)
199 "Read a string from the minibuffer, prompting with string PROMPT.
200 The optional second arg INITIAL-CONTENTS is an obsolete alternative to
201 DEFAULT-VALUE. It normally should be nil in new code, except when
202 HISTORY is a cons. It is discussed in more detail below.
203 Third arg KEYMAP is a keymap to use whilst reading;
204 if omitted or nil, the default is `minibuffer-local-map'.
205 If fourth arg READ is non-nil, then interpret the result as a Lisp object
206 and return that object:
207 in other words, do `(car (read-from-string INPUT-STRING))'
208 Fifth arg HISTORY, if non-nil, specifies a history list and optionally
209 the initial position in the list. It can be a symbol, which is the
210 history list variable to use, or it can be a cons cell
211 (HISTVAR . HISTPOS). In that case, HISTVAR is the history list variable
212 to use, and HISTPOS is the initial position for use by the minibuffer
213 history commands. For consistency, you should also specify that
214 element of the history as the value of INITIAL-CONTENTS. Positions
215 are counted starting from 1 at the beginning of the list.
216 Sixth arg DEFAULT-VALUE is the default value. If non-nil, it is available
217 for history commands; but, unless READ is non-nil, `read-from-minibuffer'
218 does NOT return DEFAULT-VALUE if the user enters empty input! It returns
219 the empty string.
220 Seventh arg INHERIT-INPUT-METHOD, if non-nil, means the minibuffer inherits
221 the current input method and the setting of `enable-multibyte-characters'.
222 Eight arg KEEP-ALL, if non-nil, says to put all inputs in the history list,
223 even empty or duplicate inputs.
224 If the variable `minibuffer-allow-text-properties' is non-nil,
225 then the string which is returned includes whatever text properties
226 were present in the minibuffer. Otherwise the value has no text properties.
228 The remainder of this documentation string describes the
229 INITIAL-CONTENTS argument in more detail. It is only relevant when
230 studying existing code, or when HISTORY is a cons. If non-nil,
231 INITIAL-CONTENTS is a string to be inserted into the minibuffer before
232 reading input. Normally, point is put at the end of that string.
233 However, if INITIAL-CONTENTS is \(STRING . POSITION), the initial
234 input is STRING, but point is placed at _one-indexed_ position
235 POSITION in the minibuffer. Any integer value less than or equal to
236 one puts point at the beginning of the string. *Note* that this
237 behavior differs from the way such arguments are used in `completing-read'
238 and some related functions, which use zero-indexing for POSITION."
239 (setup-minibuffer-for-read minibuffer-read-mode prompt initial-contents history))
241 (defun tree-find (tree obj &key (test #'eq))
242 "find OBJ in TREE. Return the OBJ or nil."
243 (cond ((typep tree obj)
244 (when (funcall test tree obj)
245 tree))
246 (t (or (tree-find (car tree) obj :test test)
247 (tree-find (cdr tree) obj :test test)))))
249 (defun tree-sibling (tree obj &key (test #'eq))
250 "Return the OBJ's sibling in tree or nil."
251 (declare (type (or list window) tree))
252 (cond ((typep tree obj)
253 nil)
254 ((funcall test obj (car tree))
255 (cdr tree))
256 ((funcall test obj (cdr tree))
257 (car tree))
258 (t (or (tree-sibling (car tree) obj :test test)
259 (tree-sibling (cdr tree) obj :test test)))))
261 (defun frame-for-window (window)
262 "Return the frame that holds WINDOW."
263 (find-if (lambda (f)
264 (tree-find (frame-window-tree f) window)) *frame-list*))
266 (defcommand ask-user ()
268 (message "user typed: ~a" (read-from-minibuffer "input: ")))
270 (defcommand exit-minibuffer ()
272 (dformat +debug-v+ "exit-minibuffer~%")
273 (throw 'exit nil))
275 (defcommand abort-recursive-edit ()
276 (throw 'exit t))
278 (defgeneric all-completions (string alist &optional predicate hide-spaces)
279 (:documentation "Return a list of possible matches."))
281 (defmethod all-completions (string (alist list) &optional predicate hide-spaces)
282 (let ((tester (or predicate
283 (lambda (s)
284 (string= string s :end2 (min (length string)
285 (length s)))))))
286 (loop for elt in alist
287 for i = (cond ((consp elt)
288 (car elt))
289 ((symbolp elt)
290 ;; FIXME: this is a hack. isn't there a
291 ;; global that decides whether they're
292 ;; printed upcase or not?
293 (string-downcase (symbol-name elt)))
294 (t elt))
295 when (funcall tester i)
296 collect i)))
298 (defun try-completion (string alist &optional predicate)
299 (labels ((all-are-good (match strings)
300 (loop for i in strings
301 never (string/= match i :end2 (min (length match)
302 (length i))))))
303 (let* ((possibles (all-completions string alist predicate))
304 (match (make-array 100 ; MOVITZ: the match can't be more than 100 chars
305 :element-type 'character
306 :fill-pointer 0
307 ;; :adjustable t
309 ;; FIXME: this dubplicates effort since the first (length string)
310 ;; chars will be the same.
311 (when possibles
312 (loop for i from 0 below (length (first possibles))
313 do (vector-push-extend (char (first possibles) i) match)
314 unless (all-are-good match possibles)
315 do (progn
316 (decf (fill-pointer match))
317 (return)))
318 match))))
320 (defcommand minibuffer-complete-and-exit ()
321 ;; FIXME: this should be done properly
322 (throw 'exit nil))
324 (defvar *minibuffer-completion-table* nil
325 "Alist or obarray used for completion in the minibuffer.
326 This becomes the ALIST argument to `try-completion' and `all-completions'.
327 The value can also be a list of strings or a hash table.
329 The value may alternatively be a function, which is given three arguments:
330 STRING, the current buffer contents;
331 PREDICATE, the predicate for filtering possible matches;
332 CODE, which says what kind of things to do.
333 CODE can be nil, t or `lambda'.
334 nil means to return the best completion of STRING, or nil if there is none.
335 t means to return a list of all possible completions of STRING.
336 `lambda' means to return t if STRING is a valid completion as it stands.")
338 (defvar *minibuffer-history* nil
339 "Default minibuffer history list.
340 This is used for all minibuffer input
341 except when an alternate history list is specified.")
343 (defvar *minibuffer-history-position* nil
344 "Current position of redoing in the history list.")
346 (defvar *minibuffer-history-variable* '*minibuffer-history*
347 "History list symbol to add minibuffer values to.
348 Each string of minibuffer input, as it appears on exit from the minibuffer,
349 is added with
350 ** (set minibuffer-history-variable
351 ** (cons STRING (symbol-value minibuffer-history-variable)))")
353 (defvar *minibuffer-completion-predicate* nil
354 "Within call to `completing-read', this holds the PREDICATE argument.")
356 (define-condition history-end (lice-condition)
357 () (:documentation "raised when at the end of the history"))
359 (define-condition history-beginning (lice-condition)
360 () (:documentation "raised when at the begining of the history"))
362 (defcommand next-history-element ((&optional n)
363 :prefix)
364 (let ((narg (- *minibuffer-history-position* n))
365 (minimum 0)
366 elt)
367 (when (and (zerop *minibuffer-history-position*)
368 (null *minibuffer-text-before-history*))
369 (setf *minibuffer-text-before-history*
370 (minibuffer-contents-no-properties)))
371 (when (< narg minimum)
372 (signal 'history-end #|"End of history; no next item"|#))
373 (when (> narg (length (symbol-value *minibuffer-history-variable*)))
374 (signal 'history-beginning #|"Beginning of history; no preceding item"|#))
375 (goto-char (point-max))
376 (delete-minibuffer-contents)
377 (setf *minibuffer-history-position* narg)
378 (cond ((= narg 0)
379 (setf elt (or *minibuffer-text-before-history* "")
380 *minibuffer-text-before-history* nil))
382 (setf elt (nth (1- *minibuffer-history-position*)
383 (symbol-value *minibuffer-history-variable*)))))
384 (insert
385 ;; (if (and (eq minibuffer-history-sexp-flag (minibuffer-depth))
386 ;; (not minibuffer-returned-to-present))
387 ;; (let ((*print-level* nil))
388 ;; (prin1-to-string elt))
389 elt)
390 (goto-char (point-max))))
393 (defcommand previous-history-element ()
394 (next-history-element -1))
396 (defcommand minibuffer-complete ()
397 (let* ((txt (minibuffer-contents))
398 (match (try-completion txt *minibuffer-completion-table*)))
399 (dformat +debug-v+ "txt: ~a match: ~a~%" txt match)
400 (when match
401 (if (= (length match)
402 (length txt))
403 ;; no new text was added, so list the possibilities
404 (let* ((txt (minibuffer-contents))
405 (strings (all-completions txt *minibuffer-completion-table*)))
406 (with-current-buffer (get-buffer-create "*Completions*")
407 (erase-buffer)
408 (insert (format nil "Here are the completions.~%"))
409 (loop for c in strings
410 do (insert (format nil "~a~%" c)))
411 (goto-char (point-min))
412 (display-buffer (current-buffer))))
413 (progn
414 (goto-char (point-max))
415 (insert (subseq match (length txt))))))))
417 (defun completing-read (prompt table &key predicate require-match
418 initial-input (history '*minibuffer-history*) def)
419 "Read a string in the minibuffer, with completion.
420 PROMPT is a string to prompt with; normally it ends in a colon and a space.
421 TABLE is an alist whose elements' cars are strings, or an obarray.
422 TABLE can also be a function to do the completion itself.
423 PREDICATE limits completion to a subset of TABLE.
424 See `try-completion' and `all-completions' for more details
425 on completion, TABLE, and PREDICATE.
427 If REQUIRE-MATCH is non-nil, the user is not allowed to exit unless
428 the input is (or completes to) an element of TABLE or is null.
429 If it is also not t, Return does not exit if it does non-null completion.
430 If the input is null, `completing-read' returns an empty string,
431 regardless of the value of REQUIRE-MATCH.
433 If INITIAL-INPUT is non-nil, insert it in the minibuffer initially.
434 If it is (STRING . POSITION), the initial input
435 is STRING, but point is placed POSITION characters into the string.
436 This feature is deprecated--it is best to pass nil for INITIAL.
437 HISTORY, if non-nil, specifies a history list
438 and optionally the initial position in the list.
439 It can be a symbol, which is the history list variable to use,
440 or it can be a cons cell (HISTVAR . HISTPOS).
441 In that case, HISTVAR is the history list variable to use,
442 and HISTPOS is the initial position (the position in the list
443 which INITIAL-INPUT corresponds to).
444 Positions are counted starting from 1 at the beginning of the list.
445 DEF, if non-nil, is the default value."
446 (let ((*minibuffer-completion-table* table)
447 (*minibuffer-completion-predicate* predicate))
448 (setup-minibuffer-for-read minibuffer-complete-mode prompt initial-input history)))
450 ;; (defun y-or-n-p (prompt)
451 ;; "Ask user a \"y or n\" question. Return t if answer is \"y\".
452 ;; Takes one argument, which is the string to display to ask the question.
453 ;; It should end in a space; `y-or-n-p' adds `(y or n) ' to it.
454 ;; No confirmation of the answer is requested; a single character is enough.
455 ;; Also accepts Space to mean yes, or Delete to mean no. (Actually, it uses
456 ;; the bindings in `query-replace-map'; see the documentation of that variable
457 ;; for more information. In this case, the useful bindings are `act', `skip',
458 ;; `recenter', and `quit'.)
460 ;; Under a windowing system a dialog box will be used if `last-nonmenu-event'
461 ;; is nil and `use-dialog-box' is non-nil."
462 ;; ;; FIXME: This needs to be redone when the ECHO AREA works.
463 ;; (string-equal "y" (read-from-minibuffer (concatenate 'string prompt "(y on n)"))))
465 (provide :lice-0.1/minibuffer)