1;;; regex-tool --- A regular expression evaluation tool for programmers
3;; Copyright (C) 2007 John Wiegley
5;; Author: John Wiegley <johnw@newartisans.com>
7;; Modified: 17 Nov 2007
9;; Keywords: regex languages programming development
10;; X-URL: http://www.newartisans.com/
12;; This program is free software; you can redistribute it and/or
13;; modify it under the terms of the GNU General Public License as
14;; published by the Free Software Foundation; either version 2, or (at
15;; your option) any later version.
17;; This program is distributed in the hope that it will be useful, but
18;; WITHOUT ANY WARRANTY; without even the implied warranty of
19;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
20;; General Public License for more details.
22;; You should have received a copy of the GNU General Public License
23;; along with GNU Emacs; see the file COPYING. If not, write to the
24;; Free Software Foundation, Inc., 59 Temple Place - Suite 330,
25;; Boston, MA 02111-1307, USA.
29;; This program currently uses frames only.
31;; After you type M-x regex-tool, you will see three buffers: *Regex*, *Text*
32;; and *Groups*. The *Regex* buffer contains your regular expression. By
33;; default, this tool uses Emacs regular expressions. If you customize the
34;; variable `regex-tool-backend', you can switch to using full Perl regular
37;; The *Text* buffer contains the sample text you want to match against.
38;; Change this however you like.
40;; The *Groups* buffer will list out any regular expression groups that match.
41;; Your regular expression is searched for as many times as it appears in the
42;; buffer, and any groups that match will be repeated.
44;; The results are updated as you type in either the *Regex* or *Text* buffer.
45;; Use C-c C-c to force an update. Use C-c C-k to quit all the regex-tool
46;; buffers and remove the frame.
50;; 1.1 - Don't die horribly if the user simply types '^' or '$'
51;; 1.2 - Include cl.el at compile time
56(defgroup regex-tool nil
57 "Outline-based notes management and organizer."
61(defvar regex-tool-mode-map (make-sparse-keymap))
62(defvar regex-tool-mode-abbrev-table)
64(define-derived-mode regex-tool-mode text-mode "Regex Tool"
65 "This is regex-tool mode."
66 (define-key regex-tool-mode-map [(control ?c) (control ?c)]
67 'regex-tool-markup-text)
68 (define-key regex-tool-mode-map [(control ?c) (control ?k)]
70 (add-hook 'after-change-functions 'regex-tool-markup-text nil t))
72(defface regex-tool-matched-face
73 '((((background light)) (:foreground "Red" :bold t))
74 (((background dark)) (:foreground "Orange" :bold t)))
78(defcustom regex-tool-backend 'emacs
79 "The backend used to process regular expressions.
80The `emacs' backend handles regular expressions directly.
81The `perl' backend talks to a perl subprocess to do the handling.\"
84 (const :tag "Emacs" emacs)
85 (const :tag "Perl" perl))
88(defun regex-render-perl (regex sample)
90 (insert (format "@lines = <DATA>;
91$line = join(\" \", @lines);
93while ($line =~ m/%s/mg) {
94 print \"(\", length($`), \" \", length($&), \" \";
97 print \"(\", $i, \" . \\\"\", $$i, \"\\\") \";
105 (call-process-region (point-min) (point-max) "perl" t t)
106 (goto-char (point-min))
107 (read (current-buffer))))
109(defvar regex-expr-buffer nil)
110(defvar regex-text-buffer nil)
111(defvar regex-group-buffer nil)
115 (select-frame (make-frame-command))
116 (split-window-vertically)
117 (split-window-vertically)
119 (setq regex-expr-buffer (get-buffer-create "*Regex*"))
120 (switch-to-buffer regex-expr-buffer)
123 (setq regex-text-buffer (get-buffer-create "*Text*"))
124 (switch-to-buffer regex-text-buffer)
125 (goto-char (point-min))
127 (insert "Hello, this is text your regular expression will match against."))
130 (setq regex-group-buffer (get-buffer-create "*Groups*"))
131 (switch-to-buffer regex-group-buffer)
134(defun regex-tool-markup-text (&optional beg end len)
136 (let ((regex (with-current-buffer regex-expr-buffer
139 (when (> (length regex) 0)
140 (with-current-buffer regex-group-buffer
142 (with-current-buffer regex-text-buffer
146 (goto-char (point-min))
147 (if (eq regex-tool-backend 'emacs)
148 (while (and (setq previous-point (point))
149 (re-search-forward regex nil t))
150 (if (= (point) previous-point)
152 (overlay-put (make-overlay (match-beginning 0)
154 'face 'regex-tool-matched-face)
156 (let ((text (match-string i)))
159 (with-current-buffer regex-group-buffer
160 (goto-char (point-max))
161 (insert (format "Group %d: '%s'\n" i text)))))))
162 (with-current-buffer regex-group-buffer
164 (let ((results (regex-render-perl regex (buffer-string))))
165 (dolist (result results)
166 (let ((offset (nth 0 result))
167 (length (nth 1 result))
168 (matches (nthcdr 2 result)))
169 (overlay-put (make-overlay (1+ offset) (+ offset length 1))
170 'face 'regex-tool-matched-face)
171 (let ((match-zero (buffer-substring (1+ offset)
172 (+ offset length 1))))
173 (with-current-buffer regex-group-buffer
174 (insert (format "Group 0: '%s'\n" match-zero))))
175 (dolist (match matches)
176 (with-current-buffer regex-group-buffer
177 (goto-char (point-max))
178 (insert (format "Group %d: '%s'\n" (car match)
180 (with-current-buffer regex-group-buffer
182 (with-current-buffer regex-group-buffer
183 (goto-char (point-min))))))
185(defun regex-tool-quit ()
187 (kill-buffer regex-expr-buffer)
188 (kill-buffer regex-text-buffer)
189 (kill-buffer regex-group-buffer)
194;; regex-tool.el ends here