diff --git a/crates/editor/src/element.rs b/crates/editor/src/element.rs index d789bbce3b5e6d36e6bf1c7f21961484c565b50f..78f854ea306f674ea7f1adf111233c63d67fde7a 100644 --- a/crates/editor/src/element.rs +++ b/crates/editor/src/element.rs @@ -3808,39 +3808,38 @@ impl EditorElement { ); let styled_text = highlighted_edits.to_styled_text(&style.text); + let line_count = highlighted_edits.text.lines().count(); - const ACCEPT_INDICATOR_HEIGHT: Pixels = px(24.); + const BORDER_WIDTH: Pixels = px(1.); - let mut element = v_flex() - .items_end() + let mut element = h_flex() + .items_start() + .child( + div() + .bg(cx.theme().colors().editor_background) + .border(BORDER_WIDTH) + .shadow_sm() + .border_color(cx.theme().colors().border) + .rounded_l_lg() + .when(line_count > 1, |el| el.rounded_br_lg()) + .pr_1() + .child(styled_text), + ) .child( h_flex() - .h(ACCEPT_INDICATOR_HEIGHT) - .mb(px(-1.)) + .h(line_height + BORDER_WIDTH * px(2.)) .px_1p5() .gap_1() .shadow_sm() .bg(Editor::edit_prediction_line_popover_bg_color(cx)) - .border_1() - .border_b_0() + .border(BORDER_WIDTH) + .border_l_0() .border_color(cx.theme().colors().border) - .rounded_t_lg() + .rounded_r_lg() .children(editor.render_edit_prediction_accept_keybind(window, cx)), ) - .child( - div() - .bg(cx.theme().colors().editor_background) - .border_1() - .shadow_sm() - .border_color(cx.theme().colors().border) - .rounded_lg() - .rounded_tr(Pixels::ZERO) - .child(styled_text), - ) .into_any(); - let line_count = highlighted_edits.text.lines().count(); - let longest_row = editor_snapshot.longest_row_in_range(edit_start.row()..edit_end.row() + 1); let longest_line_width = if visible_row_range.contains(&longest_row) { @@ -3871,55 +3870,50 @@ impl EditorElement { // Fully visible if it can be displayed within the window (allow overlapping other // panes). However, this is only allowed if the popover starts within text_bounds. - let is_fully_visible = x_after_longest < text_bounds.right() + let can_position_to_the_right = x_after_longest < text_bounds.right() && x_after_longest + element_bounds.width < viewport_bounds.right(); - let mut origin = if is_fully_visible { + let mut origin = if can_position_to_the_right { point( x_after_longest, text_bounds.origin.y + edit_start.row().as_f32() * line_height - scroll_pixel_position.y, ) } else { - // Avoid overlapping both the edited rows and the user's cursor. - let target_above = DisplayRow( - edit_start - .row() - .0 - .min( - newest_selection_head - .map_or(u32::MAX, |cursor_row| cursor_row.row().0), - ) - .saturating_sub(line_count as u32), - ); - let mut row_target; - if visible_row_range.contains(&DisplayRow(target_above.0.saturating_sub(1))) { - row_target = target_above; - } else { - row_target = DisplayRow( - edit_end.row().0.max( - newest_selection_head.map_or(0, |cursor_row| cursor_row.row().0), - ) + 1, - ); - if !visible_row_range.contains(&row_target) { - // Not visible, so fallback on displaying immediately below the cursor. - if let Some(cursor) = newest_selection_head { - row_target = DisplayRow(cursor.row().0 + 1); - } else { - // Not visible and no cursor visible, so fallback on displaying at the top of the editor. - row_target = DisplayRow(0); - } - } - }; + let cursor_row = newest_selection_head.map(|head| head.row()); + let above_edit = edit_start + .row() + .0 + .checked_sub(line_count as u32) + .map(DisplayRow); + let below_edit = Some(edit_end.row() + 1); + let above_cursor = cursor_row + .and_then(|row| row.0.checked_sub(line_count as u32).map(DisplayRow)); + let below_cursor = cursor_row.map(|cursor_row| cursor_row + 1); + + // Place the edit popover adjacent to the edit if there is a location + // available that is onscreen and does not obscure the cursor. Otherwise, + // place it adjacent to the cursor. + let row_target = [above_edit, below_edit, above_cursor, below_cursor] + .into_iter() + .flatten() + .find(|&start_row| { + let end_row = start_row + line_count as u32; + visible_row_range.contains(&start_row) + && visible_row_range.contains(&end_row) + && cursor_row.map_or(true, |cursor_row| { + !((start_row..end_row).contains(&cursor_row)) + }) + })?; - text_bounds.origin + content_origin + point( -scroll_pixel_position.x, row_target.as_f32() * line_height - scroll_pixel_position.y, ) }; - origin.y -= ACCEPT_INDICATOR_HEIGHT; + origin.x -= BORDER_WIDTH; window.defer_draw(element, origin, 1);