-
-
Notifications
You must be signed in to change notification settings - Fork 972
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
kitty breaks soft-wrap on vertical cursor motion #5766
Comments
\n is not move the cursor down. \n is newline. If you want to move the A newline is emphatically not the same as cursor down. cursor down does It is very unfortunate that these other terminals appear to change the As such, I am not inclined to copy this bad design in kitty. fish should I am closing this issue, but feel free to post if you have further |
I've also noticed multiple feedbacks here about copying fish commands (selecting text with the mouse) in kitty being inserted with extra If I remember correctly, kitty will copy the text content as is, without doing some magic to the line breaks at the edge of the screen. I personally think a terminal with fully predictable behavior would be better, for cli program developers. |
@kovidgoyal I would like to share some context which you may have missed, in hopes you will reconsider. First off: I very much agree that newline is a silly choice for fish does not actively choose to emit newlines: rather newline is the sequence published by the terminfo database for For those following along at home, one can confirm this by running This doesn't just affect fish. Any app which uses ncurses or even terminfo may be affected, by simply doing what the terminfo says. It's a dumb state of affairs, but we are all stuck with it, and I am politely requesting you to grit your teeth and implement newline as |
Lookup cud not cud1 and you will be fine. |
I noticed in the fish issue faho replied.
@kovidgoyal
#!/bin/bash
# Print some lines to fill the window
echo prev-1; echo prev-2; echo prev-3; echo prev-4;
# Since cud doesn't scroll on the last line, use `\n` line breaks for two lines first.
echo -en "line-1\nline-2\r\x1b[A";
# Then calculate and "reflow" the prompt based on the window width (here use a fixed width of 10 cells).
echo -en "\x1b[K0123456789"; echo -en "\r\x1b[B"; echo -en "\x1b[Kabc";
# Press Enter to continue
read; echo;
# Since only the current (last) prompt is rendered by the shell,
# the previous prompt with the command needs to be reprinted at this point in a single line.
# Later when the window size changes, they will be wrapped by kitty.
echo -en "\r\x1b[K\x1b[A\x1b[K"; echo "0123456789abc";
# Print the next prompt
echo -en "line-1\nline-2\r\x1b[A"; echo -en "\x1b[Knextprompt"; echo -en "\r\x1b[B"; echo -en "\x1b[K123";
# Trying to move the cursor should not affect line wrapping.
echo -en "\x1b[4A\x1b[4B";
# Try changing the window size at this point and the first prompt output will soft-wrap normally.
# The second one is unchanged because it has not been redrawn in this example.
read; kitty --config=NONE \
-o remember_window_size=no \
-o initial_window_width=10c \
-o initial_window_height=5c \
bash /path/to/example.sh However, even with Maybe I'm missing something and the above approach doesn't seem so practicable. |
I dont follow. Why does fish need to move the cursor down while redrawing the prompt? It just starts at the top and prints out everything, there should be no need for cursor movement at all. Witness the fact that no other shell has this issue. Once the prompt is fully printed out, fish moves the cursor back to its required position, this is where cursor movement comes in, and here there is no need for newlines. |
zsh is unaffected because they deliberately check for the case that Nevertheless zsh exhibits the same bug when run in TERMs without
If |
You dont need a workaround, simply use the terminfo cud property instead of cud1. If it doesn't exist fall back to cud1. It's two bytes longer, I seriously doubt that is going to cause anyone any issues. And as zsh shows you dont need down cursor to scroll lines. Quoting from the terminfo man page
You are relying on an undocumented side effect of cud1. If you need to scroll lines the correct terminfo parameter to use is ind not cud1. In fact according to the man page cud1 must not alter the text. So using newline for cud1 is actually a bug. I might change kitty's terminfo to not use newline for cud1. Since in kitty newline does affect the text, by adding a newline to it. |
I have changed kitty's terminfo to use \EB for cud1. If fish relies on cud1 scrolling lines, it needs to stop doing that. |
Actually I am going to revert the commit to change cud1 in kitty's terminfo. Given the current buggy use of cud1 in fish doing that fixes this issue but has the problem that fish cant render multiline text if the prompt is at the bottom of the screen, which is a much bigger issue. So I am afraid this can only be fixed in fish. |
…y with the terminfo man page" This reverts commit d8284be. See #5766 (comment)
And just for completeness, using kitty --dump-commands this is how fish draws multi-line text at a prompt:
So what it does when it wants to draw a character that it believes will go onto the next line is (leaving out the style changes)
This is pretty weird to begin with but presumably it has good reasons for this complicated dance, who knows. To fix it what you need to do is in step 8 instead of emitting \n emit \e[B to move the cursor down. There is no need to use \n here because you have just moved the cursor up 1 in step 6. Therefore, the screen will never scroll in any case. And while you are about it since you say one of the reasons you dont want to use \e[B is the two extra bytes, you can remove the two redundant \r one in step 1 and one in step 7. That will save you two bytes. |
As a point of comparison, this is how bash (aka readline) draws the same scenario
And this is how zsh draws it
|
fish has complicated logic for rendering because it supports features like autosuggestions, syntax highlighting, right prompt, etc, all of which require fish to calculate the actual terminal-width-aware rendering in a way that other shells do not. fish does emit excessive cursor positioning sequences; these are (often desperate) attempts to work around inconsistencies between terminals, which are a challenge for a shell to deal with. |
On Thu, Dec 22, 2022 at 11:09:42PM -0800, Peter Ammon wrote:
fish has complicated logic for rendering because it supports features like autosuggestions, syntax highlighting, right prompt, etc, all of which require fish to calculate the actual terminal-width-aware rendering in a way that other shells do not. fish does emit excessive cursor positioning sequences; these are (often desperate) attempts to work around inconsistencies between different terminal apps.
zsh has all those as well, just FYI.
From looking at the traces, its quite obvious that what fish is doing is
calculating when it expects the cursor to move to the next line, and
when it thinks it has, it deliberately moves the cursor up, and then emits
\r\r\n to move it down again. I am very curious to know what terminal
bug this algorithm is circumventing. And my contention is that in this
part of your rendering algorithm if you use \e[B instead of \n it will
break nothing, since you arent actually expecting a scroll, and will fix
this bug.
|
Sure. Our biggest challenge is calculating the width of rendered text, especially ambiguous-width characters and emoji. Terminals render these with inconsistent widths, sometimes even providing user settings to change how wide they are. Here is an example using kitty. I paste in Hammer and Wrench (U+1F6E0) with variation selector 15 (U+FE0E), first with zsh and then fish. zsh only renders one character, despite multiple pastes, and then allows deleting into the prompt, which it should never do. And when I hit enter it runs a command which was not visible on the command line. It does this because it does not conservately reposition the cursor; it has lost track of where the cursor is. fish renders it fine without these problems. This is because, while fish also miscalculates the width (this one is really hard), it emits cursor movement sequences to defend against miscalculation so it doesn't get lost. That explains the strange and excessive cursor positioning escape sequences you identified. They're not for fun, they solve a real problem. Screen.Recording.2022-12-23.at.12.04.39.AM.mov |
Sure, but what does this have to do with using cursor down after cursor The change I proposed above, of using cursor down instead of \n when |
Thanks, @kovidgoyal. |
(This issue was first reported against kitty, then that got reported to fish shell, I am bringing it back to kitty with a reduced test case.)
"Soft wrap" refers to the behavior where lines which wrapped because they exceeded the width of the terminal, may reflow and "unwrap" when the terminal's width is increased. This follows the behavior of text editors.
Kitty supports soft wrap, but unlike other terminals the soft-wrap gets "broken" when a newline is emitted on a previously wrapped line. (Note that newline is the typical value of
cursor_down
in ncurses.)To reproduce:
gcc test.c
). This code emits a line of 600 Xs, which will soft wrap. It then moves the cursor into and out of those lines../a.out
) in a terminal whose width is around 100 columnsObserved behavior: the lines of Xs do not reflow.
Expected behavior: the lines of Xs reflow, as they do in other terminals (tested with Terminal.app, iTerm2, alacritty)
Comment out the "Cursor motion" region and the soft-wrap is restored.
C code follows:
Environment details
Tested with kitty master (fefafda) run as
kitty -c NONE
The text was updated successfully, but these errors were encountered: