;; A major mode for JavaScript. ;; ;; Usage for your Emacs initialization file: ;; ;; (require 'js-deprecated-mode) ;; ;; PUBLIC at `http://reluk.ca/sys/computer/workstation/etc/emacs/` because my Emacs initialization ;; file refers to it there. http://reluk.ca/.emacs.d/lisp/initialization.el (require 'java-deprecated-mode) ;; ══════════════════════════════════════════════════════════════════════════════════════════════════════ ;; D e c l a r a t i o n s i n l e x i c o g r a p h i c o r d e r ;; ══════════════════════════════════════════════════════════════════════════════════════════════════════ (defun js-deprecated--add-font-lock-keywords() "Adds all font lock keywords for mode `js-deprecated`." (defvar js-deprecated--font-lock-added); [FV] (java-deprecated-add-font-lock-js-common) (font-lock-add-keywords nil js-deprecated--font-lock-added)) ;;; Unable to use `font-lock-defaults`, q.v. below, I use `font-lock-add-keywords` only. (defconst js-deprecated--font-lock-added `( ;; Arrow function ;; -------------- (")[ \t]*\\(=>\\)" 1 'java-deprecated-subdued) ;; Class declaration ;; ----------------- ("\\<\\(class\\)[ \t]+\\([[:upper:]][[:alnum:]_]*\\)\\(?:[ \t]+\\(extends\\)\\>\\)?" (1 'default)(2 'font-lock-type-face)(3 'java-deprecated-subdued nil t)) ("\\" 1 'java-deprecated-subdued) ;;; Anonymous subclass declaration such as: foo = new class extends Foo { ... } ;; Debuggery boilerplate ;; --------------------- ("\\" . 'default) ; Apparently some of these (final) were faced because they are obsolete keywords. ;;; https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Lexical_grammar ("\\" . 'font-lock-warning-face) ; My uses of `var` are almost always unwanted, accidental ("\\" 1 'default) ;; For statement ;; ------------- ("[[:alpha:]_][[:alnum:]_]*[ \t]+\\(of\\)[ \t]+[[:alpha:]_]" 1 'java-deprecated-subdued) ;; Getter or setter ;; ---------------- ("^[ \t]*\\(?:get\\|set\\)[ \t]+\\([[:alpha:]_][[:alnum:]_]*\\)[ \t]*(" 1 'font-lock-variable-name-face) ;; *instanceof* phrase ;; ------------------- ("\\<\\(instanceof\\)[ \t]+\\([[:alpha:]_][[:alnum:]_]*\\)" (1 'default)(2 'default)) ;; Keywords ;; -------- "\\" ;; default : Though (somehow) correctly faced by default, ;; this explicit refacing precludes clobbering by § Label declaration § DC, below ;; Label declaration ;; ----------------- ;;;("^[ \t]*\\(\\w+\\)[ \t]*:[ \t]*$" ;;;;; Rather allow the label to be followed by a statement on the same line: ("^[ \t]*\\(\\w+\\)[ \t]*:" (1 'font-lock-constant-face)) ;;; Side-effects of this: (lookaround assertions might have helped here, if Emacs supported them) ;;; DC) Clobbers the *default* clause in *switch* statements. Now precluded in § Keywords, above. ;;; PD) Clobbers property declarations in object initializers. They have a like form (NAME: VALUE,). ;;; Here is a partial fix, namely where it clobbers a function declaration. ("^[ \t]*\\(\\w+\\)[ \t]*:[ \t]*function[ \t]*(" (1 'font-lock-function-name-face t)) ;; Label reference ;; --------------- ;;;("\\<\\(?:break\\|case\\|continue\\|goto\\)[ \t]*\\([[:alpha:]_][[:alnum:]_]*\\)" ;;;;;;; Why 'case'? no label follows it ("\\<\\(?:break\\|continue\\|goto\\)[ \t]*\\([[:alpha:]_][[:alnum:]_]*\\)" 1 'font-lock-constant-face) ;; Method ;; ------ ;;;("^[ \t]*\\([[:alpha:]_][[:alnum:]_]*\\)[ \t]*([^)\n]*)[ \t]*$" 1 'font-lock-function-name-face) ;;;;;; Sadly that also faces statements such as "if( )" ;; Some forms will be difficult to distinguish from a function call, e.g. one with a multi-line ;; declaration of parameters. ;; Module-pattern export declarations via such as `FooBar_expo` or `expo` ;; ---------------------------------- ("^[ \t]*\\(?:[A-Z][[:alnum:]_]*_\\)?expo.\\([[:alpha:]_][[:alnum:]_]*\\)[ \t]+=[ \t]*function[ \t]*(" 1 'font-lock-function-name-face t) ;; Cannot easily do field/property declarations here; to distinguish an initialization ;; `expo.foo = x;` from a subsequent change `expo.foo = y;` would be difficult. ) "Font lock keywords for `js-deprecated` mode which are added to those of the parent mode." ) (define-derived-mode js-deprecated-mode js-mode "JavaScript MCA" "Major mode for editing JavaScript source code" ;(setq-local font-lock-defaults '(js-deprecated--font-lock-added)) ;;; (a) yields only js-deprecated--font-lock-added ;(setq-local font-lock-defaults (append '(js-deprecated--font-lock-added) font-lock-defaults)) ;(setq-local font-lock-defaults (append '(js-deprecated--font-lock-added) '(js--font-lock-keywords))) ;;; (b) both yield as (a), but now without strings, comments, and other syntax-table stuff ;;; With these failures, I fall back to using *font-lock-add-keywords* again, as do others, ;;; https://stackoverflow.com/a/14887163/2402790. This despite the warning, ;;; "Major mode commands must not call font-lock-add-keywords under any circumstances" ;;; https://www.gnu.org/software/emacs/manual/html_node/elisp/Customizing-Keywords.html#Customizing-Keywords (js-deprecated--add-font-lock-keywords) ) (provide 'js-deprecated-mode) ;; SALVAGE ;; ─────── ;; (require 'java-deprecated-mode) ;; (define-derived-mode js-deprecated-mode java-deprecated-mode ;; ;; (setq font-lock-maximum-decoration '((js-deprecated-mode . 1))) ; per java-deprecated-mode ;; (add-common-java-font-lock) ;; ;;; Added first, common ones get lower precedence. ;; (font-lock-add-keywords ;; nil ;; '( ;; ;; Keyword ;; ("\\<\\(each\\)\\>" . 'font-lock-keyword-face) ;; ("\\b\\(exit\\) *(" (1 'font-lock-keyword-face)) ; Nashorn ;; ("\\<\\(in\\)\\>" . 'java-deprecated-subdued) ;; ;; ;; Function declarations ;; ("\\(?:^\\|[ \t]\\)\\(function\\) +\\([a-z_]\\w*\\)(" (1 'java-deprecated-subdued) ;; (2 'font-lock-function-name-face)) ;; ("\\(?:^\\|[ \t]\\)\\([a-z_]\\w*\\) *: *\\(function\\)(" ;; (1 'font-lock-function-name-face)(2 'java-deprecated-subdued)) ; for closures in module pattern ;; ("\\(?:^\\|[ \t]\\)\\(\\(?:[a-z]+\\.\\)+\\)?\\([a-z_]\\w*\\) *= *\\(function\\)(" ;; (1 'java-deprecated-subdued t t)(2 'font-lock-function-name-face)(3 'java-deprecated-subdued)) ; for closures in module pattern ;; ;; ;; Variable declarations ;; ; ("\\[^(]" 1 'font-lock-variable-name-face) ;; ;; but unless it causes a problem, do allow leading uppercase on variable names, ;; ;; e.g. for sake of type variables: var System = Java.type( 'java.lang.System' ); ;; ("\\[^(]" 1 'font-lock-variable-name-face) ;; ; ("\\(?:^\\|[ \t]\\)\\(my\\.\\|our\\.\\)\\([a-z_]\\w*\\) *= *(" (1 'java-deprecated-subdued) ;; ; (2 'font-lock-variable-name-face)) ; for closures in module pattern ;; ;; overkill ;; ;; ;; Debugging boilerplate ;; ("\\bvar toDebug = \\(?:local\\.\\)?Local\\.toDebug[(][)];" 0 'font-lock-comment-face t) ;; ("\\bif[(] \\(?:\\w+\\.\\)?toDebug\\(?:[(][)]\\)? [)].+;" 0 'font-lock-comment-face t) ;; ;;; per toDebug /usr/local/lib/Local.js ;; ; ("\\b\\(?:\\w+\\.\\)?report[(].+?[)];" 0 'font-lock-comment-face t) ; old Votorola `bridgeFooting.js` ;; ;; )) ;; NOTE ;; ──── ;; FV · Suppressing sporadic compiler warnings ‘reference to free variable’ ;; or ‘assignment to free variable’. ;; This file has been dedicated by its author(s) to the public domain. To the extent possible ;; by law, the author(s) have waived all of their copyright and related or neighbouring rights to ;; this file under the terms of CC0 1.0. http://creativecommons.org/publicdomain/zero/1.0/ ;; The author(s) are: ;; ;; Michael Allan, mike@reluk.ca, http://reluk.ca/ ;; ;; Other authors who make further, substantial contributions to this file, and who wish to dedicate ;; their contributions to the public domain, should append their names to the list above.