From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Augusto Stoffel Newsgroups: gmane.emacs.devel Subject: Re: master 5c70ff9: New user option 'font-lock-ignore' Date: Sat, 02 Apr 2022 09:34:25 +0200 Message-ID: <87fsmwndku.fsf@gmail.com> References: <83mth43sb7.fsf@gnu.org> Mime-Version: 1.0 Content-Type: text/plain; charset=utf-8 Content-Transfer-Encoding: quoted-printable Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="30894"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.92 (gnu/linux) Cc: Stefan Monnier , emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Sat Apr 02 09:36:50 2022 Return-path: Envelope-to: ged-emacs-devel@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1naYJW-0007uI-3P for ged-emacs-devel@m.gmane-mx.org; Sat, 02 Apr 2022 09:36:50 +0200 Original-Received: from localhost ([::1]:45234 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1naYJU-0003ZT-S3 for ged-emacs-devel@m.gmane-mx.org; Sat, 02 Apr 2022 03:36:48 -0400 Original-Received: from eggs.gnu.org ([209.51.188.92]:44334) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1naYHH-00028S-8O for emacs-devel@gnu.org; Sat, 02 Apr 2022 03:34:31 -0400 Original-Received: from [2a00:1450:4864:20::532] (port=44724 helo=mail-ed1-x532.google.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1naYHF-0000VN-9t; Sat, 02 Apr 2022 03:34:30 -0400 Original-Received: by mail-ed1-x532.google.com with SMTP id u9so260111edd.11; Sat, 02 Apr 2022 00:34:28 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=from:to:cc:subject:references:date:in-reply-to:message-id :user-agent:mime-version:content-transfer-encoding; bh=zIJf7+P3bextwvBlGkIqde7L1Y+CyuIb/qewIUpwTxU=; b=l2+5Okqo87yhTQ6xnZ8EnBv9F2JAKqKRedCbitJ0+LWf2AgUowOZjjLiXWQeqF3bOr hr27G/xF2Xinm3d1BpgD7fw+taO6Q4vIk6hKeNTpF4QMycQ7G9BOl9uV0EhM6HLR+824 SZVVa2ZtBqPG7iVu1AN4Hnj+CBoZ5w1a7sqgYRcJnXyJ4GjihuerPt1ztLBsTG/zKM+5 cBgR62ND+RMPAKgCLVN+6j+9jrBRyt8XCMCBEsR0mbtlDvJzPYK8+5DXwqePEg5HUEsB K2V2V7naQHuA74uaOUaoezseoITFoP/EyJVXmexRP8kV4BjG1HclxnywadxHGHyxKQvA 5ZhQ== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=x-gm-message-state:from:to:cc:subject:references:date:in-reply-to :message-id:user-agent:mime-version:content-transfer-encoding; bh=zIJf7+P3bextwvBlGkIqde7L1Y+CyuIb/qewIUpwTxU=; b=gl2Iw/OISO4pa8cZWiit/fK2mxvF2z/UrJ7Umdo7HHNSKzoo9jhb1YH98Hvc0Ofu7k 3cVZbn81K26/gMY/fKpyc82ue+ijxPcCqNcFtkNNDnEFvsk2Kwf4BNgS9LJZIKsYmBqC f0oIEIzp6dru9mPyqE4j8x1QOHa8c4zewQ0gjXDACAKNCc1orEb/ERgU20V5KiIA4Cfq 1QA1rcsH5iUrYyCcmy+RD8JkRnpha1wbBmqqhNPHq+7epAVZWXk2dE2f/xNWGq3zpjAf Ia95x1/URUbAKCJ46N+JEeWrkM60ltLq4OIjdMWk2S/zM8DrdJL4l66f2eL8U/LY4LRG PDag== X-Gm-Message-State: AOAM530DENY4fkJtHK7XzB+XE0Ff6Fwl1XqUjTQwPABrTOfVF34ElGqv l0TFmpT8XVuCG49szx61EulGVts4N8r27Q== X-Google-Smtp-Source: ABdhPJxv18lHqwlnXiw+GonSjV9JjzsmxGNihSGIr03xeQKL866AsLj2tSCd2cg87K0BYhAN5tCVcg== X-Received: by 2002:a05:6402:5186:b0:419:651e:5137 with SMTP id q6-20020a056402518600b00419651e5137mr24440333edd.335.1648884866996; Sat, 02 Apr 2022 00:34:26 -0700 (PDT) Original-Received: from ars3 ([2a02:8109:8ac0:56d0::7039]) by smtp.gmail.com with ESMTPSA id c3-20020a17090654c300b006e4e1a3e9d5sm1195410ejp.144.2022.04.02.00.34.25 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Sat, 02 Apr 2022 00:34:26 -0700 (PDT) In-Reply-To: <83mth43sb7.fsf@gnu.org> (Eli Zaretskii's message of "Sat, 02 Apr 2022 09:36:28 +0300") X-Host-Lookup-Failed: Reverse DNS lookup failed for 2a00:1450:4864:20::532 (failed) Received-SPF: pass client-ip=2a00:1450:4864:20::532; envelope-from=arstoffel@gmail.com; helo=mail-ed1-x532.google.com X-Spam_score_int: -6 X-Spam_score: -0.7 X-Spam_bar: / X-Spam_report: (-0.7 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, PDS_HP_HELO_NORDNS=0.659, RCVD_IN_DNSWL_NONE=-0.0001, RDNS_NONE=0.793, SPF_HELO_NONE=0.001, SPF_PASS=-0.001, T_SCC_BODY_TEXT_LINE=-0.01 autolearn=no autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:287697 Archived-At: Hi Eli, thanks for your feedback. I've responded to your points below. On Sat, 2 Apr 2022 at 09:36, Eli Zaretskii wrote: > Thanks for developing this feature. > > Reading its documentation, I think it should be clarified to be more > useful. See the questions/comments below: > >> +@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 =E2=80=9CHere, @var{mode} a major or m= inor mode=E2=80=9D? This would be slightly imprecise, because technically 'mode= ' can be any variable. >> The >> +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. Unfortunately, I can't think of a better way to explain this. Or, at least, not in an annoyingly long-winded way. (Coming back to the "bolted on" remark: If this feature had been planned from the beginning, perhaps one would have forced the font-lock keyword definitions to be named and/or include other metadata like "importance" or "precedence". But that is not the case, and the filtering options provided here are IMO the best one can do at this point.) >> 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-.*-fac= e\\'" (symbol-name obj))))= )))) Do you agree this is a sensible and convenient mini-language? I guess Stefan liked the idea, at least :-). >> +@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". It would be a slight lie, because this doesn't work if the MATCHER is a function. Should we trade precision for clarity here? I think we probably should. >> +In each buffer, Font Lock keywords that match at least one applicable >> +rule are disabled. > > This should be _before_ the list of rules, not after. And given the > fact that actions of the rules are implicit (i.e. they aren't present > in the rules themselves), I would suggest to call them "conditions", > not "rules". A rule includes the action, not just the condition for > that action, and those "rules" don't. Okay, I'll move the text. About rule vs. condition, let me think about it. >> +@smallexample >> +(setq font-lock-ignore >> + '((prog-mode font-lock-*-face >> + (except help-echo)) >> + (emacs-lisp-mode (except ";;;###autoload)") >> + (whitespace-mode whitespace-empty-at-bob-regexp) >> + (makefile-mode (except *)))) >> +@end smallexample >> + >> +Line by line, this does the following: >> + >> +@enumerate >> +@item >> +In all programming modes, disable all font-lock keywords that apply >> +one of the standard font-lock faces (excluding strings and comments, >> +which are covered by syntactic Font Lock). >> + >> +@item >> +However, keep any keywords that add a @code{help-echo} text property. >> + >> +@item >> +In Emacs Lisp mode, also keep the highlighting of autoload cookies, >> +which would have been excluded by rule 1. >> + >> +@item >> +In @code{whitespace-mode} (a minor mode), don't highlight an empty >> +line at beginning of buffer. > > Shouldn't you have "also" in this last description, like you did for > Emacs Lisp mode? Yes, or maybe "Additionally, if whitespace-mode (a minor-mode) is active, don't highlight and empty line at the beginning of buffer." > 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 think it will be exceedingly rare that anyone needs any of the other rules (and, pred, not, etc.). It's so easy to implement those things that it doesn't make sense not to, but mentioning them in the example would perhaps distract from the main point. >> +*** 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. >> + >> ++++ >> *** New package vtable.el for formatting tabular data. >> This package allows formatting data using variable-pitch fonts. >> The resulting tables can display text in variable pitch fonts, text >> diff --git a/lisp/font-lock.el b/lisp/font-lock.el >> index d8a1fe3..8af3c30 100644 >> --- a/lisp/font-lock.el >> +++ b/lisp/font-lock.el >> @@ -208,6 +208,7 @@ >>=20=20 >> (require 'syntax) >> (eval-when-compile (require 'cl-lib)) >> +(eval-when-compile (require 'subr-x)) >>=20=20 >> ;; Define core `font-lock' group. >> (defgroup font-lock '((jit-lock custom-group)) >> @@ -279,6 +280,42 @@ font-lock-maximum-decoration >> (integer :tag "level" 1))))) >> :group 'font-lock) >>=20=20 >> +(defcustom font-lock-ignore nil >> + "Rules to selectively disable font-lock keywords. >> +This is a list of rule sets of the form >> + >> + (MODE RULE ...) >> + >> +where: >> + >> + - MODE is a symbol, say a major or minor mode. The subsequent >> + rules apply if the current major mode is derived from MODE or >> + MODE is bound and true as a variable. >> + >> + - Each RULE can be one of the following: >> + - A symbol, say a face name. It matches any font-lock keyword >> + containing the symbol in its definition. The symbol is >> + interpreted as a glob pattern; in particular, `*' matches >> + everything. >> + - A string. It matches any font-lock keyword defined by a regexp >> + that matches the string. >> + - A form (pred FUNCTION). It matches if FUNCTION, which is called >> + with the font-lock keyword as argument, returns non-nil. >> + - A form (not RULE). It matches if RULE doesn't. >> + - A form (and RULE ...). It matches if all the provided rules >> + match. >> + - A form (or RULE ...). It matches if any of the provided rules >> + match. >> + - A form (except RULE ...). This can be used only at top level or >> + inside an `or' clause. It undoes the effect of a previous >> + matching rule. >> + >> +In each buffer, font lock keywords that match at least one >> +applicable rule are disabled." > > Same comments apply to this doc string. Sure. >> + :type '(alist :key-type symbol :value-type sexp) >> + :group 'font-lock >> + :version "29.1") >> + >> (defcustom font-lock-verbose nil >> "If non-nil, means show status messages for buffer fontification. >> If a number, only buffers greater than this size have fontification mes= sages." >> @@ -1810,9 +1847,8 @@ font-lock-compile-keywords >> (error "Font-lock trying to use keywords before setting them up")) >> (if (eq (car-safe keywords) t) >> keywords >> - (setq keywords >> - (cons t (cons keywords >> - (mapcar #'font-lock-compile-keyword keywords)))) >> + (let ((compiled (mapcar #'font-lock-compile-keyword keywords))) >> + (setq keywords `(t ,keywords ,@(font-lock--filter-keywords compil= ed)))) >> (if (and (not syntactic-keywords) >> (let ((beg-function (with-no-warnings syntax-begin-function))) >> (or (eq beg-function #'beginning-of-defun) >> @@ -1883,6 +1919,50 @@ font-lock-choose-keywords >> (t >> (car keywords)))) >>=20=20 >> +(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. > 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. > TIA