3988 lines · 156.8 KB · Rust
RawDownload
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.