branch: master commit 459987e2bcfd8d60456a69a770dbeeca4026a27a Author: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com> Commit: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com>
Generalize for different major modes. Remove dirty benchmarking. --- context-coloring.el | 93 +++++++++++++++++++++------------------- test/context-coloring-test.el | 18 +++++++- 2 files changed, 66 insertions(+), 45 deletions(-) diff --git a/context-coloring.el b/context-coloring.el index 4a022ba..c075f71 100644 --- a/context-coloring.el +++ b/context-coloring.el @@ -146,18 +146,32 @@ For example: \"context-coloring-level-1-face\"." "-face"))) +;;; Constants + +(defconst context-coloring-path + (file-name-directory (or load-file-name buffer-file-name)) + "This file's directory.") + + ;;; Customizable variables +(let ((javascript-scopifier `(:type shell-command + :executable "node" + :command ,(expand-file-name + "./bin/scopifier" + context-coloring-path)))) + (defcustom context-coloring-scopifier-plist + `(js-mode ,javascript-scopifier + js2-mode ,javascript-scopifier + js3-mode ,javascript-scopifier) + "Property list mapping major modes to scopification programs.")) + (defcustom context-coloring-delay 0.25 "Delay between a buffer update and colorization. Increase this if your machine is high-performing. Decrease it if it ain't." :group 'context-coloring) -(defcustom context-coloring-benchmark-colorization nil - "If non-nil, display how long each colorization took." - :group 'context-coloring) - ;;; Local variables @@ -175,20 +189,9 @@ is a reference to that one process.") "Indication that the buffer has changed recently, which would imply that it should be colorized again.") -(defvar-local context-coloring-start-time nil - "Used to benchmark colorization time.") - ;;; Scopification -(defconst context-coloring-path - (file-name-directory (or load-file-name buffer-file-name)) - "This file's directory.") - -(defconst context-coloring-scopifier-path - (expand-file-name "./bin/scopifier" context-coloring-path) - "Path to the external scopifier executable.") - (defun context-coloring-apply-tokens (tokens) "Processes TOKENS to apply context-based coloring to the current buffer. Tokens are 3 integers: start, end, level. The @@ -217,11 +220,10 @@ buffer." "Specialized JSON parser for a flat array of numbers." (vconcat (mapcar 'string-to-number (split-string (substring input 1 -1) ",")))) -(defun context-coloring-scopify () - "Invokes the external scopifier with the current buffer's -contents, reading the scopifier's response asynchronously and -applying a parsed list of tokens to -`context-coloring-apply-tokens'." +(defun context-coloring-scopify-shell-command (command) + "Invokes a scopifier with the current buffer's contents, +reading the scopifier's response asynchronously and applying a +parsed list of tokens to `context-coloring-apply-tokens'." ;; Prior running tokenization is implicitly obsolete if this function is ;; called. @@ -229,45 +231,52 @@ applying a parsed list of tokens to ;; Start the process. (setq context-coloring-scopifier-process - (start-process-shell-command "scopifier" nil context-coloring-scopifier-path)) + (start-process-shell-command "scopifier" nil command)) (let ((output "") - (buffer context-coloring-buffer) - (start-time context-coloring-start-time)) + (buffer context-coloring-buffer)) ;; The process may produce output in multiple chunks. This filter ;; accumulates the chunks into a message. - (set-process-filter context-coloring-scopifier-process - (lambda (process chunk) - (setq output (concat output chunk)))) + (set-process-filter + context-coloring-scopifier-process + (lambda (process chunk) + (setq output (concat output chunk)))) ;; When the process's message is complete, this sentinel parses it as JSON ;; and applies the tokens to the buffer. - (set-process-sentinel context-coloring-scopifier-process - (lambda (process event) - (when (equal "finished\n" event) - (let ((tokens (context-coloring-parse-array output))) - (with-current-buffer buffer - (context-coloring-apply-tokens tokens)) - (setq context-coloring-scopifier-process nil) - (when context-coloring-benchmark-colorization - (message "Colorized (after %f seconds)." (- (float-time) start-time)))))))) + (set-process-sentinel + context-coloring-scopifier-process + (lambda (process event) + (when (equal "finished\n" event) + (let ((tokens (context-coloring-parse-array output))) + (with-current-buffer buffer + (context-coloring-apply-tokens tokens)) + (setq context-coloring-scopifier-process nil)))))) ;; Give the process its input so it can begin. (process-send-region context-coloring-scopifier-process (point-min) (point-max)) (process-send-eof context-coloring-scopifier-process)) +(defun context-coloring-scopify () + "Determines the optimal track for scopification of the current +buffer, then scopifies the current buffer." + (let ((scopifier (plist-get context-coloring-scopifier-plist major-mode))) + (cond ((null scopifier) + (message "%s" "Context coloring is not available for this major mode")) + ((eq (plist-get scopifier :type) 'shell-command) + (let ((executable (plist-get scopifier :executable))) + (if (null (executable-find executable)) + (message "Context coloring executable \"%s\" not found" executable) + (context-coloring-scopify-shell-command (plist-get scopifier :command)))))))) + ;;; Colorization (defun context-coloring-colorize () "Colors the current buffer by function context." (interactive) - (when (executable-find "node") - (when context-coloring-benchmark-colorization - (setq context-coloring-start-time (float-time)) - (message "%s" "Colorizing...")) - (context-coloring-scopify))) + (context-coloring-scopify)) (defun context-coloring-change-function (start end length) "Registers a change so that a context-colored buffer can be @@ -305,10 +314,6 @@ colorizing would be redundant." ;; Remember this buffer. This value should not be dynamically-bound. (setq context-coloring-buffer (current-buffer)) - ;; Alert the user that the mode is not going to work. - (if (null (executable-find "node")) - (message "context-coloring-mode requires Node.js 0.10+ to be installed")) - ;; Colorize once initially. (context-coloring-colorize) diff --git a/test/context-coloring-test.el b/test/context-coloring-test.el index d997d8b..0cc128c 100644 --- a/test/context-coloring-test.el +++ b/test/context-coloring-test.el @@ -17,7 +17,6 @@ FIXTURE." `(with-temp-buffer (insert (context-coloring-test-read-file ,fixture)) - (context-coloring-mode) ,@body)) (defun context-coloring-test-region-level-p (start end level) @@ -31,10 +30,27 @@ FIXTURE." "-face"))))) (setq i (+ i 1))))) +(defun context-coloring-test-message-should-be (expected) + (with-current-buffer "*Messages*" + (let ((messages (split-string (buffer-substring-no-properties (point-min) (point-max)) "\n"))) + (let ((message (car (nthcdr (- (length messages) 2) messages)))) + (should (equal message expected)))))) + +(ert-deftest context-coloring-test-unsupported-mode () + (context-coloring-test-with-fixture + "./fixtures/function-scopes.js" + + (context-coloring-mode) + (context-coloring-test-message-should-be + "Context coloring is not available for this major mode"))) + (ert-deftest context-coloring-test-function-scopes () (context-coloring-test-with-fixture "./fixtures/function-scopes.js" + (js-mode) + (context-coloring-mode) + (sleep-for .25) ; Wait for asynchronous coloring to complete. (context-coloring-test-region-level-p 1 9 0)