1 ;;; rxi.el --- Interactive regexp reading using rx format
3 ;; Author: Lennart Borgman (lennart O borgman A gmail O com)
4 ;; Created: 2008-04-07T18:18:39+0200 Mon
11 ;; Features that might be required by this library:
15 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
19 ;; Read regexp as `rx' forms from minibuffer.
21 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
26 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
28 ;; This program is free software; you can redistribute it and/or
29 ;; modify it under the terms of the GNU General Public License as
30 ;; published by the Free Software Foundation; either version 2, or
31 ;; (at your option) any later version.
33 ;; This program is distributed in the hope that it will be useful,
34 ;; but WITHOUT ANY WARRANTY; without even the implied warranty of
35 ;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
36 ;; General Public License for more details.
38 ;; You should have received a copy of the GNU General Public License
39 ;; along with this program; see the file COPYING. If not, write to
40 ;; the Free Software Foundation, Inc., 51 Franklin Street, Fifth
41 ;; Floor, Boston, MA 02110-1301, USA.
43 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
47 (defvar rxi-read-hist nil)
49 (defun rxi-find-definition (rx-sym)
50 (let* ((rec (assoc rx-sym rx-constituents))
52 (while (symbolp (cdr rec))
53 (setq rec (assoc (cdr rec) rx-constituents)))
56 (defun rxi-list-type-p (rx-sym)
57 (listp (rxi-find-definition rx-sym)))
59 (defun rxi-complete ()
60 "Complete `rx' constituents."
62 ;; Don't care about state for now, there will be an error instead
63 (let* ((partial (when (looking-back (rx (1+ (any "a-z01:|=>*?+\\-"))) nil t)
64 (match-string-no-properties 0)))
65 (candidates (let ((want-list
66 (= ?\( (char-before (match-beginning 0)))))
69 (let* ((sym (car rec))
70 (lst (rxi-list-type-p sym)))
71 (when (or (and want-list lst)
76 (match-set (when partial
82 (message "No completions"))
83 ((= 1 (length match-set))
84 (insert (substring (car match-set) (length partial))))
86 (with-output-to-temp-buffer "*Completions*"
87 (display-completion-list match-set partial))))))
89 (defvar rxi-read-keymap
90 (let ((map (make-sparse-keymap)))
91 (set-keymap-parent map minibuffer-local-completion-map)
92 (define-key map [tab] 'rxi-complete)
93 (define-key map [(meta tab)] 'rxi-complete)
94 (define-key map [?\ ] 'self-insert-command)
97 (defvar rxi-trailing-overlay nil)
99 (defun rxi-minibuf-setup ()
100 (when rxi-trailing-overlay (delete-overlay rxi-trailing-overlay))
101 (setq rxi-trailing-overlay
102 (make-overlay (point-max) (point-max)
105 (overlay-put rxi-trailing-overlay 'after-string
109 (fboundp 'noticeable-minibuffer-prompts-mode)
110 noticeable-minibuffer-prompts-mode)
111 'minibuffer-noticeable-prompt
112 'minibuffer-prompt)))
113 (remove-hook 'minibuffer-setup-hook 'rxi-minibuf-setup))
115 (defun rxi-minibuf-exit ()
116 (when rxi-trailing-overlay
117 (delete-overlay rxi-trailing-overlay)
118 (setq rxi-trailing-overlay nil))
119 (remove-hook 'minibuffer-exit-hook 'rxi-minibuf-exit))
121 (defun rxi-read (prompt)
122 "Read a `rx' regexp form from minibuffer.
123 Return cons of rx and regexp, both as strings."
124 (interactive (list "Test (rx "))
125 (let (rx-str rx-full-str res-regexp)
126 (while (not res-regexp)
129 (add-hook 'minibuffer-setup-hook 'rxi-minibuf-setup)
130 (add-hook 'minibuffer-exit-hook 'rxi-minibuf-exit)
131 (setq rx-str (read-from-minibuffer prompt
132 rx-str ;; initial-contents
136 nil ;; inherit-input-method - no idea...
138 (setq rx-full-str (concat "(rx " rx-str ")"))
139 (setq res-regexp (eval (read rx-full-str))))
140 (error (message "%s" (error-message-string err))
142 (when (with-no-warnings (called-interactively-p)) (message "%s => \"%s\"" rx-full-str res-regexp))
143 (cons rx-full-str res-regexp)))
147 ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;