]> code.delx.au - gnu-emacs/blob - lisp/emacs-lisp/re-builder.el
*** empty log message ***
[gnu-emacs] / lisp / emacs-lisp / re-builder.el
1 ;;; re-builder.el --- Building Regexps with visual feedback
2
3 ;; Copyright (C) 1999, 2000 Free Software Foundation, Inc.
4
5 ;; Author: Detlev Zundel <dzu@gnu.org>
6 ;; Keywords: matching, lisp, tools
7
8 ;; This file is part of GNU Emacs.
9
10 ;; GNU Emacs 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 2, or (at your option)
13 ;; any later version.
14
15 ;; GNU Emacs 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.
19
20 ;; You should have received a copy of the GNU General Public License
21 ;; along with GNU Emacs; see the file COPYING. If not, write to the
22 ;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
23 ;; Boston, MA 02111-1307, USA.
24
25 ;;; Commentary:
26
27 ;; $Id: re-builder.el,v 1.3 2000/01/25 23:42:24 dzu Exp $
28
29 ;; When I have to come up with regular expressions that are more
30 ;; complex than simple string matchers, especially if they contain sub
31 ;; expressions, I find myself spending quite some time in the
32 ;; `development cycle'. `re-builder' aims to shorten this time span
33 ;; so I can get on with the more interesting bits.
34
35 ;; With it you can have immediate visual feedback about how well the
36 ;; regexp behaves to your expectations on the intended data.
37
38 ;; When called up `re-builder' attaches itself to the current buffer
39 ;; which becomes its target buffer, where all the matching is done.
40 ;; The active window is split so you have a view on the data while
41 ;; authoring the RE. If the edited expression is valid the matches in
42 ;; the target buffer are marked automatically with colored overlays
43 ;; (for non-color displays see below) giving you feedback over the
44 ;; extents of the matched (sub) expressions. The (non-)validity is
45 ;; shown only in the modeline without throwing the errors at you. If
46 ;; you want to know the reason why RE Builder considers it as invalid
47 ;; call `reb-force-update' ("\C-c\C-u") which should reveal the error.
48
49 ;; The `re-builder' keeps the focus while updating the matches in the
50 ;; target buffer so corrections are easy to incorporate. If you are
51 ;; satisfied with the result you can paste the RE to the kill-ring
52 ;; with `reb-copy' ("\C-c\C-w"), quit the `re-builder' ("\C-c\C-q")
53 ;; and use it wherever you need it.
54
55 ;; As the automatic updates can take some time on large buffers, they
56 ;; can be limited by `reb-auto-match-limit' so that they should not
57 ;; have a negative impact on the editing. Setting it to nil makes
58 ;; even the auto updates go all the way. Forcing an update overrides
59 ;; this limit allowing an easy way to see all matches.
60
61 ;; Currently `re-builder' understands four different forms of input,
62 ;; namely `read', `string', `sregex' and `lisp-re' syntax. Read
63 ;; syntax and string syntax are both delimited by `"'s and behave
64 ;; according to their name. With the `string' syntax there's no need
65 ;; to escape the backslashes and double quotes simplifying the editing
66 ;; somewhat. The other two allow editing of symbolic regular
67 ;; expressions supported by the packages of the same name. (`lisp-re'
68 ;; is a package by me and its support may go away as it is nearly the
69 ;; same as the `sregex' package in Emacs)
70
71 ;; Editing symbolic expressions is done through a major mode derived
72 ;; from `emacs-lisp-mode' so you'll get all the good stuff like
73 ;; automatic indentation and font-locking etc.
74
75 ;; When editing a symbolic regular expression, only the first
76 ;; expression in the RE Builder buffer is considered, which helps
77 ;; limiting the extent of the expression like the `"'s do for the text
78 ;; modes. For the `sregex' syntax the function `sregex' is applied to
79 ;; the evaluated expression read. So you can use quoted arguments
80 ;; with something like '("findme") or you can construct arguments to
81 ;; your hearts delight with a valid ELisp expression. (The compiled
82 ;; string form will be copied by `reb-copy') If you want to take
83 ;; a glance at the corresponding string you can temporarily change the
84 ;; input syntax.
85
86 ;; Changing the input syntax is transparent (for the obvious exception
87 ;; non-symbolic -> symbolic) so you can change your mind as often as
88 ;; you like.
89
90 ;; There is also a shortcut function for toggling the
91 ;; `case-fold-search' variable in the target buffer with an immediate
92 ;; update.
93
94
95 ;; Q: But what if my display cannot show colored overlays?
96 ;; A: Then the cursor will flash around the matched text making it stand
97 ;; out.
98
99 ;; Q: But how can I then make out the sub-expressions?
100 ;; A: Thats where the `sub-expression mode' comes in. In it only the
101 ;; digit keys are assigned to perform an update that will flash the
102 ;; corresponding subexp only.
103
104
105 ;;; History:
106 ;;
107 ;; Changes from Version 1.2:
108 ;; - Fixed a bug preventing normal startup after killing the (previous)
109 ;; target-buffer
110 ;; - Fixed XEmacs support
111 ;;
112 ;; Changes from Version 1.1:
113 ;; - The editing is now done through two major-modes rather than
114 ;; having one minor-mode that behaves exactly like a major-mode
115 ;; - Automatic updates for valid re's simplify the user interface
116 ;; - Easy interface for changing the input syntax and case
117 ;; sensitivity of the target buffer
118 ;; - As nobody reported the bugs that were fixed you probably don't
119 ;; want to know about them...
120
121 ;;; Code:
122
123 ;; On XEmacs, load the overlay compatibility library
124 (if (not (fboundp 'make-overlay))
125 (require 'overlay))
126
127 ;; User costomizable variables
128 (defgroup re-builder nil
129 "Options for the RE Builder."
130 :group 'lisp
131 :prefix "reb-")
132
133 (defcustom reb-blink-delay 0.5
134 "*Seconds to blink cursor for next/previous match in RE Builder."
135 :group 're-builder
136 :type 'number)
137
138 (defcustom reb-mode-hook nil
139 "*Hooks to run on entering RE Builder mode."
140 :group 're-builder
141 :type 'hook)
142
143 (defcustom reb-re-syntax 'read
144 "*Syntax for the REs in the RE Builder.
145 Can either be `read', `string' or `lisp-re'."
146 :group 're-builder
147 :type '(choice (const :tag "Read syntax" read)
148 (const :tag "String syntax" string)
149 (const :tag "`sregex' syntax" sregex)
150 (const :tag "`lisp-re' syntax" lisp-re)
151 (value: sring)))
152
153 (defcustom reb-auto-match-limit 200
154 "*Positive integer limiting the matches for RE Builder auto updates.
155 Set it to nil if you don't want limits here."
156 :group 're-builder
157 :type '(restricted-sexp :match-alternatives
158 (integerp 'nil)))
159
160
161 (defface reb-match-0
162 '((((class color))
163 (:background "lightblue"))
164 (t (:inverse-video t)))
165 "Used for displaying the whole match."
166 :group 're-builder)
167
168 (defface reb-match-1
169 '((((class color))
170 (:background "aquamarine"))
171 (t (:inverse-video t)))
172 "Used for displaying the first matching subexpression."
173 :group 're-builder)
174
175 (defface reb-match-2
176 '((((class color))
177 (:background "springgreen"))
178 (t (:inverse-video t)))
179 "Used for displaying the second matching subexpression."
180 :group 're-builder)
181
182 (defface reb-match-3
183 '((((class color))
184 (:background "yellow"))
185 (t (:inverse-video t)))
186 "Used for displaying the third matching subexpression."
187 :group 're-builder)
188
189 ;; Internal variables below
190 (defvar reb-mode nil
191 "Enables the RE Builder minor mode.")
192
193 (defvar reb-target-buffer nil
194 "Buffer to which the RE is applied to.")
195
196 (defvar reb-target-window nil
197 "Window to which the RE is applied to.")
198
199 (defvar reb-regexp nil
200 "Last regexp used by RE Builder.")
201
202 (defvar reb-regexp-src nil
203 "Last regexp used by RE Builder before processing it.
204 Except for Lisp syntax this is the same as `reb-regexp'.")
205
206 (defvar reb-overlays nil
207 "List of overlays of the RE Builder.")
208
209 (defvar reb-window-config nil
210 "Old window configuration.")
211
212 (defvar reb-subexp-mode nil
213 "Indicates whether sub-exp mode is active.")
214
215 (defvar reb-subexp-displayed nil
216 "Indicates which sub-exp is active.")
217
218 (defvar reb-mode-string ""
219 "String in mode line for additional info.")
220
221 (defvar reb-valid-string ""
222 "String in mode line showing validity of RE.")
223
224 (make-variable-buffer-local 'reb-overlays)
225 (make-variable-buffer-local 'reb-regexp)
226 (make-variable-buffer-local 'reb-regexp-src)
227
228 (defconst reb-buffer "*RE-Builder*"
229 "Buffer to use for the RE Builder.")
230
231 ;; Define the local "\C-c" keymap
232 (defvar reb-mode-map nil
233 "Keymap used by the RE Builder.")
234
235 (if (not reb-mode-map)
236 (progn
237 (setq reb-mode-map (make-sparse-keymap))
238 (define-key reb-mode-map "\C-c\C-c" 'reb-toggle-case)
239 (define-key reb-mode-map "\C-c\C-q" 'reb-quit)
240 (define-key reb-mode-map "\C-c\C-w" 'reb-copy)
241 (define-key reb-mode-map "\C-c\C-s" 'reb-next-match)
242 (define-key reb-mode-map "\C-c\C-r" 'reb-prev-match)
243 (define-key reb-mode-map "\C-c\C-i" 'reb-change-syntax)
244 (define-key reb-mode-map "\C-c\C-e" 'reb-enter-subexp-mode)
245 (define-key reb-mode-map "\C-c\C-u" 'reb-force-update)))
246
247 (defun reb-mode ()
248 "Major mode for interactively building Regular Expressions.
249 \\{reb-mode-map}"
250 (interactive)
251
252 (setq major-mode 'reb-mode
253 mode-name "RE Builder")
254 (use-local-map reb-mode-map)
255 (reb-mode-common)
256 (run-hooks reb-mode-hook))
257
258 (define-derived-mode reb-lisp-mode
259 emacs-lisp-mode "RE Builder Lisp"
260 "Major mode for interactively building symbolic Regular Expressions.
261 \\{reb-lisp-mode-map}"
262 (cond ((eq reb-re-syntax 'lisp-re) ; Pull in packages
263 (require 'lisp-re)) ; as needed
264 ((eq reb-re-syntax 'sregex) ; sregex is not autoloaded
265 (require 'sregex))) ; right now..
266 (reb-mode-common))
267
268 ;; Use the same "\C-c" keymap as `reb-mode' and use font-locking from
269 ;; `emacs-lisp-mode'
270 (define-key reb-lisp-mode-map "\C-c"
271 (lookup-key reb-mode-map "\C-c"))
272
273 (if (boundp 'font-lock-defaults-alist)
274 (setq font-lock-defaults-alist
275 (cons (cons 'reb-lisp-mode
276 (cdr (assoc 'emacs-lisp-mode
277 font-lock-defaults-alist)))
278 font-lock-defaults-alist)))
279
280 (defvar reb-subexp-mode-map nil
281 "Keymap used by the RE Builder for the subexpression mode.")
282
283 (if (not reb-subexp-mode-map)
284 (progn
285 (setq reb-subexp-mode-map (make-sparse-keymap))
286 (suppress-keymap reb-subexp-mode-map)
287 ;; Again share the "\C-c" keymap for the commands
288 (define-key reb-subexp-mode-map "\C-c"
289 (lookup-key reb-mode-map "\C-c"))
290 (define-key reb-subexp-mode-map "q" 'reb-quit-subexp-mode)
291 (mapcar (lambda (digit)
292 (define-key reb-subexp-mode-map (int-to-string digit)
293 'reb-display-subexp))
294 '(0 1 2 3 4 5 6 7 8 9))))
295
296 (defun reb-mode-common ()
297 "Setup functions common to functions `reb-mode' and `reb-mode-lisp'."
298
299 (setq reb-mode-string ""
300 reb-valid-string ""
301 mode-line-buffer-identification
302 '(25 . ("%b" reb-mode-string reb-valid-string)))
303 (reb-update-modestring)
304 (make-local-variable 'after-change-functions)
305 (add-hook 'after-change-functions
306 'reb-auto-update)
307 ;; At least make the overlays go away if the buffer is killed
308 (make-local-variable 'reb-kill-buffer)
309 (add-hook 'kill-buffer-hook 'reb-kill-buffer)
310 (reb-auto-update nil nil nil))
311
312
313 ;; Handy macro for doing things in other windows
314 (defmacro reb-with-current-window (window &rest body)
315 "With WINDOW selected evaluate BODY forms and reselect previous window."
316
317 (let ((oldwindow (make-symbol "*oldwindow*")))
318 `(let ((,oldwindow (selected-window)))
319 (select-window ,window)
320 (unwind-protect
321 (progn
322 ,@body)
323 (select-window ,oldwindow)))))
324 (put 'reb-with-current-window 'lisp-indent-function 0)
325
326 (defun reb-color-display-p ()
327 "Return t if display is capable of displaying colors."
328 (eq 'color
329 ;; emacs/xemacs compatibility
330 (if (fboundp 'frame-parameter)
331 (frame-parameter (selected-frame) 'display-type)
332 (frame-property (selected-frame) 'display-type))))
333
334 (defsubst reb-lisp-syntax-p ()
335 "Return non-nil if RE Builder uses a Lisp syntax."
336 (memq reb-re-syntax '(lisp-re sregex)))
337
338 (defmacro reb-target-binding (symbol)
339 "Return binding for SYMBOL in the RE Builder target buffer."
340 `(with-current-buffer reb-target-buffer ,symbol))
341
342
343 ;;;###autoload
344 (defun re-builder ()
345 "Call up the RE Builder for the current window."
346 (interactive)
347
348 (if reb-target-buffer
349 (reb-delete-overlays))
350 (setq reb-target-buffer (current-buffer)
351 reb-target-window (selected-window)
352 reb-window-config (current-window-configuration))
353 (select-window (split-window (selected-window) (- (window-height) 4)))
354 (switch-to-buffer (get-buffer-create reb-buffer))
355 (erase-buffer)
356 (reb-insert-regexp)
357 (goto-char (+ 2 (point-min)))
358 (cond
359 ((reb-lisp-syntax-p)
360 (reb-lisp-mode))
361 (t (reb-mode))))
362
363
364 (defun reb-force-update ()
365 "Forces an update in the RE Builder target window without a match limit."
366 (interactive)
367
368 (let ((reb-auto-match-limit nil))
369 (reb-update-overlays
370 (if reb-subexp-mode reb-subexp-displayed nil))))
371
372 (defun reb-quit ()
373 "Quit the RE Builder mode."
374 (interactive)
375
376 (setq reb-subexp-mode nil
377 reb-subexp-displayed nil)
378 (reb-delete-overlays)
379 (bury-buffer)
380 (set-window-configuration reb-window-config))
381
382 (defun reb-next-match ()
383 "Go to next match in the RE Builder target window."
384 (interactive)
385
386 (reb-assert-buffer-in-window)
387 (reb-with-current-window
388 reb-target-window
389 (if (not (re-search-forward reb-regexp (point-max) t))
390 (message "No more matches.")
391 (reb-show-subexp
392 (or (and reb-subexp-mode reb-subexp-displayed) 0)
393 t))))
394
395 (defun reb-prev-match ()
396 "Go to previous match in the RE Builder target window."
397 (interactive)
398
399 (reb-assert-buffer-in-window)
400 (reb-with-current-window reb-target-window
401 (goto-char (1- (point)))
402 (if (not (re-search-backward reb-regexp (point-min) t))
403 (message "No more matches.")
404 (reb-show-subexp
405 (or (and reb-subexp-mode reb-subexp-displayed) 0)
406 t))))
407
408 (defun reb-toggle-case ()
409 "Toggle case sensitivity of searches for RE Builder target buffer."
410 (interactive)
411
412 (with-current-buffer reb-target-buffer
413 (setq case-fold-search (not case-fold-search)))
414 (reb-update-modestring)
415 (reb-auto-update nil nil nil t))
416
417 (defun reb-copy ()
418 "Copy current RE into the kill ring for later insertion."
419 (interactive)
420
421 (reb-update-regexp)
422 (let ((re (with-output-to-string
423 (print (reb-target-binding reb-regexp)))))
424 (kill-new (substring re 1 (1- (length re))))
425 (message "Regexp copied to kill-ring")))
426
427 ;; The subexpression mode is not electric because the number of
428 ;; matches should be seen rather than a prompt.
429 (defun reb-enter-subexp-mode ()
430 "Enter the subexpression mode in the RE Builder."
431 (interactive)
432
433 (setq reb-subexp-mode t)
434 (reb-update-modestring)
435 (use-local-map reb-subexp-mode-map)
436 (message "`0'-`9' to display subexpressions `q' to quit subexp mode."))
437
438 (defun reb-show-subexp (subexp &optional pause)
439 "Visually show limit of subexpression SUBEXP of recent search.
440 On color displays this just puts point to the end of the expression as
441 the match should already be marked by an overlay.
442 On other displays jump to the beginning and the end of it.
443 If the optional PAUSE is non-nil then pause at the end in any case."
444 (reb-with-current-window reb-target-window
445 (if (not (reb-color-display-p))
446 (progn (goto-char (match-beginning subexp))
447 (sit-for reb-blink-delay)))
448 (goto-char (match-end subexp))
449 (if (or (not (reb-color-display-p)) pause)
450 (sit-for reb-blink-delay))))
451
452 (defun reb-quit-subexp-mode ()
453 "Quit the subexpression mode in the RE Builder."
454 (interactive)
455
456 (setq reb-subexp-mode nil
457 reb-subexp-displayed nil)
458 (reb-update-modestring)
459 (use-local-map reb-mode-map)
460 (reb-do-update))
461
462 (defun reb-change-syntax (&optional syntax)
463 "Change the syntax used by the RE Builder.
464 Optional argument SYNTAX must be specified if called non-interactively."
465 (interactive
466 (list (intern
467 (completing-read "Select syntax: "
468 (mapcar (lambda (el) (cons (symbol-name el) 1))
469 '(read string lisp-re sregex))
470 nil t (symbol-name reb-re-syntax)))))
471
472 (if (memq syntax '(read string lisp-re sregex))
473 (let ((buffer (get-buffer reb-buffer)))
474 (setq reb-re-syntax syntax)
475 (if buffer
476 (with-current-buffer buffer
477 (erase-buffer)
478 (reb-insert-regexp)
479 (goto-char (+ 2 (point-min)))
480 (cond ((reb-lisp-syntax-p)
481 (reb-lisp-mode))
482 (t (reb-mode))))))
483 (error "Invalid syntax: %s" syntax)))
484
485
486 ;; Non-interactive functions below
487 (defun reb-do-update (&optional subexp)
488 "Update matches in the RE Builder target window.
489 If SUBEXP is non-nil mark only the corresponding sub-expressions."
490
491 (reb-assert-buffer-in-window)
492 (reb-update-regexp)
493 (reb-update-overlays subexp))
494
495 (defun reb-auto-update (beg end lenold &optional force)
496 "Called from `after-update-functions' to update the display.
497 BEG END and LENOLD are passed in from the hook.
498 An actual update is only done if the regexp has changed or if the
499 optional fourth argument FORCE is non-nil."
500 (let ((prev-valid reb-valid-string)
501 (new-valid
502 (condition-case nil
503 (progn
504 (if (or (reb-update-regexp) force)
505 (progn
506 (reb-assert-buffer-in-window)
507 (reb-do-update)))
508 "")
509 (error " *invalid*"))))
510 (setq reb-valid-string new-valid)
511 (force-mode-line-update)
512
513 ;; Through the caching of the re a change invalidating the syntax
514 ;; for symbolic expressions will not delete the overlays so we
515 ;; catch it here
516 (if (and (reb-lisp-syntax-p)
517 (not (string= prev-valid new-valid))
518 (string= prev-valid ""))
519 (reb-delete-overlays))))
520
521 (defun reb-delete-overlays ()
522 "Delete all RE Builder overlays in the `reb-target-buffer' buffer."
523 (if (buffer-live-p reb-target-buffer)
524 (with-current-buffer reb-target-buffer
525 (mapcar 'delete-overlay reb-overlays)
526 (setq reb-overlays nil))))
527
528 (defun reb-assert-buffer-in-window ()
529 "Assert that `reb-target-buffer' is displayed in `reb-target-window'."
530
531 (if (not (eq reb-target-buffer (window-buffer reb-target-window)))
532 (set-window-buffer reb-target-window reb-target-buffer)))
533
534 (defun reb-update-modestring ()
535 "Update the variable `reb-mode-string' displayed in the mode line."
536 (setq reb-mode-string
537 (concat
538 (if reb-subexp-mode
539 (concat " (subexp " (or reb-subexp-displayed "-") ")")
540 "")
541 (if (not (reb-target-binding case-fold-search))
542 " Case"
543 "")))
544 (force-mode-line-update))
545
546 (defun reb-display-subexp (&optional subexp)
547 "Highlight only subexpression SUBEXP in the RE Builder."
548 (interactive)
549
550 (setq reb-subexp-displayed
551 (or subexp (string-to-int (format "%c" last-command-char))))
552 (reb-update-modestring)
553 (reb-do-update reb-subexp-displayed))
554
555 (defun reb-kill-buffer ()
556 "When the RE Builder buffer is killed make sure no overlays stay around."
557
558 (if (member major-mode '(reb-mode reb-lisp-mode))
559 (reb-delete-overlays)))
560
561
562 ;; The next functions are the interface between the regexp and
563 ;; its textual representation in the RE Builder buffer.
564 ;; They are the only functions concerned with the actual syntax
565 ;; being used.
566 (defun reb-read-regexp ()
567 "Read current RE."
568 (save-excursion
569 (cond ((eq reb-re-syntax 'read)
570 (goto-char (point-min))
571 (read (current-buffer)))
572 ((eq reb-re-syntax 'string)
573 (goto-char (point-min))
574 (re-search-forward "\"")
575 (let ((beg (point)))
576 (goto-char (point-max))
577 (re-search-backward "\"")
578 (buffer-substring-no-properties beg (point))))
579 ((reb-lisp-syntax-p)
580 (buffer-string)))))
581
582 (defun reb-empty-regexp ()
583 "Return empty RE for current syntax."
584 (cond ((reb-lisp-syntax-p) "'()")
585 (t "")))
586
587 (defun reb-insert-regexp ()
588 "Insert current RE."
589
590 (let ((re (or (reb-target-binding reb-regexp)
591 (reb-empty-regexp))))
592 (cond ((eq reb-re-syntax 'read)
593 (print re (current-buffer)))
594 ((eq reb-re-syntax 'string)
595 (insert "\n\"" re "\""))
596 ;; For the Lisp syntax we need the "source" of the regexp
597 ((reb-lisp-syntax-p)
598 (insert (or (reb-target-binding reb-regexp-src)
599 (reb-empty-regexp)))))))
600
601 (defun reb-cook-regexp (re)
602 "Return RE after processing it according to `reb-re-syntax'."
603 (cond ((eq reb-re-syntax 'lisp-re)
604 (lre-compile-string (eval (car (read-from-string re)))))
605 ((eq reb-re-syntax 'sregex)
606 (apply 'sregex (eval (car (read-from-string re)))))
607 (t re)))
608
609 (defun reb-update-regexp ()
610 "Update the regexp for the target buffer.
611 Return t if the (cooked) expression changed."
612 (let* ((re-src (reb-read-regexp))
613 (re (reb-cook-regexp re-src)))
614 (with-current-buffer reb-target-buffer
615 (let ((oldre reb-regexp))
616 (prog1
617 (not (string= oldre re))
618 (setq reb-regexp re)
619 ;; Only update the source re for the lisp formats
620 (if (reb-lisp-syntax-p)
621 (setq reb-regexp-src re-src)))))))
622
623
624 ;; And now the real core of the whole thing
625 (defun reb-count-subexps (re)
626 "Return number of sub-expressions in the regexp RE."
627
628 (let ((i 0) (beg 0))
629 (while (string-match "\\\\(" re beg)
630 (setq i (1+ i)
631 beg (match-end 0)))
632 i))
633
634
635 (defun reb-update-overlays (&optional subexp)
636 "Switch to `reb-target-buffer' and mark all matches of `reb-regexp'.
637 If SUBEXP is non-nil mark only the corresponding sub-expressions."
638
639 (let* ((re (reb-target-binding reb-regexp))
640 (subexps (reb-count-subexps re))
641 (matches 0)
642 (submatches 0)
643 firstmatch)
644 (save-excursion
645 (set-buffer reb-target-buffer)
646 (reb-delete-overlays)
647 (goto-char (point-min))
648 (while (and (re-search-forward re (point-max) t)
649 (or (not reb-auto-match-limit)
650 (< matches reb-auto-match-limit)))
651 (if (= 0 (length (match-string 0)))
652 (error "Empty regular expression!"))
653 (let ((i 0))
654 (setq matches (1+ matches))
655 (while (<= i subexps)
656 (if (and (or (not subexp) (= subexp i))
657 (match-beginning i))
658 (let ((overlay (make-overlay (match-beginning i)
659 (match-end i)))
660 (face-name (format "reb-match-%d" i)))
661 (if (not firstmatch)
662 (setq firstmatch (match-data)))
663 (setq reb-overlays (cons overlay reb-overlays)
664 submatches (1+ submatches))
665 (overlay-put
666 overlay 'face
667 (or (intern-soft face-name)
668 (error "Too many subexpressions - face `%s' not defined"
669 face-name )))
670 (overlay-put overlay 'priority i)))
671 (setq i (1+ i))))))
672 (let ((count (if subexp submatches matches)))
673 (message"%s %smatch(es)%s"
674 (if (= 0 count) "No" (int-to-string count))
675 (if subexp "subexpression " "")
676 (if (and reb-auto-match-limit
677 (= reb-auto-match-limit count))
678 " (limit reached)" "")))
679 (if firstmatch
680 (progn (store-match-data firstmatch)
681 (reb-show-subexp (or subexp 0))))))
682
683 ;;; re-builder.el ends here