rename editable text module structs for consistency

This commit is contained in:
temportalflux
2026-07-11 09:31:07 -04:00
parent e84af920b9
commit c1d3deb170
8 changed files with 80 additions and 84 deletions
+1 -1
View File
@@ -17,7 +17,6 @@ pub use text_area_state::*;
/* TODO list
- default-value
- naming clean up (EditableText)
- remove gpuikit based input
- cursor blinking
- color styling configs
@@ -25,4 +24,5 @@ pub use text_area_state::*;
- text sanitation
- test IME (char palette only available on macos)
- unit tests
- disabled input/area
*/
@@ -238,7 +238,7 @@ pub trait EditableTextActionHandler<'app>: Sized {
}
}
pub(super) trait EditableInputActionElement: StateBackedEditableText {
pub(super) trait EditableTextActionElement: StateBackedEditableText {
fn state_entity_rc(&self) -> &Rc<RefCell<WeakEntity<Self::State>>>;
fn register_action<ActionType>(
@@ -1,6 +1,6 @@
use crate::editable_text::{
InitStorage, StateBackedEditableText, TextInputState,
actions::{DEFAULT_INPUT_CONTEXT, EditableInputActionElement},
EditableTextInputState, InitStorage, StateBackedEditableText,
actions::{DEFAULT_INPUT_CONTEXT, EditableTextActionElement},
shared_element::{self, EditableTextElement},
};
use gpui::{
@@ -31,7 +31,7 @@ pub struct TextInputElement {
// Populated on first render with an entity stored/attached to the view.
// This reference is shared with the action handlers, which are processed between renders
// and therefore cannot otherwise access state attached to the view.
state_entity: Rc<RefCell<WeakEntity<TextInputState>>>,
state_entity: Rc<RefCell<WeakEntity<EditableTextInputState>>>,
init_storage: InitStorage,
placeholder: Option<SharedString>,
}
@@ -54,6 +54,7 @@ impl InteractiveElement for TextInputElement {
}
}
// forced implementation since the API for the element doesnt use Stateful<Element>
impl StatefulInteractiveElement for TextInputElement {}
impl Styled for TextInputElement {
@@ -70,10 +71,10 @@ impl IntoElement for TextInputElement {
}
impl StateBackedEditableText for TextInputElement {
type State = TextInputState;
type State = EditableTextInputState;
}
impl EditableInputActionElement for TextInputElement {
impl EditableTextActionElement for TextInputElement {
fn state_entity_rc(&self) -> &Rc<RefCell<WeakEntity<Self::State>>> {
&self.state_entity
}
@@ -90,7 +91,7 @@ impl EditableTextElement for TextInputElement {
}
impl Element for TextInputElement {
type RequestLayoutState = shared_element::LayoutState<TextInputState>;
type RequestLayoutState = shared_element::LayoutState<EditableTextInputState>;
type PrepaintState = shared_element::PrepaintState;
fn id(&self) -> Option<ElementId> {
@@ -1,6 +1,7 @@
use super::notify::TextHistoryPushed;
use crate::editable_text::{
TextBoundary, TextInputStateBase, TextStateNotifier, UnicodeTextStorage, notify::TextChanged,
EditableTextStateBase, EditableTextStateNotifier, TextBoundary, UnicodeTextStorage,
notify::TextChanged,
};
use gpui::{
Bounds, Context, EntityInputHandler, EventEmitter, NavigationDirection, Pixels, Point,
@@ -8,34 +9,34 @@ use gpui::{
};
use std::ops::Range;
pub struct TextInputState {
internal: TextInputStateBase,
pub struct EditableTextInputState {
internal: EditableTextStateBase,
}
impl EventEmitter<TextChanged> for TextInputState {}
impl EventEmitter<TextHistoryPushed> for TextInputState {}
impl EventEmitter<TextChanged> for EditableTextInputState {}
impl EventEmitter<TextHistoryPushed> for EditableTextInputState {}
impl std::ops::Deref for TextInputState {
type Target = TextInputStateBase;
impl std::ops::Deref for EditableTextInputState {
type Target = EditableTextStateBase;
fn deref(&self) -> &Self::Target {
&self.internal
}
}
impl std::ops::DerefMut for TextInputState {
impl std::ops::DerefMut for EditableTextInputState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.internal
}
}
impl TextInputState {
impl EditableTextInputState {
pub fn new(storage: impl Into<Box<dyn UnicodeTextStorage>>, cx: &mut Context<Self>) -> Self {
let internal = TextInputStateBase::new(storage, cx);
let internal = EditableTextStateBase::new(storage, cx);
Self { internal }
}
}
impl TextStateNotifier for Context<'_, TextInputState> {
impl EditableTextStateNotifier for Context<'_, EditableTextInputState> {
fn notify_changed(&mut self) {
self.notify();
}
@@ -49,7 +50,7 @@ impl TextStateNotifier for Context<'_, TextInputState> {
}
}
impl EntityInputHandler for TextInputState {
impl EntityInputHandler for EditableTextInputState {
fn text_for_range(
&mut self,
range_utf16: Range<usize>,
@@ -92,7 +93,6 @@ impl EntityInputHandler for TextInputState {
let range_utf8 = self.internal.ime_resolve_range(range_utf16);
self.internal
.replace_text_in_range_bytes(range_utf8, text_to_insert, cx);
//self.mark_layout_dirty();
//cx.emit(CursorTrigger::PauseBlinkingForUserAction);
cx.emit_text_changed(TextChanged);
cx.notify_changed();
@@ -116,7 +116,6 @@ impl EntityInputHandler for TextInputState {
&new_selected_range_utf16,
text_to_insert.len(),
);
//self.mark_layout_dirty();
cx.emit_text_changed(TextChanged);
cx.notify_changed();
}
@@ -146,7 +145,7 @@ impl EntityInputHandler for TextInputState {
}
use super::actions::*;
impl<'app> EditableTextActionHandler<'app> for TextInputState {
impl<'app> EditableTextActionHandler<'app> for EditableTextInputState {
type Context = gpui::Context<'app, Self>;
fn escape(&mut self, _: &Escape, window: &mut Window, cx: &mut Self::Context) {
@@ -1,13 +1,12 @@
use crate::editable_text::{
TextInputLayoutData, TextLineSegment,
actions::{EditableInputActionElement, EditableTextActionHandler},
actions::{EditableTextActionElement, EditableTextActionHandler},
};
use gpui::{
Along, App, Axis, Bounds, ContentMask, Context, CursorStyle, DispatchPhase, Display,
ElementInputHandler, Entity, FocusHandle, Focusable, Hitbox, HitboxBehavior, Hsla,
InteractiveElement, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad,
Pixels, Point, ScrollWheelEvent, SharedString, Size, Style, TextAlign, TextLayout, Window,
WrappedLine, fill, point, px, size,
App, Bounds, Context, CursorStyle, DispatchPhase, Display, ElementInputHandler, Entity,
FocusHandle, Focusable, Hitbox, HitboxBehavior, Hsla, InteractiveElement, MouseButton,
MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, Pixels, Point, SharedString, Size,
Style, TextAlign, TextLayout, Window, WrappedLine, fill, point, px, size,
};
use smallvec::SmallVec;
use std::{ops::Range, sync::Arc};
@@ -49,7 +48,7 @@ pub struct PrepaintState {
pub caret_visible: bool,
}
pub trait EditableTextElement: InteractiveElement + EditableInputActionElement {
pub trait EditableTextElement: InteractiveElement + EditableTextActionElement {
fn init_state(&self, cx: &mut Context<Self::State>) -> Self::State;
fn placeholder(&self) -> &Option<SharedString>;
@@ -214,7 +213,6 @@ pub trait EditableTextElement: InteractiveElement + EditableInputActionElement {
size: Some(size),
last_seen_storage_version,
lines,
lines_represent_placeholder: show_placeholder,
};
// Update the state for use in prepaint, paint, and action handlers.
@@ -9,7 +9,7 @@ use gpui::{
};
use std::{ops::Range, sync::Arc};
pub trait TextStateNotifier {
pub trait EditableTextStateNotifier {
fn notify_changed(&mut self);
fn emit_text_changed(&mut self, event: TextChanged);
fn emit_history(&mut self, event: TextHistoryPushed);
@@ -17,13 +17,13 @@ pub trait TextStateNotifier {
pub trait StateBackedEditableText {
type State: 'static
+ std::ops::Deref<Target = TextInputStateBase>
+ std::ops::Deref<Target = EditableTextStateBase>
+ std::ops::DerefMut
+ EntityInputHandler
+ for<'app> EditableTextActionHandler<'app>;
}
pub struct TextInputStateBase {
pub struct EditableTextStateBase {
storage: Box<dyn UnicodeTextStorage>,
/// The utf-8 character range that is currently selected by the user.
@@ -60,7 +60,6 @@ pub(super) struct TextInputLayoutData {
/// The `ShapedLine` produced by the painter's `prepaint`.
/// Cached so IME `bounds_for_range` / `character_index_for_point` can evaluate without re-shaping.
pub lines: Vec<TextLineSegment>,
pub lines_represent_placeholder: bool,
}
pub(super) struct TextLineSegment {
/// The utf8 byte range in the content string that this line covers.
@@ -86,13 +85,13 @@ impl TextLineSegment {
}
}
impl Focusable for TextInputStateBase {
impl Focusable for EditableTextStateBase {
fn focus_handle(&self, _: &App) -> FocusHandle {
self.focus_handle.clone()
}
}
impl TextInputStateBase {
impl EditableTextStateBase {
pub fn new(storage: impl Into<Box<dyn UnicodeTextStorage>>, cx: &mut App) -> Self {
Self {
storage: storage.into(),
@@ -142,7 +141,7 @@ impl TextInputStateBase {
}
}
impl TextInputStateBase {
impl EditableTextStateBase {
/// Returns the utf-8 character position of the start of the line that contains the provided pixel-point.
pub fn index_for_pixel_point(&self, point: Point<Pixels>, line_height: Pixels) -> usize {
let storage_len_utf8 = self.storage.content_utf8().len();
@@ -178,7 +177,7 @@ impl TextInputStateBase {
}
}
impl TextInputStateBase {
impl EditableTextStateBase {
pub fn ime_text_for_range(
&self,
range_utf16: Range<usize>,
@@ -233,7 +232,7 @@ impl TextInputStateBase {
fn emit_change_for_undo(
&self,
cx: &mut impl TextStateNotifier,
cx: &mut impl EditableTextStateNotifier,
range: Range<usize>,
length: usize,
) {
@@ -249,7 +248,7 @@ impl TextInputStateBase {
&mut self,
range: Range<usize>,
mut text_to_insert: &str,
cx: &mut impl TextStateNotifier,
cx: &mut impl EditableTextStateNotifier,
) {
// TODO: Apply text sanitization
// single-line fields should prune \n and \r
@@ -355,8 +354,8 @@ impl TextInputStateBase {
}
}
impl TextInputStateBase {
pub fn move_to(&mut self, caret_pos: usize, cx: &mut impl TextStateNotifier) {
impl EditableTextStateBase {
pub fn move_to(&mut self, caret_pos: usize, cx: &mut impl EditableTextStateNotifier) {
//cx.emit(CursorTrigger::PauseBlinkingForUserAction);
let caret_pos = caret_pos.min(self.storage.content_utf8().len());
self.selected_range = caret_pos..caret_pos;
@@ -364,7 +363,7 @@ impl TextInputStateBase {
cx.notify_changed();
}
pub fn select_to(&mut self, caret_pos: usize, cx: &mut impl TextStateNotifier) {
pub fn select_to(&mut self, caret_pos: usize, cx: &mut impl EditableTextStateNotifier) {
//cx.emit(CursorTrigger::PauseBlinkingForUserAction);
let caret_pos = caret_pos.min(self.storage().content_utf8().len());
self.selected_range.start = caret_pos;
@@ -376,7 +375,7 @@ impl TextInputStateBase {
&mut self,
direction: NavigationDirection,
boundary: TextBoundary,
cx: &mut impl TextStateNotifier,
cx: &mut impl EditableTextStateNotifier,
) {
let range = self.selected_range();
let range = match range.is_empty() {
@@ -399,7 +398,7 @@ impl TextInputStateBase {
&mut self,
direction: NavigationDirection,
boundary: TextBoundary,
cx: &mut impl TextStateNotifier,
cx: &mut impl EditableTextStateNotifier,
) {
let caret_pos = match self.selected_range.is_empty() {
false => match direction {
@@ -489,7 +488,7 @@ impl TextInputStateBase {
(direction > 0).then(|| self.storage.content_utf8().len())
}
pub fn select_all(&mut self, cx: &mut impl TextStateNotifier) {
pub fn select_all(&mut self, cx: &mut impl EditableTextStateNotifier) {
self.selected_range = 0..self.storage.content_utf8().len();
cx.notify_changed();
}
@@ -498,7 +497,7 @@ impl TextInputStateBase {
&mut self,
direction: NavigationDirection,
boundary: TextBoundary,
cx: &mut impl TextStateNotifier,
cx: &mut impl EditableTextStateNotifier,
) {
let caret_pos = self
.storage
@@ -508,7 +507,7 @@ impl TextInputStateBase {
pub fn cut<T>(&mut self, cx: &mut T)
where
T: TextStateNotifier + std::ops::Deref<Target = App>,
T: EditableTextStateNotifier + std::ops::Deref<Target = App>,
{
if !self.selected_range.is_empty() {
// Cut selected text
@@ -559,7 +558,7 @@ impl TextInputStateBase {
pub fn paste<T>(&mut self, cx: &mut T)
where
T: TextStateNotifier + std::ops::Deref<Target = App>,
T: EditableTextStateNotifier + std::ops::Deref<Target = App>,
{
let Some(text) = cx.read_from_clipboard().and_then(|item| item.text()) else {
return;
@@ -578,7 +577,7 @@ impl TextInputStateBase {
window: &mut Window,
cx: &mut Context,
) where
Context: TextStateNotifier + std::ops::DerefMut<Target = App>,
Context: EditableTextStateNotifier + std::ops::DerefMut<Target = App>,
{
window.focus(&self.focus_handle, cx);
self.is_selecting = true;
@@ -629,7 +628,7 @@ impl TextInputStateBase {
self.is_selecting = false;
}
pub fn on_mouse_move(&mut self, character_pos: usize, cx: &mut impl TextStateNotifier) {
pub fn on_mouse_move(&mut self, character_pos: usize, cx: &mut impl EditableTextStateNotifier) {
if self.is_selecting && self.click_count == 1 {
self.select_to(character_pos, cx);
}
@@ -1,6 +1,6 @@
use crate::editable_text::{
InitStorage, StateBackedEditableText, TextAreaState,
actions::{DEFAULT_INPUT_CONTEXT, EditableInputActionElement},
EditableTextAreaState, InitStorage, StateBackedEditableText,
actions::{DEFAULT_INPUT_CONTEXT, EditableTextActionElement},
shared_element::{self, EditableTextElement},
};
use gpui::{
@@ -9,8 +9,8 @@ use gpui::{
};
use std::{cell::RefCell, rc::Rc};
pub fn text_area(id: impl Into<ElementId>) -> TextAreaElement {
let mut this = TextAreaElement {
pub fn text_area(id: impl Into<ElementId>) -> EditableTextAreaElement {
let mut this = EditableTextAreaElement {
interactivity: Interactivity::new(),
state_entity: Rc::new(RefCell::new(WeakEntity::new_invalid())),
init_storage: InitStorage::default(),
@@ -25,17 +25,17 @@ pub fn text_area(id: impl Into<ElementId>) -> TextAreaElement {
}
// TODO: Disabled flag/state?
pub struct TextAreaElement {
pub struct EditableTextAreaElement {
interactivity: Interactivity,
// Populated on first render with an entity stored/attached to the view.
// This reference is shared with the action handlers, which are processed between renders
// and therefore cannot otherwise access state attached to the view.
state_entity: Rc<RefCell<WeakEntity<TextAreaState>>>,
state_entity: Rc<RefCell<WeakEntity<EditableTextAreaState>>>,
init_storage: InitStorage,
placeholder: Option<SharedString>,
}
impl TextAreaElement {
impl EditableTextAreaElement {
pub fn placeholder(mut self, text: impl Into<SharedString>) -> Self {
self.placeholder = Some(text.into());
self
@@ -47,38 +47,39 @@ impl TextAreaElement {
}
}
impl InteractiveElement for TextAreaElement {
impl InteractiveElement for EditableTextAreaElement {
fn interactivity(&mut self) -> &mut Interactivity {
&mut self.interactivity
}
}
impl StatefulInteractiveElement for TextAreaElement {}
// forced implementation since the API for the element doesnt use Stateful<Element>
impl StatefulInteractiveElement for EditableTextAreaElement {}
impl Styled for TextAreaElement {
impl Styled for EditableTextAreaElement {
fn style(&mut self) -> &mut StyleRefinement {
&mut self.interactivity.base_style
}
}
impl IntoElement for TextAreaElement {
impl IntoElement for EditableTextAreaElement {
type Element = Self;
fn into_element(self) -> Self::Element {
self
}
}
impl StateBackedEditableText for TextAreaElement {
type State = TextAreaState;
impl StateBackedEditableText for EditableTextAreaElement {
type State = EditableTextAreaState;
}
impl EditableInputActionElement for TextAreaElement {
impl EditableTextActionElement for EditableTextAreaElement {
fn state_entity_rc(&self) -> &Rc<RefCell<WeakEntity<Self::State>>> {
&self.state_entity
}
}
impl EditableTextElement for TextAreaElement {
impl EditableTextElement for EditableTextAreaElement {
fn init_state(&self, cx: &mut gpui::prelude::Context<Self::State>) -> Self::State {
Self::State::new(self.init_storage.exec(cx), cx)
}
@@ -88,8 +89,8 @@ impl EditableTextElement for TextAreaElement {
}
}
impl Element for TextAreaElement {
type RequestLayoutState = shared_element::LayoutState<TextAreaState>;
impl Element for EditableTextAreaElement {
type RequestLayoutState = shared_element::LayoutState<EditableTextAreaState>;
type PrepaintState = shared_element::PrepaintState;
fn id(&self) -> Option<ElementId> {
@@ -1,5 +1,5 @@
use crate::editable_text::{
TextBoundary, TextInputStateBase, TextStateNotifier, UnicodeTextStorage,
EditableTextStateBase, EditableTextStateNotifier, TextBoundary, UnicodeTextStorage,
notify::{TextChanged, TextHistoryPushed},
};
use gpui::{
@@ -8,34 +8,34 @@ use gpui::{
};
use std::ops::Range;
pub struct TextAreaState {
internal: TextInputStateBase,
pub struct EditableTextAreaState {
internal: EditableTextStateBase,
}
impl EventEmitter<TextChanged> for TextAreaState {}
impl EventEmitter<TextHistoryPushed> for TextAreaState {}
impl EventEmitter<TextChanged> for EditableTextAreaState {}
impl EventEmitter<TextHistoryPushed> for EditableTextAreaState {}
impl std::ops::Deref for TextAreaState {
type Target = TextInputStateBase;
impl std::ops::Deref for EditableTextAreaState {
type Target = EditableTextStateBase;
fn deref(&self) -> &Self::Target {
&self.internal
}
}
impl std::ops::DerefMut for TextAreaState {
impl std::ops::DerefMut for EditableTextAreaState {
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.internal
}
}
impl TextAreaState {
impl EditableTextAreaState {
pub fn new(storage: impl Into<Box<dyn UnicodeTextStorage>>, cx: &mut Context<Self>) -> Self {
let internal = TextInputStateBase::new(storage, cx);
let internal = EditableTextStateBase::new(storage, cx);
Self { internal }
}
}
impl TextStateNotifier for Context<'_, TextAreaState> {
impl EditableTextStateNotifier for Context<'_, EditableTextAreaState> {
fn notify_changed(&mut self) {
self.notify();
}
@@ -49,7 +49,7 @@ impl TextStateNotifier for Context<'_, TextAreaState> {
}
}
impl EntityInputHandler for TextAreaState {
impl EntityInputHandler for EditableTextAreaState {
fn text_for_range(
&mut self,
range_utf16: Range<usize>,
@@ -92,7 +92,6 @@ impl EntityInputHandler for TextAreaState {
let range_utf8 = self.internal.ime_resolve_range(range_utf16);
self.internal
.replace_text_in_range_bytes(range_utf8, text_to_insert, cx);
//self.mark_layout_dirty();
//cx.emit(CursorTrigger::PauseBlinkingForUserAction);
cx.emit_text_changed(TextChanged);
cx.notify_changed();
@@ -116,7 +115,6 @@ impl EntityInputHandler for TextAreaState {
&new_selected_range_utf16,
text_to_insert.len(),
);
//self.mark_layout_dirty();
cx.emit_text_changed(TextChanged);
cx.notify_changed();
}
@@ -146,7 +144,7 @@ impl EntityInputHandler for TextAreaState {
}
use super::actions::*;
impl<'app> EditableTextActionHandler<'app> for TextAreaState {
impl<'app> EditableTextActionHandler<'app> for EditableTextAreaState {
type Context = gpui::Context<'app, Self>;
fn escape(&mut self, _: &Escape, window: &mut Window, cx: &mut Self::Context) {