diff --git a/src/screen.rs b/src/screen.rs index a4e9cc59d..32b2c96be 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -2049,6 +2049,10 @@ fn compute_layout( .split(|&c| c == '\n') .enumerate() { + if available_vertical_space == 0 { + truncated_vertically = true; + break; + } let autosuggestion_line = wstr::from_char_slice(autosuggestion_line); // Calculate space available for autosuggestion. @@ -2063,36 +2067,56 @@ fn compute_layout( } else { indent_width(suggestion_start - "\n".len()) }; + available_vertical_space = available_vertical_space.saturating_sub(width / screen_width); + if available_vertical_space == 0 { + truncated_vertically = true; + break; + } let column = width % screen_width; - let suggestion_line_height = { - let mut column = column; + fn consumed_lines_or_truncated_suggestion( + screen_width: usize, + available_vertical_space: usize, + mut column: usize, + autosuggestion_line: &wstr, + ) -> Result { let mut lines = 1; - for ch in autosuggestion_line.chars() { + for (i, ch) in autosuggestion_line.char_indices() { let ch_width = wcwidth_rendered_min_0(ch); let new_column = column + ch_width; - if new_column > screen_width { + if new_column >= screen_width { column = 0; - } - if column == 0 && ch_width != 0 { lines += 1; } - column = if new_column == screen_width { - 0 - } else { - column + ch_width - }; + let barely_softwrapped = new_column == screen_width; + if !barely_softwrapped { + column += ch_width; + } + if lines > available_vertical_space { + return Err(autosuggestion_line.slice_to(i)); + } } - lines - }; - match available_vertical_space.checked_sub(suggestion_line_height) { - Some(lines) => available_vertical_space = lines, - None => { - truncated_vertically = true; - break; - } - }; - - suggestion_lines.push(autosuggestion_line); + Ok(lines) + } + suggestion_lines.push( + match consumed_lines_or_truncated_suggestion( + screen_width, + available_vertical_space, + column, + autosuggestion_line, + ) { + Ok(lines) => { + available_vertical_space -= lines; + autosuggestion_line + } + Err(truncated) => { + truncated_vertically = true; + truncated + } + }, + ); + if truncated_vertically { + break; + } suggestion_start += autosuggestion_line.len() + "\n".len(); } diff --git a/tests/checks/tmux-autosuggestion-multiline.fish b/tests/checks/tmux-autosuggestion-multiline.fish index d37bd5d13..9bcfee132 100644 --- a/tests/checks/tmux-autosuggestion-multiline.fish +++ b/tests/checks/tmux-autosuggestion-multiline.fish @@ -49,22 +49,21 @@ isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^ echo 000000000000000000000000000000000000000000000000000000000000000 # CHECK: ^0000000000000000000000000000000000000… -# Currently, we take either all or nothing from soft-wrapped suggestion-lines. # The ellipsis means that we'll get more lines. isolated-tmux resize-window -y 3 tmux-sleep isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^prompt> if true -# CHECK: ^ echo 00000000000000000000000000000000000000000000000000… -# CHECK: ^ +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000 +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000000000000000… # Test that truncation also works after the resize. isolated-tmux send-keys C-u if tmux-sleep isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^prompt> if true -# CHECK: ^ echo 00000000000000000000000000000000000000000000000000… -# CHECK: ^ +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000 +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000000000000000… # Test that we truncate such that the prompt is never pushed up. isolated-tmux resize-window -y 5 \; send-keys C-u Enter if @@ -83,8 +82,8 @@ isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^prompt> # CHECK: ^prompt> # CHECK: ^prompt> if true -# CHECK: ^ echo 00000000000000000000000000000000000000000000000000… -# CHECK: ^ +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000 +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000000000000000… # Now try with a multiline prompt. isolated-tmux send-keys C-u 'function fish_prompt; printf "prompt-line%d/2> \n" 1 2; end' Enter C-l Enter if @@ -103,8 +102,8 @@ isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^prompt-line2/2> # CHECK: ^prompt-line1/2> # CHECK: ^prompt-line2/2> if true -# CHECK: ^ echo 00000000000000000000000000000000000000000000000000… -# CHECK: ^ +# CHECK: ^ echo 00000000000000000000000000000000000000000000000000 +# CHECK: ^ echo 000000000000000000000000000000000000000000000000000000… isolated-tmux send-keys C-u \; resize-window -y 7 \; send-keys if tmux-sleep @@ -132,7 +131,7 @@ isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^prompt-line1 # CHECK: ^> begin # CHECK: ^ : 000000000000000000000000000000000000000000000000000000000000000000000000 -# CHECK: ^ +# CHECK: ^… # Autosuggestions on a soft-wrapped commandline don't push the prompt. isolated-tmux resize-window -x 6 -y 4 \; send-keys C-u \ @@ -159,4 +158,4 @@ isolated-tmux capture-pane -p | sed s/^/^/ # CHECK: ^> # CHECK: ^> # CHECK: ^> echo -# CHECK: ^ +# CHECK: ^ wrap…