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