branch: externals/easy-escape commit 8623aa9d715fe7677ea24d7164ea6e4ecdb3e65b Author: Clément Pit--Claudel <clement.pitclau...@live.com> Commit: Clément Pit--Claudel <clement.pitclau...@live.com>
Hide backslashes before '(', ')', and '|' --- README.md | 18 ++---------- easy-escape.el | 86 ++++++++++++++++++++++++++++++++++++++-------------------- 2 files changed, 60 insertions(+), 44 deletions(-) diff --git a/README.md b/README.md index f0c79cd..9214fae 100644 --- a/README.md +++ b/README.md @@ -2,26 +2,14 @@  -`easy-escape-minor-mode` composes double backslashes (escape characters) into single backslashes, and highlights them to improve readability. The underlying buffer text is not modified. +`easy-escape-minor-mode` uses syntax highlighting and composition to make ELisp regular expressions more readable. More precisely, it hides double backslashes preceding regexp specials (`()|`), composes other double backslashes into single ones, and applies a special face to each. The underlying buffer text is not modified. -The default is to use a single \ character instead of two, but the character used and its color can be customized using `easy-escape-face` and `easy-escape-character`. - -## Screenshots - -### Using a custom color - - - -### Using a custom character - - +The default is to use a single \ character instead of two, and to hide backslashes preceding parentheses or `|`. The escape character and its color can be customized using `easy-escape-face` and `easy-escape-character` (which see), and backslashes before `()|` can be shown by disabling `easy-escape-hide-escapes-before-delimiters`. ## Setup ### MELPA (preferred) -This will be valid if the package gets accepted on MELPA: - 1. Setup [MELPA](http://melpa.org/#/getting-started) if you haven't yet In your `.emacs`, add these three lines: @@ -34,7 +22,7 @@ This will be valid if the package gets accepted on MELPA: 2. Install the package: `M-x package-install RET easy-escape RET` -3. Enable `easy-escape-minor-mode` in lisp buffers: +3. Enable `easy-escape-minor-mode` in Lisp buffers: ```elisp ;; Replace 'lisp-mode-hook with 'prog-mode-hook to enable everywhere diff --git a/easy-escape.el b/easy-escape.el index 9b1ca00..801b0f6 100644 --- a/easy-escape.el +++ b/easy-escape.el @@ -21,20 +21,25 @@ ;;; Commentary: -;; `easy-escape-minor-mode' composes double backslashes (escape characters) into -;; single backslashes, and highlights them to improve readability. +;; `easy-escape-minor-mode' uses syntax highlighting and composition to make ELisp regular +;; expressions more readable. More precisely, it hides double backslashes +;; preceding regexp specials (`()|'), composes other double backslashes into +;; single ones, and applies a special face to each. The underlying buffer text +;; is not modified. ;; -;; For example, `easy-escape` displays "\\(?:\\_<\\\\newcommand\\_>\\s-*\\)?" -;; as "\(?:\_<\\newcommand\_>\s-*\)?". The underlying text is not modified. +;; For example, `easy-escape` prettifies this: +;; "\\(?:\\_<\\\\newcommand\\_>\\s-*\\)?" +;; into this (`^' indicates a different color): +;; "(?:\_<\\newcommand\_>\s-*)?". +;; ^ ^ ;; -;; The default it to use a single \ character instead of two, but the character -;; used and its color can be customized using `easy-escape-face' and -;; `easy-escape-character' (which see). +;; The default is to use a single \ character instead of two, and to hide +;; backslashes preceding parentheses or `|'. The escape character and its color +;; can be customized using `easy-escape-face' and `easy-escape-character' (which see), and backslashes +;; before ()| can be shown by disabling `easy-escape-hide-escapes-before-delimiters'. ;; ;; Suggested setup: ;; (add-hook 'lisp-mode-hook 'easy-escape-minor-mode) -;; or -;; (add-hook 'prog-mode-hook 'easy-escape-minor-mode) ;; ;; NOTE: If you find the distinction between the fontified double-slash and the ;; single slash too subtle, try the following: @@ -55,6 +60,11 @@ "Face used to highlight \\\\ in strings" :group 'easy-escape) +(defface easy-escape-delimiter-face + '((t :weight bold :slant normal :inherit font-lock-warning-face)) + "Face used to highlight groups and alternations in strings" + :group 'easy-escape) + (defcustom easy-escape-character ?\\ "Character by which \\\\ is replaced when `easy-escape-minor-mode' is active. Good candidates include the following: @@ -68,31 +78,48 @@ Good candidates include the following: ⦥ MATHEMATICAL REVERSED ANGLE WITH UNDERBAR (typed as '?⦥') ⦣ MATHEMATICAL REVERSED ANGLE (typed as '?⦣') ⧹ BIG REVERSE SOLIDUS (typed as '?⧹') -Most of these characters require non-standard fonts to display properly, however." +Most of these characters require non-standard fonts to display properly, +however." :group 'easy-escape) -(defconst easy-escape--keywords - '((easy-escape--mark-escapes (0 (easy-escape--compose (match-beginning 0))) - (0 'easy-escape-face append))) - "Font-lock keyword list used internally.") +(defcustom easy-escape-hide-escapes-before-delimiters t + "Whether to hide \\\\ when it precedes one of `(', `|', and `)'." + :group 'easy-escape + :type 'boolean) (defun easy-escape--in-string-p (pos) "Indicate whether POS is inside of a string." (let ((face (get-text-property pos 'face))) - (or (eq 'font-lock-string-face face) - (and (listp face) (memq 'font-lock-string-face face))))) + (or (eq 'font-lock-doc-face face) + (eq 'font-lock-string-face face) + (and (listp face) (or (memq 'font-lock-doc-face face) + (memq 'font-lock-string-face face)))))) -(defun easy-escape--mark-escapes (limit) - "Position point at end of next \\\\, and set match data. -Search ends at LIMIT." +(defun easy-escape--mark-in-string (re lim) + "Find next match for RE before LIM that falls in a string." (catch 'found - (while (re-search-forward "\\(\\\\\\\\\\)" limit t) + (while (re-search-forward re lim t) (when (easy-escape--in-string-p (match-beginning 0)) (throw 'found t))))) -(defun easy-escape--compose (start) - "Compose characters from START to (+ 2 START) into `easy-escape-character'." - (compose-region start (+ 2 start) easy-escape-character)) +(defun easy-escape--mark-escapes (limit) + "Search for \\\\ before LIMIT." + (easy-escape--mark-in-string "\\(\\\\\\\\\\)" limit)) + +(defun easy-escape--mark-delims (limit) + "Search for a delimiter or alternation before LIMIT." + (easy-escape--mark-in-string "\\(\\\\\\\\\\)\\([()|]\\)" limit)) + +(defun easy-escape--compose (n char) + "Compose match group N into CHAR." + (compose-region (match-beginning n) (match-end n) char)) + +(defconst easy-escape--keywords + '((easy-escape--mark-escapes + (0 (progn (easy-escape--compose 0 easy-escape-character) 'easy-escape-face) prepend)) + (easy-escape--mark-delims + (0 (progn (easy-escape--compose 0 (char-after (match-beginning 2))) 'easy-escape-delimiter-face) prepend))) + "Font-lock keyword list used internally.") ;;;###autoload (define-minor-mode easy-escape-minor-mode @@ -108,12 +135,13 @@ and the single slash too subtle, try the following: * Set `easy-escape-character' to a different character." :lighter " ez-esc" :group 'easy-escape - (if easy-escape-minor-mode - (progn (font-lock-add-keywords nil easy-escape--keywords) - (add-to-list (make-local-variable 'font-lock-extra-managed-props) 'composition)) - (font-lock-remove-keywords nil easy-escape--keywords)) - (if (>= emacs-major-version 25) - (font-lock-flush) + (cond + (easy-escape-minor-mode + (font-lock-add-keywords nil easy-escape--keywords) + (make-local-variable 'font-lock-extra-managed-props) + (add-to-list 'font-lock-extra-managed-props 'composition)) + (t (font-lock-remove-keywords nil easy-escape--keywords))) + (if (>= emacs-major-version 25) (font-lock-flush) (with-no-warnings (font-lock-fontify-buffer)))) (provide 'easy-escape)