use crate::{ code_context_menus::{CodeActionsMenu, MENU_ASIDE_MAX_WIDTH, MENU_ASIDE_MIN_WIDTH, MENU_GAP}, commit_tooltip::{blame_entry_relative_timestamp, CommitTooltip, ParsedCommitMessage}, display_map::{ Block, BlockContext, BlockStyle, DisplaySnapshot, HighlightedChunk, ToDisplayPoint, }, editor_settings::{ CurrentLineHighlight, DoubleClickInMultibuffer, MultiCursorModifier, ScrollBeyondLastLine, ScrollbarDiagnostics, ShowScrollbar, }, git::blame::GitBlame, hover_popover::{ self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT, }, inlay_hint_settings, items::BufferSearchHighlights, mouse_context_menu::{self, MenuPosition, MouseContextMenu}, scroll::{axis_pair, scroll_amount::ScrollAmount, AxisPair}, BlockId, ChunkReplacement, CursorShape, CustomBlockId, DisplayDiffHunk, DisplayPoint, DisplayRow, DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GoToHunk, GoToPreviousHunk, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, InlayHintRefreshReason, InlineCompletion, JumpData, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, COLUMNAR_SELECTION_MODIFIERS, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT,};use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind};use client::ParticipantIndex;use collections::{BTreeMap, HashMap, HashSet};use file_icons::FileIcons;use git::{blame::BlameEntry, status::FileStatus, Oid};use gpui::{ anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, pattern_slash, point, px, quad, relative, size, solid_background, svg, transparent_black, Action, AnyElement, App, AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Keystroke, Length, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement, Window,};use inline_completion::Direction;use itertools::Itertools;use language::{ language_settings::{ IndentGuideBackgroundColoring, IndentGuideColoring, IndentGuideSettings, ShowWhitespaceSetting, }, ChunkRendererContext,};use lsp::DiagnosticSeverity;use multi_buffer::{ Anchor, ExcerptId, ExcerptInfo, ExpandExcerptDirection, MultiBufferPoint, MultiBufferRow, RowInfo,};use project::project_settings::{self, GitGutterSetting, GitHunkStyleSetting, ProjectSettings};use settings::Settings;use smallvec::{smallvec, SmallVec};use std::{ any::TypeId, borrow::Cow, cmp::{self, Ordering}, fmt::{self, Write}, iter, mem, ops::{Deref, Range}, rc::Rc, sync::Arc,};use sum_tree::Bias;use text::BufferId;use theme::{ActiveTheme, Appearance, BufferLineHeight, PlayerColor};use ui::{ h_flex, prelude::*, ButtonLike, ButtonStyle, ContextMenu, IconButtonShape, KeyBinding, Tooltip, POPOVER_Y_PADDING,};use unicode_segmentation::UnicodeSegmentation;use util::{debug_panic, RangeExt, ResultExt};use workspace::{item::Item, notifications::NotifyTaskExt}; const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.;const MIN_SCROLL_THUMB_SIZE: f32 = 25.; struct SelectionLayout { head: DisplayPoint, cursor_shape: CursorShape, is_newest: bool, is_local: bool, range: Range<DisplayPoint>, active_rows: Range<DisplayRow>, 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 || cursor_shape == CursorShape::Hollow) && !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 > 0 && head != map.max_point() { head = map.clip_point( DisplayPoint::new( head.row().previous_row(), map.line_len(head.row().previous_row()), ), 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().next_row(), 0); active_rows.end = head.row(); } } Self { head, cursor_shape, is_newest, is_local, range, active_rows, user_name, } }} pub struct EditorElement { editor: Entity<Editor>, style: EditorStyle,} type DisplayRowDelta = u32; impl EditorElement { pub(crate) const SCROLLBAR_WIDTH: Pixels = px(15.); pub fn new(editor: &Entity<Editor>, style: EditorStyle) -> Self { Self { editor: editor.clone(), style, } } fn register_actions(&self, window: &mut Window, cx: &mut App) { let editor = &self.editor; editor.update(cx, |editor, cx| { for action in editor.editor_actions.borrow().values() { (action)(window, cx) } }); crate::rust_analyzer_ext::apply_related_actions(editor, window, cx); crate::clangd_ext::apply_related_actions(editor, window, cx); register_action(editor, window, Editor::open_context_menu); register_action(editor, window, Editor::move_left); register_action(editor, window, Editor::move_right); register_action(editor, window, Editor::move_down); register_action(editor, window, Editor::move_down_by_lines); register_action(editor, window, Editor::select_down_by_lines); register_action(editor, window, Editor::move_up); register_action(editor, window, Editor::move_up_by_lines); register_action(editor, window, Editor::select_up_by_lines); register_action(editor, window, Editor::select_page_down); register_action(editor, window, Editor::select_page_up); register_action(editor, window, Editor::cancel); register_action(editor, window, Editor::newline); register_action(editor, window, Editor::newline_above); register_action(editor, window, Editor::newline_below); register_action(editor, window, Editor::backspace); register_action(editor, window, Editor::delete); register_action(editor, window, Editor::tab); register_action(editor, window, Editor::backtab); register_action(editor, window, Editor::indent); register_action(editor, window, Editor::outdent); register_action(editor, window, Editor::autoindent); register_action(editor, window, Editor::delete_line); register_action(editor, window, Editor::join_lines); register_action(editor, window, Editor::sort_lines_case_sensitive); register_action(editor, window, Editor::sort_lines_case_insensitive); register_action(editor, window, Editor::reverse_lines); register_action(editor, window, Editor::shuffle_lines); register_action(editor, window, Editor::convert_to_upper_case); register_action(editor, window, Editor::convert_to_lower_case); register_action(editor, window, Editor::convert_to_title_case); register_action(editor, window, Editor::convert_to_snake_case); register_action(editor, window, Editor::convert_to_kebab_case); register_action(editor, window, Editor::convert_to_upper_camel_case); register_action(editor, window, Editor::convert_to_lower_camel_case); register_action(editor, window, Editor::convert_to_opposite_case); register_action(editor, window, Editor::delete_to_previous_word_start); register_action(editor, window, Editor::delete_to_previous_subword_start); register_action(editor, window, Editor::delete_to_next_word_end); register_action(editor, window, Editor::delete_to_next_subword_end); register_action(editor, window, Editor::delete_to_beginning_of_line); register_action(editor, window, Editor::delete_to_end_of_line); register_action(editor, window, Editor::cut_to_end_of_line); register_action(editor, window, Editor::duplicate_line_up); register_action(editor, window, Editor::duplicate_line_down); register_action(editor, window, Editor::duplicate_selection); register_action(editor, window, Editor::move_line_up); register_action(editor, window, Editor::move_line_down); register_action(editor, window, Editor::transpose); register_action(editor, window, Editor::rewrap); register_action(editor, window, Editor::cut); register_action(editor, window, Editor::kill_ring_cut); register_action(editor, window, Editor::kill_ring_yank); register_action(editor, window, Editor::copy); register_action(editor, window, Editor::paste); register_action(editor, window, Editor::undo); register_action(editor, window, Editor::redo); register_action(editor, window, Editor::move_page_up); register_action(editor, window, Editor::move_page_down); register_action(editor, window, Editor::next_screen); register_action(editor, window, Editor::scroll_cursor_top); register_action(editor, window, Editor::scroll_cursor_center); register_action(editor, window, Editor::scroll_cursor_bottom); register_action(editor, window, Editor::scroll_cursor_center_top_bottom); register_action(editor, window, |editor, _: &LineDown, window, cx| { editor.scroll_screen(&ScrollAmount::Line(1.), window, cx) }); register_action(editor, window, |editor, _: &LineUp, window, cx| { editor.scroll_screen(&ScrollAmount::Line(-1.), window, cx) }); register_action(editor, window, |editor, _: &HalfPageDown, window, cx| { editor.scroll_screen(&ScrollAmount::Page(0.5), window, cx) }); register_action( editor, window, |editor, HandleInput(text): &HandleInput, window, cx| { if text.is_empty() { return; } editor.handle_input(text, window, cx); }, ); register_action(editor, window, |editor, _: &HalfPageUp, window, cx| { editor.scroll_screen(&ScrollAmount::Page(-0.5), window, cx) }); register_action(editor, window, |editor, _: &PageDown, window, cx| { editor.scroll_screen(&ScrollAmount::Page(1.), window, cx) }); register_action(editor, window, |editor, _: &PageUp, window, cx| { editor.scroll_screen(&ScrollAmount::Page(-1.), window, cx) }); register_action(editor, window, Editor::move_to_previous_word_start); register_action(editor, window, Editor::move_to_previous_subword_start); register_action(editor, window, Editor::move_to_next_word_end); register_action(editor, window, Editor::move_to_next_subword_end); register_action(editor, window, Editor::move_to_beginning_of_line); register_action(editor, window, Editor::move_to_end_of_line); register_action(editor, window, Editor::move_to_start_of_paragraph); register_action(editor, window, Editor::move_to_end_of_paragraph); register_action(editor, window, Editor::move_to_beginning); register_action(editor, window, Editor::move_to_end); register_action(editor, window, Editor::move_to_start_of_excerpt); register_action(editor, window, Editor::move_to_end_of_excerpt); register_action(editor, window, Editor::select_up); register_action(editor, window, Editor::select_down); register_action(editor, window, Editor::select_left); register_action(editor, window, Editor::select_right); register_action(editor, window, Editor::select_to_previous_word_start); register_action(editor, window, Editor::select_to_previous_subword_start); register_action(editor, window, Editor::select_to_next_word_end); register_action(editor, window, Editor::select_to_next_subword_end); register_action(editor, window, Editor::select_to_beginning_of_line); register_action(editor, window, Editor::select_to_end_of_line); register_action(editor, window, Editor::select_to_start_of_paragraph); register_action(editor, window, Editor::select_to_end_of_paragraph); register_action(editor, window, Editor::select_to_start_of_excerpt); register_action(editor, window, Editor::select_to_end_of_excerpt); register_action(editor, window, Editor::select_to_beginning); register_action(editor, window, Editor::select_to_end); register_action(editor, window, Editor::select_all); register_action(editor, window, |editor, action, window, cx| { editor.select_all_matches(action, window, cx).log_err(); }); register_action(editor, window, Editor::select_line); register_action(editor, window, Editor::split_selection_into_lines); register_action(editor, window, Editor::add_selection_above); register_action(editor, window, Editor::add_selection_below); register_action(editor, window, |editor, action, window, cx| { editor.select_next(action, window, cx).log_err(); }); register_action(editor, window, |editor, action, window, cx| { editor.select_previous(action, window, cx).log_err(); }); register_action(editor, window, Editor::toggle_comments); register_action(editor, window, Editor::select_larger_syntax_node); register_action(editor, window, Editor::select_smaller_syntax_node); register_action(editor, window, Editor::select_enclosing_symbol); register_action(editor, window, Editor::move_to_enclosing_bracket); register_action(editor, window, Editor::undo_selection); register_action(editor, window, Editor::redo_selection); if !editor.read(cx).is_singleton(cx) { register_action(editor, window, Editor::expand_excerpts); register_action(editor, window, Editor::expand_excerpts_up); register_action(editor, window, Editor::expand_excerpts_down); } register_action(editor, window, Editor::go_to_diagnostic); register_action(editor, window, Editor::go_to_prev_diagnostic); register_action(editor, window, Editor::go_to_next_hunk); register_action(editor, window, Editor::go_to_prev_hunk); register_action(editor, window, |editor, action, window, cx| { editor .go_to_definition(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_definition_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_declaration(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_declaration_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_implementation(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_implementation_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_type_definition(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_type_definition_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, Editor::open_url); register_action(editor, window, Editor::open_selected_filename); register_action(editor, window, Editor::fold); register_action(editor, window, Editor::fold_at_level); register_action(editor, window, Editor::fold_all); register_action(editor, window, Editor::fold_function_bodies); register_action(editor, window, Editor::fold_at); register_action(editor, window, Editor::fold_recursive); register_action(editor, window, Editor::toggle_fold); register_action(editor, window, Editor::toggle_fold_recursive); register_action(editor, window, Editor::unfold_lines); register_action(editor, window, Editor::unfold_recursive); register_action(editor, window, Editor::unfold_all); register_action(editor, window, Editor::unfold_at); register_action(editor, window, Editor::fold_selected_ranges); register_action(editor, window, Editor::set_mark); register_action(editor, window, Editor::swap_selection_ends); register_action(editor, window, Editor::show_completions); register_action(editor, window, Editor::toggle_code_actions); register_action(editor, window, Editor::open_excerpts); register_action(editor, window, Editor::open_excerpts_in_split); register_action(editor, window, Editor::open_proposed_changes_editor); register_action(editor, window, Editor::toggle_soft_wrap); register_action(editor, window, Editor::toggle_tab_bar); register_action(editor, window, Editor::toggle_line_numbers); register_action(editor, window, Editor::toggle_relative_line_numbers); register_action(editor, window, Editor::toggle_indent_guides); register_action(editor, window, Editor::toggle_inlay_hints); register_action(editor, window, Editor::toggle_edit_predictions); register_action(editor, window, Editor::toggle_inline_diagnostics); register_action(editor, window, hover_popover::hover); register_action(editor, window, Editor::reveal_in_finder); register_action(editor, window, Editor::copy_path); register_action(editor, window, Editor::copy_relative_path); register_action(editor, window, Editor::copy_file_name); register_action(editor, window, Editor::copy_file_name_without_extension); register_action(editor, window, Editor::copy_highlight_json); register_action(editor, window, Editor::copy_permalink_to_line); register_action(editor, window, Editor::open_permalink_to_line); register_action(editor, window, Editor::copy_file_location); register_action(editor, window, Editor::toggle_git_blame); register_action(editor, window, Editor::toggle_git_blame_inline); register_action(editor, window, Editor::toggle_selected_diff_hunks); register_action(editor, window, Editor::toggle_staged_selected_diff_hunks); register_action(editor, window, Editor::stage_and_next); register_action(editor, window, Editor::unstage_and_next); register_action(editor, window, Editor::expand_all_diff_hunks); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.format(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.format_selections(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.organize_imports(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, Editor::restart_language_server); register_action(editor, window, Editor::show_character_palette); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.confirm_completion(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.compose_completion(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.confirm_code_action(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.rename(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.confirm_rename(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.find_all_references(action, window, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(editor, window, Editor::show_signature_help); register_action(editor, window, Editor::next_edit_prediction); register_action(editor, window, Editor::previous_edit_prediction); register_action(editor, window, Editor::show_inline_completion); register_action(editor, window, Editor::context_menu_first); register_action(editor, window, Editor::context_menu_prev); register_action(editor, window, Editor::context_menu_next); register_action(editor, window, Editor::context_menu_last); register_action(editor, window, Editor::display_cursor_names); register_action(editor, window, Editor::unique_lines_case_insensitive); register_action(editor, window, Editor::unique_lines_case_sensitive); register_action(editor, window, Editor::accept_partial_inline_completion); register_action(editor, window, Editor::accept_edit_prediction); register_action(editor, window, Editor::restore_file); register_action(editor, window, Editor::git_restore); register_action(editor, window, Editor::apply_all_diff_hunks);Lines 1–500 of 9002. Load more
use crate::{ code_context_menus::{CodeActionsMenu, MENU_ASIDE_MAX_WIDTH, MENU_ASIDE_MIN_WIDTH, MENU_GAP}, commit_tooltip::{blame_entry_relative_timestamp, CommitTooltip, ParsedCommitMessage}, display_map::{ Block, BlockContext, BlockStyle, DisplaySnapshot, HighlightedChunk, ToDisplayPoint, }, editor_settings::{ CurrentLineHighlight, DoubleClickInMultibuffer, MultiCursorModifier, ScrollBeyondLastLine, ScrollbarDiagnostics, ShowScrollbar, }, git::blame::GitBlame, hover_popover::{ self, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH, MIN_POPOVER_LINE_HEIGHT, }, inlay_hint_settings, items::BufferSearchHighlights, mouse_context_menu::{self, MenuPosition, MouseContextMenu}, scroll::{axis_pair, scroll_amount::ScrollAmount, AxisPair}, BlockId, ChunkReplacement, CursorShape, CustomBlockId, DisplayDiffHunk, DisplayPoint, DisplayRow, DocumentHighlightRead, DocumentHighlightWrite, EditDisplayMode, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle, ExpandExcerpts, FocusedBlock, GoToHunk, GoToPreviousHunk, GutterDimensions, HalfPageDown, HalfPageUp, HandleInput, HoveredCursor, InlayHintRefreshReason, InlineCompletion, JumpData, LineDown, LineUp, OpenExcerpts, PageDown, PageUp, Point, RowExt, RowRangeExt, SelectPhase, SelectedTextHighlight, Selection, SoftWrap, StickyHeaderExcerpt, ToPoint, ToggleFold, COLUMNAR_SELECTION_MODIFIERS, CURSORS_VISIBLE_FOR, FILE_HEADER_HEIGHT, GIT_BLAME_MAX_AUTHOR_CHARS_DISPLAYED, MAX_LINE_LEN, MULTI_BUFFER_EXCERPT_HEADER_HEIGHT, }; use buffer_diff::{DiffHunkStatus, DiffHunkStatusKind}; use client::ParticipantIndex; use collections::{BTreeMap, HashMap, HashSet}; use file_icons::FileIcons; use git::{blame::BlameEntry, status::FileStatus, Oid}; use gpui::{ anchored, deferred, div, fill, linear_color_stop, linear_gradient, outline, pattern_slash, point, px, quad, relative, size, solid_background, svg, transparent_black, Action, AnyElement, App, AvailableSpace, Axis, Bounds, ClickEvent, ClipboardItem, ContentMask, Context, Corner, Corners, CursorStyle, DispatchPhase, Edges, Element, ElementInputHandler, Entity, Focusable as _, FontId, GlobalElementId, Hitbox, Hsla, InteractiveElement, IntoElement, Keystroke, Length, ModifiersChangedEvent, MouseButton, MouseDownEvent, MouseMoveEvent, MouseUpEvent, PaintQuad, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine, SharedString, Size, StatefulInteractiveElement, Style, Styled, Subscription, TextRun, TextStyleRefinement, Window, }; use inline_completion::Direction; use itertools::Itertools; use language::{ language_settings::{ IndentGuideBackgroundColoring, IndentGuideColoring, IndentGuideSettings, ShowWhitespaceSetting, }, ChunkRendererContext, }; use lsp::DiagnosticSeverity; use multi_buffer::{ Anchor, ExcerptId, ExcerptInfo, ExpandExcerptDirection, MultiBufferPoint, MultiBufferRow, RowInfo, }; use project::project_settings::{self, GitGutterSetting, GitHunkStyleSetting, ProjectSettings}; use settings::Settings; use smallvec::{smallvec, SmallVec}; use std::{ any::TypeId, borrow::Cow, cmp::{self, Ordering}, fmt::{self, Write}, iter, mem, ops::{Deref, Range}, rc::Rc, sync::Arc, }; use sum_tree::Bias; use text::BufferId; use theme::{ActiveTheme, Appearance, BufferLineHeight, PlayerColor}; use ui::{ h_flex, prelude::*, ButtonLike, ButtonStyle, ContextMenu, IconButtonShape, KeyBinding, Tooltip, POPOVER_Y_PADDING, }; use unicode_segmentation::UnicodeSegmentation; use util::{debug_panic, RangeExt, ResultExt}; use workspace::{item::Item, notifications::NotifyTaskExt}; const INLINE_BLAME_PADDING_EM_WIDTHS: f32 = 7.; const MIN_SCROLL_THUMB_SIZE: f32 = 25.; struct SelectionLayout { head: DisplayPoint, cursor_shape: CursorShape, is_newest: bool, is_local: bool, range: Range<DisplayPoint>, active_rows: Range<DisplayRow>, 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 || cursor_shape == CursorShape::Hollow) && !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 > 0 && head != map.max_point() { head = map.clip_point( DisplayPoint::new( head.row().previous_row(), map.line_len(head.row().previous_row()), ), 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().next_row(), 0); active_rows.end = head.row(); } } Self { head, cursor_shape, is_newest, is_local, range, active_rows, user_name, } } } pub struct EditorElement { editor: Entity<Editor>, style: EditorStyle, } type DisplayRowDelta = u32; impl EditorElement { pub(crate) const SCROLLBAR_WIDTH: Pixels = px(15.); pub fn new(editor: &Entity<Editor>, style: EditorStyle) -> Self { Self { editor: editor.clone(), style, } } fn register_actions(&self, window: &mut Window, cx: &mut App) { let editor = &self.editor; editor.update(cx, |editor, cx| { for action in editor.editor_actions.borrow().values() { (action)(window, cx) } }); crate::rust_analyzer_ext::apply_related_actions(editor, window, cx); crate::clangd_ext::apply_related_actions(editor, window, cx); register_action(editor, window, Editor::open_context_menu); register_action(editor, window, Editor::move_left); register_action(editor, window, Editor::move_right); register_action(editor, window, Editor::move_down); register_action(editor, window, Editor::move_down_by_lines); register_action(editor, window, Editor::select_down_by_lines); register_action(editor, window, Editor::move_up); register_action(editor, window, Editor::move_up_by_lines); register_action(editor, window, Editor::select_up_by_lines); register_action(editor, window, Editor::select_page_down); register_action(editor, window, Editor::select_page_up); register_action(editor, window, Editor::cancel); register_action(editor, window, Editor::newline); register_action(editor, window, Editor::newline_above); register_action(editor, window, Editor::newline_below); register_action(editor, window, Editor::backspace); register_action(editor, window, Editor::delete); register_action(editor, window, Editor::tab); register_action(editor, window, Editor::backtab); register_action(editor, window, Editor::indent); register_action(editor, window, Editor::outdent); register_action(editor, window, Editor::autoindent); register_action(editor, window, Editor::delete_line); register_action(editor, window, Editor::join_lines); register_action(editor, window, Editor::sort_lines_case_sensitive); register_action(editor, window, Editor::sort_lines_case_insensitive); register_action(editor, window, Editor::reverse_lines); register_action(editor, window, Editor::shuffle_lines); register_action(editor, window, Editor::convert_to_upper_case); register_action(editor, window, Editor::convert_to_lower_case); register_action(editor, window, Editor::convert_to_title_case); register_action(editor, window, Editor::convert_to_snake_case); register_action(editor, window, Editor::convert_to_kebab_case); register_action(editor, window, Editor::convert_to_upper_camel_case); register_action(editor, window, Editor::convert_to_lower_camel_case); register_action(editor, window, Editor::convert_to_opposite_case); register_action(editor, window, Editor::delete_to_previous_word_start); register_action(editor, window, Editor::delete_to_previous_subword_start); register_action(editor, window, Editor::delete_to_next_word_end); register_action(editor, window, Editor::delete_to_next_subword_end); register_action(editor, window, Editor::delete_to_beginning_of_line); register_action(editor, window, Editor::delete_to_end_of_line); register_action(editor, window, Editor::cut_to_end_of_line); register_action(editor, window, Editor::duplicate_line_up); register_action(editor, window, Editor::duplicate_line_down); register_action(editor, window, Editor::duplicate_selection); register_action(editor, window, Editor::move_line_up); register_action(editor, window, Editor::move_line_down); register_action(editor, window, Editor::transpose); register_action(editor, window, Editor::rewrap); register_action(editor, window, Editor::cut); register_action(editor, window, Editor::kill_ring_cut); register_action(editor, window, Editor::kill_ring_yank); register_action(editor, window, Editor::copy); register_action(editor, window, Editor::paste); register_action(editor, window, Editor::undo); register_action(editor, window, Editor::redo); register_action(editor, window, Editor::move_page_up); register_action(editor, window, Editor::move_page_down); register_action(editor, window, Editor::next_screen); register_action(editor, window, Editor::scroll_cursor_top); register_action(editor, window, Editor::scroll_cursor_center); register_action(editor, window, Editor::scroll_cursor_bottom); register_action(editor, window, Editor::scroll_cursor_center_top_bottom); register_action(editor, window, |editor, _: &LineDown, window, cx| { editor.scroll_screen(&ScrollAmount::Line(1.), window, cx) }); register_action(editor, window, |editor, _: &LineUp, window, cx| { editor.scroll_screen(&ScrollAmount::Line(-1.), window, cx) }); register_action(editor, window, |editor, _: &HalfPageDown, window, cx| { editor.scroll_screen(&ScrollAmount::Page(0.5), window, cx) }); register_action( editor, window, |editor, HandleInput(text): &HandleInput, window, cx| { if text.is_empty() { return; } editor.handle_input(text, window, cx); }, ); register_action(editor, window, |editor, _: &HalfPageUp, window, cx| { editor.scroll_screen(&ScrollAmount::Page(-0.5), window, cx) }); register_action(editor, window, |editor, _: &PageDown, window, cx| { editor.scroll_screen(&ScrollAmount::Page(1.), window, cx) }); register_action(editor, window, |editor, _: &PageUp, window, cx| { editor.scroll_screen(&ScrollAmount::Page(-1.), window, cx) }); register_action(editor, window, Editor::move_to_previous_word_start); register_action(editor, window, Editor::move_to_previous_subword_start); register_action(editor, window, Editor::move_to_next_word_end); register_action(editor, window, Editor::move_to_next_subword_end); register_action(editor, window, Editor::move_to_beginning_of_line); register_action(editor, window, Editor::move_to_end_of_line); register_action(editor, window, Editor::move_to_start_of_paragraph); register_action(editor, window, Editor::move_to_end_of_paragraph); register_action(editor, window, Editor::move_to_beginning); register_action(editor, window, Editor::move_to_end); register_action(editor, window, Editor::move_to_start_of_excerpt); register_action(editor, window, Editor::move_to_end_of_excerpt); register_action(editor, window, Editor::select_up); register_action(editor, window, Editor::select_down); register_action(editor, window, Editor::select_left); register_action(editor, window, Editor::select_right); register_action(editor, window, Editor::select_to_previous_word_start); register_action(editor, window, Editor::select_to_previous_subword_start); register_action(editor, window, Editor::select_to_next_word_end); register_action(editor, window, Editor::select_to_next_subword_end); register_action(editor, window, Editor::select_to_beginning_of_line); register_action(editor, window, Editor::select_to_end_of_line); register_action(editor, window, Editor::select_to_start_of_paragraph); register_action(editor, window, Editor::select_to_end_of_paragraph); register_action(editor, window, Editor::select_to_start_of_excerpt); register_action(editor, window, Editor::select_to_end_of_excerpt); register_action(editor, window, Editor::select_to_beginning); register_action(editor, window, Editor::select_to_end); register_action(editor, window, Editor::select_all); register_action(editor, window, |editor, action, window, cx| { editor.select_all_matches(action, window, cx).log_err(); }); register_action(editor, window, Editor::select_line); register_action(editor, window, Editor::split_selection_into_lines); register_action(editor, window, Editor::add_selection_above); register_action(editor, window, Editor::add_selection_below); register_action(editor, window, |editor, action, window, cx| { editor.select_next(action, window, cx).log_err(); }); register_action(editor, window, |editor, action, window, cx| { editor.select_previous(action, window, cx).log_err(); }); register_action(editor, window, Editor::toggle_comments); register_action(editor, window, Editor::select_larger_syntax_node); register_action(editor, window, Editor::select_smaller_syntax_node); register_action(editor, window, Editor::select_enclosing_symbol); register_action(editor, window, Editor::move_to_enclosing_bracket); register_action(editor, window, Editor::undo_selection); register_action(editor, window, Editor::redo_selection); if !editor.read(cx).is_singleton(cx) { register_action(editor, window, Editor::expand_excerpts); register_action(editor, window, Editor::expand_excerpts_up); register_action(editor, window, Editor::expand_excerpts_down); } register_action(editor, window, Editor::go_to_diagnostic); register_action(editor, window, Editor::go_to_prev_diagnostic); register_action(editor, window, Editor::go_to_next_hunk); register_action(editor, window, Editor::go_to_prev_hunk); register_action(editor, window, |editor, action, window, cx| { editor .go_to_definition(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_definition_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_declaration(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_declaration_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_implementation(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_implementation_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_type_definition(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, |editor, action, window, cx| { editor .go_to_type_definition_split(action, window, cx) .detach_and_log_err(cx); }); register_action(editor, window, Editor::open_url); register_action(editor, window, Editor::open_selected_filename); register_action(editor, window, Editor::fold); register_action(editor, window, Editor::fold_at_level); register_action(editor, window, Editor::fold_all); register_action(editor, window, Editor::fold_function_bodies); register_action(editor, window, Editor::fold_at); register_action(editor, window, Editor::fold_recursive); register_action(editor, window, Editor::toggle_fold); register_action(editor, window, Editor::toggle_fold_recursive); register_action(editor, window, Editor::unfold_lines); register_action(editor, window, Editor::unfold_recursive); register_action(editor, window, Editor::unfold_all); register_action(editor, window, Editor::unfold_at); register_action(editor, window, Editor::fold_selected_ranges); register_action(editor, window, Editor::set_mark); register_action(editor, window, Editor::swap_selection_ends); register_action(editor, window, Editor::show_completions); register_action(editor, window, Editor::toggle_code_actions); register_action(editor, window, Editor::open_excerpts); register_action(editor, window, Editor::open_excerpts_in_split); register_action(editor, window, Editor::open_proposed_changes_editor); register_action(editor, window, Editor::toggle_soft_wrap); register_action(editor, window, Editor::toggle_tab_bar); register_action(editor, window, Editor::toggle_line_numbers); register_action(editor, window, Editor::toggle_relative_line_numbers); register_action(editor, window, Editor::toggle_indent_guides); register_action(editor, window, Editor::toggle_inlay_hints); register_action(editor, window, Editor::toggle_edit_predictions); register_action(editor, window, Editor::toggle_inline_diagnostics); register_action(editor, window, hover_popover::hover); register_action(editor, window, Editor::reveal_in_finder); register_action(editor, window, Editor::copy_path); register_action(editor, window, Editor::copy_relative_path); register_action(editor, window, Editor::copy_file_name); register_action(editor, window, Editor::copy_file_name_without_extension); register_action(editor, window, Editor::copy_highlight_json); register_action(editor, window, Editor::copy_permalink_to_line); register_action(editor, window, Editor::open_permalink_to_line); register_action(editor, window, Editor::copy_file_location); register_action(editor, window, Editor::toggle_git_blame); register_action(editor, window, Editor::toggle_git_blame_inline); register_action(editor, window, Editor::toggle_selected_diff_hunks); register_action(editor, window, Editor::toggle_staged_selected_diff_hunks); register_action(editor, window, Editor::stage_and_next); register_action(editor, window, Editor::unstage_and_next); register_action(editor, window, Editor::expand_all_diff_hunks); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.format(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.format_selections(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.organize_imports(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, Editor::restart_language_server); register_action(editor, window, Editor::show_character_palette); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.confirm_completion(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.compose_completion(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.confirm_code_action(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.rename(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.confirm_rename(action, window, cx) { task.detach_and_notify_err(window, cx); } else { cx.propagate(); } }); register_action(editor, window, |editor, action, window, cx| { if let Some(task) = editor.find_all_references(action, window, cx) { task.detach_and_log_err(cx); } else { cx.propagate(); } }); register_action(editor, window, Editor::show_signature_help); register_action(editor, window, Editor::next_edit_prediction); register_action(editor, window, Editor::previous_edit_prediction); register_action(editor, window, Editor::show_inline_completion); register_action(editor, window, Editor::context_menu_first); register_action(editor, window, Editor::context_menu_prev); register_action(editor, window, Editor::context_menu_next); register_action(editor, window, Editor::context_menu_last); register_action(editor, window, Editor::display_cursor_names); register_action(editor, window, Editor::unique_lines_case_insensitive); register_action(editor, window, Editor::unique_lines_case_sensitive); register_action(editor, window, Editor::accept_partial_inline_completion); register_action(editor, window, Editor::accept_edit_prediction); register_action(editor, window, Editor::restore_file); register_action(editor, window, Editor::git_restore); register_action(editor, window, Editor::apply_all_diff_hunks);