3594 lines · 130.3 KB · Rust
RawDownload
use super::{    display_map::{BlockContext, ToDisplayPoint},    Anchor, DisplayPoint, Editor, EditorMode, EditorSnapshot, SelectPhase, SoftWrap, ToPoint,    MAX_LINE_LEN,};use crate::{    display_map::{BlockStyle, DisplaySnapshot, FoldStatus, TransformBlock},    editor_settings::ShowScrollbar,    git::{diff_hunk_to_display, DisplayDiffHunk},    hover_popover::{        hide_hover, hover_at, HOVER_POPOVER_GAP, MIN_POPOVER_CHARACTER_WIDTH,        MIN_POPOVER_LINE_HEIGHT,    },    link_go_to_definition::{        go_to_fetched_definition, go_to_fetched_type_definition, update_go_to_definition_link,        update_inlay_link_and_hover_points, GoToDefinitionTrigger,    },    mouse_context_menu, EditorSettings, EditorStyle, GutterHover, UnfoldAt,};use clock::ReplicaId;use collections::{BTreeMap, HashMap};use git::diff::DiffHunkStatus;use gpui::{    color::Color,    elements::*,    fonts::{HighlightStyle, TextStyle, Underline},    geometry::{        rect::RectF,        vector::{vec2f, Vector2F},        PathBuilder,    },    json::{self, ToJson},    platform::{CursorStyle, Modifiers, MouseButton, MouseButtonEvent, MouseMovedEvent},    text_layout::{self, Line, RunStyle, TextLayoutCache},    AnyElement, Axis, Border, CursorRegion, Element, EventContext, FontCache, LayoutContext,    MouseRegion, PaintContext, Quad, SceneBuilder, SizeConstraint, ViewContext, WindowContext,};use itertools::Itertools;use json::json;use language::{    language_settings::ShowWhitespaceSetting, Bias, CursorShape, DiagnosticSeverity, OffsetUtf16,    Selection,};use project::{    project_settings::{GitGutterSetting, ProjectSettings},    ProjectPath,};use smallvec::SmallVec;use std::{    borrow::Cow,    cmp::{self, Ordering},    fmt::Write,    iter,    ops::Range,    sync::Arc,};use text::Point;use workspace::item::Item; enum FoldMarkers {} struct SelectionLayout {    head: DisplayPoint,    cursor_shape: CursorShape,    is_newest: bool,    is_local: bool,    range: Range<DisplayPoint>,    active_rows: Range<u32>,} 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,    ) -> 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,        }    }} pub struct EditorElement {    style: Arc<EditorStyle>,} impl EditorElement {    pub fn new(style: EditorStyle) -> Self {        Self {            style: Arc::new(style),        }    }     fn attach_mouse_handlers(        scene: &mut SceneBuilder,        position_map: &Arc<PositionMap>,        has_popovers: bool,        visible_bounds: RectF,        text_bounds: RectF,        gutter_bounds: RectF,        bounds: RectF,        cx: &mut ViewContext<Editor>,    ) {        enum EditorElementMouseHandlers {}        scene.push_mouse_region(            MouseRegion::new::<EditorElementMouseHandlers>(                cx.view_id(),                cx.view_id(),                visible_bounds,            )            .on_down(MouseButton::Left, {                let position_map = position_map.clone();                move |event, editor, cx| {                    if !Self::mouse_down(                        editor,                        event.platform_event,                        position_map.as_ref(),                        text_bounds,                        gutter_bounds,                        cx,                    ) {                        cx.propagate_event();                    }                }            })            .on_down(MouseButton::Right, {                let position_map = position_map.clone();                move |event, editor, cx| {                    if !Self::mouse_right_down(                        editor,                        event.position,                        position_map.as_ref(),                        text_bounds,                        cx,                    ) {                        cx.propagate_event();                    }                }            })            .on_up(MouseButton::Left, {                let position_map = position_map.clone();                move |event, editor, cx| {                    if !Self::mouse_up(                        editor,                        event.position,                        event.cmd,                        event.shift,                        event.alt,                        position_map.as_ref(),                        text_bounds,                        cx,                    ) {                        cx.propagate_event()                    }                }            })            .on_drag(MouseButton::Left, {                let position_map = position_map.clone();                move |event, editor, cx| {                    if event.end {                        return;                    }                     if !Self::mouse_dragged(                        editor,                        event.platform_event,                        position_map.as_ref(),                        text_bounds,                        cx,                    ) {                        cx.propagate_event()                    }                }            })            .on_move({                let position_map = position_map.clone();                move |event, editor, cx| {                    if !Self::mouse_moved(                        editor,                        event.platform_event,                        &position_map,                        text_bounds,                        cx,                    ) {                        cx.propagate_event()                    }                }            })            .on_move_out(move |_, editor: &mut Editor, cx| {                if has_popovers {                    hide_hover(editor, cx);                }            })            .on_scroll({                let position_map = position_map.clone();                move |event, editor, cx| {                    if !Self::scroll(                        editor,                        event.position,                        *event.delta.raw(),                        event.delta.precise(),                        &position_map,                        bounds,                        cx,                    ) {                        cx.propagate_event()                    }                }            }),        );         enum GutterHandlers {}        scene.push_mouse_region(            MouseRegion::new::<GutterHandlers>(cx.view_id(), cx.view_id() + 1, gutter_bounds)                .on_hover(|hover, editor: &mut Editor, cx| {                    editor.gutter_hover(                        &GutterHover {                            hovered: hover.started,                        },                        cx,                    );                }),        )    }     fn mouse_down(        editor: &mut Editor,        MouseButtonEvent {            position,            modifiers:                Modifiers {                    shift,                    ctrl,                    alt,                    cmd,                    ..                },            mut click_count,            ..        }: MouseButtonEvent,        position_map: &PositionMap,        text_bounds: RectF,        gutter_bounds: RectF,        cx: &mut EventContext<Editor>,    ) -> bool {        if gutter_bounds.contains_point(position) {            click_count = 3; // Simulate triple-click when clicking the gutter to select lines        } else if !text_bounds.contains_point(position) {            return false;        }         let point_for_position = position_map.point_for_position(text_bounds, position);        let position = point_for_position.previous_valid;        if shift && alt {            editor.select(                SelectPhase::BeginColumnar {                    position,                    goal_column: point_for_position.exact_unclipped.column(),                },                cx,            );        } else if shift && !ctrl && !alt && !cmd {            editor.select(                SelectPhase::Extend {                    position,                    click_count,                },                cx,            );        } else {            editor.select(                SelectPhase::Begin {                    position,                    add: alt,                    click_count,                },                cx,            );        }         true    }     fn mouse_right_down(        editor: &mut Editor,        position: Vector2F,        position_map: &PositionMap,        text_bounds: RectF,        cx: &mut EventContext<Editor>,    ) -> bool {        if !text_bounds.contains_point(position) {            return false;        }        let point_for_position = position_map.point_for_position(text_bounds, position);        mouse_context_menu::deploy_context_menu(            editor,            position,            point_for_position.previous_valid,            cx,        );        true    }     fn mouse_up(        editor: &mut Editor,        position: Vector2F,        cmd: bool,        shift: bool,        alt: bool,        position_map: &PositionMap,        text_bounds: RectF,        cx: &mut EventContext<Editor>,    ) -> bool {        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 !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {            let point = position_map.point_for_position(text_bounds, position);            let could_be_inlay = point.as_valid().is_none();            if shift || could_be_inlay {                go_to_fetched_type_definition(editor, point, alt, cx);            } else {                go_to_fetched_definition(editor, point, alt, cx);            }             return true;        }         end_selection    }     fn mouse_dragged(        editor: &mut Editor,        MouseMovedEvent {            modifiers: Modifiers { cmd, shift, .. },            position,            ..        }: MouseMovedEvent,        position_map: &PositionMap,        text_bounds: RectF,        cx: &mut EventContext<Editor>,    ) -> bool {        // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed        // Don't trigger hover popover if mouse is hovering over context menu        let point = if text_bounds.contains_point(position) {            position_map                .point_for_position(text_bounds, position)                .as_valid()        } else {            None        };         update_go_to_definition_link(            editor,            point.map(GoToDefinitionTrigger::Text),            cmd,            shift,            cx,        );         if editor.has_pending_selection() {            let mut scroll_delta = Vector2F::zero();             let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);            let top = text_bounds.origin_y() + vertical_margin;            let bottom = text_bounds.lower_left().y() - vertical_margin;            if position.y() < top {                scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))            }            if position.y() > bottom {                scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))            }             let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);            let left = text_bounds.origin_x() + horizontal_margin;            let right = text_bounds.upper_right().x() - horizontal_margin;            if position.x() < left {                scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(                    left - position.x(),                ))            }            if position.x() > right {                scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(                    position.x() - right,                ))            }             let point_for_position = position_map.point_for_position(text_bounds, position);             editor.select(                SelectPhase::Update {                    position: point_for_position.previous_valid,                    goal_column: point_for_position.exact_unclipped.column(),                    scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)                        .clamp(Vector2F::zero(), position_map.scroll_max),                },                cx,            );            hover_at(editor, point, cx);            true        } else {            hover_at(editor, point, cx);            false        }    }     fn mouse_moved(        editor: &mut Editor,        MouseMovedEvent {            modifiers: Modifiers { shift, cmd, .. },            position,            ..        }: MouseMovedEvent,        position_map: &PositionMap,        text_bounds: RectF,        cx: &mut ViewContext<Editor>,    ) -> bool {        // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed        // Don't trigger hover popover if mouse is hovering over context menu        if text_bounds.contains_point(position) {            let point_for_position = position_map.point_for_position(text_bounds, position);            match point_for_position.as_valid() {                Some(point) => {                    update_go_to_definition_link(                        editor,                        Some(GoToDefinitionTrigger::Text(point)),                        cmd,                        shift,                        cx,                    );                    hover_at(editor, Some(point), cx);                }                None => {                    update_inlay_link_and_hover_points(                        &position_map.snapshot,                        point_for_position,                        editor,                        cmd,                        shift,                        cx,                    );                }            }        } else {            update_go_to_definition_link(editor, None, cmd, shift, cx);            hover_at(editor, None, cx);        }         true    }     fn scroll(        editor: &mut Editor,        position: Vector2F,        mut delta: Vector2F,        precise: bool,        position_map: &PositionMap,

Lines 1–500 of 3594.