1 ;;; --------------------------------------------------------------------------
2 ;;; CLFSWM - FullScreen Window Manager
4 ;;; --------------------------------------------------------------------------
5 ;;; Documentation: Query utility
6 ;;; --------------------------------------------------------------------------
8 ;;; (C) 2011 Philippe Brochard <hocwp@free.fr>
10 ;;; This program is free software; you can redistribute it and/or modify
11 ;;; it under the terms of the GNU General Public License as published by
12 ;;; the Free Software Foundation; either version 3 of the License, or
13 ;;; (at your option) any later version.
15 ;;; This program is distributed in the hope that it will be useful,
16 ;;; but WITHOUT ANY WARRANTY; without even the implied warranty of
17 ;;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 ;;; GNU General Public License for more details.
20 ;;; You should have received a copy of the GNU General Public License
21 ;;; along with this program; if not, write to the Free Software
22 ;;; Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
24 ;;; --------------------------------------------------------------------------
29 (defparameter *query-window
* nil
)
30 (defparameter *query-font
* nil
)
31 (defparameter *query-gc
* nil
)
33 (defparameter *query-history
* (list ""))
34 (defparameter *query-complet-list
* nil
)
36 (defparameter *query-message
* nil
)
37 (defparameter *query-string
* nil
)
38 (defparameter *query-pos
* nil
)
39 (defparameter *query-return
* nil
)
43 (defun query-show-paren (orig-string pos dec
)
44 "Replace matching parentheses with brackets"
45 (let ((string (copy-seq orig-string
)))
46 (labels ((have-to-find-right?
()
47 (and (< pos
(length string
)) (char= (aref string pos
) #\
()))
48 (have-to-find-left?
()
49 (and (> (1- pos
) 0) (char= (aref string
(1- pos
)) #\
))))
51 (loop :for p
:from
(1+ pos
) :below
(length string
)
52 :with level
= 1 :for c
= (aref string p
)
53 :do
(when (char= c
#\
() (incf level
))
54 (when (char= c
#\
)) (decf level
))
55 (when (= level
0) (return p
))))
57 (loop :for p
:from
(- pos
2) :downto
0
58 :with level
= 1 :for c
= (aref string p
)
59 :do
(when (char= c
#\
() (decf level
))
60 (when (char= c
#\
)) (incf level
))
61 (when (= level
0) (return p
))))
62 (draw-bloc (p &optional
(color *query-parent-color
*))
63 (setf (xlib:gcontext-foreground
*query-gc
*) (get-color color
))
64 (xlib:draw-rectangle
*pixmap-buffer
* *query-gc
*
65 (+ 10 (* p
(xlib:max-char-width
*query-font
*)) dec
)
66 (+ (xlib:max-char-ascent
*query-font
*) (xlib:max-char-descent
*query-font
*) 7)
67 (xlib:max-char-width
*query-font
*)
68 (+ (xlib:max-char-ascent
*query-font
*) (xlib:max-char-descent
*query-font
*))
70 (cond ((have-to-find-left?
) (let ((p (pos-left)))
72 (progn (draw-bloc p
) (draw-bloc (1- pos
)))
73 (draw-bloc (1- pos
) *query-parent-error-color
*))))
74 ((have-to-find-right?
) (let ((p (pos-right)))
76 (progn (draw-bloc p
) (draw-bloc pos
))
77 (draw-bloc pos
*query-parent-error-color
*))))))))
80 (defun clear-query-history ()
81 "Clear the query-string history"
82 (setf *query-history
* (list "")))
86 (defun leave-query-mode (&optional
(return :Escape
))
87 "Leave the query mode"
88 (setf *query-return
* return
)
89 (throw 'exit-query-loop nil
))
92 (defun leave-query-mode-valid ()
93 (leave-query-mode :Return
))
95 (add-hook *binding-hook
* 'init-
*query-keys
*)
98 (defun query-find-complet-list ()
99 (remove-if-not (lambda (x)
100 (zerop (or (search *query-string
* x
:test
#'string-equal
) -
1)))
101 *query-complet-list
*))
104 (defun query-print-string ()
105 (let ((dec (min 0 (- (- (x-drawable-width *query-window
*) 10)
106 (+ 10 (* *query-pos
* (xlib:max-char-width
*query-font
*)))))))
107 (clear-pixmap-buffer *query-window
* *query-gc
*)
108 (setf (xlib:gcontext-foreground
*query-gc
*) (get-color *query-message-color
*))
109 (xlib:draw-glyphs
*pixmap-buffer
* *query-gc
* 5 (+ (xlib:max-char-ascent
*query-font
*) 5)
110 (format nil
"~A ~{~A~^, ~}" *query-message
*
111 (query-find-complet-list)))
112 (when (< *query-pos
* 0)
113 (setf *query-pos
* 0))
114 (when (> *query-pos
* (length *query-string
*))
115 (setf *query-pos
* (length *query-string
*)))
116 (query-show-paren *query-string
* *query-pos
* dec
)
117 (setf (xlib:gcontext-foreground
*query-gc
*) (get-color *query-foreground
*))
118 (xlib:draw-glyphs
*pixmap-buffer
* *query-gc
*
120 (+ (* 2 (+ (xlib:max-char-ascent
*query-font
*) (xlib:max-char-descent
*query-font
*))) 5)
122 (setf (xlib:gcontext-foreground
*query-gc
*) (get-color *query-cursor-color
*))
123 (xlib:draw-line
*pixmap-buffer
* *query-gc
*
124 (+ 10 (* *query-pos
* (xlib:max-char-width
*query-font
*)) dec
)
125 (+ (* 2 (+ (xlib:max-char-ascent
*query-font
*) (xlib:max-char-descent
*query-font
*))) 6)
126 (+ 10 (* *query-pos
* (xlib:max-char-width
*query-font
*)) dec
)
127 (+ (* 1 (+ (xlib:max-char-ascent
*query-font
*) (xlib:max-char-descent
*query-font
*))) 7))
128 (copy-pixmap-buffer *query-window
* *query-gc
*)))
132 (defun query-enter-function ()
133 (setf *query-font
* (xlib:open-font
*display
* *query-font-string
*))
134 (let ((width (- (xlib:screen-width
*screen
*) 2))
135 (height (* 3 (+ (xlib:max-char-ascent
*query-font
*) (xlib:max-char-descent
*query-font
*)))))
136 (with-placement (*query-mode-placement
* x y width height
)
137 (setf *query-window
* (xlib:create-window
:parent
*root
*
141 :background
(get-color *query-background
*)
142 :border-width
*border-size
*
143 :border
(get-color *query-border
*)
144 :colormap
(xlib:screen-default-colormap
*screen
*)
145 :event-mask
'(:exposure
:key-press
))
146 *query-gc
* (xlib:create-gcontext
:drawable
*query-window
*
147 :foreground
(get-color *query-foreground
*)
148 :background
(get-color *query-background
*)
151 (setf (window-transparency *query-window
*) *query-transparency
*)
152 (map-window *query-window
*)
154 (wait-no-key-or-button-press))))
158 (defun query-leave-function ()
159 (xlib:destroy-window
*query-window
*)
160 (xlib:close-font
*query-font
*)
161 (wait-no-key-or-button-press))
163 (defun query-loop-function ()
164 (raise-window *query-window
*))
168 (labels ((generic-backspace (del-pos)
170 (setf *query-string
* (concatenate 'string
171 (subseq *query-string
* 0 del-pos
)
172 (subseq *query-string
* *query-pos
*))
173 *query-pos
* del-pos
))))
174 (defun query-backspace ()
175 "Delete a character backward"
176 (generic-backspace (1- *query-pos
*)))
178 (defun query-backspace-word ()
179 "Delete a word backward"
180 (generic-backspace (or (position #\Space
*query-string
* :from-end t
:end
*query-pos
*) 0))))
183 (labels ((generic-delete (del-pos)
184 (when (<= del-pos
(length *query-string
*))
185 (setf *query-string
* (concatenate 'string
186 (subseq *query-string
* 0 *query-pos
*)
187 (subseq *query-string
* del-pos
))))))
188 (defun query-delete ()
189 "Delete a character forward"
190 (generic-delete (1+ *query-pos
*)))
192 (defun query-delete-word ()
193 "Delete a word forward"
194 (generic-delete (1+ (or (position #\Space
*query-string
* :start
*query-pos
*)
195 (1- (length *query-string
*)))))))
200 "Move cursor to line begining"
201 (setf *query-pos
* 0))
204 "Move cursor to line end"
205 (setf *query-pos
* (length *query-string
*)))
209 "Move cursor to left"
210 (when (> *query-pos
* 0)
211 (setf *query-pos
* (1- *query-pos
*))))
213 (defun query-left-word ()
214 "Move cursor to left word"
215 (when (> *query-pos
* 0)
216 (setf *query-pos
* (let ((p (position #\Space
*query-string
*
217 :end
(min (1- *query-pos
*) (length *query-string
*))
221 (defun query-right ()
222 "Move cursor to right"
223 (when (< *query-pos
* (length *query-string
*))
224 (setf *query-pos
* (1+ *query-pos
*))))
226 (defun query-right-word ()
227 "Move cursor to right word"
228 (when (< *query-pos
* (length *query-string
*))
229 (setf *query-pos
* (let ((p (position #\Space
*query-string
*
230 :start
(min (1+ *query-pos
*) (length *query-string
*)))))
231 (if p p
(length *query-string
*))))))
233 (defun query-previous-history ()
234 "Circulate backward in history"
235 (setf *query-string
* (first *query-history
*)
236 *query-pos
* (length *query-string
*)
237 *query-history
* (rotate-list *query-history
*)))
240 (defun query-next-history ()
241 "Circulate forward in history"
242 (setf *query-string
* (first *query-history
*)
243 *query-pos
* (length *query-string
*)
244 *query-history
* (anti-rotate-list *query-history
*)))
248 (defun query-delete-eof ()
249 "Delete the end of the line"
250 (setf *query-string
* (subseq *query-string
* 0 *query-pos
*)))
253 (defun query-mode-complet ()
254 (setf *query-string
* (find-common-string *query-string
* (query-find-complet-list)))
255 (let ((complet (query-find-complet-list)))
256 (when (= (length complet
) 1)
257 (setf *query-string
* (first complet
))))
262 (add-hook *binding-hook
* 'set-default-query-keys
)
264 (defun set-default-query-keys ()
265 (define-query-key ("Return") 'leave-query-mode-valid
)
266 (define-query-key ("Escape") 'leave-query-mode
)
267 (define-query-key ("g" :control
) 'leave-query-mode
)
268 (define-query-key ("Tab") 'query-mode-complet
)
269 (define-query-key ("BackSpace") 'query-backspace
)
270 (define-query-key ("BackSpace" :control
) 'query-backspace-word
)
271 (define-query-key ("Delete") 'query-delete
)
272 (define-query-key ("Delete" :control
) 'query-delete-word
)
273 (define-query-key ("Home") 'query-home
)
274 (define-query-key ("End") 'query-end
)
275 (define-query-key ("Left") 'query-left
)
276 (define-query-key ("Left" :control
) 'query-left-word
)
277 (define-query-key ("Right") 'query-right
)
278 (define-query-key ("Right" :control
) 'query-right-word
)
279 (define-query-key ("Up") 'query-previous-history
)
280 (define-query-key ("Down") 'query-next-history
)
281 (define-query-key ("k" :control
) 'query-delete-eof
))
285 (defun add-in-query-string (code state
)
286 (let* ((modifiers (state->modifiers state
))
287 (keysym (keycode->keysym code modifiers
))
288 (char (xlib:keysym-
>character
*display
* keysym state
)))
289 (when (and char
(characterp char
))
290 (setf *query-string
* (concatenate 'string
291 (when (<= *query-pos
* (length *query-string
*))
292 (subseq *query-string
* 0 *query-pos
*))
294 (when (< *query-pos
* (length *query-string
*))
295 (subseq *query-string
* *query-pos
*))))
296 (incf *query-pos
*))))
300 (define-handler query-mode
:key-press
(code state
)
301 (unless (funcall-key-from-code *query-keys
* code state
)
302 (add-in-query-string code state
))
303 (query-print-string))
307 (defun query-string (message &optional
(default "") complet-list
)
308 "Query a string from the keyboard. Display msg as prompt"
309 (let ((grab-keyboard-p (xgrab-keyboard-p))
310 (grab-pointer-p (xgrab-pointer-p)))
311 (setf *query-message
* message
312 *query-string
* default
313 *query-pos
* (length default
)
314 *query-complet-list
* complet-list
)
315 (xgrab-pointer *root
* 92 93)
316 (unless grab-keyboard-p
318 (xgrab-keyboard *root
*))
319 (generic-mode 'query-mode
'exit-query-loop
320 :enter-function
#'query-enter-function
321 :loop-function
#'query-loop-function
322 :leave-function
#'query-leave-function
323 :original-mode
'(main-mode))
324 (unless grab-keyboard-p
328 (xgrab-pointer *root
* 66 67)
330 (when (equal *query-return
* :Return
)
331 (pushnew default
*query-history
* :test
#'equal
)
332 (push *query-string
* *query-history
*))
333 (values *query-string
*
338 (defun query-number (msg &optional
(default 0))
339 "Query a number from the query input"
340 (multiple-value-bind (string return
)
341 (query-string msg
(format nil
"~A" default
))
342 (if (equal return
:Return
)
343 (or (parse-integer (or string
"") :junk-allowed t
) default
)