]> git.eshelyaron.com Git - emacs.git/commitdiff
Font-lock shorthands in elisp-mode for quick visual recognition (bug#50959)
authorJoão Távora <joaotavora@gmail.com>
Sun, 3 Oct 2021 10:56:16 +0000 (11:56 +0100)
committerJoão Távora <joaotavora@gmail.com>
Sun, 3 Oct 2021 15:18:40 +0000 (16:18 +0100)
Only the shorthanded prefix is font-locked.  This allows the remainder
of the font-lock logic to subsist (e.g. for macro-defining symbols).

* lisp/shorthands.el (cl-lib): Require it when compiling.
(elisp-shorthand-font-lock-face): New face.
(shorthands--mismatch-from-end): New helper.
(shorthands-font-lock-shorthands): New helper.

* test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el:
Add some dummy test code.

lisp/shorthands.el
test/lisp/progmodes/elisp-mode-resources/simple-shorthand-test.el

index 6162efd6095a37c07b00aebf35b84b46ca45473f..f65704777761c32a0a0a56599f900dcd8eb3e825 100644 (file)
@@ -26,6 +26,7 @@
 
 ;;; Code:
 (require 'files)
+(eval-when-compile (require 'cl-lib))
 
 (defun hack-elisp-shorthands (fullname)
   "Return value of `elisp-shorthands' file-local variable in FULLNAME.
@@ -57,4 +58,42 @@ value of `elisp-shorthands', when it processes that file's Elisp code."
   (let ((elisp-shorthands (hack-elisp-shorthands fullname)))
     (load-with-code-conversion fullname file noerror nomessage)))
 
+\f
+;; FIXME: move this all to progmodes/elisp-mode.el?  OTOH it'd make
+;; more sense there, OTOH all the elisp font-lock stuff is actually in
+;; lisp/emacs-lisp/lisp-mode.el, which isn't right either.  So
+;; shorthand font-locking logic is probably better here for now.
+
+(defface elisp-shorthand-font-lock-face
+  '((t :inherit font-lock-keyword-face :foreground "cyan"))
+  "Face for highlighting shorthands in Emacs Lisp."
+  :version "28.1"
+  :group 'font-lock-faces)
+
+(defun shorthands--mismatch-from-end (str1 str2)
+  (cl-loop with l1 = (length str1) with l2 = (length str2)
+           for i from 1
+           for i1 = (- l1 i) for i2 = (- l2 i)
+           while (and (>= i1 0) (>= i2 0) (eq (aref str1 i1) (aref str2 i2)))
+           finally (return (1- i))))
+
+(defun shorthands-font-lock-shorthands (limit)
+  (when elisp-shorthands
+    (while (re-search-forward
+            (eval-when-compile
+              (concat "\\_<\\(" lisp-mode-symbol-regexp "\\)\\_>"))
+            limit t)
+      (let* ((existing (get-text-property (match-beginning 1) 'face))
+             (probe (and (not (memq existing '(font-lock-comment-face
+                                               font-lock-string-face)))
+                         (intern-soft (match-string 1))))
+             (sname (and probe (symbol-name probe)))
+             (mm (and sname (shorthands--mismatch-from-end
+                             (match-string 1) sname))))
+        (unless (or (null mm) (= mm (length sname)))
+          (add-face-text-property (match-beginning 1) (1+ (- (match-end 1) mm))
+                                  'elisp-shorthand-font-lock-face))))))
+
+(font-lock-add-keywords 'emacs-lisp-mode '((shorthands-font-lock-shorthands)) t)
+
 ;;; shorthands.el ends here
index ec568093af224880445f99b45c823c86faf856e2..29ee36a3151e8358116dee6219306077c370919c 100644 (file)
 
 (defvar f-test-complete-me 42)
 
+(elisp--foo-test3)
+
 (defun #_f-test4--- () 84)
 
+(defmacro f-define-test-5 ())
+
+;; should be font locked with both shorthand
+;; highlighting _and_ macro highlighting.
+(f-define-test-5)
+
 (when nil
   (f-test3)
   (f-test2)