input: Fix may flash scroll when move cursor in auto grow mode. (#1419)

This commit is contained in:
Jason Lee 2025-10-23 17:43:33 +08:00 committed by GitHub
parent b80fca28c1
commit 6dd857a7f7
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
3 changed files with 45 additions and 19 deletions

View file

@ -1,14 +1,15 @@
use gpui::{
px, App, AppContext as _, ClickEvent, Context, Entity, Focusable, InteractiveElement,
IntoElement, ParentElement as _, Render, Styled, Window,
App, AppContext as _, ClickEvent, Context, Entity, Focusable, InteractiveElement, IntoElement,
ParentElement as _, Render, Styled, Window, px,
};
use crate::section;
use gpui_component::{
Sizable,
button::Button,
h_flex,
input::{InputState, TextInput},
v_flex, Sizable,
v_flex,
};
pub fn init(_: &mut App) {}
@ -17,6 +18,7 @@ pub struct TextareaStory {
textarea: Entity<InputState>,
textarea_auto_grow: Entity<InputState>,
textarea_no_wrap: Entity<InputState>,
textarea_auto_grow_no_wrap: Entity<InputState>,
}
impl super::Story for TextareaStory {
@ -73,13 +75,6 @@ impl TextareaStory {
)
});
let textarea_auto_grow = cx.new(|cx| {
InputState::new(window, cx)
.auto_grow(1, 5)
.placeholder("Enter text here...")
.default_value("Hello 世界this is GPUI component.")
});
let textarea_no_wrap = cx.new(|cx| {
InputState::new(window, cx)
.multi_line()
@ -88,10 +83,26 @@ impl TextareaStory {
.default_value("This is a very long line of text to test if the horizontal scrolling function is working properly, and it should not wrap automatically but display a horizontal scrollbar.\nThe second line is also very long text, used to test the horizontal scrolling effect under multiple lines, and you can input more content to test.\nThe third line: Here you can input other long text content that requires horizontal scrolling.\n")
});
let textarea_auto_grow = cx.new(|cx| {
InputState::new(window, cx)
.auto_grow(1, 5)
.placeholder("Enter text here...")
.default_value("Hello 世界, this is a very long line of text to test if the horizontal scrolling function is working properly, and it should not wrap automatically but display a horizontal scrollbar.\nThe second line is also very long text, used to test the horizontal scrolling effect under multiple lines, and you can input more content to test.\nThe third line: Here you can input other long text content that requires horizontal scrolling.\n")
});
let textarea_auto_grow_no_wrap = cx.new(|cx| {
InputState::new(window, cx)
.auto_grow(1, 5)
.soft_wrap(false)
.placeholder("Enter text here...")
.default_value("Hello 世界this is GPUI component.")
});
Self {
textarea,
textarea_auto_grow,
textarea_no_wrap,
textarea_auto_grow_no_wrap,
}
}
@ -166,11 +177,20 @@ impl Render for TextareaStory {
),
),
)
.child(section("Textarea Auto Grow").child(TextInput::new(&self.textarea_auto_grow)))
.child(
section("No Wrap")
.max_w_md()
.child(TextInput::new(&self.textarea_no_wrap).h(px(200.))),
)
.child(
section("Auto Grow")
.max_w_md()
.child(TextInput::new(&self.textarea_auto_grow)),
)
.child(
section("Auto Grow with No Wrap")
.max_w_md()
.child(TextInput::new(&self.textarea_auto_grow_no_wrap)),
)
}
}

View file

@ -974,14 +974,14 @@ impl Element for TextElement {
last_layout.lines = Rc::new(lines);
let total_wrapped_lines = state.text_wrapper.len();
let empty_bottom_height = if state.mode.is_auto_grow() || state.mode.is_single_line() {
px(0.)
} else {
let empty_bottom_height = if state.mode.is_code_editor() {
bounds
.size
.height
.half()
.max(BOTTOM_MARGIN_ROWS * line_height)
} else {
px(0.)
};
let scroll_size = size(
@ -1283,9 +1283,7 @@ impl Element for TextElement {
state.set_input_bounds(input_bounds, cx);
state.last_selected_range = Some(selected_range);
state.scroll_size = prepaint.scroll_size;
state
.scroll_handle
.set_offset(prepaint.cursor_scroll_offset);
state.update_scroll_offset(Some(prepaint.cursor_scroll_offset), cx);
state.deferred_scroll_offset = None;
cx.notify();

View file

@ -1456,7 +1456,11 @@ impl InputState {
self.diagnostic_popover = None;
}
fn update_scroll_offset(&mut self, offset: Option<Point<Pixels>>, cx: &mut Context<Self>) {
pub(super) fn update_scroll_offset(
&mut self,
offset: Option<Point<Pixels>>,
cx: &mut Context<Self>,
) {
let mut offset = offset.unwrap_or(self.scroll_handle.offset());
let safe_y_range =
@ -1516,7 +1520,11 @@ impl InputState {
// Check if row_offset_y is out of the viewport
// If row offset is not in the viewport, scroll to make it visible
let edge_height = 3 * line_height;
let edge_height = if self.mode.is_code_editor() {
3 * line_height
} else {
line_height
};
if row_offset_y - edge_height < -scroll_offset.y {
// Scroll up
scroll_offset.y = -row_offset_y + edge_height;