From c982c802e21ea0ea1cd7a15cb738644a3c843fca Mon Sep 17 00:00:00 2001 From: reya Date: Sat, 1 Feb 2025 15:32:53 +0700 Subject: [PATCH] fix: clippy issues --- crates/ui/Cargo.toml | 2 +- crates/ui/src/clipboard.rs | 16 ++- crates/ui/src/context_menu.rs | 6 +- crates/ui/src/dropdown.rs | 18 ++- crates/ui/src/input/element.rs | 12 +- crates/ui/src/input/input.rs | 185 +++++++++++++++++++++++++------ crates/ui/src/modal.rs | 4 +- crates/ui/src/popover.rs | 15 ++- crates/ui/src/popup_menu.rs | 4 + crates/ui/src/resizable/panel.rs | 10 +- 10 files changed, 205 insertions(+), 67 deletions(-) diff --git a/crates/ui/Cargo.toml b/crates/ui/Cargo.toml index b84b820..d2783c5 100644 --- a/crates/ui/Cargo.toml +++ b/crates/ui/Cargo.toml @@ -16,7 +16,7 @@ chrono.workspace = true paste = "1" regex = "1" -unicode-segmentation = "1.11.0" +unicode-segmentation = "1.12.0" uuid = "1.10" once_cell = "1.19.0" image = "0.25.1" diff --git a/crates/ui/src/clipboard.rs b/crates/ui/src/clipboard.rs index ef3f794..99f7361 100644 --- a/crates/ui/src/clipboard.rs +++ b/crates/ui/src/clipboard.rs @@ -1,18 +1,22 @@ -use crate::{ - button::{Button, ButtonVariants as _}, - h_flex, IconName, Sizable as _, -}; use gpui::{ prelude::FluentBuilder, AnyElement, App, ClipboardItem, Element, ElementId, GlobalElementId, IntoElement, LayoutId, ParentElement, SharedString, Styled, Window, }; use std::{cell::RefCell, rc::Rc, time::Duration}; +use crate::{ + button::{Button, ButtonVariants as _}, + h_flex, IconName, Sizable as _, +}; + +type ContentBuilder = Option AnyElement>>; +type CopiedCallback = Option>; + pub struct Clipboard { id: ElementId, value: SharedString, - content_builder: Option AnyElement>>, - copied_callback: Option>, + content_builder: ContentBuilder, + copied_callback: CopiedCallback, } impl Clipboard { diff --git a/crates/ui/src/context_menu.rs b/crates/ui/src/context_menu.rs index aea2022..546c8eb 100644 --- a/crates/ui/src/context_menu.rs +++ b/crates/ui/src/context_menu.rs @@ -19,11 +19,13 @@ pub trait ContextMenuExt: ParentElement + Sized { impl ContextMenuExt for Stateful where E: ParentElement {} impl ContextMenuExt for FocusableWrapper where E: ParentElement {} +type Menu = + Option) -> PopupMenu + 'static>>; + /// A context menu that can be shown on right-click. pub struct ContextMenu { id: ElementId, - menu: - Option) -> PopupMenu + 'static>>, + menu: Menu, anchor: Corner, } diff --git a/crates/ui/src/dropdown.rs b/crates/ui/src/dropdown.rs index 1071c1c..7164b96 100644 --- a/crates/ui/src/dropdown.rs +++ b/crates/ui/src/dropdown.rs @@ -1,9 +1,3 @@ -use crate::{ - h_flex, - list::{self, List, ListDelegate, ListItem}, - theme::{scale::ColorScaleStep, ActiveTheme}, - v_flex, Icon, IconName, Sizable, Size, StyleSized, StyledExt, -}; use gpui::{ actions, anchored, canvas, deferred, div, prelude::FluentBuilder, px, rems, AnyElement, App, AppContext, Bounds, ClickEvent, Context, DismissEvent, ElementId, Entity, EventEmitter, @@ -11,6 +5,13 @@ use gpui::{ Pixels, Render, SharedString, StatefulInteractiveElement, Styled, Task, WeakEntity, Window, }; +use crate::{ + h_flex, + list::{self, List, ListDelegate, ListItem}, + theme::{scale::ColorScaleStep, ActiveTheme}, + v_flex, Icon, IconName, Sizable, Size, StyleSized, StyledExt, +}; + actions!(dropdown, [Up, Down, Enter, Escape]); const CONTEXT: &str = "Dropdown"; @@ -524,11 +525,6 @@ where cx.notify(); } - fn clean(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context) { - self.set_selected_index(None, window, cx); - cx.emit(DropdownEvent::Confirm(None)); - } - fn display_title(&self, window: &Window, cx: &App) -> impl IntoElement { let title = if let Some(selected_index) = &self.selected_index(window, cx) { let title = self diff --git a/crates/ui/src/input/element.rs b/crates/ui/src/input/element.rs index 04482a1..e019404 100644 --- a/crates/ui/src/input/element.rs +++ b/crates/ui/src/input/element.rs @@ -271,7 +271,7 @@ impl TextElement { // print_points_as_svg_path(&line_corners, &points); - let first_p = *points.get(0).unwrap(); + let first_p = *points.first().unwrap(); let mut builder = gpui::PathBuilder::fill(); builder.move_to(bounds.origin + first_p); for p in points.iter().skip(1) { @@ -503,6 +503,16 @@ impl Element for TextElement { let origin = bounds.origin; let mut offset_y = px(0.); + + if self.input.read(cx).masked { + // Move down offset for vertical centering the ***** + if cfg!(target_os = "macos") { + offset_y = px(3.); + } else { + offset_y = px(2.5); + } + } + for line in prepaint.lines.iter() { let p = point(origin.x, origin.y + offset_y); _ = line.paint(p, line_height, window, cx); diff --git a/crates/ui/src/input/input.rs b/crates/ui/src/input/input.rs index 2afa552..52b0abf 100644 --- a/crates/ui/src/input/input.rs +++ b/crates/ui/src/input/input.rs @@ -1,7 +1,13 @@ -//! A text input field that allows the user to enter text. -//! -//! Based on the `Input` example from the `gpui` crate. -//! https://github.com/zed-industries/zed/blob/main/crates/gpui/examples/input.rs +use gpui::{ + actions, div, point, prelude::FluentBuilder as _, px, AnyElement, App, AppContext, Bounds, + ClipboardItem, Context, Entity, EntityInputHandler, EventEmitter, FocusHandle, Focusable, Half, + InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, MouseDownEvent, + MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Rems, Render, ScrollHandle, + ScrollWheelEvent, SharedString, Styled as _, UTF16Selection, Window, WrappedLine, +}; +use smallvec::SmallVec; +use std::{cell::Cell, ops::Range, rc::Rc}; +use unicode_segmentation::*; use super::{blink_cursor::BlinkCursor, change::Change, element::TextElement}; use crate::{ @@ -11,16 +17,6 @@ use crate::{ theme::{scale::ColorScaleStep, ActiveTheme}, Sizable, Size, StyleSized, StyledExt, }; -use gpui::{ - actions, div, point, prelude::FluentBuilder as _, px, AnyElement, App, AppContext, Bounds, - ClickEvent, ClipboardItem, Context, Entity, EntityInputHandler, EventEmitter, FocusHandle, - Focusable, Half, InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, - MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Rems, Render, - ScrollHandle, ScrollWheelEvent, SharedString, Styled as _, UTF16Selection, Window, WrappedLine, -}; -use smallvec::SmallVec; -use std::{cell::Cell, ops::Range, rc::Rc}; -use unicode_segmentation::*; actions!( input, @@ -29,6 +25,8 @@ actions!( Delete, DeleteToBeginningOfLine, DeleteToEndOfLine, + DeleteToPreviousWordStart, + DeleteToNextWordEnd, Enter, Up, Down, @@ -45,6 +43,8 @@ actions!( SelectToEndOfLine, SelectToStart, SelectToEnd, + SelectToPreviousWordStart, + SelectToNextWordEnd, ShowCharacterPalette, Copy, Cut, @@ -55,6 +55,8 @@ actions!( MoveToEndOfLine, MoveToStart, MoveToEnd, + MoveToPreviousWord, + MoveToNextWord, TextChanged, ] ); @@ -77,6 +79,14 @@ pub fn init(cx: &mut App) { KeyBinding::new("cmd-backspace", DeleteToBeginningOfLine, Some(CONTEXT)), #[cfg(target_os = "macos")] KeyBinding::new("cmd-delete", DeleteToEndOfLine, Some(CONTEXT)), + #[cfg(target_os = "macos")] + KeyBinding::new("alt-backspace", DeleteToPreviousWordStart, Some(CONTEXT)), + #[cfg(not(target_os = "macos"))] + KeyBinding::new("ctrl-backspace", DeleteToPreviousWordStart, Some(CONTEXT)), + #[cfg(target_os = "macos")] + KeyBinding::new("alt-delete", DeleteToNextWordEnd, Some(CONTEXT)), + #[cfg(not(target_os = "macos"))] + KeyBinding::new("ctrl-delete", DeleteToNextWordEnd, Some(CONTEXT)), KeyBinding::new("enter", Enter, Some(CONTEXT)), KeyBinding::new("up", Up, Some(CONTEXT)), KeyBinding::new("down", Down, Some(CONTEXT)), @@ -99,6 +109,14 @@ pub fn init(cx: &mut App) { #[cfg(target_os = "macos")] KeyBinding::new("shift-cmd-right", SelectToEndOfLine, Some(CONTEXT)), #[cfg(target_os = "macos")] + KeyBinding::new("alt-shift-left", SelectToPreviousWordStart, Some(CONTEXT)), + #[cfg(not(target_os = "macos"))] + KeyBinding::new("ctrl-shift-left", SelectToPreviousWordStart, Some(CONTEXT)), + #[cfg(target_os = "macos")] + KeyBinding::new("alt-shift-right", SelectToNextWordEnd, Some(CONTEXT)), + #[cfg(not(target_os = "macos"))] + KeyBinding::new("ctrl-shift-right", SelectToNextWordEnd, Some(CONTEXT)), + #[cfg(target_os = "macos")] KeyBinding::new("ctrl-cmd-space", ShowCharacterPalette, Some(CONTEXT)), #[cfg(target_os = "macos")] KeyBinding::new("cmd-a", SelectAll, Some(CONTEXT)), @@ -133,6 +151,14 @@ pub fn init(cx: &mut App) { #[cfg(target_os = "macos")] KeyBinding::new("cmd-down", MoveToEnd, Some(CONTEXT)), #[cfg(target_os = "macos")] + KeyBinding::new("alt-left", MoveToPreviousWord, Some(CONTEXT)), + #[cfg(target_os = "macos")] + KeyBinding::new("alt-right", MoveToNextWord, Some(CONTEXT)), + #[cfg(not(target_os = "macos"))] + KeyBinding::new("ctrl-left", MoveToPreviousWord, Some(CONTEXT)), + #[cfg(not(target_os = "macos"))] + KeyBinding::new("ctrl-right", MoveToNextWord, Some(CONTEXT)), + #[cfg(target_os = "macos")] KeyBinding::new("cmd-shift-up", SelectToStart, Some(CONTEXT)), #[cfg(target_os = "macos")] KeyBinding::new("cmd-shift-down", SelectToEnd, Some(CONTEXT)), @@ -438,13 +464,13 @@ impl TextInput { } /// Set the disabled state of the input field. - pub fn set_disabled(&mut self, disabled: bool, window: &mut Window, cx: &mut Context) { + pub fn set_disabled(&mut self, disabled: bool, _window: &mut Window, cx: &mut Context) { self.disabled = disabled; cx.notify(); } /// Set the masked state of the input field. - pub fn set_masked(&mut self, masked: bool, window: &mut Window, cx: &mut Context) { + pub fn set_masked(&mut self, masked: bool, _window: &mut Window, cx: &mut Context) { self.masked = masked; cx.notify(); } @@ -474,7 +500,7 @@ impl TextInput { } /// Set the Input size - pub fn set_size(&mut self, size: Size, window: &mut Window, cx: &mut Context) { + pub fn set_size(&mut self, size: Size, _window: &mut Window, cx: &mut Context) { self.size = size; cx.notify(); } @@ -550,7 +576,7 @@ impl TextInput { } /// Set true to show indicator at the input right. - pub fn set_loading(&mut self, loading: bool, window: &mut Window, cx: &mut Context) { + pub fn set_loading(&mut self, loading: bool, _window: &mut Window, cx: &mut Context) { self.loading = loading; cx.notify(); } @@ -565,7 +591,7 @@ impl TextInput { } /// Focus the input field. - pub fn focus(&self, window: &mut Window, cx: &mut Context) { + pub fn focus(&self, window: &mut Window, _cx: &mut Context) { self.focus_handle.focus(window); } @@ -653,6 +679,25 @@ impl TextInput { self.move_to(end, window, cx); } + fn move_to_previous_word( + &mut self, + _: &MoveToPreviousWord, + window: &mut Window, + cx: &mut Context, + ) { + let offset = self.previous_start_of_word(); + self.move_to(offset, window, cx); + } + fn move_to_next_word( + &mut self, + _: &MoveToNextWord, + window: &mut Window, + cx: &mut Context, + ) { + let offset = self.next_end_of_word(); + self.move_to(offset, window, cx); + } + fn select_to_start(&mut self, _: &SelectToStart, window: &mut Window, cx: &mut Context) { self.select_to(0, window, cx); } @@ -682,6 +727,47 @@ impl TextInput { self.select_to(self.next_boundary(offset), window, cx); } + fn select_to_previous_word( + &mut self, + _: &SelectToPreviousWordStart, + window: &mut Window, + cx: &mut Context, + ) { + let offset = self.previous_start_of_word(); + self.select_to(offset, window, cx); + } + + fn select_to_next_word( + &mut self, + _: &SelectToNextWordEnd, + window: &mut Window, + cx: &mut Context, + ) { + let offset = self.next_end_of_word(); + self.select_to(offset, window, cx); + } + + /// Return the start offset of the previous word. + fn previous_start_of_word(&mut self) -> usize { + let offset = self.selected_range.start; + let prev_str = &self.text[..offset].to_string(); + UnicodeSegmentation::split_word_bound_indices(prev_str as &str) + .filter(|(_, s)| !s.trim_start().is_empty()) + .next_back() + .map(|(i, _)| i) + .unwrap_or(0) + } + + /// Return the next end offset of the next word. + fn next_end_of_word(&mut self) -> usize { + let offset = self.cursor_offset(); + let next_str = &self.text[offset..].to_string(); + UnicodeSegmentation::split_word_bound_indices(next_str as &str) + .find(|(_, s)| !s.trim_start().is_empty()) + .map(|(i, s)| offset + i + s.len()) + .unwrap_or(self.text.len()) + } + /// Get start of line fn start_of_line(&mut self, window: &mut Window, cx: &mut Context) -> usize { if self.is_single_line() { @@ -689,13 +775,12 @@ impl TextInput { } let offset = self.previous_boundary(self.cursor_offset()); - let line = self - .text_for_range(self.range_to_utf16(&(0..offset + 1)), &mut None, window, cx) + + self.text_for_range(self.range_to_utf16(&(0..offset + 1)), &mut None, window, cx) .unwrap_or_default() .rfind('\n') .map(|i| i + 1) - .unwrap_or(0); - line + .unwrap_or(0) } /// Get end of line @@ -779,6 +864,38 @@ impl TextInput { self.pause_blink_cursor(cx); } + fn delete_previous_word( + &mut self, + _: &DeleteToPreviousWordStart, + window: &mut Window, + cx: &mut Context, + ) { + let offset = self.previous_start_of_word(); + self.replace_text_in_range( + Some(self.range_to_utf16(&(offset..self.cursor_offset()))), + "", + window, + cx, + ); + self.pause_blink_cursor(cx); + } + + fn delete_next_word( + &mut self, + _: &DeleteToNextWordEnd, + window: &mut Window, + cx: &mut Context, + ) { + let offset = self.next_end_of_word(); + self.replace_text_in_range( + Some(self.range_to_utf16(&(self.cursor_offset()..offset))), + "", + window, + cx, + ); + self.pause_blink_cursor(cx); + } + fn enter(&mut self, _: &Enter, window: &mut Window, cx: &mut Context) { if self.is_multi_line() { let is_eof = self.selected_range.end == self.text.len(); @@ -795,10 +912,6 @@ impl TextInput { cx.emit(InputEvent::PressEnter); } - fn clean(&mut self, _: &ClickEvent, window: &mut Window, cx: &mut Context) { - self.replace_text("", window, cx); - } - fn on_mouse_down( &mut self, event: &MouseDownEvent, @@ -1122,7 +1235,7 @@ impl TextInput { cx.notify() } - fn unselect(&mut self, window: &mut Window, cx: &mut Context) { + fn unselect(&mut self, _window: &mut Window, cx: &mut Context) { self.selected_range = self.cursor_offset()..self.cursor_offset(); cx.notify() } @@ -1209,7 +1322,7 @@ impl TextInput { fn on_key_down_for_blink_cursor( &mut self, _: &KeyDownEvent, - window: &mut Window, + _window: &mut Window, cx: &mut Context, ) { self.pause_blink_cursor(cx) @@ -1272,7 +1385,7 @@ impl EntityInputHandler for TextInput { range_utf16: Range, adjusted_range: &mut Option>, _window: &mut Window, - cx: &mut Context, + _cx: &mut Context, ) -> Option { let range = self.range_from_utf16(&range_utf16); adjusted_range.replace(self.range_to_utf16(&range)); @@ -1283,7 +1396,7 @@ impl EntityInputHandler for TextInput { &mut self, _ignore_disabled_input: bool, _window: &mut Window, - cx: &mut Context, + _cx: &mut Context, ) -> Option { Some(UTF16Selection { range: self.range_to_utf16(&self.selected_range), @@ -1294,14 +1407,14 @@ impl EntityInputHandler for TextInput { fn marked_text_range( &self, _window: &mut Window, - cx: &mut Context, + _cx: &mut Context, ) -> Option> { self.marked_range .as_ref() .map(|range| self.range_to_utf16(range)) } - fn unmark_text(&mut self, _window: &mut Window, cx: &mut Context) { + fn unmark_text(&mut self, _window: &mut Window, _cx: &mut Context) { self.marked_range = None; } @@ -1437,6 +1550,8 @@ impl Render for TextInput { .on_action(cx.listener(Self::delete)) .on_action(cx.listener(Self::delete_to_beginning_of_line)) .on_action(cx.listener(Self::delete_to_end_of_line)) + .on_action(cx.listener(Self::delete_previous_word)) + .on_action(cx.listener(Self::delete_next_word)) .on_action(cx.listener(Self::enter)) }) .on_action(cx.listener(Self::left)) @@ -1452,10 +1567,14 @@ impl Render for TextInput { .on_action(cx.listener(Self::select_all)) .on_action(cx.listener(Self::select_to_start_of_line)) .on_action(cx.listener(Self::select_to_end_of_line)) + .on_action(cx.listener(Self::select_to_previous_word)) + .on_action(cx.listener(Self::select_to_next_word)) .on_action(cx.listener(Self::home)) .on_action(cx.listener(Self::end)) .on_action(cx.listener(Self::move_to_start)) .on_action(cx.listener(Self::move_to_end)) + .on_action(cx.listener(Self::move_to_previous_word)) + .on_action(cx.listener(Self::move_to_next_word)) .on_action(cx.listener(Self::select_to_start)) .on_action(cx.listener(Self::select_to_end)) .on_action(cx.listener(Self::show_character_palette)) diff --git a/crates/ui/src/modal.rs b/crates/ui/src/modal.rs index e48d499..dc0d978 100644 --- a/crates/ui/src/modal.rs +++ b/crates/ui/src/modal.rs @@ -20,6 +20,8 @@ pub fn init(cx: &mut App) { cx.bind_keys([KeyBinding::new("escape", Escape, Some(CONTEXT))]) } +type OnClose = Rc; + #[derive(IntoElement)] pub struct Modal { base: Div, @@ -29,7 +31,7 @@ pub struct Modal { width: Pixels, max_width: Option, margin_top: Option, - on_close: Rc, + on_close: OnClose, show_close: bool, keyboard: bool, /// This will be change when open the modal, the focus handle is create when open the modal. diff --git a/crates/ui/src/popover.rs b/crates/ui/src/popover.rs index d1dcdb3..273a2a1 100644 --- a/crates/ui/src/popover.rs +++ b/crates/ui/src/popover.rs @@ -16,10 +16,12 @@ pub fn init(cx: &mut App) { cx.bind_keys([KeyBinding::new("escape", Escape, Some(CONTEXT))]) } +type PopoverChild = Rc) -> AnyElement>; + pub struct PopoverContent { focus_handle: FocusHandle, - content: Rc) -> AnyElement>, max_width: Option, + child: PopoverChild, } impl PopoverContent { @@ -31,7 +33,7 @@ impl PopoverContent { Self { focus_handle, - content: Rc::new(content), + child: Rc::new(content), max_width: None, } } @@ -58,15 +60,18 @@ impl Render for PopoverContent { .on_action(cx.listener(|_, _: &Escape, _, cx| cx.emit(DismissEvent))) .p_2() .when_some(self.max_width, |this, v| this.max_w(v)) - .child(self.content.clone()(window, cx)) + .child(self.child.clone()(window, cx)) } } +type Trigger = Option AnyElement + 'static>>; +type Content = Option Entity + 'static>>; + pub struct Popover { id: ElementId, anchor: Corner, - trigger: Option AnyElement + 'static>>, - content: Option Entity + 'static>>, + trigger: Trigger, + content: Content, /// Style for trigger element. /// This is used for hotfix the trigger element style to support w_full. trigger_style: Option, diff --git a/crates/ui/src/popup_menu.rs b/crates/ui/src/popup_menu.rs index c9249a2..1094b53 100644 --- a/crates/ui/src/popup_menu.rs +++ b/crates/ui/src/popup_menu.rs @@ -67,10 +67,13 @@ enum PopupMenuItem { icon: Option, label: SharedString, action: Option>, + #[allow(clippy::type_complexity)] handler: Rc, }, ElementItem { + #[allow(clippy::type_complexity)] render: Box AnyElement + 'static>, + #[allow(clippy::type_complexity)] handler: Rc, }, Submenu { @@ -249,6 +252,7 @@ impl PopupMenu { self } + #[allow(clippy::type_complexity)] fn wrap_handler(&self, action: Box) -> Rc { let action_focus_handle = self.action_focus_handle.clone(); diff --git a/crates/ui/src/resizable/panel.rs b/crates/ui/src/resizable/panel.rs index dbd6674..bf299f4 100644 --- a/crates/ui/src/resizable/panel.rs +++ b/crates/ui/src/resizable/panel.rs @@ -1,5 +1,3 @@ -use super::resize_handle; -use crate::{h_flex, v_flex, AxisExt}; use gpui::{ canvas, div, prelude::FluentBuilder, px, relative, Along, AnyElement, AnyView, App, AppContext, Axis, Bounds, Context, Element, Entity, EntityId, EventEmitter, IntoElement, IsZero, @@ -8,6 +6,9 @@ use gpui::{ }; use std::rc::Rc; +use super::resize_handle; +use crate::{h_flex, v_flex, AxisExt}; + pub(crate) const PANEL_MIN_SIZE: Pixels = px(100.); pub enum ResizablePanelEvent { @@ -90,11 +91,6 @@ impl ResizablePanelGroup { self } - /// Returns the sizes of the resizable panels. - pub(crate) fn sizes(&self) -> Vec { - self.sizes.clone() - } - /// Calculates the sum of all panel sizes within the group. pub fn total_size(&self) -> Pixels { self.sizes.iter().fold(px(0.0), |acc, &size| acc + size)