[lice @ simulate interrupt key when waiting for input]
[lice.git] / subr.lisp
blob30d05c6b2c72aedefd25bb987123f8e79ffc82c7
1 ;;; subr.lice --- basic lisp subroutines for Emacs
3 (in-package :lice)
5 (defun split-string (string &optional (separators "
6 "))
7 "Splits STRING into substrings where there are matches for SEPARATORS.
8 Each match for SEPARATORS is a splitting point.
9 The substrings between the splitting points are made into a list
10 which is returned.
11 ***If SEPARATORS is absent, it defaults to \"[ \f\t\n\r\v]+\".
13 If there is match for SEPARATORS at the beginning of STRING, we do not
14 include a null substring for that. Likewise, if there is a match
15 at the end of STRING, we don't include a null substring for that.
17 Modifies the match data; use `save-match-data' if necessary."
18 ;; FIXME: This let is here because movitz doesn't 'lend optional'
19 (let ((seps separators))
20 (labels ((sep (c)
21 (find c seps :test #'char=)))
22 (loop for i = (position-if (complement #'sep) string)
23 then (position-if (complement #'sep) string :start j)
24 while i
25 as j = (position-if #'sep string :start i)
26 collect (subseq string i j)
27 while j))))
29 (define-condition kbd-parse (lice-condition)
30 () (:documentation "Raised when a kbd string failed to parse."))
32 (defun parse-mods (mods end)
33 "MODS is a sequence of <MOD CHAR> #\- pairs. Return a list suitable
34 for passing as the last argument to (apply #'make-key ...)"
35 (unless (evenp end)
36 (signal 'kbd-parse))
37 (apply #'nconc (loop for i from 0 below end by 2
38 if (char/= (char mods (1+ i)) #\-)
39 do (signal 'kbd-parse)
40 collect (case (char mods i)
41 (#\M (list :meta t))
42 (#\A (list :alt t))
43 (#\C (list :control t))
44 (#\H (list :hyper t))
45 (#\s (list :super t))
46 (#\S (list :shift t))
47 (t (signal 'kbd-parse))))))
49 (defun parse-char-name (string)
50 "Return the character whose name is STRING."
51 (or (name-char string)
52 (and (= (length string) 1)
53 (char string 0))))
55 (defun parse-key (string)
56 "Parse STRING and return a key structure."
57 ;; FIXME: we want to return NIL when we get a kbd-parse error
58 ;;(ignore-errors
59 (let* ((p (when (> (length string) 2)
60 (position #\- string :from-end t :end (- (length string) 1))))
61 (mods (parse-mods string (if p (1+ p) 0)))
62 (ch (parse-char-name (subseq string (if p (1+ p) 0)))))
63 (and ch
64 (apply #'make-instance 'key :char ch mods))))
66 (defun parse-key-seq (keys)
67 "KEYS is a key sequence. Parse it and return the list of keys."
68 (mapcar 'parse-key (split-string keys)))
70 (defun kbd (keys)
71 "Convert KEYS to the internal Emacs key representation.
72 KEYS should be a string constant in the format used for
73 saving keyboard macros ***(see `insert-kbd-macro')."
74 ;; XXX: define-key needs to be fixed to handle a list of keys
75 (first (parse-key-seq keys)))
78 ;;; Argument types
80 (defun interactive (&rest prompts)
81 "Read input from the minibuffer and return it in a list."
82 (loop for p in prompts
83 collect (read-from-minibuffer p)))
85 (defvar *extended-command-history* nil)
87 (defun read-command (prompt)
88 "Read the name of a command and return as a symbol.
89 Prompt with prompt. By default, return default-value."
90 (let (cmds)
91 (maphash (lambda (k v)
92 (declare (ignore v))
93 (push k cmds))
94 *commands*)
95 (dformat +debug-v+ "commands: ~s~%" cmds)
96 ;; Sadly, a cheap hack
97 (find (completing-read prompt cmds :history '*extended-command-history*)
98 cmds :test #'string-equal :key #'symbol-name)))
100 (defun read-buffer (prompt &optional def require-match)
101 "Read the name of a buffer and return as a string.
102 Prompt with prompt.
103 Optional second arg def is value to return if user enters an empty line.
104 *If optional third arg require-match is non-nil,
105 * only existing buffer names are allowed."
106 (declare (ignore require-match))
107 (let* ((bufs (mapcar (lambda (b)
108 (cons (buffer-name b) b))
109 *buffer-list*))
110 (b (completing-read (if def
111 (format nil "~a(default ~a) " prompt def)
112 prompt)
113 bufs)))
114 (if (zerop (length b))
116 b)))
118 (defun read-file-name (prompt &key dir default-filename mustmatch initial predicate)
119 "Read file name, prompting with prompt and completing in directory dir.
120 Value is not expanded---you must call `expand-file-name' yourself.
121 Default name to default-filename if user exits the minibuffer with
122 the same non-empty string that was inserted by this function.
123 (If default-filename is omitted, the visited file name is used,
124 except that if initial is specified, that combined with dir is used.)
125 If the user exits with an empty minibuffer, this function returns
126 an empty string. (This can only happen if the user erased the
127 pre-inserted contents or if `insert-default-directory' is nil.)
128 Fourth arg mustmatch non-nil means require existing file's name.
129 Non-nil and non-t means also require confirmation after completion.
130 Fifth arg initial specifies text to start with.
131 If optional sixth arg predicate is non-nil, possible completions and
132 the resulting file name must satisfy (funcall predicate NAME).
133 dir should be an absolute directory name. It defaults to the value of
134 `:default-directory'.
136 If this command was invoked with the mouse, use a file dialog box if
137 `use-dialog-box' is non-nil, and the window system or X toolkit in use
138 provides a file dialog box.
140 See also `read-file-name-completion-ignore-case'
141 and `read-file-name-function'."
142 (declare (ignore predicate initial mustmatch default-filename dir))
143 (completing-read prompt #'file-completions :initial-input (princ-to-string (buffer-local :default-directory))))
145 (defun read-string (prompt &optional initial-input history default-value)
146 "Read a string from the minibuffer, prompting with string prompt.
147 If non-nil, second arg initial-input is a string to insert before reading.
148 This argument has been superseded by default-value and should normally
149 be nil in new code. It behaves as in `read-from-minibuffer'. See the
150 documentation string of that function for details.
151 The third arg history, if non-nil, specifies a history list
152 and optionally the initial position in the list.
153 See `read-from-minibuffer' for details of history argument.
154 Fourth arg default-value is the default value. If non-nil, it is used
155 for history commands, and as the value to return if the user enters
156 the empty string.
157 **Fifth arg inherit-input-method, if non-nil, means the minibuffer inherits
158 the current input method and the setting of `enable-multibyte-characters'."
159 (read-from-minibuffer prompt :initial-contents initial-input :history history :default-value default-value))
161 (defun region-limit (beginningp)
162 "Return the start or end position of the region.
163 BEGINNINGP non-zero means return the start.
164 If there is no region active, signal an error."
165 (if beginningp
166 (min (point) (mark))
167 (max (point) (mark))))
169 (defun region-beginning ()
170 "Return position of beginning of region, as an integer."
171 (region-limit t))
173 (defun region-end ()
174 "Return position of end of region, as an integer."
175 (region-limit nil))
177 (defun add-command-arg-type (type fn)
178 "TYPE is a symbol. Add it to the hash table of command types and link it to FN, a function or function symbol."
179 (setf (gethash type *command-arg-type-hash*) fn))
181 (defun init-command-arg-types ()
182 "populate the hash table with some defaults"
183 ;; Reset the hash table. FIXME: should we do this?
184 (setf *command-arg-type-hash* (make-hash-table))
185 (add-command-arg-type :buffer 'read-buffer)
186 (add-command-arg-type :file 'read-file-name)
187 (add-command-arg-type :string 'read-from-minibuffer)
188 (add-command-arg-type :command 'read-command)
189 (add-command-arg-type :prefix 'prefix-arg)
190 (add-command-arg-type :raw-prefix 'raw-prefix-arg)
191 (add-command-arg-type :region-beginning 'region-beginning)
192 (add-command-arg-type :region-end 'region-end))
194 (defun get-buffer-window-list (buffer &optional minibuf frame)
195 "Return list of all windows displaying BUFFER, or nil if none.
196 BUFFER can be a buffer or a buffer name.
197 See `walk-windows' for the meaning of MINIBUF and FRAME."
198 (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows)
199 (mapc (lambda (window)
200 (if (eq (window-buffer window) buffer)
201 (push window windows)))
202 (frame-window-list frame minibuf))
203 windows))
205 ;; FIXME: this isn't complete.
206 (defmacro defalias (from-symbol to-symbol)
207 "Set symbol's function definition to definition, and return definition."
208 `(define-symbol-macro ,from-symbol ,to-symbol))
210 (defun intern-soft (name &optional (package *package*))
211 (find-symbol name package))
213 (defcommand eval-region ((start end &optional print-flag (read-function 'read-from-string))
214 :region-beginning :region-end)
215 "Execute the region as Lisp code.
216 When called from programs, expects two arguments,
217 giving starting and ending indices in the current buffer
218 of the text to be executed.
219 Programs can pass third argument PRINTFLAG which controls output:
220 A value of nil means discard it; anything else is stream for printing it.
221 Also the fourth argument READ-FUNCTION, if non-nil, is used
222 instead of `read' to read each expression. It gets one argument
223 which is the input stream for reading characters.
225 This function does not move point."
226 (let* ((stdout (make-string-output-stream))
227 (*standard-output* stdout)
228 (*standard-error* stdout)
229 (*debug-io* stdout)
230 (string (buffer-substring-no-properties start end))
231 (pos 0)
232 last obj)
233 (loop
234 (setf last obj)
235 (multiple-value-setq (obj pos) (funcall read-function string nil string :start pos))
236 (when (eq obj string)
237 (cond ((eq print-flag t)
238 (message "~s" last)))
239 (return-from eval-region last)))))
241 (provide :lice-0.1/subr)