branch: master commit 841aac4767d49a8f24dc7b1bebd0bd59abc062f7 Author: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com> Commit: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com>
Add eval-expression support. --- README.md | 10 +++- context-coloring.el | 87 ++++++++++++++++++++++++++-------------- test/context-coloring-test.el | 27 +++++++++++++ 3 files changed, 90 insertions(+), 34 deletions(-) diff --git a/README.md b/README.md index 40506e7..568be45 100644 --- a/README.md +++ b/README.md @@ -21,6 +21,7 @@ By default, comments and strings are still highlighted syntactically. - `defun`, `lambda`, `let`, `let*`, `cond`, `condition-case`, `defadvice`, `dolist`, `quote`, `backquote` and backquote splicing. - Instantaneous lazy coloring, 8000 lines-per-second full coloring. + - Works in `eval-expression` too. ## Installation @@ -68,14 +69,17 @@ Add the following to your init file: ```lisp ;; js-mode: -(add-hook 'js-mode-hook 'context-coloring-mode) +(add-hook 'js-mode-hook #'context-coloring-mode) ;; js2-mode: (add-to-list 'auto-mode-alist '("\\.js\\'" . js2-mode)) -(add-hook 'js2-mode-hook 'context-coloring-mode) +(add-hook 'js2-mode-hook #'context-coloring-mode) ;; emacs-lisp-mode: -(add-hook 'emacs-lisp-mode-hook 'context-coloring-mode) +(add-hook 'emacs-lisp-mode-hook #'context-coloring-mode) + +;; Minibuffer: +(add-hook 'eval-expression-minibuffer-setup-hook #'context-coloring-mode) ``` ## Customizing diff --git a/context-coloring.el b/context-coloring.el index fa85c43..42c1e68 100644 --- a/context-coloring.el +++ b/context-coloring.el @@ -993,44 +993,61 @@ point. It could be a quoted or backquoted expression." (max-specpdl-size (max max-specpdl-size 3000))) (context-coloring-elisp-colorize-region start end))) -(defun context-coloring-elisp-colorize () - "Color the current buffer, parsing elisp to determine its -scopes and variables." - (interactive) +(defun context-coloring-elisp-colorize-guard (callback) + "Silently color in CALLBACK." (with-silent-modifications (save-excursion (condition-case nil - (cond - ;; Just colorize the changed region. - (context-coloring-changed-p - (let* (;; Prevent `beginning-of-defun' from making poor assumptions. - (open-paren-in-column-0-is-defun-start nil) - ;; Seek the beginning and end of the previous and next - ;; offscreen defuns, so just enough is colored. - (start (progn (goto-char context-coloring-changed-start) - (while (and (< (point-min) (point)) - (pos-visible-in-window-p)) - (end-of-line 0)) - (beginning-of-defun) - (point))) - (end (progn (goto-char context-coloring-changed-end) - (while (and (> (point-max) (point)) - (pos-visible-in-window-p)) - (forward-line 1)) - (end-of-defun) - (point)))) - (context-coloring-elisp-colorize-region-initially start end) - ;; Fast coloring is nice, but if the code is not well-formed - ;; (e.g. an unclosed string literal is parsed at any time) then - ;; there could be leftover incorrectly-colored code offscreen. So - ;; do a clean sweep as soon as appropriate. - (context-coloring-schedule-coloring context-coloring-default-delay))) - (t - (context-coloring-elisp-colorize-region-initially (point-min) (point-max)))) + (funcall callback) ;; Scan errors can happen virtually anywhere if parenthesis are ;; unbalanced. Just swallow them. (`progn' for test coverage.) (scan-error (progn)))))) +(defun context-coloring-elisp-colorize () + "Color the current buffer, parsing elisp to determine its +scopes and variables." + (interactive) + (context-coloring-elisp-colorize-guard + (lambda () + (cond + ;; Just colorize the changed region. + (context-coloring-changed-p + (let* ( ;; Prevent `beginning-of-defun' from making poor assumptions. + (open-paren-in-column-0-is-defun-start nil) + ;; Seek the beginning and end of the previous and next + ;; offscreen defuns, so just enough is colored. + (start (progn (goto-char context-coloring-changed-start) + (while (and (< (point-min) (point)) + (pos-visible-in-window-p)) + (end-of-line 0)) + (beginning-of-defun) + (point))) + (end (progn (goto-char context-coloring-changed-end) + (while (and (> (point-max) (point)) + (pos-visible-in-window-p)) + (forward-line 1)) + (end-of-defun) + (point)))) + (context-coloring-elisp-colorize-region-initially start end) + ;; Fast coloring is nice, but if the code is not well-formed + ;; (e.g. an unclosed string literal is parsed at any time) then + ;; there could be leftover incorrectly-colored code offscreen. So + ;; do a clean sweep as soon as appropriate. + (context-coloring-schedule-coloring context-coloring-default-delay))) + (t + (context-coloring-elisp-colorize-region-initially (point-min) (point-max))))))) + +(defun context-coloring-eval-expression-colorize () + "Color the `eval-expression' minibuffer prompt as elisp." + (interactive) + (context-coloring-elisp-colorize-guard + (lambda () + (context-coloring-elisp-colorize-region-initially + (progn + (string-match "\\`Eval: " (buffer-string)) + (1+ (match-end 0))) + (point-max))))) + ;;; Shell command scopification / colorization @@ -1723,6 +1740,14 @@ precedence, i.e. the car of `custom-enabled-themes'." :setup #'context-coloring-setup-idle-change-detection :teardown #'context-coloring-teardown-idle-change-detection) +(context-coloring-define-dispatch + 'eval-expression + :modes '(minibuffer-inactive-mode) + :colorizer #'context-coloring-eval-expression-colorize + :delay 0.016 + :setup #'context-coloring-setup-idle-change-detection + :teardown #'context-coloring-teardown-idle-change-detection) + (defun context-coloring-dispatch (&optional callback) "Determine the optimal track for scopification / coloring of the current buffer, then execute it. diff --git a/test/context-coloring-test.el b/test/context-coloring-test.el index 7020589..cf985c9 100644 --- a/test/context-coloring-test.el +++ b/test/context-coloring-test.el @@ -234,6 +234,10 @@ ARGS)." :extension "el" :enable-context-coloring-mode t) +(context-coloring-test-define-deftest eval-expression + :mode #'fundamental-mode + :no-fixture t) + (context-coloring-test-define-deftest define-theme :mode #'fundamental-mode :no-fixture t @@ -1268,6 +1272,29 @@ nnnnn n nnn nnnnnnnn"))) 1111 111 nnnn nn"))) +(defun context-coloring-test-eval-expression-let () + "Test that coloring works inside `eval-expression.'" + (let ((input "(ignore-errors (let (a) (message a free)))")) + (insert input) + (context-coloring-colorize) + (context-coloring-test-assert-coloring " +xxxx: 0000000-000000 1111 111 11111111 1 0000110"))) + +(context-coloring-test-deftest-eval-expression let + (lambda () + (add-hook + 'eval-expression-minibuffer-setup-hook + #'context-coloring-test-eval-expression-let) + (execute-kbd-macro + (vconcat + [?\C-u] ;; Don't output to stdout. + [?\M-x] + (vconcat "eval-expression")))) + :after (lambda () + (remove-hook + 'eval-expression-minibuffer-setup-hook + #'context-coloring-test-eval-expression-let))) + (provide 'context-coloring-test) ;;; context-coloring-test.el ends here