add read-only mode for input

This commit is contained in:
2026-10-29 14:42:11 +07:00
parent d95baae418
commit e2331f2ba5
3 changed files with 156 additions and 7 deletions
+109 -2
View File
@@ -1,6 +1,6 @@
use gpui::{
Entity, Modifiers, ParentElement as _, Render, Styled as _, TestAppContext, VisualTestContext,
Window, div, point, px,
Entity, Modifiers, MouseButton, MouseDownEvent, MouseUpEvent, ParentElement as _, Render,
Styled as _, TestAppContext, VisualTestContext, Window, div, point, px,
};
use gpui_native_core::input::{Input, InputState, InputStateEvent};
use gpui_native_theme::Theme;
@@ -211,6 +211,113 @@ fn set_value_clears_the_history() {
assert_eq!(value(&cx, &state), "preset");
}
#[test]
fn read_only_refuses_edits_but_keeps_selection_and_copy() {
let (cx, state, mut visual) = input_window("hello", false);
focus(&mut visual, &state);
visual.update(|_, cx| {
state.update(cx, |state, cx| state.set_read_only(true, cx));
});
// Typing and backspace are refused.
visual.simulate_keystrokes("x backspace");
assert_eq!(value(&cx, &state), "hello");
// Paste is refused.
cx.update(|cx| {
cx.write_to_clipboard(gpui::ClipboardItem::new_string("Z".to_string()));
});
visual.simulate_keystrokes("cmd-v");
assert_eq!(value(&cx, &state), "hello");
// Selection and copy still work.
visual.simulate_keystrokes("shift-left shift-left");
visual.simulate_keystrokes("cmd-c");
let clipboard = cx.update(|cx| {
cx.read_from_clipboard()
.and_then(|item| item.text())
.unwrap_or_default()
});
assert_eq!(clipboard, "lo");
// Cut neither changes the field nor touches the clipboard.
visual.simulate_keystrokes("cmd-x");
assert_eq!(value(&cx, &state), "hello");
let clipboard = cx.update(|cx| {
cx.read_from_clipboard()
.and_then(|item| item.text())
.unwrap_or_default()
});
assert_eq!(clipboard, "lo");
}
#[test]
fn read_only_blocks_undo_redo_but_set_value_still_writes() {
let (cx, state, mut visual) = input_window("", false);
focus(&mut visual, &state);
visual.simulate_keystrokes("a");
visual.simulate_keystrokes("cmd-z");
assert_eq!(value(&cx, &state), "");
visual.update(|_, cx| {
state.update(cx, |state, cx| state.set_read_only(true, cx));
});
visual.simulate_keystrokes("cmd-shift-z");
assert_eq!(value(&cx, &state), "");
visual.update(|window, cx| {
state.update(cx, |state, cx| state.set_value("preset", window, cx));
});
assert_eq!(value(&cx, &state), "preset");
}
#[test]
fn escape_blurs_the_field() {
let (mut cx, state, mut visual) = input_window("", false);
let (sink, _subscription) = record_events(&mut cx, &state);
focus(&mut visual, &state);
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
visual.run_until_parked();
assert_eq!(count(&sink, &InputStateEvent::Focused), 1);
visual.simulate_keystrokes("escape");
let focused = visual.update(|window, cx| state.read(cx).focus_handle().is_focused(window));
assert!(!focused);
visual.update(|window, cx| {
window.draw(cx).clear(cx);
});
visual.run_until_parked();
assert_eq!(count(&sink, &InputStateEvent::Blurred), 1);
}
#[test]
fn triple_click_selects_all_and_typing_replaces_it() {
let (cx, state, mut visual) = input_window("hello world", false);
focus(&mut visual, &state);
let at = point(px(30.), px(14.));
visual.simulate_event(MouseDownEvent {
position: at,
modifiers: Modifiers::default(),
button: MouseButton::Left,
click_count: 3,
first_mouse: false,
});
visual.simulate_event(MouseUpEvent {
position: at,
modifiers: Modifiers::default(),
button: MouseButton::Left,
click_count: 3,
});
// The selection spans the whole value: one keystroke replaces all of it.
visual.simulate_keystrokes("x");
assert_eq!(value(&cx, &state), "x");
}
#[test]
fn shift_arrow_selects_and_backspace_removes_the_selection() {
let (cx, state, mut visual) = input_window("ab", false);