diff options
| author | Lennart Borgman | 2019-06-27 19:08:42 +0200 |
|---|---|---|
| committer | Lars Ingebrigtsen | 2019-06-27 19:08:42 +0200 |
| commit | c1234ca9c3703cd8bae3912f3e0a1948bae3aed1 (patch) | |
| tree | 69be7cb1f0d74c1e6c6783f2c9b159bfdbc07099 /lisp | |
| parent | 2fbcda71a9f1d6ebff041203cb5ca4979decdf3e (diff) | |
| download | emacs-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.el | 145 |
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. |
| 488 | Optional argument SYNTAX must be specified if called non-interactively." | 497 | Optional 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 |