Reapply "Clear to eol before outputting line in multi-line prompt"

In case a terminal resize[1] causes us
to repaint a multi-line prompt that changes width like

    function fish_prompt
        for i in 1 2 3
            random choice 'aaaaaaaaaaaaaaaaaaaaaaaaaaaaa' 'bbbbbbbbbbb'
        end
    end

we add a clr_eol after each line[2] , to make sure
that a "b" line does not have leftover "a" letters
(80aaae5b7 (Clear to end of each line in left prompt, 2020-10-25)).

Unfortunately, if a prompt line takes up all the columns, clr_eol will
wrongly clear the last column. Reproduce with

    function fish_prompt
        string repeat $COLUMNS -
        echo "$PWD> "
    end

and observe that the last "-" is missing.

Previous (reverted) attempt d3ceba107 (Clear to eol before outputting line
in multi-line prompt, 2021-05-17) found the right fix but had an off-by-one
error which reintroduced the leftover "a" letters in the "random choice"
prompt above.

Given prompt string "aa\nbb\ncc", it wrongly printed

    clr_eol "aa" clr_eol "\nbb" "\ncc"

Observe that the first line is cleared twice, while the second line is
never cleared. Fix that.

[1]: or an async "commandline -f repaint" triggered by a uvar change /
     async prompt update
[2]: except after the last line where we probably already emit clr_eol
     elsewhere..

Alternative fix: emit both clr_eol and clr_bol *before* drawing the current
line. However, if fish and the terminal disagree on character width, that
approach might erase too much.

Closes #8164
This commit is contained in:
Johannes Altmanninger 2024-09-28 09:14:20 +02:00
parent 48a6550688
commit 263f1b35de

View file

@ -824,11 +824,11 @@ impl Screen {
zelf.write_bytes(b"\x1b]133;A;special_key=1\x07");
let mut start = 0;
for line_break in left_prompt_layout.line_breaks {
zelf.write_str(&left_prompt[start..line_break]);
zelf.outp
.borrow_mut()
.tputs_if_some(&term.and_then(|term| term.clr_eol.as_ref()));
start = line_break;
zelf.write_str(&left_prompt[start..=line_break]);
start = line_break + 1;
}
zelf.write_str(&left_prompt[start..]);
zelf.actual_left_prompt = left_prompt.to_owned();