From 88325ea14b0786a97d53eddb2797759d039d77a2 Mon Sep 17 00:00:00 2001 From: Jason Lee Date: Mon, 17 Mar 2025 22:40:09 +0800 Subject: [PATCH] input: Add `insert` and `replace` method to Input. (#721) Close #719 https://github.com/user-attachments/assets/aed24aef-c69f-4512-81bb-bb7e4a6de14e --- crates/story/src/input_story.rs | 55 ++++++++++++++++++++++++++++++--- crates/ui/src/input/input.rs | 29 +++++++++++++++++ 2 files changed, 80 insertions(+), 4 deletions(-) diff --git a/crates/story/src/input_story.rs b/crates/story/src/input_story.rs index 7f7cbc33..902bbdb3 100644 --- a/crates/story/src/input_story.rs +++ b/crates/story/src/input_story.rs @@ -1,7 +1,7 @@ use gpui::{ - actions, div, prelude::FluentBuilder as _, px, App, AppContext as _, Context, Entity, - FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, ParentElement as _, - Render, SharedString, Styled, Window, + actions, div, prelude::FluentBuilder as _, px, App, AppContext as _, ClickEvent, Context, + Entity, FocusHandle, Focusable, InteractiveElement, IntoElement, KeyBinding, + ParentElement as _, Render, SharedString, Styled, Window, }; use regex::Regex; @@ -335,6 +335,28 @@ impl InputStory { input.set_masked(self.otp_masked, window, cx) }); } + + fn on_insert_text_to_textarea( + &mut self, + _: &ClickEvent, + window: &mut Window, + cx: &mut Context, + ) { + self.textarea.update(cx, |input, cx| { + input.insert("Hello 你好", window, cx); + }); + } + + fn on_replace_text_to_textarea( + &mut self, + _: &ClickEvent, + window: &mut Window, + cx: &mut Context, + ) { + self.textarea.update(cx, |input, cx| { + input.replace("Hello 你好", window, cx); + }); + } } impl FocusableCycle for InputStory { @@ -388,7 +410,32 @@ impl Render for InputStory { ), ) .child( - section("Textarea", cx).child(div().flex_1().child(self.textarea.clone())), + section("Textarea", cx).child( + v_flex() + .gap_2() + .w_full() + .child(self.textarea.clone()) + .child( + h_flex() + .gap_2() + .child( + Button::new("btn-insert-text") + .xsmall() + .label("Insert Text") + .on_click( + cx.listener(Self::on_insert_text_to_textarea), + ), + ) + .child( + Button::new("btn-replace-text") + .xsmall() + .label("Replace Text") + .on_click( + cx.listener(Self::on_replace_text_to_textarea), + ), + ), + ), + ), ) .child( section("Input State", cx) diff --git a/crates/ui/src/input/input.rs b/crates/ui/src/input/input.rs index 255be4c7..7e3a5e80 100644 --- a/crates/ui/src/input/input.rs +++ b/crates/ui/src/input/input.rs @@ -474,6 +474,35 @@ impl TextInput { cx.notify(); } + /// Insert text at the current cursor position. + /// + /// And the cursor will be moved to the end of inserted text. + pub fn insert( + &mut self, + text: impl Into, + window: &mut Window, + cx: &mut Context, + ) { + let text: SharedString = text.into(); + let range = self.range_to_utf16(&(self.cursor_offset()..self.cursor_offset())); + self.replace_text_in_range(Some(range), &text, window, cx); + self.selected_range = self.selected_range.end..self.selected_range.end; + } + + /// Replace text at the current cursor position. + /// + /// And the cursor will be moved to the end of replaced text. + pub fn replace( + &mut self, + text: impl Into, + window: &mut Window, + cx: &mut Context, + ) { + let text: SharedString = text.into(); + self.replace_text_in_range(None, &text, window, cx); + self.selected_range = self.selected_range.end..self.selected_range.end; + } + fn replace_text( &mut self, text: impl Into,