add "mess when resizing" to troubleshooting

This commit is contained in:
romkatv 2020-02-01 17:37:04 +01:00
parent cea51ee866
commit 0b9829d409
1 changed files with 128 additions and 0 deletions

128
README.md
View File

@ -1198,6 +1198,133 @@ There are several ways to fix this.
The parameter you are looking for is called `POWERLEVEL9K_DIR_BACKGROUND`. You can find it in
in `~/.p10k.zsh`. Uncomment it if it's commented out and try different values.
### Horrific mess when resizing terminal window
When you resize terminal window horizontally back and forth a few times, you might see this ugly
picture.
![Powerlevel10k Resizing Mess](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resizing-mess.png)
tl;dr: This is a bug in Zsh that isn't specific to Powerlevel10k. See [mitigation](#mitigation).
#### Zsh bug
This issue is caused by a bug in Zsh that gets triggered the vertical distance between the start of
the current prompt and the cursor (henceforth `VD`) changes when the terminal window is resized.
This bug is not specific to Powerlevel10k.
When a terminal window gets shrunk horizontally, there are two ways for a terminal to handle long
lines that no longer fit: *reflow* or *truncate*.
Terminal content before shrinking:
![Terminal Content Before Shrinking](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-original.png)
Terminal reflows text when shrinking:
![Terminal Reflows Text When Shrinking](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-reflow.png)
Terminal truncates text when shrinking:
![Terminal Truncates Text When Shrinking](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-truncate.png)
Reflowing strategy can change the hight of terminal content. If such content happens to be between
the start of the current prompt and the cursor, Zsh will print prompt on the wrong line. Truncation
strategy never changes the hight of terminal content, so it doesn't trigger this bug in Zsh.
Let's see how the bug plays out in slow motion. We'll start by launching `zsh -df` and pasting
the following code:
```zsh
function pause() { read -s }
functions -M pause 0
reset
print -l {1..3}
setopt prompt_subst
PROMPT=$'${$((pause()))+}left>${(pl.$((COLUMNS-12))..-.)}<right\n> '
```
When `PROMPT` gets expanded, it calls `pause` to let us observe the state of the terminal. Here's
the initial state:
![Zsh Resizing Bug 1](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-bug-1.png)
Zsh keeps track of the cursor position relative to the start of the current prompt. In this case it
knows that the cursor is one line below. When we shrink the terminal window, it looks like this:
![Zsh Resizing Bug 2](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-bug-2.png)
At this point the terminal sends `SIGWINCH` to Zsh to notify it about changes in the terminal
dimensions. Note that this signal is sent *after* the content of the terminal has been reflown.
When Zsh receives `SIGWINCH`, it attempts to erase the current prompt and print it anew. It goes to
the position where it *thinks* the current prompt is -- one line above the cursor (!) -- erases all
terminal content that follows and prints reexpanded prompt there. However, after resizing prompt is
no longer one line above the cursor. It's two lines above! Zsh ends up printing new prompt one line
too low.
![Zsh Resizing Bug 3](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-bug-3.png)
In this case we ended up with unwanted junk content because `VD` has *increased*. When you make
terminal window wider, `VD` can also *decrease*, which would result in the new prompt being printed
higher than intended, potentially erasing useful content in the process.
Here are a few more examples where shrinking terminal window increased `VD`.
Simple one-line left prompt with right prompt. No `prompt_subst`. Note that the cursor is below the
prompt line (hit *ESC-ENTER* to get it there).
![Zsh Prompt That Breaks on Terminal Shrinking 1](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-breakable-1.png)
Simple one-line left prompt. No `prompt_subst`, no right prompt. Here `VD` is bound to increase
upon terminal shrinking due to the command line wrapping around.
![Zsh Prompt That Breaks on Terminal Shrinking 2](
https://raw.githubusercontent.com/romkatv/powerlevel10k-media/master/resize-breakable-2.png)
#### Zsh patch
The bug described above has been fixed in [this branch](
https://github.com/romkatv/zsh/tree/fix-winchanged). The idea behind the fix is to use `sc` (save
cursor) terminal capability before printing prompt and `rc` (restore cursor) to move cursor back
to the same position when prompt needs to be refreshed.
There are two alternative approaches to fixing the bug that may seem to work at fight glance but in
fact don't:
- Instead of `sc`, use `u7` terminal capability to query the current cursor position and then `cup`
to go back to it. This doesn't work because the absolute position of the start of the current
prompt changes when text gets reflown.
- Recompute `VD` based on new terminal dimensions before attempting to refresh prompt. This doesn't
work because Zsh doesn't know whether terminal reflows text or truncates it. If Zsh could somehow
know that the terminal reflows text, this approach still wouldn't work on terminals that
continuously reflow text and rapid-fire `SIGWINCH` when the window is being resized. In such
environment real terminal dimensions go out of sync with what Zsh thinks the dimensions are.
There is no ETA for the patch making its way into upstream Zsh. See [discussion](
https://www.zsh.org/mla/workers//2019/msg00561.html).
#### Mitigation
There are a few mitigation options for this issue.
- Apply [the patch](#zsh-patch) and rebuild Zsh from source.
- Disable text reflowing on window resize in terminal settings. If your terminal doesn't have this
setting, try a different terminal.
- Avoid long lines between the start of prompt and cursor.
1. Disable right prompt with `POWERLEVEL9K_RIGHT_PROMPT_ELEMENTS=()`.
2. Disable ruler with `POWERLEVEL9K_SHOW_RULER=false`.
3. Disable prompt gap with `POWERLEVEL9K_MULTILINE_FIRST_PROMPT_GAP_CHAR=' '`.
## Table of contents
- [Features](#features)
@ -1266,3 +1393,4 @@ There are several ways to fix this.
- [Weird things happen after typing `source ~/.zshrc`](#weird-things-happen-after-typing-source-zshrc)
- [Cannot make Powerlevel10k work with my plugin manager](#cannot-make-powerlevel10k-work-with-my-plugin-manager)
- [Directory is difficult to see in prompt when using Rainbow style](#directory-is-difficult-to-see-in-prompt-when-using-rainbow-style)
- [Horrific mess when resizing terminal window](#horrific-mess-when-resizing-terminal-window)