element.rs

   1use super::{
   2    DisplayPoint, DisplayRow, Editor, EditorMode, EditorSettings, EditorStyle, Input, Scroll,
   3    Select, SelectPhase, Snapshot, MAX_LINE_LEN,
   4};
   5use clock::ReplicaId;
   6use gpui::{
   7    color::Color,
   8    geometry::{
   9        rect::RectF,
  10        vector::{vec2f, Vector2F},
  11        PathBuilder,
  12    },
  13    json::{self, ToJson},
  14    keymap::Keystroke,
  15    text_layout::{self, RunStyle, TextLayoutCache},
  16    AppContext, Axis, Border, Element, Event, EventContext, FontCache, LayoutContext,
  17    MutableAppContext, PaintContext, Quad, Scene, SizeConstraint, ViewContext, WeakViewHandle,
  18};
  19use json::json;
  20use language::Chunk;
  21use smallvec::SmallVec;
  22use std::{
  23    cmp::{self, Ordering},
  24    collections::{BTreeMap, HashMap},
  25    fmt::Write,
  26    ops::Range,
  27};
  28use theme::BlockStyle;
  29
  30pub struct EditorElement {
  31    view: WeakViewHandle<Editor>,
  32    settings: EditorSettings,
  33}
  34
  35impl EditorElement {
  36    pub fn new(view: WeakViewHandle<Editor>, settings: EditorSettings) -> Self {
  37        Self { view, settings }
  38    }
  39
  40    fn view<'a>(&self, cx: &'a AppContext) -> &'a Editor {
  41        self.view.upgrade(cx).unwrap().read(cx)
  42    }
  43
  44    fn update_view<F, T>(&self, cx: &mut MutableAppContext, f: F) -> T
  45    where
  46        F: FnOnce(&mut Editor, &mut ViewContext<Editor>) -> T,
  47    {
  48        self.view.upgrade(cx).unwrap().update(cx, f)
  49    }
  50
  51    fn snapshot(&self, cx: &mut MutableAppContext) -> Snapshot {
  52        self.update_view(cx, |view, cx| view.snapshot(cx))
  53    }
  54
  55    fn mouse_down(
  56        &self,
  57        position: Vector2F,
  58        cmd: bool,
  59        layout: &mut LayoutState,
  60        paint: &mut PaintState,
  61        cx: &mut EventContext,
  62    ) -> bool {
  63        if paint.text_bounds.contains_point(position) {
  64            let snapshot = self.snapshot(cx.app);
  65            let position = paint.point_for_position(&snapshot, layout, position);
  66            cx.dispatch_action(Select(SelectPhase::Begin { position, add: cmd }));
  67            true
  68        } else {
  69            false
  70        }
  71    }
  72
  73    fn mouse_up(&self, _position: Vector2F, cx: &mut EventContext) -> bool {
  74        if self.view(cx.app.as_ref()).is_selecting() {
  75            cx.dispatch_action(Select(SelectPhase::End));
  76            true
  77        } else {
  78            false
  79        }
  80    }
  81
  82    fn mouse_dragged(
  83        &self,
  84        position: Vector2F,
  85        layout: &mut LayoutState,
  86        paint: &mut PaintState,
  87        cx: &mut EventContext,
  88    ) -> bool {
  89        let view = self.view(cx.app.as_ref());
  90
  91        if view.is_selecting() {
  92            let rect = paint.text_bounds;
  93            let mut scroll_delta = Vector2F::zero();
  94
  95            let vertical_margin = layout.line_height.min(rect.height() / 3.0);
  96            let top = rect.origin_y() + vertical_margin;
  97            let bottom = rect.lower_left().y() - vertical_margin;
  98            if position.y() < top {
  99                scroll_delta.set_y(-scale_vertical_mouse_autoscroll_delta(top - position.y()))
 100            }
 101            if position.y() > bottom {
 102                scroll_delta.set_y(scale_vertical_mouse_autoscroll_delta(position.y() - bottom))
 103            }
 104
 105            let horizontal_margin = layout.line_height.min(rect.width() / 3.0);
 106            let left = rect.origin_x() + horizontal_margin;
 107            let right = rect.upper_right().x() - horizontal_margin;
 108            if position.x() < left {
 109                scroll_delta.set_x(-scale_horizontal_mouse_autoscroll_delta(
 110                    left - position.x(),
 111                ))
 112            }
 113            if position.x() > right {
 114                scroll_delta.set_x(scale_horizontal_mouse_autoscroll_delta(
 115                    position.x() - right,
 116                ))
 117            }
 118
 119            let font_cache = cx.font_cache.clone();
 120            let text_layout_cache = cx.text_layout_cache.clone();
 121            let snapshot = self.snapshot(cx.app);
 122            let position = paint.point_for_position(&snapshot, layout, position);
 123
 124            cx.dispatch_action(Select(SelectPhase::Update {
 125                position,
 126                scroll_position: (snapshot.scroll_position() + scroll_delta).clamp(
 127                    Vector2F::zero(),
 128                    layout.scroll_max(&font_cache, &text_layout_cache),
 129                ),
 130            }));
 131            true
 132        } else {
 133            false
 134        }
 135    }
 136
 137    fn key_down(&self, chars: &str, keystroke: &Keystroke, cx: &mut EventContext) -> bool {
 138        let view = self.view.upgrade(cx.app).unwrap();
 139
 140        if view.is_focused(cx.app) {
 141            if chars.is_empty() {
 142                false
 143            } else {
 144                if chars.chars().any(|c| c.is_control()) || keystroke.cmd || keystroke.ctrl {
 145                    false
 146                } else {
 147                    cx.dispatch_action(Input(chars.to_string()));
 148                    true
 149                }
 150            }
 151        } else {
 152            false
 153        }
 154    }
 155
 156    fn scroll(
 157        &self,
 158        position: Vector2F,
 159        mut delta: Vector2F,
 160        precise: bool,
 161        layout: &mut LayoutState,
 162        paint: &mut PaintState,
 163        cx: &mut EventContext,
 164    ) -> bool {
 165        if !paint.bounds.contains_point(position) {
 166            return false;
 167        }
 168
 169        let snapshot = self.snapshot(cx.app);
 170        let font_cache = &cx.font_cache;
 171        let layout_cache = &cx.text_layout_cache;
 172        let max_glyph_width = layout.em_width;
 173        if !precise {
 174            delta *= vec2f(max_glyph_width, layout.line_height);
 175        }
 176
 177        let scroll_position = snapshot.scroll_position();
 178        let x = (scroll_position.x() * max_glyph_width - delta.x()) / max_glyph_width;
 179        let y = (scroll_position.y() * layout.line_height - delta.y()) / layout.line_height;
 180        let scroll_position = vec2f(x, y).clamp(
 181            Vector2F::zero(),
 182            layout.scroll_max(font_cache, layout_cache),
 183        );
 184
 185        cx.dispatch_action(Scroll(scroll_position));
 186
 187        true
 188    }
 189
 190    fn paint_background(
 191        &self,
 192        gutter_bounds: RectF,
 193        text_bounds: RectF,
 194        layout: &LayoutState,
 195        cx: &mut PaintContext,
 196    ) {
 197        let bounds = gutter_bounds.union_rect(text_bounds);
 198        let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
 199        let editor = self.view(cx.app);
 200        let style = &self.settings.style;
 201        cx.scene.push_quad(Quad {
 202            bounds: gutter_bounds,
 203            background: Some(style.gutter_background),
 204            border: Border::new(0., Color::transparent_black()),
 205            corner_radius: 0.,
 206        });
 207        cx.scene.push_quad(Quad {
 208            bounds: text_bounds,
 209            background: Some(style.background),
 210            border: Border::new(0., Color::transparent_black()),
 211            corner_radius: 0.,
 212        });
 213
 214        if let EditorMode::Full = editor.mode {
 215            let mut active_rows = layout.active_rows.iter().peekable();
 216            while let Some((start_row, contains_non_empty_selection)) = active_rows.next() {
 217                let mut end_row = *start_row;
 218                while active_rows.peek().map_or(false, |r| {
 219                    *r.0 == end_row + 1 && r.1 == contains_non_empty_selection
 220                }) {
 221                    active_rows.next().unwrap();
 222                    end_row += 1;
 223                }
 224
 225                if !contains_non_empty_selection {
 226                    let origin = vec2f(
 227                        bounds.origin_x(),
 228                        bounds.origin_y() + (layout.line_height * *start_row as f32) - scroll_top,
 229                    );
 230                    let size = vec2f(
 231                        bounds.width(),
 232                        layout.line_height * (end_row - start_row + 1) as f32,
 233                    );
 234                    cx.scene.push_quad(Quad {
 235                        bounds: RectF::new(origin, size),
 236                        background: Some(style.active_line_background),
 237                        border: Border::default(),
 238                        corner_radius: 0.,
 239                    });
 240                }
 241            }
 242        }
 243    }
 244
 245    fn paint_gutter(
 246        &mut self,
 247        bounds: RectF,
 248        visible_bounds: RectF,
 249        layout: &LayoutState,
 250        cx: &mut PaintContext,
 251    ) {
 252        let scroll_top = layout.snapshot.scroll_position().y() * layout.line_height;
 253        for (ix, line) in layout.line_number_layouts.iter().enumerate() {
 254            if let Some(line) = line {
 255                let line_origin = bounds.origin()
 256                    + vec2f(
 257                        bounds.width() - line.width() - layout.gutter_padding,
 258                        ix as f32 * layout.line_height - (scroll_top % layout.line_height),
 259                    );
 260                line.paint(line_origin, visible_bounds, layout.line_height, cx);
 261            }
 262        }
 263    }
 264
 265    fn paint_text(
 266        &mut self,
 267        bounds: RectF,
 268        visible_bounds: RectF,
 269        layout: &LayoutState,
 270        cx: &mut PaintContext,
 271    ) {
 272        let view = self.view(cx.app);
 273        let style = &self.settings.style;
 274        let local_replica_id = view.replica_id(cx);
 275        let scroll_position = layout.snapshot.scroll_position();
 276        let start_row = scroll_position.y() as u32;
 277        let scroll_top = scroll_position.y() * layout.line_height;
 278        let end_row = ((scroll_top + bounds.height()) / layout.line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
 279        let max_glyph_width = layout.em_width;
 280        let scroll_left = scroll_position.x() * max_glyph_width;
 281
 282        cx.scene.push_layer(Some(bounds));
 283
 284        // Draw selections
 285        let corner_radius = 2.5;
 286        let mut cursors = SmallVec::<[Cursor; 32]>::new();
 287
 288        let content_origin = bounds.origin() + layout.text_offset;
 289
 290        for (replica_id, selections) in &layout.selections {
 291            let style_ix = *replica_id as usize % (style.guest_selections.len() + 1);
 292            let style = if style_ix == 0 {
 293                &style.selection
 294            } else {
 295                &style.guest_selections[style_ix - 1]
 296            };
 297
 298            for selection in selections {
 299                if selection.start != selection.end {
 300                    let range_start = cmp::min(selection.start, selection.end);
 301                    let range_end = cmp::max(selection.start, selection.end);
 302                    let row_range = if range_end.column() == 0 {
 303                        cmp::max(range_start.row(), start_row)..cmp::min(range_end.row(), end_row)
 304                    } else {
 305                        cmp::max(range_start.row(), start_row)
 306                            ..cmp::min(range_end.row() + 1, end_row)
 307                    };
 308
 309                    let selection = Selection {
 310                        color: style.selection,
 311                        line_height: layout.line_height,
 312                        start_y: content_origin.y() + row_range.start as f32 * layout.line_height
 313                            - scroll_top,
 314                        lines: row_range
 315                            .into_iter()
 316                            .map(|row| {
 317                                let line_layout = &layout.line_layouts[(row - start_row) as usize];
 318                                SelectionLine {
 319                                    start_x: if row == range_start.row() {
 320                                        content_origin.x()
 321                                            + line_layout.x_for_index(range_start.column() as usize)
 322                                            - scroll_left
 323                                    } else {
 324                                        content_origin.x() - scroll_left
 325                                    },
 326                                    end_x: if row == range_end.row() {
 327                                        content_origin.x()
 328                                            + line_layout.x_for_index(range_end.column() as usize)
 329                                            - scroll_left
 330                                    } else {
 331                                        content_origin.x()
 332                                            + line_layout.width()
 333                                            + corner_radius * 2.0
 334                                            - scroll_left
 335                                    },
 336                                }
 337                            })
 338                            .collect(),
 339                    };
 340
 341                    selection.paint(bounds, cx.scene);
 342                }
 343
 344                if view.show_local_cursors() || *replica_id != local_replica_id {
 345                    let cursor_position = selection.end;
 346                    if (start_row..end_row).contains(&cursor_position.row()) {
 347                        let cursor_row_layout =
 348                            &layout.line_layouts[(selection.end.row() - start_row) as usize];
 349                        let x = cursor_row_layout.x_for_index(selection.end.column() as usize)
 350                            - scroll_left;
 351                        let y = selection.end.row() as f32 * layout.line_height - scroll_top;
 352                        cursors.push(Cursor {
 353                            color: style.cursor,
 354                            origin: content_origin + vec2f(x, y),
 355                            line_height: layout.line_height,
 356                        });
 357                    }
 358                }
 359            }
 360        }
 361
 362        if let Some(visible_text_bounds) = bounds.intersection(visible_bounds) {
 363            // Draw blocks
 364            for (ixs, block_style) in &layout.block_layouts {
 365                let row = start_row + ixs.start;
 366                let origin = content_origin
 367                    + vec2f(-scroll_left, row as f32 * layout.line_height - scroll_top);
 368                let height = ixs.len() as f32 * layout.line_height;
 369                cx.scene.push_quad(Quad {
 370                    bounds: RectF::new(origin, vec2f(visible_text_bounds.width(), height)),
 371                    background: block_style.background,
 372                    border: block_style
 373                        .border
 374                        .map_or(Default::default(), |color| Border {
 375                            width: 1.,
 376                            color,
 377                            overlay: true,
 378                            top: true,
 379                            right: false,
 380                            bottom: true,
 381                            left: false,
 382                        }),
 383                    corner_radius: 0.,
 384                });
 385            }
 386
 387            // Draw glyphs
 388            for (ix, line) in layout.line_layouts.iter().enumerate() {
 389                let row = start_row + ix as u32;
 390                line.paint(
 391                    content_origin
 392                        + vec2f(-scroll_left, row as f32 * layout.line_height - scroll_top),
 393                    visible_text_bounds,
 394                    layout.line_height,
 395                    cx,
 396                );
 397            }
 398        }
 399
 400        cx.scene.push_layer(Some(bounds));
 401        for cursor in cursors {
 402            cursor.paint(cx);
 403        }
 404        cx.scene.pop_layer();
 405
 406        cx.scene.pop_layer();
 407    }
 408
 409    fn max_line_number_width(&self, snapshot: &Snapshot, cx: &LayoutContext) -> f32 {
 410        let digit_count = (snapshot.buffer_row_count() as f32).log10().floor() as usize + 1;
 411        let style = &self.settings.style;
 412
 413        cx.text_layout_cache
 414            .layout_str(
 415                "1".repeat(digit_count).as_str(),
 416                style.text.font_size,
 417                &[(
 418                    digit_count,
 419                    RunStyle {
 420                        font_id: style.text.font_id,
 421                        color: Color::black(),
 422                        underline: None,
 423                    },
 424                )],
 425            )
 426            .width()
 427    }
 428
 429    fn layout_rows(
 430        &self,
 431        rows: Range<u32>,
 432        active_rows: &BTreeMap<u32, bool>,
 433        snapshot: &Snapshot,
 434        cx: &LayoutContext,
 435    ) -> (
 436        Vec<Option<text_layout::Line>>,
 437        Vec<(Range<u32>, BlockStyle)>,
 438    ) {
 439        let style = &self.settings.style;
 440        let include_line_numbers = snapshot.mode == EditorMode::Full;
 441        let mut last_block_id = None;
 442        let mut blocks = Vec::<(Range<u32>, BlockStyle)>::new();
 443        let mut line_number_layouts = Vec::with_capacity(rows.len());
 444        let mut line_number = String::new();
 445        for (ix, row) in snapshot
 446            .buffer_rows(rows.start, cx)
 447            .take((rows.end - rows.start) as usize)
 448            .enumerate()
 449        {
 450            let display_row = rows.start + ix as u32;
 451            let color = if active_rows.contains_key(&display_row) {
 452                style.line_number_active
 453            } else {
 454                style.line_number
 455            };
 456            match row {
 457                DisplayRow::Buffer(buffer_row) => {
 458                    if include_line_numbers {
 459                        line_number.clear();
 460                        write!(&mut line_number, "{}", buffer_row + 1).unwrap();
 461                        line_number_layouts.push(Some(cx.text_layout_cache.layout_str(
 462                            &line_number,
 463                            style.text.font_size,
 464                            &[(
 465                                line_number.len(),
 466                                RunStyle {
 467                                    font_id: style.text.font_id,
 468                                    color,
 469                                    underline: None,
 470                                },
 471                            )],
 472                        )));
 473                    }
 474                    last_block_id = None;
 475                }
 476                DisplayRow::Block(block_id, style) => {
 477                    let ix = ix as u32;
 478                    if last_block_id == Some(block_id) {
 479                        if let Some((row_range, _)) = blocks.last_mut() {
 480                            row_range.end += 1;
 481                        }
 482                    } else if let Some(style) = style {
 483                        blocks.push((ix..ix + 1, style));
 484                    }
 485                    line_number_layouts.push(None);
 486                    last_block_id = Some(block_id);
 487                }
 488                DisplayRow::Wrap => {
 489                    line_number_layouts.push(None);
 490                    last_block_id = None;
 491                }
 492            }
 493        }
 494
 495        (line_number_layouts, blocks)
 496    }
 497
 498    fn layout_lines(
 499        &mut self,
 500        mut rows: Range<u32>,
 501        snapshot: &mut Snapshot,
 502        cx: &LayoutContext,
 503    ) -> Vec<text_layout::Line> {
 504        rows.end = cmp::min(rows.end, snapshot.max_point().row() + 1);
 505        if rows.start >= rows.end {
 506            return Vec::new();
 507        }
 508
 509        // When the editor is empty and unfocused, then show the placeholder.
 510        if snapshot.is_empty() && !snapshot.is_focused() {
 511            let placeholder_style = self.settings.style.placeholder_text();
 512            let placeholder_text = snapshot.placeholder_text();
 513            let placeholder_lines = placeholder_text
 514                .as_ref()
 515                .map_or("", AsRef::as_ref)
 516                .split('\n')
 517                .skip(rows.start as usize)
 518                .take(rows.len());
 519            return placeholder_lines
 520                .map(|line| {
 521                    cx.text_layout_cache.layout_str(
 522                        line,
 523                        placeholder_style.font_size,
 524                        &[(
 525                            line.len(),
 526                            RunStyle {
 527                                font_id: placeholder_style.font_id,
 528                                color: placeholder_style.color,
 529                                underline: None,
 530                            },
 531                        )],
 532                    )
 533                })
 534                .collect();
 535        }
 536
 537        let style = &self.settings.style;
 538        let mut prev_font_properties = style.text.font_properties.clone();
 539        let mut prev_font_id = style.text.font_id;
 540
 541        let mut layouts = Vec::with_capacity(rows.len());
 542        let mut line = String::new();
 543        let mut styles = Vec::new();
 544        let mut row = rows.start;
 545        let mut line_exceeded_max_len = false;
 546        let chunks = snapshot.chunks(rows.clone(), Some(&style.syntax), cx);
 547
 548        let newline_chunk = Chunk {
 549            text: "\n",
 550            ..Default::default()
 551        };
 552        'outer: for chunk in chunks.chain([newline_chunk]) {
 553            for (ix, mut line_chunk) in chunk.text.split('\n').enumerate() {
 554                if ix > 0 {
 555                    layouts.push(cx.text_layout_cache.layout_str(
 556                        &line,
 557                        style.text.font_size,
 558                        &styles,
 559                    ));
 560                    line.clear();
 561                    styles.clear();
 562                    row += 1;
 563                    line_exceeded_max_len = false;
 564                    if row == rows.end {
 565                        break 'outer;
 566                    }
 567                }
 568
 569                if !line_chunk.is_empty() && !line_exceeded_max_len {
 570                    let highlight_style =
 571                        chunk.highlight_style.unwrap_or(style.text.clone().into());
 572                    // Avoid a lookup if the font properties match the previous ones.
 573                    let font_id = if highlight_style.font_properties == prev_font_properties {
 574                        prev_font_id
 575                    } else {
 576                        cx.font_cache
 577                            .select_font(
 578                                style.text.font_family_id,
 579                                &highlight_style.font_properties,
 580                            )
 581                            .unwrap_or(style.text.font_id)
 582                    };
 583
 584                    if line.len() + line_chunk.len() > MAX_LINE_LEN {
 585                        let mut chunk_len = MAX_LINE_LEN - line.len();
 586                        while !line_chunk.is_char_boundary(chunk_len) {
 587                            chunk_len -= 1;
 588                        }
 589                        line_chunk = &line_chunk[..chunk_len];
 590                        line_exceeded_max_len = true;
 591                    }
 592
 593                    let underline = if let Some(severity) = chunk.diagnostic {
 594                        Some(super::diagnostic_style(severity, style).text)
 595                    } else {
 596                        highlight_style.underline
 597                    };
 598
 599                    line.push_str(line_chunk);
 600                    styles.push((
 601                        line_chunk.len(),
 602                        RunStyle {
 603                            font_id,
 604                            color: highlight_style.color,
 605                            underline,
 606                        },
 607                    ));
 608                    prev_font_id = font_id;
 609                    prev_font_properties = highlight_style.font_properties;
 610                }
 611            }
 612        }
 613
 614        layouts
 615    }
 616}
 617
 618impl Element for EditorElement {
 619    type LayoutState = Option<LayoutState>;
 620    type PaintState = Option<PaintState>;
 621
 622    fn layout(
 623        &mut self,
 624        constraint: SizeConstraint,
 625        cx: &mut LayoutContext,
 626    ) -> (Vector2F, Self::LayoutState) {
 627        let mut size = constraint.max;
 628        if size.x().is_infinite() {
 629            unimplemented!("we don't yet handle an infinite width constraint on buffer elements");
 630        }
 631
 632        let snapshot = self.snapshot(cx.app);
 633        let style = self.settings.style.clone();
 634        let line_height = style.text.line_height(cx.font_cache);
 635
 636        let gutter_padding;
 637        let gutter_width;
 638        if snapshot.mode == EditorMode::Full {
 639            gutter_padding = style.text.em_width(cx.font_cache);
 640            gutter_width = self.max_line_number_width(&snapshot, cx) + gutter_padding * 2.0;
 641        } else {
 642            gutter_padding = 0.0;
 643            gutter_width = 0.0
 644        };
 645
 646        let text_width = size.x() - gutter_width;
 647        let text_offset = vec2f(-style.text.descent(cx.font_cache), 0.);
 648        let em_width = style.text.em_width(cx.font_cache);
 649        let overscroll = vec2f(em_width, 0.);
 650        let wrap_width = text_width - text_offset.x() - overscroll.x() - em_width;
 651        let snapshot = self.update_view(cx.app, |view, cx| {
 652            if view.set_wrap_width(wrap_width, cx) {
 653                view.snapshot(cx)
 654            } else {
 655                snapshot
 656            }
 657        });
 658
 659        let scroll_height = (snapshot.max_point().row() + 1) as f32 * line_height;
 660        if let EditorMode::AutoHeight { max_lines } = snapshot.mode {
 661            size.set_y(
 662                scroll_height
 663                    .min(constraint.max_along(Axis::Vertical))
 664                    .max(constraint.min_along(Axis::Vertical))
 665                    .min(line_height * max_lines as f32),
 666            )
 667        } else if size.y().is_infinite() {
 668            size.set_y(scroll_height);
 669        }
 670        let gutter_size = vec2f(gutter_width, size.y());
 671        let text_size = vec2f(text_width, size.y());
 672
 673        let (autoscroll_horizontally, mut snapshot) = self.update_view(cx.app, |view, cx| {
 674            let autoscroll_horizontally = view.autoscroll_vertically(size.y(), line_height, cx);
 675            let snapshot = view.snapshot(cx);
 676            (autoscroll_horizontally, snapshot)
 677        });
 678
 679        let scroll_position = snapshot.scroll_position();
 680        let start_row = scroll_position.y() as u32;
 681        let scroll_top = scroll_position.y() * line_height;
 682        let end_row = ((scroll_top + size.y()) / line_height).ceil() as u32 + 1; // Add 1 to ensure selections bleed off screen
 683
 684        let mut selections = HashMap::new();
 685        let mut active_rows = BTreeMap::new();
 686        self.update_view(cx.app, |view, cx| {
 687            for selection_set_id in view.active_selection_sets(cx).collect::<Vec<_>>() {
 688                let mut set = Vec::new();
 689                for selection in view.selections_in_range(
 690                    selection_set_id,
 691                    DisplayPoint::new(start_row, 0)..DisplayPoint::new(end_row, 0),
 692                    cx,
 693                ) {
 694                    set.push(selection.clone());
 695                    if selection_set_id == view.selection_set_id {
 696                        let is_empty = selection.start == selection.end;
 697                        let mut selection_start;
 698                        let mut selection_end;
 699                        if selection.start < selection.end {
 700                            selection_start = selection.start;
 701                            selection_end = selection.end;
 702                        } else {
 703                            selection_start = selection.end;
 704                            selection_end = selection.start;
 705                        };
 706                        selection_start = snapshot.prev_row_boundary(selection_start).0;
 707                        selection_end = snapshot.next_row_boundary(selection_end).0;
 708                        for row in cmp::max(selection_start.row(), start_row)
 709                            ..=cmp::min(selection_end.row(), end_row)
 710                        {
 711                            let contains_non_empty_selection =
 712                                active_rows.entry(row).or_insert(!is_empty);
 713                            *contains_non_empty_selection |= !is_empty;
 714                        }
 715                    }
 716                }
 717
 718                selections.insert(selection_set_id.replica_id, set);
 719            }
 720        });
 721
 722        let (line_number_layouts, block_layouts) =
 723            self.layout_rows(start_row..end_row, &active_rows, &snapshot, cx);
 724
 725        let mut max_visible_line_width = 0.0;
 726        let line_layouts = self.layout_lines(start_row..end_row, &mut snapshot, cx);
 727        for line in &line_layouts {
 728            if line.width() > max_visible_line_width {
 729                max_visible_line_width = line.width();
 730            }
 731        }
 732
 733        let mut layout = LayoutState {
 734            size,
 735            gutter_size,
 736            gutter_padding,
 737            text_size,
 738            overscroll,
 739            text_offset,
 740            snapshot,
 741            style: self.settings.style.clone(),
 742            active_rows,
 743            line_layouts,
 744            line_number_layouts,
 745            block_layouts,
 746            line_height,
 747            em_width,
 748            selections,
 749            max_visible_line_width,
 750        };
 751
 752        let scroll_max = layout.scroll_max(cx.font_cache, cx.text_layout_cache).x();
 753        let scroll_width = layout.scroll_width(cx.text_layout_cache);
 754        let max_glyph_width = style.text.em_width(&cx.font_cache);
 755        self.update_view(cx.app, |view, cx| {
 756            let clamped = view.clamp_scroll_left(scroll_max);
 757            let autoscrolled;
 758            if autoscroll_horizontally {
 759                autoscrolled = view.autoscroll_horizontally(
 760                    start_row,
 761                    layout.text_size.x(),
 762                    scroll_width,
 763                    max_glyph_width,
 764                    &layout.line_layouts,
 765                    cx,
 766                );
 767            } else {
 768                autoscrolled = false;
 769            }
 770
 771            if clamped || autoscrolled {
 772                layout.snapshot = view.snapshot(cx);
 773            }
 774        });
 775
 776        (size, Some(layout))
 777    }
 778
 779    fn paint(
 780        &mut self,
 781        bounds: RectF,
 782        visible_bounds: RectF,
 783        layout: &mut Self::LayoutState,
 784        cx: &mut PaintContext,
 785    ) -> Self::PaintState {
 786        if let Some(layout) = layout {
 787            cx.scene.push_layer(Some(bounds));
 788
 789            let gutter_bounds = RectF::new(bounds.origin(), layout.gutter_size);
 790            let text_bounds = RectF::new(
 791                bounds.origin() + vec2f(layout.gutter_size.x(), 0.0),
 792                layout.text_size,
 793            );
 794
 795            self.paint_background(gutter_bounds, text_bounds, layout, cx);
 796            if layout.gutter_size.x() > 0. {
 797                self.paint_gutter(gutter_bounds, visible_bounds, layout, cx);
 798            }
 799            self.paint_text(text_bounds, visible_bounds, layout, cx);
 800
 801            cx.scene.pop_layer();
 802
 803            Some(PaintState {
 804                bounds,
 805                text_bounds,
 806            })
 807        } else {
 808            None
 809        }
 810    }
 811
 812    fn dispatch_event(
 813        &mut self,
 814        event: &Event,
 815        _: RectF,
 816        layout: &mut Self::LayoutState,
 817        paint: &mut Self::PaintState,
 818        cx: &mut EventContext,
 819    ) -> bool {
 820        if let (Some(layout), Some(paint)) = (layout, paint) {
 821            match event {
 822                Event::LeftMouseDown { position, cmd } => {
 823                    self.mouse_down(*position, *cmd, layout, paint, cx)
 824                }
 825                Event::LeftMouseUp { position } => self.mouse_up(*position, cx),
 826                Event::LeftMouseDragged { position } => {
 827                    self.mouse_dragged(*position, layout, paint, cx)
 828                }
 829                Event::ScrollWheel {
 830                    position,
 831                    delta,
 832                    precise,
 833                } => self.scroll(*position, *delta, *precise, layout, paint, cx),
 834                Event::KeyDown {
 835                    chars, keystroke, ..
 836                } => self.key_down(chars, keystroke, cx),
 837                _ => false,
 838            }
 839        } else {
 840            false
 841        }
 842    }
 843
 844    fn debug(
 845        &self,
 846        bounds: RectF,
 847        _: &Self::LayoutState,
 848        _: &Self::PaintState,
 849        _: &gpui::DebugContext,
 850    ) -> json::Value {
 851        json!({
 852            "type": "BufferElement",
 853            "bounds": bounds.to_json()
 854        })
 855    }
 856}
 857
 858pub struct LayoutState {
 859    size: Vector2F,
 860    gutter_size: Vector2F,
 861    gutter_padding: f32,
 862    text_size: Vector2F,
 863    style: EditorStyle,
 864    snapshot: Snapshot,
 865    active_rows: BTreeMap<u32, bool>,
 866    line_layouts: Vec<text_layout::Line>,
 867    line_number_layouts: Vec<Option<text_layout::Line>>,
 868    block_layouts: Vec<(Range<u32>, BlockStyle)>,
 869    line_height: f32,
 870    em_width: f32,
 871    selections: HashMap<ReplicaId, Vec<Range<DisplayPoint>>>,
 872    overscroll: Vector2F,
 873    text_offset: Vector2F,
 874    max_visible_line_width: f32,
 875}
 876
 877impl LayoutState {
 878    fn scroll_width(&self, layout_cache: &TextLayoutCache) -> f32 {
 879        let row = self.snapshot.longest_row();
 880        let longest_line_width = self.layout_line(row, &self.snapshot, layout_cache).width();
 881        longest_line_width.max(self.max_visible_line_width) + self.overscroll.x()
 882    }
 883
 884    fn scroll_max(&self, font_cache: &FontCache, layout_cache: &TextLayoutCache) -> Vector2F {
 885        let text_width = self.text_size.x();
 886        let scroll_width = self.scroll_width(layout_cache);
 887        let em_width = self.style.text.em_width(font_cache);
 888        let max_row = self.snapshot.max_point().row();
 889
 890        vec2f(
 891            ((scroll_width - text_width) / em_width).max(0.0),
 892            max_row.saturating_sub(1) as f32,
 893        )
 894    }
 895
 896    pub fn layout_line(
 897        &self,
 898        row: u32,
 899        snapshot: &Snapshot,
 900        layout_cache: &TextLayoutCache,
 901    ) -> text_layout::Line {
 902        let mut line = snapshot.line(row);
 903
 904        if line.len() > MAX_LINE_LEN {
 905            let mut len = MAX_LINE_LEN;
 906            while !line.is_char_boundary(len) {
 907                len -= 1;
 908            }
 909            line.truncate(len);
 910        }
 911
 912        layout_cache.layout_str(
 913            &line,
 914            self.style.text.font_size,
 915            &[(
 916                snapshot.line_len(row) as usize,
 917                RunStyle {
 918                    font_id: self.style.text.font_id,
 919                    color: Color::black(),
 920                    underline: None,
 921                },
 922            )],
 923        )
 924    }
 925}
 926
 927pub struct PaintState {
 928    bounds: RectF,
 929    text_bounds: RectF,
 930}
 931
 932impl PaintState {
 933    fn point_for_position(
 934        &self,
 935        snapshot: &Snapshot,
 936        layout: &LayoutState,
 937        position: Vector2F,
 938    ) -> DisplayPoint {
 939        let scroll_position = snapshot.scroll_position();
 940        let position = position - self.text_bounds.origin();
 941        let y = position.y().max(0.0).min(layout.size.y());
 942        let row = ((y / layout.line_height) + scroll_position.y()) as u32;
 943        let row = cmp::min(row, snapshot.max_point().row());
 944        let line = &layout.line_layouts[(row - scroll_position.y() as u32) as usize];
 945        let x = position.x() + (scroll_position.x() * layout.em_width);
 946
 947        let column = if x >= 0.0 {
 948            line.index_for_x(x)
 949                .map(|ix| ix as u32)
 950                .unwrap_or(snapshot.line_len(row))
 951        } else {
 952            0
 953        };
 954
 955        DisplayPoint::new(row, column)
 956    }
 957}
 958
 959struct Cursor {
 960    origin: Vector2F,
 961    line_height: f32,
 962    color: Color,
 963}
 964
 965impl Cursor {
 966    fn paint(&self, cx: &mut PaintContext) {
 967        cx.scene.push_quad(Quad {
 968            bounds: RectF::new(self.origin, vec2f(2.0, self.line_height)),
 969            background: Some(self.color),
 970            border: Border::new(0., Color::black()),
 971            corner_radius: 0.,
 972        });
 973    }
 974}
 975
 976#[derive(Debug)]
 977struct Selection {
 978    start_y: f32,
 979    line_height: f32,
 980    lines: Vec<SelectionLine>,
 981    color: Color,
 982}
 983
 984#[derive(Debug)]
 985struct SelectionLine {
 986    start_x: f32,
 987    end_x: f32,
 988}
 989
 990impl Selection {
 991    fn paint(&self, bounds: RectF, scene: &mut Scene) {
 992        if self.lines.len() >= 2 && self.lines[0].start_x > self.lines[1].end_x {
 993            self.paint_lines(self.start_y, &self.lines[0..1], bounds, scene);
 994            self.paint_lines(
 995                self.start_y + self.line_height,
 996                &self.lines[1..],
 997                bounds,
 998                scene,
 999            );
1000        } else {
1001            self.paint_lines(self.start_y, &self.lines, bounds, scene);
1002        }
1003    }
1004
1005    fn paint_lines(&self, start_y: f32, lines: &[SelectionLine], bounds: RectF, scene: &mut Scene) {
1006        if lines.is_empty() {
1007            return;
1008        }
1009
1010        let mut path = PathBuilder::new();
1011        let corner_radius = 0.15 * self.line_height;
1012        let first_line = lines.first().unwrap();
1013        let last_line = lines.last().unwrap();
1014
1015        let first_top_left = vec2f(first_line.start_x, start_y);
1016        let first_top_right = vec2f(first_line.end_x, start_y);
1017
1018        let curve_height = vec2f(0., corner_radius);
1019        let curve_width = |start_x: f32, end_x: f32| {
1020            let max = (end_x - start_x) / 2.;
1021            let width = if max < corner_radius {
1022                max
1023            } else {
1024                corner_radius
1025            };
1026
1027            vec2f(width, 0.)
1028        };
1029
1030        let top_curve_width = curve_width(first_line.start_x, first_line.end_x);
1031        path.reset(first_top_right - top_curve_width);
1032        path.curve_to(first_top_right + curve_height, first_top_right);
1033
1034        let mut iter = lines.iter().enumerate().peekable();
1035        while let Some((ix, line)) = iter.next() {
1036            let bottom_right = vec2f(line.end_x, start_y + (ix + 1) as f32 * self.line_height);
1037
1038            if let Some((_, next_line)) = iter.peek() {
1039                let next_top_right = vec2f(next_line.end_x, bottom_right.y());
1040
1041                match next_top_right.x().partial_cmp(&bottom_right.x()).unwrap() {
1042                    Ordering::Equal => {
1043                        path.line_to(bottom_right);
1044                    }
1045                    Ordering::Less => {
1046                        let curve_width = curve_width(next_top_right.x(), bottom_right.x());
1047                        path.line_to(bottom_right - curve_height);
1048                        path.curve_to(bottom_right - curve_width, bottom_right);
1049                        path.line_to(next_top_right + curve_width);
1050                        path.curve_to(next_top_right + curve_height, next_top_right);
1051                    }
1052                    Ordering::Greater => {
1053                        let curve_width = curve_width(bottom_right.x(), next_top_right.x());
1054                        path.line_to(bottom_right - curve_height);
1055                        path.curve_to(bottom_right + curve_width, bottom_right);
1056                        path.line_to(next_top_right - curve_width);
1057                        path.curve_to(next_top_right + curve_height, next_top_right);
1058                    }
1059                }
1060            } else {
1061                let curve_width = curve_width(line.start_x, line.end_x);
1062                path.line_to(bottom_right - curve_height);
1063                path.curve_to(bottom_right - curve_width, bottom_right);
1064
1065                let bottom_left = vec2f(line.start_x, bottom_right.y());
1066                path.line_to(bottom_left + curve_width);
1067                path.curve_to(bottom_left - curve_height, bottom_left);
1068            }
1069        }
1070
1071        if first_line.start_x > last_line.start_x {
1072            let curve_width = curve_width(last_line.start_x, first_line.start_x);
1073            let second_top_left = vec2f(last_line.start_x, start_y + self.line_height);
1074            path.line_to(second_top_left + curve_height);
1075            path.curve_to(second_top_left + curve_width, second_top_left);
1076            let first_bottom_left = vec2f(first_line.start_x, second_top_left.y());
1077            path.line_to(first_bottom_left - curve_width);
1078            path.curve_to(first_bottom_left - curve_height, first_bottom_left);
1079        }
1080
1081        path.line_to(first_top_left + curve_height);
1082        path.curve_to(first_top_left + top_curve_width, first_top_left);
1083        path.line_to(first_top_right - top_curve_width);
1084
1085        scene.push_path(path.build(self.color, Some(bounds)));
1086    }
1087}
1088
1089fn scale_vertical_mouse_autoscroll_delta(delta: f32) -> f32 {
1090    delta.powf(1.5) / 100.0
1091}
1092
1093fn scale_horizontal_mouse_autoscroll_delta(delta: f32) -> f32 {
1094    delta.powf(1.2) / 300.0
1095}
1096
1097#[cfg(test)]
1098mod tests {
1099    use super::*;
1100    use crate::{
1101        test::sample_text,
1102        {Editor, EditorSettings},
1103    };
1104    use language::Buffer;
1105
1106    #[gpui::test]
1107    fn test_layout_line_numbers(cx: &mut gpui::MutableAppContext) {
1108        let settings = EditorSettings::test(cx);
1109
1110        let buffer = cx.add_model(|cx| Buffer::new(0, sample_text(6, 6), cx));
1111        let (window_id, editor) = cx.add_window(Default::default(), |cx| {
1112            Editor::for_buffer(
1113                buffer,
1114                {
1115                    let settings = settings.clone();
1116                    move |_| settings.clone()
1117                },
1118                cx,
1119            )
1120        });
1121        let element = EditorElement::new(editor.downgrade(), settings);
1122
1123        let (layouts, _) = editor.update(cx, |editor, cx| {
1124            let snapshot = editor.snapshot(cx);
1125            let mut presenter = cx.build_presenter(window_id, 30.);
1126            let mut layout_cx = presenter.build_layout_context(false, cx);
1127            element.layout_rows(0..6, &Default::default(), &snapshot, &mut layout_cx)
1128        });
1129        assert_eq!(layouts.len(), 6);
1130    }
1131}