[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: Moving point around empty overlays with 'after-text
From: |
Platon Pronko |
Subject: |
Re: Moving point around empty overlays with 'after-text |
Date: |
Tue, 11 Apr 2023 16:49:10 +0800 |
User-agent: |
Mozilla/5.0 (X11; Linux x86_64; rv:102.0) Gecko/20100101 Thunderbird/102.9.1 |
On 2023-04-10 17:56, Yuri Khan wrote:
You’re talking about typing “41, ” as if it were an atomic action. In
some cases (e.g. pasting from clipboard) it could be, but normally
you’ll be inserting characters one by one, and it might be instructive
to look at the buffer contents and expected inlay behavior through the
intermediate stages.
0. Base state:
def test(a1: Int = 1, a2: Int = 2, a3: Int = 3) {}
test({a1=}42)
1. You type “4”. Depending on how the editor interprets the insertion
around the inlay:
1a. The editor inserts the digit 4 at the position where the inlay is.
The text is now “test(442)”. Syntactically, you just changed the
argument value, so the inlay should stay before the newly inserted
character.
def test(a1: Int = 1, a2: Int = 2, a3: Int = 3) {}
test({a1=}42)
1b. The editor lets you insert the digit 4 before the inlay and
somehow knows it is separate from the “42” that used to be the first
argument. The text is now “test(4█42)” where the block represents some
kind of separator. Likely, this text is invalid syntax, so the inlay
is now technically incorrect.
def test(a1: Int = 1, a2: Int = 2, a3: Int = 3) {}
test(4█a1=█42)
2. You type “1”. Same thing as “4” before, only in case 2a the
insertion is no longer adjacent to the inlay so the issue does not
even arise. In case 2b, you now have “test(41█42)” in the buffer and
“test(41█a1=█42)” in the view.
3. You type “,”.
3a. The text is now “test(41,42)” and syntactically it’s a call with
two arguments. The inlay for the first argument stays right after the
opening paren; a new inlay appears after the comma and before the 42.
3b. The text is now syntactically well-formed, so the IDE can update the inlays.
def test(a1: Int = 1, a2: Int = 2, a3: Int = 3) {}
test({a1=}41,{a2=}42)
4. You type a space.
For typographical reasons, a well-designed grammar will infer the
space to belong to the separator, not the argument expression. The
inlay will shift after the space.
def test(a1: Int = 1, a2: Int = 2, a3: Int = 3) {}
test({a1=}41, {a2=}42)
Basically, after working out the above, my question is: Why is it
important to let the user choose whether to insert newly typed
characters before or after the inlay, if the inlay is going to be
updated and repositioned based on the resulting buffer text?
Alternatively, why is it important to let the user bring the buffer
into an invalid state that may even be unrepresentable in text?
You are discussing the technical part, and there you are correct on all points.
Of course, from the buffer standpoint all my examples are equivalent and it
makes absolutely no difference on what side of the overlay the cursor is. And
after the user types something the well-implemented mode will remove the
overlay and everything will be fine.
I'm talking more about the user intention, before he actually types anything,
and consequently the confusion he will temporarily experience when he will try
to execute this intention. We here in Emacs mailing list understand the
internals quite well and thus can understand that the overlay is zero-width and
cursor position is actually the same on both sides. Less-enlightened user won't
- for him the inlay is something tangible, present in the buffer the same way
as the characters are present in the buffer.
And in the discussed example the user can have two different intentions:
Intention 1: prepending something to argument value. In this case he will want
to position the cursor after the overlay:
test(a1=<cursor>42)
test(a1=1<cursor>42)
(here and after - I'm intentionally omitting the braces around the {a1=} part, to
illustrate my point better - usually the inlays look very close to syntactically correct
code, so when the developer is working with the code he is likely to treat that
"nonexistent" code very similarly to the real one, as if it was actually
present)
It will not make sense for him to want to position the cursor before the
overlay. Look how confusing his intuition would be if overlay was setup to show
cursor before:
test(<cusor>a1=42)
// User is confused.
// He might want to move cursor to the right,
// but then it jumps into the middle of the next argument:
test(a1=4<cursor>)
// He returns back:
test(<cursor>a1=42)
// User types "1". Here's how his brain predicts the next state of the buffer:
test(1a1=42)
Of course once the inlay is hidden, everything is back to normal. But user is
already slightly frustrated.
Intention 2: prepending another argument. In this case he will want to position
the cursor before the overlay:
test(<cursor>a1=42)
// User tries to type "a0=1," (let's imagine there was such an argument)
test(a<cursor>a1=42)
// More typing
test(a0=1,<cursor>a1=42)
Here, if the overlay was set up such that the cursor is shown after, the user's
intuition would be screwed again:
test(a1=<cursor>42)
// Why my cursor is between the argument name and argument value?
// Move left:
test<cursor>(a1=42)
// Something is broken, let's move back:
test(a1=<cursor>42)
// Let's try typing "a0=1". Here's the intuitively expected state of the
buffer, completely garbled:
test(a1=a0=142)
In all these examples nothing horrible happened - after a short struggle the user will be
able to fix the issue and continue on his way. But such issues contribute to the overall
feeling of the editor, and I would be sad if Emacs was leaving people with the feeling of
"ever so slightly broken". We can be better than that :)
(and in "we" I include myself - I'm not just idly discussing, I will be willing
to go into the code and create a patch if we can agree on how it should be patched, if it
should be)
Oh, and by the way, even if we disregard all of the above - we still don't have
any well-defined way of positioning the cursor around the zero-width overlay.
The way it works currently is it's either broken and cursor is shown on the
wrong side, or the code relies on some side effect of overlay implementation
(c.f. https://debbugs.gnu.org/cgi/bugreport.cgi?bug=62540).
- Re: Moving point around empty overlays with 'after-text, (continued)
- Re: Moving point around empty overlays with 'after-text, Eli Zaretskii, 2023/04/08
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/08
- Re: Moving point around empty overlays with 'after-text, Ash, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, tomas, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Eli Zaretskii, 2023/04/10
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/10
- Re: Moving point around empty overlays with 'after-text, Yuri Khan, 2023/04/10
- Re: Moving point around empty overlays with 'after-text,
Platon Pronko <=
- Re: Moving point around empty overlays with 'after-text, Yuri Khan, 2023/04/11
- Re: Moving point around empty overlays with 'after-text, tomas, 2023/04/10
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/10
- Re: Moving point around empty overlays with 'after-text, Ash, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Ash, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/09
- Re: Moving point around empty overlays with 'after-text, Ash, 2023/04/10
- Re: Moving point around empty overlays with 'after-text, Eli Zaretskii, 2023/04/10
- Re: Moving point around empty overlays with 'after-text, Platon Pronko, 2023/04/10