all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
* Local face remapping
@ 2023-10-04 12:58 JD Smith
  2023-10-04 16:54 ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: JD Smith @ 2023-10-04 12:58 UTC (permalink / raw)
  To: emacs-devel

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

My indent-bars <https://github.com/jdtsmith/indent-bars> package makes good use of `face-remap-add-relative’ to provide performant depth-based context highlighting via a post-command-hook.  This is very fast and simple: just check the indentation depth, and if it changed, update the buffer-local face remapping list accordingly.  I am now considering a feature which would make this highlighting local in regions based on treesitter block scope.

Is there any means of achieving local face remapping within regions?  Ideally overlays could be used, if they had a `remapping-alist' property, similar to the global or buffer-local value, but applying only within the bounds of the overlay.  Given that this does not exist, is there another way to achieve something similar?


[-- Attachment #2: Type: text/html, Size: 1060 bytes --]

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Local face remapping
  2023-10-04 12:58 Local face remapping JD Smith
@ 2023-10-04 16:54 ` Eli Zaretskii
  2023-10-04 18:48   ` JD Smith
  0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2023-10-04 16:54 UTC (permalink / raw)
  To: JD Smith; +Cc: emacs-devel

> From: JD Smith <jdtsmith@gmail.com>
> Date: Wed, 4 Oct 2023 08:58:34 -0400
> 
> My indent-bars package makes good use of `face-remap-add-relative’ to provide performant
> depth-based context highlighting via a post-command-hook.  This is very fast and simple: just check
> the indentation depth, and if it changed, update the buffer-local face remapping list accordingly.  I am
> now considering a feature which would make this highlighting local in regions based on treesitter
> block scope.
> 
> Is there any means of achieving local face remapping within regions?  Ideally overlays could be
> used, if they had a `remapping-alist' property, similar to the global or buffer-local value, but applying
> only within the bounds of the overlay.  Given that this does not exist, is there another way to achieve
> something similar?

Use different faces?



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Local face remapping
  2023-10-04 16:54 ` Eli Zaretskii
@ 2023-10-04 18:48   ` JD Smith
  2023-10-05  5:32     ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: JD Smith @ 2023-10-04 18:48 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel


> On Oct 4, 2023, at 12:54 PM, Eli Zaretskii <eliz@gnu.org> wrote:
> 
> Use different faces?

Ha.  Yes, of course you can can find and replace all the relevant faces in a region, but given that face-remapping-alist already does this efficiently for the entire buffer, I had hoped a similar region-constrained / overlay-based functionality might exist.  I’ll take that as a no :).


^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Local face remapping
  2023-10-04 18:48   ` JD Smith
@ 2023-10-05  5:32     ` Eli Zaretskii
  2023-10-05 13:12       ` JD Smith
  0 siblings, 1 reply; 6+ messages in thread
From: Eli Zaretskii @ 2023-10-05  5:32 UTC (permalink / raw)
  To: JD Smith; +Cc: emacs-devel

> From: JD Smith <jdtsmith@gmail.com>
> Date: Wed, 4 Oct 2023 14:48:22 -0400
> Cc: emacs-devel@gnu.org
> 
> 
> > On Oct 4, 2023, at 12:54 PM, Eli Zaretskii <eliz@gnu.org> wrote:
> > 
> > Use different faces?
> 
> Ha.  Yes, of course you can can find and replace all the relevant faces in a region, but given that face-remapping-alist already does this efficiently for the entire buffer, I had hoped a similar region-constrained / overlay-based functionality might exist.  I’ll take that as a no :).

Let me help you understand the situation better.

In Emacs, faces are defined per-frame.  That is, each frame can have a
different definition of the same face symbol.

face-remapping-alist doesn't (and cannot) change that simple fact, so
it is a trick: it creates new faces based on default faces, in a way
that is buffer-local.  This works (btw, not in all places) because the
display engine consults the buffer-local value of face-remapping-alist
each time it needs to realize a face for display.  If that variable is
non-nil, and the face to be realized is mentioned in the alist, then
the display engine generates a new face on the fly and uses that new
face for display.

So, if you want face-remapping that depends on buffer positions, you
will need to change the implementation of face-remapping: instead of a
simple alist, we will probably need to also allow a function returning
such an alist, and the C code will need to be taught to deal with
the situation where face-remapping-alist's value is a function.

My suggestion to use different faces just does explicitly what
face-remapping-alist does implicitly.



^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Local face remapping
  2023-10-05  5:32     ` Eli Zaretskii
@ 2023-10-05 13:12       ` JD Smith
  2023-10-06  5:41         ` Eli Zaretskii
  0 siblings, 1 reply; 6+ messages in thread
From: JD Smith @ 2023-10-05 13:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: emacs-devel

> Let me help you understand the situation better.

Thanks very much for your detailed explanation.

> In Emacs, faces are defined per-frame.  That is, each frame can have a
> different definition of the same face symbol.
> 
> face-remapping-alist doesn't (and cannot) change that simple fact, so
> it is a trick: it creates new faces based on default faces, in a way
> that is buffer-local.  This works (btw, not in all places) because the
> display engine consults the buffer-local value of face-remapping-alist
> each time it needs to realize a face for display.  If that variable is
> non-nil, and the face to be realized is mentioned in the alist, then
> the display engine generates a new face on the fly and uses that new
> face for display.

Interesting.  I presume with caching?

> So, if you want face-remapping that depends on buffer positions, you
> will need to change the implementation of face-remapping: instead of a
> simple alist, we will probably need to also allow a function returning
> such an alist, and the C code will need to be taught to deal with
> the situation where face-remapping-alist's value is a function.

That’s an interesting idea, more flexible than hard-coding a simple function that considers START…END.  You wouldn’t want to call such a function for each FACE character, and if the region divides a FACE interval, that adds complexity. But maybe tractable.

> My suggestion to use different faces just does explicitly what
> face-remapping-alist does implicitly.

But much less efficiently, if the faces to be altered appear in many non-contiguous intervals, and within ‘display strings in that (potentially large) region.  The advantage of the “just in time” face substitution you describe is it operates from the top down and is thus suitable for rapid updates via, e.g., post-command-hooks. It also plays nicely with font-lock, etc.

A perhaps related concept would be allowing code (including font-lock) to apply secondary face(s) to text, via an alist, perhaps.  Secondary faces would lie dormant, unless and until an overlay or text property explicitly enables one of them (`use-secondary-face ‘foo', or similar).  In this way it would be similar to mouse-face, but explicitly under programmatic control instead of implicit mouse position control. An overlay or text property could then be applied to an entire region enabling specific secondary faces within it to “come alive”, quite similar to how mouse position causes mouse-face to activate.




^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: Local face remapping
  2023-10-05 13:12       ` JD Smith
@ 2023-10-06  5:41         ` Eli Zaretskii
  0 siblings, 0 replies; 6+ messages in thread
From: Eli Zaretskii @ 2023-10-06  5:41 UTC (permalink / raw)
  To: JD Smith; +Cc: emacs-devel

> From: JD Smith <jdtsmith@gmail.com>
> Date: Thu, 5 Oct 2023 09:12:58 -0400
> Cc: emacs-devel@gnu.org
> 
> > In Emacs, faces are defined per-frame.  That is, each frame can have a
> > different definition of the same face symbol.
> > 
> > face-remapping-alist doesn't (and cannot) change that simple fact, so
> > it is a trick: it creates new faces based on default faces, in a way
> > that is buffer-local.  This works (btw, not in all places) because the
> > display engine consults the buffer-local value of face-remapping-alist
> > each time it needs to realize a face for display.  If that variable is
> > non-nil, and the face to be realized is mentioned in the alist, then
> > the display engine generates a new face on the fly and uses that new
> > face for display.
> 
> Interesting.  I presume with caching?

Yes, each frame has its own face cache (that is orthogonal to face
remapping).

> > So, if you want face-remapping that depends on buffer positions, you
> > will need to change the implementation of face-remapping: instead of a
> > simple alist, we will probably need to also allow a function returning
> > such an alist, and the C code will need to be taught to deal with
> > the situation where face-remapping-alist's value is a function.
> 
> That’s an interesting idea, more flexible than hard-coding a simple function that considers START…END.  You wouldn’t want to call such a function for each FACE character, and if the region divides a FACE interval, that adds complexity. But maybe tractable.

Emacs only computes the faces when the face changes, so this is not a
significant complication, IMO.

> > My suggestion to use different faces just does explicitly what
> > face-remapping-alist does implicitly.
> 
> But much less efficiently, if the faces to be altered appear in many non-contiguous intervals, and within ‘display strings in that (potentially large) region.  The advantage of the “just in time” face substitution you describe is it operates from the top down and is thus suitable for rapid updates via, e.g., post-command-hooks. It also plays nicely with font-lock, etc.

Maybe.  My idea was that the same code which decides that colors
should change can place the new faces on the text in the region, and
how heavy could that be?

> A perhaps related concept would be allowing code (including font-lock) to apply secondary face(s) to text, via an alist, perhaps.  Secondary faces would lie dormant, unless and until an overlay or text property explicitly enables one of them (`use-secondary-face ‘foo', or similar).  In this way it would be similar to mouse-face, but explicitly under programmatic control instead of implicit mouse position control. An overlay or text property could then be applied to an entire region enabling specific secondary faces within it to “come alive”, quite similar to how mouse position causes mouse-face to activate.

Actually, mouse-face is also under Lisp program control: see
mouse-highlight.



^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2023-10-06  5:41 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-10-04 12:58 Local face remapping JD Smith
2023-10-04 16:54 ` Eli Zaretskii
2023-10-04 18:48   ` JD Smith
2023-10-05  5:32     ` Eli Zaretskii
2023-10-05 13:12       ` JD Smith
2023-10-06  5:41         ` Eli Zaretskii

Code repositories for project(s) associated with this external index

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

This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.