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