multiline input: unable to delete previous lines #150

Closed
opened 1 year ago by mcpcpc · 9 comments
mcpcpc commented 1 year ago

This behavior was first reported as part of https://github.com/mcpcpc/kirc/issues/39 and appears to impact multiple terminal emulators (e.g. st and ate) while behaving fine in others (e.g. xterm)

To reproduce, one simply needs to read input from stdin (e.g. fgets) and type more characters than the width of the terminal window. the text that is longer than window width is then printed as a new line, making the previous line uneditable.

A simple verifiable example (written in C) includes the following:

#include <stdio.h>
#include <stdlib.h>

int
main() {
    char a[1000];
    fgets(a, 1000, stdin);
    printf("string: %s\n", a);
    return 0;
}
This behavior was first reported as part of https://github.com/mcpcpc/kirc/issues/39 and appears to impact multiple terminal emulators (e.g. st and ate) while behaving fine in others (e.g. xterm) To reproduce, one simply needs to read input from stdin (e.g. fgets) and type more characters than the width of the terminal window. the text that is longer than window width is then printed as a new line, making the previous line uneditable. A simple verifiable example (written in C) includes the following: ``` #include <stdio.h> #include <stdlib.h> int main() { char a[1000]; fgets(a, 1000, stdin); printf("string: %s\n", a); return 0; } ```
dnkl commented 1 year ago
Owner

From reading the original issue, and the reddit thread, I'm guessing you are referring to the "reverse wrap" mode. This is an xterm extension, and I think there are quite a lot of terminal emulators that don't implement it.

It's true that foot doesn't support this.

However, foot's current behavior is the standard behavior. It is xterm's default behavior too; you need to explicitly enable reverse wrap mode. It is mentioned in a couple of places in the xterm man page.

If you are going to depend on reverse wrap mode, your application should enable it programatically. Search for "Ps = 4 5 ⇒ Reverse-wraparound mode, xterm." in https://invisible-island.net/xterm/ctlseqs/ctlseqs.html.

I don't mind adding support for this to foot. Since most applications expect reverse wrap to be disabled, that would be the default. You'd have to enable it with CSI ? 45h.

From reading the original issue, and the reddit thread, I'm guessing you are referring to the _"reverse wrap"_ mode. This is an xterm **extension**, and I think there are quite a lot of terminal emulators that don't implement it. It's true that foot doesn't support this. However, foot's current behavior **is** the **standard** behavior. It is xterm's default behavior too; you need to explicitly enable reverse wrap mode. It is mentioned in a couple of places in the xterm man page. If you are going to depend on reverse wrap mode, your application should enable it programatically. Search for _"Ps = 4 5 ⇒ Reverse-wraparound mode, xterm."_ in https://invisible-island.net/xterm/ctlseqs/ctlseqs.html. I don't mind adding support for this to foot. Since most applications expect reverse wrap to be disabled, that would be the default. You'd have to enable it with `CSI ? 45h`.
dnkl added the
enhancement
label 1 year ago
Poster

Thanks for the quick follow up and clarifying why the behavior I expected "works" in xterm. Additionally, screen, tmux and urxvt seem to enable "reverse wrap" by default.

Standard or not, it seems like a "strange" to me why this would be the default sane behavior and has been raised by others (e.g. https://gitlab.gnome.org/GNOME/vte/-/issues/62).

I would agree that it would be nice to have "reverse wrap" mode as a user selectable feature and, as you indicated, enabled programmatically via CSI ? 45h.

For those interested, link to the Reddit thread.

Thanks for the quick follow up and clarifying _why_ the behavior I expected "works" in `xterm`. Additionally, `screen`, `tmux` and `urxvt` seem to enable "reverse wrap" by default. **Standard** or not, it seems like a "strange" to me why this would be the default _sane_ behavior and has been raised by others (e.g. https://gitlab.gnome.org/GNOME/vte/-/issues/62). I would agree that it would be nice to have "reverse wrap" mode as a user selectable feature and, as you indicated, enabled programmatically via `CSI ? 45h`. For those interested, link to the [Reddit thread](https://www.reddit.com/r/C_Programming/comments/j300kp/fgets_erase_previous_line_in_multiline_input/).
dnkl commented 1 year ago
Owner

Standard or not, it seems like a “strange” to me why this would be the default sane behavior and has been raised by others (e.g. https://gitlab.gnome.org/GNOME/vte/-/issues/62).

Compatibility I'd say. Applications need to have the same understanding of what an escape sequence is supposed to do as the terminal emulator. Most applications expect the cursor to stop at the left margin. Changing this risk breaking these applications.

Digging a bit deeper into this there's actually a terminfo entry for this: bw. If this capability is set, the terminal does reverse-wrapping.

XTerm's terminfo does not set bw, which I guess is why reverse-wrapping is disabled by default in XTerm. But like most things in XTerm, it can still be enabled by the user via xresources, or the command line. Or programatically by the application.

urxvt's terminfo does set bw, which explains why it does reverse-wrapping by default.

Thus, an application should ideally check the terminfo before relying on this feature, and be prepared to handle wrapping itself if not supported by the terminal.

This does complicate things slightly for foot; should we do like XTerm, or like urxvt?

At this point I'm not really sure what the best approach is, and I'm open for input.

@craigbarnes: do you have any thoughts on this?

> Standard or not, it seems like a “strange” to me why this would be the default sane behavior and has been raised by others (e.g. https://gitlab.gnome.org/GNOME/vte/-/issues/62). Compatibility I'd say. Applications need to have the same understanding of what an escape sequence is supposed to do as the terminal emulator. Most applications expect the cursor to stop at the left margin. Changing this risk breaking these applications. Digging a bit deeper into this there's actually a terminfo entry for this: `bw`. If this capability is set, the terminal does reverse-wrapping. XTerm's terminfo does **not** set `bw`, which I guess is why reverse-wrapping is disabled by default in XTerm. But like most things in XTerm, it can still be enabled by the user via xresources, or the command line. Or programatically by the application. urxvt's terminfo **does** set `bw`, which explains why it does reverse-wrapping by default. Thus, an application should ideally check the terminfo before relying on this feature, and be prepared to handle wrapping itself if not supported by the terminal. This does complicate things slightly for foot; should we do like XTerm, or like urxvt? At this point I'm not really sure what the best approach is, and I'm open for input. @craigbarnes: do you have any thoughts on this?
dnkl commented 1 year ago
Owner

To summarize, the way I see it we have three options:

  • Do nothing. Foot's terminfo doesn't have bw and thus applications cannot assume foot does reverse-wrapping.
  • Do nothing by default, but allow applications to programatically enable reverse-wrapping.
  • Set bw in foot's terminfo and do reverse-wrapping by default, but allow applications to programatically disable (and re-enable) it.
To summarize, the way I see it we have three options: * Do nothing. Foot's terminfo doesn't have `bw` and thus applications cannot assume foot does reverse-wrapping. * Do nothing _by default_, but allow applications to programatically enable reverse-wrapping. * Set `bw` in foot's terminfo and do reverse-wrapping by default, but allow applications to programatically disable (and re-enable) it.
Collaborator

@craigbarnes: do you have any thoughts on this?

I think it's worth supporting xterm's reverse-wraparound mode, if only for the sake of completeness, but I don't really have any particular opinion on what the default should be.

Even if it's implemented in foot though, it's still not going to realistically free client apps from having to deal with the non-wrapping behaviour in X number of other terminals.

The terminfo(5) man page says:

A very important point here is that the local cursor motions encoded in terminfo are undefined at the left and top edges of a CRT terminal. Programs should never attempt to backspace around the left edge, unless bw is given, and never attempt to go up locally off the top.

I guess that doesn't strictly apply in this case, since it's the user (rather than "the program") doing it, but it still implies that, if you want to have working multi-line editing, you need to either handle the portability quirks properly or otherwise use a library to do it for you.

> @craigbarnes: do you have any thoughts on this? I think it's worth supporting xterm's reverse-wraparound mode, if only for the sake of completeness, but I don't really have any particular opinion on what the default should be. Even if it's implemented in foot though, it's still not going to realistically free client apps from having to deal with the non-wrapping behaviour in *X* number of other terminals. The `terminfo(5)` man page says: > A very important point here is that the local cursor motions encoded in terminfo are undefined at the left and top edges of a CRT terminal. Programs should never attempt to backspace around the left edge, unless `bw` is given, and never attempt to go up locally off the top. I guess that doesn't strictly apply in this case, since it's the user (rather than "the program") doing it, but it still implies that, if you want to have working multi-line editing, you need to either handle the portability quirks properly or otherwise use a library to do it for you.
Collaborator

Relevant part of ECMA-48:

6.1.6 Implicit movement

...

In the following situation, the effect of an attempt to move the active data position is not defined by this Standard:

an attempt to perform an implicit movement when the active data position is the last character position of a line and the direction of the implicit movement is the same as that of the character progression, or when the active data position is the first character position of a line and the direction of the implicit movement is opposite to that of the character progression;

Depending on the implementation, an attempt to perform such movements may

a) cause a wrap-around movement;
b) cause the position to be blocked (a condition in which no graphic character can be entered until a valid explicit position movement is performed);
c) cause the position to remain where it is but permit graphic characters to be entered thereby replacing or overstriking the previously entered character;
d) cause the cursor to disappear from the operator's view;
e) cause the cursor to move to the opposite end of the display but one column or row offset;
f) cause scrolling to occur;
g) cause other implementation-dependent action.

Relevant part of ECMA-48: > 6.1.6 Implicit movement > > ... > >In the following situation, the effect of an attempt to move the active data position is not defined by this Standard: > > an attempt to perform an implicit movement when the active data position is the last character position of a line and the direction of the implicit movement is the same as that of the character progression, or when the active data position is the first character position of a line and the direction of the implicit movement is opposite to that of the character progression; > > Depending on the implementation, an attempt to perform such movements may > > a) cause a wrap-around movement; > b) cause the position to be blocked (a condition in which no graphic character can be entered until a valid explicit position movement is performed); > c) cause the position to remain where it is but permit graphic characters to be entered thereby replacing or overstriking the previously entered character; > d) cause the cursor to disappear from the operator's view; > e) cause the cursor to move to the opposite end of the display but one column or row offset; > f) cause scrolling to occur; > g) cause other implementation-dependent action.
dnkl commented 1 year ago
Owner

@craigbarnes thank you for taking the time to look into this (and so thoroughly!)

I think it’s worth supporting xterm’s reverse-wraparound mode, if only for the sake of completeness, but I don’t really have any particular opinion on what the default should be.

I implemented a prototype of this, and the patch is really quite small, so yes, I agree: it's worth implementing it.

From what I can tell, most terminals don't support this at all. I think that's an as good reason as any, to leave reverse wraparound disabled by default.

The terminfo(5) man page says:

Yeah, I read that too. I do think it's worth stressing: bw isn't the only "problem" with cursor movements around the margins.

I guess that doesn’t strictly apply in this case, since it’s the user (rather than “the program”) doing it, but it still implies that, if you want to have working multi-line editing, you need to either handle the portability quirks properly or otherwise use a library to do it for you.

Agreed.

Relevant part of ECMA-48:

I like how it lists six(!) different actions, and then ends the list with "or just about anything you can imagine"... :)

Just to name another problem; with or without bw, you'll see issues with backspace (in most terminals) when the cursor is past the right margin ("waiting" to be wrapped on the next character). urxvt handles this they way a user might expect; it deletes the last character, but XTerm (and pretty much all other terminals) instead deletes the second to last character. There's no terminfo capability that describes this behavior, as far as I know.

Anyway, what I'll do is implement the escapes to enable/disable reverse-wraparound. The default mode will be disabled. The bw capability will not be added to foot's terminfo.

@mcpcpc this turned out to be a fairly long discussion. Hopefully the solution described above is good enough for your use case.

@craigbarnes thank you for taking the time to look into this (and so thoroughly!) > I think it’s worth supporting xterm’s reverse-wraparound mode, if only for the sake of completeness, but I don’t really have any particular opinion on what the default should be. I implemented a prototype of this, and the patch is really quite small, so yes, I agree: it's worth implementing it. From what I can tell, most terminals don't support this at all. I think that's an as good reason as any, to leave reverse wraparound disabled by default. > The terminfo(5) man page says: Yeah, I read that too. I do think it's worth stressing: `bw` isn't the only "problem" with cursor movements around the margins. > I guess that doesn’t strictly apply in this case, since it’s the user (rather than “the program”) doing it, but it still implies that, if you want to have working multi-line editing, you need to either handle the portability quirks properly or otherwise use a library to do it for you. Agreed. > Relevant part of ECMA-48: I like how it lists six(!) different actions, **and** then ends the list with _"or just about anything you can imagine"_... :) Just to name another problem; with or without `bw`, you'll see issues with backspace (in most terminals) when the cursor is past the right margin ("waiting" to be wrapped on the next character). urxvt handles this they way a user might expect; it deletes the **last** character, but XTerm (and pretty much all other terminals) instead deletes the **second to last** character. There's no terminfo capability that describes this behavior, as far as I know. Anyway, what I'll do is implement the escapes to enable/disable reverse-wraparound. The default mode will be **disabled**. The `bw` capability will **not** be added to foot's terminfo. @mcpcpc this turned out to be a fairly long discussion. Hopefully the solution described above is good enough for your use case.
dnkl commented 1 year ago
Owner

#153 implements reverse auto-wrap. As usual, I would appreciate testing :)

https://codeberg.org/dnkl/foot/pulls/153 implements reverse auto-wrap. As usual, I would appreciate testing :)
dnkl self-assigned this 1 year ago
Poster

#153 implements reverse auto-wrap. As usual, I would appreciate testing :)

THis satisfies my original intent. I will reach out to a few people and see if they can verify this PR for you asap.

I appreciate you taking the time to consider this enhancement! Also, the discussion was very informative =)

> https://codeberg.org/dnkl/foot/pulls/153 implements reverse auto-wrap. As usual, I would appreciate testing :) THis satisfies my original intent. I will reach out to a few people and see if they can verify this PR for you asap. I appreciate you taking the time to consider this enhancement! Also, the discussion was very informative =)
dnkl closed this issue 1 year ago
Sign in to join this conversation.
No Milestone
No Assignees
3 Participants
Notifications
Due Date

No due date set.

Dependencies

This issue currently doesn't have any dependencies.

Loading…
There is no content yet.