all messages for Emacs-related lists mirrored at yhetil.org
 help / color / mirror / code / Atom feed
From: JD Smith <jdtsmith@gmail.com>
To: Eli Zaretskii <eliz@gnu.org>
Cc: Stefan Monnier <monnier@iro.umontreal.ca>, emacs-devel@gnu.org
Subject: Re: region-based face-remapping
Date: Tue, 9 Jan 2024 16:31:30 -0500	[thread overview]
Message-ID: <23BA0312-2129-49A5-A43F-900F789E8C54@gmail.com> (raw)
In-Reply-To: <83o7dupskh.fsf@gnu.org>

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



> On Jan 9, 2024, at 8:03 AM, Eli Zaretskii <eliz@gnu.org> wrote:
> 
>> From: JD Smith <jdtsmith@gmail.com>
>> Date: Mon, 8 Jan 2024 16:49:21 -0500
>> Cc: emacs-devel@gnu.org
>> 
>> Why cannot this be done by modifying faces or overlays in the affected
>> region?
>> 
>> It can, but the region where such face modification is needed could be arbitrarily large (including the
>> entire buffer), which makes this more like a font-lock-problem in a PCH or via a timer (with the bonus
>> that it could occur either on modification or just point change).  So at worst it would be like
>> re-font-locking the entire buffer (many thousands of locations, most just 1 character wide) on every
>> key press (or rapidly with a timer).
> 
> Not sure changing faces will be significantly slower than what you had
> in mind.  Maybe simpler (for a Lisp program), but not necessarily
> slower.  After all, that's what JIT font-lock does all the time, and
> we accept the performance it provides.

As long as the changes happen at the right places (ala font-lock) and not all over the buffer,  you may be right.  And it’s reasonable to consider this since font-lock is already the one applying those faces in the first place.  The trick is how to actually implement it. 

>> What I’m struggling with is how to do something “like font lock” — i.e. refontify some potentially
>> substantial fraction of all the faces in a buffer, not (just) on modifications in an after-change-hook, but
>> also on point-dependent “region of interest” changes, with a priority given to the displayed region in
>> the window.  IMO, tree-sitter will make this kind of idea more common.
> 
> Did you try to use jit-lock-register machinery?
> 
> Maybe Stefan (CC'ed) will have better ideas.

I haven’t.  In my (limited) understanding and experience, all the font-lock apparatus is highly tuned to after-change modifications.  Here we need to (in addition) mark regions (old and new) as outdated, even when the buffer hasn’t changed at all, just based on the movement of the (selected window’s) point.  I can know how to expand modified regions with `font-lock-extend-region-functions’, but I don’t know how to inform font-lock that “even though you didn’t see changes, trust me, these regions are in need of updating”.  I would do this in a PCH, rate-limited by a timer.

Maybe it’s as simple as calling `font-lock-flush’ on those regions?  If so, can you call font-lock-flush multiple times in a row on overlapping regions without creating issues?  Does font-lock-flush do the right (JIT) thing, even when you mark a very large region?

And (this is the big one) how do you handle two chef’s both with their spoons in the font-locking pot at the same time?

Normal font-lock responding to changes in the buffer to refontify regions.
PCH+timer marks regions for refontification when the buffer-modified-tick or treesitter region-of-interest changes (the former because you can no longer trust that equal regions are in fact equivalent).

Seem like there’d be a bunch of unnecessarily repetitive refontification in such a scheme.  And marking large regions with `font-lock-flush’ every 75ms as you type also seems problematic.

For disclosure, I’ve never used jit-lock-register, and personally find the font-lock documentation light on details for implementing non-standard fontification scenarios such as this.

>> For the highlighting/unhighlighting operation, I think I also mentioned that the faces of interest can and
>> will live in display properties, so you’d need to check all ‘display strings within the (un-)highlit region
>> too, and rebuild those with the updated faces.
> 
> I hope the number of faces you use in those display strings is small,
> in which case the feature should still work reasonably well, since you
> presumably are familiar with those faces and are managing them in your
> code.

Yes, here again it's just a handful of faces that may appear inside ‘display strings.  But there may be many such strings (e.g. one for every empty/tab-indented line).  In the pure font-lock approach we are discussing, these display strings would just be regenerated as text is altered. 

>> But suppose the change of region was precipitated by the removal or addition of text in the buffer,
>> not just point movement?  Now your old region (old-roi, above) is outdated, likely wrong, and possibly
>> had holes put in it by the edits.
> 
> That's exactly what JIT font-lock solves, right?  Editing a buffer
> changes the text, and thus the faces that need to be put on the text
> change also.  For example, something that was a comment can become
> non-comment, or vice versa.  Isn't what you describe similar (read:
> identical), except that the faces themselves are different, i.e. not
> font-lock faces?

I guess so. The difficulty seems perhaps the other way around: updating font-lock JIT for both buffer modifications and (potentially) point movement (simultaneously, without stepping on each other!).

>> It could be a buffer-local variable, which defines the size of the
>> region around point where the faces should change their appearance

> This was related to my idea of asking the display engine to handle
> faces specially in the vicinity of point.  Since the display engine
> examines each change in the face property, it could apply special
> handling for faces of buffer positions around point.  For a simple
> example, suppose that the buffer-local variable I mention above has
> the value
> 
>   (BEFORE AFTER :background "red")
> 
> where BEFORE and AFTER are numbers of positions before and after point
> to give the specified background color to all the faces in that
> region.  Then the display engine could automatically merge each face
> in the region with an anonymous face '(:background "red")', and use
> that for the characters in the region.

This could indeed be useful, but in my situation, it’s a bunch of smaller text regions between BEFORE and AFTER that need altering individually. Hence the interest in a top-level “alternative class” type specifier, ala CSS. 

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

  parent reply	other threads:[~2024-01-09 21:31 UTC|newest]

Thread overview: 37+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2024-01-08 21:49 region-based face-remapping 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 [this message]
2024-01-10 12:44     ` Eli Zaretskii
  -- strict thread matches above, loose matches on Subject: below --
2024-01-02  0:22 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
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

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

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

  git send-email \
    --in-reply-to=23BA0312-2129-49A5-A43F-900F789E8C54@gmail.com \
    --to=jdtsmith@gmail.com \
    --cc=eliz@gnu.org \
    --cc=emacs-devel@gnu.org \
    --cc=monnier@iro.umontreal.ca \
    /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 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.