From 0a23a78523969cf74448dae4058ac21671d9e7b4 Mon Sep 17 00:00:00 2001 From: Johannes Altmanninger Date: Fri, 2 Jan 2026 17:57:40 +0100 Subject: [PATCH] Soft-wrapped autosuggestion to hide right prompt for now Prior to f417cbc9818 (Show soft-wrapped portions in autosuggestions, 2025-12-11), we'd truncate autosuggestions before the right prompt. We no longer do that for autosuggestions that soft-wrap, which means we try to draw both right prompt and suggestion in the same space. Make suggestion paint over right prompt for now, since this seems to be a simple and robust solution. We can revisit this later. Fixes #12255 --- CHANGELOG.rst | 1 + src/screen.rs | 78 ++++++++++++++++------------- tests/checks/tmux-right-prompt.fish | 22 ++++++++ 3 files changed, 66 insertions(+), 35 deletions(-) create mode 100644 tests/checks/tmux-right-prompt.fish diff --git a/CHANGELOG.rst b/CHANGELOG.rst index 5a63bb245..7b8d89aa7 100644 --- a/CHANGELOG.rst +++ b/CHANGELOG.rst @@ -4,6 +4,7 @@ fish ?.?.? (released ???) This release fixes the following problems identified in fish 4.3.0: - Selecting a completion could insert only part of the token (:issue:`12249`). +- Glitch with soft-wrapped autosuggestions and :doc:`cmds/fish_right_prompt` (:issue:`12255`). - The sample prompts and themes are correctly installed (:issue:`12241`). - Last line of command output could be hidden when missing newline (:issue:`12246`). diff --git a/src/screen.rs b/src/screen.rs index 23a27a3fe..0ce822a3c 100644 --- a/src/screen.rs +++ b/src/screen.rs @@ -1980,7 +1980,7 @@ fn compute_layout( ); let left_prompt_width = left_prompt_layout.last_line_width; - let mut right_prompt_width = right_prompt_layout.last_line_width; + let right_prompt_width = right_prompt_layout.last_line_width; // Get the width of the first line, and if there is more than one line. let first_command_line_width: usize = line_at_cursor(commandline_before_suggestion, 0) @@ -2016,24 +2016,14 @@ fn compute_layout( ..Default::default() }; - // Hide the right prompt if it doesn't fit on the first line. - if left_prompt_width + first_command_line_width + right_prompt_width < screen_width { - result.right_prompt = right_prompt; - } else { - right_prompt_width = 0; - } - - // Now we should definitely fit. - assert!(left_prompt_width + right_prompt_width <= screen_width); - // Track each logical line from the autosuggestion so we can determine how much of it fits // on screen. We allow the lines to soft wrap naturally and we only truncate vertically if // we would exceed the screen height. - let cursor_y = left_prompt_layout.line_starts.len() - 1 - + commandline_before_suggestion - .chars() - .filter(|&c| c == '\n') - .count(); + let commandline_before_suggestion_lines = commandline_before_suggestion + .chars() + .filter(|&c| c == '\n') + .count(); + let cursor_y = left_prompt_layout.line_starts.len() - 1 + commandline_before_suggestion_lines; let mut suggestion_lines = vec![]; @@ -2062,7 +2052,8 @@ fn compute_layout( + commandline_before_suggestion .chars() .rposition(|c| c == '\n') - .map_or(right_prompt_width, indent_width) + .map(indent_width) + .unwrap_or_default() } else { indent_width(suggestion_start - "\n".len()) }; @@ -2122,6 +2113,24 @@ fn consumed_lines_or_truncated_suggestion( let mut autosuggestion = WString::new(); let mut displayed_len = 0; + { + // Hide the right prompt if it doesn't fit on the first line. + let first_command_line_suggestion_width = if commandline_before_suggestion_lines == 0 { + suggestion_lines.first().map_or(0, |line| { + line.chars().map(wcwidth_rendered_min_0).sum::() + }) + } else { + 0 + }; + if left_prompt_width + + first_command_line_width + + first_command_line_suggestion_width + + right_prompt_width + <= screen_width + { + result.right_prompt = right_prompt; + } + } for (line_idx, autosuggestion_line) in suggestion_lines.iter().enumerate() { if line_idx != 0 { autosuggestion.push('\n'); @@ -2421,20 +2430,19 @@ fn test_prompt_truncation() { fn test_compute_layout() { macro_rules! validate { ( - ( - $screen_width:expr, - $left_untrunc_prompt:literal, - $right_untrunc_prompt:literal, - $commandline_before_suggestion:literal, - $autosuggestion_str:literal, - $commandline_after_suggestion:literal - ) - -> ( - $left_prompt:literal, - $left_prompt_space:expr, - $right_prompt:literal, - $autosuggestion:literal $(,)? - ) + ( + $screen_width:expr, + $left_untrunc_prompt:literal, + $right_untrunc_prompt:literal, + $commandline_before_suggestion:literal, + $autosuggestion_str:literal, + $commandline_after_suggestion:literal + ) -> ( + $left_prompt:literal, + $left_prompt_space:expr, + $right_prompt:literal, + $autosuggestion:literal $(,)? + ) ) => {{ let full_commandline = L!($commandline_before_suggestion).to_owned() + L!($autosuggestion_str) @@ -2482,7 +2490,7 @@ macro_rules! validate { ) -> ( "left>", 5, - " ( "left>", 5, - "", + " ( "left>", 5, - "", + " ( "left>", 5, - "", + " {{ *}} RP +# CHECK: prompt 0> echo {{(a{65,})}} +# CHECK: {{(a{35,})}} + +isolated-tmux send-keys C-h C-l "echo line1" M-Enter "e" +tmux-sleep +isolated-tmux capture-pane -p +# CHECK: prompt 0> echo line1 {{ *}} RP +# CHECK: echo {{(a{65,})}} +# CHECK: {{(a{35,})}}