unofficial mirror of emacs-devel@gnu.org 
 help / color / mirror / code / Atom feed
* Tracking buffer positions across time, without markers (was Re: PL support)
@ 2020-05-09 19:47 Clément Pit-Claudel
  2020-05-09 21:38 ` João Távora
  0 siblings, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-09 19:47 UTC (permalink / raw)
  To: Emacs developers, João Távora

Hi João,

On 09/05/2020 13.08, João Távora wrote:
> Since exchanging information about source-file changes is largely a
> solved problem, as soon as servers start declaring support the new
> syntax highlighting extensions, it's is a question of applying the
> text properties in an efficient manner.


Can you clarify what you mean by 'a solved problem'?  One long-standing issue that I've had with Emacs is that I don't know of a way to track buffer positions without adding markers.  Here's a concrete example:

I start with a buffer that contains "int foo ()", and send that to a subprocess (say a syntax highlighter, for example).  It returns [0:3:type; 4:7:name].  In the meantime, the user has inserted more text in the buffer, which now contains "static int foo ()".  If I apply the highlighting as-is, it will be all wrong!

Visual Studio has a nice API for this: there is a way to snapshot a buffer, and to translate positions between two snapshots.  In my example, this allows you to translate 0:3 in the original buffer to 7:10 in the new one.

I don't think Emacs has such a facility at the moment — did I miss something?

I've been thinking of building one for a while.  I think it can be done entirely in ELisp, by using the undo list: snapshots would be pointers into the undo list, and positions could be translated by iterating over all undo list entries between two snapshots and adjusting positions according to each undo-list entry.

Are you using something different in eglot? Or are you assuming that calls are fast enough that this isn't a problem?  I ran into this problem with very slow subprocesses, like running an SMT solver.

Clément.



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-09 19:47 Tracking buffer positions across time, without markers (was Re: PL support) Clément Pit-Claudel
@ 2020-05-09 21:38 ` João Távora
  2020-05-09 22:22   ` Clément Pit-Claudel
  0 siblings, 1 reply; 25+ messages in thread
From: João Távora @ 2020-05-09 21:38 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: Emacs developers

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

On Sat, May 9, 2020 at 8:47 PM Clément Pit-Claudel <cpitclaudel@gmail.com>
wrote:

> Can you clarify what you mean by 'a solved problem'?


I meant it in the context of LSP.


> One long-standing issue that I've had with Emacs is that I don't know of a
> way to track buffer positions without adding markers.  Here's a concrete
> example:
>
> I start with a buffer that contains "int foo ()", and send that to a
> subprocess (say a syntax highlighter, for example).  It returns [0:3:type;
> 4:7:name].  In the meantime, the user has inserted more text in the buffer,
> which now contains "static int foo ()".  If I apply the highlighting as-is,
> it will be all wrong!
>

Some idle time after you type, Eglot will inform the LSP server
that things have changed, and it will reply with more stuff
to highlight.

This is how I interpret this.  It's the way it works with, say syntax
errors, which are already supported.  I've NOT looked at the spec.

Did this help?

João

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

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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-09 21:38 ` João Távora
@ 2020-05-09 22:22   ` Clément Pit-Claudel
  2020-05-09 23:26     ` João Távora
  0 siblings, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-09 22:22 UTC (permalink / raw)
  To: João Távora; +Cc: Emacs developers

On 09/05/2020 17.38, João Távora wrote:
> On Sat, May 9, 2020 at 8:47 PM Clément Pit-Claudel <cpitclaudel@gmail.com <mailto:cpitclaudel@gmail.com>> wrote:
> 
>     Can you clarify what you mean by 'a solved problem'?  
> 
> 
> I meant it in the context of LSP. 
>  
> 
>     One long-standing issue that I've had with Emacs is that I don't know of a way to track buffer positions without adding markers.  Here's a concrete example:
> 
>     I start with a buffer that contains "int foo ()", and send that to a subprocess (say a syntax highlighter, for example).  It returns [0:3:type; 4:7:name].  In the meantime, the user has inserted more text in the buffer, which now contains "static int foo ()".  If I apply the highlighting as-is, it will be all wrong!
> 
> 
> Some idle time after you type, Eglot will inform the LSP server
> that things have changed, and it will reply with more stuff
> to highlight. 
> 
> This is how I interpret this.  It's the way it works with, say syntax
> errors, which are already supported.  I've NOT looked at the spec.
> 
> Did this help?

A bit.  But this works only if the interaction is fast enough, right? (Same for syntax errors: positions may well be outdated by the time the errors come back)



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-09 22:22   ` Clément Pit-Claudel
@ 2020-05-09 23:26     ` João Távora
  2020-05-10  3:45       ` Clément Pit-Claudel
  0 siblings, 1 reply; 25+ messages in thread
From: João Távora @ 2020-05-09 23:26 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: Emacs developers

On Sat, May 9, 2020 at 11:22 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
>
> On 09/05/2020 17.38, João Távora wrote:
> > On Sat, May 9, 2020 at 8:47 PM Clément Pit-Claudel <cpitclaudel@gmail.com <mailto:cpitclaudel@gmail.com>> wrote:
> >
> >     Can you clarify what you mean by 'a solved problem'?
> >
> >
> > I meant it in the context of LSP.
> >
> >
> >     One long-standing issue that I've had with Emacs is that I don't know of a way to track buffer positions without adding markers.  Here's a concrete example:
> >
> >     I start with a buffer that contains "int foo ()", and send that to a subprocess (say a syntax highlighter, for example).  It returns [0:3:type; 4:7:name].  In the meantime, the user has inserted more text in the buffer, which now contains "static int foo ()".  If I apply the highlighting as-is, it will be all wrong!
> >
> >
> > Some idle time after you type, Eglot will inform the LSP server
> > that things have changed, and it will reply with more stuff
> > to highlight.
> >
> > This is how I interpret this.  It's the way it works with, say syntax
> > errors, which are already supported.  I've NOT looked at the spec.
> >
> > Did this help?
>
> A bit.  But this works only if the interaction is fast enough, right? (Same for syntax errors: positions may well be outdated by the time the errors come back)

By that time another request is probably already underway.
The same thing happens in completion, for example.  As you
type more characters, the completion list that is about to be
rendered loses validity, you have to request another one.

This is done with an idle timer, much the way that Flycheck
works, I believe.  So you're not emitting one request per
keystroke. You emit a "check this buffer" request once the
user has stopped changing the buffer for a little while.

For syntax highlighting, and indentation, I suppose you would
want to do it every n inputs too, so that typing really fast doesn't
break too much.

But, as I said, I haven't read any of the spec yet on this topic,
because it is very new.

João



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-09 23:26     ` João Távora
@ 2020-05-10  3:45       ` Clément Pit-Claudel
  2020-05-10  4:32         ` Eli Zaretskii
  0 siblings, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-10  3:45 UTC (permalink / raw)
  To: João Távora; +Cc: Emacs developers

On 09/05/2020 19.26, João Távora wrote:
> This is done with an idle timer, much the way that Flycheck
> works, I believe. 

Yup, it's a longstanding issue in Flycheck ^^

> > A bit.  But this works only if the interaction is fast enough, right? (Same for syntax errors: positions may well be outdated by the time the errors come back)

> By that time another request is probably already underway.

As long as the requests are fast.  With slow checkers (typically, proof assistants and automated reasoning tools, a single query can easily take a minute — by that point lots can have changed in a buffer.

The APIs that make this work in Visual Studio (spans and snapshots) are described here: https://docs.microsoft.com/en-us/visualstudio/extensibility/inside-the-editor?view=vs-2019

I'd love to hear opinions on what the proper implementation of this would for Emacs be.



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10  3:45       ` Clément Pit-Claudel
@ 2020-05-10  4:32         ` Eli Zaretskii
  2020-05-10 19:27           ` Clément Pit-Claudel
  0 siblings, 1 reply; 25+ messages in thread
From: Eli Zaretskii @ 2020-05-10  4:32 UTC (permalink / raw)
  To: emacs-devel, Clément Pit-Claudel, João Távora
  Cc: Emacs developers

On May 10, 2020 6:45:13 AM GMT+03:00, "Clément Pit-Claudel" <cpitclaudel@gmail.com> wrote:
> On 09/05/2020 19.26, João Távora wrote:
> > This is done with an idle timer, much the way that Flycheck
> > works, I believe. 
> 
> Yup, it's a longstanding issue in Flycheck ^^
> 
> > > A bit.  But this works only if the interaction is fast enough,
> right? (Same for syntax errors: positions may well be outdated by the
> time the errors come back)
> 
> > By that time another request is probably already underway.
> 
> As long as the requests are fast.  With slow checkers (typically,
> proof assistants and automated reasoning tools, a single query can
> easily take a minute — by that point lots can have changed in a
> buffer.
> 
> The APIs that make this work in Visual Studio (spans and snapshots)
> are described here:
> https://docs.microsoft.com/en-us/visualstudio/extensibility/inside-the-editor?view=vs-2019
> 
> I'd love to hear opinions on what the proper implementation of this
> would for Emacs be.

Can you explain why using markers is not a good solution for this?



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10  4:32         ` Eli Zaretskii
@ 2020-05-10 19:27           ` Clément Pit-Claudel
  2020-05-10 19:42             ` Drew Adams
                               ` (3 more replies)
  0 siblings, 4 replies; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-10 19:27 UTC (permalink / raw)
  To: Eli Zaretskii, emacs-devel, João Távora

On 10/05/2020 00.32, Eli Zaretskii wrote:
> On May 10, 2020 6:45:13 AM GMT+03:00, "Clément Pit-Claudel" <cpitclaudel@gmail.com> wrote:
>> On 09/05/2020 19.26, João Távora wrote:
>>> This is done with an idle timer, much the way that Flycheck
>>> works, I believe. 
>>
>> Yup, it's a longstanding issue in Flycheck ^^
>>
>>>> A bit.  But this works only if the interaction is fast enough,
>> right? (Same for syntax errors: positions may well be outdated by the
>> time the errors come back)
>>
>>> By that time another request is probably already underway.
>>
>> As long as the requests are fast.  With slow checkers (typically,
>> proof assistants and automated reasoning tools, a single query can
>> easily take a minute — by that point lots can have changed in a
>> buffer.
>>
>> The APIs that make this work in Visual Studio (spans and snapshots)
>> are described here:
>> https://docs.microsoft.com/en-us/visualstudio/extensibility/inside-the-editor?view=vs-2019
>>
>> I'd love to hear opinions on what the proper implementation of this
>> would for Emacs be.
> 
> Can you explain why using markers is not a good solution for this?

Of course: in brief, because we don't know where to put the markers.

The general problem is this: I send the contents of a buffer to a subprocess.  Some time later, the subprocess returns a list of positions (offsets from the beginning of the buffer, or line/column pairs, etc).  At that point, these positions may be stale, since the contents of the buffer may have changed.  I need a way to translate these positions (relative to the old buffer contents) into positions relative to the new buffer contents.

Since we don't know beforehand what positions the subprocess will return, I don't think markers can help; right?




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

* RE: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 19:27           ` Clément Pit-Claudel
@ 2020-05-10 19:42             ` Drew Adams
  2020-05-10 19:49             ` Eli Zaretskii
                               ` (2 subsequent siblings)
  3 siblings, 0 replies; 25+ messages in thread
From: Drew Adams @ 2020-05-10 19:42 UTC (permalink / raw)
  To: Clément Pit-Claudel, Eli Zaretskii, emacs-devel,
	João Távora

> > Can you explain why using markers is not a good solution for this?
> 
> Of course: in brief, because we don't know where to put the markers.
> 
> The general problem is this: I send the contents of a buffer to a
> subprocess.  Some time later, the subprocess returns a list of
> positions (offsets from the beginning of the buffer, or line/column
> pairs, etc).  At that point, these positions may be stale, since the
> contents of the buffer may have changed.  I need a way to translate
> these positions (relative to the old buffer contents) into positions
> relative to the new buffer contents.
> 
> Since we don't know beforehand what positions the subprocess will
> return, I don't think markers can help; right?

The closest example I can recall, of handling this
kind of thing, is what is done for bookmarks.

In that case, in addition to saving the position,
some buffer text surrounding the position is saved,
as context.  In the case of bookmarks, saving can
be, and often is, persistent. 

Later (in the case of bookmarks, maybe MUCH later),
when the bookmark is jumped to, the code first goes
to the recorded position.  It then looks ahead and
back for context matches.  If necessary and possible,
it relocates the position based on the updated
content and matching context.

It can also prompt the user to confirm relocating
to the newly found position.

Dunno if such an approach is feasible/helpful in
the case you're considering.



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 19:27           ` Clément Pit-Claudel
  2020-05-10 19:42             ` Drew Adams
@ 2020-05-10 19:49             ` Eli Zaretskii
  2020-05-10 20:52               ` Clément Pit-Claudel
  2020-05-10 20:46             ` Stefan Monnier
  2020-05-11  0:17             ` Vladimir Sedach
  3 siblings, 1 reply; 25+ messages in thread
From: Eli Zaretskii @ 2020-05-10 19:49 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: joaotavora, emacs-devel

> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Sun, 10 May 2020 15:27:47 -0400
> 
> The general problem is this: I send the contents of a buffer to a subprocess.  Some time later, the subprocess returns a list of positions (offsets from the beginning of the buffer, or line/column pairs, etc).  At that point, these positions may be stale, since the contents of the buffer may have changed.  I need a way to translate these positions (relative to the old buffer contents) into positions relative to the new buffer contents.

If by the time the output arrives the user have edited the buffer, you
will have to throw the output away, and send a new request.  Rinse,
repeat.  Eventually, the user will stop typing, at least for a short
time, and the output that arrives after that could be used for
fontifying because no changes have been done.  But if this never
happens, i.e. the user keeps being ahead of the subprocess, it would
mean the buffer will not be fontified for a time that is long enough
to be an annoyance.  Which means the solution is not workable.  Right?

IOW, the process of sending whatever you need to send and receiving
the output should be fast enough to be completed before the user types
a lot, or at least short enough to hold off buffer modifications, or
else this is simply not going to work.  Think of the current JIT
font-lock: if it doesn't finish fontifying the current windowful by
the time the user decides to type something, the user will complain,
right?



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 19:27           ` Clément Pit-Claudel
  2020-05-10 19:42             ` Drew Adams
  2020-05-10 19:49             ` Eli Zaretskii
@ 2020-05-10 20:46             ` Stefan Monnier
  2020-05-11  2:27               ` Eli Zaretskii
  2020-05-11  0:17             ` Vladimir Sedach
  3 siblings, 1 reply; 25+ messages in thread
From: Stefan Monnier @ 2020-05-10 20:46 UTC (permalink / raw)
  To: Clément Pit-Claudel
  Cc: Eli Zaretskii, João Távora, emacs-devel

> The general problem is this: I send the contents of a buffer to
> a subprocess.  Some time later, the subprocess returns a list of positions
> (offsets from the beginning of the buffer, or line/column pairs, etc).
> At that point, these positions may be stale, since the contents of the
> buffer may have changed.  I need a way to translate these positions
> (relative to the old buffer contents) into positions relative to the new
> buffer contents.

As you said you should be able to use the undo-list for that.
It'll require a bit of work, but hopefully that can be used in
several places, justifying the investment.

If you have the option to ask for a more up-to-date version of the data
to be sent, you can obviously throw the data away, but even in that case
you should be able to do better with fairly little work: use an
after-change-function to keep track of just 2 markers that indicate the
beginning and end of the part of the buffer that's been modified.
Then you can easily translate all the positions before the first and
after the second marker and only discard the data between the two.


        Stefan




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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 19:49             ` Eli Zaretskii
@ 2020-05-10 20:52               ` Clément Pit-Claudel
  2020-05-11 14:24                 ` Eli Zaretskii
  0 siblings, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-10 20:52 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: joaotavora, emacs-devel

On 10/05/2020 15.49, Eli Zaretskii wrote:
>> From: Clément Pit-Claudel <cpitclaudel@gmail.com> Date: Sun, 10 May
>> 2020 15:27:47 -0400
>> 
>> The general problem is this: I send the contents of a buffer to a
>> subprocess.  Some time later, the subprocess returns a list of
>> positions (offsets from the beginning of the buffer, or line/column
>> pairs, etc).  At that point, these positions may be stale, since
>> the contents of the buffer may have changed.  I need a way to
>> translate these positions (relative to the old buffer contents)
>> into positions relative to the new buffer contents.
> 
> If by the time the output arrives the user have edited the buffer,
> you will have to throw the output away, and send a new request.

No, it's quite acceptable to use the old output in my case, as long as it can be displayed in the right place.

> Rinse, repeat.  Eventually, the user will stop typing, at least for a
> short time, and the output that arrives after that could be used for 
> fontifying because no changes have been done.  But if this never 
> happens, i.e. the user keeps being ahead of the subprocess, it would 
> mean the buffer will not be fontified for a time that is long enough 
> to be an annoyance.  Which means the solution is not workable.
> Right?

My use case is not fontification, it's showing errors and hints from a compiler.  It's not unusual for compilation cycles or checking to take up to a minute, and resending the query doesn't help.
 
> IOW, the process of sending whatever you need to send and receiving 
> the output should be fast enough to be completed before the user
> types a lot, or at least short enough to hold off buffer
> modifications, or else this is simply not going to work.

It works OK currently, although often the highlights are not exactly in the right place.




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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 19:27           ` Clément Pit-Claudel
                               ` (2 preceding siblings ...)
  2020-05-10 20:46             ` Stefan Monnier
@ 2020-05-11  0:17             ` Vladimir Sedach
  2020-05-11 14:18               ` Clément Pit-Claudel
  2020-05-11 14:39               ` Eli Zaretskii
  3 siblings, 2 replies; 25+ messages in thread
From: Vladimir Sedach @ 2020-05-11  0:17 UTC (permalink / raw)
  To: Clément Pit-Claudel
  Cc: Eli Zaretskii, João Távora, emacs-devel


Clément Pit-Claudel <cpitclaudel@gmail.com> writes:
> Since we don't know beforehand what positions the subprocess will
> return, I don't think markers can help; right?

It sounds like the fundamental thing you need here is a function from
the integers 1 to point-max of the buffer as it was when you sent
its contents to the sub-process, to the integers 1 to point-max of
the buffer as it is when the sub-process returns some results.

One naive way to obtain this function is to "snapshot" the buffer by
assigning every character in the buffer a text property with the
value of its position at the time of the snapshot.

A refinement would be to put the text property on tokens. Sticky text
properties would do the right thing when changing identifier names.

Another refinement is to use Stefan's idea of delimiting unmodified
intervals and only add properties in the modified interval.

Text properties are nice because they follow kill/yank. Markers do
not. A problem is that text properties are wiped away by
replace-string and similar.

I can see this displaying confusing and nonsensical results if there
are a lot of edits in the time it take the sub-process to return.

--
Vladimir Sedach
Software engineering services in Los Angeles https://oneofus.la



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 20:46             ` Stefan Monnier
@ 2020-05-11  2:27               ` Eli Zaretskii
  2020-05-11  3:19                 ` Stefan Monnier
  0 siblings, 1 reply; 25+ messages in thread
From: Eli Zaretskii @ 2020-05-11  2:27 UTC (permalink / raw)
  To: Stefan Monnier; +Cc: cpitclaudel, joaotavora, emacs-devel

> From: Stefan Monnier <monnier@iro.umontreal.ca>
> Cc: Eli Zaretskii <eliz@gnu.org>,  emacs-devel@gnu.org,
>   João Távora
>  <joaotavora@gmail.com>
> Date: Sun, 10 May 2020 16:46:29 -0400
> 
> If you have the option to ask for a more up-to-date version of the data
> to be sent, you can obviously throw the data away, but even in that case
> you should be able to do better with fairly little work: use an
> after-change-function to keep track of just 2 markers that indicate the
> beginning and end of the part of the buffer that's been modified.
> Then you can easily translate all the positions before the first and
> after the second marker and only discard the data between the two.

This is all possible, of course, but I don't (yet) see why it would be
necessary.  We survive without this complexity when using JIT
font-lock, and any alternative back-end for the same job should be
able to reuse the same basic architecture.



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11  2:27               ` Eli Zaretskii
@ 2020-05-11  3:19                 ` Stefan Monnier
  0 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2020-05-11  3:19 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: cpitclaudel, joaotavora, emacs-devel

> This is all possible, of course, but I don't (yet) see why it would be
> necessary.  We survive without this complexity when using JIT
> font-lock, and any alternative back-end for the same job should be
> able to reuse the same basic architecture.

His context is very different from JIT font-lock since it's
not synchronous.  He basically sends the buffer to some external
processs which replies a minute(!) later with some highlighting
instructions.  Those instructions obviously refer to the buffer as it was
a minute ago.  Jit-lock works "between buffer updates", so it doesn't
have to deal with this problem.


        Stefan




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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11  0:17             ` Vladimir Sedach
@ 2020-05-11 14:18               ` Clément Pit-Claudel
  2020-05-11 15:16                 ` João Távora
  2020-05-11 14:39               ` Eli Zaretskii
  1 sibling, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-11 14:18 UTC (permalink / raw)
  To: Vladimir Sedach; +Cc: Eli Zaretskii, João Távora, emacs-devel

On 10/05/2020 20.17, Vladimir Sedach wrote:
> 
> Clément Pit-Claudel <cpitclaudel@gmail.com> writes:
>> Since we don't know beforehand what positions the subprocess will
>> return, I don't think markers can help; right?
> 
> It sounds like the fundamental thing you need here is a function from
> the integers 1 to point-max of the buffer as it was when you sent
> its contents to the sub-process, to the integers 1 to point-max of
> the buffer as it is when the sub-process returns some results.

Yes, eactly, that's what I meant when I wrote "Visual Studio has a nice API for this: there is a way to snapshot a buffer, and to translate positions between two snapshots.  In my example, this allows you to translate 0:3 in the original buffer to 7:10 in the new one."

> Another refinement is to use Stefan's idea of delimiting unmodified
> intervals and only add properties in the modified interval.

Yes, I need to think more about that one :)

> A refinement would be to put the text property on tokens. Sticky text
> properties would do the right thing when changing identifier names.

Interesting idea.  At first I worried that this would be too costly, but font-lock uses text properties and is quite fast…
But wouldn't the process of mapping back from properties to spans of text be very costly?



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-10 20:52               ` Clément Pit-Claudel
@ 2020-05-11 14:24                 ` Eli Zaretskii
  2020-05-11 15:03                   ` Clément Pit-Claudel
  2020-05-11 15:25                   ` Stefan Monnier
  0 siblings, 2 replies; 25+ messages in thread
From: Eli Zaretskii @ 2020-05-11 14:24 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: joaotavora, emacs-devel

> Cc: emacs-devel@gnu.org, joaotavora@gmail.com
> From: Clément Pit-Claudel <cpitclaudel@gmail.com>
> Date: Sun, 10 May 2020 16:52:23 -0400
> 
> My use case is not fontification, it's showing errors and hints from a compiler.

Ah, I didn't realize that.  Then something like what Stefan suggested
should be good.  But even before that, I'd suggest to consider using
the two variables Emacs maintains for each buffer: the buffer position
before which there was no change and the buffer position after which
there was no change (given as offset from EOB).  It might be possible
to use these in many cases without relying on more complicated
mechanisms.

> It's not unusual for compilation cycles or checking to take up to a minute

Minutes sounds ... bad.  What takes minutes in these cases?



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11  0:17             ` Vladimir Sedach
  2020-05-11 14:18               ` Clément Pit-Claudel
@ 2020-05-11 14:39               ` Eli Zaretskii
  1 sibling, 0 replies; 25+ messages in thread
From: Eli Zaretskii @ 2020-05-11 14:39 UTC (permalink / raw)
  To: Vladimir Sedach; +Cc: cpitclaudel, joaotavora, emacs-devel

> From: Vladimir Sedach <vas@oneofus.la>
> Cc: Eli Zaretskii <eliz@gnu.org>, João Távora
>  <joaotavora@gmail.com>, emacs-devel@gnu.org
> Date: Sun, 10 May 2020 17:17:10 -0700
> 
> One naive way to obtain this function is to "snapshot" the buffer by
> assigning every character in the buffer a text property with the
> value of its position at the time of the snapshot.

This is not recommended, as it might slow down redisplay considerably.
The display engine examines text properties of characters as it moves
through the visible portion of the buffer deciding how to lay it out
on display.  Commands that use "display simulation", such as C-n, will
also be affected.



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 14:24                 ` Eli Zaretskii
@ 2020-05-11 15:03                   ` Clément Pit-Claudel
  2020-05-11 15:25                   ` Stefan Monnier
  1 sibling, 0 replies; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-11 15:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: joaotavora, emacs-devel

On 11/05/2020 10.24, Eli Zaretskii wrote:
>> It's not unusual for compilation cycles or checking to take up to a minute
> 
> Minutes sounds ... bad.  What takes minutes in these cases?

Typechecking :)
I often work with complicated type systems that can encode arbitrary properties, and there typechecking can be costly.
Or I work with tools that statically check assertions in code, and often these checks are pretty slow.




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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 14:18               ` Clément Pit-Claudel
@ 2020-05-11 15:16                 ` João Távora
  2020-05-11 15:33                   ` Clément Pit-Claudel
  0 siblings, 1 reply; 25+ messages in thread
From: João Távora @ 2020-05-11 15:16 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: Eli Zaretskii, emacs-devel

On Mon, May 11, 2020 at 3:18 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:

> Yes, eactly, that's what I meant when I wrote "Visual Studio has a nice API for this: there is a way to snapshot a buffer, and to translate positions between two snapshots.  In my example, this allows you to translate 0:3 in the original buffer to 7:10 in the new one."

Well, if I understand correctly, you can still do this with markers.
You just need to register, somehow, somewher, at the time you
make the request  to the  server that "3" means "that marker there".
Then recover this  information. In the worse case, this means this
means a table of markers that is as the number of positions in the
buffer, which is probably a performance no-no :-(

But if you could know in advance that the server would only return
things for a specific region, or only a subset of positions within that
region, then the costs could be reduced drastically.

By the way the way LSP deals with this is by not fixing it. It temporarily
misaligns the syntax errors.  But that's because it doesn't take 1 minute
to syntax-check :-), rather around 1 second or so in the common cases.

João



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 14:24                 ` Eli Zaretskii
  2020-05-11 15:03                   ` Clément Pit-Claudel
@ 2020-05-11 15:25                   ` Stefan Monnier
  1 sibling, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2020-05-11 15:25 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Clément Pit-Claudel, joaotavora, emacs-devel

>> It's not unusual for compilation cycles or checking to take up to a minute
> Minutes sounds ... bad.  What takes minutes in these cases?

Basically: proof-search.


        Stefan




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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 15:16                 ` João Távora
@ 2020-05-11 15:33                   ` Clément Pit-Claudel
  2020-05-11 15:44                     ` João Távora
  0 siblings, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-11 15:33 UTC (permalink / raw)
  To: João Távora; +Cc: Eli Zaretskii, emacs-devel

On 11/05/2020 11.16, João Távora wrote:
> On Mon, May 11, 2020 at 3:18 PM Clément Pit-Claudel
> <cpitclaudel@gmail.com> wrote:
> 
>> Yes, eactly, that's what I meant when I wrote "Visual Studio has a nice API for this: there is a way to snapshot a buffer, and to translate positions between two snapshots.  In my example, this allows you to translate 0:3 in the original buffer to 7:10 in the new one."
> 
> Well, if I understand correctly, you can still do this with markers.
> You just need to register, somehow, somewher, at the time you
> make the request  to the  server that "3" means "that marker there".
> Then recover this  information. In the worse case, this means this
> means a table of markers that is as the number of positions in the
> buffer, which is probably a performance no-no :-(

Indeed :(

> By the way the way LSP deals with this is by not fixing it. It temporarily
> misaligns the syntax errors.  But that's because it doesn't take 1 minute
> to syntax-check :-), rather around 1 second or so in the common cases.

Same in Flycheck :) People who write very slow typecheckers don't blame me, they blame their typecheckers ^^



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 15:33                   ` Clément Pit-Claudel
@ 2020-05-11 15:44                     ` João Távora
  2020-05-11 16:02                       ` Clément Pit-Claudel
  0 siblings, 1 reply; 25+ messages in thread
From: João Távora @ 2020-05-11 15:44 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: Eli Zaretskii, emacs-devel

On Mon, May 11, 2020 at 4:33 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:
>
> On 11/05/2020 11.16, João Távora wrote:
> > On Mon, May 11, 2020 at 3:18 PM Clément Pit-Claudel
> > <cpitclaudel@gmail.com> wrote:
> >
> >> Yes, eactly, that's what I meant when I wrote "Visual Studio has a nice API for this: there is a way to snapshot a buffer, and to translate positions between two snapshots.  In my example, this allows you to translate 0:3 in the original buffer to 7:10 in the new one."
> >
> > Well, if I understand correctly, you can still do this with markers.
> > You just need to register, somehow, somewher, at the time you
> > make the request  to the  server that "3" means "that marker there".
> > Then recover this  information. In the worse case, this means this
> > means a table of markers that is as the number of positions in the
> > buffer, which is probably a performance no-no :-(
>
> Indeed :(

Of course, the smart way is to use the buffer-undo-list.  Now I
understand Stefan's suggestion. You should be able to record
the value of the variable buffer-undo-list into a variable
at the time you make the request.  Then you need a function
that, given that value OLD-BUL, a buffer position OLD, the new
value of buffer-undo-list NEW-BUL and a thing called X,  gives
you the current buffer position NEW where a marker of type X would
have ended up if it had been set at OLD. This is a nice elisp exercise,
good for unit-testing with ert.  If you post it to emacs-help or reddit
someone maybe someone will do the hard work for you (maybe
a change from the general theme of indignation).

João



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 15:44                     ` João Távora
@ 2020-05-11 16:02                       ` Clément Pit-Claudel
  2020-05-11 16:11                         ` João Távora
  0 siblings, 1 reply; 25+ messages in thread
From: Clément Pit-Claudel @ 2020-05-11 16:02 UTC (permalink / raw)
  To: João Távora; +Cc: Eli Zaretskii, emacs-devel

On 11/05/2020 11.44, João Távora wrote:
> Of course, the smart way is to use the buffer-undo-list.

High praise!

> Now I understand Stefan's suggestion. You should be able to record 
> the value of the variable buffer-undo-list into a variable at the
> time you make the request.  Then you need a function that, given that
> value OLD-BUL, a buffer position OLD, the new value of
> buffer-undo-list NEW-BUL and a thing called X,  gives you the current
> buffer position NEW where a marker of type X would have ended up if
> it had been set at OLD.

Thanks, but I think you're just explaining back my suggestion to me :) In my original email, I wrote "I've been thinking of building one for a while.  I think it can be done entirely in ELisp, by using the undo list: snapshots would be pointers into the undo list, and positions could be translated by iterating over all undo list entries between two snapshots and adjusting positions according to each undo-list entry."

> This is a nice elisp exercise, good for unit-testing with ert.  If
> you post it to emacs-help or reddit someone maybe someone will do the
> hard work for you (maybe a change from the general theme of
> indignation).

Oh, no worries, I'll probably get around to doing it if no one beats me to it :)



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 16:02                       ` Clément Pit-Claudel
@ 2020-05-11 16:11                         ` João Távora
  2020-05-11 17:20                           ` Stefan Monnier
  0 siblings, 1 reply; 25+ messages in thread
From: João Távora @ 2020-05-11 16:11 UTC (permalink / raw)
  To: Clément Pit-Claudel; +Cc: Eli Zaretskii, emacs-devel

On Mon, May 11, 2020 at 5:02 PM Clément Pit-Claudel
<cpitclaudel@gmail.com> wrote:

> > Now I understand Stefan's suggestion. You should be able to record
> > the value of the variable buffer-undo-list into a variable at the
> > time you make the request.  Then you need a function that, given that
> > value OLD-BUL, a buffer position OLD, the new value of
> > buffer-undo-list NEW-BUL and a thing called X,  gives you the current
> > buffer position NEW where a marker of type X would have ended up if
> > it had been set at OLD.
>
> Thanks, but I think you're just explaining back my suggestion to me :)

Sorry.  Now you know I didn't read your mail in all that detail :D

you should have written an executive summary :-)

João



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

* Re: Tracking buffer positions across time, without markers (was Re: PL support)
  2020-05-11 16:11                         ` João Távora
@ 2020-05-11 17:20                           ` Stefan Monnier
  0 siblings, 0 replies; 25+ messages in thread
From: Stefan Monnier @ 2020-05-11 17:20 UTC (permalink / raw)
  To: João Távora
  Cc: Clément Pit-Claudel, Eli Zaretskii, emacs-devel

> you should have written an executive summary :-)

Actually, he should have included the code.

As a general rule, people should never ask questions without including
a solution in the form of code.  Even more so for reporting bugs.

A bug report without a patch is like a bike without a cake.


        Stefan "procrastinating"




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

end of thread, other threads:[~2020-05-11 17:20 UTC | newest]

Thread overview: 25+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2020-05-09 19:47 Tracking buffer positions across time, without markers (was Re: PL support) Clément Pit-Claudel
2020-05-09 21:38 ` João Távora
2020-05-09 22:22   ` Clément Pit-Claudel
2020-05-09 23:26     ` João Távora
2020-05-10  3:45       ` Clément Pit-Claudel
2020-05-10  4:32         ` Eli Zaretskii
2020-05-10 19:27           ` Clément Pit-Claudel
2020-05-10 19:42             ` Drew Adams
2020-05-10 19:49             ` Eli Zaretskii
2020-05-10 20:52               ` Clément Pit-Claudel
2020-05-11 14:24                 ` Eli Zaretskii
2020-05-11 15:03                   ` Clément Pit-Claudel
2020-05-11 15:25                   ` Stefan Monnier
2020-05-10 20:46             ` Stefan Monnier
2020-05-11  2:27               ` Eli Zaretskii
2020-05-11  3:19                 ` Stefan Monnier
2020-05-11  0:17             ` Vladimir Sedach
2020-05-11 14:18               ` Clément Pit-Claudel
2020-05-11 15:16                 ` João Távora
2020-05-11 15:33                   ` Clément Pit-Claudel
2020-05-11 15:44                     ` João Távora
2020-05-11 16:02                       ` Clément Pit-Claudel
2020-05-11 16:11                         ` João Távora
2020-05-11 17:20                           ` Stefan Monnier
2020-05-11 14:39               ` Eli Zaretskii

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).