emacs-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: master 5c70ff9: New user option 'font-lock-ignore'


From: Augusto Stoffel
Subject: Re: master 5c70ff9: New user option 'font-lock-ignore'
Date: Sat, 02 Apr 2022 13:18:40 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.92 (gnu/linux)

On Sat,  2 Apr 2022 at 13:01, Eli Zaretskii <eliz@gnu.org> wrote:

>> From: Augusto Stoffel <arstoffel@gmail.com>
>> Cc: Stefan Monnier <monnier@iro.umontreal.ca>,  emacs-devel@gnu.org
>> Date: Sat, 02 Apr 2022 09:34:25 +0200
>> 
>> >> +@example
>> >> +(@var{mode} @var{rule} @dots{})
>> >> +@end example
>> >> +
>> >> +Here, @var{mode} is a symbol, say a major or minor mode.
>> >
>> > Why "say"?  Can it usefully be something else? if so, what can it be?
>> 
>> This is easiest to explain with code.  A rule for a given xyz-mode
>> applies if
>> 
>>     (or (bound-and-true-p xyz-mode)
>>         (derived-mode-p xyz-mode))
>> 
>> Do you think it's better to just say “Here, @var{mode} a major or minor
>> mode”?  This would be slightly imprecise, because technically 'mode' can
>> be any variable.
>
> If MODE could be any symbol that is bound-and-true-p, does it mean
> that just by defining a variable with a non-nil value will trigger
> such a rule?

That is correct.  Of course there could be a conflict if a major mode
name is also bound as a variable.  I haven't seen this happen in nature.
However, if you have a better way to test whether a given symbol is a
minor mode and is on, we should definitely use it.

>> >> +subsequent rules apply if the current major mode is derived from
>> >> +@var{mode} or @var{mode} is bound and true as a variable.  Each
>> >> +@var{rule} can be one of the following:
>> >> +
>> >> +@table @code
>> >> +@cindex @var{font-lock-ignore} rules
>> >> +@item @var{symbol}
>> >> +A symbol, say a face name, matches any Font Lock keyword containing
>> >> +the symbol in its definition.
>> >
>> > I don't think I understand how can a keyword "contain" a symbol.
>> > Please elaborate or suggest a different text that clarifies this.
>> 
>> Okay, as a general remark, this feature has been bolted on the existing
>> font lock mechanism, and it shows.  So the user has to interact to some
>> degree with the font-lock internals to make any meaningful use of it.
>> 
>> Specifically regarding your question, the user has to be aware that
>> 'font-lock-keywords' is a list where (quoting the docstring):
>> 
>>     Each element [...] should have one of these forms:
>> 
>>      MATCHER
>>      (MATCHER . SUBEXP)
>>      (MATCHER . FACENAME)
>>      (MATCHER . HIGHLIGHT)
>>      (MATCHER HIGHLIGHT ...)
>>      (eval . FORM)
>> 
>>     where MATCHER can be either the regexp to search for, or the
>>     function name to call to make the search (called with one
>> 
>> So here I mean that 'symbol' equals the MATCHER, or the FACENAME, or is
>> a member of (flatten-tree FORM), and so on.
>
> It can equal _any_ symbol in those places?  Even stuff like 'and'
> etc.?  What a strange feature!  Why not enable just a test against the
> MATCHER part?

The config example in the manual is not an academic one.  I personally
want to disable _most_ font-locking, therefore I use this as my very
first font-lock-ignore rule:

    (prog-mode font-lock-*-face)

But I will gladly take some warning fontifications if someone went the
trouble of implementing them.  So I'm using this rule as well:

   (prog-mode (except help-echo))

Does that catch only fontifications I care about, and not catch any
fontifications I don't care about?  Probably not, but it's a good enough
approximation.  It achieves something I find pretty good using only 1
very succinct heuristic.

Granted, 'and' is not a meaningful RULE.  But it's not disallowed
because there's not point in disallowing it.

>> >> The symbol is interpreted as a glob
>> >> +pattern; in particular, @code{*} matches everything.
>> >
>> > Do you mean shell glob patterns?  AFAIK, we don't use them in Emacs
>> > except for shell wildcards, so why are they used here? why not
>> > regexps?  And in any case, those patterns need a thorough description,
>> > since we don't use them elsewhere.  For example, the way to quote
>> > meta-characters such as '*' must be documented, because it isn't
>> > self-evident.
>> 
>> The intention is that the user can write, for instance
>> 
>>     (setq font-lock-ignore '((prog-mode font-lock-*-face)))
>> 
>> and this will be equivalent to
>> 
>>     (setq font-lock-ignore '((prog-mode (pred (lambda (obj)
>>                                                  (and (symbolp obj)
>>                                                       (string-match-p
>>                                                        
>> "\\`font-lock-.*-face\\'"
>>                                                        (symbol-name 
>> obj))))))))
>> 
>> Do you agree this is a sensible and convenient mini-language?  I guess
>> Stefan liked the idea, at least :-).
>
> I understand the intent.  I'm saying that we should document this
> "mini-language" in sufficient detail, so that Lisp programmers knew
> how to use it.

Strictly speaking the docstring of 'font-lock-ignore' provides a
complete specification of the mini-language; if not, it's a bug in the
docstring.  But we can always expand the examples, of course.

>> >> +@item @var{string}
>> >> +A string matches any font-lock keyword defined by a regexp that
>> >> +matches the string.
>> >
>> > I don't think I understand this sentence.  In particular, saying "a
>> > regexp that matches the string" is at least unusual: we usually say it
>> > the other way around: "a string that matches the regexp".  And what
>> > does it mean for a keyword to be "defined by a regexp"?
>> 
>> Just to make sure we're on the same page, this refers, for instance, to
>> the rule
>> 
>>     (emacs-lisp-mode ";;;###autoload")
>> 
>> which would deactivate the highlighting of autoload cookies.
>> 
>> So, we could say "A string matches any font-lock rule which would
>> highlight that string".
>
> What do you mean by "font-lock rule" here?

Yeah, I meant "entry of font-lock-keywords".

>> > And why doesn't the example show all the possible forms of a "rule",
>> > but just one of them?
>> 
>> Well, I just wanted to keep true to this being a "@smallexample".
>
> I see no problem with this: adding a couple of lines shouldn't make
> the example too large.

Sounds good.

>> >> +*** New user option 'font-lock-ignore'.
>> >> +This variable provides a mechanism to selectively disable font-lock
>> >> +keywords.
>> >
>> > I don't think it disables keywords, I think it disables
>> > fontifications.  (How can one disable a keyword?)
>> 
>> Hum, I'm not sure I understand the fine-grained distinction your are
>> making here.  font-lock.el speaks of "font lock keywords"; the thing
>> that fontifies variable names with font-lock-variable-face would be a
>> "font lock keyword" in that terminology.  I'm just following along the
>> terminology.
>
> That terminology (if this is how you perceive it) is wrong, and I'm
> about to change it to make that more clear.  font-lock-keywords are
> not just keywords, they are rules for fontification.

I certainly agree that font-lock.el's use of "font-lock keyword" as a
term for "rules for fontification" is a bit odd.  OTOH it's an
established use.  Anyway, any changes that make things clearer are
welcome.

>  This new feature allows to selectively disable some of those
> fontifications without editing the rules themselves.

That's correct.  I see this as an end-user configuration, so providing
the ability to modify the fontifications would probably be going too
far.  If someone can come up with an expressive mini-language to modify
fontifications, that might be cool.  Other than that, the user can
always modify 'font-lock-keywords' manually.

>> >> +(defun font-lock--match-keyword (rule keyword)
>> >> +  "Return non-nil if font-lock KEYWORD matches RULE.
>> >> +See `font-lock-ignore' for the possible rules."
>> >> +  (pcase-exhaustive rule
>> >> +    ('* t)
>> >> +    ((pred symbolp)
>> >> +     (let ((regexp (when (string-match-p "[*?]" (symbol-name rule))
>> >> +                     (wildcard-to-regexp (symbol-name rule)))))
>> >
>> > So "[abcd]" isn't supported by these "glob patterns"?  This should be
>> > documented.
>> 
>> Ah, okay, I guess we should use the regexp "[][*?]" in that test.
>
> Why not allow a regexp to begin with?  Then 2 problems will be solved
> in one blow: (1) the need to change the code, and (2) the need to
> describe what is allowed and what isn't.

So your suggestion is that when RULE is a string, the string is treated
as a regexp and symbol names are matched against it, right?

IMO the current mini-langauge is more useful: the RULE "(defun" can be
used to match the following element of font-lock-keywords found in
emacs-lisp-mode:

```
("(\\(cl-def\\(?:generic\\|m\\(?:acro\\|ethod\\)\\|s\\(?:\\(?:truc\\|ubs\\)t\\)\\|type\\|un\\)\\|def\\(?:a\\(?:dvice\\|lias\\)\\|c\\(?:lass\\|onst\\|ustom\\)\\|face\\|g\\(?:eneric\\|roup\\)\\|ine-\\(?:advice\\|derived-mode\\|g\\(?:\\(?:eneric\\|lobal\\(?:\\(?:ized\\)?-minor\\)\\)-mode\\)\\|inline\\|minor-mode\\|skeleton\\|widget\\)\\|m\\(?:acro\\|ethod\\)\\|subst\\|theme\\|un\\|var\\(?:-local\\|alias\\)?\\)\\|ert-deftest\\)\\_>[
        ']*\\(([        ']*\\)?\\(\\(setf\\)[   
]+\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\|\\(?:\\sw\\|\\s_\\|\\\\.\\)+\\)?"
 (1 font-lock-keyword-face)
 (3
  (let
      ((type
        (get
         (intern-soft
          (match-string 1))
         'lisp-define-type)))
    (cond
     ((eq type 'var)
      font-lock-variable-name-face)
     ((eq type 'type)
      font-lock-type-face)
     ((or
       (not
        (match-string 2))
       (and
        (match-string 2)
        (match-string 4)))
      font-lock-function-name-face)))
  nil t))
```

>> > I'm okay with clarifying the docs myself if you explain enough for me
>> > to understand how to do that.
>> 
>> I guess yes, it would be great if we could have the perspective of a
>> different person incorporated in the documentation, so please go ahead!
>> I'll be glad to provide further clarifications.
>
> Will do, after you reply to this followup message.

Great, thanks!

> Thanks.



reply via email to

[Prev in Thread] Current Thread [Next in Thread]