1
Fork 0
mirror of git://git.sv.gnu.org/emacs.git synced 2025-12-06 06:20:55 -08:00

; Expand ELisp semantic highlighting documentation

* lisp/emacs-lisp/elisp-scope.el
(elisp-scope-get-symbol-role-property)
(elisp-scope-set-symbol-role-property)
(elisp-scope-safe-macro-p, elisp-scope-report-s)
(elisp-scope-1, elisp-scope-n): Add docstring.
(elisp-scope-analyze-form):
* lisp/progmodes/elisp-mode.el (elisp-fontify-semantically):
Expand docstring.
* etc/NEWS: Refer to 'elisp-fontify-semantically' for
documentation.
This commit is contained in:
Eshel Yaron 2025-10-02 14:19:37 +02:00
parent f0cab9d27e
commit cfc58025cd
No known key found for this signature in database
GPG key ID: EF3EE9CA35D78618
3 changed files with 91 additions and 8 deletions

View file

@ -47,6 +47,7 @@ NAME inherits properties that do not appear in PROPS from its PARENTS."
;;;###autoload
(defun elisp-scope-get-symbol-role-property (role prop)
"Return value of property PROP for symbol role ROLE."
(seq-some
(lambda (c) (plist-get (get c 'elisp-scope-role-properties) prop))
(elisp-scope--all-reachable-symbol-roles role)))
@ -64,6 +65,7 @@ NAME inherits properties that do not appear in PROPS from its PARENTS."
;;;###autoload
(defun elisp-scope-set-symbol-role-property (role prop value)
"Set value of property PROP for symbol role ROLE to VALUE."
(put role 'elisp-scope-role-properties
(plist-put (get role 'elisp-scope-role-properties) prop value)))
@ -1615,6 +1617,12 @@ trusted code macro expansion is always safe."
rx cl-macrolet nnoo-define-basics))
(defun elisp-scope-safe-macro-p (macro)
"Check whether it is safe to expand MACRO, return non-nil iff so.
If MACRO is one of the macros in `elisp-scope-unsafe-macros', then it is
never considered safe. Otherwise, MACRO is safe if it specified in
`elisp-scope-safe-macros', or if it has a non-nil `safe-macro' symbol
property, or if the current buffer is trusted (see `trusted-content-p')."
(and (not (memq macro elisp-scope-unsafe-macros))
(or (eq elisp-scope-safe-macros t)
(memq macro elisp-scope-safe-macros)
@ -1645,7 +1653,7 @@ trusted code macro expansion is always safe."
(defmacro elisp-scope-define-macro-analyzer (fsym args &rest body)
(declare (indent defun))
(let* ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1"))))
(let ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1"))))
`(progn
(defun ,helper ,args ,@body)
(elisp-scope-define-analyzer ,fsym (f &rest args)
@ -1654,7 +1662,7 @@ trusted code macro expansion is always safe."
(defmacro elisp-scope-define-special-form-analyzer (fsym args &rest body)
(declare (indent defun))
(let* ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1"))))
(let ((helper (intern (concat "elisp-scope--analyze-" (symbol-name fsym) "-1"))))
`(progn
(defun ,helper ,args ,@body)
(elisp-scope-define-analyzer ,fsym (f &rest args)
@ -2660,12 +2668,52 @@ trusted code macro expansion is always safe."
(put 'unwind-protect 'elisp-scope-analyzer #'elisp-scope--analyze-prog1)
(defun elisp-scope-report-s (sym role)
"Report that symbol SYM has role ROLE.
If SYM is not a symbol with position information, do nothing."
(when-let* ((beg (elisp-scope-sym-pos sym)) (bare (bare-symbol sym)))
(elisp-scope-report role beg (length (symbol-name bare)))))
(defvar-local elisp-scope-buffer-file-name nil)
(defun elisp-scope-1 (form &optional outtype)
"Analyze FORM as an evaluated form with expected output type OUTTYPE.
If OUTTYPE is non-nil, it specifies FORM's expected \"output type\".
This guides the analysis of quoted (sub)forms.
OUTTYPE can be one the following:
- t: FORM evaluates to an arbitrary object.
In other words, OUTTYPE of t conveys no information about FORM.
- `code': FORM evaluates to a form to be evaluated elsewhere.
The quoted output of FORM will again be analyzed as an evaluated form,
in a \"clean\" local environment.
- (symbol . ROLE): FORM evaluates to a symbol with role ROLE.
See `elisp-scope-define-symbol-role' for more information about
defining new symbol roles.
- (repeat . TYPE): FORM evaluates to a list with elements of type TYPE.
- (cons CARTYPE . CDRTYPE): FORM evaluates to a cons cell whose `car'
has type CARTYPE and whose `cdr' has type CDRTYPE.
- (equal . VAL): FORM evaluates to VAL (or something `equal' to VAL).
- (or . TYPES): FORM evaluates to a value that matches one of TYPES.
For example, to analyze a FORM that evaluates to either a list of major
mode names or just to a single major mode name, use OUTTYPE as follows:
(elisp-scope-1 FORM \\='(or (repeat . (symbol . major-mode))
(symbol . major-mode)))
If FORM in this example is (if (something-p) \\='foo \\='(bar baz)),
then all of `foo', `bar' and `baz' will be analyzed as major mode names.
See also `elisp-scope-analyze-form' for an details about how subforms
are analyzed."
(cond
((consp form)
(let* ((f (car form)) (bare (elisp-scope-sym-bare f))
@ -2706,9 +2754,13 @@ trusted code macro expansion is always safe."
(when elisp-scope-assume-func (elisp-scope-n forms)))))))
((symbol-with-pos-p form) (elisp-scope-s form))))
(defun elisp-scope-n (body &optional outtype)
(while (cdr-safe body) (elisp-scope-1 (pop body)))
(when-let* ((form (car-safe body))) (elisp-scope-1 form outtype)))
(defun elisp-scope-n (forms &optional outtype)
"Analyze FORMS as evaluated forms.
OUTTYPE is the expected output type of the last form in FORMS, if any.
It is passed to `elisp-scope-1', which see."
(while (cdr-safe forms) (elisp-scope-1 (pop forms)))
(when-let* ((form (car-safe forms))) (elisp-scope-1 form outtype)))
;;;###autoload
(defun elisp-scope-analyze-form (callback &optional stream)
@ -2727,7 +2779,23 @@ the symbol as it appears in STREAM.
If STREAM is nil, it defaults to the current buffer.
This function recursively analyzes Lisp forms (HEAD . TAIL), usually
starting with a top-level form, by inspecting HEAD at each level."
starting with a top-level form, by inspecting HEAD at each level:
- If HEAD is a symbol with a non-nil `elisp-scope-analyzer' symbol
property, then the value of that property specifies an analzyer
function AF that is called as (AF HEAD . TAIL) to analyze the form.
The analyzer function can use `elisp-scope-report-s', `elisp-scope-1'
and `elisp-scope-n' to analyze its arguments.
- If HEAD satisfies `functionp', which means it is a function in the
running Emacs session, analzye the form as a function call.
- If HEAD is a safe macro (see `elisp-scope-safe-macro-p'), expand it
and analyzes the resulting form.
- If HEAD is unknown, then the arguments in TAIL are ignored, unless
`elisp-scope-assume-func' is non-nil, in which case they are analyzed
as evaluated forms (i.e. HEAD is assumed to be a function)."
(let ((elisp-scope-counter 0)
(elisp-scope-callback callback)
(read-symbol-shorthands nil)