element.rs

   1use crate::{
   2    display_map::{BlockStyle, DisplaySnapshot, FoldStatus, HighlightedChunk, ToDisplayPoint},
   3    editor_settings::ShowScrollbar,
   4    git::{diff_hunk_to_display, DisplayDiffHunk},
   5    hover_popover::hover_at,
   6    link_go_to_definition::{
   7        update_go_to_definition_link, update_inlay_link_and_hover_points, GoToDefinitionTrigger,
   8    },
   9    scroll::scroll_amount::ScrollAmount,
  10    CursorShape, DisplayPoint, Editor, EditorMode, EditorSettings, EditorSnapshot, EditorStyle,
  11    HalfPageDown, HalfPageUp, LineDown, LineUp, MoveDown, PageDown, PageUp, Point, Selection,
  12    SoftWrap, ToPoint, MAX_LINE_LEN,
  13};
  14use anyhow::Result;
  15use collections::{BTreeMap, HashMap};
  16use gpui::{
  17    black, hsla, point, px, relative, size, transparent_black, Action, AnyElement,
  18    BorrowAppContext, BorrowWindow, Bounds, ContentMask, Corners, DispatchContext, DispatchPhase,
  19    Edges, Element, ElementId, Entity, Hsla, KeyDownEvent, KeyListener, KeyMatch, Line, Modifiers,
  20    MouseMoveEvent, Pixels, ScrollWheelEvent, ShapedGlyph, Size, StatefulInteraction, Style,
  21    TextRun, TextStyle, TextSystem, ViewContext, WindowContext,
  22};
  23use itertools::Itertools;
  24use language::language_settings::ShowWhitespaceSetting;
  25use multi_buffer::Anchor;
  26use project::project_settings::{GitGutterSetting, ProjectSettings};
  27use settings::Settings;
  28use smallvec::SmallVec;
  29use std::{
  30    any::TypeId,
  31    borrow::Cow,
  32    cmp::{self, Ordering},
  33    fmt::Write,
  34    iter,
  35    ops::Range,
  36    sync::Arc,
  37};
  38use sum_tree::Bias;
  39use theme::{ActiveTheme, PlayerColor};
  40use util::ResultExt;
  41use workspace::item::Item;
  42
  43enum FoldMarkers {}
  44
  45struct SelectionLayout {
  46    head: DisplayPoint,
  47    cursor_shape: CursorShape,
  48    is_newest: bool,
  49    is_local: bool,
  50    range: Range<DisplayPoint>,
  51    active_rows: Range<u32>,
  52}
  53
  54impl SelectionLayout {
  55    fn new<T: ToPoint + ToDisplayPoint + Clone>(
  56        selection: Selection<T>,
  57        line_mode: bool,
  58        cursor_shape: CursorShape,
  59        map: &DisplaySnapshot,
  60        is_newest: bool,
  61        is_local: bool,
  62    ) -> Self {
  63        let point_selection = selection.map(|p| p.to_point(&map.buffer_snapshot));
  64        let display_selection = point_selection.map(|p| p.to_display_point(map));
  65        let mut range = display_selection.range();
  66        let mut head = display_selection.head();
  67        let mut active_rows = map.prev_line_boundary(point_selection.start).1.row()
  68            ..map.next_line_boundary(point_selection.end).1.row();
  69
  70        // vim visual line mode
  71        if line_mode {
  72            let point_range = map.expand_to_line(point_selection.range());
  73            range = point_range.start.to_display_point(map)..point_range.end.to_display_point(map);
  74        }
  75
  76        // any vim visual mode (including line mode)
  77        if cursor_shape == CursorShape::Block && !range.is_empty() && !selection.reversed {
  78            if head.column() > 0 {
  79                head = map.clip_point(DisplayPoint::new(head.row(), head.column() - 1), Bias::Left)
  80            } else if head.row() > 0 && head != map.max_point() {
  81                head = map.clip_point(
  82                    DisplayPoint::new(head.row() - 1, map.line_len(head.row() - 1)),
  83                    Bias::Left,
  84                );
  85                // updating range.end is a no-op unless you're cursor is
  86                // on the newline containing a multi-buffer divider
  87                // in which case the clip_point may have moved the head up
  88                // an additional row.
  89                range.end = DisplayPoint::new(head.row() + 1, 0);
  90                active_rows.end = head.row();
  91            }
  92        }
  93
  94        Self {
  95            head,
  96            cursor_shape,
  97            is_newest,
  98            is_local,
  99            range,
 100            active_rows,
 101        }
 102    }
 103}
 104
 105pub struct EditorElement {
 106    style: EditorStyle,
 107}
 108
 109impl EditorElement {
 110    pub fn new(style: EditorStyle) -> Self {
 111        Self { style }
 112    }
 113
 114    // fn attach_mouse_handlers(
 115    //     position_map: &Arc<PositionMap>,
 116    //     has_popovers: bool,
 117    //     visible_bounds: Bounds<Pixels>,
 118    //     text_bounds: Bounds<Pixels>,
 119    //     gutter_bounds: Bounds<Pixels>,
 120    //     bounds: Bounds<Pixels>,
 121    //     cx: &mut ViewContext<Editor>,
 122    // ) {
 123    //     enum EditorElementMouseHandlers {}
 124    //     let view_id = cx.view_id();
 125    //     cx.scene().push_mouse_region(
 126    //         MouseRegion::new::<EditorElementMouseHandlers>(view_id, view_id, visible_bounds)
 127    //             .on_down(MouseButton::Left, {
 128    //                 let position_map = position_map.clone();
 129    //                 move |event, editor, cx| {
 130    //                     if !Self::mouse_down(
 131    //                         editor,
 132    //                         event.platform_event,
 133    //                         position_map.as_ref(),
 134    //                         text_bounds,
 135    //                         gutter_bounds,
 136    //                         cx,
 137    //                     ) {
 138    //                         cx.propagate_event();
 139    //                     }
 140    //                 }
 141    //             })
 142    //             .on_down(MouseButton::Right, {
 143    //                 let position_map = position_map.clone();
 144    //                 move |event, editor, cx| {
 145    //                     if !Self::mouse_right_down(
 146    //                         editor,
 147    //                         event.position,
 148    //                         position_map.as_ref(),
 149    //                         text_bounds,
 150    //                         cx,
 151    //                     ) {
 152    //                         cx.propagate_event();
 153    //                     }
 154    //                 }
 155    //             })
 156    //             .on_up(MouseButton::Left, {
 157    //                 let position_map = position_map.clone();
 158    //                 move |event, editor, cx| {
 159    //                     if !Self::mouse_up(
 160    //                         editor,
 161    //                         event.position,
 162    //                         event.cmd,
 163    //                         event.shift,
 164    //                         event.alt,
 165    //                         position_map.as_ref(),
 166    //                         text_bounds,
 167    //                         cx,
 168    //                     ) {
 169    //                         cx.propagate_event()
 170    //                     }
 171    //                 }
 172    //             })
 173    //             .on_drag(MouseButton::Left, {
 174    //                 let position_map = position_map.clone();
 175    //                 move |event, editor, cx| {
 176    //                     if event.end {
 177    //                         return;
 178    //                     }
 179
 180    //                     if !Self::mouse_dragged(
 181    //                         editor,
 182    //                         event.platform_event,
 183    //                         position_map.as_ref(),
 184    //                         text_bounds,
 185    //                         cx,
 186    //                     ) {
 187    //                         cx.propagate_event()
 188    //                     }
 189    //                 }
 190    //             })
 191    //             .on_move({
 192    //                 let position_map = position_map.clone();
 193    //                 move |event, editor, cx| {
 194    //                     if !Self::mouse_moved(
 195    //                         editor,
 196    //                         event.platform_event,
 197    //                         &position_map,
 198    //                         text_bounds,
 199    //                         cx,
 200    //                     ) {
 201    //                         cx.propagate_event()
 202    //                     }
 203    //                 }
 204    //             })
 205    //             .on_move_out(move |_, editor: &mut Editor, cx| {
 206    //                 if has_popovers {
 207    //                     hide_hover(editor, cx);
 208    //                 }
 209    //             })
 210    //             .on_scroll({
 211    //                 let position_map = position_map.clone();
 212    //                 move |event, editor, cx| {
 213    //                     if !Self::scroll(
 214    //                         editor,
 215    //                         event.position,
 216    //                         *event.delta.raw(),
 217    //                         event.delta.precise(),
 218    //                         &position_map,
 219    //                         bounds,
 220    //                         cx,
 221    //                     ) {
 222    //                         cx.propagate_event()
 223    //                     }
 224    //                 }
 225    //             }),
 226    //     );
 227
 228    //     enum GutterHandlers {}
 229    //     let view_id = cx.view_id();
 230    //     let region_id = cx.view_id() + 1;
 231    //     cx.scene().push_mouse_region(
 232    //         MouseRegion::new::<GutterHandlers>(view_id, region_id, gutter_bounds).on_hover(
 233    //             |hover, editor: &mut Editor, cx| {
 234    //                 editor.gutter_hover(
 235    //                     &GutterHover {
 236    //                         hovered: hover.started,
 237    //                     },
 238    //                     cx,
 239    //                 );
 240    //             },
 241    //         ),
 242    //     )
 243    // }
 244
 245    // fn mouse_down(
 246    //     editor: &mut Editor,
 247    //     MouseButtonEvent {
 248    //         position,
 249    //         modifiers:
 250    //             Modifiers {
 251    //                 shift,
 252    //                 ctrl,
 253    //                 alt,
 254    //                 cmd,
 255    //                 ..
 256    //             },
 257    //         mut click_count,
 258    //         ..
 259    //     }: MouseButtonEvent,
 260    //     position_map: &PositionMap,
 261    //     text_bounds: Bounds<Pixels>,
 262    //     gutter_bounds: Bounds<Pixels>,
 263    //     cx: &mut EventContext<Editor>,
 264    // ) -> bool {
 265    //     if gutter_bounds.contains_point(position) {
 266    //         click_count = 3; // Simulate triple-click when clicking the gutter to select lines
 267    //     } else if !text_bounds.contains_point(position) {
 268    //         return false;
 269    //     }
 270
 271    //     let point_for_position = position_map.point_for_position(text_bounds, position);
 272    //     let position = point_for_position.previous_valid;
 273    //     if shift && alt {
 274    //         editor.select(
 275    //             SelectPhase::BeginColumnar {
 276    //                 position,
 277    //                 goal_column: point_for_position.exact_unclipped.column(),
 278    //             },
 279    //             cx,
 280    //         );
 281    //     } else if shift && !ctrl && !alt && !cmd {
 282    //         editor.select(
 283    //             SelectPhase::Extend {
 284    //                 position,
 285    //                 click_count,
 286    //             },
 287    //             cx,
 288    //         );
 289    //     } else {
 290    //         editor.select(
 291    //             SelectPhase::Begin {
 292    //                 position,
 293    //                 add: alt,
 294    //                 click_count,
 295    //             },
 296    //             cx,
 297    //         );
 298    //     }
 299
 300    //     true
 301    // }
 302
 303    // fn mouse_right_down(
 304    //     editor: &mut Editor,
 305    //     position: gpui::Point<Pixels>,
 306    //     position_map: &PositionMap,
 307    //     text_bounds: Bounds<Pixels>,
 308    //     cx: &mut EventContext<Editor>,
 309    // ) -> bool {
 310    //     if !text_bounds.contains_point(position) {
 311    //         return false;
 312    //     }
 313    //     let point_for_position = position_map.point_for_position(text_bounds, position);
 314    //     mouse_context_menu::deploy_context_menu(
 315    //         editor,
 316    //         position,
 317    //         point_for_position.previous_valid,
 318    //         cx,
 319    //     );
 320    //     true
 321    // }
 322
 323    // fn mouse_up(
 324    //     editor: &mut Editor,
 325    //     position: gpui::Point<Pixels>,
 326    //     cmd: bool,
 327    //     shift: bool,
 328    //     alt: bool,
 329    //     position_map: &PositionMap,
 330    //     text_bounds: Bounds<Pixels>,
 331    //     cx: &mut EventContext<Editor>,
 332    // ) -> bool {
 333    //     let end_selection = editor.has_pending_selection();
 334    //     let pending_nonempty_selections = editor.has_pending_nonempty_selection();
 335
 336    //     if end_selection {
 337    //         editor.select(SelectPhase::End, cx);
 338    //     }
 339
 340    //     if !pending_nonempty_selections && cmd && text_bounds.contains_point(position) {
 341    //         let point = position_map.point_for_position(text_bounds, position);
 342    //         let could_be_inlay = point.as_valid().is_none();
 343    //         if shift || could_be_inlay {
 344    //             go_to_fetched_type_definition(editor, point, alt, cx);
 345    //         } else {
 346    //             go_to_fetched_definition(editor, point, alt, cx);
 347    //         }
 348
 349    //         return true;
 350    //     }
 351
 352    //     end_selection
 353    // }
 354
 355    // fn mouse_dragged(
 356    //     editor: &mut Editor,
 357    //     MouseMovedEvent {
 358    //         modifiers: Modifiers { cmd, shift, .. },
 359    //         position,
 360    //         ..
 361    //     }: MouseMovedEvent,
 362    //     position_map: &PositionMap,
 363    //     text_bounds: Bounds<Pixels>,
 364    //     cx: &mut EventContext<Editor>,
 365    // ) -> bool {
 366    //     // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
 367    //     // Don't trigger hover popover if mouse is hovering over context menu
 368    //     let point = if text_bounds.contains_point(position) {
 369    //         position_map
 370    //             .point_for_position(text_bounds, position)
 371    //             .as_valid()
 372    //     } else {
 373    //         None
 374    //     };
 375
 376    //     update_go_to_definition_link(
 377    //         editor,
 378    //         point.map(GoToDefinitionTrigger::Text),
 379    //         cmd,
 380    //         shift,
 381    //         cx,
 382    //     );
 383
 384    //     if editor.has_pending_selection() {
 385    //         let mut scroll_delta = gpui::Point::<Pixels>::zero();
 386
 387    //         let vertical_margin = position_map.line_height.min(text_bounds.height() / 3.0);
 388    //         let top = text_bounds.origin.y + vertical_margin;
 389    //         let bottom = text_bounds.lower_left().y - vertical_margin;
 390    //         if position.y < top {
 391    //             scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y))
 392    //         }
 393    //         if position.y > bottom {
 394    //             scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y - bottom))
 395    //         }
 396
 397    //         let horizontal_margin = position_map.line_height.min(text_bounds.width() / 3.0);
 398    //         let left = text_bounds.origin.x + horizontal_margin;
 399    //         let right = text_bounds.upper_right().x - horizontal_margin;
 400    //         if position.x < left {
 401    //             scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
 402    //                 left - position.x,
 403    //             ))
 404    //         }
 405    //         if position.x > right {
 406    //             scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
 407    //                 position.x - right,
 408    //             ))
 409    //         }
 410
 411    //         let point_for_position = position_map.point_for_position(text_bounds, position);
 412
 413    //         editor.select(
 414    //             SelectPhase::Update {
 415    //                 position: point_for_position.previous_valid,
 416    //                 goal_column: point_for_position.exact_unclipped.column(),
 417    //                 scroll_position: (position_map.snapshot.scroll_position() + scroll_delta)
 418    //                     .clamp(gpui::Point::<Pixels>::zero(), position_map.scroll_max),
 419    //             },
 420    //             cx,
 421    //         );
 422    //         hover_at(editor, point, cx);
 423    //         true
 424    //     } else {
 425    //         hover_at(editor, point, cx);
 426    //         false
 427    //     }
 428    // }
 429
 430    fn mouse_moved(
 431        editor: &mut Editor,
 432        MouseMoveEvent {
 433            modifiers: Modifiers { shift, command, .. },
 434            position,
 435            ..
 436        }: &MouseMoveEvent,
 437        position_map: &PositionMap,
 438        text_bounds: Bounds<Pixels>,
 439        cx: &mut ViewContext<Editor>,
 440    ) -> bool {
 441        // This will be handled more correctly once https://github.com/zed-industries/zed/issues/1218 is completed
 442        // Don't trigger hover popover if mouse is hovering over context menu
 443        if text_bounds.contains_point(position) {
 444            let point_for_position = position_map.point_for_position(text_bounds, position.clone());
 445            match point_for_position.as_valid() {
 446                Some(point) => {
 447                    update_go_to_definition_link(
 448                        editor,
 449                        Some(GoToDefinitionTrigger::Text(point)),
 450                        *command,
 451                        *shift,
 452                        cx,
 453                    );
 454                    hover_at(editor, Some(point), cx);
 455                }
 456                None => {
 457                    update_inlay_link_and_hover_points(
 458                        &position_map.snapshot,
 459                        point_for_position,
 460                        editor,
 461                        *command,
 462                        *shift,
 463                        cx,
 464                    );
 465                }
 466            }
 467        } else {
 468            update_go_to_definition_link(editor, None, *command, *shift, cx);
 469            hover_at(editor, None, cx);
 470        }
 471
 472        true
 473    }
 474
 475    fn scroll(
 476        editor: &mut Editor,
 477        event: &ScrollWheelEvent,
 478        position_map: &PositionMap,
 479        bounds: Bounds<Pixels>,
 480        cx: &mut ViewContext<Editor>,
 481    ) -> bool {
 482        if !bounds.contains_point(&event.position) {
 483            return false;
 484        }
 485
 486        let line_height = position_map.line_height;
 487        let max_glyph_width = position_map.em_width;
 488        let (delta, axis) = match event.delta {
 489            gpui::ScrollDelta::Pixels(mut pixels) => {
 490                //Trackpad
 491                let axis = position_map.snapshot.ongoing_scroll.filter(&mut pixels);
 492                (pixels, axis)
 493            }
 494
 495            gpui::ScrollDelta::Lines(lines) => {
 496                //Not trackpad
 497                let pixels = point(lines.x * max_glyph_width, lines.y * line_height);
 498                (pixels, None)
 499            }
 500        };
 501
 502        let scroll_position = position_map.snapshot.scroll_position();
 503        let x = f32::from((scroll_position.x * max_glyph_width - delta.x) / max_glyph_width);
 504        let y = f32::from((scroll_position.y * line_height - delta.y) / line_height);
 505        let scroll_position = point(x, y).clamp(&point(0., 0.), &position_map.scroll_max);
 506        editor.scroll(scroll_position, axis, cx);
 507
 508        true
 509    }
 510
 511    fn paint_background(
 512        &self,
 513        gutter_bounds: Bounds<Pixels>,
 514        text_bounds: Bounds<Pixels>,
 515        layout: &LayoutState,
 516        cx: &mut ViewContext<Editor>,
 517    ) {
 518        let bounds = gutter_bounds.union(&text_bounds);
 519        let scroll_top =
 520            layout.position_map.snapshot.scroll_position().y * layout.position_map.line_height;
 521        let gutter_bg = cx.theme().colors().editor_gutter_background;
 522        cx.paint_quad(
 523            gutter_bounds,
 524            Corners::default(),
 525            gutter_bg,
 526            Edges::default(),
 527            transparent_black(),
 528        );
 529        cx.paint_quad(
 530            text_bounds,
 531            Corners::default(),
 532            self.style.background,
 533            Edges::default(),
 534            transparent_black(),
 535        );
 536
 537        if let EditorMode::Full = layout.mode {
 538            let mut active_rows = layout.active_rows.iter().peekable();
 539            while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
 540                let mut end_row = *start_row;
 541                while active_rows.peek().map_or(false, |r| {
 542                    *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
 543                }) {
 544                    active_rows.next().unwrap();
 545                    end_row += 1;
 546                }
 547
 548                if !contains_non_empty_selection {
 549                    let origin = point(
 550                        bounds.origin.x,
 551                        bounds.origin.y + (layout.position_map.line_height * *start_row as f32)
 552                            - scroll_top,
 553                    );
 554                    let size = size(
 555                        bounds.size.width,
 556                        layout.position_map.line_height * (end_row - start_row + 1) as f32,
 557                    );
 558                    let active_line_bg = cx.theme().colors().editor_active_line_background;
 559                    cx.paint_quad(
 560                        Bounds { origin, size },
 561                        Corners::default(),
 562                        active_line_bg,
 563                        Edges::default(),
 564                        transparent_black(),
 565                    );
 566                }
 567            }
 568
 569            if let Some(highlighted_rows) = &layout.highlighted_rows {
 570                let origin = point(
 571                    bounds.origin.x,
 572                    bounds.origin.y
 573                        + (layout.position_map.line_height * highlighted_rows.start as f32)
 574                        - scroll_top,
 575                );
 576                let size = size(
 577                    bounds.size.width,
 578                    layout.position_map.line_height * highlighted_rows.len() as f32,
 579                );
 580                let highlighted_line_bg = cx.theme().colors().editor_highlighted_line_background;
 581                cx.paint_quad(
 582                    Bounds { origin, size },
 583                    Corners::default(),
 584                    highlighted_line_bg,
 585                    Edges::default(),
 586                    transparent_black(),
 587                );
 588            }
 589
 590            let scroll_left =
 591                layout.position_map.snapshot.scroll_position().x * layout.position_map.em_width;
 592
 593            for (wrap_position, active) in layout.wrap_guides.iter() {
 594                let x = (text_bounds.origin.x + *wrap_position + layout.position_map.em_width / 2.)
 595                    - scroll_left;
 596
 597                if x < text_bounds.origin.x
 598                    || (layout.show_scrollbars && x > self.scrollbar_left(&bounds))
 599                {
 600                    continue;
 601                }
 602
 603                let color = if *active {
 604                    cx.theme().colors().editor_active_wrap_guide
 605                } else {
 606                    cx.theme().colors().editor_wrap_guide
 607                };
 608                cx.paint_quad(
 609                    Bounds {
 610                        origin: point(x, text_bounds.origin.y),
 611                        size: size(px(1.), text_bounds.size.height),
 612                    },
 613                    Corners::default(),
 614                    color,
 615                    Edges::default(),
 616                    transparent_black(),
 617                );
 618            }
 619        }
 620    }
 621
 622    fn paint_gutter(
 623        &mut self,
 624        bounds: Bounds<Pixels>,
 625        layout: &LayoutState,
 626        editor: &mut Editor,
 627        cx: &mut ViewContext<Editor>,
 628    ) {
 629        let line_height = layout.position_map.line_height;
 630
 631        let scroll_position = layout.position_map.snapshot.scroll_position();
 632        let scroll_top = scroll_position.y * line_height;
 633
 634        let show_gutter = matches!(
 635            ProjectSettings::get_global(cx).git.git_gutter,
 636            Some(GitGutterSetting::TrackedFiles)
 637        );
 638
 639        if show_gutter {
 640            Self::paint_diff_hunks(bounds, layout, cx);
 641        }
 642
 643        for (ix, line) in layout.line_number_layouts.iter().enumerate() {
 644            if let Some(line) = line {
 645                let line_origin = bounds.origin
 646                    + point(
 647                        bounds.size.width - line.width - layout.gutter_padding,
 648                        ix as f32 * line_height - (scroll_top % line_height),
 649                    );
 650
 651                line.paint(line_origin, line_height, cx);
 652            }
 653        }
 654
 655        // todo!("fold indicators")
 656        // for (ix, fold_indicator) in layout.fold_indicators.iter_mut().enumerate() {
 657        //     if let Some(indicator) = fold_indicator.as_mut() {
 658        //         let position = point(
 659        //             bounds.width() - layout.gutter_padding,
 660        //             ix as f32 * line_height - (scroll_top % line_height),
 661        //         );
 662        //         let centering_offset = point(
 663        //             (layout.gutter_padding + layout.gutter_margin - indicator.size().x) / 2.,
 664        //             (line_height - indicator.size().y) / 2.,
 665        //         );
 666
 667        //         let indicator_origin = bounds.origin + position + centering_offset;
 668
 669        //         indicator.paint(indicator_origin, visible_bounds, editor, cx);
 670        //     }
 671        // }
 672
 673        // todo!("code actions indicator")
 674        // if let Some((row, indicator)) = layout.code_actions_indicator.as_mut() {
 675        //     let mut x = 0.;
 676        //     let mut y = *row as f32 * line_height - scroll_top;
 677        //     x += ((layout.gutter_padding + layout.gutter_margin) - indicator.size().x) / 2.;
 678        //     y += (line_height - indicator.size().y) / 2.;
 679        //     indicator.paint(bounds.origin + point(x, y), visible_bounds, editor, cx);
 680        // }
 681    }
 682
 683    fn paint_diff_hunks(
 684        bounds: Bounds<Pixels>,
 685        layout: &LayoutState,
 686        cx: &mut ViewContext<Editor>,
 687    ) {
 688        // todo!()
 689        // let diff_style = &theme::current(cx).editor.diff.clone();
 690        // let line_height = layout.position_map.line_height;
 691
 692        // let scroll_position = layout.position_map.snapshot.scroll_position();
 693        // let scroll_top = scroll_position.y * line_height;
 694
 695        // for hunk in &layout.display_hunks {
 696        //     let (display_row_range, status) = match hunk {
 697        //         //TODO: This rendering is entirely a horrible hack
 698        //         &DisplayDiffHunk::Folded { display_row: row } => {
 699        //             let start_y = row as f32 * line_height - scroll_top;
 700        //             let end_y = start_y + line_height;
 701
 702        //             let width = diff_style.removed_width_em * line_height;
 703        //             let highlight_origin = bounds.origin + point(-width, start_y);
 704        //             let highlight_size = point(width * 2., end_y - start_y);
 705        //             let highlight_bounds = Bounds::<Pixels>::new(highlight_origin, highlight_size);
 706
 707        //             cx.paint_quad(Quad {
 708        //                 bounds: highlight_bounds,
 709        //                 background: Some(diff_style.modified),
 710        //                 border: Border::new(0., Color::transparent_black()).into(),
 711        //                 corner_radii: (1. * line_height).into(),
 712        //             });
 713
 714        //             continue;
 715        //         }
 716
 717        //         DisplayDiffHunk::Unfolded {
 718        //             display_row_range,
 719        //             status,
 720        //         } => (display_row_range, status),
 721        //     };
 722
 723        //     let color = match status {
 724        //         DiffHunkStatus::Added => diff_style.inserted,
 725        //         DiffHunkStatus::Modified => diff_style.modified,
 726
 727        //         //TODO: This rendering is entirely a horrible hack
 728        //         DiffHunkStatus::Removed => {
 729        //             let row = display_row_range.start;
 730
 731        //             let offset = line_height / 2.;
 732        //             let start_y = row as f32 * line_height - offset - scroll_top;
 733        //             let end_y = start_y + line_height;
 734
 735        //             let width = diff_style.removed_width_em * line_height;
 736        //             let highlight_origin = bounds.origin + point(-width, start_y);
 737        //             let highlight_size = point(width * 2., end_y - start_y);
 738        //             let highlight_bounds = Bounds::<Pixels>::new(highlight_origin, highlight_size);
 739
 740        //             cx.paint_quad(Quad {
 741        //                 bounds: highlight_bounds,
 742        //                 background: Some(diff_style.deleted),
 743        //                 border: Border::new(0., Color::transparent_black()).into(),
 744        //                 corner_radii: (1. * line_height).into(),
 745        //             });
 746
 747        //             continue;
 748        //         }
 749        //     };
 750
 751        //     let start_row = display_row_range.start;
 752        //     let end_row = display_row_range.end;
 753
 754        //     let start_y = start_row as f32 * line_height - scroll_top;
 755        //     let end_y = end_row as f32 * line_height - scroll_top;
 756
 757        //     let width = diff_style.width_em * line_height;
 758        //     let highlight_origin = bounds.origin + point(-width, start_y);
 759        //     let highlight_size = point(width * 2., end_y - start_y);
 760        //     let highlight_bounds = Bounds::<Pixels>::new(highlight_origin, highlight_size);
 761
 762        //     cx.paint_quad(Quad {
 763        //         bounds: highlight_bounds,
 764        //         background: Some(color),
 765        //         border: Border::new(0., Color::transparent_black()).into(),
 766        //         corner_radii: (diff_style.corner_radius * line_height).into(),
 767        //     });
 768        // }
 769    }
 770
 771    fn paint_text(
 772        &mut self,
 773        bounds: Bounds<Pixels>,
 774        layout: &LayoutState,
 775        editor: &mut Editor,
 776        cx: &mut ViewContext<Editor>,
 777    ) {
 778        let scroll_position = layout.position_map.snapshot.scroll_position();
 779        let start_row = layout.visible_display_row_range.start;
 780        let scroll_top = scroll_position.y * layout.position_map.line_height;
 781        let max_glyph_width = layout.position_map.em_width;
 782        let scroll_left = scroll_position.x * max_glyph_width;
 783        let content_origin = bounds.origin + point(layout.gutter_margin, Pixels::ZERO);
 784        let line_end_overshoot = 0.15 * layout.position_map.line_height;
 785        let whitespace_setting = editor.buffer.read(cx).settings_at(0, cx).show_whitespaces;
 786
 787        cx.with_content_mask(ContentMask { bounds }, |cx| {
 788            // todo!("cursor region")
 789            // cx.scene().push_cursor_region(CursorRegion {
 790            //     bounds,
 791            //     style: if !editor.link_go_to_definition_state.definitions.is_empty {
 792            //         CursorStyle::PointingHand
 793            //     } else {
 794            //         CursorStyle::IBeam
 795            //     },
 796            // });
 797
 798            // todo!("fold ranges")
 799            // let fold_corner_radius =
 800            //     self.style.folds.ellipses.corner_radius_factor * layout.position_map.line_height;
 801            // for (id, range, color) in layout.fold_ranges.iter() {
 802            //     self.paint_highlighted_range(
 803            //         range.clone(),
 804            //         *color,
 805            //         fold_corner_radius,
 806            //         fold_corner_radius * 2.,
 807            //         layout,
 808            //         content_origin,
 809            //         scroll_top,
 810            //         scroll_left,
 811            //         bounds,
 812            //         cx,
 813            //     );
 814
 815            //     for bound in range_to_bounds(
 816            //         &range,
 817            //         content_origin,
 818            //         scroll_left,
 819            //         scroll_top,
 820            //         &layout.visible_display_row_range,
 821            //         line_end_overshoot,
 822            //         &layout.position_map,
 823            //     ) {
 824            //         cx.scene().push_cursor_region(CursorRegion {
 825            //             bounds: bound,
 826            //             style: CursorStyle::PointingHand,
 827            //         });
 828
 829            //         let display_row = range.start.row();
 830
 831            //         let buffer_row = DisplayPoint::new(display_row, 0)
 832            //             .to_point(&layout.position_map.snapshot.display_snapshot)
 833            //             .row;
 834
 835            //         let view_id = cx.view_id();
 836            //         cx.scene().push_mouse_region(
 837            //             MouseRegion::new::<FoldMarkers>(view_id, *id as usize, bound)
 838            //                 .on_click(MouseButton::Left, move |_, editor: &mut Editor, cx| {
 839            //                     editor.unfold_at(&UnfoldAt { buffer_row }, cx)
 840            //                 })
 841            //                 .with_notify_on_hover(true)
 842            //                 .with_notify_on_click(true),
 843            //         )
 844            //     }
 845            // }
 846
 847            for (range, color) in &layout.highlighted_ranges {
 848                self.paint_highlighted_range(
 849                    range.clone(),
 850                    *color,
 851                    Pixels::ZERO,
 852                    line_end_overshoot,
 853                    layout,
 854                    content_origin,
 855                    scroll_top,
 856                    scroll_left,
 857                    bounds,
 858                    cx,
 859                );
 860            }
 861
 862            let mut cursors = SmallVec::<[Cursor; 32]>::new();
 863            let corner_radius = 0.15 * layout.position_map.line_height;
 864            let mut invisible_display_ranges = SmallVec::<[Range<DisplayPoint>; 32]>::new();
 865
 866            for (selection_style, selections) in &layout.selections {
 867                for selection in selections {
 868                    self.paint_highlighted_range(
 869                        selection.range.clone(),
 870                        selection_style.selection,
 871                        corner_radius,
 872                        corner_radius * 2.,
 873                        layout,
 874                        content_origin,
 875                        scroll_top,
 876                        scroll_left,
 877                        bounds,
 878                        cx,
 879                    );
 880
 881                    if selection.is_local && !selection.range.is_empty() {
 882                        invisible_display_ranges.push(selection.range.clone());
 883                    }
 884
 885                    if !selection.is_local || editor.show_local_cursors(cx) {
 886                        let cursor_position = selection.head;
 887                        if layout
 888                            .visible_display_row_range
 889                            .contains(&cursor_position.row())
 890                        {
 891                            let cursor_row_layout = &layout.position_map.line_layouts
 892                                [(cursor_position.row() - start_row) as usize]
 893                                .line;
 894                            let cursor_column = cursor_position.column() as usize;
 895
 896                            let cursor_character_x = cursor_row_layout.x_for_index(cursor_column);
 897                            let mut block_width = cursor_row_layout.x_for_index(cursor_column + 1)
 898                                - cursor_character_x;
 899                            if block_width == Pixels::ZERO {
 900                                block_width = layout.position_map.em_width;
 901                            }
 902                            let block_text = if let CursorShape::Block = selection.cursor_shape {
 903                                layout
 904                                    .position_map
 905                                    .snapshot
 906                                    .chars_at(cursor_position)
 907                                    .next()
 908                                    .and_then(|(character, _)| {
 909                                        let text = character.to_string();
 910                                        cx.text_system()
 911                                            .layout_text(
 912                                                &text,
 913                                                cursor_row_layout.font_size,
 914                                                &[TextRun {
 915                                                    len: text.len(),
 916                                                    font: self.style.text.font(),
 917                                                    color: self.style.background,
 918                                                    underline: None,
 919                                                }],
 920                                                None,
 921                                            )
 922                                            .unwrap()
 923                                            .pop()
 924                                    })
 925                            } else {
 926                                None
 927                            };
 928
 929                            let x = cursor_character_x - scroll_left;
 930                            let y = cursor_position.row() as f32 * layout.position_map.line_height
 931                                - scroll_top;
 932                            if selection.is_newest {
 933                                editor.pixel_position_of_newest_cursor = Some(point(
 934                                    bounds.origin.x + x + block_width / 2.,
 935                                    bounds.origin.y + y + layout.position_map.line_height / 2.,
 936                                ));
 937                            }
 938                            cursors.push(Cursor {
 939                                color: selection_style.cursor,
 940                                block_width,
 941                                origin: point(x, y),
 942                                line_height: layout.position_map.line_height,
 943                                shape: selection.cursor_shape,
 944                                block_text,
 945                            });
 946                        }
 947                    }
 948                }
 949            }
 950
 951            for (ix, line_with_invisibles) in layout.position_map.line_layouts.iter().enumerate() {
 952                let row = start_row + ix as u32;
 953                line_with_invisibles.draw(
 954                    layout,
 955                    row,
 956                    scroll_top,
 957                    content_origin,
 958                    scroll_left,
 959                    whitespace_setting,
 960                    &invisible_display_ranges,
 961                    cx,
 962                )
 963            }
 964
 965            cx.stack(0, |cx| {
 966                for cursor in cursors {
 967                    cursor.paint(content_origin, cx);
 968                }
 969            });
 970            // cx.scene().push_layer(Some(bounds));
 971
 972            // cx.scene().pop_layer();
 973
 974            // if let Some((position, context_menu)) = layout.context_menu.as_mut() {
 975            //     cx.scene().push_stacking_context(None, None);
 976            //     let cursor_row_layout =
 977            //         &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
 978            //     let x = cursor_row_layout.x_for_index(position.column() as usize) - scroll_left;
 979            //     let y = (position.row() + 1) as f32 * layout.position_map.line_height - scroll_top;
 980            //     let mut list_origin = content_origin + point(x, y);
 981            //     let list_width = context_menu.size().x;
 982            //     let list_height = context_menu.size().y;
 983
 984            //     // Snap the right edge of the list to the right edge of the window if
 985            //     // its horizontal bounds overflow.
 986            //     if list_origin.x + list_width > cx.window_size().x {
 987            //         list_origin.set_x((cx.window_size().x - list_width).max(0.));
 988            //     }
 989
 990            //     if list_origin.y + list_height > bounds.max_y {
 991            //         list_origin
 992            //             .set_y(list_origin.y - layout.position_map.line_height - list_height);
 993            //     }
 994
 995            //     context_menu.paint(
 996            //         list_origin,
 997            //         Bounds::<Pixels>::from_points(
 998            //             gpui::Point::<Pixels>::zero(),
 999            //             point(f32::MAX, f32::MAX),
1000            //         ), // Let content bleed outside of editor
1001            //         editor,
1002            //         cx,
1003            //     );
1004
1005            //     cx.scene().pop_stacking_context();
1006            // }
1007
1008            // if let Some((position, hover_popovers)) = layout.hover_popovers.as_mut() {
1009            //     cx.scene().push_stacking_context(None, None);
1010
1011            //     // This is safe because we check on layout whether the required row is available
1012            //     let hovered_row_layout =
1013            //         &layout.position_map.line_layouts[(position.row() - start_row) as usize].line;
1014
1015            //     // Minimum required size: Take the first popover, and add 1.5 times the minimum popover
1016            //     // height. This is the size we will use to decide whether to render popovers above or below
1017            //     // the hovered line.
1018            //     let first_size = hover_popovers[0].size();
1019            //     let height_to_reserve = first_size.y
1020            //         + 1.5 * MIN_POPOVER_LINE_HEIGHT as f32 * layout.position_map.line_height;
1021
1022            //     // Compute Hovered Point
1023            //     let x = hovered_row_layout.x_for_index(position.column() as usize) - scroll_left;
1024            //     let y = position.row() as f32 * layout.position_map.line_height - scroll_top;
1025            //     let hovered_point = content_origin + point(x, y);
1026
1027            //     if hovered_point.y - height_to_reserve > 0.0 {
1028            //         // There is enough space above. Render popovers above the hovered point
1029            //         let mut current_y = hovered_point.y;
1030            //         for hover_popover in hover_popovers {
1031            //             let size = hover_popover.size();
1032            //             let mut popover_origin = point(hovered_point.x, current_y - size.y);
1033
1034            //             let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
1035            //             if x_out_of_bounds < 0.0 {
1036            //                 popover_origin.set_x(popover_origin.x + x_out_of_bounds);
1037            //             }
1038
1039            //             hover_popover.paint(
1040            //                 popover_origin,
1041            //                 Bounds::<Pixels>::from_points(
1042            //                     gpui::Point::<Pixels>::zero(),
1043            //                     point(f32::MAX, f32::MAX),
1044            //                 ), // Let content bleed outside of editor
1045            //                 editor,
1046            //                 cx,
1047            //             );
1048
1049            //             current_y = popover_origin.y - HOVER_POPOVER_GAP;
1050            //         }
1051            //     } else {
1052            //         // There is not enough space above. Render popovers below the hovered point
1053            //         let mut current_y = hovered_point.y + layout.position_map.line_height;
1054            //         for hover_popover in hover_popovers {
1055            //             let size = hover_popover.size();
1056            //             let mut popover_origin = point(hovered_point.x, current_y);
1057
1058            //             let x_out_of_bounds = bounds.max_x - (popover_origin.x + size.x);
1059            //             if x_out_of_bounds < 0.0 {
1060            //                 popover_origin.set_x(popover_origin.x + x_out_of_bounds);
1061            //             }
1062
1063            //             hover_popover.paint(
1064            //                 popover_origin,
1065            //                 Bounds::<Pixels>::from_points(
1066            //                     gpui::Point::<Pixels>::zero(),
1067            //                     point(f32::MAX, f32::MAX),
1068            //                 ), // Let content bleed outside of editor
1069            //                 editor,
1070            //                 cx,
1071            //             );
1072
1073            //             current_y = popover_origin.y + size.y + HOVER_POPOVER_GAP;
1074            //         }
1075            //     }
1076
1077            //     cx.scene().pop_stacking_context();
1078            // }
1079        })
1080    }
1081
1082    fn scrollbar_left(&self, bounds: &Bounds<Pixels>) -> Pixels {
1083        bounds.upper_right().x - self.style.scrollbar_width
1084    }
1085
1086    // fn paint_scrollbar(
1087    //     &mut self,
1088    //     bounds: Bounds<Pixels>,
1089    //     layout: &mut LayoutState,
1090    //     editor: &Editor,
1091    //     cx: &mut ViewContext<Editor>,
1092    // ) {
1093    //     enum ScrollbarMouseHandlers {}
1094    //     if layout.mode != EditorMode::Full {
1095    //         return;
1096    //     }
1097
1098    //     let style = &self.style.theme.scrollbar;
1099
1100    //     let top = bounds.min_y;
1101    //     let bottom = bounds.max_y;
1102    //     let right = bounds.max_x;
1103    //     let left = self.scrollbar_left(&bounds);
1104    //     let row_range = &layout.scrollbar_row_range;
1105    //     let max_row = layout.max_row as f32 + (row_range.end - row_range.start);
1106
1107    //     let mut height = bounds.height();
1108    //     let mut first_row_y_offset = 0.0;
1109
1110    //     // Impose a minimum height on the scrollbar thumb
1111    //     let row_height = height / max_row;
1112    //     let min_thumb_height =
1113    //         style.min_height_factor * cx.font_cache.line_height(self.style.text.font_size);
1114    //     let thumb_height = (row_range.end - row_range.start) * row_height;
1115    //     if thumb_height < min_thumb_height {
1116    //         first_row_y_offset = (min_thumb_height - thumb_height) / 2.0;
1117    //         height -= min_thumb_height - thumb_height;
1118    //     }
1119
1120    //     let y_for_row = |row: f32| -> f32 { top + first_row_y_offset + row * row_height };
1121
1122    //     let thumb_top = y_for_row(row_range.start) - first_row_y_offset;
1123    //     let thumb_bottom = y_for_row(row_range.end) + first_row_y_offset;
1124    //     let track_bounds = Bounds::<Pixels>::from_points(point(left, top), point(right, bottom));
1125    //     let thumb_bounds = Bounds::<Pixels>::from_points(point(left, thumb_top), point(right, thumb_bottom));
1126
1127    //     if layout.show_scrollbars {
1128    //         cx.paint_quad(Quad {
1129    //             bounds: track_bounds,
1130    //             border: style.track.border.into(),
1131    //             background: style.track.background_color,
1132    //             ..Default::default()
1133    //         });
1134    //         let scrollbar_settings = settings::get::<EditorSettings>(cx).scrollbar;
1135    //         let theme = theme::current(cx);
1136    //         let scrollbar_theme = &theme.editor.scrollbar;
1137    //         if layout.is_singleton && scrollbar_settings.selections {
1138    //             let start_anchor = Anchor::min();
1139    //             let end_anchor = Anchor::max;
1140    //             let color = scrollbar_theme.selections;
1141    //             let border = Border {
1142    //                 width: 1.,
1143    //                 color: style.thumb.border.color,
1144    //                 overlay: false,
1145    //                 top: false,
1146    //                 right: true,
1147    //                 bottom: false,
1148    //                 left: true,
1149    //             };
1150    //             let mut push_region = |start: DisplayPoint, end: DisplayPoint| {
1151    //                 let start_y = y_for_row(start.row() as f32);
1152    //                 let mut end_y = y_for_row(end.row() as f32);
1153    //                 if end_y - start_y < 1. {
1154    //                     end_y = start_y + 1.;
1155    //                 }
1156    //                 let bounds = Bounds::<Pixels>::from_points(point(left, start_y), point(right, end_y));
1157
1158    //                 cx.paint_quad(Quad {
1159    //                     bounds,
1160    //                     background: Some(color),
1161    //                     border: border.into(),
1162    //                     corner_radii: style.thumb.corner_radii.into(),
1163    //                 })
1164    //             };
1165    //             let background_ranges = editor
1166    //                 .background_highlight_row_ranges::<crate::items::BufferSearchHighlights>(
1167    //                     start_anchor..end_anchor,
1168    //                     &layout.position_map.snapshot,
1169    //                     50000,
1170    //                 );
1171    //             for row in background_ranges {
1172    //                 let start = row.start();
1173    //                 let end = row.end();
1174    //                 push_region(*start, *end);
1175    //             }
1176    //         }
1177
1178    //         if layout.is_singleton && scrollbar_settings.git_diff {
1179    //             let diff_style = scrollbar_theme.git.clone();
1180    //             for hunk in layout
1181    //                 .position_map
1182    //                 .snapshot
1183    //                 .buffer_snapshot
1184    //                 .git_diff_hunks_in_range(0..(max_row.floor() as u32))
1185    //             {
1186    //                 let start_display = Point::new(hunk.buffer_range.start, 0)
1187    //                     .to_display_point(&layout.position_map.snapshot.display_snapshot);
1188    //                 let end_display = Point::new(hunk.buffer_range.end, 0)
1189    //                     .to_display_point(&layout.position_map.snapshot.display_snapshot);
1190    //                 let start_y = y_for_row(start_display.row() as f32);
1191    //                 let mut end_y = if hunk.buffer_range.start == hunk.buffer_range.end {
1192    //                     y_for_row((end_display.row() + 1) as f32)
1193    //                 } else {
1194    //                     y_for_row((end_display.row()) as f32)
1195    //                 };
1196
1197    //                 if end_y - start_y < 1. {
1198    //                     end_y = start_y + 1.;
1199    //                 }
1200    //                 let bounds = Bounds::<Pixels>::from_points(point(left, start_y), point(right, end_y));
1201
1202    //                 let color = match hunk.status() {
1203    //                     DiffHunkStatus::Added => diff_style.inserted,
1204    //                     DiffHunkStatus::Modified => diff_style.modified,
1205    //                     DiffHunkStatus::Removed => diff_style.deleted,
1206    //                 };
1207
1208    //                 let border = Border {
1209    //                     width: 1.,
1210    //                     color: style.thumb.border.color,
1211    //                     overlay: false,
1212    //                     top: false,
1213    //                     right: true,
1214    //                     bottom: false,
1215    //                     left: true,
1216    //                 };
1217
1218    //                 cx.paint_quad(Quad {
1219    //                     bounds,
1220    //                     background: Some(color),
1221    //                     border: border.into(),
1222    //                     corner_radii: style.thumb.corner_radii.into(),
1223    //                 })
1224    //             }
1225    //         }
1226
1227    //         cx.paint_quad(Quad {
1228    //             bounds: thumb_bounds,
1229    //             border: style.thumb.border.into(),
1230    //             background: style.thumb.background_color,
1231    //             corner_radii: style.thumb.corner_radii.into(),
1232    //         });
1233    //     }
1234
1235    //     cx.scene().push_cursor_region(CursorRegion {
1236    //         bounds: track_bounds,
1237    //         style: CursorStyle::Arrow,
1238    //     });
1239    //     let region_id = cx.view_id();
1240    //     cx.scene().push_mouse_region(
1241    //         MouseRegion::new::<ScrollbarMouseHandlers>(region_id, region_id, track_bounds)
1242    //             .on_move(move |event, editor: &mut Editor, cx| {
1243    //                 if event.pressed_button.is_none() {
1244    //                     editor.scroll_manager.show_scrollbar(cx);
1245    //                 }
1246    //             })
1247    //             .on_down(MouseButton::Left, {
1248    //                 let row_range = row_range.clone();
1249    //                 move |event, editor: &mut Editor, cx| {
1250    //                     let y = event.position.y;
1251    //                     if y < thumb_top || thumb_bottom < y {
1252    //                         let center_row = ((y - top) * max_row as f32 / height).round() as u32;
1253    //                         let top_row = center_row
1254    //                             .saturating_sub((row_range.end - row_range.start) as u32 / 2);
1255    //                         let mut position = editor.scroll_position(cx);
1256    //                         position.set_y(top_row as f32);
1257    //                         editor.set_scroll_position(position, cx);
1258    //                     } else {
1259    //                         editor.scroll_manager.show_scrollbar(cx);
1260    //                     }
1261    //                 }
1262    //             })
1263    //             .on_drag(MouseButton::Left, {
1264    //                 move |event, editor: &mut Editor, cx| {
1265    //                     if event.end {
1266    //                         return;
1267    //                     }
1268
1269    //                     let y = event.prev_mouse_position.y;
1270    //                     let new_y = event.position.y;
1271    //                     if thumb_top < y && y < thumb_bottom {
1272    //                         let mut position = editor.scroll_position(cx);
1273    //                         position.set_y(position.y + (new_y - y) * (max_row as f32) / height);
1274    //                         if position.y < 0.0 {
1275    //                             position.set_y(0.);
1276    //                         }
1277    //                         editor.set_scroll_position(position, cx);
1278    //                     }
1279    //                 }
1280    //             }),
1281    //     );
1282    // }
1283
1284    #[allow(clippy::too_many_arguments)]
1285    fn paint_highlighted_range(
1286        &self,
1287        range: Range<DisplayPoint>,
1288        color: Hsla,
1289        corner_radius: Pixels,
1290        line_end_overshoot: Pixels,
1291        layout: &LayoutState,
1292        content_origin: gpui::Point<Pixels>,
1293        scroll_top: Pixels,
1294        scroll_left: Pixels,
1295        bounds: Bounds<Pixels>,
1296        cx: &mut ViewContext<Editor>,
1297    ) {
1298        let start_row = layout.visible_display_row_range.start;
1299        let end_row = layout.visible_display_row_range.end;
1300        if range.start != range.end {
1301            let row_range = if range.end.column() == 0 {
1302                cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
1303            } else {
1304                cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
1305            };
1306
1307            let highlighted_range = HighlightedRange {
1308                color,
1309                line_height: layout.position_map.line_height,
1310                corner_radius,
1311                start_y: content_origin.y
1312                    + row_range.start as f32 * layout.position_map.line_height
1313                    - scroll_top,
1314                lines: row_range
1315                    .into_iter()
1316                    .map(|row| {
1317                        let line_layout =
1318                            &layout.position_map.line_layouts[(row - start_row) as usize].line;
1319                        HighlightedRangeLine {
1320                            start_x: if row == range.start.row() {
1321                                content_origin.x
1322                                    + line_layout.x_for_index(range.start.column() as usize)
1323                                    - scroll_left
1324                            } else {
1325                                content_origin.x - scroll_left
1326                            },
1327                            end_x: if row == range.end.row() {
1328                                content_origin.x
1329                                    + line_layout.x_for_index(range.end.column() as usize)
1330                                    - scroll_left
1331                            } else {
1332                                content_origin.x + line_layout.width + line_end_overshoot
1333                                    - scroll_left
1334                            },
1335                        }
1336                    })
1337                    .collect(),
1338            };
1339
1340            highlighted_range.paint(bounds, cx);
1341        }
1342    }
1343
1344    // fn paint_blocks(
1345    //     &mut self,
1346    //     bounds: Bounds<Pixels>,
1347    //     visible_bounds: Bounds<Pixels>,
1348    //     layout: &mut LayoutState,
1349    //     editor: &mut Editor,
1350    //     cx: &mut ViewContext<Editor>,
1351    // ) {
1352    //     let scroll_position = layout.position_map.snapshot.scroll_position();
1353    //     let scroll_left = scroll_position.x * layout.position_map.em_width;
1354    //     let scroll_top = scroll_position.y * layout.position_map.line_height;
1355
1356    //     for block in &mut layout.blocks {
1357    //         let mut origin = bounds.origin
1358    //             + point(
1359    //                 0.,
1360    //                 block.row as f32 * layout.position_map.line_height - scroll_top,
1361    //             );
1362    //         if !matches!(block.style, BlockStyle::Sticky) {
1363    //             origin += point(-scroll_left, 0.);
1364    //         }
1365    //         block.element.paint(origin, visible_bounds, editor, cx);
1366    //     }
1367    // }
1368
1369    fn column_pixels(&self, column: usize, cx: &ViewContext<Editor>) -> Pixels {
1370        let style = &self.style;
1371        let font_size = style.text.font_size.to_pixels(cx.rem_size());
1372        let layout = cx
1373            .text_system()
1374            .layout_text(
1375                " ".repeat(column).as_str(),
1376                font_size,
1377                &[TextRun {
1378                    len: column,
1379                    font: style.text.font(),
1380                    color: Hsla::default(),
1381                    underline: None,
1382                }],
1383                None,
1384            )
1385            .unwrap();
1386
1387        layout[0].width
1388    }
1389
1390    fn max_line_number_width(&self, snapshot: &EditorSnapshot, cx: &ViewContext<Editor>) -> Pixels {
1391        let digit_count = (snapshot.max_buffer_row() as f32 + 1.).log10().floor() as usize + 1;
1392        self.column_pixels(digit_count, cx)
1393    }
1394
1395    //Folds contained in a hunk are ignored apart from shrinking visual size
1396    //If a fold contains any hunks then that fold line is marked as modified
1397    fn layout_git_gutters(
1398        &self,
1399        display_rows: Range<u32>,
1400        snapshot: &EditorSnapshot,
1401    ) -> Vec<DisplayDiffHunk> {
1402        let buffer_snapshot = &snapshot.buffer_snapshot;
1403
1404        let buffer_start_row = DisplayPoint::new(display_rows.start, 0)
1405            .to_point(snapshot)
1406            .row;
1407        let buffer_end_row = DisplayPoint::new(display_rows.end, 0)
1408            .to_point(snapshot)
1409            .row;
1410
1411        buffer_snapshot
1412            .git_diff_hunks_in_range(buffer_start_row..buffer_end_row)
1413            .map(|hunk| diff_hunk_to_display(hunk, snapshot))
1414            .dedup()
1415            .collect()
1416    }
1417
1418    fn calculate_relative_line_numbers(
1419        &self,
1420        snapshot: &EditorSnapshot,
1421        rows: &Range<u32>,
1422        relative_to: Option<u32>,
1423    ) -> HashMap<u32, u32> {
1424        let mut relative_rows: HashMap<u32, u32> = Default::default();
1425        let Some(relative_to) = relative_to else {
1426            return relative_rows;
1427        };
1428
1429        let start = rows.start.min(relative_to);
1430        let end = rows.end.max(relative_to);
1431
1432        let buffer_rows = snapshot
1433            .buffer_rows(start)
1434            .take(1 + (end - start) as usize)
1435            .collect::<Vec<_>>();
1436
1437        let head_idx = relative_to - start;
1438        let mut delta = 1;
1439        let mut i = head_idx + 1;
1440        while i < buffer_rows.len() as u32 {
1441            if buffer_rows[i as usize].is_some() {
1442                if rows.contains(&(i + start)) {
1443                    relative_rows.insert(i + start, delta);
1444                }
1445                delta += 1;
1446            }
1447            i += 1;
1448        }
1449        delta = 1;
1450        i = head_idx.min(buffer_rows.len() as u32 - 1);
1451        while i > 0 && buffer_rows[i as usize].is_none() {
1452            i -= 1;
1453        }
1454
1455        while i > 0 {
1456            i -= 1;
1457            if buffer_rows[i as usize].is_some() {
1458                if rows.contains(&(i + start)) {
1459                    relative_rows.insert(i + start, delta);
1460                }
1461                delta += 1;
1462            }
1463        }
1464
1465        relative_rows
1466    }
1467
1468    fn layout_line_numbers(
1469        &self,
1470        rows: Range<u32>,
1471        active_rows: &BTreeMap<u32, bool>,
1472        newest_selection_head: DisplayPoint,
1473        is_singleton: bool,
1474        snapshot: &EditorSnapshot,
1475        cx: &ViewContext<Editor>,
1476    ) -> (
1477        Vec<Option<gpui::Line>>,
1478        Vec<Option<(FoldStatus, BufferRow, bool)>>,
1479    ) {
1480        let font_size = self.style.text.font_size.to_pixels(cx.rem_size());
1481        let include_line_numbers = snapshot.mode == EditorMode::Full;
1482        let mut line_number_layouts = Vec::with_capacity(rows.len());
1483        let mut fold_statuses = Vec::with_capacity(rows.len());
1484        let mut line_number = String::new();
1485        let is_relative = EditorSettings::get_global(cx).relative_line_numbers;
1486        let relative_to = if is_relative {
1487            Some(newest_selection_head.row())
1488        } else {
1489            None
1490        };
1491
1492        let relative_rows = self.calculate_relative_line_numbers(&snapshot, &rows, relative_to);
1493
1494        for (ix, row) in snapshot
1495            .buffer_rows(rows.start)
1496            .take((rows.end - rows.start) as usize)
1497            .enumerate()
1498        {
1499            let display_row = rows.start + ix as u32;
1500            let (active, color) = if active_rows.contains_key(&display_row) {
1501                (true, cx.theme().colors().editor_active_line_number)
1502            } else {
1503                (false, cx.theme().colors().editor_line_number)
1504            };
1505            if let Some(buffer_row) = row {
1506                if include_line_numbers {
1507                    line_number.clear();
1508                    let default_number = buffer_row + 1;
1509                    let number = relative_rows
1510                        .get(&(ix as u32 + rows.start))
1511                        .unwrap_or(&default_number);
1512                    write!(&mut line_number, "{}", number).unwrap();
1513                    let run = TextRun {
1514                        len: line_number.len(),
1515                        font: self.style.text.font(),
1516                        color,
1517                        underline: None,
1518                    };
1519                    let layout = cx
1520                        .text_system()
1521                        .layout_text(&line_number, font_size, &[run], None)
1522                        .unwrap()
1523                        .pop()
1524                        .unwrap();
1525                    line_number_layouts.push(Some(layout));
1526                    fold_statuses.push(
1527                        is_singleton
1528                            .then(|| {
1529                                snapshot
1530                                    .fold_for_line(buffer_row)
1531                                    .map(|fold_status| (fold_status, buffer_row, active))
1532                            })
1533                            .flatten(),
1534                    )
1535                }
1536            } else {
1537                fold_statuses.push(None);
1538                line_number_layouts.push(None);
1539            }
1540        }
1541
1542        (line_number_layouts, fold_statuses)
1543    }
1544
1545    fn layout_lines(
1546        &mut self,
1547        rows: Range<u32>,
1548        line_number_layouts: &[Option<Line>],
1549        snapshot: &EditorSnapshot,
1550        cx: &ViewContext<Editor>,
1551    ) -> Vec<LineWithInvisibles> {
1552        if rows.start >= rows.end {
1553            return Vec::new();
1554        }
1555
1556        // When the editor is empty and unfocused, then show the placeholder.
1557        if snapshot.is_empty() {
1558            let font_size = self.style.text.font_size.to_pixels(cx.rem_size());
1559            let placeholder_color = cx.theme().styles.colors.text_placeholder;
1560            let placeholder_text = snapshot.placeholder_text();
1561            let placeholder_lines = placeholder_text
1562                .as_ref()
1563                .map_or("", AsRef::as_ref)
1564                .split('\n')
1565                .skip(rows.start as usize)
1566                .chain(iter::repeat(""))
1567                .take(rows.len());
1568            placeholder_lines
1569                .map(|line| {
1570                    let run = TextRun {
1571                        len: line.len(),
1572                        font: self.style.text.font(),
1573                        color: placeholder_color,
1574                        underline: Default::default(),
1575                    };
1576                    cx.text_system()
1577                        .layout_text(line, font_size, &[run], None)
1578                        .unwrap()
1579                        .pop()
1580                        .unwrap()
1581                })
1582                .map(|line| LineWithInvisibles {
1583                    line,
1584                    invisibles: Vec::new(),
1585                })
1586                .collect()
1587        } else {
1588            let chunks = snapshot.highlighted_chunks(rows.clone(), true, &self.style);
1589            LineWithInvisibles::from_chunks(
1590                chunks,
1591                &self.style.text,
1592                MAX_LINE_LEN,
1593                rows.len() as usize,
1594                line_number_layouts,
1595                snapshot.mode,
1596                cx,
1597            )
1598        }
1599    }
1600
1601    fn compute_layout(
1602        &mut self,
1603        editor: &mut Editor,
1604        cx: &mut ViewContext<'_, Editor>,
1605        mut bounds: Bounds<Pixels>,
1606    ) -> LayoutState {
1607        // let mut size = constraint.max;
1608        // if size.x.is_infinite() {
1609        //     unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
1610        // }
1611
1612        let snapshot = editor.snapshot(cx);
1613        let style = self.style.clone();
1614        let font_id = cx.text_system().font_id(&style.text.font()).unwrap();
1615        let font_size = style.text.font_size.to_pixels(cx.rem_size());
1616        let line_height = style.text.line_height_in_pixels(cx.rem_size());
1617        let em_width = cx
1618            .text_system()
1619            .typographic_bounds(font_id, font_size, 'm')
1620            .unwrap()
1621            .size
1622            .width;
1623        let em_advance = cx
1624            .text_system()
1625            .advance(font_id, font_size, 'm')
1626            .unwrap()
1627            .width;
1628
1629        let gutter_padding;
1630        let gutter_width;
1631        let gutter_margin;
1632        if snapshot.show_gutter {
1633            let descent = cx.text_system().descent(font_id, font_size).unwrap();
1634
1635            let gutter_padding_factor = 3.5;
1636            gutter_padding = (em_width * gutter_padding_factor).round();
1637            gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
1638            gutter_margin = -descent;
1639        } else {
1640            gutter_padding = Pixels::ZERO;
1641            gutter_width = Pixels::ZERO;
1642            gutter_margin = Pixels::ZERO;
1643        };
1644
1645        let text_width = bounds.size.width - gutter_width;
1646        let overscroll = size(em_width, px(0.));
1647        let snapshot = {
1648            editor.set_visible_line_count((bounds.size.height / line_height).into(), cx);
1649
1650            let editor_width = text_width - gutter_margin - overscroll.width - em_width;
1651            let wrap_width = match editor.soft_wrap_mode(cx) {
1652                SoftWrap::None => (MAX_LINE_LEN / 2) as f32 * em_advance,
1653                SoftWrap::EditorWidth => editor_width,
1654                SoftWrap::Column(column) => editor_width.min(column as f32 * em_advance),
1655            };
1656
1657            if editor.set_wrap_width(Some(wrap_width), cx) {
1658                editor.snapshot(cx)
1659            } else {
1660                snapshot
1661            }
1662        };
1663
1664        let wrap_guides = editor
1665            .wrap_guides(cx)
1666            .iter()
1667            .map(|(guide, active)| (self.column_pixels(*guide, cx), *active))
1668            .collect::<SmallVec<[_; 2]>>();
1669
1670        let scroll_height = Pixels::from(snapshot.max_point().row() + 1) * line_height;
1671        // todo!("this should happen during layout")
1672        let editor_mode = snapshot.mode;
1673        if let EditorMode::AutoHeight { max_lines } = editor_mode {
1674            todo!()
1675            //     size.set_y(
1676            //         scroll_height
1677            //             .min(constraint.max_along(Axis::Vertical))
1678            //             .max(constraint.min_along(Axis::Vertical))
1679            //             .max(line_height)
1680            //             .min(line_height * max_lines as f32),
1681            //     )
1682        } else if let EditorMode::SingleLine = editor_mode {
1683            bounds.size.height = line_height.min(bounds.size.height);
1684        }
1685        // todo!()
1686        // else if size.y.is_infinite() {
1687        //     //     size.set_y(scroll_height);
1688        // }
1689        //
1690        let gutter_size = size(gutter_width, bounds.size.height);
1691        let text_size = size(text_width, bounds.size.height);
1692
1693        let autoscroll_horizontally =
1694            editor.autoscroll_vertically(bounds.size.height, line_height, cx);
1695        let mut snapshot = editor.snapshot(cx);
1696
1697        let scroll_position = snapshot.scroll_position();
1698        // The scroll position is a fractional point, the whole number of which represents
1699        // the top of the window in terms of display rows.
1700        let start_row = scroll_position.y as u32;
1701        let height_in_lines = f32::from(bounds.size.height / line_height);
1702        let max_row = snapshot.max_point().row();
1703
1704        // Add 1 to ensure selections bleed off screen
1705        let end_row = 1 + cmp::min((scroll_position.y + height_in_lines).ceil() as u32, max_row);
1706
1707        let start_anchor = if start_row == 0 {
1708            Anchor::min()
1709        } else {
1710            snapshot
1711                .buffer_snapshot
1712                .anchor_before(DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left))
1713        };
1714        let end_anchor = if end_row > max_row {
1715            Anchor::max()
1716        } else {
1717            snapshot
1718                .buffer_snapshot
1719                .anchor_before(DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right))
1720        };
1721
1722        let mut selections: Vec<(PlayerColor, Vec<SelectionLayout>)> = Vec::new();
1723        let mut active_rows = BTreeMap::new();
1724        let mut fold_ranges = Vec::new();
1725        let is_singleton = editor.is_singleton(cx);
1726
1727        let highlighted_rows = editor.highlighted_rows();
1728        let highlighted_ranges = editor.background_highlights_in_range(
1729            start_anchor..end_anchor,
1730            &snapshot.display_snapshot,
1731            cx.theme().colors(),
1732        );
1733
1734        fold_ranges.extend(
1735            snapshot
1736                .folds_in_range(start_anchor..end_anchor)
1737                .map(|anchor| {
1738                    let start = anchor.start.to_point(&snapshot.buffer_snapshot);
1739                    (
1740                        start.row,
1741                        start.to_display_point(&snapshot.display_snapshot)
1742                            ..anchor.end.to_display_point(&snapshot),
1743                    )
1744                }),
1745        );
1746
1747        let mut newest_selection_head = None;
1748
1749        if editor.show_local_selections {
1750            let mut local_selections: Vec<Selection<Point>> = editor
1751                .selections
1752                .disjoint_in_range(start_anchor..end_anchor, cx);
1753            local_selections.extend(editor.selections.pending(cx));
1754            let mut layouts = Vec::new();
1755            let newest = editor.selections.newest(cx);
1756            for selection in local_selections.drain(..) {
1757                let is_empty = selection.start == selection.end;
1758                let is_newest = selection == newest;
1759
1760                let layout = SelectionLayout::new(
1761                    selection,
1762                    editor.selections.line_mode,
1763                    editor.cursor_shape,
1764                    &snapshot.display_snapshot,
1765                    is_newest,
1766                    true,
1767                );
1768                if is_newest {
1769                    newest_selection_head = Some(layout.head);
1770                }
1771
1772                for row in cmp::max(layout.active_rows.start, start_row)
1773                    ..=cmp::min(layout.active_rows.end, end_row)
1774                {
1775                    let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty);
1776                    *contains_non_empty_selection |= !is_empty;
1777                }
1778                layouts.push(layout);
1779            }
1780
1781            selections.push((style.local_player, layouts));
1782        }
1783
1784        if let Some(collaboration_hub) = &editor.collaboration_hub {
1785            // When following someone, render the local selections in their color.
1786            if let Some(leader_id) = editor.leader_peer_id {
1787                if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id) {
1788                    if let Some(participant_index) = collaboration_hub
1789                        .user_participant_indices(cx)
1790                        .get(&collaborator.user_id)
1791                    {
1792                        if let Some((local_selection_style, _)) = selections.first_mut() {
1793                            *local_selection_style = cx
1794                                .theme()
1795                                .players()
1796                                .color_for_participant(participant_index.0);
1797                        }
1798                    }
1799                }
1800            }
1801
1802            let mut remote_selections = HashMap::default();
1803            for selection in snapshot.remote_selections_in_range(
1804                &(start_anchor..end_anchor),
1805                collaboration_hub.as_ref(),
1806                cx,
1807            ) {
1808                let selection_style = if let Some(participant_index) = selection.participant_index {
1809                    cx.theme()
1810                        .players()
1811                        .color_for_participant(participant_index.0)
1812                } else {
1813                    cx.theme().players().absent()
1814                };
1815
1816                // Don't re-render the leader's selections, since the local selections
1817                // match theirs.
1818                if Some(selection.peer_id) == editor.leader_peer_id {
1819                    continue;
1820                }
1821
1822                remote_selections
1823                    .entry(selection.replica_id)
1824                    .or_insert((selection_style, Vec::new()))
1825                    .1
1826                    .push(SelectionLayout::new(
1827                        selection.selection,
1828                        selection.line_mode,
1829                        selection.cursor_shape,
1830                        &snapshot.display_snapshot,
1831                        false,
1832                        false,
1833                    ));
1834            }
1835
1836            selections.extend(remote_selections.into_values());
1837        }
1838
1839        let scrollbar_settings = EditorSettings::get_global(cx).scrollbar;
1840        let show_scrollbars = match scrollbar_settings.show {
1841            ShowScrollbar::Auto => {
1842                // Git
1843                (is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs())
1844                        ||
1845                        // Selections
1846                        (is_singleton && scrollbar_settings.selections && !highlighted_ranges.is_empty())
1847                        // Scrollmanager
1848                        || editor.scroll_manager.scrollbars_visible()
1849            }
1850            ShowScrollbar::System => editor.scroll_manager.scrollbars_visible(),
1851            ShowScrollbar::Always => true,
1852            ShowScrollbar::Never => false,
1853        };
1854
1855        let fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Hsla)> = fold_ranges
1856            .into_iter()
1857            .map(|(id, fold)| {
1858                todo!("folds!")
1859                // let color = self
1860                //     .style
1861                //     .folds
1862                //     .ellipses
1863                //     .background
1864                //     .style_for(&mut cx.mouse_state::<FoldMarkers>(id as usize))
1865                //     .color;
1866
1867                // (id, fold, color)
1868            })
1869            .collect();
1870
1871        let head_for_relative = newest_selection_head.unwrap_or_else(|| {
1872            let newest = editor.selections.newest::<Point>(cx);
1873            SelectionLayout::new(
1874                newest,
1875                editor.selections.line_mode,
1876                editor.cursor_shape,
1877                &snapshot.display_snapshot,
1878                true,
1879                true,
1880            )
1881            .head
1882        });
1883
1884        let (line_number_layouts, fold_statuses) = self.layout_line_numbers(
1885            start_row..end_row,
1886            &active_rows,
1887            head_for_relative,
1888            is_singleton,
1889            &snapshot,
1890            cx,
1891        );
1892
1893        let display_hunks = self.layout_git_gutters(start_row..end_row, &snapshot);
1894
1895        let scrollbar_row_range = scroll_position.y..(scroll_position.y + height_in_lines);
1896
1897        let mut max_visible_line_width = Pixels::ZERO;
1898        let line_layouts =
1899            self.layout_lines(start_row..end_row, &line_number_layouts, &snapshot, cx);
1900        for line_with_invisibles in &line_layouts {
1901            if line_with_invisibles.line.width > max_visible_line_width {
1902                max_visible_line_width = line_with_invisibles.line.width;
1903            }
1904        }
1905
1906        let longest_line_width = layout_line(snapshot.longest_row(), &snapshot, &style, cx)
1907            .unwrap()
1908            .width;
1909        let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.width;
1910        // todo!("blocks")
1911        // let (scroll_width, blocks) = self.layout_blocks(
1912        //     start_row..end_row,
1913        //     &snapshot,
1914        //     size.x,
1915        //     scroll_width,
1916        //     gutter_padding,
1917        //     gutter_width,
1918        //     em_width,
1919        //     gutter_width + gutter_margin,
1920        //     line_height,
1921        //     &style,
1922        //     &line_layouts,
1923        //     editor,
1924        //     cx,
1925        // );
1926
1927        let scroll_max = point(
1928            f32::from((scroll_width - text_size.width) / em_width).max(0.0),
1929            max_row as f32,
1930        );
1931
1932        let clamped = editor.scroll_manager.clamp_scroll_left(scroll_max.x);
1933
1934        let autoscrolled = if autoscroll_horizontally {
1935            editor.autoscroll_horizontally(
1936                start_row,
1937                text_size.width,
1938                scroll_width,
1939                em_width,
1940                &line_layouts,
1941                cx,
1942            )
1943        } else {
1944            false
1945        };
1946
1947        if clamped || autoscrolled {
1948            snapshot = editor.snapshot(cx);
1949        }
1950
1951        // todo!("context menu")
1952        // let mut context_menu = None;
1953        // let mut code_actions_indicator = None;
1954        // if let Some(newest_selection_head) = newest_selection_head {
1955        //     if (start_row..end_row).contains(&newest_selection_head.row()) {
1956        //         if editor.context_menu_visible() {
1957        //             context_menu =
1958        //                 editor.render_context_menu(newest_selection_head, style.clone(), cx);
1959        //         }
1960
1961        //         let active = matches!(
1962        //             editor.context_menu.read().as_ref(),
1963        //             Some(crate::ContextMenu::CodeActions(_))
1964        //         );
1965
1966        //         code_actions_indicator = editor
1967        //             .render_code_actions_indicator(&style, active, cx)
1968        //             .map(|indicator| (newest_selection_head.row(), indicator));
1969        //     }
1970        // }
1971
1972        let visible_rows = start_row..start_row + line_layouts.len() as u32;
1973        // todo!("hover")
1974        // let mut hover = editor.hover_state.render(
1975        //     &snapshot,
1976        //     &style,
1977        //     visible_rows,
1978        //     editor.workspace.as_ref().map(|(w, _)| w.clone()),
1979        //     cx,
1980        // );
1981        // let mode = editor.mode;
1982
1983        // todo!("fold_indicators")
1984        // let mut fold_indicators = editor.render_fold_indicators(
1985        //     fold_statuses,
1986        //     &style,
1987        //     editor.gutter_hovered,
1988        //     line_height,
1989        //     gutter_margin,
1990        //     cx,
1991        // );
1992
1993        // todo!("context_menu")
1994        // if let Some((_, context_menu)) = context_menu.as_mut() {
1995        //     context_menu.layout(
1996        //         SizeConstraint {
1997        //             min: gpui::Point::<Pixels>::zero(),
1998        //             max: point(
1999        //                 cx.window_size().x * 0.7,
2000        //                 (12. * line_height).min((size.y - line_height) / 2.),
2001        //             ),
2002        //         },
2003        //         editor,
2004        //         cx,
2005        //     );
2006        // }
2007
2008        // todo!("code actions")
2009        // if let Some((_, indicator)) = code_actions_indicator.as_mut() {
2010        //     indicator.layout(
2011        //         SizeConstraint::strict_along(
2012        //             Axis::Vertical,
2013        //             line_height * style.code_actions.vertical_scale,
2014        //         ),
2015        //         editor,
2016        //         cx,
2017        //     );
2018        // }
2019
2020        // todo!("fold indicators")
2021        // for fold_indicator in fold_indicators.iter_mut() {
2022        //     if let Some(indicator) = fold_indicator.as_mut() {
2023        //         indicator.layout(
2024        //             SizeConstraint::strict_along(
2025        //                 Axis::Vertical,
2026        //                 line_height * style.code_actions.vertical_scale,
2027        //             ),
2028        //             editor,
2029        //             cx,
2030        //         );
2031        //     }
2032        // }
2033
2034        // todo!("hover popovers")
2035        // if let Some((_, hover_popovers)) = hover.as_mut() {
2036        //     for hover_popover in hover_popovers.iter_mut() {
2037        //         hover_popover.layout(
2038        //             SizeConstraint {
2039        //                 min: gpui::Point::<Pixels>::zero(),
2040        //                 max: point(
2041        //                     (120. * em_width) // Default size
2042        //                         .min(size.x / 2.) // Shrink to half of the editor width
2043        //                         .max(MIN_POPOVER_CHARACTER_WIDTH * em_width), // Apply minimum width of 20 characters
2044        //                     (16. * line_height) // Default size
2045        //                         .min(size.y / 2.) // Shrink to half of the editor height
2046        //                         .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
2047        //                 ),
2048        //             },
2049        //             editor,
2050        //             cx,
2051        //         );
2052        //     }
2053        // }
2054
2055        let invisible_symbol_font_size = font_size / 2.;
2056        let tab_invisible = cx
2057            .text_system()
2058            .layout_text(
2059                "",
2060                invisible_symbol_font_size,
2061                &[TextRun {
2062                    len: "".len(),
2063                    font: self.style.text.font(),
2064                    color: cx.theme().colors().editor_invisible,
2065                    underline: None,
2066                }],
2067                None,
2068            )
2069            .unwrap()
2070            .pop()
2071            .unwrap();
2072        let space_invisible = cx
2073            .text_system()
2074            .layout_text(
2075                "",
2076                invisible_symbol_font_size,
2077                &[TextRun {
2078                    len: "".len(),
2079                    font: self.style.text.font(),
2080                    color: cx.theme().colors().editor_invisible,
2081                    underline: None,
2082                }],
2083                None,
2084            )
2085            .unwrap()
2086            .pop()
2087            .unwrap();
2088
2089        LayoutState {
2090            mode: editor_mode,
2091            position_map: Arc::new(PositionMap {
2092                size: bounds.size,
2093                scroll_max,
2094                line_layouts,
2095                line_height,
2096                em_width,
2097                em_advance,
2098                snapshot,
2099            }),
2100            visible_display_row_range: start_row..end_row,
2101            wrap_guides,
2102            gutter_size,
2103            gutter_padding,
2104            text_size,
2105            scrollbar_row_range,
2106            show_scrollbars,
2107            is_singleton,
2108            max_row,
2109            gutter_margin,
2110            active_rows,
2111            highlighted_rows,
2112            highlighted_ranges,
2113            fold_ranges,
2114            line_number_layouts,
2115            display_hunks,
2116            // blocks,
2117            selections,
2118            // context_menu,
2119            // code_actions_indicator,
2120            // fold_indicators,
2121            tab_invisible,
2122            space_invisible,
2123            // hover_popovers: hover,
2124        }
2125    }
2126
2127    // #[allow(clippy::too_many_arguments)]
2128    // fn layout_blocks(
2129    //     &mut self,
2130    //     rows: Range<u32>,
2131    //     snapshot: &EditorSnapshot,
2132    //     editor_width: f32,
2133    //     scroll_width: f32,
2134    //     gutter_padding: f32,
2135    //     gutter_width: f32,
2136    //     em_width: f32,
2137    //     text_x: f32,
2138    //     line_height: f32,
2139    //     style: &EditorStyle,
2140    //     line_layouts: &[LineWithInvisibles],
2141    //     editor: &mut Editor,
2142    //     cx: &mut ViewContext<Editor>,
2143    // ) -> (f32, Vec<BlockLayout>) {
2144    //     let mut block_id = 0;
2145    //     let scroll_x = snapshot.scroll_anchor.offset.x;
2146    //     let (fixed_blocks, non_fixed_blocks) = snapshot
2147    //         .blocks_in_range(rows.clone())
2148    //         .partition::<Vec<_>, _>(|(_, block)| match block {
2149    //             TransformBlock::ExcerptHeader { .. } => false,
2150    //             TransformBlock::Custom(block) => block.style() == BlockStyle::Fixed,
2151    //         });
2152    //     let mut render_block = |block: &TransformBlock, width: f32, block_id: usize| {
2153    //         let mut element = match block {
2154    //             TransformBlock::Custom(block) => {
2155    //                 let align_to = block
2156    //                     .position()
2157    //                     .to_point(&snapshot.buffer_snapshot)
2158    //                     .to_display_point(snapshot);
2159    //                 let anchor_x = text_x
2160    //                     + if rows.contains(&align_to.row()) {
2161    //                         line_layouts[(align_to.row() - rows.start) as usize]
2162    //                             .line
2163    //                             .x_for_index(align_to.column() as usize)
2164    //                     } else {
2165    //                         layout_line(align_to.row(), snapshot, style, cx.text_layout_cache())
2166    //                             .x_for_index(align_to.column() as usize)
2167    //                     };
2168
2169    //                 block.render(&mut BlockContext {
2170    //                     view_context: cx,
2171    //                     anchor_x,
2172    //                     gutter_padding,
2173    //                     line_height,
2174    //                     scroll_x,
2175    //                     gutter_width,
2176    //                     em_width,
2177    //                     block_id,
2178    //                 })
2179    //             }
2180    //             TransformBlock::ExcerptHeader {
2181    //                 id,
2182    //                 buffer,
2183    //                 range,
2184    //                 starts_new_buffer,
2185    //                 ..
2186    //             } => {
2187    //                 let tooltip_style = theme::current(cx).tooltip.clone();
2188    //                 let include_root = editor
2189    //                     .project
2190    //                     .as_ref()
2191    //                     .map(|project| project.read(cx).visible_worktrees(cx).count() > 1)
2192    //                     .unwrap_or_default();
2193    //                 let jump_icon = project::File::from_dyn(buffer.file()).map(|file| {
2194    //                     let jump_path = ProjectPath {
2195    //                         worktree_id: file.worktree_id(cx),
2196    //                         path: file.path.clone(),
2197    //                     };
2198    //                     let jump_anchor = range
2199    //                         .primary
2200    //                         .as_ref()
2201    //                         .map_or(range.context.start, |primary| primary.start);
2202    //                     let jump_position = language::ToPoint::to_point(&jump_anchor, buffer);
2203
2204    //                     enum JumpIcon {}
2205    //                     MouseEventHandler::new::<JumpIcon, _>((*id).into(), cx, |state, _| {
2206    //                         let style = style.jump_icon.style_for(state);
2207    //                         Svg::new("icons/arrow_up_right.svg")
2208    //                             .with_color(style.color)
2209    //                             .constrained()
2210    //                             .with_width(style.icon_width)
2211    //                             .aligned()
2212    //                             .contained()
2213    //                             .with_style(style.container)
2214    //                             .constrained()
2215    //                             .with_width(style.button_width)
2216    //                             .with_height(style.button_width)
2217    //                     })
2218    //                     .with_cursor_style(CursorStyle::PointingHand)
2219    //                     .on_click(MouseButton::Left, move |_, editor, cx| {
2220    //                         if let Some(workspace) = editor
2221    //                             .workspace
2222    //                             .as_ref()
2223    //                             .and_then(|(workspace, _)| workspace.upgrade(cx))
2224    //                         {
2225    //                             workspace.update(cx, |workspace, cx| {
2226    //                                 Editor::jump(
2227    //                                     workspace,
2228    //                                     jump_path.clone(),
2229    //                                     jump_position,
2230    //                                     jump_anchor,
2231    //                                     cx,
2232    //                                 );
2233    //                             });
2234    //                         }
2235    //                     })
2236    //                     .with_tooltip::<JumpIcon>(
2237    //                         (*id).into(),
2238    //                         "Jump to Buffer".to_string(),
2239    //                         Some(Box::new(crate::OpenExcerpts)),
2240    //                         tooltip_style.clone(),
2241    //                         cx,
2242    //                     )
2243    //                     .aligned()
2244    //                     .flex_float()
2245    //                 });
2246
2247    //                 if *starts_new_buffer {
2248    //                     let editor_font_size = style.text.font_size;
2249    //                     let style = &style.diagnostic_path_header;
2250    //                     let font_size = (style.text_scale_factor * editor_font_size).round();
2251
2252    //                     let path = buffer.resolve_file_path(cx, include_root);
2253    //                     let mut filename = None;
2254    //                     let mut parent_path = None;
2255    //                     // Can't use .and_then() because `.file_name()` and `.parent()` return references :(
2256    //                     if let Some(path) = path {
2257    //                         filename = path.file_name().map(|f| f.to_string_lossy.to_string());
2258    //                         parent_path =
2259    //                             path.parent().map(|p| p.to_string_lossy.to_string() + "/");
2260    //                     }
2261
2262    //                     Flex::row()
2263    //                         .with_child(
2264    //                             Label::new(
2265    //                                 filename.unwrap_or_else(|| "untitled".to_string()),
2266    //                                 style.filename.text.clone().with_font_size(font_size),
2267    //                             )
2268    //                             .contained()
2269    //                             .with_style(style.filename.container)
2270    //                             .aligned(),
2271    //                         )
2272    //                         .with_children(parent_path.map(|path| {
2273    //                             Label::new(path, style.path.text.clone().with_font_size(font_size))
2274    //                                 .contained()
2275    //                                 .with_style(style.path.container)
2276    //                                 .aligned()
2277    //                         }))
2278    //                         .with_children(jump_icon)
2279    //                         .contained()
2280    //                         .with_style(style.container)
2281    //                         .with_padding_left(gutter_padding)
2282    //                         .with_padding_right(gutter_padding)
2283    //                         .expanded()
2284    //                         .into_any_named("path header block")
2285    //                 } else {
2286    //                     let text_style = style.text.clone();
2287    //                     Flex::row()
2288    //                         .with_child(Label::new("⋯", text_style))
2289    //                         .with_children(jump_icon)
2290    //                         .contained()
2291    //                         .with_padding_left(gutter_padding)
2292    //                         .with_padding_right(gutter_padding)
2293    //                         .expanded()
2294    //                         .into_any_named("collapsed context")
2295    //                 }
2296    //             }
2297    //         };
2298
2299    //         element.layout(
2300    //             SizeConstraint {
2301    //                 min: gpui::Point::<Pixels>::zero(),
2302    //                 max: point(width, block.height() as f32 * line_height),
2303    //             },
2304    //             editor,
2305    //             cx,
2306    //         );
2307    //         element
2308    //     };
2309
2310    //     let mut fixed_block_max_width = 0f32;
2311    //     let mut blocks = Vec::new();
2312    //     for (row, block) in fixed_blocks {
2313    //         let element = render_block(block, f32::INFINITY, block_id);
2314    //         block_id += 1;
2315    //         fixed_block_max_width = fixed_block_max_width.max(element.size().x + em_width);
2316    //         blocks.push(BlockLayout {
2317    //             row,
2318    //             element,
2319    //             style: BlockStyle::Fixed,
2320    //         });
2321    //     }
2322    //     for (row, block) in non_fixed_blocks {
2323    //         let style = match block {
2324    //             TransformBlock::Custom(block) => block.style(),
2325    //             TransformBlock::ExcerptHeader { .. } => BlockStyle::Sticky,
2326    //         };
2327    //         let width = match style {
2328    //             BlockStyle::Sticky => editor_width,
2329    //             BlockStyle::Flex => editor_width
2330    //                 .max(fixed_block_max_width)
2331    //                 .max(gutter_width + scroll_width),
2332    //             BlockStyle::Fixed => unreachable!(),
2333    //         };
2334    //         let element = render_block(block, width, block_id);
2335    //         block_id += 1;
2336    //         blocks.push(BlockLayout {
2337    //             row,
2338    //             element,
2339    //             style,
2340    //         });
2341    //     }
2342    //     (
2343    //         scroll_width.max(fixed_block_max_width - gutter_width),
2344    //         blocks,
2345    //     )
2346    // }
2347}
2348
2349#[derive(Debug)]
2350pub struct LineWithInvisibles {
2351    pub line: Line,
2352    invisibles: Vec<Invisible>,
2353}
2354
2355impl LineWithInvisibles {
2356    fn from_chunks<'a>(
2357        chunks: impl Iterator<Item = HighlightedChunk<'a>>,
2358        text_style: &TextStyle,
2359        max_line_len: usize,
2360        max_line_count: usize,
2361        line_number_layouts: &[Option<Line>],
2362        editor_mode: EditorMode,
2363        cx: &WindowContext,
2364    ) -> Vec<Self> {
2365        let mut layouts = Vec::with_capacity(max_line_count);
2366        let mut line = String::new();
2367        let mut invisibles = Vec::new();
2368        let mut styles = Vec::new();
2369        let mut non_whitespace_added = false;
2370        let mut row = 0;
2371        let mut line_exceeded_max_len = false;
2372        let font_size = text_style.font_size.to_pixels(cx.rem_size());
2373
2374        for highlighted_chunk in chunks.chain([HighlightedChunk {
2375            chunk: "\n",
2376            style: None,
2377            is_tab: false,
2378        }]) {
2379            for (ix, mut line_chunk) in highlighted_chunk.chunk.split('\n').enumerate() {
2380                if ix > 0 {
2381                    let layout = cx
2382                        .text_system()
2383                        .layout_text(&line, font_size, &styles, None);
2384                    layouts.push(Self {
2385                        line: layout.unwrap().pop().unwrap(),
2386                        invisibles: invisibles.drain(..).collect(),
2387                    });
2388
2389                    line.clear();
2390                    styles.clear();
2391                    row += 1;
2392                    line_exceeded_max_len = false;
2393                    non_whitespace_added = false;
2394                    if row == max_line_count {
2395                        return layouts;
2396                    }
2397                }
2398
2399                if !line_chunk.is_empty() && !line_exceeded_max_len {
2400                    let text_style = if let Some(style) = highlighted_chunk.style {
2401                        text_style
2402                            .clone()
2403                            .highlight(style)
2404                            .map(Cow::Owned)
2405                            .unwrap_or_else(|_| Cow::Borrowed(text_style))
2406                    } else {
2407                        Cow::Borrowed(text_style)
2408                    };
2409
2410                    if line.len() + line_chunk.len() > max_line_len {
2411                        let mut chunk_len = max_line_len - line.len();
2412                        while !line_chunk.is_char_boundary(chunk_len) {
2413                            chunk_len -= 1;
2414                        }
2415                        line_chunk = &line_chunk[..chunk_len];
2416                        line_exceeded_max_len = true;
2417                    }
2418
2419                    styles.push(TextRun {
2420                        len: line_chunk.len(),
2421                        font: text_style.font(),
2422                        color: text_style.color,
2423                        underline: text_style.underline,
2424                    });
2425
2426                    if editor_mode == EditorMode::Full {
2427                        // Line wrap pads its contents with fake whitespaces,
2428                        // avoid printing them
2429                        let inside_wrapped_string = line_number_layouts
2430                            .get(row)
2431                            .and_then(|layout| layout.as_ref())
2432                            .is_none();
2433                        if highlighted_chunk.is_tab {
2434                            if non_whitespace_added || !inside_wrapped_string {
2435                                invisibles.push(Invisible::Tab {
2436                                    line_start_offset: line.len(),
2437                                });
2438                            }
2439                        } else {
2440                            invisibles.extend(
2441                                line_chunk
2442                                    .chars()
2443                                    .enumerate()
2444                                    .filter(|(_, line_char)| {
2445                                        let is_whitespace = line_char.is_whitespace();
2446                                        non_whitespace_added |= !is_whitespace;
2447                                        is_whitespace
2448                                            && (non_whitespace_added || !inside_wrapped_string)
2449                                    })
2450                                    .map(|(whitespace_index, _)| Invisible::Whitespace {
2451                                        line_offset: line.len() + whitespace_index,
2452                                    }),
2453                            )
2454                        }
2455                    }
2456
2457                    line.push_str(line_chunk);
2458                }
2459            }
2460        }
2461
2462        layouts
2463    }
2464
2465    fn draw(
2466        &self,
2467        layout: &LayoutState,
2468        row: u32,
2469        scroll_top: Pixels,
2470        content_origin: gpui::Point<Pixels>,
2471        scroll_left: Pixels,
2472        whitespace_setting: ShowWhitespaceSetting,
2473        selection_ranges: &[Range<DisplayPoint>],
2474        cx: &mut ViewContext<Editor>,
2475    ) {
2476        let line_height = layout.position_map.line_height;
2477        let line_y = line_height * row as f32 - scroll_top;
2478
2479        self.line.paint(
2480            content_origin + gpui::point(-scroll_left, line_y),
2481            line_height,
2482            cx,
2483        );
2484
2485        self.draw_invisibles(
2486            &selection_ranges,
2487            layout,
2488            content_origin,
2489            scroll_left,
2490            line_y,
2491            row,
2492            line_height,
2493            whitespace_setting,
2494            cx,
2495        );
2496    }
2497
2498    fn draw_invisibles(
2499        &self,
2500        selection_ranges: &[Range<DisplayPoint>],
2501        layout: &LayoutState,
2502        content_origin: gpui::Point<Pixels>,
2503        scroll_left: Pixels,
2504        line_y: Pixels,
2505        row: u32,
2506        line_height: Pixels,
2507        whitespace_setting: ShowWhitespaceSetting,
2508        cx: &mut ViewContext<Editor>,
2509    ) {
2510        let allowed_invisibles_regions = match whitespace_setting {
2511            ShowWhitespaceSetting::None => return,
2512            ShowWhitespaceSetting::Selection => Some(selection_ranges),
2513            ShowWhitespaceSetting::All => None,
2514        };
2515
2516        for invisible in &self.invisibles {
2517            let (&token_offset, invisible_symbol) = match invisible {
2518                Invisible::Tab { line_start_offset } => (line_start_offset, &layout.tab_invisible),
2519                Invisible::Whitespace { line_offset } => (line_offset, &layout.space_invisible),
2520            };
2521
2522            let x_offset = self.line.x_for_index(token_offset);
2523            let invisible_offset =
2524                (layout.position_map.em_width - invisible_symbol.width).max(Pixels::ZERO) / 2.0;
2525            let origin =
2526                content_origin + gpui::point(-scroll_left + x_offset + invisible_offset, line_y);
2527
2528            if let Some(allowed_regions) = allowed_invisibles_regions {
2529                let invisible_point = DisplayPoint::new(row, token_offset as u32);
2530                if !allowed_regions
2531                    .iter()
2532                    .any(|region| region.start <= invisible_point && invisible_point < region.end)
2533                {
2534                    continue;
2535                }
2536            }
2537            invisible_symbol.paint(origin, line_height, cx);
2538        }
2539    }
2540}
2541
2542#[derive(Debug, Clone, Copy, PartialEq, Eq)]
2543enum Invisible {
2544    Tab { line_start_offset: usize },
2545    Whitespace { line_offset: usize },
2546}
2547
2548impl Element<Editor> for EditorElement {
2549    type ElementState = ();
2550
2551    fn id(&self) -> Option<gpui::ElementId> {
2552        None
2553    }
2554
2555    fn initialize(
2556        &mut self,
2557        editor: &mut Editor,
2558        element_state: Option<Self::ElementState>,
2559        cx: &mut gpui::ViewContext<Editor>,
2560    ) -> Self::ElementState {
2561        editor.style = Some(self.style.clone()); // Long-term, we'd like to eliminate this.
2562
2563        let dispatch_context = editor.dispatch_context(cx);
2564        cx.with_element_id(cx.view().entity_id(), |global_id, cx| {
2565            cx.with_key_dispatch_context(dispatch_context, |cx| {
2566                cx.with_key_listeners(
2567                    [
2568                        build_action_listener(Editor::move_left),
2569                        build_action_listener(Editor::move_right),
2570                        build_action_listener(Editor::move_down),
2571                        build_action_listener(Editor::move_up),
2572                        // build_action_listener(Editor::new_file), todo!()
2573                        // build_action_listener(Editor::new_file_in_direction), todo!()
2574                        build_action_listener(Editor::cancel),
2575                        build_action_listener(Editor::newline),
2576                        build_action_listener(Editor::newline_above),
2577                        build_action_listener(Editor::newline_below),
2578                        build_action_listener(Editor::backspace),
2579                        build_action_listener(Editor::delete),
2580                        build_action_listener(Editor::tab),
2581                        build_action_listener(Editor::tab_prev),
2582                        build_action_listener(Editor::indent),
2583                        build_action_listener(Editor::outdent),
2584                        build_action_listener(Editor::delete_line),
2585                        build_action_listener(Editor::join_lines),
2586                        build_action_listener(Editor::sort_lines_case_sensitive),
2587                        build_action_listener(Editor::sort_lines_case_insensitive),
2588                        build_action_listener(Editor::reverse_lines),
2589                        build_action_listener(Editor::shuffle_lines),
2590                        build_action_listener(Editor::convert_to_upper_case),
2591                        build_action_listener(Editor::convert_to_lower_case),
2592                        build_action_listener(Editor::convert_to_title_case),
2593                        build_action_listener(Editor::convert_to_snake_case),
2594                        build_action_listener(Editor::convert_to_kebab_case),
2595                        build_action_listener(Editor::convert_to_upper_camel_case),
2596                        build_action_listener(Editor::convert_to_lower_camel_case),
2597                        build_action_listener(Editor::delete_to_previous_word_start),
2598                        build_action_listener(Editor::delete_to_previous_subword_start),
2599                        build_action_listener(Editor::delete_to_next_word_end),
2600                        build_action_listener(Editor::delete_to_next_subword_end),
2601                        build_action_listener(Editor::delete_to_beginning_of_line),
2602                        build_action_listener(Editor::delete_to_end_of_line),
2603                        build_action_listener(Editor::cut_to_end_of_line),
2604                        build_action_listener(Editor::duplicate_line),
2605                        build_action_listener(Editor::move_line_up),
2606                        build_action_listener(Editor::move_line_down),
2607                        build_action_listener(Editor::transpose),
2608                        build_action_listener(Editor::cut),
2609                        build_action_listener(Editor::copy),
2610                        build_action_listener(Editor::paste),
2611                        build_action_listener(Editor::undo),
2612                        build_action_listener(Editor::redo),
2613                        build_action_listener(Editor::move_page_up),
2614                        build_action_listener(Editor::move_page_down),
2615                        build_action_listener(Editor::next_screen),
2616                        build_action_listener(Editor::scroll_cursor_top),
2617                        build_action_listener(Editor::scroll_cursor_center),
2618                        build_action_listener(Editor::scroll_cursor_bottom),
2619                        build_action_listener(|editor, _: &LineDown, cx| {
2620                            editor.scroll_screen(&ScrollAmount::Line(1.), cx)
2621                        }),
2622                        build_action_listener(|editor, _: &LineUp, cx| {
2623                            editor.scroll_screen(&ScrollAmount::Line(-1.), cx)
2624                        }),
2625                        build_action_listener(|editor, _: &HalfPageDown, cx| {
2626                            editor.scroll_screen(&ScrollAmount::Page(0.5), cx)
2627                        }),
2628                        build_action_listener(|editor, _: &HalfPageUp, cx| {
2629                            editor.scroll_screen(&ScrollAmount::Page(-0.5), cx)
2630                        }),
2631                        build_action_listener(|editor, _: &PageDown, cx| {
2632                            editor.scroll_screen(&ScrollAmount::Page(1.), cx)
2633                        }),
2634                        build_action_listener(|editor, _: &PageUp, cx| {
2635                            editor.scroll_screen(&ScrollAmount::Page(-1.), cx)
2636                        }),
2637                        build_action_listener(Editor::move_to_previous_word_start),
2638                        build_action_listener(Editor::move_to_previous_subword_start),
2639                        build_action_listener(Editor::move_to_next_word_end),
2640                        build_action_listener(Editor::move_to_next_subword_end),
2641                        build_action_listener(Editor::move_to_beginning_of_line),
2642                        build_action_listener(Editor::move_to_end_of_line),
2643                        build_action_listener(Editor::move_to_start_of_paragraph),
2644                        build_action_listener(Editor::move_to_end_of_paragraph),
2645                        build_action_listener(Editor::move_to_beginning),
2646                        build_action_listener(Editor::move_to_end),
2647                        build_action_listener(Editor::select_up),
2648                        build_action_listener(Editor::select_down),
2649                        build_action_listener(Editor::select_left),
2650                        build_action_listener(Editor::select_right),
2651                        build_action_listener(Editor::select_to_previous_word_start),
2652                        build_action_listener(Editor::select_to_previous_subword_start),
2653                        build_action_listener(Editor::select_to_next_word_end),
2654                        build_action_listener(Editor::select_to_next_subword_end),
2655                        build_action_listener(Editor::select_to_beginning_of_line),
2656                        build_action_listener(Editor::select_to_end_of_line),
2657                        build_action_listener(Editor::select_to_start_of_paragraph),
2658                        build_action_listener(Editor::select_to_end_of_paragraph),
2659                        build_action_listener(Editor::select_to_beginning),
2660                        build_action_listener(Editor::select_to_end),
2661                        build_action_listener(Editor::select_all),
2662                        build_action_listener(|editor, action, cx| {
2663                            editor.select_all_matches(action, cx).log_err();
2664                        }),
2665                        build_action_listener(Editor::select_line),
2666                        build_action_listener(Editor::split_selection_into_lines),
2667                        build_action_listener(Editor::add_selection_above),
2668                        build_action_listener(Editor::add_selection_below),
2669                        build_action_listener(|editor, action, cx| {
2670                            editor.select_next(action, cx).log_err();
2671                        }),
2672                        build_action_listener(|editor, action, cx| {
2673                            editor.select_previous(action, cx).log_err();
2674                        }),
2675                        build_action_listener(Editor::toggle_comments),
2676                        build_action_listener(Editor::select_larger_syntax_node),
2677                        build_action_listener(Editor::select_smaller_syntax_node),
2678                        build_action_listener(Editor::move_to_enclosing_bracket),
2679                        build_action_listener(Editor::undo_selection),
2680                        build_action_listener(Editor::redo_selection),
2681                        build_action_listener(Editor::go_to_diagnostic),
2682                        build_action_listener(Editor::go_to_prev_diagnostic),
2683                        build_action_listener(Editor::go_to_hunk),
2684                        build_action_listener(Editor::go_to_prev_hunk),
2685                        build_action_listener(Editor::go_to_definition),
2686                        build_action_listener(Editor::go_to_definition_split),
2687                        build_action_listener(Editor::go_to_type_definition),
2688                        build_action_listener(Editor::go_to_type_definition_split),
2689                        build_action_listener(Editor::fold),
2690                        build_action_listener(Editor::fold_at),
2691                        build_action_listener(Editor::unfold_lines),
2692                        build_action_listener(Editor::unfold_at),
2693                        // build_action_listener(Editor::gutter_hover), todo!()
2694                        build_action_listener(Editor::fold_selected_ranges),
2695                        build_action_listener(Editor::show_completions),
2696                        // build_action_listener(Editor::toggle_code_actions), todo!()
2697                        // build_action_listener(Editor::open_excerpts), todo!()
2698                        build_action_listener(Editor::toggle_soft_wrap),
2699                        build_action_listener(Editor::toggle_inlay_hints),
2700                        build_action_listener(Editor::reveal_in_finder),
2701                        build_action_listener(Editor::copy_path),
2702                        build_action_listener(Editor::copy_relative_path),
2703                        build_action_listener(Editor::copy_highlight_json),
2704                        build_action_listener(|editor, action, cx| {
2705                            editor
2706                                .format(action, cx)
2707                                .map(|task| task.detach_and_log_err(cx));
2708                        }),
2709                        build_action_listener(Editor::restart_language_server),
2710                        build_action_listener(Editor::show_character_palette),
2711                        // build_action_listener(Editor::confirm_completion), todo!()
2712                        // build_action_listener(Editor::confirm_code_action), todo!()
2713                        // build_action_listener(Editor::rename), todo!()
2714                        // build_action_listener(Editor::confirm_rename), todo!()
2715                        // build_action_listener(Editor::find_all_references), todo!()
2716                        build_action_listener(Editor::next_copilot_suggestion),
2717                        build_action_listener(Editor::previous_copilot_suggestion),
2718                        build_action_listener(Editor::copilot_suggest),
2719                        build_key_listener(
2720                            move |editor, key_down: &KeyDownEvent, dispatch_context, phase, cx| {
2721                                if phase == DispatchPhase::Bubble {
2722                                    if let KeyMatch::Some(action) = cx.match_keystroke(
2723                                        &global_id,
2724                                        &key_down.keystroke,
2725                                        dispatch_context,
2726                                    ) {
2727                                        return Some(action);
2728                                    }
2729                                }
2730
2731                                None
2732                            },
2733                        ),
2734                    ],
2735                    |cx| cx.with_focus(editor.focus_handle.clone(), |_| {}),
2736                );
2737            })
2738        });
2739    }
2740
2741    fn layout(
2742        &mut self,
2743        editor: &mut Editor,
2744        element_state: &mut Self::ElementState,
2745        cx: &mut gpui::ViewContext<Editor>,
2746    ) -> gpui::LayoutId {
2747        let rem_size = cx.rem_size();
2748        let mut style = Style::default();
2749        style.size.width = relative(1.).into();
2750        style.size.height = match editor.mode {
2751            EditorMode::SingleLine => self.style.text.line_height_in_pixels(cx.rem_size()).into(),
2752            EditorMode::AutoHeight { .. } => todo!(),
2753            EditorMode::Full => relative(1.).into(),
2754        };
2755        cx.request_layout(&style, None)
2756    }
2757
2758    fn paint(
2759        &mut self,
2760        bounds: Bounds<gpui::Pixels>,
2761        editor: &mut Editor,
2762        element_state: &mut Self::ElementState,
2763        cx: &mut gpui::ViewContext<Editor>,
2764    ) {
2765        let layout = self.compute_layout(editor, cx, bounds);
2766
2767        cx.on_mouse_event({
2768            let position_map = layout.position_map.clone();
2769            move |editor, event: &ScrollWheelEvent, phase, cx| {
2770                if phase != DispatchPhase::Bubble {
2771                    return;
2772                }
2773
2774                if Self::scroll(editor, event, &position_map, bounds, cx) {
2775                    cx.stop_propagation();
2776                }
2777            }
2778        });
2779        cx.on_mouse_event({
2780            let position_map = layout.position_map.clone();
2781            move |editor, event: &MouseMoveEvent, phase, cx| {
2782                if phase != DispatchPhase::Bubble {
2783                    return;
2784                }
2785
2786                if Self::mouse_moved(editor, event, &position_map, bounds, cx) {
2787                    cx.stop_propagation()
2788                }
2789            }
2790        });
2791
2792        if editor.focus_handle.is_focused(cx) {
2793            cx.handle_text_input();
2794        }
2795
2796        cx.with_content_mask(ContentMask { bounds }, |cx| {
2797            let gutter_bounds = Bounds {
2798                origin: bounds.origin,
2799                size: layout.gutter_size,
2800            };
2801            let text_bounds = Bounds {
2802                origin: gutter_bounds.upper_right(),
2803                size: layout.text_size,
2804            };
2805
2806            self.paint_background(gutter_bounds, text_bounds, &layout, cx);
2807            if layout.gutter_size.width > Pixels::ZERO {
2808                self.paint_gutter(gutter_bounds, &layout, editor, cx);
2809            }
2810            self.paint_text(text_bounds, &layout, editor, cx);
2811        });
2812    }
2813}
2814
2815// impl EditorElement {
2816//     type LayoutState = LayoutState;
2817//     type PaintState = ();
2818
2819//     fn layout(
2820//         &mut self,
2821//         constraint: SizeConstraint,
2822//         editor: &mut Editor,
2823//         cx: &mut ViewContext<Editor>,
2824//     ) -> (gpui::Point<Pixels>, Self::LayoutState) {
2825//         let mut size = constraint.max;
2826//         if size.x.is_infinite() {
2827//             unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
2828//         }
2829
2830//         let snapshot = editor.snapshot(cx);
2831//         let style = self.style.clone();
2832
2833//         let line_height = (style.text.font_size * style.line_height_scalar).round();
2834
2835//         let gutter_padding;
2836//         let gutter_width;
2837//         let gutter_margin;
2838//         if snapshot.show_gutter {
2839//             let em_width = style.text.em_width(cx.font_cache());
2840//             gutter_padding = (em_width * style.gutter_padding_factor).round();
2841//             gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
2842//             gutter_margin = -style.text.descent(cx.font_cache());
2843//         } else {
2844//             gutter_padding = 0.0;
2845//             gutter_width = 0.0;
2846//             gutter_margin = 0.0;
2847//         };
2848
2849//         let text_width = size.x - gutter_width;
2850//         let em_width = style.text.em_width(cx.font_cache());
2851//         let em_advance = style.text.em_advance(cx.font_cache());
2852//         let overscroll = point(em_width, 0.);
2853//         let snapshot = {
2854//             editor.set_visible_line_count(size.y / line_height, cx);
2855
2856//             let editor_width = text_width - gutter_margin - overscroll.x - em_width;
2857//             let wrap_width = match editor.soft_wrap_mode(cx) {
2858//                 SoftWrap::None => (MAX_LINE_LEN / 2) as f32 * em_advance,
2859//                 SoftWrap::EditorWidth => editor_width,
2860//                 SoftWrap::Column(column) => editor_width.min(column as f32 * em_advance),
2861//             };
2862
2863//             if editor.set_wrap_width(Some(wrap_width), cx) {
2864//                 editor.snapshot(cx)
2865//             } else {
2866//                 snapshot
2867//             }
2868//         };
2869
2870//         let wrap_guides = editor
2871//             .wrap_guides(cx)
2872//             .iter()
2873//             .map(|(guide, active)| (self.column_pixels(*guide, cx), *active))
2874//             .collect();
2875
2876//         let scroll_height = (snapshot.max_point().row() + 1) as f32 * line_height;
2877//         if let EditorMode::AutoHeight { max_lines } = snapshot.mode {
2878//             size.set_y(
2879//                 scroll_height
2880//                     .min(constraint.max_along(Axis::Vertical))
2881//                     .max(constraint.min_along(Axis::Vertical))
2882//                     .max(line_height)
2883//                     .min(line_height * max_lines as f32),
2884//             )
2885//         } else if let EditorMode::SingleLine = snapshot.mode {
2886//             size.set_y(line_height.max(constraint.min_along(Axis::Vertical)))
2887//         } else if size.y.is_infinite() {
2888//             size.set_y(scroll_height);
2889//         }
2890//         let gutter_size = point(gutter_width, size.y);
2891//         let text_size = point(text_width, size.y);
2892
2893//         let autoscroll_horizontally = editor.autoscroll_vertically(size.y, line_height, cx);
2894//         let mut snapshot = editor.snapshot(cx);
2895
2896//         let scroll_position = snapshot.scroll_position();
2897//         // The scroll position is a fractional point, the whole number of which represents
2898//         // the top of the window in terms of display rows.
2899//         let start_row = scroll_position.y as u32;
2900//         let height_in_lines = size.y / line_height;
2901//         let max_row = snapshot.max_point().row();
2902
2903//         // Add 1 to ensure selections bleed off screen
2904//         let end_row = 1 + cmp::min(
2905//             (scroll_position.y + height_in_lines).ceil() as u32,
2906//             max_row,
2907//         );
2908
2909//         let start_anchor = if start_row == 0 {
2910//             Anchor::min()
2911//         } else {
2912//             snapshot
2913//                 .buffer_snapshot
2914//                 .anchor_before(DisplayPoint::new(start_row, 0).to_offset(&snapshot, Bias::Left))
2915//         };
2916//         let end_anchor = if end_row > max_row {
2917//             Anchor::max
2918//         } else {
2919//             snapshot
2920//                 .buffer_snapshot
2921//                 .anchor_before(DisplayPoint::new(end_row, 0).to_offset(&snapshot, Bias::Right))
2922//         };
2923
2924//         let mut selections: Vec<(SelectionStyle, Vec<SelectionLayout>)> = Vec::new();
2925//         let mut active_rows = BTreeMap::new();
2926//         let mut fold_ranges = Vec::new();
2927//         let is_singleton = editor.is_singleton(cx);
2928
2929//         let highlighted_rows = editor.highlighted_rows();
2930//         let theme = theme::current(cx);
2931//         let highlighted_ranges = editor.background_highlights_in_range(
2932//             start_anchor..end_anchor,
2933//             &snapshot.display_snapshot,
2934//             theme.as_ref(),
2935//         );
2936
2937//         fold_ranges.extend(
2938//             snapshot
2939//                 .folds_in_range(start_anchor..end_anchor)
2940//                 .map(|anchor| {
2941//                     let start = anchor.start.to_point(&snapshot.buffer_snapshot);
2942//                     (
2943//                         start.row,
2944//                         start.to_display_point(&snapshot.display_snapshot)
2945//                             ..anchor.end.to_display_point(&snapshot),
2946//                     )
2947//                 }),
2948//         );
2949
2950//         let mut newest_selection_head = None;
2951
2952//         if editor.show_local_selections {
2953//             let mut local_selections: Vec<Selection<Point>> = editor
2954//                 .selections
2955//                 .disjoint_in_range(start_anchor..end_anchor, cx);
2956//             local_selections.extend(editor.selections.pending(cx));
2957//             let mut layouts = Vec::new();
2958//             let newest = editor.selections.newest(cx);
2959//             for selection in local_selections.drain(..) {
2960//                 let is_empty = selection.start == selection.end;
2961//                 let is_newest = selection == newest;
2962
2963//                 let layout = SelectionLayout::new(
2964//                     selection,
2965//                     editor.selections.line_mode,
2966//                     editor.cursor_shape,
2967//                     &snapshot.display_snapshot,
2968//                     is_newest,
2969//                     true,
2970//                 );
2971//                 if is_newest {
2972//                     newest_selection_head = Some(layout.head);
2973//                 }
2974
2975//                 for row in cmp::max(layout.active_rows.start, start_row)
2976//                     ..=cmp::min(layout.active_rows.end, end_row)
2977//                 {
2978//                     let contains_non_empty_selection = active_rows.entry(row).or_insert(!is_empty);
2979//                     *contains_non_empty_selection |= !is_empty;
2980//                 }
2981//                 layouts.push(layout);
2982//             }
2983
2984//             selections.push((style.selection, layouts));
2985//         }
2986
2987//         if let Some(collaboration_hub) = &editor.collaboration_hub {
2988//             // When following someone, render the local selections in their color.
2989//             if let Some(leader_id) = editor.leader_peer_id {
2990//                 if let Some(collaborator) = collaboration_hub.collaborators(cx).get(&leader_id) {
2991//                     if let Some(participant_index) = collaboration_hub
2992//                         .user_participant_indices(cx)
2993//                         .get(&collaborator.user_id)
2994//                     {
2995//                         if let Some((local_selection_style, _)) = selections.first_mut() {
2996//                             *local_selection_style =
2997//                                 style.selection_style_for_room_participant(participant_index.0);
2998//                         }
2999//                     }
3000//                 }
3001//             }
3002
3003//             let mut remote_selections = HashMap::default();
3004//             for selection in snapshot.remote_selections_in_range(
3005//                 &(start_anchor..end_anchor),
3006//                 collaboration_hub.as_ref(),
3007//                 cx,
3008//             ) {
3009//                 let selection_style = if let Some(participant_index) = selection.participant_index {
3010//                     style.selection_style_for_room_participant(participant_index.0)
3011//                 } else {
3012//                     style.absent_selection
3013//                 };
3014
3015//                 // Don't re-render the leader's selections, since the local selections
3016//                 // match theirs.
3017//                 if Some(selection.peer_id) == editor.leader_peer_id {
3018//                     continue;
3019//                 }
3020
3021//                 remote_selections
3022//                     .entry(selection.replica_id)
3023//                     .or_insert((selection_style, Vec::new()))
3024//                     .1
3025//                     .push(SelectionLayout::new(
3026//                         selection.selection,
3027//                         selection.line_mode,
3028//                         selection.cursor_shape,
3029//                         &snapshot.display_snapshot,
3030//                         false,
3031//                         false,
3032//                     ));
3033//             }
3034
3035//             selections.extend(remote_selections.into_values());
3036//         }
3037
3038//         let scrollbar_settings = &settings::get::<EditorSettings>(cx).scrollbar;
3039//         let show_scrollbars = match scrollbar_settings.show {
3040//             ShowScrollbar::Auto => {
3041//                 // Git
3042//                 (is_singleton && scrollbar_settings.git_diff && snapshot.buffer_snapshot.has_git_diffs())
3043//                 ||
3044//                 // Selections
3045//                 (is_singleton && scrollbar_settings.selections && !highlighted_ranges.is_empty)
3046//                 // Scrollmanager
3047//                 || editor.scroll_manager.scrollbars_visible()
3048//             }
3049//             ShowScrollbar::System => editor.scroll_manager.scrollbars_visible(),
3050//             ShowScrollbar::Always => true,
3051//             ShowScrollbar::Never => false,
3052//         };
3053
3054//         let fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Color)> = fold_ranges
3055//             .into_iter()
3056//             .map(|(id, fold)| {
3057//                 let color = self
3058//                     .style
3059//                     .folds
3060//                     .ellipses
3061//                     .background
3062//                     .style_for(&mut cx.mouse_state::<FoldMarkers>(id as usize))
3063//                     .color;
3064
3065//                 (id, fold, color)
3066//             })
3067//             .collect();
3068
3069//         let head_for_relative = newest_selection_head.unwrap_or_else(|| {
3070//             let newest = editor.selections.newest::<Point>(cx);
3071//             SelectionLayout::new(
3072//                 newest,
3073//                 editor.selections.line_mode,
3074//                 editor.cursor_shape,
3075//                 &snapshot.display_snapshot,
3076//                 true,
3077//                 true,
3078//             )
3079//             .head
3080//         });
3081
3082//         let (line_number_layouts, fold_statuses) = self.layout_line_numbers(
3083//             start_row..end_row,
3084//             &active_rows,
3085//             head_for_relative,
3086//             is_singleton,
3087//             &snapshot,
3088//             cx,
3089//         );
3090
3091//         let display_hunks = self.layout_git_gutters(start_row..end_row, &snapshot);
3092
3093//         let scrollbar_row_range = scroll_position.y..(scroll_position.y + height_in_lines);
3094
3095//         let mut max_visible_line_width = 0.0;
3096//         let line_layouts =
3097//             self.layout_lines(start_row..end_row, &line_number_layouts, &snapshot, cx);
3098//         for line_with_invisibles in &line_layouts {
3099//             if line_with_invisibles.line.width() > max_visible_line_width {
3100//                 max_visible_line_width = line_with_invisibles.line.width();
3101//             }
3102//         }
3103
3104//         let style = self.style.clone();
3105//         let longest_line_width = layout_line(
3106//             snapshot.longest_row(),
3107//             &snapshot,
3108//             &style,
3109//             cx.text_layout_cache(),
3110//         )
3111//         .width();
3112//         let scroll_width = longest_line_width.max(max_visible_line_width) + overscroll.x;
3113//         let em_width = style.text.em_width(cx.font_cache());
3114//         let (scroll_width, blocks) = self.layout_blocks(
3115//             start_row..end_row,
3116//             &snapshot,
3117//             size.x,
3118//             scroll_width,
3119//             gutter_padding,
3120//             gutter_width,
3121//             em_width,
3122//             gutter_width + gutter_margin,
3123//             line_height,
3124//             &style,
3125//             &line_layouts,
3126//             editor,
3127//             cx,
3128//         );
3129
3130//         let scroll_max = point(
3131//             ((scroll_width - text_size.x) / em_width).max(0.0),
3132//             max_row as f32,
3133//         );
3134
3135//         let clamped = editor.scroll_manager.clamp_scroll_left(scroll_max.x);
3136
3137//         let autoscrolled = if autoscroll_horizontally {
3138//             editor.autoscroll_horizontally(
3139//                 start_row,
3140//                 text_size.x,
3141//                 scroll_width,
3142//                 em_width,
3143//                 &line_layouts,
3144//                 cx,
3145//             )
3146//         } else {
3147//             false
3148//         };
3149
3150//         if clamped || autoscrolled {
3151//             snapshot = editor.snapshot(cx);
3152//         }
3153
3154//         let style = editor.style(cx);
3155
3156//         let mut context_menu = None;
3157//         let mut code_actions_indicator = None;
3158//         if let Some(newest_selection_head) = newest_selection_head {
3159//             if (start_row..end_row).contains(&newest_selection_head.row()) {
3160//                 if editor.context_menu_visible() {
3161//                     context_menu =
3162//                         editor.render_context_menu(newest_selection_head, style.clone(), cx);
3163//                 }
3164
3165//                 let active = matches!(
3166//                     editor.context_menu.read().as_ref(),
3167//                     Some(crate::ContextMenu::CodeActions(_))
3168//                 );
3169
3170//                 code_actions_indicator = editor
3171//                     .render_code_actions_indicator(&style, active, cx)
3172//                     .map(|indicator| (newest_selection_head.row(), indicator));
3173//             }
3174//         }
3175
3176//         let visible_rows = start_row..start_row + line_layouts.len() as u32;
3177//         let mut hover = editor.hover_state.render(
3178//             &snapshot,
3179//             &style,
3180//             visible_rows,
3181//             editor.workspace.as_ref().map(|(w, _)| w.clone()),
3182//             cx,
3183//         );
3184//         let mode = editor.mode;
3185
3186//         let mut fold_indicators = editor.render_fold_indicators(
3187//             fold_statuses,
3188//             &style,
3189//             editor.gutter_hovered,
3190//             line_height,
3191//             gutter_margin,
3192//             cx,
3193//         );
3194
3195//         if let Some((_, context_menu)) = context_menu.as_mut() {
3196//             context_menu.layout(
3197//                 SizeConstraint {
3198//                     min: gpui::Point::<Pixels>::zero(),
3199//                     max: point(
3200//                         cx.window_size().x * 0.7,
3201//                         (12. * line_height).min((size.y - line_height) / 2.),
3202//                     ),
3203//                 },
3204//                 editor,
3205//                 cx,
3206//             );
3207//         }
3208
3209//         if let Some((_, indicator)) = code_actions_indicator.as_mut() {
3210//             indicator.layout(
3211//                 SizeConstraint::strict_along(
3212//                     Axis::Vertical,
3213//                     line_height * style.code_actions.vertical_scale,
3214//                 ),
3215//                 editor,
3216//                 cx,
3217//             );
3218//         }
3219
3220//         for fold_indicator in fold_indicators.iter_mut() {
3221//             if let Some(indicator) = fold_indicator.as_mut() {
3222//                 indicator.layout(
3223//                     SizeConstraint::strict_along(
3224//                         Axis::Vertical,
3225//                         line_height * style.code_actions.vertical_scale,
3226//                     ),
3227//                     editor,
3228//                     cx,
3229//                 );
3230//             }
3231//         }
3232
3233//         if let Some((_, hover_popovers)) = hover.as_mut() {
3234//             for hover_popover in hover_popovers.iter_mut() {
3235//                 hover_popover.layout(
3236//                     SizeConstraint {
3237//                         min: gpui::Point::<Pixels>::zero(),
3238//                         max: point(
3239//                             (120. * em_width) // Default size
3240//                                 .min(size.x / 2.) // Shrink to half of the editor width
3241//                                 .max(MIN_POPOVER_CHARACTER_WIDTH * em_width), // Apply minimum width of 20 characters
3242//                             (16. * line_height) // Default size
3243//                                 .min(size.y / 2.) // Shrink to half of the editor height
3244//                                 .max(MIN_POPOVER_LINE_HEIGHT * line_height), // Apply minimum height of 4 lines
3245//                         ),
3246//                     },
3247//                     editor,
3248//                     cx,
3249//                 );
3250//             }
3251//         }
3252
3253//         let invisible_symbol_font_size = self.style.text.font_size / 2.0;
3254//         let invisible_symbol_style = RunStyle {
3255//             color: self.style.whitespace,
3256//             font_id: self.style.text.font_id,
3257//             underline: Default::default(),
3258//         };
3259
3260//         (
3261//             size,
3262//             LayoutState {
3263//                 mode,
3264//                 position_map: Arc::new(PositionMap {
3265//                     size,
3266//                     scroll_max,
3267//                     line_layouts,
3268//                     line_height,
3269//                     em_width,
3270//                     em_advance,
3271//                     snapshot,
3272//                 }),
3273//                 visible_display_row_range: start_row..end_row,
3274//                 wrap_guides,
3275//                 gutter_size,
3276//                 gutter_padding,
3277//                 text_size,
3278//                 scrollbar_row_range,
3279//                 show_scrollbars,
3280//                 is_singleton,
3281//                 max_row,
3282//                 gutter_margin,
3283//                 active_rows,
3284//                 highlighted_rows,
3285//                 highlighted_ranges,
3286//                 fold_ranges,
3287//                 line_number_layouts,
3288//                 display_hunks,
3289//                 blocks,
3290//                 selections,
3291//                 context_menu,
3292//                 code_actions_indicator,
3293//                 fold_indicators,
3294//                 tab_invisible: cx.text_layout_cache().layout_str(
3295//                     "→",
3296//                     invisible_symbol_font_size,
3297//                     &[("→".len(), invisible_symbol_style)],
3298//                 ),
3299//                 space_invisible: cx.text_layout_cache().layout_str(
3300//                     "•",
3301//                     invisible_symbol_font_size,
3302//                     &[("•".len(), invisible_symbol_style)],
3303//                 ),
3304//                 hover_popovers: hover,
3305//             },
3306//         )
3307//     }
3308
3309//     fn paint(
3310//         &mut self,
3311//         bounds: Bounds<Pixels>,
3312//         visible_bounds: Bounds<Pixels>,
3313//         layout: &mut Self::LayoutState,
3314//         editor: &mut Editor,
3315//         cx: &mut ViewContext<Editor>,
3316//     ) -> Self::PaintState {
3317//         let visible_bounds = bounds.intersection(visible_bounds).unwrap_or_default();
3318//         cx.scene().push_layer(Some(visible_bounds));
3319
3320//         let gutter_bounds = Bounds::<Pixels>::new(bounds.origin, layout.gutter_size);
3321//         let text_bounds = Bounds::<Pixels>::new(
3322//             bounds.origin + point(layout.gutter_size.x, 0.0),
3323//             layout.text_size,
3324//         );
3325
3326//         Self::attach_mouse_handlers(
3327//             &layout.position_map,
3328//             layout.hover_popovers.is_some(),
3329//             visible_bounds,
3330//             text_bounds,
3331//             gutter_bounds,
3332//             bounds,
3333//             cx,
3334//         );
3335
3336//         self.paint_background(gutter_bounds, text_bounds, layout, cx);
3337//         if layout.gutter_size.x > 0. {
3338//             self.paint_gutter(gutter_bounds, visible_bounds, layout, editor, cx);
3339//         }
3340//         self.paint_text(text_bounds, visible_bounds, layout, editor, cx);
3341
3342//         cx.scene().push_layer(Some(bounds));
3343//         if !layout.blocks.is_empty {
3344//             self.paint_blocks(bounds, visible_bounds, layout, editor, cx);
3345//         }
3346//         self.paint_scrollbar(bounds, layout, &editor, cx);
3347//         cx.scene().pop_layer();
3348//         cx.scene().pop_layer();
3349//     }
3350
3351//     fn rect_for_text_range(
3352//         &self,
3353//         range_utf16: Range<usize>,
3354//         bounds: Bounds<Pixels>,
3355//         _: Bounds<Pixels>,
3356//         layout: &Self::LayoutState,
3357//         _: &Self::PaintState,
3358//         _: &Editor,
3359//         _: &ViewContext<Editor>,
3360//     ) -> Option<Bounds<Pixels>> {
3361//         let text_bounds = Bounds::<Pixels>::new(
3362//             bounds.origin + point(layout.gutter_size.x, 0.0),
3363//             layout.text_size,
3364//         );
3365//         let content_origin = text_bounds.origin + point(layout.gutter_margin, 0.);
3366//         let scroll_position = layout.position_map.snapshot.scroll_position();
3367//         let start_row = scroll_position.y as u32;
3368//         let scroll_top = scroll_position.y * layout.position_map.line_height;
3369//         let scroll_left = scroll_position.x * layout.position_map.em_width;
3370
3371//         let range_start = OffsetUtf16(range_utf16.start)
3372//             .to_display_point(&layout.position_map.snapshot.display_snapshot);
3373//         if range_start.row() < start_row {
3374//             return None;
3375//         }
3376
3377//         let line = &layout
3378//             .position_map
3379//             .line_layouts
3380//             .get((range_start.row() - start_row) as usize)?
3381//             .line;
3382//         let range_start_x = line.x_for_index(range_start.column() as usize);
3383//         let range_start_y = range_start.row() as f32 * layout.position_map.line_height;
3384//         Some(Bounds::<Pixels>::new(
3385//             content_origin
3386//                 + point(
3387//                     range_start_x,
3388//                     range_start_y + layout.position_map.line_height,
3389//                 )
3390//                 - point(scroll_left, scroll_top),
3391//             point(
3392//                 layout.position_map.em_width,
3393//                 layout.position_map.line_height,
3394//             ),
3395//         ))
3396//     }
3397
3398//     fn debug(
3399//         &self,
3400//         bounds: Bounds<Pixels>,
3401//         _: &Self::LayoutState,
3402//         _: &Self::PaintState,
3403//         _: &Editor,
3404//         _: &ViewContext<Editor>,
3405//     ) -> json::Value {
3406//         json!({
3407//             "type": "BufferElement",
3408//             "bounds": bounds.to_json()
3409//         })
3410//     }
3411// }
3412
3413type BufferRow = u32;
3414
3415pub struct LayoutState {
3416    position_map: Arc<PositionMap>,
3417    gutter_size: Size<Pixels>,
3418    gutter_padding: Pixels,
3419    gutter_margin: Pixels,
3420    text_size: gpui::Size<Pixels>,
3421    mode: EditorMode,
3422    wrap_guides: SmallVec<[(Pixels, bool); 2]>,
3423    visible_display_row_range: Range<u32>,
3424    active_rows: BTreeMap<u32, bool>,
3425    highlighted_rows: Option<Range<u32>>,
3426    line_number_layouts: Vec<Option<gpui::Line>>,
3427    display_hunks: Vec<DisplayDiffHunk>,
3428    // blocks: Vec<BlockLayout>,
3429    highlighted_ranges: Vec<(Range<DisplayPoint>, Hsla)>,
3430    fold_ranges: Vec<(BufferRow, Range<DisplayPoint>, Hsla)>,
3431    selections: Vec<(PlayerColor, Vec<SelectionLayout>)>,
3432    scrollbar_row_range: Range<f32>,
3433    show_scrollbars: bool,
3434    is_singleton: bool,
3435    max_row: u32,
3436    // context_menu: Option<(DisplayPoint, AnyElement<Editor>)>,
3437    // code_actions_indicator: Option<(u32, AnyElement<Editor>)>,
3438    // hover_popovers: Option<(DisplayPoint, Vec<AnyElement<Editor>>)>,
3439    // fold_indicators: Vec<Option<AnyElement<Editor>>>,
3440    tab_invisible: Line,
3441    space_invisible: Line,
3442}
3443
3444struct PositionMap {
3445    size: Size<Pixels>,
3446    line_height: Pixels,
3447    scroll_max: gpui::Point<f32>,
3448    em_width: Pixels,
3449    em_advance: Pixels,
3450    line_layouts: Vec<LineWithInvisibles>,
3451    snapshot: EditorSnapshot,
3452}
3453
3454#[derive(Debug, Copy, Clone)]
3455pub struct PointForPosition {
3456    pub previous_valid: DisplayPoint,
3457    pub next_valid: DisplayPoint,
3458    pub exact_unclipped: DisplayPoint,
3459    pub column_overshoot_after_line_end: u32,
3460}
3461
3462impl PointForPosition {
3463    #[cfg(test)]
3464    pub fn valid(valid: DisplayPoint) -> Self {
3465        Self {
3466            previous_valid: valid,
3467            next_valid: valid,
3468            exact_unclipped: valid,
3469            column_overshoot_after_line_end: 0,
3470        }
3471    }
3472
3473    pub fn as_valid(&self) -> Option<DisplayPoint> {
3474        if self.previous_valid == self.exact_unclipped && self.next_valid == self.exact_unclipped {
3475            Some(self.previous_valid)
3476        } else {
3477            None
3478        }
3479    }
3480}
3481
3482impl PositionMap {
3483    fn point_for_position(
3484        &self,
3485        text_bounds: Bounds<Pixels>,
3486        position: gpui::Point<Pixels>,
3487    ) -> PointForPosition {
3488        let scroll_position = self.snapshot.scroll_position();
3489        let position = position - text_bounds.origin;
3490        let y = position.y.max(px(0.)).min(self.size.width);
3491        let x = position.x + (scroll_position.x * self.em_width);
3492        let row = (f32::from(y / self.line_height) + scroll_position.y) as u32;
3493
3494        let (column, x_overshoot_after_line_end) = if let Some(line) = self
3495            .line_layouts
3496            .get(row as usize - scroll_position.y as usize)
3497            .map(|&LineWithInvisibles { ref line, .. }| line)
3498        {
3499            if let Some(ix) = line.index_for_x(x) {
3500                (ix as u32, px(0.))
3501            } else {
3502                (line.len as u32, px(0.).max(x - line.width))
3503            }
3504        } else {
3505            (0, x)
3506        };
3507
3508        let mut exact_unclipped = DisplayPoint::new(row, column);
3509        let previous_valid = self.snapshot.clip_point(exact_unclipped, Bias::Left);
3510        let next_valid = self.snapshot.clip_point(exact_unclipped, Bias::Right);
3511
3512        let column_overshoot_after_line_end = (x_overshoot_after_line_end / self.em_advance).into();
3513        *exact_unclipped.column_mut() += column_overshoot_after_line_end;
3514        PointForPosition {
3515            previous_valid,
3516            next_valid,
3517            exact_unclipped,
3518            column_overshoot_after_line_end,
3519        }
3520    }
3521}
3522
3523struct BlockLayout {
3524    row: u32,
3525    element: AnyElement<Editor>,
3526    style: BlockStyle,
3527}
3528
3529fn layout_line(
3530    row: u32,
3531    snapshot: &EditorSnapshot,
3532    style: &EditorStyle,
3533    cx: &WindowContext,
3534) -> Result<Line> {
3535    let mut line = snapshot.line(row);
3536
3537    if line.len() > MAX_LINE_LEN {
3538        let mut len = MAX_LINE_LEN;
3539        while !line.is_char_boundary(len) {
3540            len -= 1;
3541        }
3542
3543        line.truncate(len);
3544    }
3545
3546    Ok(cx
3547        .text_system()
3548        .layout_text(
3549            &line,
3550            style.text.font_size.to_pixels(cx.rem_size()),
3551            &[TextRun {
3552                len: snapshot.line_len(row) as usize,
3553                font: style.text.font(),
3554                color: Hsla::default(),
3555                underline: None,
3556            }],
3557            None,
3558        )?
3559        .pop()
3560        .unwrap())
3561}
3562
3563#[derive(Debug)]
3564pub struct Cursor {
3565    origin: gpui::Point<Pixels>,
3566    block_width: Pixels,
3567    line_height: Pixels,
3568    color: Hsla,
3569    shape: CursorShape,
3570    block_text: Option<Line>,
3571}
3572
3573impl Cursor {
3574    pub fn new(
3575        origin: gpui::Point<Pixels>,
3576        block_width: Pixels,
3577        line_height: Pixels,
3578        color: Hsla,
3579        shape: CursorShape,
3580        block_text: Option<Line>,
3581    ) -> Cursor {
3582        Cursor {
3583            origin,
3584            block_width,
3585            line_height,
3586            color,
3587            shape,
3588            block_text,
3589        }
3590    }
3591
3592    pub fn bounding_rect(&self, origin: gpui::Point<Pixels>) -> Bounds<Pixels> {
3593        Bounds {
3594            origin: self.origin + origin,
3595            size: size(self.block_width, self.line_height),
3596        }
3597    }
3598
3599    pub fn paint(&self, origin: gpui::Point<Pixels>, cx: &mut WindowContext) {
3600        let bounds = match self.shape {
3601            CursorShape::Bar => Bounds {
3602                origin: self.origin + origin,
3603                size: size(px(2.0), self.line_height),
3604            },
3605            CursorShape::Block | CursorShape::Hollow => Bounds {
3606                origin: self.origin + origin,
3607                size: size(self.block_width, self.line_height),
3608            },
3609            CursorShape::Underscore => Bounds {
3610                origin: self.origin
3611                    + origin
3612                    + gpui::Point::new(Pixels::ZERO, self.line_height - px(2.0)),
3613                size: size(self.block_width, px(2.0)),
3614            },
3615        };
3616
3617        //Draw background or border quad
3618        if matches!(self.shape, CursorShape::Hollow) {
3619            cx.paint_quad(
3620                bounds,
3621                Corners::default(),
3622                transparent_black(),
3623                Edges::all(px(1.)),
3624                self.color,
3625            );
3626        } else {
3627            cx.paint_quad(
3628                bounds,
3629                Corners::default(),
3630                self.color,
3631                Edges::default(),
3632                transparent_black(),
3633            );
3634        }
3635
3636        if let Some(block_text) = &self.block_text {
3637            block_text.paint(self.origin + origin, self.line_height, cx);
3638        }
3639    }
3640
3641    pub fn shape(&self) -> CursorShape {
3642        self.shape
3643    }
3644}
3645
3646#[derive(Debug)]
3647pub struct HighlightedRange {
3648    pub start_y: Pixels,
3649    pub line_height: Pixels,
3650    pub lines: Vec<HighlightedRangeLine>,
3651    pub color: Hsla,
3652    pub corner_radius: Pixels,
3653}
3654
3655#[derive(Debug)]
3656pub struct HighlightedRangeLine {
3657    pub start_x: Pixels,
3658    pub end_x: Pixels,
3659}
3660
3661impl HighlightedRange {
3662    pub fn paint(&self, bounds: Bounds<Pixels>, cx: &mut WindowContext) {
3663        if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
3664            self.paint_lines(self.start_y, &self.lines[0..1], bounds, cx);
3665            self.paint_lines(
3666                self.start_y + self.line_height,
3667                &self.lines[1..],
3668                bounds,
3669                cx,
3670            );
3671        } else {
3672            self.paint_lines(self.start_y, &self.lines, bounds, cx);
3673        }
3674    }
3675
3676    fn paint_lines(
3677        &self,
3678        start_y: Pixels,
3679        lines: &[HighlightedRangeLine],
3680        bounds: Bounds<Pixels>,
3681        cx: &mut WindowContext,
3682    ) {
3683        if lines.is_empty() {
3684            return;
3685        }
3686
3687        let first_line = lines.first().unwrap();
3688        let last_line = lines.last().unwrap();
3689
3690        let first_top_left = point(first_line.start_x, start_y);
3691        let first_top_right = point(first_line.end_x, start_y);
3692
3693        let curve_height = point(Pixels::ZERO, self.corner_radius);
3694        let curve_width = |start_x: Pixels, end_x: Pixels| {
3695            let max = (end_x - start_x) / 2.;
3696            let width = if max < self.corner_radius {
3697                max
3698            } else {
3699                self.corner_radius
3700            };
3701
3702            point(width, Pixels::ZERO)
3703        };
3704
3705        let top_curve_width = curve_width(first_line.start_x, first_line.end_x);
3706        let mut path = gpui::Path::new(first_top_right - top_curve_width);
3707        path.curve_to(first_top_right + curve_height, first_top_right);
3708
3709        let mut iter = lines.iter().enumerate().peekable();
3710        while let Some((ix, line)) = iter.next() {
3711            let bottom_right = point(line.end_x, start_y + (ix + 1) as f32 * self.line_height);
3712
3713            if let Some((_, next_line)) = iter.peek() {
3714                let next_top_right = point(next_line.end_x, bottom_right.y);
3715
3716                match next_top_right.x.partial_cmp(&bottom_right.x).unwrap() {
3717                    Ordering::Equal => {
3718                        path.line_to(bottom_right);
3719                    }
3720                    Ordering::Less => {
3721                        let curve_width = curve_width(next_top_right.x, bottom_right.x);
3722                        path.line_to(bottom_right - curve_height);
3723                        if self.corner_radius > Pixels::ZERO {
3724                            path.curve_to(bottom_right - curve_width, bottom_right);
3725                        }
3726                        path.line_to(next_top_right + curve_width);
3727                        if self.corner_radius > Pixels::ZERO {
3728                            path.curve_to(next_top_right + curve_height, next_top_right);
3729                        }
3730                    }
3731                    Ordering::Greater => {
3732                        let curve_width = curve_width(bottom_right.x, next_top_right.x);
3733                        path.line_to(bottom_right - curve_height);
3734                        if self.corner_radius > Pixels::ZERO {
3735                            path.curve_to(bottom_right + curve_width, bottom_right);
3736                        }
3737                        path.line_to(next_top_right - curve_width);
3738                        if self.corner_radius > Pixels::ZERO {
3739                            path.curve_to(next_top_right + curve_height, next_top_right);
3740                        }
3741                    }
3742                }
3743            } else {
3744                let curve_width = curve_width(line.start_x, line.end_x);
3745                path.line_to(bottom_right - curve_height);
3746                if self.corner_radius > Pixels::ZERO {
3747                    path.curve_to(bottom_right - curve_width, bottom_right);
3748                }
3749
3750                let bottom_left = point(line.start_x, bottom_right.y);
3751                path.line_to(bottom_left + curve_width);
3752                if self.corner_radius > Pixels::ZERO {
3753                    path.curve_to(bottom_left - curve_height, bottom_left);
3754                }
3755            }
3756        }
3757
3758        if first_line.start_x > last_line.start_x {
3759            let curve_width = curve_width(last_line.start_x, first_line.start_x);
3760            let second_top_left = point(last_line.start_x, start_y + self.line_height);
3761            path.line_to(second_top_left + curve_height);
3762            if self.corner_radius > Pixels::ZERO {
3763                path.curve_to(second_top_left + curve_width, second_top_left);
3764            }
3765            let first_bottom_left = point(first_line.start_x, second_top_left.y);
3766            path.line_to(first_bottom_left - curve_width);
3767            if self.corner_radius > Pixels::ZERO {
3768                path.curve_to(first_bottom_left - curve_height, first_bottom_left);
3769            }
3770        }
3771
3772        path.line_to(first_top_left + curve_height);
3773        if self.corner_radius > Pixels::ZERO {
3774            path.curve_to(first_top_left + top_curve_width, first_top_left);
3775        }
3776        path.line_to(first_top_right - top_curve_width);
3777
3778        cx.paint_path(path, self.color);
3779    }
3780}
3781
3782// fn range_to_bounds(
3783//     range: &Range<DisplayPoint>,
3784//     content_origin: gpui::Point<Pixels>,
3785//     scroll_left: f32,
3786//     scroll_top: f32,
3787//     visible_row_range: &Range<u32>,
3788//     line_end_overshoot: f32,
3789//     position_map: &PositionMap,
3790// ) -> impl Iterator<Item = Bounds<Pixels>> {
3791//     let mut bounds: SmallVec<[Bounds<Pixels>; 1]> = SmallVec::new();
3792
3793//     if range.start == range.end {
3794//         return bounds.into_iter();
3795//     }
3796
3797//     let start_row = visible_row_range.start;
3798//     let end_row = visible_row_range.end;
3799
3800//     let row_range = if range.end.column() == 0 {
3801//         cmp::max(range.start.row(), start_row)..cmp::min(range.end.row(), end_row)
3802//     } else {
3803//         cmp::max(range.start.row(), start_row)..cmp::min(range.end.row() + 1, end_row)
3804//     };
3805
3806//     let first_y =
3807//         content_origin.y + row_range.start as f32 * position_map.line_height - scroll_top;
3808
3809//     for (idx, row) in row_range.enumerate() {
3810//         let line_layout = &position_map.line_layouts[(row - start_row) as usize].line;
3811
3812//         let start_x = if row == range.start.row() {
3813//             content_origin.x + line_layout.x_for_index(range.start.column() as usize)
3814//                 - scroll_left
3815//         } else {
3816//             content_origin.x - scroll_left
3817//         };
3818
3819//         let end_x = if row == range.end.row() {
3820//             content_origin.x + line_layout.x_for_index(range.end.column() as usize) - scroll_left
3821//         } else {
3822//             content_origin.x + line_layout.width() + line_end_overshoot - scroll_left
3823//         };
3824
3825//         bounds.push(Bounds::<Pixels>::from_points(
3826//             point(start_x, first_y + position_map.line_height * idx as f32),
3827//             point(end_x, first_y + position_map.line_height * (idx + 1) as f32),
3828//         ))
3829//     }
3830
3831//     bounds.into_iter()
3832// }
3833
3834pub fn scale_vertical_mouse_autoscroll_delta(delta: f32) -> f32 {
3835    delta.powf(1.5) / 100.0
3836}
3837
3838fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
3839    delta.powf(1.2) / 300.0
3840}
3841
3842// #[cfg(test)]
3843// mod tests {
3844//     use super::*;
3845//     use crate::{
3846//         display_map::{BlockDisposition, BlockProperties},
3847//         editor_tests::{init_test, update_test_language_settings},
3848//         Editor, MultiBuffer,
3849//     };
3850//     use gpui::TestAppContext;
3851//     use language::language_settings;
3852//     use log::info;
3853//     use std::{num::NonZeroU32, sync::Arc};
3854//     use util::test::sample_text;
3855
3856//     #[gpui::test]
3857//     fn test_layout_line_numbers(cx: &mut TestAppContext) {
3858//         init_test(cx, |_| {});
3859//         let editor = cx
3860//             .add_window(|cx| {
3861//                 let buffer = MultiBuffer::build_simple(&sample_text(6, 6, 'a'), cx);
3862//                 Editor::new(EditorMode::Full, buffer, None, None, cx)
3863//             })
3864//             .root(cx);
3865//         let element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3866
3867//         let layouts = editor.update(cx, |editor, cx| {
3868//             let snapshot = editor.snapshot(cx);
3869//             element
3870//                 .layout_line_numbers(
3871//                     0..6,
3872//                     &Default::default(),
3873//                     DisplayPoint::new(0, 0),
3874//                     false,
3875//                     &snapshot,
3876//                     cx,
3877//                 )
3878//                 .0
3879//         });
3880//         assert_eq!(layouts.len(), 6);
3881
3882//         let relative_rows = editor.update(cx, |editor, cx| {
3883//             let snapshot = editor.snapshot(cx);
3884//             element.calculate_relative_line_numbers(&snapshot, &(0..6), Some(3))
3885//         });
3886//         assert_eq!(relative_rows[&0], 3);
3887//         assert_eq!(relative_rows[&1], 2);
3888//         assert_eq!(relative_rows[&2], 1);
3889//         // current line has no relative number
3890//         assert_eq!(relative_rows[&4], 1);
3891//         assert_eq!(relative_rows[&5], 2);
3892
3893//         // works if cursor is before screen
3894//         let relative_rows = editor.update(cx, |editor, cx| {
3895//             let snapshot = editor.snapshot(cx);
3896
3897//             element.calculate_relative_line_numbers(&snapshot, &(3..6), Some(1))
3898//         });
3899//         assert_eq!(relative_rows.len(), 3);
3900//         assert_eq!(relative_rows[&3], 2);
3901//         assert_eq!(relative_rows[&4], 3);
3902//         assert_eq!(relative_rows[&5], 4);
3903
3904//         // works if cursor is after screen
3905//         let relative_rows = editor.update(cx, |editor, cx| {
3906//             let snapshot = editor.snapshot(cx);
3907
3908//             element.calculate_relative_line_numbers(&snapshot, &(0..3), Some(6))
3909//         });
3910//         assert_eq!(relative_rows.len(), 3);
3911//         assert_eq!(relative_rows[&0], 5);
3912//         assert_eq!(relative_rows[&1], 4);
3913//         assert_eq!(relative_rows[&2], 3);
3914//     }
3915
3916//     #[gpui::test]
3917//     async fn test_vim_visual_selections(cx: &mut TestAppContext) {
3918//         init_test(cx, |_| {});
3919
3920//         let editor = cx
3921//             .add_window(|cx| {
3922//                 let buffer = MultiBuffer::build_simple(&(sample_text(6, 6, 'a') + "\n"), cx);
3923//                 Editor::new(EditorMode::Full, buffer, None, None, cx)
3924//             })
3925//             .root(cx);
3926//         let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
3927//         let (_, state) = editor.update(cx, |editor, cx| {
3928//             editor.cursor_shape = CursorShape::Block;
3929//             editor.change_selections(None, cx, |s| {
3930//                 s.select_ranges([
3931//                     Point::new(0, 0)..Point::new(1, 0),
3932//                     Point::new(3, 2)..Point::new(3, 3),
3933//                     Point::new(5, 6)..Point::new(6, 0),
3934//                 ]);
3935//             });
3936//             element.layout(
3937//                 SizeConstraint::new(point(500., 500.), point(500., 500.)),
3938//                 editor,
3939//                 cx,
3940//             )
3941//         });
3942//         assert_eq!(state.selections.len(), 1);
3943//         let local_selections = &state.selections[0].1;
3944//         assert_eq!(local_selections.len(), 3);
3945//         // moves cursor back one line
3946//         assert_eq!(local_selections[0].head, DisplayPoint::new(0, 6));
3947//         assert_eq!(
3948//             local_selections[0].range,
3949//             DisplayPoint::new(0, 0)..DisplayPoint::new(1, 0)
3950//         );
3951
3952//         // moves cursor back one column
3953//         assert_eq!(
3954//             local_selections[1].range,
3955//             DisplayPoint::new(3, 2)..DisplayPoint::new(3, 3)
3956//         );
3957//         assert_eq!(local_selections[1].head, DisplayPoint::new(3, 2));
3958
3959//         // leaves cursor on the max point
3960//         assert_eq!(
3961//             local_selections[2].range,
3962//             DisplayPoint::new(5, 6)..DisplayPoint::new(6, 0)
3963//         );
3964//         assert_eq!(local_selections[2].head, DisplayPoint::new(6, 0));
3965
3966//         // active lines does not include 1 (even though the range of the selection does)
3967//         assert_eq!(
3968//             state.active_rows.keys().cloned().collect::<Vec<u32>>(),
3969//             vec![0, 3, 5, 6]
3970//         );
3971
3972//         // multi-buffer support
3973//         // in DisplayPoint co-ordinates, this is what we're dealing with:
3974//         //  0: [[file
3975//         //  1:   header]]
3976//         //  2: aaaaaa
3977//         //  3: bbbbbb
3978//         //  4: cccccc
3979//         //  5:
3980//         //  6: ...
3981//         //  7: ffffff
3982//         //  8: gggggg
3983//         //  9: hhhhhh
3984//         // 10:
3985//         // 11: [[file
3986//         // 12:   header]]
3987//         // 13: bbbbbb
3988//         // 14: cccccc
3989//         // 15: dddddd
3990//         let editor = cx
3991//             .add_window(|cx| {
3992//                 let buffer = MultiBuffer::build_multi(
3993//                     [
3994//                         (
3995//                             &(sample_text(8, 6, 'a') + "\n"),
3996//                             vec![
3997//                                 Point::new(0, 0)..Point::new(3, 0),
3998//                                 Point::new(4, 0)..Point::new(7, 0),
3999//                             ],
4000//                         ),
4001//                         (
4002//                             &(sample_text(8, 6, 'a') + "\n"),
4003//                             vec![Point::new(1, 0)..Point::new(3, 0)],
4004//                         ),
4005//                     ],
4006//                     cx,
4007//                 );
4008//                 Editor::new(EditorMode::Full, buffer, None, None, cx)
4009//             })
4010//             .root(cx);
4011//         let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
4012//         let (_, state) = editor.update(cx, |editor, cx| {
4013//             editor.cursor_shape = CursorShape::Block;
4014//             editor.change_selections(None, cx, |s| {
4015//                 s.select_display_ranges([
4016//                     DisplayPoint::new(4, 0)..DisplayPoint::new(7, 0),
4017//                     DisplayPoint::new(10, 0)..DisplayPoint::new(13, 0),
4018//                 ]);
4019//             });
4020//             element.layout(
4021//                 SizeConstraint::new(point(500., 500.), point(500., 500.)),
4022//                 editor,
4023//                 cx,
4024//             )
4025//         });
4026
4027//         assert_eq!(state.selections.len(), 1);
4028//         let local_selections = &state.selections[0].1;
4029//         assert_eq!(local_selections.len(), 2);
4030
4031//         // moves cursor on excerpt boundary back a line
4032//         // and doesn't allow selection to bleed through
4033//         assert_eq!(
4034//             local_selections[0].range,
4035//             DisplayPoint::new(4, 0)..DisplayPoint::new(6, 0)
4036//         );
4037//         assert_eq!(local_selections[0].head, DisplayPoint::new(5, 0));
4038
4039//         // moves cursor on buffer boundary back two lines
4040//         // and doesn't allow selection to bleed through
4041//         assert_eq!(
4042//             local_selections[1].range,
4043//             DisplayPoint::new(10, 0)..DisplayPoint::new(11, 0)
4044//         );
4045//         assert_eq!(local_selections[1].head, DisplayPoint::new(10, 0));
4046//     }
4047
4048//     #[gpui::test]
4049//     fn test_layout_with_placeholder_text_and_blocks(cx: &mut TestAppContext) {
4050//         init_test(cx, |_| {});
4051
4052//         let editor = cx
4053//             .add_window(|cx| {
4054//                 let buffer = MultiBuffer::build_simple("", cx);
4055//                 Editor::new(EditorMode::Full, buffer, None, None, cx)
4056//             })
4057//             .root(cx);
4058
4059//         editor.update(cx, |editor, cx| {
4060//             editor.set_placeholder_text("hello", cx);
4061//             editor.insert_blocks(
4062//                 [BlockProperties {
4063//                     style: BlockStyle::Fixed,
4064//                     disposition: BlockDisposition::Above,
4065//                     height: 3,
4066//                     position: Anchor::min(),
4067//                     render: Arc::new(|_| Empty::new().into_any),
4068//                 }],
4069//                 None,
4070//                 cx,
4071//             );
4072
4073//             // Blur the editor so that it displays placeholder text.
4074//             cx.blur();
4075//         });
4076
4077//         let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
4078//         let (size, mut state) = editor.update(cx, |editor, cx| {
4079//             element.layout(
4080//                 SizeConstraint::new(point(500., 500.), point(500., 500.)),
4081//                 editor,
4082//                 cx,
4083//             )
4084//         });
4085
4086//         assert_eq!(state.position_map.line_layouts.len(), 4);
4087//         assert_eq!(
4088//             state
4089//                 .line_number_layouts
4090//                 .iter()
4091//                 .map(Option::is_some)
4092//                 .collect::<Vec<_>>(),
4093//             &[false, false, false, true]
4094//         );
4095
4096//         // Don't panic.
4097//         let bounds = Bounds::<Pixels>::new(Default::default(), size);
4098//         editor.update(cx, |editor, cx| {
4099//             element.paint(bounds, bounds, &mut state, editor, cx);
4100//         });
4101//     }
4102
4103//     #[gpui::test]
4104//     fn test_all_invisibles_drawing(cx: &mut TestAppContext) {
4105//         const TAB_SIZE: u32 = 4;
4106
4107//         let input_text = "\t \t|\t| a b";
4108//         let expected_invisibles = vec![
4109//             Invisible::Tab {
4110//                 line_start_offset: 0,
4111//             },
4112//             Invisible::Whitespace {
4113//                 line_offset: TAB_SIZE as usize,
4114//             },
4115//             Invisible::Tab {
4116//                 line_start_offset: TAB_SIZE as usize + 1,
4117//             },
4118//             Invisible::Tab {
4119//                 line_start_offset: TAB_SIZE as usize * 2 + 1,
4120//             },
4121//             Invisible::Whitespace {
4122//                 line_offset: TAB_SIZE as usize * 3 + 1,
4123//             },
4124//             Invisible::Whitespace {
4125//                 line_offset: TAB_SIZE as usize * 3 + 3,
4126//             },
4127//         ];
4128//         assert_eq!(
4129//             expected_invisibles.len(),
4130//             input_text
4131//                 .chars()
4132//                 .filter(|initial_char| initial_char.is_whitespace())
4133//                 .count(),
4134//             "Hardcoded expected invisibles differ from the actual ones in '{input_text}'"
4135//         );
4136
4137//         init_test(cx, |s| {
4138//             s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
4139//             s.defaults.tab_size = NonZeroU32::new(TAB_SIZE);
4140//         });
4141
4142//         let actual_invisibles =
4143//             collect_invisibles_from_new_editor(cx, EditorMode::Full, &input_text, 500.0);
4144
4145//         assert_eq!(expected_invisibles, actual_invisibles);
4146//     }
4147
4148//     #[gpui::test]
4149//     fn test_invisibles_dont_appear_in_certain_editors(cx: &mut TestAppContext) {
4150//         init_test(cx, |s| {
4151//             s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
4152//             s.defaults.tab_size = NonZeroU32::new(4);
4153//         });
4154
4155//         for editor_mode_without_invisibles in [
4156//             EditorMode::SingleLine,
4157//             EditorMode::AutoHeight { max_lines: 100 },
4158//         ] {
4159//             let invisibles = collect_invisibles_from_new_editor(
4160//                 cx,
4161//                 editor_mode_without_invisibles,
4162//                 "\t\t\t| | a b",
4163//                 500.0,
4164//             );
4165//             assert!(invisibles.is_empty,
4166//                 "For editor mode {editor_mode_without_invisibles:?} no invisibles was expected but got {invisibles:?}");
4167//         }
4168//     }
4169
4170//     #[gpui::test]
4171//     fn test_wrapped_invisibles_drawing(cx: &mut TestAppContext) {
4172//         let tab_size = 4;
4173//         let input_text = "a\tbcd   ".repeat(9);
4174//         let repeated_invisibles = [
4175//             Invisible::Tab {
4176//                 line_start_offset: 1,
4177//             },
4178//             Invisible::Whitespace {
4179//                 line_offset: tab_size as usize + 3,
4180//             },
4181//             Invisible::Whitespace {
4182//                 line_offset: tab_size as usize + 4,
4183//             },
4184//             Invisible::Whitespace {
4185//                 line_offset: tab_size as usize + 5,
4186//             },
4187//         ];
4188//         let expected_invisibles = std::iter::once(repeated_invisibles)
4189//             .cycle()
4190//             .take(9)
4191//             .flatten()
4192//             .collect::<Vec<_>>();
4193//         assert_eq!(
4194//             expected_invisibles.len(),
4195//             input_text
4196//                 .chars()
4197//                 .filter(|initial_char| initial_char.is_whitespace())
4198//                 .count(),
4199//             "Hardcoded expected invisibles differ from the actual ones in '{input_text}'"
4200//         );
4201//         info!("Expected invisibles: {expected_invisibles:?}");
4202
4203//         init_test(cx, |_| {});
4204
4205//         // Put the same string with repeating whitespace pattern into editors of various size,
4206//         // take deliberately small steps during resizing, to put all whitespace kinds near the wrap point.
4207//         let resize_step = 10.0;
4208//         let mut editor_width = 200.0;
4209//         while editor_width <= 1000.0 {
4210//             update_test_language_settings(cx, |s| {
4211//                 s.defaults.tab_size = NonZeroU32::new(tab_size);
4212//                 s.defaults.show_whitespaces = Some(ShowWhitespaceSetting::All);
4213//                 s.defaults.preferred_line_length = Some(editor_width as u32);
4214//                 s.defaults.soft_wrap = Some(language_settings::SoftWrap::PreferredLineLength);
4215//             });
4216
4217//             let actual_invisibles =
4218//                 collect_invisibles_from_new_editor(cx, EditorMode::Full, &input_text, editor_width);
4219
4220//             // Whatever the editor size is, ensure it has the same invisible kinds in the same order
4221//             // (no good guarantees about the offsets: wrapping could trigger padding and its tests should check the offsets).
4222//             let mut i = 0;
4223//             for (actual_index, actual_invisible) in actual_invisibles.iter().enumerate() {
4224//                 i = actual_index;
4225//                 match expected_invisibles.get(i) {
4226//                     Some(expected_invisible) => match (expected_invisible, actual_invisible) {
4227//                         (Invisible::Whitespace { .. }, Invisible::Whitespace { .. })
4228//                         | (Invisible::Tab { .. }, Invisible::Tab { .. }) => {}
4229//                         _ => {
4230//                             panic!("At index {i}, expected invisible {expected_invisible:?} does not match actual {actual_invisible:?} by kind. Actual invisibles: {actual_invisibles:?}")
4231//                         }
4232//                     },
4233//                     None => panic!("Unexpected extra invisible {actual_invisible:?} at index {i}"),
4234//                 }
4235//             }
4236//             let missing_expected_invisibles = &expected_invisibles[i + 1..];
4237//             assert!(
4238//                 missing_expected_invisibles.is_empty,
4239//                 "Missing expected invisibles after index {i}: {missing_expected_invisibles:?}"
4240//             );
4241
4242//             editor_width += resize_step;
4243//         }
4244//     }
4245
4246//     fn collect_invisibles_from_new_editor(
4247//         cx: &mut TestAppContext,
4248//         editor_mode: EditorMode,
4249//         input_text: &str,
4250//         editor_width: f32,
4251//     ) -> Vec<Invisible> {
4252//         info!(
4253//             "Creating editor with mode {editor_mode:?}, width {editor_width} and text '{input_text}'"
4254//         );
4255//         let editor = cx
4256//             .add_window(|cx| {
4257//                 let buffer = MultiBuffer::build_simple(&input_text, cx);
4258//                 Editor::new(editor_mode, buffer, None, None, cx)
4259//             })
4260//             .root(cx);
4261
4262//         let mut element = EditorElement::new(editor.read_with(cx, |editor, cx| editor.style(cx)));
4263//         let (_, layout_state) = editor.update(cx, |editor, cx| {
4264//             editor.set_soft_wrap_mode(language_settings::SoftWrap::EditorWidth, cx);
4265//             editor.set_wrap_width(Some(editor_width), cx);
4266
4267//             element.layout(
4268//                 SizeConstraint::new(point(editor_width, 500.), point(editor_width, 500.)),
4269//                 editor,
4270//                 cx,
4271//             )
4272//         });
4273
4274//         layout_state
4275//             .position_map
4276//             .line_layouts
4277//             .iter()
4278//             .map(|line_with_invisibles| &line_with_invisibles.invisibles)
4279//             .flatten()
4280//             .cloned()
4281//             .collect()
4282//     }
4283// }
4284
4285fn build_key_listener<T: 'static>(
4286    listener: impl Fn(
4287            &mut Editor,
4288            &T,
4289            &[&DispatchContext],
4290            DispatchPhase,
4291            &mut ViewContext<Editor>,
4292        ) -> Option<Box<dyn Action>>
4293        + 'static,
4294) -> (TypeId, KeyListener<Editor>) {
4295    (
4296        TypeId::of::<T>(),
4297        Box::new(move |editor, event, dispatch_context, phase, cx| {
4298            let key_event = event.downcast_ref::<T>()?;
4299            listener(editor, key_event, dispatch_context, phase, cx)
4300        }),
4301    )
4302}
4303
4304fn build_action_listener<T: Action>(
4305    listener: impl Fn(&mut Editor, &T, &mut ViewContext<Editor>) + 'static,
4306) -> (TypeId, KeyListener<Editor>) {
4307    build_key_listener(move |editor, action: &T, dispatch_context, phase, cx| {
4308        if phase == DispatchPhase::Bubble {
4309            listener(editor, action, cx);
4310        }
4311        None
4312    })
4313}