element.rs

   1use super::{
   2    display_map::{BlockContext, ToDisplayPoint},
   3    Anchor, DisplayPoint, Editor, EditorMode, EditorSnapshot, Scroll, Select, SelectPhase,
   4    SoftWrap, ToPoint, MAX_LINE_LEN,
   5};
   6use crate::{
   7    display_map::{BlockStyle, DisplaySnapshot, TransformBlock},
   8    hover_popover::HoverAt,
   9    link_go_to_definition::{
  10        CmdShiftChanged, GoToFetchedDefinition, GoToFetchedTypeDefinition, UpdateGoToDefinitionLink,
  11    },
  12    mouse_context_menu::DeployMouseContextMenu,
  13    EditorStyle,
  14};
  15use clock::ReplicaId;
  16use collections::{BTreeMap, HashMap};
  17use gpui::{
  18    color::Color,
  19    elements::*,
  20    fonts::{HighlightStyle, Underline},
  21    geometry::{
  22        rect::RectF,
  23        vector::{vec2f, Vector2F},
  24        PathBuilder,
  25    },
  26    json::{self, ToJson},
  27    platform::CursorStyle,
  28    text_layout::{self, Line, RunStyle, TextLayoutCache},
  29    AppContext, Axis, Border, CursorRegion, Element, ElementBox, Event, EventContext,
  30    LayoutContext, ModifiersChangedEvent, MouseButton, MouseButtonEvent, MouseMovedEvent,
  31    MutableAppContext, PaintContext, Quad, Scene, ScrollWheelEvent, SizeConstraint, ViewContext,
  32    WeakViewHandle,
  33};
  34use json::json;
  35use language::{Bias, DiagnosticSeverity, OffsetUtf16, Selection};
  36use project::ProjectPath;
  37use settings::Settings;
  38use smallvec::SmallVec;
  39use std::{
  40    cmp::{self, Ordering},
  41    fmt::Write,
  42    iter,
  43    ops::Range,
  44};
  45
  46const MIN_POPOVER_CHARACTER_WIDTH: f32 = 20.;
  47const MIN_POPOVER_LINE_HEIGHT: f32 = 4.;
  48const HOVER_POPOVER_GAP: f32 = 10.;
  49
  50struct SelectionLayout {
  51    head: DisplayPoint,
  52    range: Range<DisplayPoint>,
  53}
  54
  55impl SelectionLayout {
  56    fn new<T: ToPoint + ToDisplayPoint + Clone>(
  57        selection: Selection<T>,
  58        line_mode: bool,
  59        map: &DisplaySnapshot,
  60    ) -> Self {
  61        if line_mode {
  62            let selection = selection.map(|p| p.to_point(&map.buffer_snapshot));
  63            let point_range = map.expand_to_line(selection.range());
  64            Self {
  65                head: selection.head().to_display_point(map),
  66                range: point_range.start.to_display_point(map)
  67                    ..point_range.end.to_display_point(map),
  68            }
  69        } else {
  70            let selection = selection.map(|p| p.to_display_point(map));
  71            Self {
  72                head: selection.head(),
  73                range: selection.range(),
  74            }
  75        }
  76    }
  77}
  78
  79pub struct EditorElement {
  80    view: WeakViewHandle<Editor>,
  81    style: EditorStyle,
  82    cursor_shape: CursorShape,
  83}
  84
  85impl EditorElement {
  86    pub fn new(
  87        view: WeakViewHandle<Editor>,
  88        style: EditorStyle,
  89        cursor_shape: CursorShape,
  90    ) -> Self {
  91        Self {
  92            view,
  93            style,
  94            cursor_shape,
  95        }
  96    }
  97
  98    fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor {
  99        self.view.upgrade(cx).unwrap().read(cx)
 100    }
 101
 102    fn update_view<F, T>(&self, cx: &mut MutableAppContext, f: F) -> T
 103    where
 104        F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
 105    {
 106        self.view.upgrade(cx).unwrap().update(cx, f)
 107    }
 108
 109    fn snapshot(&self, cx: &mut MutableAppContext) -> EditorSnapshot {
 110        self.update_view(cx, |view, cx| view.snapshot(cx))
 111    }
 112
 113    fn mouse_down(
 114        &self,
 115        position: Vector2F,
 116        cmd: bool,
 117        alt: bool,
 118        shift: bool,
 119        mut click_count: usize,
 120        layout: &mut LayoutState,
 121        paint: &mut PaintState,
 122        cx: &mut EventContext,
 123    ) -> bool {
 124        if cmd && paint.text_bounds.contains_point(position) {
 125            let (point, target_point) =
 126                paint.point_for_position(&self.snapshot(cx), layout, position);
 127            if point == target_point {
 128                if shift {
 129                    cx.dispatch_action(GoToFetchedTypeDefinition { point });
 130                } else {
 131                    cx.dispatch_action(GoToFetchedDefinition { point });
 132                }
 133
 134                return true;
 135            }
 136        }
 137
 138        if paint.gutter_bounds.contains_point(position) {
 139            click_count = 3; // Simulate triple-click when clicking the gutter to select lines
 140        } else if !paint.text_bounds.contains_point(position) {
 141            return false;
 142        }
 143
 144        let snapshot = self.snapshot(cx.app);
 145        let (position, target_position) = paint.point_for_position(&snapshot, layout, position);
 146
 147        if shift && alt {
 148            cx.dispatch_action(Select(SelectPhase::BeginColumnar {
 149                position,
 150                goal_column: target_position.column(),
 151            }));
 152        } else if shift {
 153            cx.dispatch_action(Select(SelectPhase::Extend {
 154                position,
 155                click_count,
 156            }));
 157        } else {
 158            cx.dispatch_action(Select(SelectPhase::Begin {
 159                position,
 160                add: alt,
 161                click_count,
 162            }));
 163        }
 164
 165        true
 166    }
 167
 168    fn mouse_right_down(
 169        &self,
 170        position: Vector2F,
 171        layout: &mut LayoutState,
 172        paint: &mut PaintState,
 173        cx: &mut EventContext,
 174    ) -> bool {
 175        if !paint.text_bounds.contains_point(position) {
 176            return false;
 177        }
 178
 179        let snapshot = self.snapshot(cx.app);
 180        let (point, _) = paint.point_for_position(&snapshot, layout, position);
 181
 182        cx.dispatch_action(DeployMouseContextMenu { position, point });
 183        true
 184    }
 185
 186    fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool {
 187        if self.view(cx.app.as_ref()).is_selecting() {
 188            cx.dispatch_action(Select(SelectPhase::End));
 189            true
 190        } else {
 191            false
 192        }
 193    }
 194
 195    fn mouse_dragged(
 196        &self,
 197        position: Vector2F,
 198        layout: &mut LayoutState,
 199        paint: &mut PaintState,
 200        cx: &mut EventContext,
 201    ) -> bool {
 202        let view = self.view(cx.app.as_ref());
 203
 204        if view.is_selecting() {
 205            let rect = paint.text_bounds;
 206            let mut scroll_delta = Vector2F::zero();
 207
 208            let vertical_margin = layout.line_height.min(rect.height() / 3.0);
 209            let top = rect.origin_y() + vertical_margin;
 210            let bottom = rect.lower_left().y() - vertical_margin;
 211            if position.y() < top {
 212                scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
 213            }
 214            if position.y() > bottom {
 215                scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
 216            }
 217
 218            let horizontal_margin = layout.line_height.min(rect.width() / 3.0);
 219            let left = rect.origin_x() + horizontal_margin;
 220            let right = rect.upper_right().x() - horizontal_margin;
 221            if position.x() < left {
 222                scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
 223                    left - position.x(),
 224                ))
 225            }
 226            if position.x() > right {
 227                scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
 228                    position.x() - right,
 229                ))
 230            }
 231
 232            let snapshot = self.snapshot(cx.app);
 233            let (position, target_position) = paint.point_for_position(&snapshot, layout, position);
 234
 235            cx.dispatch_action(Select(SelectPhase::Update {
 236                position,
 237                goal_column: target_position.column(),
 238                scroll_position: (snapshot.scroll_position() + scroll_delta)
 239                    .clamp(Vector2F::zero(), layout.scroll_max),
 240            }));
 241            true
 242        } else {
 243            false
 244        }
 245    }
 246
 247    fn mouse_moved(
 248        &self,
 249        MouseMovedEvent {
 250            cmd,
 251            shift,
 252            position,
 253            ..
 254        }: MouseMovedEvent,
 255        layout: &LayoutState,
 256        paint: &PaintState,
 257        cx: &mut EventContext,
 258    ) -> bool {
 259        // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
 260        // Don't trigger hover popover if mouse is hovering over context menu
 261        let point = if paint.text_bounds.contains_point(position) {
 262            let (point, target_point) =
 263                paint.point_for_position(&self.snapshot(cx), layout, position);
 264            if point == target_point {
 265                Some(point)
 266            } else {
 267                None
 268            }
 269        } else {
 270            None
 271        };
 272
 273        cx.dispatch_action(UpdateGoToDefinitionLink {
 274            point,
 275            cmd_held: cmd,
 276            shift_held: shift,
 277        });
 278
 279        if paint
 280            .context_menu_bounds
 281            .map_or(false, |context_menu_bounds| {
 282                context_menu_bounds.contains_point(position)
 283            })
 284        {
 285            return false;
 286        }
 287
 288        if paint
 289            .hover_popover_bounds
 290            .iter()
 291            .any(|hover_bounds| hover_bounds.contains_point(position))
 292        {
 293            return false;
 294        }
 295
 296        cx.dispatch_action(HoverAt { point });
 297        true
 298    }
 299
 300    fn modifiers_changed(&self, event: ModifiersChangedEvent, cx: &mut EventContext) -> bool {
 301        cx.dispatch_action(CmdShiftChanged {
 302            cmd_down: event.cmd,
 303            shift_down: event.shift,
 304        });
 305        false
 306    }
 307
 308    fn scroll(
 309        &self,
 310        position: Vector2F,
 311        mut delta: Vector2F,
 312        precise: bool,
 313        layout: &mut LayoutState,
 314        paint: &mut PaintState,
 315        cx: &mut EventContext,
 316    ) -> bool {
 317        if !paint.bounds.contains_point(position) {
 318            return false;
 319        }
 320
 321        let snapshot = self.snapshot(cx.app);
 322        let max_glyph_width = layout.em_width;
 323        if !precise {
 324            delta *= vec2f(max_glyph_width, layout.line_height);
 325        }
 326
 327        let scroll_position = snapshot.scroll_position();
 328        let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
 329        let y = (scroll_position.y() * layout.line_height - delta.y()) / layout.line_height;
 330        let scroll_position = vec2f(x, y).clamp(Vector2F::zero(), layout.scroll_max);
 331
 332        cx.dispatch_action(Scroll(scroll_position));
 333
 334        true
 335    }
 336
 337    fn paint_background(
 338        &self,
 339        gutter_bounds: RectF,
 340        text_bounds: RectF,
 341        layout: &LayoutState,
 342        cx: &mut PaintContext,
 343    ) {
 344        let bounds = gutter_bounds.union_rect(text_bounds);
 345        let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
 346        let editor = self.view(cx.app);
 347        cx.scene.push_quad(Quad {
 348            bounds: gutter_bounds,
 349            background: Some(self.style.gutter_background),
 350            border: Border::new(0., Color::transparent_black()),
 351            corner_radius: 0.,
 352        });
 353        cx.scene.push_quad(Quad {
 354            bounds: text_bounds,
 355            background: Some(self.style.background),
 356            border: Border::new(0., Color::transparent_black()),
 357            corner_radius: 0.,
 358        });
 359
 360        if let EditorMode::Full = editor.mode {
 361            let mut active_rows = layout.active_rows.iter().peekable();
 362            while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
 363                let mut end_row = *start_row;
 364                while active_rows.peek().map_or(false, |r| {
 365                    *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
 366                }) {
 367                    active_rows.next().unwrap();
 368                    end_row += 1;
 369                }
 370
 371                if !contains_non_empty_selection {
 372                    let origin = vec2f(
 373                        bounds.origin_x(),
 374                        bounds.origin_y() + (layout.line_height * *start_row as f32) - scroll_top,
 375                    );
 376                    let size = vec2f(
 377                        bounds.width(),
 378                        layout.line_height * (end_row - start_row + 1) as f32,
 379                    );
 380                    cx.scene.push_quad(Quad {
 381                        bounds: RectF::new(origin, size),
 382                        background: Some(self.style.active_line_background),
 383                        border: Border::default(),
 384                        corner_radius: 0.,
 385                    });
 386                }
 387            }
 388
 389            if let Some(highlighted_rows) = &layout.highlighted_rows {
 390                let origin = vec2f(
 391                    bounds.origin_x(),
 392                    bounds.origin_y() + (layout.line_height * highlighted_rows.start as f32)
 393                        - scroll_top,
 394                );
 395                let size = vec2f(
 396                    bounds.width(),
 397                    layout.line_height * highlighted_rows.len() as f32,
 398                );
 399                cx.scene.push_quad(Quad {
 400                    bounds: RectF::new(origin, size),
 401                    background: Some(self.style.highlighted_line_background),
 402                    border: Border::default(),
 403                    corner_radius: 0.,
 404                });
 405            }
 406        }
 407    }
 408
 409    fn paint_gutter(
 410        &mut self,
 411        bounds: RectF,
 412        visible_bounds: RectF,
 413        layout: &mut LayoutState,
 414        cx: &mut PaintContext,
 415    ) {
 416        let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
 417        for (ix, line) in layout.line_number_layouts.iter().enumerate() {
 418            if let Some(line) = line {
 419                let line_origin = bounds.origin()
 420                    + vec2f(
 421                        bounds.width() - line.width() - layout.gutter_padding,
 422                        ix as f32 * layout.line_height - (scroll_top % layout.line_height),
 423                    );
 424                line.paint(line_origin, visible_bounds, layout.line_height, cx);
 425            }
 426        }
 427
 428        if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
 429            let mut x = bounds.width() - layout.gutter_padding;
 430            let mut y = *row as f32 * layout.line_height - scroll_top;
 431            x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x()) / 2.;
 432            y += (layout.line_height - indicator.size().y()) / 2.;
 433            indicator.paint(bounds.origin() + vec2f(x, y), visible_bounds, cx);
 434        }
 435    }
 436
 437    fn paint_text(
 438        &mut self,
 439        bounds: RectF,
 440        visible_bounds: RectF,
 441        layout: &mut LayoutState,
 442        paint: &mut PaintState,
 443        cx: &mut PaintContext,
 444    ) {
 445        let view = self.view(cx.app);
 446        let style = &self.style;
 447        let local_replica_id = view.replica_id(cx);
 448        let scroll_position = layout.snapshot.scroll_position();
 449        let start_row = scroll_position.y() as u32;
 450        let scroll_top = scroll_position.y() * layout.line_height;
 451        let end_row = ((scroll_top + bounds.height()) / layout.line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
 452        let max_glyph_width = layout.em_width;
 453        let scroll_left = scroll_position.x() * max_glyph_width;
 454        let content_origin = bounds.origin() + vec2f(layout.gutter_margin, 0.);
 455
 456        cx.scene.push_layer(Some(bounds));
 457
 458        cx.scene.push_cursor_region(CursorRegion {
 459            bounds,
 460            style: if !view.link_go_to_definition_state.definitions.is_empty() {
 461                CursorStyle::PointingHand
 462            } else {
 463                CursorStyle::IBeam
 464            },
 465        });
 466
 467        for (range, color) in &layout.highlighted_ranges {
 468            self.paint_highlighted_range(
 469                range.clone(),
 470                start_row,
 471                end_row,
 472                *color,
 473                0.,
 474                0.15 * layout.line_height,
 475                layout,
 476                content_origin,
 477                scroll_top,
 478                scroll_left,
 479                bounds,
 480                cx,
 481            );
 482        }
 483
 484        let mut cursors = SmallVec::<[Cursor; 32]>::new();
 485        for (replica_id, selections) in &layout.selections {
 486            let selection_style = style.replica_selection_style(*replica_id);
 487            let corner_radius = 0.15 * layout.line_height;
 488
 489            for selection in selections {
 490                self.paint_highlighted_range(
 491                    selection.range.clone(),
 492                    start_row,
 493                    end_row,
 494                    selection_style.selection,
 495                    corner_radius,
 496                    corner_radius * 2.,
 497                    layout,
 498                    content_origin,
 499                    scroll_top,
 500                    scroll_left,
 501                    bounds,
 502                    cx,
 503                );
 504
 505                if view.show_local_cursors() || *replica_id != local_replica_id {
 506                    let cursor_position = selection.head;
 507                    if (start_row..end_row).contains(&cursor_position.row()) {
 508                        let cursor_row_layout =
 509                            &layout.line_layouts[(cursor_position.row() - start_row) as usize];
 510                        let cursor_column = cursor_position.column() as usize;
 511
 512                        let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 513                        let mut block_width =
 514                            cursor_row_layout.x_for_index(cursor_column + 1) - cursor_character_x;
 515                        if block_width == 0.0 {
 516                            block_width = layout.em_width;
 517                        }
 518
 519                        let block_text =
 520                            if let CursorShape::Block = self.cursor_shape {
 521                                layout.snapshot.chars_at(cursor_position).next().and_then(
 522                                    |character| {
 523                                        let font_id =
 524                                            cursor_row_layout.font_for_index(cursor_column)?;
 525                                        let text = character.to_string();
 526
 527                                        Some(cx.text_layout_cache.layout_str(
 528                                            &text,
 529                                            cursor_row_layout.font_size(),
 530                                            &[(
 531                                                text.len(),
 532                                                RunStyle {
 533                                                    font_id,
 534                                                    color: style.background,
 535                                                    underline: Default::default(),
 536                                                },
 537                                            )],
 538                                        ))
 539                                    },
 540                                )
 541                            } else {
 542                                None
 543                            };
 544
 545                        let x = cursor_character_x - scroll_left;
 546                        let y = cursor_position.row() as f32 * layout.line_height - scroll_top;
 547                        cursors.push(Cursor {
 548                            color: selection_style.cursor,
 549                            block_width,
 550                            origin: vec2f(x, y),
 551                            line_height: layout.line_height,
 552                            shape: self.cursor_shape,
 553                            block_text,
 554                        });
 555                    }
 556                }
 557            }
 558        }
 559
 560        if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
 561            // Draw glyphs
 562            for (ix, line) in layout.line_layouts.iter().enumerate() {
 563                let row = start_row + ix as u32;
 564                line.paint(
 565                    content_origin
 566                        + vec2f(-scroll_left, row as f32 * layout.line_height - scroll_top),
 567                    visible_text_bounds,
 568                    layout.line_height,
 569                    cx,
 570                );
 571            }
 572        }
 573
 574        cx.scene.push_layer(Some(bounds));
 575        for cursor in cursors {
 576            cursor.paint(content_origin, cx);
 577        }
 578        cx.scene.pop_layer();
 579
 580        if let Some((position, context_menu)) = layout.context_menu.as_mut() {
 581            cx.scene.push_stacking_context(None);
 582            let cursor_row_layout = &layout.line_layouts[(position.row() - start_row) as usize];
 583            let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
 584            let y = (position.row() + 1) as f32 * layout.line_height - scroll_top;
 585            let mut list_origin = content_origin + vec2f(x, y);
 586            let list_width = context_menu.size().x();
 587            let list_height = context_menu.size().y();
 588
 589            // Snap the right edge of the list to the right edge of the window if
 590            // its horizontal bounds overflow.
 591            if list_origin.x() + list_width > cx.window_size.x() {
 592                list_origin.set_x((cx.window_size.x() - list_width).max(0.));
 593            }
 594
 595            if list_origin.y() + list_height > bounds.max_y() {
 596                list_origin.set_y(list_origin.y() - layout.line_height - list_height);
 597            }
 598
 599            context_menu.paint(
 600                list_origin,
 601                RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
 602                cx,
 603            );
 604
 605            paint.context_menu_bounds = Some(RectF::new(list_origin, context_menu.size()));
 606
 607            cx.scene.pop_stacking_context();
 608        }
 609
 610        if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
 611            cx.scene.push_stacking_context(None);
 612
 613            // This is safe because we check on layout whether the required row is available
 614            let hovered_row_layout = &layout.line_layouts[(position.row() - start_row) as usize];
 615
 616            // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
 617            // height. This is the size we will use to decide whether to render popovers above or below
 618            // the hovered line.
 619            let first_size = hover_popovers[0].size();
 620            let height_to_reserve =
 621                first_size.y() + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.line_height;
 622
 623            // Compute Hovered Point
 624            let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
 625            let y = position.row() as f32 * layout.line_height - scroll_top;
 626            let hovered_point = content_origin + vec2f(x, y);
 627
 628            paint.hover_popover_bounds.clear();
 629
 630            if hovered_point.y() - height_to_reserve > 0.0 {
 631                // There is enough space above. Render popovers above the hovered point
 632                let mut current_y = hovered_point.y();
 633                for hover_popover in hover_popovers {
 634                    let size = hover_popover.size();
 635                    let mut popover_origin = vec2f(hovered_point.x(), current_y - size.y());
 636
 637                    let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
 638                    if x_out_of_bounds < 0.0 {
 639                        popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
 640                    }
 641
 642                    hover_popover.paint(
 643                        popover_origin,
 644                        RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
 645                        cx,
 646                    );
 647
 648                    paint.hover_popover_bounds.push(
 649                        RectF::new(popover_origin, hover_popover.size())
 650                            .dilate(Vector2F::new(0., 5.)),
 651                    );
 652
 653                    current_y = popover_origin.y() - HOVER_POPOVER_GAP;
 654                }
 655            } else {
 656                // There is not enough space above. Render popovers below the hovered point
 657                let mut current_y = hovered_point.y() + layout.line_height;
 658                for hover_popover in hover_popovers {
 659                    let size = hover_popover.size();
 660                    let mut popover_origin = vec2f(hovered_point.x(), current_y);
 661
 662                    let x_out_of_bounds = bounds.max_x() - (popover_origin.x() + size.x());
 663                    if x_out_of_bounds < 0.0 {
 664                        popover_origin.set_x(popover_origin.x() + x_out_of_bounds);
 665                    }
 666
 667                    hover_popover.paint(
 668                        popover_origin,
 669                        RectF::from_points(Vector2F::zero(), vec2f(f32::MAX, f32::MAX)), // Let content bleed outside of editor
 670                        cx,
 671                    );
 672
 673                    paint.hover_popover_bounds.push(
 674                        RectF::new(popover_origin, hover_popover.size())
 675                            .dilate(Vector2F::new(0., 5.)),
 676                    );
 677
 678                    current_y = popover_origin.y() + size.y() + HOVER_POPOVER_GAP;
 679                }
 680            }
 681
 682            cx.scene.pop_stacking_context();
 683        }
 684
 685        cx.scene.pop_layer();
 686    }
 687
 688    fn paint_highlighted_range(
 689        &self,
 690        range: Range<DisplayPoint>,
 691        start_row: u32,
 692        end_row: u32,
 693        color: Color,
 694        corner_radius: f32,
 695        line_end_overshoot: f32,
 696        layout: &LayoutState,
 697        content_origin: Vector2F,
 698        scroll_top: f32,
 699        scroll_left: f32,
 700        bounds: RectF,
 701        cx: &mut PaintContext,
 702    ) {
 703        if range.start != range.end {
 704            let row_range = if range.end.column() == 0 {
 705                cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
 706            } else {
 707                cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
 708            };
 709
 710            let highlighted_range = HighlightedRange {
 711                color,
 712                line_height: layout.line_height,
 713                corner_radius,
 714                start_y: content_origin.y() + row_range.start as f32 * layout.line_height
 715                    - scroll_top,
 716                lines: row_range
 717                    .into_iter()
 718                    .map(|row| {
 719                        let line_layout = &layout.line_layouts[(row - start_row) as usize];
 720                        HighlightedRangeLine {
 721                            start_x: if row == range.start.row() {
 722                                content_origin.x()
 723                                    + line_layout.x_for_index(range.start.column() as usize)
 724                                    - scroll_left
 725                            } else {
 726                                content_origin.x() - scroll_left
 727                            },
 728                            end_x: if row == range.end.row() {
 729                                content_origin.x()
 730                                    + line_layout.x_for_index(range.end.column() as usize)
 731                                    - scroll_left
 732                            } else {
 733                                content_origin.x() + line_layout.width() + line_end_overshoot
 734                                    - scroll_left
 735                            },
 736                        }
 737                    })
 738                    .collect(),
 739            };
 740
 741            highlighted_range.paint(bounds, cx.scene);
 742        }
 743    }
 744
 745    fn paint_blocks(
 746        &mut self,
 747        bounds: RectF,
 748        visible_bounds: RectF,
 749        layout: &mut LayoutState,
 750        cx: &mut PaintContext,
 751    ) {
 752        let scroll_position = layout.snapshot.scroll_position();
 753        let scroll_left = scroll_position.x() * layout.em_width;
 754        let scroll_top = scroll_position.y() * layout.line_height;
 755
 756        for block in &mut layout.blocks {
 757            let mut origin =
 758                bounds.origin() + vec2f(0., block.row as f32 * layout.line_height - scroll_top);
 759            if !matches!(block.style, BlockStyle::Sticky) {
 760                origin += vec2f(-scroll_left, 0.);
 761            }
 762            block.element.paint(origin, visible_bounds, cx);
 763        }
 764    }
 765
 766    fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &LayoutContext) -> f32 {
 767        let digit_count = (snapshot.max_buffer_row() as f32).log10().floor() as usize + 1;
 768        let style = &self.style;
 769
 770        cx.text_layout_cache
 771            .layout_str(
 772                "1".repeat(digit_count).as_str(),
 773                style.text.font_size,
 774                &[(
 775                    digit_count,
 776                    RunStyle {
 777                        font_id: style.text.font_id,
 778                        color: Color::black(),
 779                        underline: Default::default(),
 780                    },
 781                )],
 782            )
 783            .width()
 784    }
 785
 786    fn layout_line_numbers(
 787        &self,
 788        rows: Range<u32>,
 789        active_rows: &BTreeMap<u32, bool>,
 790        snapshot: &EditorSnapshot,
 791        cx: &LayoutContext,
 792    ) -> Vec<Option<text_layout::Line>> {
 793        let style = &self.style;
 794        let include_line_numbers = snapshot.mode == EditorMode::Full;
 795        let mut line_number_layouts = Vec::with_capacity(rows.len());
 796        let mut line_number = String::new();
 797        for (ix, row) in snapshot
 798            .buffer_rows(rows.start)
 799            .take((rows.end - rows.start) as usize)
 800            .enumerate()
 801        {
 802            let display_row = rows.start + ix as u32;
 803            let color = if active_rows.contains_key(&display_row) {
 804                style.line_number_active
 805            } else {
 806                style.line_number
 807            };
 808            if let Some(buffer_row) = row {
 809                if include_line_numbers {
 810                    line_number.clear();
 811                    write!(&mut line_number, "{}", buffer_row + 1).unwrap();
 812                    line_number_layouts.push(Some(cx.text_layout_cache.layout_str(
 813                        &line_number,
 814                        style.text.font_size,
 815                        &[(
 816                            line_number.len(),
 817                            RunStyle {
 818                                font_id: style.text.font_id,
 819                                color,
 820                                underline: Default::default(),
 821                            },
 822                        )],
 823                    )));
 824                }
 825            } else {
 826                line_number_layouts.push(None);
 827            }
 828        }
 829
 830        line_number_layouts
 831    }
 832
 833    fn layout_lines(
 834        &mut self,
 835        rows: Range<u32>,
 836        snapshot: &EditorSnapshot,
 837        cx: &LayoutContext,
 838    ) -> Vec<text_layout::Line> {
 839        if rows.start >= rows.end {
 840            return Vec::new();
 841        }
 842
 843        // When the editor is empty and unfocused, then show the placeholder.
 844        if snapshot.is_empty() && !snapshot.is_focused() {
 845            let placeholder_style = self
 846                .style
 847                .placeholder_text
 848                .as_ref()
 849                .unwrap_or_else(|| &self.style.text);
 850            let placeholder_text = snapshot.placeholder_text();
 851            let placeholder_lines = placeholder_text
 852                .as_ref()
 853                .map_or("", AsRef::as_ref)
 854                .split('\n')
 855                .skip(rows.start as usize)
 856                .chain(iter::repeat(""))
 857                .take(rows.len());
 858            return placeholder_lines
 859                .map(|line| {
 860                    cx.text_layout_cache.layout_str(
 861                        line,
 862                        placeholder_style.font_size,
 863                        &[(
 864                            line.len(),
 865                            RunStyle {
 866                                font_id: placeholder_style.font_id,
 867                                color: placeholder_style.color,
 868                                underline: Default::default(),
 869                            },
 870                        )],
 871                    )
 872                })
 873                .collect();
 874        } else {
 875            let style = &self.style;
 876            let chunks = snapshot.chunks(rows.clone(), true).map(|chunk| {
 877                let mut highlight_style = chunk
 878                    .syntax_highlight_id
 879                    .and_then(|id| id.style(&style.syntax));
 880
 881                if let Some(chunk_highlight) = chunk.highlight_style {
 882                    if let Some(highlight_style) = highlight_style.as_mut() {
 883                        highlight_style.highlight(chunk_highlight);
 884                    } else {
 885                        highlight_style = Some(chunk_highlight);
 886                    }
 887                }
 888
 889                let mut diagnostic_highlight = HighlightStyle::default();
 890
 891                if chunk.is_unnecessary {
 892                    diagnostic_highlight.fade_out = Some(style.unnecessary_code_fade);
 893                }
 894
 895                if let Some(severity) = chunk.diagnostic_severity {
 896                    // Omit underlines for HINT/INFO diagnostics on 'unnecessary' code.
 897                    if severity <= DiagnosticSeverity::WARNING || !chunk.is_unnecessary {
 898                        let diagnostic_style = super::diagnostic_style(severity, true, style);
 899                        diagnostic_highlight.underline = Some(Underline {
 900                            color: Some(diagnostic_style.message.text.color),
 901                            thickness: 1.0.into(),
 902                            squiggly: true,
 903                        });
 904                    }
 905                }
 906
 907                if let Some(highlight_style) = highlight_style.as_mut() {
 908                    highlight_style.highlight(diagnostic_highlight);
 909                } else {
 910                    highlight_style = Some(diagnostic_highlight);
 911                }
 912
 913                (chunk.text, highlight_style)
 914            });
 915            layout_highlighted_chunks(
 916                chunks,
 917                &style.text,
 918                &cx.text_layout_cache,
 919                &cx.font_cache,
 920                MAX_LINE_LEN,
 921                rows.len() as usize,
 922            )
 923        }
 924    }
 925
 926    fn layout_blocks(
 927        &mut self,
 928        rows: Range<u32>,
 929        snapshot: &EditorSnapshot,
 930        editor_width: f32,
 931        scroll_width: f32,
 932        gutter_padding: f32,
 933        gutter_width: f32,
 934        em_width: f32,
 935        text_x: f32,
 936        line_height: f32,
 937        style: &EditorStyle,
 938        line_layouts: &[text_layout::Line],
 939        cx: &mut LayoutContext,
 940    ) -> (f32, Vec<BlockLayout>) {
 941        let editor = if let Some(editor) = self.view.upgrade(cx) {
 942            editor
 943        } else {
 944            return Default::default();
 945        };
 946
 947        let tooltip_style = cx.global::<Settings>().theme.tooltip.clone();
 948        let scroll_x = snapshot.scroll_position.x();
 949        let (fixed_blocks, non_fixed_blocks) = snapshot
 950            .blocks_in_range(rows.clone())
 951            .partition::<Vec<_>, _>(|(_, block)| match block {
 952                TransformBlock::ExcerptHeader { .. } => false,
 953                TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed,
 954            });
 955        let mut render_block = |block: &TransformBlock, width: f32| {
 956            let mut element = match block {
 957                TransformBlock::Custom(block) => {
 958                    let align_to = block
 959                        .position()
 960                        .to_point(&snapshot.buffer_snapshot)
 961                        .to_display_point(snapshot);
 962                    let anchor_x = text_x
 963                        + if rows.contains(&align_to.row()) {
 964                            line_layouts[(align_to.row() - rows.start) as usize]
 965                                .x_for_index(align_to.column() as usize)
 966                        } else {
 967                            layout_line(align_to.row(), snapshot, style, cx.text_layout_cache)
 968                                .x_for_index(align_to.column() as usize)
 969                        };
 970
 971                    cx.render(&editor, |_, cx| {
 972                        block.render(&mut BlockContext {
 973                            cx,
 974                            anchor_x,
 975                            gutter_padding,
 976                            line_height,
 977                            scroll_x,
 978                            gutter_width,
 979                            em_width,
 980                        })
 981                    })
 982                }
 983                TransformBlock::ExcerptHeader {
 984                    key,
 985                    buffer,
 986                    range,
 987                    starts_new_buffer,
 988                    ..
 989                } => {
 990                    let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
 991                        let jump_position = range
 992                            .primary
 993                            .as_ref()
 994                            .map_or(range.context.start, |primary| primary.start);
 995                        let jump_action = crate::Jump {
 996                            path: ProjectPath {
 997                                worktree_id: file.worktree_id(cx),
 998                                path: file.path.clone(),
 999                            },
1000                            position: language::ToPoint::to_point(&jump_position, buffer),
1001                            anchor: jump_position,
1002                        };
1003
1004                        enum JumpIcon {}
1005                        cx.render(&editor, |_, cx| {
1006                            MouseEventHandler::new::<JumpIcon, _, _>(*key, cx, |state, _| {
1007                                let style = style.jump_icon.style_for(state, false);
1008                                Svg::new("icons/arrow_up_right_8.svg")
1009                                    .with_color(style.color)
1010                                    .constrained()
1011                                    .with_width(style.icon_width)
1012                                    .aligned()
1013                                    .contained()
1014                                    .with_style(style.container)
1015                                    .constrained()
1016                                    .with_width(style.button_width)
1017                                    .with_height(style.button_width)
1018                                    .boxed()
1019                            })
1020                            .with_cursor_style(CursorStyle::PointingHand)
1021                            .on_click(MouseButton::Left, move |_, cx| {
1022                                cx.dispatch_action(jump_action.clone())
1023                            })
1024                            .with_tooltip::<JumpIcon, _>(
1025                                *key,
1026                                "Jump to Buffer".to_string(),
1027                                Some(Box::new(crate::OpenExcerpts)),
1028                                tooltip_style.clone(),
1029                                cx,
1030                            )
1031                            .aligned()
1032                            .flex_float()
1033                            .boxed()
1034                        })
1035                    });
1036
1037                    if *starts_new_buffer {
1038                        let style = &self.style.diagnostic_path_header;
1039                        let font_size =
1040                            (style.text_scale_factor * self.style.text.font_size).round();
1041
1042                        let mut filename = None;
1043                        let mut parent_path = None;
1044                        if let Some(file) = buffer.file() {
1045                            let path = file.path();
1046                            filename = path.file_name().map(|f| f.to_string_lossy().to_string());
1047                            parent_path =
1048                                path.parent().map(|p| p.to_string_lossy().to_string() + "/");
1049                        }
1050
1051                        Flex::row()
1052                            .with_child(
1053                                Label::new(
1054                                    filename.unwrap_or_else(|| "untitled".to_string()),
1055                                    style.filename.text.clone().with_font_size(font_size),
1056                                )
1057                                .contained()
1058                                .with_style(style.filename.container)
1059                                .aligned()
1060                                .boxed(),
1061                            )
1062                            .with_children(parent_path.map(|path| {
1063                                Label::new(path, style.path.text.clone().with_font_size(font_size))
1064                                    .contained()
1065                                    .with_style(style.path.container)
1066                                    .aligned()
1067                                    .boxed()
1068                            }))
1069                            .with_children(jump_icon)
1070                            .contained()
1071                            .with_style(style.container)
1072                            .with_padding_left(gutter_padding)
1073                            .with_padding_right(gutter_padding)
1074                            .expanded()
1075                            .named("path header block")
1076                    } else {
1077                        let text_style = self.style.text.clone();
1078                        Flex::row()
1079                            .with_child(Label::new("".to_string(), text_style).boxed())
1080                            .with_children(jump_icon)
1081                            .contained()
1082                            .with_padding_left(gutter_padding)
1083                            .with_padding_right(gutter_padding)
1084                            .expanded()
1085                            .named("collapsed context")
1086                    }
1087                }
1088            };
1089
1090            element.layout(
1091                SizeConstraint {
1092                    min: Vector2F::zero(),
1093                    max: vec2f(width, block.height() as f32 * line_height),
1094                },
1095                cx,
1096            );
1097            element
1098        };
1099
1100        let mut fixed_block_max_width = 0f32;
1101        let mut blocks = Vec::new();
1102        for (row, block) in fixed_blocks {
1103            let element = render_block(block, f32::INFINITY);
1104            fixed_block_max_width = fixed_block_max_width.max(element.size().x() + em_width);
1105            blocks.push(BlockLayout {
1106                row,
1107                element,
1108                style: BlockStyle::Fixed,
1109            });
1110        }
1111        for (row, block) in non_fixed_blocks {
1112            let style = match block {
1113                TransformBlock::Custom(block) => block.style(),
1114                TransformBlock::ExcerptHeader { .. } => BlockStyle::Sticky,
1115            };
1116            let width = match style {
1117                BlockStyle::Sticky => editor_width,
1118                BlockStyle::Flex => editor_width
1119                    .max(fixed_block_max_width)
1120                    .max(gutter_width + scroll_width),
1121                BlockStyle::Fixed => unreachable!(),
1122            };
1123            let element = render_block(block, width);
1124            blocks.push(BlockLayout {
1125                row,
1126                element,
1127                style,
1128            });
1129        }
1130        (
1131            scroll_width.max(fixed_block_max_width - gutter_width),
1132            blocks,
1133        )
1134    }
1135}
1136
1137impl Element for EditorElement {
1138    type LayoutState = LayoutState;
1139    type PaintState = PaintState;
1140
1141    fn layout(
1142        &mut self,
1143        constraint: SizeConstraint,
1144        cx: &mut LayoutContext,
1145    ) -> (Vector2F, Self::LayoutState) {
1146        let mut size = constraint.max;
1147        if size.x().is_infinite() {
1148            unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
1149        }
1150
1151        let snapshot = self.snapshot(cx.app);
1152        let style = self.style.clone();
1153        let line_height = style.text.line_height(cx.font_cache);
1154
1155        let gutter_padding;
1156        let gutter_width;
1157        let gutter_margin;
1158        if snapshot.mode == EditorMode::Full {
1159            gutter_padding = style.text.em_width(cx.font_cache) * style.gutter_padding_factor;
1160            gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
1161            gutter_margin = -style.text.descent(cx.font_cache);
1162        } else {
1163            gutter_padding = 0.0;
1164            gutter_width = 0.0;
1165            gutter_margin = 0.0;
1166        };
1167
1168        let text_width = size.x() - gutter_width;
1169        let em_width = style.text.em_width(cx.font_cache);
1170        let em_advance = style.text.em_advance(cx.font_cache);
1171        let overscroll = vec2f(em_width, 0.);
1172        let snapshot = self.update_view(cx.app, |view, cx| {
1173            let wrap_width = match view.soft_wrap_mode(cx) {
1174                SoftWrap::None => Some((MAX_LINE_LEN / 2) as f32 * em_advance),
1175                SoftWrap::EditorWidth => {
1176                    Some(text_width - gutter_margin - overscroll.x() - em_width)
1177                }
1178                SoftWrap::Column(column) => Some(column as f32 * em_advance),
1179            };
1180
1181            if view.set_wrap_width(wrap_width, cx) {
1182                view.snapshot(cx)
1183            } else {
1184                snapshot
1185            }
1186        });
1187
1188        let scroll_height = (snapshot.max_point().row() + 1) as f32 * line_height;
1189        if let EditorMode::AutoHeight { max_lines } = snapshot.mode {
1190            size.set_y(
1191                scroll_height
1192                    .min(constraint.max_along(Axis::Vertical))
1193                    .max(constraint.min_along(Axis::Vertical))
1194                    .min(line_height * max_lines as f32),
1195            )
1196        } else if let EditorMode::SingleLine = snapshot.mode {
1197            size.set_y(
1198                line_height
1199                    .min(constraint.max_along(Axis::Vertical))
1200                    .max(constraint.min_along(Axis::Vertical)),
1201            )
1202        } else if size.y().is_infinite() {
1203            size.set_y(scroll_height);
1204        }
1205        let gutter_size = vec2f(gutter_width, size.y());
1206        let text_size = vec2f(text_width, size.y());
1207
1208        let (autoscroll_horizontally, mut snapshot) = self.update_view(cx.app, |view, cx| {
1209            let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx);
1210            let snapshot = view.snapshot(cx);
1211            (autoscroll_horizontally, snapshot)
1212        });
1213
1214        let scroll_position = snapshot.scroll_position();
1215        // The scroll position is a fractional point, the whole number of which represents
1216        // the top of the window in terms of display rows.
1217        let start_row = scroll_position.y() as u32;
1218        let scroll_top = scroll_position.y() * line_height;
1219
1220        // Add 1 to ensure selections bleed off screen
1221        let end_row = 1 + cmp::min(
1222            ((scroll_top + size.y()) / line_height).ceil() as u32,
1223            snapshot.max_point().row(),
1224        );
1225
1226        let start_anchor = if start_row == 0 {
1227            Anchor::min()
1228        } else {
1229            snapshot
1230                .buffer_snapshot
1231                .anchor_before(DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left))
1232        };
1233        let end_anchor = if end_row > snapshot.max_point().row() {
1234            Anchor::max()
1235        } else {
1236            snapshot
1237                .buffer_snapshot
1238                .anchor_before(DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right))
1239        };
1240
1241        let mut selections: Vec<(ReplicaId, Vec<SelectionLayout>)> = Vec::new();
1242        let mut active_rows = BTreeMap::new();
1243        let mut highlighted_rows = None;
1244        let mut highlighted_ranges = Vec::new();
1245        self.update_view(cx.app, |view, cx| {
1246            let display_map = view.display_map.update(cx, |map, cx| map.snapshot(cx));
1247
1248            highlighted_rows = view.highlighted_rows();
1249            let theme = cx.global::<Settings>().theme.as_ref();
1250            highlighted_ranges = view.background_highlights_in_range(
1251                start_anchor.clone()..end_anchor.clone(),
1252                &display_map,
1253                theme,
1254            );
1255
1256            let mut remote_selections = HashMap::default();
1257            for (replica_id, line_mode, selection) in display_map
1258                .buffer_snapshot
1259                .remote_selections_in_range(&(start_anchor.clone()..end_anchor.clone()))
1260            {
1261                // The local selections match the leader's selections.
1262                if Some(replica_id) == view.leader_replica_id {
1263                    continue;
1264                }
1265                remote_selections
1266                    .entry(replica_id)
1267                    .or_insert(Vec::new())
1268                    .push(SelectionLayout::new(selection, line_mode, &display_map));
1269            }
1270            selections.extend(remote_selections);
1271
1272            if view.show_local_selections {
1273                let mut local_selections = view
1274                    .selections
1275                    .disjoint_in_range(start_anchor..end_anchor, cx);
1276                local_selections.extend(view.selections.pending(cx));
1277                for selection in &local_selections {
1278                    let is_empty = selection.start == selection.end;
1279                    let selection_start = snapshot.prev_line_boundary(selection.start).1;
1280                    let selection_end = snapshot.next_line_boundary(selection.end).1;
1281                    for row in cmp::max(selection_start.row(), start_row)
1282                        ..=cmp::min(selection_end.row(), end_row)
1283                    {
1284                        let contains_non_empty_selection =
1285                            active_rows.entry(row).or_insert(!is_empty);
1286                        *contains_non_empty_selection |= !is_empty;
1287                    }
1288                }
1289
1290                // Render the local selections in the leader's color when following.
1291                let local_replica_id = view.leader_replica_id.unwrap_or(view.replica_id(cx));
1292
1293                selections.push((
1294                    local_replica_id,
1295                    local_selections
1296                        .into_iter()
1297                        .map(|selection| {
1298                            SelectionLayout::new(selection, view.selections.line_mode, &display_map)
1299                        })
1300                        .collect(),
1301                ));
1302            }
1303        });
1304
1305        let line_number_layouts =
1306            self.layout_line_numbers(start_row..end_row, &active_rows, &snapshot, cx);
1307
1308        let mut max_visible_line_width = 0.0;
1309        let line_layouts = self.layout_lines(start_row..end_row, &snapshot, cx);
1310        for line in &line_layouts {
1311            if line.width() > max_visible_line_width {
1312                max_visible_line_width = line.width();
1313            }
1314        }
1315
1316        let style = self.style.clone();
1317        let longest_line_width = layout_line(
1318            snapshot.longest_row(),
1319            &snapshot,
1320            &style,
1321            cx.text_layout_cache,
1322        )
1323        .width();
1324        let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.x();
1325        let em_width = style.text.em_width(cx.font_cache);
1326        let (scroll_width, blocks) = self.layout_blocks(
1327            start_row..end_row,
1328            &snapshot,
1329            size.x(),
1330            scroll_width,
1331            gutter_padding,
1332            gutter_width,
1333            em_width,
1334            gutter_width + gutter_margin,
1335            line_height,
1336            &style,
1337            &line_layouts,
1338            cx,
1339        );
1340
1341        let max_row = snapshot.max_point().row();
1342        let scroll_max = vec2f(
1343            ((scroll_width - text_size.x()) / em_width).max(0.0),
1344            max_row.saturating_sub(1) as f32,
1345        );
1346
1347        self.update_view(cx.app, |view, cx| {
1348            let clamped = view.clamp_scroll_left(scroll_max.x());
1349            let autoscrolled;
1350            if autoscroll_horizontally {
1351                autoscrolled = view.autoscroll_horizontally(
1352                    start_row,
1353                    text_size.x(),
1354                    scroll_width,
1355                    em_width,
1356                    &line_layouts,
1357                    cx,
1358                );
1359            } else {
1360                autoscrolled = false;
1361            }
1362
1363            if clamped || autoscrolled {
1364                snapshot = view.snapshot(cx);
1365            }
1366        });
1367
1368        let mut context_menu = None;
1369        let mut code_actions_indicator = None;
1370        let mut hover = None;
1371        cx.render(&self.view.upgrade(cx).unwrap(), |view, cx| {
1372            let newest_selection_head = view
1373                .selections
1374                .newest::<usize>(cx)
1375                .head()
1376                .to_display_point(&snapshot);
1377
1378            let style = view.style(cx);
1379            if (start_row..end_row).contains(&newest_selection_head.row()) {
1380                if view.context_menu_visible() {
1381                    context_menu =
1382                        view.render_context_menu(newest_selection_head, style.clone(), cx);
1383                }
1384
1385                code_actions_indicator = view
1386                    .render_code_actions_indicator(&style, cx)
1387                    .map(|indicator| (newest_selection_head.row(), indicator));
1388            }
1389
1390            let visible_rows = start_row..start_row + line_layouts.len() as u32;
1391            hover = view.hover_state.render(&snapshot, &style, visible_rows, cx);
1392        });
1393
1394        if let Some((_, context_menu)) = context_menu.as_mut() {
1395            context_menu.layout(
1396                SizeConstraint {
1397                    min: Vector2F::zero(),
1398                    max: vec2f(
1399                        cx.window_size.x() * 0.7,
1400                        (12. * line_height).min((size.y() - line_height) / 2.),
1401                    ),
1402                },
1403                cx,
1404            );
1405        }
1406
1407        if let Some((_, indicator)) = code_actions_indicator.as_mut() {
1408            indicator.layout(
1409                SizeConstraint::strict_along(Axis::Vertical, line_height * 0.618),
1410                cx,
1411            );
1412        }
1413
1414        if let Some((_, hover_popovers)) = hover.as_mut() {
1415            for hover_popover in hover_popovers.iter_mut() {
1416                hover_popover.layout(
1417                    SizeConstraint {
1418                        min: Vector2F::zero(),
1419                        max: vec2f(
1420                            (120. * em_width) // Default size
1421                                .min(size.x() / 2.) // Shrink to half of the editor width
1422                                .max(MIN_POPOVER_CHARACTER_WIDTH * em_width), // Apply minimum width of 20 characters
1423                            (16. * line_height) // Default size
1424                                .min(size.y() / 2.) // Shrink to half of the editor height
1425                                .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
1426                        ),
1427                    },
1428                    cx,
1429                );
1430            }
1431        }
1432
1433        (
1434            size,
1435            LayoutState {
1436                size,
1437                scroll_max,
1438                gutter_size,
1439                gutter_padding,
1440                text_size,
1441                gutter_margin,
1442                snapshot,
1443                active_rows,
1444                highlighted_rows,
1445                highlighted_ranges,
1446                line_layouts,
1447                line_number_layouts,
1448                blocks,
1449                line_height,
1450                em_width,
1451                em_advance,
1452                selections,
1453                context_menu,
1454                code_actions_indicator,
1455                hover_popovers: hover,
1456            },
1457        )
1458    }
1459
1460    fn paint(
1461        &mut self,
1462        bounds: RectF,
1463        visible_bounds: RectF,
1464        layout: &mut Self::LayoutState,
1465        cx: &mut PaintContext,
1466    ) -> Self::PaintState {
1467        cx.scene.push_layer(Some(bounds));
1468
1469        let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
1470        let text_bounds = RectF::new(
1471            bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
1472            layout.text_size,
1473        );
1474
1475        let mut paint_state = PaintState {
1476            bounds,
1477            gutter_bounds,
1478            text_bounds,
1479            context_menu_bounds: None,
1480            hover_popover_bounds: Default::default(),
1481        };
1482
1483        self.paint_background(gutter_bounds, text_bounds, layout, cx);
1484        if layout.gutter_size.x() > 0. {
1485            self.paint_gutter(gutter_bounds, visible_bounds, layout, cx);
1486        }
1487        self.paint_text(text_bounds, visible_bounds, layout, &mut paint_state, cx);
1488
1489        if !layout.blocks.is_empty() {
1490            cx.scene.push_layer(Some(bounds));
1491            self.paint_blocks(bounds, visible_bounds, layout, cx);
1492            cx.scene.pop_layer();
1493        }
1494
1495        cx.scene.pop_layer();
1496
1497        paint_state
1498    }
1499
1500    fn dispatch_event(
1501        &mut self,
1502        event: &Event,
1503        _: RectF,
1504        _: RectF,
1505        layout: &mut LayoutState,
1506        paint: &mut PaintState,
1507        cx: &mut EventContext,
1508    ) -> bool {
1509        if let Some((_, context_menu)) = &mut layout.context_menu {
1510            if context_menu.dispatch_event(event, cx) {
1511                return true;
1512            }
1513        }
1514
1515        if let Some((_, indicator)) = &mut layout.code_actions_indicator {
1516            if indicator.dispatch_event(event, cx) {
1517                return true;
1518            }
1519        }
1520
1521        if let Some((_, popover_elements)) = &mut layout.hover_popovers {
1522            for popover_element in popover_elements.iter_mut() {
1523                if popover_element.dispatch_event(event, cx) {
1524                    return true;
1525                }
1526            }
1527        }
1528
1529        for block in &mut layout.blocks {
1530            if block.element.dispatch_event(event, cx) {
1531                return true;
1532            }
1533        }
1534
1535        match event {
1536            Event::MouseDown(MouseButtonEvent {
1537                button: MouseButton::Left,
1538                position,
1539                cmd,
1540                alt,
1541                shift,
1542                click_count,
1543                ..
1544            }) => self.mouse_down(
1545                *position,
1546                *cmd,
1547                *alt,
1548                *shift,
1549                *click_count,
1550                layout,
1551                paint,
1552                cx,
1553            ),
1554
1555            Event::MouseDown(MouseButtonEvent {
1556                button: MouseButton::Right,
1557                position,
1558                ..
1559            }) => self.mouse_right_down(*position, layout, paint, cx),
1560
1561            Event::MouseUp(MouseButtonEvent {
1562                button: MouseButton::Left,
1563                position,
1564                ..
1565            }) => self.mouse_up(*position, cx),
1566
1567            Event::MouseMoved(MouseMovedEvent {
1568                pressed_button: Some(MouseButton::Left),
1569                position,
1570                ..
1571            }) => self.mouse_dragged(*position, layout, paint, cx),
1572
1573            Event::ScrollWheel(ScrollWheelEvent {
1574                position,
1575                delta,
1576                precise,
1577            }) => self.scroll(*position, *delta, *precise, layout, paint, cx),
1578
1579            &Event::ModifiersChanged(event) => self.modifiers_changed(event, cx),
1580
1581            &Event::MouseMoved(event) => self.mouse_moved(event, layout, paint, cx),
1582
1583            _ => false,
1584        }
1585    }
1586
1587    fn rect_for_text_range(
1588        &self,
1589        range_utf16: Range<usize>,
1590        bounds: RectF,
1591        _: RectF,
1592        layout: &Self::LayoutState,
1593        _: &Self::PaintState,
1594        _: &gpui::MeasurementContext,
1595    ) -> Option<RectF> {
1596        let text_bounds = RectF::new(
1597            bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
1598            layout.text_size,
1599        );
1600        let content_origin = text_bounds.origin() + vec2f(layout.gutter_margin, 0.);
1601        let scroll_position = layout.snapshot.scroll_position();
1602        let start_row = scroll_position.y() as u32;
1603        let scroll_top = scroll_position.y() * layout.line_height;
1604        let scroll_left = scroll_position.x() * layout.em_width;
1605
1606        let range_start =
1607            OffsetUtf16(range_utf16.start).to_display_point(&layout.snapshot.display_snapshot);
1608        if range_start.row() < start_row {
1609            return None;
1610        }
1611
1612        let line = layout
1613            .line_layouts
1614            .get((range_start.row() - start_row) as usize)?;
1615        let range_start_x = line.x_for_index(range_start.column() as usize);
1616        let range_start_y = range_start.row() as f32 * layout.line_height;
1617        Some(RectF::new(
1618            content_origin + vec2f(range_start_x, range_start_y + layout.line_height)
1619                - vec2f(scroll_left, scroll_top),
1620            vec2f(layout.em_width, layout.line_height),
1621        ))
1622    }
1623
1624    fn debug(
1625        &self,
1626        bounds: RectF,
1627        _: &Self::LayoutState,
1628        _: &Self::PaintState,
1629        _: &gpui::DebugContext,
1630    ) -> json::Value {
1631        json!({
1632            "type": "BufferElement",
1633            "bounds": bounds.to_json()
1634        })
1635    }
1636}
1637
1638pub struct LayoutState {
1639    size: Vector2F,
1640    scroll_max: Vector2F,
1641    gutter_size: Vector2F,
1642    gutter_padding: f32,
1643    gutter_margin: f32,
1644    text_size: Vector2F,
1645    snapshot: EditorSnapshot,
1646    active_rows: BTreeMap<u32, bool>,
1647    highlighted_rows: Option<Range<u32>>,
1648    line_layouts: Vec<text_layout::Line>,
1649    line_number_layouts: Vec<Option<text_layout::Line>>,
1650    blocks: Vec<BlockLayout>,
1651    line_height: f32,
1652    em_width: f32,
1653    em_advance: f32,
1654    highlighted_ranges: Vec<(Range<DisplayPoint>, Color)>,
1655    selections: Vec<(ReplicaId, Vec<SelectionLayout>)>,
1656    context_menu: Option<(DisplayPoint, ElementBox)>,
1657    code_actions_indicator: Option<(u32, ElementBox)>,
1658    hover_popovers: Option<(DisplayPoint, Vec<ElementBox>)>,
1659}
1660
1661struct BlockLayout {
1662    row: u32,
1663    element: ElementBox,
1664    style: BlockStyle,
1665}
1666
1667fn layout_line(
1668    row: u32,
1669    snapshot: &EditorSnapshot,
1670    style: &EditorStyle,
1671    layout_cache: &TextLayoutCache,
1672) -> text_layout::Line {
1673    let mut line = snapshot.line(row);
1674
1675    if line.len() > MAX_LINE_LEN {
1676        let mut len = MAX_LINE_LEN;
1677        while !line.is_char_boundary(len) {
1678            len -= 1;
1679        }
1680
1681        line.truncate(len);
1682    }
1683
1684    layout_cache.layout_str(
1685        &line,
1686        style.text.font_size,
1687        &[(
1688            snapshot.line_len(row) as usize,
1689            RunStyle {
1690                font_id: style.text.font_id,
1691                color: Color::black(),
1692                underline: Default::default(),
1693            },
1694        )],
1695    )
1696}
1697
1698pub struct PaintState {
1699    bounds: RectF,
1700    gutter_bounds: RectF,
1701    text_bounds: RectF,
1702    context_menu_bounds: Option<RectF>,
1703    hover_popover_bounds: Vec<RectF>,
1704}
1705
1706impl PaintState {
1707    /// Returns two display points:
1708    /// 1. The nearest *valid* position in the editor
1709    /// 2. An unclipped, potentially *invalid* position that maps directly to
1710    ///    the given pixel position.
1711    fn point_for_position(
1712        &self,
1713        snapshot: &EditorSnapshot,
1714        layout: &LayoutState,
1715        position: Vector2F,
1716    ) -> (DisplayPoint, DisplayPoint) {
1717        let scroll_position = snapshot.scroll_position();
1718        let position = position - self.text_bounds.origin();
1719        let y = position.y().max(0.0).min(layout.size.y());
1720        let x = position.x() + (scroll_position.x() * layout.em_width);
1721        let row = (y / layout.line_height + scroll_position.y()) as u32;
1722        let (column, x_overshoot) = if let Some(line) = layout
1723            .line_layouts
1724            .get(row as usize - scroll_position.y() as usize)
1725        {
1726            if let Some(ix) = line.index_for_x(x) {
1727                (ix as u32, 0.0)
1728            } else {
1729                (line.len() as u32, 0f32.max(x - line.width()))
1730            }
1731        } else {
1732            (0, x)
1733        };
1734
1735        let mut target_point = DisplayPoint::new(row, column);
1736        let point = snapshot.clip_point(target_point, Bias::Left);
1737        *target_point.column_mut() += (x_overshoot / layout.em_advance) as u32;
1738
1739        (point, target_point)
1740    }
1741}
1742
1743#[derive(Copy, Clone, PartialEq, Eq, Debug)]
1744pub enum CursorShape {
1745    Bar,
1746    Block,
1747    Underscore,
1748}
1749
1750impl Default for CursorShape {
1751    fn default() -> Self {
1752        CursorShape::Bar
1753    }
1754}
1755
1756#[derive(Debug)]
1757pub struct Cursor {
1758    origin: Vector2F,
1759    block_width: f32,
1760    line_height: f32,
1761    color: Color,
1762    shape: CursorShape,
1763    block_text: Option<Line>,
1764}
1765
1766impl Cursor {
1767    pub fn new(
1768        origin: Vector2F,
1769        block_width: f32,
1770        line_height: f32,
1771        color: Color,
1772        shape: CursorShape,
1773        block_text: Option<Line>,
1774    ) -> Cursor {
1775        Cursor {
1776            origin,
1777            block_width,
1778            line_height,
1779            color,
1780            shape,
1781            block_text,
1782        }
1783    }
1784
1785    pub fn bounding_rect(&self, origin: Vector2F) -> RectF {
1786        RectF::new(
1787            self.origin + origin,
1788            vec2f(self.block_width, self.line_height),
1789        )
1790    }
1791
1792    pub fn paint(&self, origin: Vector2F, cx: &mut PaintContext) {
1793        let bounds = match self.shape {
1794            CursorShape::Bar => RectF::new(self.origin + origin, vec2f(2.0, self.line_height)),
1795            CursorShape::Block => RectF::new(
1796                self.origin + origin,
1797                vec2f(self.block_width, self.line_height),
1798            ),
1799            CursorShape::Underscore => RectF::new(
1800                self.origin + origin + Vector2F::new(0.0, self.line_height - 2.0),
1801                vec2f(self.block_width, 2.0),
1802            ),
1803        };
1804
1805        cx.scene.push_quad(Quad {
1806            bounds,
1807            background: Some(self.color),
1808            border: Border::new(0., Color::black()),
1809            corner_radius: 0.,
1810        });
1811
1812        if let Some(block_text) = &self.block_text {
1813            block_text.paint(self.origin + origin, bounds, self.line_height, cx);
1814        }
1815    }
1816}
1817
1818#[derive(Debug)]
1819pub struct HighlightedRange {
1820    pub start_y: f32,
1821    pub line_height: f32,
1822    pub lines: Vec<HighlightedRangeLine>,
1823    pub color: Color,
1824    pub corner_radius: f32,
1825}
1826
1827#[derive(Debug)]
1828pub struct HighlightedRangeLine {
1829    pub start_x: f32,
1830    pub end_x: f32,
1831}
1832
1833impl HighlightedRange {
1834    pub fn paint(&self, bounds: RectF, scene: &mut Scene) {
1835        if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
1836            self.paint_lines(self.start_y, &self.lines[0..1], bounds, scene);
1837            self.paint_lines(
1838                self.start_y + self.line_height,
1839                &self.lines[1..],
1840                bounds,
1841                scene,
1842            );
1843        } else {
1844            self.paint_lines(self.start_y, &self.lines, bounds, scene);
1845        }
1846    }
1847
1848    fn paint_lines(
1849        &self,
1850        start_y: f32,
1851        lines: &[HighlightedRangeLine],
1852        bounds: RectF,
1853        scene: &mut Scene,
1854    ) {
1855        if lines.is_empty() {
1856            return;
1857        }
1858
1859        let mut path = PathBuilder::new();
1860        let first_line = lines.first().unwrap();
1861        let last_line = lines.last().unwrap();
1862
1863        let first_top_left = vec2f(first_line.start_x, start_y);
1864        let first_top_right = vec2f(first_line.end_x, start_y);
1865
1866        let curve_height = vec2f(0., self.corner_radius);
1867        let curve_width = |start_x: f32, end_x: f32| {
1868            let max = (end_x - start_x) / 2.;
1869            let width = if max < self.corner_radius {
1870                max
1871            } else {
1872                self.corner_radius
1873            };
1874
1875            vec2f(width, 0.)
1876        };
1877
1878        let top_curve_width = curve_width(first_line.start_x, first_line.end_x);
1879        path.reset(first_top_right - top_curve_width);
1880        path.curve_to(first_top_right + curve_height, first_top_right);
1881
1882        let mut iter = lines.iter().enumerate().peekable();
1883        while let Some((ix, line)) = iter.next() {
1884            let bottom_right = vec2f(line.end_x, start_y + (ix + 1) as f32 * self.line_height);
1885
1886            if let Some((_, next_line)) = iter.peek() {
1887                let next_top_right = vec2f(next_line.end_x, bottom_right.y());
1888
1889                match next_top_right.x().partial_cmp(&bottom_right.x()).unwrap() {
1890                    Ordering::Equal => {
1891                        path.line_to(bottom_right);
1892                    }
1893                    Ordering::Less => {
1894                        let curve_width = curve_width(next_top_right.x(), bottom_right.x());
1895                        path.line_to(bottom_right - curve_height);
1896                        if self.corner_radius > 0. {
1897                            path.curve_to(bottom_right - curve_width, bottom_right);
1898                        }
1899                        path.line_to(next_top_right + curve_width);
1900                        if self.corner_radius > 0. {
1901                            path.curve_to(next_top_right + curve_height, next_top_right);
1902                        }
1903                    }
1904                    Ordering::Greater => {
1905                        let curve_width = curve_width(bottom_right.x(), next_top_right.x());
1906                        path.line_to(bottom_right - curve_height);
1907                        if self.corner_radius > 0. {
1908                            path.curve_to(bottom_right + curve_width, bottom_right);
1909                        }
1910                        path.line_to(next_top_right - curve_width);
1911                        if self.corner_radius > 0. {
1912                            path.curve_to(next_top_right + curve_height, next_top_right);
1913                        }
1914                    }
1915                }
1916            } else {
1917                let curve_width = curve_width(line.start_x, line.end_x);
1918                path.line_to(bottom_right - curve_height);
1919                if self.corner_radius > 0. {
1920                    path.curve_to(bottom_right - curve_width, bottom_right);
1921                }
1922
1923                let bottom_left = vec2f(line.start_x, bottom_right.y());
1924                path.line_to(bottom_left + curve_width);
1925                if self.corner_radius > 0. {
1926                    path.curve_to(bottom_left - curve_height, bottom_left);
1927                }
1928            }
1929        }
1930
1931        if first_line.start_x > last_line.start_x {
1932            let curve_width = curve_width(last_line.start_x, first_line.start_x);
1933            let second_top_left = vec2f(last_line.start_x, start_y + self.line_height);
1934            path.line_to(second_top_left + curve_height);
1935            if self.corner_radius > 0. {
1936                path.curve_to(second_top_left + curve_width, second_top_left);
1937            }
1938            let first_bottom_left = vec2f(first_line.start_x, second_top_left.y());
1939            path.line_to(first_bottom_left - curve_width);
1940            if self.corner_radius > 0. {
1941                path.curve_to(first_bottom_left - curve_height, first_bottom_left);
1942            }
1943        }
1944
1945        path.line_to(first_top_left + curve_height);
1946        if self.corner_radius > 0. {
1947            path.curve_to(first_top_left + top_curve_width, first_top_left);
1948        }
1949        path.line_to(first_top_right - top_curve_width);
1950
1951        scene.push_path(path.build(self.color, Some(bounds)));
1952    }
1953}
1954
1955fn scale_vertical_mouse_autoscroll_delta(delta: f32) -> f32 {
1956    delta.powf(1.5) / 100.0
1957}
1958
1959fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
1960    delta.powf(1.2) / 300.0
1961}
1962
1963#[cfg(test)]
1964mod tests {
1965    use std::sync::Arc;
1966
1967    use super::*;
1968    use crate::{
1969        display_map::{BlockDisposition, BlockProperties},
1970        Editor, MultiBuffer,
1971    };
1972    use settings::Settings;
1973    use util::test::sample_text;
1974
1975    #[gpui::test]
1976    fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) {
1977        cx.set_global(Settings::test(cx));
1978        let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
1979        let (window_id, editor) = cx.add_window(Default::default(), |cx| {
1980            Editor::new(EditorMode::Full, buffer, None, None, cx)
1981        });
1982        let element = EditorElement::new(
1983            editor.downgrade(),
1984            editor.read(cx).style(cx),
1985            CursorShape::Bar,
1986        );
1987
1988        let layouts = editor.update(cx, |editor, cx| {
1989            let snapshot = editor.snapshot(cx);
1990            let mut presenter = cx.build_presenter(window_id, 30.);
1991            let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
1992            element.layout_line_numbers(0..6, &Default::default(), &snapshot, &mut layout_cx)
1993        });
1994        assert_eq!(layouts.len(), 6);
1995    }
1996
1997    #[gpui::test]
1998    fn test_layout_with_placeholder_text_and_blocks(cx: &mut gpui::MutableAppContext) {
1999        cx.set_global(Settings::test(cx));
2000        let buffer = MultiBuffer::build_simple("", cx);
2001        let (window_id, editor) = cx.add_window(Default::default(), |cx| {
2002            Editor::new(EditorMode::Full, buffer, None, None, cx)
2003        });
2004
2005        editor.update(cx, |editor, cx| {
2006            editor.set_placeholder_text("hello", cx);
2007            editor.insert_blocks(
2008                [BlockProperties {
2009                    style: BlockStyle::Fixed,
2010                    disposition: BlockDisposition::Above,
2011                    height: 3,
2012                    position: Anchor::min(),
2013                    render: Arc::new(|_| Empty::new().boxed()),
2014                }],
2015                cx,
2016            );
2017
2018            // Blur the editor so that it displays placeholder text.
2019            cx.blur();
2020        });
2021
2022        let mut element = EditorElement::new(
2023            editor.downgrade(),
2024            editor.read(cx).style(cx),
2025            CursorShape::Bar,
2026        );
2027
2028        let mut scene = Scene::new(1.0);
2029        let mut presenter = cx.build_presenter(window_id, 30.);
2030        let mut layout_cx = presenter.build_layout_context(Vector2F::zero(), false, cx);
2031        let (size, mut state) = element.layout(
2032            SizeConstraint::new(vec2f(500., 500.), vec2f(500., 500.)),
2033            &mut layout_cx,
2034        );
2035
2036        assert_eq!(state.line_layouts.len(), 4);
2037        assert_eq!(
2038            state
2039                .line_number_layouts
2040                .iter()
2041                .map(Option::is_some)
2042                .collect::<Vec<_>>(),
2043            &[false, false, false, true]
2044        );
2045
2046        // Don't panic.
2047        let bounds = RectF::new(Default::default(), size);
2048        let mut paint_cx = presenter.build_paint_context(&mut scene, bounds.size(), cx);
2049        element.paint(bounds, bounds, &mut state, &mut paint_cx);
2050    }
2051}