unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
From: JD Smith <jdtsmith@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: emacs-devel@gnu.org
Subject: Re: region-based face-remapping
Date: Wed, 3 Jan 2024 18:15:04 -0500	[thread overview]
Message-ID: <ABD260AF-CB90-41A5-A417-322212C32C51@gmail.com> (raw)
In-Reply-To: <83edeyzjgp.fsf@gnu.org>

[-- Attachment #1: Type: text/plain, Size: 6056 bytes --]



> On Jan 3, 2024, at 7:31 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>> From: JD Smith <jdtsmith@gmail.com>
>> 
>> To make the entire face API position-dependent does seem complex. I presume face calculation
>> first checks if there is a valid 'face-remapping-alist’ and does substitutions.
> 
> Not exactly. You need to keep in mind that each buffer or string
> position could have several sources of face information, see
> "Displaying Faces" in the ELisp manual for the gory details.So first
> Emacs needs to collect all those faces from all the relevant sources,
> and then it merges them. Face remapping happens during the merge: each
> face that is referenced by a symbol (a.k.a. "named face") is remapped
> if needed.

I see.  But if there were a property at the position where Emacs is collecting and merging all the face information, say

	 ‘(face-remap ((some-face . another-face)))

would the merge process be able to easily use this style of remap-information, in addition to the buffer-local 'face-remapping-alist (with the local property taking precedence over the variable)?

>> If 'face-remap were a
>> valid (overlay/text) property, that would seem to obviate any deeper API changes: just add this
>> property where remapping is desired.
> 
> I don't think I follow.
> 
> The workhorse we use now for obtaining face information is the
> function face_at_buffer_position, which calls the various face-merging
> routines.  Those merging routines and their subroutines consider
> face-remapping-alist as part of face merging process outlined above.
> I don't see how we can avoid passing the buffer position to them if
> face-remapping depends on buffer position. Also, those routines will
> now need to perform property or overlay search for the special
> face-remapping property, using the position they are passed.
> 
> Am I missing something?

Perhaps we are talking about different things.  I was speaking from the point of the view of the ELISP user of the faces API.  From the ELISP face API, I don’t see a need to include any new position information for face definition and face property assignment.  I think now that you were speaking about the internal API.  Internally during the face merge process, I agree there would need to know the properties at a merging-the-face-info point under consideration, which could influence the merge.  

Maybe the issue is that face_at_buffer_position is called only at certain special positions, not on each position in the buffer?  If so, I can see how your concern about property/overlay search would apply (though what those positions would be I don’t know, since I can assign a different 'face property to arbitrary ranges as small as one character).

>> This may relate to the text-property “planes” discussion from a
>> couple years back.  Based on that discussion, perhaps targeting only ‘face is not enough. Is there
>> another approach to “selectively enabling/substituting properties by region”, beyond just
>> text-property-search-forward within the region (looking within ‘display properties too)?
> 
> I don't think I understand which discussion you have in mind and how
> it is relevant to the issue at hand.

I meant this discussion (and the related earlier one mentioned, by Stefan M):

https://lists.nongnu.org/archive/html/emacs-devel/2019-11/msg00599.html

My read of that discussion is it would allow external control of various “planes" of a text property: turn some on, others off, without searching through the entirety of the buffer finding and replacing those properties.  Similar to layers in a photo editor.  Whether that type of external control could be limited to a region I am unsure (though the MMM discussion makes me think that was envisioned).  The “layers” or “planes” concept certainly seems related.

>> To make this concrete, how would people approach the following:
>> 
>> 1 On point motion, treesitter’s syntax tree is consulted to find an "enclosing semantic context
>> region".
>> 2 Within that region, pre-existing faces (or perhaps other properties) get updated to a “highlighted”
>> variant.
>> 3 Outdated/prior regions have the highlighted variants removed.
>> 
>> Since you don’t know in advance how large such regions might be, it seems problematic to search
>> and replace all the various faces or other properties.   
> 
> How do you envision to do items 2 and 3 above?  IOW, how do you
> "update pre-existing faces"?  

In an ideal scenario, by applying a text or overlay property '(face-remap ((some-face . some-highlight-face))) to that region.

> The naïve solution, of somehow changing
> the face attributes on the fly, will be a performance killer, since
> currently any change in any named face invalidates all the faces we
> already know about and requires their "realization" anew -- because we
> don't track the dependencies between faces, and thus don't know which
> other faces need to be updated as result.  So this would mean that any
> point movement could potentially cause recalculation of all the faces
> on the selected frame.  

I do this very thing already in indent-bars[1], globally in the buffer, using face-remapping-alist.  The performance of that remapping is incredibly good in my experience.  So fast in fact that I’ve had to introduce a timer to artificially slow it down since it leads to rapid face flashing during smooth scrolling.

> And face realization is a relatively expensive
> process, especially if there are a lot of them (we had reports about
> users who routinely have hundreds or even thousands of faces on a
> frame). Thus my question about items 2 and 3, which seem to do exactly
> what we avoid doing: modify named faces.


Does “substitute a named face for another named or anonymous face” lead to similar concerns?  Or can those then all be precomputed without the constant face realization concern?

[1] https://github.com/jdtsmith/indent-bars


[-- Attachment #2.1: Type: text/html, Size: 35856 bytes --]

[-- Attachment #2.2: favicon.ico --]
[-- Type: image/vnd.microsoft.icon, Size: 1406 bytes --]

  parent reply	other threads:[~2024-01-03 23:15 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-02  0:22 region-based face-remapping JD Smith
2024-01-02 13:00 ` Eli Zaretskii
2024-01-02 15:49   ` JD Smith
2024-01-03 12:31     ` Eli Zaretskii
2024-01-03 12:40       ` Dmitry Gutov
2024-01-03 13:42         ` Eli Zaretskii
2024-01-04  0:07           ` Dmitry Gutov
2024-01-04  7:05             ` Eli Zaretskii
2024-01-05  3:49               ` Dmitry Gutov
2024-01-05  8:50                 ` Eli Zaretskii
2024-01-05 14:18                   ` Dmitry Gutov
2024-01-05 14:34                     ` Eli Zaretskii
2024-01-05 16:25                       ` Dmitry Gutov
2024-01-03 23:15       ` JD Smith [this message]
2024-01-04  6:58         ` Eli Zaretskii
2024-01-05  0:51           ` JD Smith
2024-01-05  8:19             ` Eli Zaretskii
2024-01-05 16:35               ` Dmitry Gutov
2024-01-06 14:04                 ` JD Smith
2024-01-06 13:53               ` JD Smith
2024-01-06 14:27                 ` Eli Zaretskii
2024-01-06 14:56                   ` JD Smith
2024-01-08 17:28                     ` Eli Zaretskii
2024-01-07  3:41                 ` Dmitry Gutov
2024-01-15 19:55     ` Stefan Monnier via Emacs development discussions.
2024-01-15 20:19       ` Eli Zaretskii
2024-01-15 20:25         ` Eli Zaretskii
2024-01-15 20:36         ` Stefan Monnier
  -- strict thread matches above, loose matches on Subject: below --
2024-01-08 21:49 JD Smith
2024-01-09 13:03 ` Eli Zaretskii
2024-01-09 14:15   ` Stefan Monnier
2024-01-09 20:20     ` JD Smith
2024-01-15 20:17       ` Stefan Monnier via Emacs development discussions.
2024-01-09 20:20     ` JD Smith
2024-01-10 12:36       ` Eli Zaretskii
2024-01-09 21:31   ` JD Smith
2024-01-10 12:44     ` Eli Zaretskii

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: https://www.gnu.org/software/emacs/

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=ABD260AF-CB90-41A5-A417-322212C32C51@gmail.com \
    --to=jdtsmith@gmail.com \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
Code repositories for project(s) associated with this public inbox

	https://git.savannah.gnu.org/cgit/emacs.git

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).