[lice @ initial input]
[lice.git] / subr.lisp
blob4b95eedc038e654702e87816d97b67e6efa3cf1b
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 (defun read-command (prompt)
86 "Read the name of a command and return as a symbol.
87 Prompt with prompt. By default, return default-value."
88 (let (cmds)
89 (maphash (lambda (k v)
90 (declare (ignore v))
91 (push k cmds))
92 *commands*)
93 (dformat +debug-v+ "commands: ~s~%" cmds)
94 ;; Sadly, a cheap hack
95 (find (completing-read prompt cmds) cmds :test #'string-equal :key #'symbol-name)))
97 (defun read-buffer (prompt &optional def require-match)
98 "Read the name of a buffer and return as a string.
99 Prompt with prompt.
100 Optional second arg def is value to return if user enters an empty line.
101 *If optional third arg require-match is non-nil,
102 * only existing buffer names are allowed."
103 (declare (ignore require-match))
104 (let* ((bufs (mapcar (lambda (b)
105 (cons (buffer-name b) b))
106 *buffer-list*))
107 (b (completing-read (if def
108 (format nil "~a(default ~a) " prompt def)
109 prompt)
110 bufs)))
111 (if (zerop (length b))
113 b)))
115 (defun read-file-name (prompt &key dir default-filename mustmatch initial predicate)
116 "Read file name, prompting with prompt and completing in directory dir.
117 Value is not expanded---you must call `expand-file-name' yourself.
118 Default name to default-filename if user exits the minibuffer with
119 the same non-empty string that was inserted by this function.
120 (If default-filename is omitted, the visited file name is used,
121 except that if initial is specified, that combined with dir is used.)
122 If the user exits with an empty minibuffer, this function returns
123 an empty string. (This can only happen if the user erased the
124 pre-inserted contents or if `insert-default-directory' is nil.)
125 Fourth arg mustmatch non-nil means require existing file's name.
126 Non-nil and non-t means also require confirmation after completion.
127 Fifth arg initial specifies text to start with.
128 If optional sixth arg predicate is non-nil, possible completions and
129 the resulting file name must satisfy (funcall predicate NAME).
130 dir should be an absolute directory name. It defaults to the value of
131 `default-directory'.
133 If this command was invoked with the mouse, use a file dialog box if
134 `use-dialog-box' is non-nil, and the window system or X toolkit in use
135 provides a file dialog box.
137 See also `read-file-name-completion-ignore-case'
138 and `read-file-name-function'."
139 (declare (ignore predicate initial mustmatch default-filename dir))
140 (completing-read prompt #'file-completions :initial-input (princ-to-string *default-directory*)))
142 (defun region-limit (beginningp)
143 "Return the start or end position of the region.
144 BEGINNINGP non-zero means return the start.
145 If there is no region active, signal an error."
146 (if (and (< (point) (mark))
147 beginningp)
148 (point)
149 (mark)))
151 (defun region-beginning ()
152 "Return position of beginning of region, as an integer."
153 (region-limit t))
155 (defun region-end ()
156 "Return position of end of region, as an integer."
157 (region-limit nil))
159 (defun add-command-arg-type (type fn)
160 "TYPE is a symbol. Add it to the hash table of command types and link it to FN, a function or function symbol."
161 (setf (gethash type *command-arg-type-hash*) fn))
163 (defun init-command-arg-types ()
164 "populate the hash table with some defaults"
165 ;; Reset the hash table. FIXME: should we do this?
166 (setf *command-arg-type-hash* (make-hash-table))
167 (add-command-arg-type :buffer 'read-buffer)
168 (add-command-arg-type :file 'read-file-name)
169 (add-command-arg-type :string 'read-from-minibuffer)
170 (add-command-arg-type :command 'read-command)
171 (add-command-arg-type :prefix 'prefix-arg)
172 (add-command-arg-type :raw-prefix 'raw-prefix-arg)
173 (add-command-arg-type :region-beginning 'region-beginning)
174 (add-command-arg-type :region-end 'region-end))
176 (defun get-buffer-window-list (buffer &optional minibuf frame)
177 "Return list of all windows displaying BUFFER, or nil if none.
178 BUFFER can be a buffer or a buffer name.
179 See `walk-windows' for the meaning of MINIBUF and FRAME."
180 (let ((buffer (if (bufferp buffer) buffer (get-buffer buffer))) windows)
181 (mapc (lambda (window)
182 (if (eq (window-buffer window) buffer)
183 (push window windows)))
184 (frame-window-list frame minibuf))
185 windows))
187 (provide :lice-0.1/subr)