use crate::{ display_map::{ BlockContext, BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint, TransformBlock, }, editor_settings::ShowScrollbar, git::{diff_hunk_to_display, DisplayDiffHunk}, hover_popover::{ self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT, }, items::BufferSearchHighlights, link_go_to_definition::{ go_to_fetched_definition, go_to_fetched_type_definition, show_link_definition, update_go_to_definition_link, update_inlay_link_and_hover_points, GoToDefinitionTrigger, LinkGoToDefinitionState, }, mouse_context_menu, scroll::scroll_amount::ScrollAmount, CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, HalfPageDown, HalfPageUp, HoveredCursor, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, SelectPhase, Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN,};use anyhow::Result;use collections::{BTreeMap, HashMap};use git::diff::DiffHunkStatus;use gpui::{ div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla, InteractiveBounds, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, View, ViewContext, WindowContext,};use itertools::Itertools;use language::language_settings::ShowWhitespaceSetting;use multi_buffer::Anchor;use project::{ project_settings::{GitGutterSetting, ProjectSettings}, ProjectPath,};use settings::Settings;use smallvec::SmallVec;use std::{ any::TypeId, borrow::Cow, cmp::{self, Ordering}, fmt::Write, iter, ops::Range, sync::Arc,};use sum_tree::Bias;use theme::{ActiveTheme, PlayerColor};use ui::prelude::*;use ui::{h_flex, ButtonLike, ButtonStyle, IconButton, Tooltip};use util::ResultExt;use workspace::item::Item; struct SelectionLayout { head: DisplayPoint, cursor_shape: CursorShape, is_newest: bool, is_local: bool, range: Range<DisplayPoint>, active_rows: Range<u32>, user_name: Option<SharedString>,} impl SelectionLayout { fn new<T: ToPoint + ToDisplayPoint + Clone>( selection: Selection<T>, line_mode: bool, cursor_shape: CursorShape, map: &DisplaySnapshot, is_newest: bool, is_local: bool, user_name: Option<SharedString>, ) -> Self { let point_selection = selection.map(|p| p.to_point(&map.buffer_snapshot)); let display_selection = point_selection.map(|p| p.to_display_point(map)); let mut range = display_selection.range(); let mut head = display_selection.head(); let mut active_rows = map.prev_line_boundary(point_selection.start).1.row() ..map.next_line_boundary(point_selection.end).1.row(); // vim visual line mode if line_mode { let point_range = map.expand_to_line(point_selection.range()); range = point_range.start.to_display_point(map)..point_range.end.to_display_point(map); } // any vim visual mode (including line mode) if cursor_shape == CursorShape::Block && !range.is_empty() && !selection.reversed { if head.column() > 0 { head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left) } else if head.row() > 0 && head != map.max_point() { head = map.clip_point( DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)), Bias::Left, ); // updating range.end is a no-op unless you're cursor is // on the newline containing a multi-buffer divider // in which case the clip_point may have moved the head up // an additional row. range.end = DisplayPoint::new(head.row() + 1, 0); active_rows.end = head.row(); } } Self { head, cursor_shape, is_newest, is_local, range, active_rows, user_name, } }} pub struct EditorElement { editor: View<Editor>, style: EditorStyle,} impl EditorElement { pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self { Self { editor: editor.clone(), style, } } fn register_actions(&self, cx: &mut WindowContext) { let view = &self.editor; view.update(cx, |editor, cx| { for action in editor.editor_actions.iter() { (action)(cx) } }); crate::rust_analyzer_ext::apply_related_actions(view, cx); register_action(view, cx, Editor::move_left); register_action(view, cx, Editor::move_right); register_action(view, cx, Editor::move_down); register_action(view, cx, Editor::move_up); register_action(view, cx, Editor::cancel); register_action(view, cx, Editor::newline); register_action(view, cx, Editor::newline_above); register_action(view, cx, Editor::newline_below); register_action(view, cx, Editor::backspace); register_action(view, cx, Editor::delete); register_action(view, cx, Editor::tab); register_action(view, cx, Editor::tab_prev); register_action(view, cx, Editor::indent); register_action(view, cx, Editor::outdent); register_action(view, cx, Editor::delete_line); register_action(view, cx, Editor::join_lines); register_action(view, cx, Editor::sort_lines_case_sensitive); register_action(view, cx, Editor::sort_lines_case_insensitive); register_action(view, cx, Editor::reverse_lines); register_action(view, cx, Editor::shuffle_lines); register_action(view, cx, Editor::convert_to_upper_case); register_action(view, cx, Editor::convert_to_lower_case); register_action(view, cx, Editor::convert_to_title_case); register_action(view, cx, Editor::convert_to_snake_case); register_action(view, cx, Editor::convert_to_kebab_case); register_action(view, cx, Editor::convert_to_upper_camel_case); register_action(view, cx, Editor::convert_to_lower_camel_case); register_action(view, cx, Editor::delete_to_previous_word_start); register_action(view, cx, Editor::delete_to_previous_subword_start); register_action(view, cx, Editor::delete_to_next_word_end); register_action(view, cx, Editor::delete_to_next_subword_end); register_action(view, cx, Editor::delete_to_beginning_of_line); register_action(view, cx, Editor::delete_to_end_of_line); register_action(view, cx, Editor::cut_to_end_of_line); register_action(view, cx, Editor::duplicate_line); register_action(view, cx, Editor::move_line_up); register_action(view, cx, Editor::move_line_down); register_action(view, cx, Editor::transpose); register_action(view, cx, Editor::cut); register_action(view, cx, Editor::copy); register_action(view, cx, Editor::paste); register_action(view, cx, Editor::undo); register_action(view, cx, Editor::redo); register_action(view, cx, Editor::move_page_up); register_action(view, cx, Editor::move_page_down); register_action(view, cx, Editor::next_screen); register_action(view, cx, Editor::scroll_cursor_top); register_action(view, cx, Editor::scroll_cursor_center); register_action(view, cx, Editor::scroll_cursor_bottom); register_action(view, cx, |editor, _: &LineDown, cx| { editor.scroll_screen(&ScrollAmount::Line(1.), cx) }); register_action(view, cx, |editor, _: &LineUp, cx| { editor.scroll_screen(&ScrollAmount::Line(-1.), cx) }); register_action(view, cx, |editor, _: &HalfPageDown, cx| { editor.scroll_screen(&ScrollAmount::Page(0.5), cx) }); register_action(view, cx, |editor, _: &HalfPageUp, cx| { editor.scroll_screen(&ScrollAmount::Page(-0.5), cx) }); register_action(view, cx, |editor, _: &PageDown, cx| { editor.scroll_screen(&ScrollAmount::Page(1.), cx) }); register_action(view, cx, |editor, _: &PageUp, cx| { editor.scroll_screen(&ScrollAmount::Page(-1.), cx) }); register_action(view, cx, Editor::move_to_previous_word_start); register_action(view, cx, Editor::move_to_previous_subword_start); register_action(view, cx, Editor::move_to_next_word_end); register_action(view, cx, Editor::move_to_next_subword_end); register_action(view, cx, Editor::move_to_beginning_of_line); register_action(view, cx, Editor::move_to_end_of_line); register_action(view, cx, Editor::move_to_start_of_paragraph); register_action(view, cx, Editor::move_to_end_of_paragraph); register_action(view, cx, Editor::move_to_beginning); register_action(view, cx, Editor::move_to_end); register_action(view, cx, Editor::select_up); register_action(view, cx, Editor::select_down); register_action(view, cx, Editor::select_left); register_action(view, cx, Editor::select_right); register_action(view, cx, Editor::select_to_previous_word_start); register_action(view, cx, Editor::select_to_previous_subword_start); register_action(view, cx, Editor::select_to_next_word_end); register_action(view, cx, Editor::select_to_next_subword_end); register_action(view, cx, Editor::select_to_beginning_of_line); register_action(view, cx, Editor::select_to_end_of_line); register_action(view, cx, Editor::select_to_start_of_paragraph); register_action(view, cx, Editor::select_to_end_of_paragraph); register_action(view, cx, Editor::select_to_beginning); register_action(view, cx, Editor::select_to_end); register_action(view, cx, Editor::select_all); register_action(view, cx, |editor, action, cx| { editor.select_all_matches(action, cx).log_err(); }); register_action(view, cx, Editor::select_line); register_action(view, cx, Editor::split_selection_into_lines); register_action(view, cx, Editor::add_selection_above); register_action(view, cx, Editor::add_selection_below); register_action(view, cx, |editor, action, cx| { editor.select_next(action, cx).log_err(); }); register_action(view, cx, |editor, action, cx| { editor.select_previous(action, cx).log_err(); }); register_action(view, cx, Editor::toggle_comments); register_action(view, cx, Editor::select_larger_syntax_node); register_action(view, cx, Editor::select_smaller_syntax_node); register_action(view, cx, Editor::move_to_enclosing_bracket); register_action(view, cx, Editor::undo_selection); register_action(view, cx, Editor::redo_selection); register_action(view, cx, Editor::go_to_diagnostic); register_action(view, cx, Editor::go_to_prev_diagnostic); register_action(view, cx, Editor::go_to_hunk); register_action(view, cx, Editor::go_to_prev_hunk); register_action(view, cx, Editor::go_to_definition); register_action(view, cx, Editor::go_to_definition_split); register_action(view, cx, Editor::go_to_type_definition); register_action(view, cx, Editor::go_to_type_definition_split); register_action(view, cx, Editor::fold); register_action(view, cx, Editor::fold_at); register_action(view, cx, Editor::unfold_lines); register_action(view, cx, Editor::unfold_at); register_action(view, cx, Editor::fold_selected_ranges); register_action(view, cx, Editor::show_completions); register_action(view, cx, Editor::toggle_code_actions); register_action(view, cx, Editor::open_excerpts); register_action(view, cx, Editor::toggle_soft_wrap); register_action(view, cx, Editor::toggle_inlay_hints); register_action(view, cx, hover_popover::hover); register_action(view, cx, Editor::reveal_in_finder); register_action(view, cx, Editor::copy_path); register_action(view, cx, Editor::copy_relative_path); register_action(view, cx, Editor::copy_highlight_json); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.format(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, Editor::restart_language_server); register_action(view, cx, Editor::show_character_palette); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.confirm_completion(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.confirm_code_action(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.rename(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.confirm_rename(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.find_all_references(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, Editor::next_copilot_suggestion); register_action(view, cx, Editor::previous_copilot_suggestion); register_action(view, cx, Editor::copilot_suggest); register_action(view, cx, Editor::context_menu_first); register_action(view, cx, Editor::context_menu_prev); register_action(view, cx, Editor::context_menu_next); register_action(view, cx, Editor::context_menu_last); register_action(view, cx, Editor::display_cursor_names); } fn register_key_listeners(&self, cx: &mut ElementContext) { cx.on_key_event({ let editor = self.editor.clone(); move |event: &ModifiersChangedEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } if editor.update(cx, |editor, cx| Self::modifiers_changed(editor, event, cx)) { cx.stop_propagation(); } } }); } pub(crate) fn modifiers_changed( editor: &mut Editor, event: &ModifiersChangedEvent, cx: &mut ViewContext<Editor>, ) -> bool { let pending_selection = editor.has_pending_selection(); if let Some(point) = &editor.link_go_to_definition_state.last_trigger_point { if event.command && !pending_selection { let point = point.clone(); let snapshot = editor.snapshot(cx); let kind = point.definition_kind(event.shift); show_link_definition(kind, editor, point, snapshot, cx); return false; } } { if editor.link_go_to_definition_state.symbol_range.is_some() || !editor.link_go_to_definition_state.definitions.is_empty() { editor.link_go_to_definition_state.symbol_range.take(); editor.link_go_to_definition_state.definitions.clear(); cx.notify(); } editor.link_go_to_definition_state.task = None; editor.clear_highlights::<LinkGoToDefinitionState>(cx); } false } fn mouse_left_down( editor: &mut Editor, event: &MouseDownEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, gutter_bounds: Bounds<Pixels>, stacking_order: &StackingOrder, cx: &mut ViewContext<Editor>, ) { let mut click_count = event.click_count; let modifiers = event.modifiers; if cx.default_prevented() { return; } else if gutter_bounds.contains(&event.position) { click_count = 3; // Simulate triple-click when clicking the gutter to select lines } else if !text_bounds.contains(&event.position) { return; } if !cx.was_top_layer(&event.position, stacking_order) { return; } let point_for_position = position_map.point_for_position(text_bounds, event.position); let position = point_for_position.previous_valid; if modifiers.shift && modifiers.alt { editor.select( SelectPhase::BeginColumnar { position, goal_column: point_for_position.exact_unclipped.column(), }, cx, ); } else if modifiers.shift && !modifiers.control && !modifiers.alt && !modifiers.command { editor.select( SelectPhase::Extend { position, click_count, }, cx, ); } else { editor.select( SelectPhase::Begin { position, add: modifiers.alt, click_count, }, cx, ); } cx.stop_propagation(); } fn mouse_right_down( editor: &mut Editor, event: &MouseDownEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, cx: &mut ViewContext<Editor>, ) { if !text_bounds.contains(&event.position) { return; } let point_for_position = position_map.point_for_position(text_bounds, event.position); mouse_context_menu::deploy_context_menu( editor, event.position, point_for_position.previous_valid, cx, ); cx.stop_propagation(); } fn mouse_up( editor: &mut Editor, event: &MouseUpEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, interactive_bounds: &InteractiveBounds, stacking_order: &StackingOrder, cx: &mut ViewContext<Editor>, ) { let end_selection = editor.has_pending_selection(); let pending_nonempty_selections = editor.has_pending_nonempty_selection(); if end_selection { editor.select(SelectPhase::End, cx); } if interactive_bounds.visibly_contains(&event.position, cx) && !pending_nonempty_selections && event.modifiers.command && text_bounds.contains(&event.position) && cx.was_top_layer(&event.position, stacking_order) { let point = position_map.point_for_position(text_bounds, event.position); let could_be_inlay = point.as_valid().is_none(); let split = event.modifiers.alt; if event.modifiers.shift || could_be_inlay { go_to_fetched_type_definition(editor, point, split, cx); } else { go_to_fetched_definition(editor, point, split, cx); } cx.stop_propagation(); } else if end_selection { cx.stop_propagation(); } } fn mouse_dragged( editor: &mut Editor, event: &MouseMoveEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, _gutter_bounds: Bounds<Pixels>,Lines 1–500 of 3988. Load more
use crate::{ display_map::{ BlockContext, BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint, TransformBlock, }, editor_settings::ShowScrollbar, git::{diff_hunk_to_display, DisplayDiffHunk}, hover_popover::{ self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT, }, items::BufferSearchHighlights, link_go_to_definition::{ go_to_fetched_definition, go_to_fetched_type_definition, show_link_definition, update_go_to_definition_link, update_inlay_link_and_hover_points, GoToDefinitionTrigger, LinkGoToDefinitionState, }, mouse_context_menu, scroll::scroll_amount::ScrollAmount, CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, HalfPageDown, HalfPageUp, HoveredCursor, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, SelectPhase, Selection, SoftWrap, ToPoint, CURSORS_VISIBLE_FOR, MAX_LINE_LEN, }; use anyhow::Result; use collections::{BTreeMap, HashMap}; use git::diff::DiffHunkStatus; use gpui::{ div, fill, outline, overlay, point, px, quad, relative, size, transparent_black, Action, AnchorCorner, AnyElement, AvailableSpace, Bounds, ContentMask, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Hsla, InteractiveBounds, InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size, StackingOrder, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle, View, ViewContext, WindowContext, }; use itertools::Itertools; use language::language_settings::ShowWhitespaceSetting; use multi_buffer::Anchor; use project::{ project_settings::{GitGutterSetting, ProjectSettings}, ProjectPath, }; use settings::Settings; use smallvec::SmallVec; use std::{ any::TypeId, borrow::Cow, cmp::{self, Ordering}, fmt::Write, iter, ops::Range, sync::Arc, }; use sum_tree::Bias; use theme::{ActiveTheme, PlayerColor}; use ui::prelude::*; use ui::{h_flex, ButtonLike, ButtonStyle, IconButton, Tooltip}; use util::ResultExt; use workspace::item::Item; struct SelectionLayout { head: DisplayPoint, cursor_shape: CursorShape, is_newest: bool, is_local: bool, range: Range<DisplayPoint>, active_rows: Range<u32>, user_name: Option<SharedString>, } impl SelectionLayout { fn new<T: ToPoint + ToDisplayPoint + Clone>( selection: Selection<T>, line_mode: bool, cursor_shape: CursorShape, map: &DisplaySnapshot, is_newest: bool, is_local: bool, user_name: Option<SharedString>, ) -> Self { let point_selection = selection.map(|p| p.to_point(&map.buffer_snapshot)); let display_selection = point_selection.map(|p| p.to_display_point(map)); let mut range = display_selection.range(); let mut head = display_selection.head(); let mut active_rows = map.prev_line_boundary(point_selection.start).1.row() ..map.next_line_boundary(point_selection.end).1.row(); // vim visual line mode if line_mode { let point_range = map.expand_to_line(point_selection.range()); range = point_range.start.to_display_point(map)..point_range.end.to_display_point(map); } // any vim visual mode (including line mode) if cursor_shape == CursorShape::Block && !range.is_empty() && !selection.reversed { if head.column() > 0 { head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left) } else if head.row() > 0 && head != map.max_point() { head = map.clip_point( DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)), Bias::Left, ); // updating range.end is a no-op unless you're cursor is // on the newline containing a multi-buffer divider // in which case the clip_point may have moved the head up // an additional row. range.end = DisplayPoint::new(head.row() + 1, 0); active_rows.end = head.row(); } } Self { head, cursor_shape, is_newest, is_local, range, active_rows, user_name, } } } pub struct EditorElement { editor: View<Editor>, style: EditorStyle, } impl EditorElement { pub fn new(editor: &View<Editor>, style: EditorStyle) -> Self { Self { editor: editor.clone(), style, } } fn register_actions(&self, cx: &mut WindowContext) { let view = &self.editor; view.update(cx, |editor, cx| { for action in editor.editor_actions.iter() { (action)(cx) } }); crate::rust_analyzer_ext::apply_related_actions(view, cx); register_action(view, cx, Editor::move_left); register_action(view, cx, Editor::move_right); register_action(view, cx, Editor::move_down); register_action(view, cx, Editor::move_up); register_action(view, cx, Editor::cancel); register_action(view, cx, Editor::newline); register_action(view, cx, Editor::newline_above); register_action(view, cx, Editor::newline_below); register_action(view, cx, Editor::backspace); register_action(view, cx, Editor::delete); register_action(view, cx, Editor::tab); register_action(view, cx, Editor::tab_prev); register_action(view, cx, Editor::indent); register_action(view, cx, Editor::outdent); register_action(view, cx, Editor::delete_line); register_action(view, cx, Editor::join_lines); register_action(view, cx, Editor::sort_lines_case_sensitive); register_action(view, cx, Editor::sort_lines_case_insensitive); register_action(view, cx, Editor::reverse_lines); register_action(view, cx, Editor::shuffle_lines); register_action(view, cx, Editor::convert_to_upper_case); register_action(view, cx, Editor::convert_to_lower_case); register_action(view, cx, Editor::convert_to_title_case); register_action(view, cx, Editor::convert_to_snake_case); register_action(view, cx, Editor::convert_to_kebab_case); register_action(view, cx, Editor::convert_to_upper_camel_case); register_action(view, cx, Editor::convert_to_lower_camel_case); register_action(view, cx, Editor::delete_to_previous_word_start); register_action(view, cx, Editor::delete_to_previous_subword_start); register_action(view, cx, Editor::delete_to_next_word_end); register_action(view, cx, Editor::delete_to_next_subword_end); register_action(view, cx, Editor::delete_to_beginning_of_line); register_action(view, cx, Editor::delete_to_end_of_line); register_action(view, cx, Editor::cut_to_end_of_line); register_action(view, cx, Editor::duplicate_line); register_action(view, cx, Editor::move_line_up); register_action(view, cx, Editor::move_line_down); register_action(view, cx, Editor::transpose); register_action(view, cx, Editor::cut); register_action(view, cx, Editor::copy); register_action(view, cx, Editor::paste); register_action(view, cx, Editor::undo); register_action(view, cx, Editor::redo); register_action(view, cx, Editor::move_page_up); register_action(view, cx, Editor::move_page_down); register_action(view, cx, Editor::next_screen); register_action(view, cx, Editor::scroll_cursor_top); register_action(view, cx, Editor::scroll_cursor_center); register_action(view, cx, Editor::scroll_cursor_bottom); register_action(view, cx, |editor, _: &LineDown, cx| { editor.scroll_screen(&ScrollAmount::Line(1.), cx) }); register_action(view, cx, |editor, _: &LineUp, cx| { editor.scroll_screen(&ScrollAmount::Line(-1.), cx) }); register_action(view, cx, |editor, _: &HalfPageDown, cx| { editor.scroll_screen(&ScrollAmount::Page(0.5), cx) }); register_action(view, cx, |editor, _: &HalfPageUp, cx| { editor.scroll_screen(&ScrollAmount::Page(-0.5), cx) }); register_action(view, cx, |editor, _: &PageDown, cx| { editor.scroll_screen(&ScrollAmount::Page(1.), cx) }); register_action(view, cx, |editor, _: &PageUp, cx| { editor.scroll_screen(&ScrollAmount::Page(-1.), cx) }); register_action(view, cx, Editor::move_to_previous_word_start); register_action(view, cx, Editor::move_to_previous_subword_start); register_action(view, cx, Editor::move_to_next_word_end); register_action(view, cx, Editor::move_to_next_subword_end); register_action(view, cx, Editor::move_to_beginning_of_line); register_action(view, cx, Editor::move_to_end_of_line); register_action(view, cx, Editor::move_to_start_of_paragraph); register_action(view, cx, Editor::move_to_end_of_paragraph); register_action(view, cx, Editor::move_to_beginning); register_action(view, cx, Editor::move_to_end); register_action(view, cx, Editor::select_up); register_action(view, cx, Editor::select_down); register_action(view, cx, Editor::select_left); register_action(view, cx, Editor::select_right); register_action(view, cx, Editor::select_to_previous_word_start); register_action(view, cx, Editor::select_to_previous_subword_start); register_action(view, cx, Editor::select_to_next_word_end); register_action(view, cx, Editor::select_to_next_subword_end); register_action(view, cx, Editor::select_to_beginning_of_line); register_action(view, cx, Editor::select_to_end_of_line); register_action(view, cx, Editor::select_to_start_of_paragraph); register_action(view, cx, Editor::select_to_end_of_paragraph); register_action(view, cx, Editor::select_to_beginning); register_action(view, cx, Editor::select_to_end); register_action(view, cx, Editor::select_all); register_action(view, cx, |editor, action, cx| { editor.select_all_matches(action, cx).log_err(); }); register_action(view, cx, Editor::select_line); register_action(view, cx, Editor::split_selection_into_lines); register_action(view, cx, Editor::add_selection_above); register_action(view, cx, Editor::add_selection_below); register_action(view, cx, |editor, action, cx| { editor.select_next(action, cx).log_err(); }); register_action(view, cx, |editor, action, cx| { editor.select_previous(action, cx).log_err(); }); register_action(view, cx, Editor::toggle_comments); register_action(view, cx, Editor::select_larger_syntax_node); register_action(view, cx, Editor::select_smaller_syntax_node); register_action(view, cx, Editor::move_to_enclosing_bracket); register_action(view, cx, Editor::undo_selection); register_action(view, cx, Editor::redo_selection); register_action(view, cx, Editor::go_to_diagnostic); register_action(view, cx, Editor::go_to_prev_diagnostic); register_action(view, cx, Editor::go_to_hunk); register_action(view, cx, Editor::go_to_prev_hunk); register_action(view, cx, Editor::go_to_definition); register_action(view, cx, Editor::go_to_definition_split); register_action(view, cx, Editor::go_to_type_definition); register_action(view, cx, Editor::go_to_type_definition_split); register_action(view, cx, Editor::fold); register_action(view, cx, Editor::fold_at); register_action(view, cx, Editor::unfold_lines); register_action(view, cx, Editor::unfold_at); register_action(view, cx, Editor::fold_selected_ranges); register_action(view, cx, Editor::show_completions); register_action(view, cx, Editor::toggle_code_actions); register_action(view, cx, Editor::open_excerpts); register_action(view, cx, Editor::toggle_soft_wrap); register_action(view, cx, Editor::toggle_inlay_hints); register_action(view, cx, hover_popover::hover); register_action(view, cx, Editor::reveal_in_finder); register_action(view, cx, Editor::copy_path); register_action(view, cx, Editor::copy_relative_path); register_action(view, cx, Editor::copy_highlight_json); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.format(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, Editor::restart_language_server); register_action(view, cx, Editor::show_character_palette); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.confirm_completion(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.confirm_code_action(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.rename(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.confirm_rename(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, |editor, action, cx| { if let Some(task) = editor.find_all_references(action, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(view, cx, Editor::next_copilot_suggestion); register_action(view, cx, Editor::previous_copilot_suggestion); register_action(view, cx, Editor::copilot_suggest); register_action(view, cx, Editor::context_menu_first); register_action(view, cx, Editor::context_menu_prev); register_action(view, cx, Editor::context_menu_next); register_action(view, cx, Editor::context_menu_last); register_action(view, cx, Editor::display_cursor_names); } fn register_key_listeners(&self, cx: &mut ElementContext) { cx.on_key_event({ let editor = self.editor.clone(); move |event: &ModifiersChangedEvent, phase, cx| { if phase != DispatchPhase::Bubble { return; } if editor.update(cx, |editor, cx| Self::modifiers_changed(editor, event, cx)) { cx.stop_propagation(); } } }); } pub(crate) fn modifiers_changed( editor: &mut Editor, event: &ModifiersChangedEvent, cx: &mut ViewContext<Editor>, ) -> bool { let pending_selection = editor.has_pending_selection(); if let Some(point) = &editor.link_go_to_definition_state.last_trigger_point { if event.command && !pending_selection { let point = point.clone(); let snapshot = editor.snapshot(cx); let kind = point.definition_kind(event.shift); show_link_definition(kind, editor, point, snapshot, cx); return false; } } { if editor.link_go_to_definition_state.symbol_range.is_some() || !editor.link_go_to_definition_state.definitions.is_empty() { editor.link_go_to_definition_state.symbol_range.take(); editor.link_go_to_definition_state.definitions.clear(); cx.notify(); } editor.link_go_to_definition_state.task = None; editor.clear_highlights::<LinkGoToDefinitionState>(cx); } false } fn mouse_left_down( editor: &mut Editor, event: &MouseDownEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, gutter_bounds: Bounds<Pixels>, stacking_order: &StackingOrder, cx: &mut ViewContext<Editor>, ) { let mut click_count = event.click_count; let modifiers = event.modifiers; if cx.default_prevented() { return; } else if gutter_bounds.contains(&event.position) { click_count = 3; // Simulate triple-click when clicking the gutter to select lines } else if !text_bounds.contains(&event.position) { return; } if !cx.was_top_layer(&event.position, stacking_order) { return; } let point_for_position = position_map.point_for_position(text_bounds, event.position); let position = point_for_position.previous_valid; if modifiers.shift && modifiers.alt { editor.select( SelectPhase::BeginColumnar { position, goal_column: point_for_position.exact_unclipped.column(), }, cx, ); } else if modifiers.shift && !modifiers.control && !modifiers.alt && !modifiers.command { editor.select( SelectPhase::Extend { position, click_count, }, cx, ); } else { editor.select( SelectPhase::Begin { position, add: modifiers.alt, click_count, }, cx, ); } cx.stop_propagation(); } fn mouse_right_down( editor: &mut Editor, event: &MouseDownEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, cx: &mut ViewContext<Editor>, ) { if !text_bounds.contains(&event.position) { return; } let point_for_position = position_map.point_for_position(text_bounds, event.position); mouse_context_menu::deploy_context_menu( editor, event.position, point_for_position.previous_valid, cx, ); cx.stop_propagation(); } fn mouse_up( editor: &mut Editor, event: &MouseUpEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, interactive_bounds: &InteractiveBounds, stacking_order: &StackingOrder, cx: &mut ViewContext<Editor>, ) { let end_selection = editor.has_pending_selection(); let pending_nonempty_selections = editor.has_pending_nonempty_selection(); if end_selection { editor.select(SelectPhase::End, cx); } if interactive_bounds.visibly_contains(&event.position, cx) && !pending_nonempty_selections && event.modifiers.command && text_bounds.contains(&event.position) && cx.was_top_layer(&event.position, stacking_order) { let point = position_map.point_for_position(text_bounds, event.position); let could_be_inlay = point.as_valid().is_none(); let split = event.modifiers.alt; if event.modifiers.shift || could_be_inlay { go_to_fetched_type_definition(editor, point, split, cx); } else { go_to_fetched_definition(editor, point, split, cx); } cx.stop_propagation(); } else if end_selection { cx.stop_propagation(); } } fn mouse_dragged( editor: &mut Editor, event: &MouseMoveEvent, position_map: &PositionMap, text_bounds: Bounds<Pixels>, _gutter_bounds: Bounds<Pixels>,