aboutsummaryrefslogtreecommitdiffstats
path: root/lisp
diff options
context:
space:
mode:
authorLennart Borgman2019-06-27 19:08:42 +0200
committerLars Ingebrigtsen2019-06-27 19:08:42 +0200
commitc1234ca9c3703cd8bae3912f3e0a1948bae3aed1 (patch)
tree69be7cb1f0d74c1e6c6783f2c9b159bfdbc07099 /lisp
parent2fbcda71a9f1d6ebff041203cb5ca4979decdf3e (diff)
downloademacs-c1234ca9c3703cd8bae3912f3e0a1948bae3aed1.tar.gz
emacs-c1234ca9c3703cd8bae3912f3e0a1948bae3aed1.zip
Add more fontification to regexp builder mode
* lisp/emacs-lisp/re-builder.el (reb-copy): Work in the presence of newlines in the regexps. (reb-change-syntax): Use a dedicated history variable. (reb-fontify-string-re): Fontify sub-matches. (reb-regexp-grouping-backslash, reb-regexp-grouping-construct): New faces. (reb-string-font-lock-keywords): New variable. (reb-mark-non-matching-parenthesis): Match parenthesis. (reb-restart-font-lock): New function. * lisp/emacs-lisp/re-builder.el (reb-mode-map): Add divider some dividers (bug#6347).
Diffstat (limited to 'lisp')
-rw-r--r--lisp/emacs-lisp/re-builder.el145
1 files changed, 141 insertions, 4 deletions
diff --git a/lisp/emacs-lisp/re-builder.el b/lisp/emacs-lisp/re-builder.el
index f5b1dd89b4b..cc432e7cb45 100644
--- a/lisp/emacs-lisp/re-builder.el
+++ b/lisp/emacs-lisp/re-builder.el
@@ -240,6 +240,7 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
240 (define-key menu-map [rq] 240 (define-key menu-map [rq]
241 '(menu-item "Quit" reb-quit 241 '(menu-item "Quit" reb-quit
242 :help "Quit the RE Builder mode")) 242 :help "Quit the RE Builder mode"))
243 (define-key menu-map [div1] '(menu-item "--"))
243 (define-key menu-map [rt] 244 (define-key menu-map [rt]
244 '(menu-item "Case sensitive" reb-toggle-case 245 '(menu-item "Case sensitive" reb-toggle-case
245 :button (:toggle . (with-current-buffer 246 :button (:toggle . (with-current-buffer
@@ -252,6 +253,7 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
252 (define-key menu-map [rs] 253 (define-key menu-map [rs]
253 '(menu-item "Change syntax..." reb-change-syntax 254 '(menu-item "Change syntax..." reb-change-syntax
254 :help "Change the syntax used by the RE Builder")) 255 :help "Change the syntax used by the RE Builder"))
256 (define-key menu-map [div2] '(menu-item "--"))
255 (define-key menu-map [re] 257 (define-key menu-map [re]
256 '(menu-item "Enter subexpression mode" reb-enter-subexp-mode 258 '(menu-item "Enter subexpression mode" reb-enter-subexp-mode
257 :help "Enter the subexpression mode in the RE Builder")) 259 :help "Enter the subexpression mode in the RE Builder"))
@@ -264,6 +266,7 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
264 (define-key menu-map [rp] 266 (define-key menu-map [rp]
265 '(menu-item "Go to previous match" reb-prev-match 267 '(menu-item "Go to previous match" reb-prev-match
266 :help "Go to previous match in the RE Builder target window")) 268 :help "Go to previous match in the RE Builder target window"))
269 (define-key menu-map [div3] '(menu-item "--"))
267 (define-key menu-map [rc] 270 (define-key menu-map [rc]
268 '(menu-item "Copy current RE" reb-copy 271 '(menu-item "Copy current RE" reb-copy
269 :help "Copy current RE into the kill ring for later insertion")) 272 :help "Copy current RE into the kill ring for later insertion"))
@@ -339,6 +342,7 @@ Except for Lisp syntax this is the same as `reb-regexp'.")
339 (cond ((reb-lisp-syntax-p) 342 (cond ((reb-lisp-syntax-p)
340 (reb-lisp-mode)) 343 (reb-lisp-mode))
341 (t (reb-mode))) 344 (t (reb-mode)))
345 (reb-restart-font-lock)
342 (reb-do-update)) 346 (reb-do-update))
343 347
344(defun reb-mode-buffer-p () 348(defun reb-mode-buffer-p ()
@@ -371,6 +375,7 @@ matching parts of the target buffer will be highlighted."
371 (setq reb-window-config (current-window-configuration)) 375 (setq reb-window-config (current-window-configuration))
372 (split-window (selected-window) (- (window-height) 4))))) 376 (split-window (selected-window) (- (window-height) 4)))))
373 (switch-to-buffer (get-buffer-create reb-buffer)) 377 (switch-to-buffer (get-buffer-create reb-buffer))
378 (font-lock-mode 1)
374 (reb-initialize-buffer))) 379 (reb-initialize-buffer)))
375 380
376(defun reb-change-target-buffer (buf) 381(defun reb-change-target-buffer (buf)
@@ -447,7 +452,9 @@ matching parts of the target buffer will be highlighted."
447 (reb-update-regexp) 452 (reb-update-regexp)
448 (let ((re (with-output-to-string 453 (let ((re (with-output-to-string
449 (print (reb-target-binding reb-regexp))))) 454 (print (reb-target-binding reb-regexp)))))
450 (kill-new (substring re 1 (1- (length re)))) 455 (setq re (substring re 1 (1- (length re))))
456 (setq re (replace-regexp-in-string "\n" "\\n" re nil t))
457 (kill-new re)
451 (message "Regexp copied to kill-ring"))) 458 (message "Regexp copied to kill-ring")))
452 459
453;; The subexpression mode is not electric because the number of 460;; The subexpression mode is not electric because the number of
@@ -483,6 +490,8 @@ If the optional PAUSE is non-nil then pause at the end in any case."
483 (use-local-map reb-mode-map) 490 (use-local-map reb-mode-map)
484 (reb-do-update)) 491 (reb-do-update))
485 492
493(defvar reb-change-syntax-hist nil)
494
486(defun reb-change-syntax (&optional syntax) 495(defun reb-change-syntax (&optional syntax)
487 "Change the syntax used by the RE Builder. 496 "Change the syntax used by the RE Builder.
488Optional argument SYNTAX must be specified if called non-interactively." 497Optional argument SYNTAX must be specified if called non-interactively."
@@ -491,7 +500,8 @@ Optional argument SYNTAX must be specified if called non-interactively."
491 (completing-read 500 (completing-read
492 (format "Select syntax (default %s): " reb-re-syntax) 501 (format "Select syntax (default %s): " reb-re-syntax)
493 '(read string sregex rx) 502 '(read string sregex rx)
494 nil t nil nil (symbol-name reb-re-syntax))))) 503 nil t nil nil (symbol-name reb-re-syntax)
504 'reb-change-syntax-hist))))
495 505
496 (if (memq syntax '(read string sregex rx)) 506 (if (memq syntax '(read string sregex rx))
497 (let ((buffer (get-buffer reb-buffer))) 507 (let ((buffer (get-buffer reb-buffer)))
@@ -653,8 +663,14 @@ If SUBEXP is non-nil mark only the corresponding sub-expressions."
653 (subexps (reb-count-subexps re)) 663 (subexps (reb-count-subexps re))
654 (matches 0) 664 (matches 0)
655 (submatches 0) 665 (submatches 0)
656 firstmatch) 666 firstmatch
667 here
668 firstmatch-after-here)
657 (with-current-buffer reb-target-buffer 669 (with-current-buffer reb-target-buffer
670 (setq here
671 (if reb-target-window
672 (with-selected-window reb-target-window (window-point))
673 (point)))
658 (reb-delete-overlays) 674 (reb-delete-overlays)
659 (goto-char (point-min)) 675 (goto-char (point-min))
660 (while (and (not (eobp)) 676 (while (and (not (eobp))
@@ -689,6 +705,9 @@ If SUBEXP is non-nil mark only the corresponding sub-expressions."
689 ;; `reb-match-1' must exist. 705 ;; `reb-match-1' must exist.
690 'reb-match-1)))) 706 'reb-match-1))))
691 (unless firstmatch (setq firstmatch (match-data))) 707 (unless firstmatch (setq firstmatch (match-data)))
708 (unless firstmatch-after-here
709 (when (> (point) here)
710 (setq firstmatch-after-here (match-data))))
692 (setq reb-overlays (cons overlay reb-overlays) 711 (setq reb-overlays (cons overlay reb-overlays)
693 submatches (1+ submatches)) 712 submatches (1+ submatches))
694 (overlay-put overlay 'face face) 713 (overlay-put overlay 'face face)
@@ -703,7 +722,7 @@ If SUBEXP is non-nil mark only the corresponding sub-expressions."
703 (= reb-auto-match-limit count)) 722 (= reb-auto-match-limit count))
704 " (limit reached)" ""))) 723 " (limit reached)" "")))
705 (when firstmatch 724 (when firstmatch
706 (store-match-data firstmatch) 725 (store-match-data (or firstmatch-after-here firstmatch))
707 (reb-show-subexp (or subexp 0))))) 726 (reb-show-subexp (or subexp 0)))))
708 727
709;; The End 728;; The End
@@ -718,6 +737,124 @@ If SUBEXP is non-nil mark only the corresponding sub-expressions."
718 ;; continue standard unloading 737 ;; continue standard unloading
719 nil) 738 nil)
720 739
740(defun reb-fontify-string-re (bound)
741 (catch 'found
742 ;; The following loop is needed to continue searching after matches
743 ;; that do not occur in strings. The associated regexp matches one
744 ;; of `\\\\' `\\(' `\\(?:' `\\|' `\\)'. `\\\\' has been included to
745 ;; avoid highlighting, for example, `\\(' in `\\\\('.
746 (when (memq reb-re-syntax '(read string))
747 (while (re-search-forward
748 (if (eq reb-re-syntax 'read)
749 ;; Copied from font-lock.el
750 "\\(\\\\\\\\\\)\\(?:\\(\\\\\\\\\\)\\|\\((\\(?:\\?[0-9]*:\\)?\\|[|)]\\)\\)"
751 "\\(\\\\\\)\\(?:\\(\\\\\\)\\|\\((\\(?:\\?[0-9]*:\\)?\\|[|)]\\)\\)")
752 bound t)
753 (unless (match-beginning 2)
754 (let ((face (get-text-property (1- (point)) 'face)))
755 (when (or (and (listp face)
756 (memq 'font-lock-string-face face))
757 (eq 'font-lock-string-face face)
758 t)
759 (throw 'found t))))))))
760
761(defface reb-regexp-grouping-backslash
762 '((t :inherit font-lock-keyword-face :weight bold :underline t))
763 "Font Lock mode face for backslashes in Lisp regexp grouping constructs."
764 :group 're-builder)
765
766(defface reb-regexp-grouping-construct
767 '((t :inherit font-lock-keyword-face :weight bold :underline t))
768 "Font Lock mode face used to highlight grouping constructs in Lisp regexps."
769 :group 're-builder)
770
771(defconst reb-string-font-lock-keywords
772 (eval-when-compile
773 '(((reb-fontify-string-re
774 (1 'reb-regexp-grouping-backslash prepend)
775 (3 'reb-regexp-grouping-construct prepend))
776 (reb-mark-non-matching-parenthesis))
777 nil)))
778
779(defsubst reb-while (limit counter where)
780 (let ((count (symbol-value counter)))
781 (if (= count limit)
782 (progn
783 (message "Reached (while limit=%s, where=%s)" limit where)
784 nil)
785 (set counter (1+ count)))))
786
787(defun reb-mark-non-matching-parenthesis (bound)
788 ;; We have a small string, check the whole of it, but wait until
789 ;; everything else is fontified.
790 (when (>= bound (point-max))
791 (let (left-pars
792 faces-here)
793 (goto-char (point-min))
794 (while (and (reb-while 100 'n-reb "mark-par")
795 (not (eobp)))
796 (skip-chars-forward "^()")
797 (unless (eobp)
798 (setq faces-here (get-text-property (point) 'face))
799 ;; It is already fontified, use that info:
800 (when (or (eq 'reb-regexp-grouping-construct faces-here)
801 (and (listp faces-here)
802 (memq 'reb-regexp-grouping-construct faces-here)))
803 (cond ((eq (char-after) ?\()
804 (setq left-pars (cons (point) left-pars)))
805 ((eq (char-after) ?\))
806 (if left-pars
807 (setq left-pars (cdr left-pars))
808 (put-text-property (point) (1+ (point))
809 'face 'font-lock-warning-face)))
810 (t (message "markpar: char-after=%s"
811 (char-to-string (char-after))))))
812 (forward-char)))
813 (dolist (lp left-pars)
814 (put-text-property lp (1+ lp)
815 'face 'font-lock-warning-face)))))
816
817(require 'rx)
818(defconst reb-rx-font-lock-keywords
819 (let ((constituents (mapcar (lambda (rec)
820 (symbol-name (car rec)))
821 rx-constituents))
822 (syntax (mapcar (lambda (rec) (symbol-name (car rec))) rx-syntax))
823 (categories (mapcar (lambda (rec)
824 (symbol-name (car rec)))
825 rx-categories)))
826 `(
827 (,(concat "(" (regexp-opt (list "rx-to-string") t) "[[:space:]]")
828 (1 font-lock-function-name-face))
829 (,(concat "(" (regexp-opt (list "rx") t) "[[:space:]]")
830 (1 font-lock-preprocessor-face))
831 (,(concat "(category[[:space:]]+" (regexp-opt categories t) ")")
832 (1 font-lock-variable-name-face))
833 (,(concat "(syntax[[:space:]]+" (regexp-opt syntax t) ")")
834 (1 font-lock-type-face))
835 (,(concat "(" (regexp-opt constituents t))
836 (1 font-lock-keyword-face))
837 )))
838
839(defun reb-restart-font-lock ()
840 "Restart `font-lock-mode' to fit current regexp format."
841 (message "reb-restart-font-lock re-re-syntax=%s" reb-re-syntax)
842 (with-current-buffer (get-buffer reb-buffer)
843 (let ((font-lock-is-on font-lock-mode))
844 (font-lock-mode -1)
845 (kill-local-variable 'font-lock-set-defaults)
846 ;;(set (make-local-variable 'reb-re-syntax) 'string)
847 ;;(set (make-local-variable 'reb-re-syntax) 'rx)
848 (setq font-lock-defaults
849 (cond
850 ((memq reb-re-syntax '(read string))
851 reb-string-font-lock-keywords)
852 ((eq reb-re-syntax 'rx)
853 '(reb-rx-font-lock-keywords
854 nil))
855 (t nil)))
856 (when font-lock-is-on (font-lock-mode 1)))))
857
721(provide 're-builder) 858(provide 're-builder)
722 859
723;;; re-builder.el ends here 860;;; re-builder.el ends here