[lice @ get doctor working. fix line-end-position. fix move-to-left-margin.]
[lice.git] / subr.lisp
blobce22ac5078d123f9df8252a5050102257ee91f63
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 (cond
52 ((string= string "RET") #\Newline)
53 ((string= string "TAB") #\Tab))
54 (name-char string)
55 (and (= (length string) 1)
56 (char string 0))))
58 (defun parse-key (string)
59 "Parse STRING and return a key structure."
60 ;; FIXME: we want to return NIL when we get a kbd-parse error
61 ;;(ignore-errors
62 (let* ((p (when (> (length string) 2)
63 (position #\- string :from-end t :end (- (length string) 1))))
64 (mods (parse-mods string (if p (1+ p) 0)))
65 (ch (parse-char-name (subseq string (if p (1+ p) 0)))))
66 (and ch
67 (apply #'make-key :char ch mods))))
69 (defun parse-key-seq (keys)
70 "KEYS is a key sequence. Parse it and return the list of keys."
71 (mapcar 'parse-key (split-string keys)))
73 (defun kbd (keys)
74 "Convert KEYS to the internal Emacs key representation.
75 KEYS should be a string constant in the format used for
76 saving keyboard macros ***(see `insert-kbd-macro')."
77 ;; XXX: define-key needs to be fixed to handle a list of keys
78 (first (parse-key-seq keys)))
81 ;;; Argument types
83 (defun interactive (&rest prompts)
84 "Read input from the minibuffer and return it in a list."
85 (loop for p in prompts
86 collect (read-from-minibuffer p)))
88 (defvar *extended-command-history* nil)
90 (defun read-command (prompt)
91 "Read the name of a command and return as a symbol.
92 Prompt with prompt. By default, return default-value."
93 (let (cmds)
94 (maphash (lambda (k v)
95 (declare (ignore v))
96 (push k cmds))
97 *commands*)
98 (dformat +debug-v+ "commands: ~s~%" cmds)
99 ;; Sadly, a cheap hack
100 (find (completing-read prompt cmds :history '*extended-command-history*)
101 cmds :test #'string-equal :key #'symbol-name)))
103 (defun read-buffer (prompt &optional def require-match)
104 "Read the name of a buffer and return as a string.
105 Prompt with prompt.
106 Optional second arg def is value to return if user enters an empty line.
107 *If optional third arg require-match is non-nil,
108 * only existing buffer names are allowed."
109 (declare (ignore require-match))
110 (let* ((bufs (mapcar (lambda (b)
111 (cons (buffer-name b) b))
112 *buffer-list*))
113 (b (completing-read (if def
114 (format nil "~a(default ~a) " prompt def)
115 prompt)
116 bufs)))
117 (if (zerop (length b))
119 b)))
121 (defun read-file-name (prompt &key dir default-filename mustmatch initial predicate)
122 "Read file name, prompting with prompt and completing in directory dir.
123 Value is not expanded---you must call `expand-file-name' yourself.
124 Default name to default-filename if user exits the minibuffer with
125 the same non-empty string that was inserted by this function.
126 (If default-filename is omitted, the visited file name is used,
127 except that if initial is specified, that combined with dir is used.)
128 If the user exits with an empty minibuffer, this function returns
129 an empty string. (This can only happen if the user erased the
130 pre-inserted contents or if `insert-default-directory' is nil.)
131 Fourth arg mustmatch non-nil means require existing file's name.
132 Non-nil and non-t means also require confirmation after completion.
133 Fifth arg initial specifies text to start with.
134 If optional sixth arg predicate is non-nil, possible completions and
135 the resulting file name must satisfy (funcall predicate NAME).
136 dir should be an absolute directory name. It defaults to the value of
137 `:default-directory'.
139 If this command was invoked with the mouse, use a file dialog box if
140 `use-dialog-box' is non-nil, and the window system or X toolkit in use
141 provides a file dialog box.
143 See also `read-file-name-completion-ignore-case'
144 and `read-file-name-function'."
145 (declare (ignore predicate initial mustmatch default-filename dir))
146 (completing-read prompt #'file-completions :initial-input (princ-to-string *default-directory*)))
148 (defun read-string (prompt &optional initial-input history default-value)
149 "Read a string from the minibuffer, prompting with string prompt.
150 If non-nil, second arg initial-input is a string to insert before reading.
151 This argument has been superseded by default-value and should normally
152 be nil in new code. It behaves as in `read-from-minibuffer'. See the
153 documentation string of that function for details.
154 The third arg history, if non-nil, specifies a history list
155 and optionally the initial position in the list.
156 See `read-from-minibuffer' for details of history argument.
157 Fourth arg default-value is the default value. If non-nil, it is used
158 for history commands, and as the value to return if the user enters
159 the empty string.
160 **Fifth arg inherit-input-method, if non-nil, means the minibuffer inherits
161 the current input method and the setting of `enable-multibyte-characters'."
162 (read-from-minibuffer prompt :initial-contents initial-input :history history :default-value default-value))
164 (defun region-limit (beginningp)
165 "Return the start or end position of the region.
166 BEGINNINGP non-zero means return the start.
167 If there is no region active, signal an error."
168 (if beginningp
169 (min (point) (mark))
170 (max (point) (mark))))
172 (defun region-beginning ()
173 "Return position of beginning of region, as an integer."
174 (region-limit t))
176 (defun region-end ()
177 "Return position of end of region, as an integer."
178 (region-limit nil))
180 (defun add-command-arg-type (type fn)
181 "TYPE is a symbol. Add it to the hash table of command types and link it to FN, a function or function symbol."
182 (setf (gethash type *command-arg-type-hash*) fn))
184 (defun init-command-arg-types ()
185 "populate the hash table with some defaults"
186 ;; Reset the hash table. FIXME: should we do this?
187 (setf *command-arg-type-hash* (make-hash-table))
188 (add-command-arg-type :buffer 'read-buffer)
189 (add-command-arg-type :file 'read-file-name)
190 (add-command-arg-type :string 'read-from-minibuffer)
191 (add-command-arg-type :command 'read-command)
192 (add-command-arg-type :prefix 'prefix-arg)
193 (add-command-arg-type :raw-prefix 'raw-prefix-arg)
194 (add-command-arg-type :region-beginning 'region-beginning)
195 (add-command-arg-type :region-end 'region-end))
197 (defun get-buffer-window-list (buffer &optional minibuf frame)
198 "Return list of all windows displaying BUFFER, or nil if none.
199 BUFFER can be a buffer or a buffer name.
200 See `walk-windows' for the meaning of MINIBUF and FRAME."
201 (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows)
202 (mapc (lambda (window)
203 (if (eq (window-buffer window) buffer)
204 (push window windows)))
205 (frame-window-list frame minibuf))
206 windows))
208 ;; FIXME: this isn't complete.
209 (defmacro defalias (from-symbol to-symbol)
210 "Set symbol's function definition to definition, and return definition."
211 `(define-symbol-macro ,from-symbol ,to-symbol))
213 (defun intern-soft (name &optional (package *package*))
214 (find-symbol name package))
216 (defcommand eval-region ((start end &optional print-flag (read-function 'read-from-string))
217 :region-beginning :region-end)
218 "Execute the region as Lisp code.
219 When called from programs, expects two arguments,
220 giving starting and ending indices in the current buffer
221 of the text to be executed.
222 Programs can pass third argument PRINTFLAG which controls output:
223 A value of nil means discard it; anything else is stream for printing it.
224 Also the fourth argument READ-FUNCTION, if non-nil, is used
225 instead of `read' to read each expression. It gets one argument
226 which is the input stream for reading characters.
228 This function does not move point."
229 (let* ((stdout (make-string-output-stream))
230 (*standard-output* stdout)
231 (*error-output* stdout)
232 (*debug-io* stdout)
233 (string (buffer-substring-no-properties start end))
234 (pos 0)
235 last obj)
236 (loop
237 (setf last obj)
238 (multiple-value-setq (obj pos) (funcall read-function string nil string :start pos))
239 (when (eq obj string)
240 (cond ((eq print-flag t)
241 (message "~s" last)))
242 (return-from eval-region last)))))
244 (provide :lice-0.1/subr)