Files
Eshel Yaron 551231bb53 elisp-scope.el: Add variable value specifications
We add a symbol property 'elisp-scope-variable-spec', which
holds a specification for the values of a variable with that
property.  For example, (put 'foo '(symbol . face)) says
that the value of variable 'foo' is a face name.
This allows elisp-scope.el to analyze forms such as
(setq foo 'bar) and (let ((foo 'bar)) ...) more accurately.
This is also used for analyzing macros that let-bind (one of)
their arguments to a specific special variable, such as
'with-connection-local-application-variables'.

We initially add this new property to some common variables.

* lisp/emacs-lisp/elisp-scope.el: Add
'elisp-scope-variable-spec' property to
'coding-system-for-read/write' and 'major-mode'.
(elisp-scope--variable-spec): New defsubst.
(elisp-scope--let-1, elisp-scope-let*, elisp-scope-setq):
Use it.
* test/lisp/progmodes/elisp-mode-resources/semantic-highlighting.el:
Add test form.
2026-02-18 19:42:47 +01:00

190 lines
7.4 KiB
EmacsLisp

;;; semantic-highlighting.el --- -*- lexical-binding: t; -*-
(defun foo (bar)
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ (elisp-defun font-lock-function-name-face)
;; ^ elisp-binding-variable
(let ((cpa current-prefix-arg))
;; ^ (elisp-special-form font-lock-keyword-face)
;; ^ elisp-binding-variable
;; ^ elisp-free-variable
(or cpa (ignore bar)))
;; ^ (elisp-special-form font-lock-keyword-face)
;; ^ elisp-bound-variable
;; ^ elisp-function
;; ^ elisp-bound-variable
)
(add-face-text-property
;; ^ elisp-function
(point) (mark)
;; ^ elisp-function
;; ^ elisp-function
(if not-good
;; ^ (elisp-special-form font-lock-keyword-face)
;; ^ elisp-free-variable
'error
;; ^ elisp-face
(message "Good.")
;; ^ elisp-function
'success))
;; ^ elisp-face
(require 'cl-lib)
;; ^ (elisp-function font-lock-keyword-face)
;; ^ (elisp-feature font-lock-constant-face)
;; Taken from `completion-shorthand-try-completion' in minibuffer.el:
(defun foobaz (string table pred point)
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ (elisp-defun font-lock-function-name-face)
;; ^ ^ ^ ^ elisp-binding-variable
(cl-loop with expanded
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ elisp-binding-variable
for (short . long) in
;; ^ elisp-binding-variable
;; ^ elisp-binding-variable
(with-current-buffer minibuffer--original-buffer
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ elisp-free-variable
read-symbol-shorthands)
;; ^ elisp-free-variable
for probe =
;; ^ elisp-binding-variable
(and (> point (length short))
;; ^ (elisp-special-form font-lock-keyword-face)
;; ^ elisp-function
;; ^ elisp-bound-variable
;; ^ elisp-function
;; ^ elisp-bound-variable
(string-prefix-p short string)
;; ^ elisp-function
;; ^ elisp-bound-variable
;; ^ elisp-bound-variable
(try-completion (setq expanded
;; ^ elisp-function
;; ^ (elisp-special-form font-lock-keyword-face)
;; ^ elisp-bound-variable
(concat long
;; ^ elisp-function
;; ^ elisp-bound-variable
(substring
;; ^ elisp-function
string
;; ^ elisp-bound-variable
(length short))))
;; ^ elisp-function
;; ^ elisp-bound-variable
table pred))
;; ^ elisp-bound-variable
;; ^ elisp-bound-variable
when probe
;; ^ elisp-bound-variable
do (message "Shorthand expansion")
;; ^ elisp-function
and return (cons expanded (max (length long)
;; ^ elisp-function
;; ^ elisp-bound-variable
;; ^ elisp-function
;; ^ elisp-function
;; ^ elisp-bound-variable
(+ (- point (length short))
;; ^ elisp-function
;; ^ elisp-function
;; ^ elisp-function
;; ^ elisp-bound-variable
(length long))))))
;; ^ elisp-function
;; ^ elisp-bound-variable
(let ((foo 'bar))
;; ^ (elisp-special-form font-lock-keyword-face)
;; ^ elisp-binding-variable
(cl-flet ((foo () 'baz))
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ elisp-function
(foo)
;; ^ elisp-function
(cl-macrolet ((foo () 'foo))
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ elisp-macro
(foo))))
;; ^ elisp-macro
(when-let* ((foo (symbol-at-point))
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ elisp-binding-variable
;; ^ elisp-function
current-prefix-arg
;; ^ elisp-shadowing-variable
((commandp foo)))
;; ^ elisp-function
;; ^ elisp-bound-variable
foo)
;; ^ elisp-bound-variable
;; Taken from minibuffer.el:
(defcustom my-foo nil
;; ^ (elisp-macro font-lock-keyword-face)
;; ^ (elisp-defvar font-lock-variable-name-face)
"Foo."
:type '(choice (const :tag "No special message handling" nil)
;; ^ elisp-widget-type
;; ^ elisp-widget-type
(repeat
;; ^ elisp-widget-type
(choice (function-item :tag "Inhibit some messages"
;; ^ elisp-widget-type
;; ^ elisp-widget-type
inhibit-message)
;; ^ elisp-function
(function-item :tag "Accumulate messages"
set-multi-message)
;; ^ elisp-function
(function-item :tag "Handle minibuffer"
set-minibuffer-message)
;; ^ elisp-function
(function :tag "Custom function")
;; ^ (elisp-widget-type font-lock-keyword-face)
)))
:version "29.1")
;; Taken from browse-url.el:
(defcustom baz-opt 'browse-url-mail
"Baz."
:type '(function-item :tag "Emacs Mail" :value browse-url-mail))
;; ^ elisp-widget-type
;; ^ (elisp-constant font-lock-builtin-face)
(e-s-analyze-form #'ignore)
;; ^ (elisp-shorthand-font-lock-face elisp-function)
;; ^ elisp-function
;; ^ elisp-function
(defface foobar
'((default :inherit font-lock-function-call-face)
;; ^ (elisp-constant font-lock-builtin-face)
;; ^ elisp-face
(((background light)) :foreground "#00008b")
(((background dark)) :foreground "#5c9cff"))
"Face for highlighting symbol role names in Emacs Lisp code."
:version "31.1")
;; ^ (elisp-constant font-lock-builtin-face)
(propertize foo
'face
(cond
((random) '(success (:foreground "green" :inherit default)))
;; ^ elisp-face
;; ^ elisp-face
((foobar) 'font-lock-keyword-face)
;; ^ elisp-face
(t '(:inherit error))))
;; ^ elisp-face
;; From desktop.el:
(let ((coding-system-for-write 'utf-8-emacs))
;; ^ elisp-coding
(write-region (point-min) (point-max) (desktop-full-file-name) nil 'nomessage))