4392 lines · 171.0 KB · Rust
RawDownload
use crate::{    display_map::{        BlockContext, BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint,        TransformBlock,    },    editor_settings::{DoubleClickInMultibuffer, MultiCursorModifier, 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,    mouse_context_menu,    scroll::scroll_amount::ScrollAmount,    CursorShape, DisplayPoint, DocumentHighlightRead, DocumentHighlightWrite, Editor, EditorMode,    EditorSettings, EditorSnapshot, EditorStyle, GutterDimensions, 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, ElementContext, ElementInputHandler, Entity, Hitbox, Hsla,    InteractiveElement, IntoElement, ModifiersChangedEvent, MouseButton, MouseDownEvent,    MouseMoveEvent, MouseUpEvent, ParentElement, Pixels, ScrollDelta, ScrollWheelEvent, ShapedLine,    SharedString, Size, Stateful, StatefulInteractiveElement, Style, Styled, TextRun, TextStyle,    TextStyleRefinement, View, ViewContext, WindowContext,};use itertools::Itertools;use language::language_settings::ShowWhitespaceSetting;use lsp::DiagnosticSeverity;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, mem,    ops::Range,    sync::Arc,};use sum_tree::Bias;use theme::{ActiveTheme, PlayerColor};use ui::prelude::*;use ui::{h_flex, ButtonLike, ButtonStyle, 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_down_by_lines);        register_action(view, cx, Editor::select_down_by_lines);        register_action(view, cx, Editor::move_up);        register_action(view, cx, Editor::move_up_by_lines);        register_action(view, cx, Editor::select_up_by_lines);        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, a, cx| {            editor.go_to_definition(a, cx).detach_and_log_err(cx);        });        register_action(view, cx, |editor, a, cx| {            editor.go_to_definition_split(a, cx).detach_and_log_err(cx);        });        register_action(view, cx, |editor, a, cx| {            editor.go_to_implementation(a, cx).detach_and_log_err(cx);        });        register_action(view, cx, |editor, a, cx| {            editor                .go_to_implementation_split(a, cx)                .detach_and_log_err(cx);        });        register_action(view, cx, |editor, a, cx| {            editor.go_to_type_definition(a, cx).detach_and_log_err(cx);        });        register_action(view, cx, |editor, a, cx| {            editor                .go_to_type_definition_split(a, cx)                .detach_and_log_err(cx);        });        register_action(view, cx, Editor::open_url);        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::open_excerpts_in_split);        register_action(view, cx, Editor::toggle_soft_wrap);        register_action(view, cx, Editor::toggle_line_numbers);        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::copy_permalink_to_line);        register_action(view, cx, Editor::open_permalink_to_line);        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);        register_action(view, cx, Editor::unique_lines_case_insensitive);        register_action(view, cx, Editor::unique_lines_case_sensitive);        register_action(view, cx, Editor::accept_partial_copilot_suggestion);        register_action(view, cx, Editor::revert_selected_hunks);    }     fn register_key_listeners(&self, cx: &mut ElementContext, layout: &EditorLayout) {        let position_map = layout.position_map.clone();        cx.on_key_event({            let editor = self.editor.clone();            let text_hitbox = layout.text_hitbox.clone();            move |event: &ModifiersChangedEvent, phase, cx| {                if phase != DispatchPhase::Bubble {                    return;                }                 editor.update(cx, |editor, cx| {                    Self::modifiers_changed(editor, event, &position_map, &text_hitbox, cx)                })            }        });    }     fn modifiers_changed(        editor: &mut Editor,        event: &ModifiersChangedEvent,        position_map: &PositionMap,        text_hitbox: &Hitbox,        cx: &mut ViewContext<Editor>,    ) {        let mouse_position = cx.mouse_position();        if !text_hitbox.is_hovered(cx) {            return;        }         editor.update_hovered_link(            position_map.point_for_position(text_hitbox.bounds, mouse_position),            &position_map.snapshot,            event.modifiers,            cx,        )    }     fn mouse_left_down(        editor: &mut Editor,        event: &MouseDownEvent,        position_map: &PositionMap,        text_hitbox: &Hitbox,        gutter_hitbox: &Hitbox,        cx: &mut ViewContext<Editor>,    ) {        if cx.default_prevented() {            return;        }         let mut click_count = event.click_count;        let mut modifiers = event.modifiers;         if gutter_hitbox.is_hovered(cx) {            click_count = 3; // Simulate triple-click when clicking the gutter to select lines        } else if !text_hitbox.is_hovered(cx) {            return;        }         if click_count == 2 && !editor.buffer().read(cx).is_singleton() {            match EditorSettings::get_global(cx).double_click_in_multibuffer {                DoubleClickInMultibuffer::Select => {                    // do nothing special on double click, all selection logic is below                }                DoubleClickInMultibuffer::Open => {                    if modifiers.alt {                        // if double click is made with alt, pretend it's a regular double click without opening and alt,                        // and run the selection logic.                        modifiers.alt = false;                    } else {                        // if double click is made without alt, open the corresponding excerp                        editor.open_excerpts(&OpenExcerpts, cx);                        return;                    }                }            }        }         let point_for_position =            position_map.point_for_position(text_hitbox.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 {            let multi_cursor_setting = EditorSettings::get_global(cx).multi_cursor_modifier;            let multi_cursor_modifier = match multi_cursor_setting {                MultiCursorModifier::Alt => modifiers.alt,                MultiCursorModifier::Cmd => modifiers.command,            };            editor.select(                SelectPhase::Begin {                    position,                    add: multi_cursor_modifier,                    click_count,                },                cx,            );        }         cx.stop_propagation();    }     fn mouse_right_down(        editor: &mut Editor,        event: &MouseDownEvent,        position_map: &PositionMap,        text_hitbox: &Hitbox,        cx: &mut ViewContext<Editor>,    ) {        if !text_hitbox.is_hovered(cx) {            return;        }        let point_for_position =            position_map.point_for_position(text_hitbox.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,

Lines 1–500 of 4392.