input: Refactor InputEvent::Change to not include the text. (#1246)

Change this to avoid Rope `to_string` performance cost. Ref #1220 

The listeners of `InputEvent::Change` may not be going to use entire of
text.

## Break Change

- The `InputEvent::Change(SharedString)` removed value.

```diff
- pub enum InputEvent {
-    Change(SharedString),
+ pub enum InputEvent {
+    Change,
```
This commit is contained in:
Jason Lee 2025-09-15 20:50:30 +08:00 committed by GitHub
parent f1b6d7c5ed
commit aab1321b70
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
10 changed files with 45 additions and 37 deletions

View file

@ -134,13 +134,16 @@ impl InputStory {
fn on_input_event(
&mut self,
_: &Entity<InputState>,
state: &Entity<InputState>,
event: &InputEvent,
_window: &mut Window,
_cx: &mut Context<Self>,
) {
match event {
InputEvent::Change(text) => println!("Change: {}", text),
InputEvent::Change => {
let text = state.read(_cx).value();
println!("Change: {}", text)
}
InputEvent::PressEnter { secondary } => println!("PressEnter secondary: {}", secondary),
InputEvent::Focus => println!("Focus"),
InputEvent::Blur => println!("Blur"),

View file

@ -47,9 +47,9 @@ impl LabelStory {
let _subscriptions =
vec![
cx.subscribe(&highlights_input, |this, _, e: &InputEvent, cx| {
if let InputEvent::Change(v) = e {
this.highlights_text = v.clone();
cx.subscribe(&highlights_input, |this, state, e: &InputEvent, cx| {
if let InputEvent::Change = e {
this.highlights_text = state.read(cx).value();
cx.notify();
}
}),

View file

@ -22,7 +22,7 @@ impl Gallery {
pub fn new(init_story: Option<&str>, window: &mut Window, cx: &mut Context<Self>) -> Self {
let search_input = cx.new(|cx| InputState::new(window, cx).placeholder("Search..."));
let _subscriptions = vec![cx.subscribe(&search_input, |this, _, e, cx| match e {
InputEvent::Change(_) => {
InputEvent::Change => {
this.active_group_index = Some(0);
this.active_index = Some(0);
cx.notify()

View file

@ -132,22 +132,23 @@ impl NumberInputStory {
fn on_input_event(
&mut self,
this: &Entity<InputState>,
state: &Entity<InputState>,
event: &InputEvent,
_: &mut Window,
_: &mut Context<Self>,
cx: &mut Context<Self>,
) {
match event {
InputEvent::Change(text) => {
if this == &self.number_input1 {
InputEvent::Change => {
let text = state.read(cx).value();
if state == &self.number_input1 {
if let Ok(value) = text.parse::<i64>() {
self.number_input1_value = value;
}
} else if this == &self.number_input2 {
} else if state == &self.number_input2 {
if let Ok(value) = text.parse::<u64>() {
self.number_input2_value = value;
}
} else if this == &self.number_input3 {
} else if state == &self.number_input3 {
if let Ok(value) = text.parse::<f64>() {
self.number_input3_value = value;
}

View file

@ -59,16 +59,16 @@ impl OtpInputStory {
fn new(window: &mut Window, cx: &mut Context<Self>) -> Self {
let otp_state = cx.new(|cx| OtpState::new(6, window, cx).masked(true));
let _subscriptions =
vec![
cx.subscribe(&otp_state, |this, _, ev: &InputEvent, cx| match ev {
InputEvent::Change(text) => {
this.otp_value = Some(text.clone());
cx.notify();
}
_ => {}
}),
];
let _subscriptions = vec![
cx.subscribe(&otp_state, |this, state, ev: &InputEvent, cx| match ev {
InputEvent::Change => {
let text = state.read(cx).value();
this.otp_value = Some(text.clone());
cx.notify();
}
_ => {}
}),
];
Self {
otp_masked: true,

View file

@ -74,9 +74,10 @@ impl ColorPickerState {
let _subscriptions = vec![cx.subscribe_in(
&state,
window,
|this, _, ev: &InputEvent, window, cx| match ev {
InputEvent::Change(value) => {
if let Ok(color) = Hsla::parse_hex(value) {
|this, state, ev: &InputEvent, window, cx| match ev {
InputEvent::Change => {
let value = state.read(cx).value();
if let Ok(color) = Hsla::parse_hex(value.as_str()) {
this.value = Some(color);
this.hovered_color = Some(color);
}

View file

@ -133,7 +133,7 @@ impl OtpState {
self.value = SharedString::from(chars.iter().collect::<String>());
if self.value.chars().count() == self.length {
cx.emit(InputEvent::Change(self.value.clone()));
cx.emit(InputEvent::Change);
}
cx.notify()
}

View file

@ -95,7 +95,7 @@ actions!(
#[derive(Clone)]
pub enum InputEvent {
Change(SharedString),
Change,
PressEnter { secondary: bool },
Focus,
Blur,
@ -2236,7 +2236,7 @@ impl EntityInputHandler for InputState {
self.update_scroll_offset(None, cx);
self.mode.update_auto_grow(&self.text_wrapper);
self.handle_completion_trigger(&range, &new_text, window, cx);
cx.emit(InputEvent::Change(self.unmask_value()));
cx.emit(InputEvent::Change);
cx.notify();
}
@ -2289,7 +2289,7 @@ impl EntityInputHandler for InputState {
.into();
}
self.mode.update_auto_grow(&self.text_wrapper);
cx.emit(InputEvent::Change(self.unmask_value()));
cx.emit(InputEvent::Change);
cx.notify();
}

View file

@ -115,9 +115,10 @@ impl DivInspector {
cx.subscribe_in(
&json_input_state,
window,
|this: &mut DivInspector, _, event: &InputEvent, window, cx| match event {
InputEvent::Change(new_style) => {
this.edit_json(new_style, window, cx);
|this: &mut DivInspector, state, event: &InputEvent, window, cx| match event {
InputEvent::Change => {
let new_style = state.read(cx).value();
this.edit_json(new_style.as_str(), window, cx);
}
_ => {}
},
@ -125,9 +126,10 @@ impl DivInspector {
cx.subscribe_in(
&rust_input_state,
window,
|this: &mut DivInspector, _, event: &InputEvent, window, cx| match event {
InputEvent::Change(new_style) => {
this.edit_rust(new_style, window, cx);
|this: &mut DivInspector, state, event: &InputEvent, window, cx| match event {
InputEvent::Change => {
let new_style = state.read(cx).value();
this.edit_rust(new_style.as_str(), window, cx);
}
_ => {}
},

View file

@ -238,13 +238,14 @@ where
fn on_query_input_event(
&mut self,
_: &Entity<InputState>,
state: &Entity<InputState>,
event: &InputEvent,
window: &mut Window,
cx: &mut Context<Self>,
) {
match event {
InputEvent::Change(text) => {
InputEvent::Change => {
let text = state.read(cx).value();
let text = text.trim().to_string();
if Some(&text) == self.last_query.as_ref() {
return;