diff --git a/crates/ui/src/history.rs b/crates/ui/src/history.rs index 71f8939..d933c4c 100644 --- a/crates/ui/src/history.rs +++ b/crates/ui/src/history.rs @@ -173,3 +173,12 @@ where } } } + +impl Default for History +where + I: HistoryItem, +{ + fn default() -> Self { + Self::new() + } +} diff --git a/crates/ui/src/input/element.rs b/crates/ui/src/input/element.rs index 6202893..c53166e 100644 --- a/crates/ui/src/input/element.rs +++ b/crates/ui/src/input/element.rs @@ -149,9 +149,7 @@ impl Element for EditorScrollbar { cx: &mut App, ) -> Self::PrepaintState { let state = self.state.read(cx); - let Some(snapshot) = state.editor_scrollbar_snapshot.get() else { - return None; - }; + let snapshot = state.editor_scrollbar_snapshot.get()?; let scroll_handle = state.scroll_handle.clone(); if scroll_handle.offset() != snapshot.cursor_scroll_offset { @@ -492,7 +490,7 @@ impl TextElement { bounds.size.height, ); - bounds.origin = bounds.origin + scroll_offset; + bounds.origin += scroll_offset; (cursor_bounds, scroll_offset, current_row) } @@ -622,17 +620,17 @@ impl TextElement { let mut rev_line_corners = line_corners.iter().rev().peekable(); while let Some(corners) = rev_line_corners.next() { points.push(corners.top_left); - if let Some(next) = rev_line_corners.peek() { - if next.top_left.x > corners.top_left.x { - points.push(point(next.top_left.x, corners.top_left.y)); - } + if let Some(next) = rev_line_corners.peek() + && next.top_left.x > corners.top_left.x + { + points.push(point(next.top_left.x, corners.top_left.y)); } } // print_points_as_svg_path(&line_corners, &points); let path_origin = bounds.origin + point(line_number_width, px(0.)); - let first_p = *points.get(0).unwrap(); + let first_p = *points.first().unwrap(); let mut builder = gpui::PathBuilder::fill(); builder.move_to(path_origin + first_p); for p in points.iter().skip(1) { @@ -690,10 +688,10 @@ impl TextElement { } let mut selected_range = state.selected_range; - if let Some(ime_marked_range) = &state.ime_marked_range { - if !ime_marked_range.is_empty() { - selected_range = (ime_marked_range.end..ime_marked_range.end).into(); - } + if let Some(ime_marked_range) = &state.ime_marked_range + && !ime_marked_range.is_empty() + { + selected_range = (ime_marked_range.end..ime_marked_range.end).into(); } if selected_range.is_empty() { return None; @@ -713,7 +711,7 @@ impl TextElement { let range = start_ix.max(last_layout.visible_range_offset.start) ..end_ix.min(last_layout.visible_range_offset.end); - Self::layout_match_range(range, &last_layout, bounds) + Self::layout_match_range(range, last_layout, bounds) } /// Calculate the visible range of lines in the viewport. @@ -1065,7 +1063,7 @@ impl TextElement { let shaped_line = window.text_system().shape_line( display_text.to_string().into(), font_size, - &runs, + runs, None, ); @@ -1114,7 +1112,7 @@ impl TextElement { let mut wrapped_lines = SmallVec::with_capacity(1); for range in &line_item.wrapped_lines { - let line_runs = runs_for_range(runs, run_offset, &range); + let line_runs = runs_for_range(runs, run_offset, range); let line_runs = if bg_segments.is_empty() { line_runs } else { @@ -1260,10 +1258,7 @@ impl IntoElement for TextElement { /// A debug function to print points as SVG path. #[allow(unused)] -fn print_points_as_svg_path( - line_corners: &Vec>, - points: &Vec>, -) { +fn print_points_as_svg_path(line_corners: &Vec>, points: Vec>) { for corners in line_corners { println!( "tl: ({}, {}), tr: ({}, {}), bl: ({}, {}), br: ({}, {})", @@ -1278,7 +1273,7 @@ fn print_points_as_svg_path( ); } - if points.len() > 0 { + if !points.is_empty() { println!( "M{},{}", points[0].x.as_f32() as i32, @@ -1353,7 +1348,7 @@ impl Element for TextElement { let line_height = window.line_height(); let (visible_range, visible_buffer_lines, visible_top) = - self.calculate_visible_range(&state, line_height, bounds.size.height); + self.calculate_visible_range(state, line_height, bounds.size.height); let visible_start_offset = state.text.line_start_offset(visible_range.start); let visible_end_offset = state .text @@ -1387,7 +1382,7 @@ impl Element for TextElement { // Calculate the width of the line numbers let (line_number_width, line_number_len) = - Self::layout_line_numbers(&state, &text, text_size, &text_style, window); + Self::layout_line_numbers(state, &text, text_size, &text_style, window); let mut bounds = bounds; let wrap_width = if multi_line && state.soft_wrap { @@ -1460,14 +1455,14 @@ impl Element for TextElement { runs.extend(highlight_styles.iter().map(|(range, style)| { let mut run = text_style.clone().highlight(*style).to_run(range.len()); - if let Some(ime_marked_range) = &state.ime_marked_range { - if range.start >= ime_marked_range.start - && range.end <= ime_marked_range.end - { - run.color = marked_run.color; - run.strikethrough = marked_run.strikethrough; - run.underline = marked_run.underline; - } + + if let Some(ime_marked_range) = &state.ime_marked_range + && range.start >= ime_marked_range.start + && range.end <= ime_marked_range.end + { + run.color = marked_run.color; + run.strikethrough = marked_run.strikethrough; + run.underline = marked_run.underline; } run @@ -1505,11 +1500,11 @@ impl Element for TextElement { // Create shaped lines for whitespace indicators before layout let whitespace_indicators = - Self::layout_whitespace_indicators(&state, text_size, &text_style, window, cx); + Self::layout_whitespace_indicators(state, text_size, &text_style, window, cx); let lines = Self::layout_lines( - &state, - &display_text, + state, + display_text, &last_layout, text_size, &runs, @@ -1621,9 +1616,9 @@ impl Element for TextElement { self.layout_cursor(&last_layout, &mut bounds, scroll_size, window, cx); last_layout.cursor_bounds = cursor_bounds; - let search_match_paths = self.layout_search_matches(&last_layout, &mut bounds, cx); + let search_match_paths = self.layout_search_matches(&last_layout, &bounds, cx); let selection_path = self.layout_selections(&last_layout, &mut bounds, window, cx); - let hover_highlight_path = self.layout_hover_highlight(&last_layout, &mut bounds, cx); + let hover_highlight_path = self.layout_hover_highlight(&last_layout, &bounds, cx); let document_color_paths = self.layout_document_colors(&document_colors, &last_layout, &bounds, cx); @@ -1666,7 +1661,7 @@ impl Element for TextElement { sub_lines.push( window .text_system() - .shape_line(line_no, text_size, &runs, None), + .shape_line(line_no, text_size, runs, None), ); for _ in 0..line.wrapped_lines.len().saturating_sub(1) { sub_lines.push(ShapedLine::default()); @@ -1847,7 +1842,7 @@ impl Element for TextElement { ); // Paint the actual line - _ = line.paint( + line.paint( p, line_height, text_align, @@ -1893,10 +1888,11 @@ impl Element for TextElement { } // Paint blinking cursor - if focused && show_cursor { - if let Some(cursor_bounds) = prepaint.cursor_bounds_with_scroll() { - window.paint_quad(fill(cursor_bounds, cx.theme().cursor)); - } + if focused + && show_cursor + && let Some(cursor_bounds) = prepaint.cursor_bounds_with_scroll() + { + window.paint_quad(fill(cursor_bounds, cx.theme().cursor)); } // Paint line numbers @@ -1956,26 +1952,24 @@ impl Element for TextElement { }); if let Some(hitbox) = prepaint.hover_definition_hitbox.as_ref() { - window.set_cursor_style(gpui::CursorStyle::PointingHand, &hitbox); + window.set_cursor_style(gpui::CursorStyle::PointingHand, hitbox); } // Paint inline completion first line suffix (after cursor on same line) - if focused { - if let Some(first_line) = &prepaint.ghost_first_line { - if let (Some(cursor_bounds), Some(cursor_row_y)) = - (prepaint.cursor_bounds_with_scroll(), cursor_row_y) - { - let first_line_x = cursor_bounds.origin.x + cursor_bounds.size.width; - let p = point(first_line_x, cursor_row_y); + if focused + && let Some(first_line) = &prepaint.ghost_first_line + && let (Some(cursor_bounds), Some(cursor_row_y)) = + (prepaint.cursor_bounds_with_scroll(), cursor_row_y) + { + let first_line_x = cursor_bounds.origin.x + cursor_bounds.size.width; + let p = point(first_line_x, cursor_row_y); - // Paint background to cover any existing text - let bg_bounds = Bounds::new(p, size(first_line.width + px(4.), line_height)); - window.paint_quad(fill(bg_bounds, cx.theme().surface_background)); + // Paint background to cover any existing text + let bg_bounds = Bounds::new(p, size(first_line.width + px(4.), line_height)); + window.paint_quad(fill(bg_bounds, cx.theme().surface_background)); - // Paint first line completion text - _ = first_line.paint(p, line_height, text_align, None, window, cx); - } - } + // Paint first line completion text + _ = first_line.paint(p, line_height, text_align, None, window, cx); } self.paint_mouse_listeners(window, cx); diff --git a/crates/ui/src/input/indent.rs b/crates/ui/src/input/indent.rs index eedce68..54dd386 100644 --- a/crates/ui/src/input/indent.rs +++ b/crates/ui/src/input/indent.rs @@ -26,7 +26,7 @@ impl Default for TabSize { } impl TabSize { - pub(super) fn to_string(&self) -> SharedString { + pub(super) fn to_string(self) -> SharedString { if self.hard_tabs { "\t".into() } else { @@ -146,7 +146,7 @@ impl TextElement { builder.line_to(point(pos.x, pos.y + line_height)); current_indents.push(pos.x); } - } else if last_indents.len() > 0 { + } else if !last_indents.is_empty() { for x in &last_indents { let pos = point(*x, offset_y); builder.move_to(pos); diff --git a/crates/ui/src/input/input.rs b/crates/ui/src/input/input.rs index 697d2a7..68d4e1f 100644 --- a/crates/ui/src/input/input.rs +++ b/crates/ui/src/input/input.rs @@ -1,10 +1,8 @@ -use std::rc::Rc; - use gpui::prelude::FluentBuilder as _; use gpui::{ - AnyElement, App, Context, DefiniteLength, Edges, EdgesRefinement, Entity, Hsla, - InteractiveElement as _, IntoElement, MouseButton, ParentElement as _, Rems, RenderOnce, - StyleRefinement, Styled, TextAlign, Window, div, px, relative, + AnyElement, App, DefiniteLength, Edges, EdgesRefinement, Entity, Hsla, InteractiveElement as _, + IntoElement, MouseButton, ParentElement as _, Rems, RenderOnce, StyleRefinement, Styled, + TextAlign, Window, div, px, relative, }; use theme::ActiveTheme; @@ -13,7 +11,6 @@ use super::element::EditorScrollbar; use crate::button::{Button, ButtonVariants as _}; use crate::indicator::Indicator; use crate::input::clear_button; -use crate::menu::PopupMenu; use crate::{IconName, Selectable, Sizable, Size, StyleSized, StyledExt, h_flex, v_flex}; /// Returns `(background, foreground)` colors for input-like components. @@ -42,12 +39,6 @@ pub struct Input { focus_bordered: bool, tab_index: isize, selected: bool, - - /// An optional context menu builder to allow a custom context menu on the input. - /// - /// If set, this will override the built-in context menu. - context_menu_builder: - Option) -> PopupMenu>>, } impl Sizable for Input { @@ -86,7 +77,6 @@ impl Input { focus_bordered: true, tab_index: 0, selected: false, - context_menu_builder: None, } } @@ -154,15 +144,6 @@ impl Input { self } - /// Sets the context menu for the input. - pub fn context_menu( - mut self, - f: impl Fn(PopupMenu, &mut Window, &mut Context) -> PopupMenu + 'static, - ) -> Self { - self.context_menu_builder = Some(Rc::new(f)); - self - } - fn render_toggle_mask_button(state: &Entity, cx: &App) -> impl IntoElement { let _masked = state.read(cx).masked; Button::new("toggle-mask") @@ -234,10 +215,8 @@ impl RenderOnce for Input { let text_align = self.style.text.text_align.unwrap_or(TextAlign::Left); self.state.update(cx, |state, _| { - state.context_menu_builder = self.context_menu_builder.clone(); state.disabled = self.disabled; state.size = self.size; - // Only for single line mode if state.mode.is_single_line() { state.text_align = text_align; @@ -342,7 +321,6 @@ impl RenderOnce for Input { MouseButton::Right, window.listener_for(&self.state, InputState::on_mouse_up), ) - .on_mouse_move(window.listener_for(&self.state, InputState::on_mouse_move)) .on_scroll_wheel(window.listener_for(&self.state, InputState::on_scroll_wheel)) .size_full() .line_height(LINE_HEIGHT) @@ -372,7 +350,7 @@ impl RenderOnce for Input { .children(prefix) .when(state.mode.is_multi_line(), |mut this| { let paddings = this.style().padding.clone(); - this.child(Self::render_editor(paddings, &self.state, &state, window)) + this.child(Self::render_editor(paddings, &self.state, state, window)) }) .when(!state.mode.is_multi_line(), |this| { this.child(self.state.clone()) diff --git a/crates/ui/src/input/mask_pattern.rs b/crates/ui/src/input/mask_pattern.rs index a1b40a4..e78f234 100644 --- a/crates/ui/src/input/mask_pattern.rs +++ b/crates/ui/src/input/mask_pattern.rs @@ -225,13 +225,12 @@ impl MaskPattern { } // check if the fraction part is valid - if let Some(frac) = frac_part { - if !frac + if let Some(frac) = frac_part + && !frac .chars() .all(|ch| ch.is_ascii_digit() || Some(ch) == *separator) - { - return false; - } + { + return false; } true @@ -255,10 +254,10 @@ impl MaskPattern { if token.is_sep() { // If next token is match, it's valid - if let Some(next_token) = tokens.get(pos + 1) { - if next_token.is_match(ch) { - return true; - } + if let Some(next_token) = tokens.get(pos + 1) + && next_token.is_match(ch) + { + return true; } } } @@ -305,11 +304,7 @@ impl MaskPattern { let mut chars: Vec = int_part.chars().rev().collect(); // Removing the sign from formatting to avoid cases such as: -,123 - let maybe_signed = if let Some(pos) = chars.iter().position(is_sign) { - Some(chars.remove(pos)) - } else { - None - }; + let maybe_signed = chars.iter().position(is_sign).map(|pos| chars.remove(pos)); let mut result = String::new(); for (i, ch) in chars.iter().enumerate() { @@ -386,7 +381,7 @@ impl MaskPattern { return result; } - return mask_text.to_owned(); + mask_text.to_owned() } Self::Pattern { tokens, .. } => { let mut result = String::new(); @@ -412,226 +407,3 @@ impl MaskPattern { fn is_sign(ch: &char) -> bool { matches!(ch, '+' | '-') } - -#[cfg(test)] -mod tests { - use crate::input::mask_pattern::{MaskPattern, MaskToken}; - - #[test] - fn test_is_match() { - assert_eq!(MaskToken::Sep('(').is_match('('), true); - assert_eq!(MaskToken::Sep('-').is_match('('), false); - assert_eq!(MaskToken::Sep('-').is_match('3'), false); - - assert_eq!(MaskToken::Digit.is_match('0'), true); - assert_eq!(MaskToken::Digit.is_match('9'), true); - assert_eq!(MaskToken::Digit.is_match('a'), false); - assert_eq!(MaskToken::Digit.is_match('C'), false); - - assert_eq!(MaskToken::Letter.is_match('a'), true); - assert_eq!(MaskToken::Letter.is_match('Z'), true); - assert_eq!(MaskToken::Letter.is_match('3'), false); - assert_eq!(MaskToken::Letter.is_match('-'), false); - - assert_eq!(MaskToken::LetterOrDigit.is_match('0'), true); - assert_eq!(MaskToken::LetterOrDigit.is_match('9'), true); - assert_eq!(MaskToken::LetterOrDigit.is_match('a'), true); - assert_eq!(MaskToken::LetterOrDigit.is_match('Z'), true); - assert_eq!(MaskToken::LetterOrDigit.is_match('3'), true); - - assert_eq!(MaskToken::Any.is_match('a'), true); - assert_eq!(MaskToken::Any.is_match('3'), true); - assert_eq!(MaskToken::Any.is_match('-'), true); - assert_eq!(MaskToken::Any.is_match(' '), true); - } - - #[test] - fn test_mask_none() { - let mask = MaskPattern::None; - assert_eq!(mask.is_none(), true); - assert_eq!(mask.is_valid("1124124ASLDJKljk"), true); - assert_eq!(mask.mask("hello-world"), "hello-world"); - assert_eq!(mask.unmask("hello-world"), "hello-world"); - } - - #[test] - fn test_mask_pattern1() { - let mask = MaskPattern::new("(AA)999-999"); - assert_eq!( - mask.tokens(), - Some(&vec![ - MaskToken::Sep('('), - MaskToken::Letter, - MaskToken::Letter, - MaskToken::Sep(')'), - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Sep('-'), - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Digit, - ]) - ); - - assert_eq!(mask.is_valid_at('(', 0), true); - assert_eq!(mask.is_valid_at('H', 0), true); - assert_eq!(mask.is_valid_at('3', 0), false); - assert_eq!(mask.is_valid_at('-', 0), false); - assert_eq!(mask.is_valid_at(')', 1), false); - assert_eq!(mask.is_valid_at('H', 1), true); - assert_eq!(mask.is_valid_at('1', 1), false); - assert_eq!(mask.is_valid_at('e', 2), true); - assert_eq!(mask.is_valid_at(')', 3), true); - assert_eq!(mask.is_valid_at('1', 3), true); - assert_eq!(mask.is_valid_at('2', 4), true); - - assert_eq!(mask.is_valid("(AB)123-456"), true); - - assert_eq!(mask.mask("AB123456"), "(AB)123-456"); - assert_eq!(mask.mask("(AB)123-456"), "(AB)123-456"); - assert_eq!(mask.mask("(AB123456"), "(AB)123-456"); - assert_eq!(mask.mask("AB123-456"), "(AB)123-456"); - assert_eq!(mask.mask("AB123-"), "(AB)123-"); - assert_eq!(mask.mask("AB123--"), "(AB)123-"); - assert_eq!(mask.mask("AB123-4"), "(AB)123-4"); - - let unmasked_text = mask.unmask("(AB)123-456"); - assert_eq!(unmasked_text, "AB123456"); - - assert_eq!(mask.is_valid("12AB345"), false); - assert_eq!(mask.is_valid("(11)123-456"), false); - assert_eq!(mask.is_valid("##"), false); - assert_eq!(mask.is_valid("(AB)123456"), true); - } - - #[test] - fn test_mask_pattern2() { - let mask = MaskPattern::new("999-999-******"); - assert_eq!( - mask.tokens(), - Some(&vec![ - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Sep('-'), - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Digit, - MaskToken::Sep('-'), - MaskToken::Any, - MaskToken::Any, - MaskToken::Any, - MaskToken::Any, - MaskToken::Any, - MaskToken::Any, - ]) - ); - - let text = "123456A(111)"; - let masked_text = mask.mask(text); - assert_eq!(masked_text, "123-456-A(111)"); - let unmasked_text = mask.unmask(&masked_text); - assert_eq!(unmasked_text, "123456A(111)"); - assert_eq!(mask.is_valid(&masked_text), true); - } - - #[test] - fn test_number_with_group_separator() { - // Use comma as group separator - let mask = MaskPattern::number(Some(',')); - assert_eq!(mask.mask("1234567"), "1,234,567"); - assert_eq!(mask.mask("1,234,567"), "1,234,567"); - assert_eq!(mask.unmask("1,234,567"), "1234567"); - let mask = MaskPattern::number(Some(',')); - assert_eq!(mask.mask("1234567.89"), "1,234,567.89"); - assert_eq!(mask.unmask("1,234,567.89"), "1234567.89"); - - // Use space as group separator - let mask = MaskPattern::number(Some(' ')); - assert_eq!(mask.mask("1234567"), "1 234 567"); - assert_eq!(mask.unmask("1 234 567"), "1234567"); - let mask = MaskPattern::number(Some(' ')); - assert_eq!(mask.mask("1234567.89"), "1 234 567.89"); - assert_eq!(mask.unmask("1 234 567.89"), "1234567.89"); - - // No group separator - let mask = MaskPattern::number(None); - assert_eq!(mask.mask("1234567"), "1234567"); - assert_eq!(mask.unmask("1234567"), "1234567"); - let mask = MaskPattern::number(None); - assert_eq!(mask.mask("1234567.89"), "1234567.89"); - assert_eq!(mask.unmask("1234567.89"), "1234567.89"); - } - - #[test] - fn test_number_with_fraction_digits() { - let mask = MaskPattern::Number { - separator: Some(','), - fraction: Some(4), - }; - - assert_eq!(mask.mask("1234567"), "1,234,567"); - assert_eq!(mask.unmask("1,234,567"), "1234567"); - assert_eq!(mask.mask("1234567."), "1,234,567."); - assert_eq!(mask.mask("1234567.89"), "1,234,567.89"); - assert_eq!(mask.unmask("1,234,567.890"), "1234567.89"); - assert_eq!(mask.mask("1234567.891"), "1,234,567.891"); - assert_eq!(mask.mask("1234567.891234"), "1,234,567.8912"); - - let mask = MaskPattern::Number { - separator: Some(','), - fraction: None, - }; - - assert_eq!(mask.mask("1234567.1234567"), "1,234,567.1234567"); - - let mask = MaskPattern::Number { - separator: Some(','), - fraction: Some(0), - }; - - assert_eq!(mask.mask("1234567.1234567"), "1,234,567"); - } - - #[test] - fn test_signed_number_numbers() { - let mask = MaskPattern::Number { - separator: Some(','), - fraction: Some(2), - }; - - assert_eq!(mask.is_valid("-"), true); - assert_eq!(mask.is_valid("-1234567"), true); - assert_eq!(mask.is_valid("-1,234,567"), true); - assert_eq!(mask.is_valid("-1234567."), true); - assert_eq!(mask.is_valid("-1234567.89"), true); - - assert_eq!(mask.is_valid("+"), true); - assert_eq!(mask.is_valid("+1234567"), true); - assert_eq!(mask.is_valid("+1,234,567"), true); - assert_eq!(mask.is_valid("+1234567."), true); - assert_eq!(mask.is_valid("+1234567.89"), true); - - // Only one sign is valid - assert_eq!(mask.is_valid("+-"), false); - assert_eq!(mask.is_valid("-+"), false); - assert_eq!(mask.is_valid("+-1234567"), false); - - // No sign is valid in the middle of the number - assert_eq!(mask.is_valid("1,-234,567"), false); - assert_eq!(mask.is_valid("12-34567.89"), false); - - // Signs in fractions are invalid - assert_eq!(mask.is_valid("+1234567.-"), false); - - // The separator does not show up before the sign i.e. -,123 - assert_eq!(mask.mask("-123"), "-123"); - - assert_eq!(mask.mask("-1234567"), "-1,234,567"); - assert_eq!(mask.mask("+1234567"), "+1,234,567"); - assert_eq!(mask.unmask("-1,234,567"), "-1234567"); - assert_eq!(mask.mask("-1234567."), "-1,234,567."); - assert_eq!(mask.mask("-1234567.89"), "-1,234,567.89"); - } -} diff --git a/crates/ui/src/input/mod.rs b/crates/ui/src/input/mod.rs index 5800313..63d5bce 100644 --- a/crates/ui/src/input/mod.rs +++ b/crates/ui/src/input/mod.rs @@ -7,6 +7,7 @@ mod cursor; mod display_map; mod element; mod indent; +#[allow(clippy::module_inception)] mod input; mod mask_pattern; mod mode; diff --git a/crates/ui/src/input/movement.rs b/crates/ui/src/input/movement.rs index d4cdf89..5e6160f 100644 --- a/crates/ui/src/input/movement.rs +++ b/crates/ui/src/input/movement.rs @@ -152,7 +152,7 @@ impl InputState { } } - pub(super) fn up(&mut self, action: &MoveUp, window: &mut Window, cx: &mut Context) { + pub(super) fn up(&mut self, _action: &MoveUp, window: &mut Window, cx: &mut Context) { if self.mode.is_single_line() { return; } @@ -168,7 +168,7 @@ impl InputState { self.move_vertical(-1, window, cx); } - pub(super) fn down(&mut self, action: &MoveDown, window: &mut Window, cx: &mut Context) { + pub(super) fn down(&mut self, _action: &MoveDown, window: &mut Window, cx: &mut Context) { if self.mode.is_single_line() { return; } diff --git a/crates/ui/src/input/rope_ext.rs b/crates/ui/src/input/rope_ext.rs index 4f6aa20..609112a 100644 --- a/crates/ui/src/input/rope_ext.rs +++ b/crates/ui/src/input/rope_ext.rs @@ -304,7 +304,7 @@ impl RopeExt for Rope { } fn iter_lines(&self) -> RopeLines<'_> { - RopeLines::new(&self) + RopeLines::new(self) } fn line_len(&self, row: usize) -> usize { diff --git a/crates/ui/src/input/selection.rs b/crates/ui/src/input/selection.rs index c875865..ad01817 100644 --- a/crates/ui/src/input/selection.rs +++ b/crates/ui/src/input/selection.rs @@ -54,13 +54,11 @@ impl TextSelector { /// Returns the start and end offsets of the selected word. pub fn word_range(text: &Rope, offset: usize) -> Option> { let offset = text.clip_offset(offset, Bias::Left); - let Some(char) = text.char_at(offset) else { - return None; - }; - + let char = text.char_at(offset)?; let end = offset + char.len_utf8(); let prev_chars = text.chars_at(offset).reversed().take(128); let next_chars = text.chars_at(end).take(128); + Some(word_range_from_chars(offset, char, prev_chars, next_chars)) } } diff --git a/crates/ui/src/input/state.rs b/crates/ui/src/input/state.rs index 210721c..6fdd4ff 100644 --- a/crates/ui/src/input/state.rs +++ b/crates/ui/src/input/state.rs @@ -6,14 +6,13 @@ use std::cell::Cell; use std::ops::Range; use std::rc::Rc; -use anyhow::Result; use gpui::prelude::FluentBuilder as _; use gpui::{ Action, App, AppContext, Bounds, ClipboardItem, Context, Edges, Entity, EntityInputHandler, EventEmitter, FocusHandle, Focusable, Half, InteractiveElement as _, IntoElement, KeyBinding, KeyDownEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement as _, Pixels, Point, Render, ScrollHandle, ScrollWheelEvent, ShapedLine, SharedString, Styled as _, - Subscription, Task, TextAlign, UTF16Selection, Window, actions, div, point, px, + Subscription, TextAlign, UTF16Selection, Window, actions, div, point, px, }; use ropey::{Rope, RopeSlice}; use serde::Deserialize; @@ -34,7 +33,6 @@ use crate::input::element::RIGHT_MARGIN; use crate::input::movement::MoveDirection; use crate::input::rope_ext::Position; use crate::input::{RopeExt as _, Selection}; -use crate::menu::PopupMenu; use crate::{Root, Size}; #[derive(Action, Clone, PartialEq, Eq, Deserialize)] @@ -323,6 +321,7 @@ impl LastLayout { } /// InputState to keep editing state of the [`super::Input`]. +#[allow(clippy::type_complexity)] pub struct InputState { pub(super) focus_handle: FocusHandle, pub(super) mode: InputMode, @@ -374,24 +373,6 @@ pub struct InputState { pub(crate) mask_pattern: MaskPattern, pub(super) placeholder: SharedString, - /// An optional context menu builder to allow a custom context menu on the input. - /// - /// If set, this will override the built-in context menu and ignore the value set in [`Self::enable_context_menu`]. - pub(super) context_menu_builder: - Option) -> PopupMenu>>, - - /// Whether the context menu that shows on right-click is enabled. - /// - /// This value will be ignored if a context menu builder is defined in [`Self::context_menu_builder`]. - pub(super) enable_context_menu: bool, - - /// A flag to indicate if we are currently inserting a completion item. - pub(super) completion_inserting: bool, - - /// A flag to indicate if we have a pending update to the text. - /// - /// If true, will call some update (for example LSP, Syntax Highlight) before render. - _pending_update: bool, /// A flag to indicate if we should ignore the next completion event. pub(super) silent_replace_text: bool, /// A flag to indicate if we should emit InputEvents. @@ -403,8 +384,6 @@ pub struct InputState { /// The second element is the column (usize), fallback to use this. pub(super) preferred_column: Option<(Pixels, usize)>, _subscriptions: Vec, - - pub(super) _context_menu_task: Task>, } impl EventEmitter for InputState {} @@ -479,15 +458,10 @@ impl InputState { placeholder: SharedString::default(), mask_pattern: MaskPattern::default(), text_align: TextAlign::Left, - context_menu_builder: None, - enable_context_menu: true, - completion_inserting: false, silent_replace_text: false, emit_events: true, size: Size::default(), _subscriptions, - _context_menu_task: Task::ready(Ok(())), - _pending_update: false, cursor_line_end_affinity: false, } } @@ -533,15 +507,6 @@ impl InputState { self } - /// Sets whether the context menu that shows on right-click is enabled. - /// - /// The context menu is enabled by default. - /// This value will be ignored if a custom context menu is defined on the input. - pub fn context_menu(mut self, enable: bool) -> Self { - self.enable_context_menu = enable; - self - } - /// Set whether search UI allows replacement, default is true. pub fn replaceable(mut self, allow: bool) -> Self { self.replaceable = allow; @@ -625,26 +590,21 @@ impl InputState { new_language: impl Into, cx: &mut Context, ) { - match &mut self.mode { - InputMode::CodeEditor { - language, - parse_task, - .. - } => { - *language = new_language.into(); - parse_task.borrow_mut().take(); - } - _ => {} + if let InputMode::CodeEditor { + language, + parse_task, + .. + } = &mut self.mode + { + *language = new_language.into(); + parse_task.borrow_mut().take(); } cx.notify(); } fn reset_highlighter(&mut self, cx: &mut Context) { - match &mut self.mode { - InputMode::CodeEditor { parse_task, .. } => { - parse_task.borrow_mut().take(); - } - _ => {} + if let InputMode::CodeEditor { parse_task, .. } = &mut self.mode { + parse_task.borrow_mut().take(); } cx.notify(); } @@ -713,10 +673,6 @@ impl InputState { self.selected_range.clear(); } - if self.mode.is_code_editor() { - self._pending_update = true; - } - // Move scroll to top self.scroll_handle.set_offset(point(px(0.), px(0.))); @@ -902,9 +858,6 @@ impl InputState { pub fn default_value(mut self, value: impl Into) -> Self { let text: SharedString = value.into(); self.text = Rope::from(text.as_str()); - // Note: We can't call display_map.set_text here because it needs cx. - // The text will be set during prepare_if_need in element.rs - self._pending_update = true; self } @@ -1146,13 +1099,11 @@ impl InputState { offset += 1; } - 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 indent string of next line. @@ -1188,9 +1139,9 @@ impl InputState { } if next_indent.len() > current_indent.len() { - return next_indent; + next_indent } else { - return current_indent; + current_indent } } @@ -1361,10 +1312,10 @@ impl InputState { ) { // If there have IME marked range and is empty (Means pressed Esc to abort IME typing) // Clear the marked range. - if let Some(ime_marked_range) = &self.ime_marked_range { - if ime_marked_range.len() == 0 { - self.ime_marked_range = None; - } + if let Some(ime_marked_range) = &self.ime_marked_range + && ime_marked_range.is_empty() + { + self.ime_marked_range = None; } self.selecting = true; @@ -1402,25 +1353,6 @@ impl InputState { self.selected_word_range = None; } - pub(super) fn on_mouse_move( - &mut self, - event: &MouseMoveEvent, - _window: &mut Window, - _cx: &mut Context, - ) { - // Check if mouse is within bounds - let within_bounds = self - .last_bounds - .as_ref() - .map(|bounds| bounds.contains(&event.position)) - .unwrap_or(false); - - if !within_bounds { - // Clear hover when mouse leaves the input - return; - } - } - pub(super) fn on_scroll_wheel( &mut self, event: &ScrollWheelEvent, @@ -2041,22 +1973,6 @@ impl InputState { self.replace_text_in_range(range_utf16, new_text, window, cx); self.silent_replace_text = false; } - - /// Update fold candidates from tree-sitter syntax tree (full extraction). - /// Used only on initial load or language changes. - fn update_fold_candidates(&mut self) { - if !self.mode.is_folding() { - return; - } - } - - /// Incrementally update fold candidates after a text edit. - /// Only traverses the edited region of the syntax tree instead of the full tree. - fn update_fold_candidates_incremental(&mut self, _edit_range: &Range, _new_text: &str) { - if !self.mode.is_folding() { - return; - } - } } impl EntityInputHandler for InputState { @@ -2105,7 +2021,7 @@ impl EntityInputHandler for InputState { &mut self, range_utf16: Option>, new_text: &str, - window: &mut Window, + _window: &mut Window, cx: &mut Context, ) { if self.disabled { @@ -2147,7 +2063,7 @@ impl EntityInputHandler for InputState { } } - self.push_history(&old_text, &range, &new_text); + self.push_history(&old_text, &range, new_text); self.history.end_grouping(); // Adjust folds before updating wrap map: remove overlapping folds and shift others @@ -2156,7 +2072,6 @@ impl EntityInputHandler for InputState { self.display_map .on_text_changed(&self.text, &range, &Rope::from(new_text), cx); - self.update_fold_candidates_incremental(&range, new_text); self.selected_range = (new_offset..new_offset).into(); self.ime_marked_range.take(); self.update_preferred_column(); @@ -2206,8 +2121,6 @@ impl EntityInputHandler for InputState { self.display_map .on_text_changed(&self.text, &range, &Rope::from(new_text), cx); - self.update_fold_candidates_incremental(&range, new_text); - if new_text.is_empty() { // Cancel selection, when cancel IME input. self.selected_range = (range.start..range.start).into(); @@ -2253,24 +2166,24 @@ impl EntityInputHandler for InputState { let index_offset = last_layout.visible_line_byte_offsets[vi]; - if start_origin.is_none() { - if let Some(p) = line.position_for_index( + if start_origin.is_none() + && let Some(p) = line.position_for_index( range.start.saturating_sub(index_offset), last_layout, false, - ) { - start_origin = Some(p + point(px(0.), y_offset)); - } + ) + { + start_origin = Some(p + point(px(0.), y_offset)); } - if end_origin.is_none() { - if let Some(p) = line.position_for_index( + if end_origin.is_none() + && let Some(p) = line.position_for_index( range.end.saturating_sub(index_offset), last_layout, false, - ) { - end_origin = Some(p + point(px(0.), y_offset)); - } + ) + { + end_origin = Some(p + point(px(0.), y_offset)); } y_offset += line.size(line_height).height; @@ -2316,11 +2229,6 @@ impl Focusable for InputState { impl Render for InputState { fn render(&mut self, _window: &mut Window, cx: &mut Context) -> impl IntoElement { - if self._pending_update { - self.update_fold_candidates(); - self._pending_update = false; - } - div() .id("input-state") .flex_1() diff --git a/crates/ui/src/list/list.rs b/crates/ui/src/list/list.rs index 73b343f..5a14721 100644 --- a/crates/ui/src/list/list.rs +++ b/crates/ui/src/list/list.rs @@ -288,7 +288,7 @@ where }); }); } - InputEvent::PressEnter { secondary, shift } => self.on_action_confirm( + InputEvent::PressEnter { secondary, .. } => self.on_action_confirm( &Confirm { secondary: *secondary, },