branch: master commit d8859208d5ef9b2cf7734d601edf937e45b098a9 Merge: 127b312 ef461da Author: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com> Commit: Jackson Ray Hamilton <jack...@jacksonrayhamilton.com>
Merge branch 'feature/comments-and-strings' into develop --- README.md | 32 +++++------- context-coloring.el | 23 +++++---- languages/javascript/scopifier.js | 12 ---- scopifier.png | Bin 2516 -> 2609 bytes screenshot.png | Bin 21829 -> 22006 bytes test/context-coloring-test.el | 96 +++++++++++++++++++++++++------- test/fixtures/comments-and-strings.js | 3 + 7 files changed, 104 insertions(+), 62 deletions(-) diff --git a/README.md b/README.md index b2e2c57..bb53dde 100644 --- a/README.md +++ b/README.md @@ -9,20 +9,21 @@ Highlights code according to function context. - Code in the global scope is one color. Code in functions within the global scope is a different color, and code within such functions is another color, and so on. -- Identifiers retain the color of the scope in which they were declared. -- Comments are a neutral color. +- Identifiers retain the color of the scope in which they are declared. Lexical scope information at-a-glance can assist a programmer in understanding -the overall structure of a program. It can also help curb nasty bugs like name -shadowing or unexpected assignment. A rainbow can indicate excessive -complexity. A spot of contrast followed by an assignment expression could be a -side-effect. The state of a closure could be undergoing change. +the overall structure of a program. It can help to curb nasty bugs like name +shadowing. A rainbow can indicate excessive complexity. State change within a +closure is easily monitored. -This coloring strategy is probably more useful than conventional *syntax* -highlighting. Highlighting keywords can help one to detect spelling errors, and -highlighting the content between quotation marks can alert one to unclosed -string literals. But a [linter][] could also spot those errors, and if -integrated via [flycheck][], an extra spot opens up in your editing toolbelt. +By default, Context Coloring still highlights comments and strings +syntactically. It is still easy to differentiate code from non-code, and strings +cannot be confused for variables. + +This coloring strategy is probably more useful than conventional syntax +highlighting. Highlighting keywords can help one to detect spelling errors, but +a [linter][] could also spot those errors, and if integrated with [flycheck][], +an extra spot opens up in your editing toolbelt. Give context coloring a try; you may find that it *changes the way you write code*. @@ -31,14 +32,7 @@ code*. - Supported languages: JavaScript - Light and dark (customizable) color schemes. -- Insanely fast for regular files, quick for big ones too. - - jQuery (9191 lines): 0.20 seconds (js2-mode), 0.57 seconds (js-mode) - - Lodash (6786 lines): 0.07 seconds (js2-mode), 0.35 seconds (js-mode) - - Async (1124 lines): 0.03 seconds (js2-mode), 0.17 seconds (js-mode) - - mkdirp (98 lines): 0.002 seconds (js2-mode), 0.09 seconds (js-mode) - -\* js2-mode parses idly, irrespective of this plugin; its benchmarks represent -coloring only. js-mode benchmarks represent parsing and coloring. +- Very fast for files under 1000 lines. ## Usage diff --git a/context-coloring.el b/context-coloring.el index 88660e0..d0579d1 100644 --- a/context-coloring.el +++ b/context-coloring.el @@ -51,6 +51,10 @@ Increase this if your machine is high-performing. Decrease it if it ain't. Supported modes: `js-mode', `js3-mode'" :group 'context-coloring) +(defcustom context-coloring-comments-and-strings t + "If non-nil, also color comments and strings using `font-lock'." + :group 'context-coloring) + (defcustom context-coloring-js-block-scopes nil "If non-nil, also color block scopes in the scope hierarchy in JavaScript. @@ -97,7 +101,6 @@ used.") ,doc :group 'context-coloring))) -(context-coloring-defface -1 "white" "#7f7f7f" "#7f7f7f") (context-coloring-defface 0 "white" "#000000" "#ffffff") (context-coloring-defface 1 "yellow" "#007f80" "#ffff80") (context-coloring-defface 2 "green" "#001580" "#cdfacd") @@ -139,9 +142,6 @@ Determines level at which to cycle through faces again." (dolist (pair pairs) (let ((level (car pair)) (color (cdr pair))) - (cond - ((eq level 'comment) - (setq level -1))) (set-face-foreground (context-coloring-face-symbol level) color)))) (defsubst context-coloring-level-face (level) @@ -159,6 +159,11 @@ END (exclusive) with the face corresponding to LEVEL." end `(face ,(context-coloring-level-face level)))) +(defsubst context-coloring-maybe-colorize-comments-and-strings () + (when context-coloring-comments-and-strings + (save-excursion + (font-lock-fontify-syntactically-region (point-min) (point-max))))) + ;;; js2-mode colorization @@ -216,10 +221,6 @@ generated by js2-mode." (lambda (node end-p) (when (null end-p) (cond - ((js2-comment-node-p node) - (context-coloring-js2-colorize-node - node - -1)) ((js2-scope-p node) (context-coloring-js2-colorize-node node @@ -238,7 +239,8 @@ generated by js2-mode." node (context-coloring-js2-scope-level defining-scope)))))) ;; The `t' indicates to search children. - t))))) + t))) + (context-coloring-maybe-colorize-comments-and-strings))) ;;; Shell command scopification / colorization @@ -256,7 +258,8 @@ level. The vector is flat, with a new token occurring after every (elt tokens i) (elt tokens (+ i 1)) (elt tokens (+ i 2))) - (setq i (+ i 3)))))) + (setq i (+ i 3)))) + (context-coloring-maybe-colorize-comments-and-strings))) (defun context-coloring-parse-array (input) "Specialized JSON parser for a flat array of numbers." diff --git a/languages/javascript/scopifier.js b/languages/javascript/scopifier.js index 6b46392..0171ab2 100644 --- a/languages/javascript/scopifier.js +++ b/languages/javascript/scopifier.js @@ -11,7 +11,6 @@ function scopifier(code) { var analyzedScopes, ast, - comment, definition, definitionsCount, definitionsIndex, @@ -30,7 +29,6 @@ function scopifier(code) { // Gracefully handle parse errors by doing nothing. try { ast = esprima.parse(code, { - comment: true, range: true }); analyzedScopes = escope.analyze(ast).scopes; @@ -109,16 +107,6 @@ function scopifier(code) { } } - for (i = 0; i < ast.comments.length; i += 1) { - comment = ast.comments[i]; - range = comment.range; - tokens.push( - range[0] + 1, - range[1] + 1, - -1 - ); - } - return scopes.concat(tokens); } diff --git a/scopifier.png b/scopifier.png index 1d690cb..1ec5d10 100644 Binary files a/scopifier.png and b/scopifier.png differ diff --git a/screenshot.png b/screenshot.png index fe45d9b..89665b7 100644 Binary files a/screenshot.png and b/screenshot.png differ diff --git a/test/context-coloring-test.el b/test/context-coloring-test.el index 52a93fb..64ed6e4 100644 --- a/test/context-coloring-test.el +++ b/test/context-coloring-test.el @@ -14,7 +14,11 @@ (defun context-coloring-test-read-file (path) (get-string-from-file (context-coloring-test-resolve-path path))) +(defun context-coloring-test-setup () + (setq context-coloring-comments-and-strings nil)) + (defun context-coloring-test-cleanup () + (setq context-coloring-comments-and-strings t) (setq context-coloring-after-colorize-hook nil) (setq context-coloring-js-block-scopes nil)) @@ -24,6 +28,7 @@ FIXTURE." `(with-temp-buffer (unwind-protect (progn + (context-coloring-test-setup) (insert (context-coloring-test-read-file ,fixture)) ,@body) (context-coloring-test-cleanup)))) @@ -43,12 +48,15 @@ is done." (kill-buffer temp-buffer)) (set-buffer previous-buffer)))))) -(defun context-coloring-test-with-fixture-async (fixture callback) +(defun context-coloring-test-with-fixture-async (fixture callback &optional setup) "Evaluate CALLBACK in a temporary buffer with the relative FIXTURE. A teardown callback is passed to CALLBACK for it to -invoke when it is done." +invoke when it is done. An optional SETUP callback can be passed +to run arbitrary code before the mode is invoked." (context-coloring-test-with-temp-buffer-async (lambda (done-with-temp-buffer) + (context-coloring-test-setup) + (if setup (funcall setup)) (insert (context-coloring-test-read-file fixture)) (funcall callback @@ -56,7 +64,7 @@ invoke when it is done." (context-coloring-test-cleanup) (funcall done-with-temp-buffer)))))) -(defun context-coloring-test-js-mode (fixture callback) +(defun context-coloring-test-js-mode (fixture callback &optional setup) (context-coloring-test-with-fixture-async fixture (lambda (done-with-test) @@ -64,7 +72,8 @@ invoke when it is done." (context-coloring-mode) (context-coloring-colorize (lambda () - (funcall callback done-with-test)))))) + (funcall callback done-with-test)))) + setup)) (defmacro context-coloring-test-js2-mode (fixture &rest body) `(context-coloring-test-with-fixture @@ -76,27 +85,46 @@ invoke when it is done." (context-coloring-mode) ,@body)) +(defmacro context-coloring-test-assert-region (&rest body) + `(let ((i 0) + (length (- end start))) + (while (< i length) + (let* ((point (+ i start)) + (face (get-text-property point 'face)) + actual-level) + ,@body) + (setq i (+ i 1))))) + (defconst context-coloring-test-level-regexp "context-coloring-level-\\([[:digit:]]+\\)-face") (defun context-coloring-test-assert-region-level (start end level) - (let ((i 0) - (length (- end start))) - (while (< i length) - (let* ((point (+ i start)) - (face (get-text-property point 'face)) - actual-level) - (when (not (when face - (let* ((face-string (symbol-name face)) - (matches (string-match context-coloring-test-level-regexp face-string))) - (when matches - (setq actual-level (string-to-number (substring face-string - (match-beginning 1) - (match-end 1)))) - (= level actual-level))))) - (ert-fail (format "Expected level in region [%s, %s), which is \"%s\", to be %s; but at point %s, it was %s" - start end (buffer-substring-no-properties start end) level point actual-level)))) - (setq i (+ i 1))))) + (context-coloring-test-assert-region + (when (not (when face + (let* ((face-string (symbol-name face)) + (matches (string-match context-coloring-test-level-regexp face-string))) + (when matches + (setq actual-level (string-to-number (substring face-string + (match-beginning 1) + (match-end 1)))) + (= level actual-level))))) + (ert-fail (format "Expected level in region [%s, %s), which is \"%s\", to be %s; but at point %s, it was %s" + start end (buffer-substring-no-properties start end) level point actual-level))))) + +(defun context-coloring-test-assert-region-face (start end expected-face) + (context-coloring-test-assert-region + (when (not (eq face expected-face)) + (ert-fail (format "Expected face in region [%s, %s), which is \"%s\", to be %s; but at point %s, it was %s" + start end (buffer-substring-no-properties start end) expected-face point face))))) + +(defun context-coloring-test-assert-region-comment-delimiter (start end) + (context-coloring-test-assert-region-face start end 'font-lock-comment-delimiter-face)) + +(defun context-coloring-test-assert-region-comment (start end) + (context-coloring-test-assert-region-face start end 'font-lock-comment-face)) + +(defun context-coloring-test-assert-region-string (start end) + (context-coloring-test-assert-region-face start end 'font-lock-string-face)) (defun context-coloring-test-assert-message (expected) (with-current-buffer "*Messages*" @@ -252,4 +280,30 @@ invoke when it is done." "./fixtures/key-values.js" (context-coloring-test-js-key-values))) +(defun context-coloring-test-js-comments-and-strings () + (context-coloring-test-assert-region-comment-delimiter 1 4) + (context-coloring-test-assert-region-comment 4 8) + (context-coloring-test-assert-region-comment-delimiter 9 12) + (context-coloring-test-assert-region-comment 12 19) + (context-coloring-test-assert-region-string 20 32) + (context-coloring-test-assert-region-level 32 33 0)) + +(ert-deftest-async context-coloring-test-js-mode-comments-and-strings (done) + (context-coloring-test-js-mode + "./fixtures/comments-and-strings.js" + (lambda (teardown) + (unwind-protect + (context-coloring-test-js-comments-and-strings) + (funcall teardown)) + (funcall done)) + (lambda () + (setq context-coloring-comments-and-strings t)))) + +(ert-deftest context-coloring-test-js2-mode-comments-and-strings () + (context-coloring-test-js2-mode + "./fixtures/comments-and-strings.js" + (setq context-coloring-comments-and-strings t) + (context-coloring-colorize) + (context-coloring-test-js-comments-and-strings))) + (provide 'context-coloring-test) diff --git a/test/fixtures/comments-and-strings.js b/test/fixtures/comments-and-strings.js new file mode 100644 index 0000000..9910b02 --- /dev/null +++ b/test/fixtures/comments-and-strings.js @@ -0,0 +1,3 @@ +// Foo. +/* Bar. */ +'use strict';