buffer_view.rs

   1use super::{
   2    buffer, movement, Anchor, Bias, Buffer, BufferElement, DisplayMap, DisplayPoint, Point,
   3    ToOffset, ToPoint,
   4};
   5use crate::{settings::Settings, watch, workspace};
   6use anyhow::Result;
   7use easy_parallel::Parallel;
   8use gpui::{
   9    fonts::Properties as FontProperties, keymap::Binding, text_layout, App, AppContext, Element,
  10    ElementBox, Entity, FontCache, ModelHandle, View, ViewContext, WeakViewHandle,
  11};
  12use gpui::{geometry::vector::Vector2F, TextLayoutCache};
  13use parking_lot::Mutex;
  14use smallvec::SmallVec;
  15use smol::Timer;
  16use std::{
  17    cmp::{self, Ordering},
  18    fmt::Write,
  19    mem,
  20    ops::Range,
  21    sync::Arc,
  22    time::Duration,
  23};
  24
  25const CURSOR_BLINK_INTERVAL: Duration = Duration::from_millis(500);
  26
  27pub fn init(app: &mut App) {
  28    app.add_bindings(vec![
  29        Binding::new("backspace", "buffer:backspace", Some("BufferView")),
  30        Binding::new("enter", "buffer:newline", Some("BufferView")),
  31        Binding::new("up", "buffer:move_up", Some("BufferView")),
  32        Binding::new("down", "buffer:move_down", Some("BufferView")),
  33        Binding::new("left", "buffer:move_left", Some("BufferView")),
  34        Binding::new("right", "buffer:move_right", Some("BufferView")),
  35        Binding::new("shift-up", "buffer:select_up", Some("BufferView")),
  36        Binding::new("shift-down", "buffer:select_down", Some("BufferView")),
  37        Binding::new("shift-left", "buffer:select_left", Some("BufferView")),
  38        Binding::new("shift-right", "buffer:select_right", Some("BufferView")),
  39        Binding::new("pageup", "buffer:page_up", Some("BufferView")),
  40        Binding::new("pagedown", "buffer:page_down", Some("BufferView")),
  41        Binding::new("alt-cmd-[", "buffer:fold", Some("BufferView")),
  42        Binding::new("alt-cmd-]", "buffer:unfold", Some("BufferView")),
  43        Binding::new(
  44            "alt-cmd-f",
  45            "buffer:fold_selected_ranges",
  46            Some("BufferView"),
  47        ),
  48    ]);
  49
  50    app.add_action("buffer:scroll", BufferView::scroll);
  51    app.add_action("buffer:select", BufferView::select);
  52    app.add_action("buffer:insert", BufferView::insert);
  53    app.add_action("buffer:newline", BufferView::newline);
  54    app.add_action("buffer:backspace", BufferView::backspace);
  55    app.add_action("buffer:move_up", BufferView::move_up);
  56    app.add_action("buffer:move_down", BufferView::move_down);
  57    app.add_action("buffer:move_left", BufferView::move_left);
  58    app.add_action("buffer:move_right", BufferView::move_right);
  59    app.add_action("buffer:select_up", BufferView::select_up);
  60    app.add_action("buffer:select_down", BufferView::select_down);
  61    app.add_action("buffer:select_left", BufferView::select_left);
  62    app.add_action("buffer:select_right", BufferView::select_right);
  63    app.add_action("buffer:page_up", BufferView::page_up);
  64    app.add_action("buffer:page_down", BufferView::page_down);
  65    app.add_action("buffer:fold", BufferView::fold);
  66    app.add_action("buffer:unfold", BufferView::unfold);
  67    app.add_action(
  68        "buffer:fold_selected_ranges",
  69        BufferView::fold_selected_ranges,
  70    );
  71}
  72
  73pub enum SelectAction {
  74    Begin {
  75        position: DisplayPoint,
  76        add: bool,
  77    },
  78    Update {
  79        position: DisplayPoint,
  80        scroll_position: Vector2F,
  81    },
  82    End,
  83}
  84
  85// impl workspace::Item for Buffer {
  86//     type View = BufferView;
  87
  88//     fn build_view(
  89//         buffer: ModelHandle<Self>,
  90//         settings: watch::Receiver<Settings>,
  91//         ctx: &mut ViewContext<Self::View>,
  92//     ) -> Self::View {
  93//         BufferView::for_buffer(buffer, settings, ctx)
  94//     }
  95// }
  96
  97pub struct BufferView {
  98    handle: WeakViewHandle<Self>,
  99    buffer: ModelHandle<Buffer>,
 100    display_map: ModelHandle<DisplayMap>,
 101    selections: Vec<Selection>,
 102    pending_selection: Option<Selection>,
 103    scroll_position: Mutex<Vector2F>,
 104    autoscroll_requested: Mutex<bool>,
 105    settings: watch::Receiver<Settings>,
 106    focused: bool,
 107    cursors_visible: bool,
 108    blink_epoch: usize,
 109    blinking_paused: bool,
 110    single_line: bool,
 111}
 112
 113impl BufferView {
 114    pub fn single_line(settings: watch::Receiver<Settings>, ctx: &mut ViewContext<Self>) -> Self {
 115        let buffer = ctx.add_model(|_| Buffer::new(0, String::new()));
 116        let mut view = Self::for_buffer(buffer, settings, ctx);
 117        view.single_line = true;
 118        view
 119    }
 120
 121    pub fn for_buffer(
 122        buffer: ModelHandle<Buffer>,
 123        settings: watch::Receiver<Settings>,
 124        ctx: &mut ViewContext<Self>,
 125    ) -> Self {
 126        settings.notify_view_on_change(ctx);
 127
 128        ctx.observe(&buffer, Self::on_buffer_changed);
 129        ctx.subscribe_to_model(&buffer, Self::on_buffer_event);
 130        let display_map = ctx.add_model(|ctx| {
 131            DisplayMap::new(
 132                buffer.clone(),
 133                smol::block_on(settings.read()).tab_size,
 134                ctx,
 135            )
 136        });
 137        ctx.observe(&display_map, Self::on_display_map_changed);
 138
 139        let buffer_ref = buffer.as_ref(ctx);
 140        Self {
 141            handle: ctx.handle(),
 142            buffer,
 143            display_map,
 144            selections: vec![Selection {
 145                start: buffer_ref.anchor_before(0).unwrap(),
 146                end: buffer_ref.anchor_before(0).unwrap(),
 147                reversed: false,
 148                goal_column: None,
 149            }],
 150            pending_selection: None,
 151            scroll_position: Mutex::new(Vector2F::zero()),
 152            autoscroll_requested: Mutex::new(false),
 153            settings,
 154            focused: false,
 155            cursors_visible: false,
 156            blink_epoch: 0,
 157            blinking_paused: false,
 158            single_line: false,
 159        }
 160    }
 161
 162    pub fn buffer(&self) -> &ModelHandle<Buffer> {
 163        &self.buffer
 164    }
 165
 166    pub fn is_gutter_visible(&self) -> bool {
 167        !self.single_line
 168    }
 169
 170    fn scroll(&mut self, scroll_position: &Vector2F, ctx: &mut ViewContext<Self>) {
 171        *self.scroll_position.lock() = *scroll_position;
 172        ctx.notify();
 173    }
 174
 175    pub fn scroll_position(&self) -> Vector2F {
 176        *self.scroll_position.lock()
 177    }
 178
 179    pub fn clamp_scroll_left(&self, max: f32) {
 180        let mut scroll_position = self.scroll_position.lock();
 181        let scroll_left = scroll_position.x();
 182        scroll_position.set_x(scroll_left.min(max));
 183    }
 184
 185    pub fn autoscroll_vertically(
 186        &self,
 187        viewport_height: f32,
 188        line_height: f32,
 189        app: &AppContext,
 190    ) -> bool {
 191        let mut scroll_position = self.scroll_position.lock();
 192        let scroll_top = scroll_position.y();
 193        scroll_position.set_y(scroll_top.min(self.max_point(app).row().saturating_sub(1) as f32));
 194
 195        let mut autoscroll_requested = self.autoscroll_requested.lock();
 196        if *autoscroll_requested {
 197            *autoscroll_requested = false;
 198        } else {
 199            return false;
 200        }
 201
 202        let map = self.display_map.as_ref(app);
 203        let visible_lines = viewport_height / line_height;
 204        let first_cursor_top = self
 205            .selections
 206            .first()
 207            .unwrap()
 208            .head()
 209            .to_display_point(map, app)
 210            .unwrap()
 211            .row() as f32;
 212        let last_cursor_bottom = self
 213            .selections
 214            .last()
 215            .unwrap()
 216            .head()
 217            .to_display_point(map, app)
 218            .unwrap()
 219            .row() as f32
 220            + 1.0;
 221
 222        let margin = ((visible_lines - (last_cursor_bottom - first_cursor_top)) / 2.0)
 223            .floor()
 224            .min(3.0);
 225        if margin < 0.0 {
 226            return false;
 227        }
 228
 229        let target_top = (first_cursor_top - margin).max(0.0);
 230        let target_bottom = last_cursor_bottom + margin;
 231        let start_row = scroll_position.y();
 232        let end_row = start_row + visible_lines;
 233
 234        if target_top < start_row {
 235            scroll_position.set_y(target_top);
 236        } else if target_bottom >= end_row {
 237            scroll_position.set_y(target_bottom - visible_lines);
 238        }
 239
 240        true
 241    }
 242
 243    pub fn autoscroll_horizontally(
 244        &self,
 245        start_row: u32,
 246        viewport_width: f32,
 247        scroll_width: f32,
 248        max_glyph_width: f32,
 249        layouts: &[Arc<text_layout::Line>],
 250        app: &AppContext,
 251    ) {
 252        let map = self.display_map.as_ref(app);
 253
 254        let mut target_left = std::f32::INFINITY;
 255        let mut target_right = 0.0_f32;
 256        for selection in &self.selections {
 257            let head = selection.head().to_display_point(map, app).unwrap();
 258            let start_column = head.column().saturating_sub(3);
 259            let end_column = cmp::min(map.line_len(head.row(), app).unwrap(), head.column() + 3);
 260            target_left = target_left
 261                .min(layouts[(head.row() - start_row) as usize].x_for_index(start_column as usize));
 262            target_right = target_right.max(
 263                layouts[(head.row() - start_row) as usize].x_for_index(end_column as usize)
 264                    + max_glyph_width,
 265            );
 266        }
 267        target_right = target_right.min(scroll_width);
 268
 269        if target_right - target_left > viewport_width {
 270            return;
 271        }
 272
 273        let mut scroll_position = self.scroll_position.lock();
 274        let scroll_left = scroll_position.x() * max_glyph_width;
 275        let scroll_right = scroll_left + viewport_width;
 276
 277        if target_left < scroll_left {
 278            scroll_position.set_x(target_left / max_glyph_width);
 279        } else if target_right > scroll_right {
 280            scroll_position.set_x((target_right - viewport_width) / max_glyph_width);
 281        }
 282    }
 283
 284    fn select(&mut self, arg: &SelectAction, ctx: &mut ViewContext<Self>) {
 285        match arg {
 286            SelectAction::Begin { position, add } => self.begin_selection(*position, *add, ctx),
 287            SelectAction::Update {
 288                position,
 289                scroll_position,
 290            } => self.update_selection(*position, *scroll_position, ctx),
 291            SelectAction::End => self.end_selection(ctx),
 292        }
 293    }
 294
 295    fn begin_selection(&mut self, position: DisplayPoint, add: bool, ctx: &mut ViewContext<Self>) {
 296        if !self.focused {
 297            ctx.focus_self();
 298            ctx.emit(Event::Activate);
 299        }
 300
 301        let display_map = self.display_map.as_ref(ctx);
 302        let cursor = display_map
 303            .anchor_before(position, Bias::Left, ctx.app())
 304            .unwrap();
 305        let selection = Selection {
 306            start: cursor.clone(),
 307            end: cursor,
 308            reversed: false,
 309            goal_column: None,
 310        };
 311
 312        if !add {
 313            self.selections.clear();
 314        }
 315        self.pending_selection = Some(selection);
 316
 317        ctx.notify();
 318    }
 319
 320    fn update_selection(
 321        &mut self,
 322        position: DisplayPoint,
 323        scroll_position: Vector2F,
 324        ctx: &mut ViewContext<Self>,
 325    ) {
 326        let buffer = self.buffer.as_ref(ctx);
 327        let map = self.display_map.as_ref(ctx);
 328        let cursor = map.anchor_before(position, Bias::Left, ctx.app()).unwrap();
 329        if let Some(selection) = self.pending_selection.as_mut() {
 330            selection.set_head(buffer, cursor);
 331        } else {
 332            log::error!("update_selection dispatched with no pending selection");
 333            return;
 334        }
 335
 336        *self.scroll_position.lock() = scroll_position;
 337
 338        ctx.notify();
 339    }
 340
 341    fn end_selection(&mut self, ctx: &mut ViewContext<Self>) {
 342        if let Some(selection) = self.pending_selection.take() {
 343            let ix = self.selection_insertion_index(&selection.start, ctx.app());
 344            self.selections.insert(ix, selection);
 345            self.merge_selections(ctx.app());
 346            ctx.notify();
 347        } else {
 348            log::error!("end_selection dispatched with no pending selection");
 349        }
 350    }
 351
 352    pub fn is_selecting(&self) -> bool {
 353        self.pending_selection.is_some()
 354    }
 355
 356    #[cfg(test)]
 357    fn select_ranges<T>(&mut self, ranges: T, ctx: &mut ViewContext<Self>) -> Result<()>
 358    where
 359        T: IntoIterator<Item = Range<DisplayPoint>>,
 360    {
 361        let buffer = self.buffer.as_ref(ctx);
 362        let map = self.display_map.as_ref(ctx);
 363        let mut selections = Vec::new();
 364        for range in ranges {
 365            selections.push(Selection {
 366                start: map.anchor_after(range.start, Bias::Left, ctx.app())?,
 367                end: map.anchor_before(range.end, Bias::Left, ctx.app())?,
 368                reversed: false,
 369                goal_column: None,
 370            });
 371        }
 372        selections.sort_unstable_by(|a, b| a.start.cmp(&b.start, buffer).unwrap());
 373        self.selections = selections;
 374        self.merge_selections(ctx.app());
 375        ctx.notify();
 376        Ok(())
 377    }
 378
 379    fn insert(&mut self, text: &String, ctx: &mut ViewContext<Self>) {
 380        let buffer = self.buffer.as_ref(ctx);
 381        let mut offset_ranges = SmallVec::<[Range<usize>; 32]>::new();
 382        for selection in &self.selections {
 383            let start = selection.start.to_offset(buffer).unwrap();
 384            let end = selection.end.to_offset(buffer).unwrap();
 385            offset_ranges.push(start..end);
 386        }
 387
 388        self.buffer.update(ctx, |buffer, ctx| {
 389            if let Err(error) = buffer.edit(offset_ranges.iter().cloned(), text.as_str(), Some(ctx))
 390            {
 391                log::error!("error inserting text: {}", error);
 392            };
 393        });
 394
 395        let buffer = self.buffer.as_ref(ctx);
 396        let char_count = text.chars().count() as isize;
 397        let mut delta = 0_isize;
 398        self.selections = offset_ranges
 399            .into_iter()
 400            .map(|range| {
 401                let start = range.start as isize;
 402                let end = range.end as isize;
 403                let anchor = buffer
 404                    .anchor_before((start + delta + char_count) as usize)
 405                    .unwrap();
 406                let deleted_count = end - start;
 407                delta += char_count - deleted_count;
 408                Selection {
 409                    start: anchor.clone(),
 410                    end: anchor,
 411                    reversed: false,
 412                    goal_column: None,
 413                }
 414            })
 415            .collect();
 416
 417        self.pause_cursor_blinking(ctx);
 418        *self.autoscroll_requested.lock() = true;
 419    }
 420
 421    fn newline(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 422        if self.single_line {
 423            ctx.propagate_action();
 424        } else {
 425            self.insert(&"\n".into(), ctx);
 426        }
 427    }
 428
 429    pub fn backspace(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 430        self.select_left(&(), ctx);
 431        self.insert(&String::new(), ctx);
 432    }
 433
 434    pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 435        {
 436            let app = ctx.app();
 437            let map = self.display_map.as_ref(ctx);
 438            for selection in &mut self.selections {
 439                let start = selection.start.to_display_point(map, app).unwrap();
 440                let end = selection.end.to_display_point(map, app).unwrap();
 441
 442                if start != end {
 443                    selection.end = selection.start.clone();
 444                } else {
 445                    let cursor = map
 446                        .anchor_before(movement::left(map, start, app).unwrap(), Bias::Left, app)
 447                        .unwrap();
 448                    selection.start = cursor.clone();
 449                    selection.end = cursor;
 450                }
 451                selection.reversed = false;
 452                selection.goal_column = None;
 453            }
 454        }
 455        self.changed_selections(ctx);
 456    }
 457
 458    pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 459        {
 460            let buffer = self.buffer.as_ref(ctx);
 461            let map = self.display_map.as_ref(ctx);
 462            for selection in &mut self.selections {
 463                let head = selection.head().to_display_point(map, ctx.app()).unwrap();
 464                let cursor = map
 465                    .anchor_before(
 466                        movement::left(map, head, ctx.app()).unwrap(),
 467                        Bias::Left,
 468                        ctx.app(),
 469                    )
 470                    .unwrap();
 471                selection.set_head(&buffer, cursor);
 472                selection.goal_column = None;
 473            }
 474        }
 475        self.changed_selections(ctx);
 476    }
 477
 478    pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 479        {
 480            let app = ctx.app();
 481            let map = self.display_map.as_ref(app);
 482            for selection in &mut self.selections {
 483                let start = selection.start.to_display_point(map, app).unwrap();
 484                let end = selection.end.to_display_point(map, app).unwrap();
 485
 486                if start != end {
 487                    selection.start = selection.end.clone();
 488                } else {
 489                    let cursor = map
 490                        .anchor_before(movement::right(map, end, app).unwrap(), Bias::Right, app)
 491                        .unwrap();
 492                    selection.start = cursor.clone();
 493                    selection.end = cursor;
 494                }
 495                selection.reversed = false;
 496                selection.goal_column = None;
 497            }
 498        }
 499        self.changed_selections(ctx);
 500    }
 501
 502    pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 503        {
 504            let buffer = self.buffer.as_ref(ctx);
 505            let app = ctx.app();
 506            let map = self.display_map.as_ref(app);
 507            for selection in &mut self.selections {
 508                let head = selection.head().to_display_point(map, ctx.app()).unwrap();
 509                let cursor = map
 510                    .anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app)
 511                    .unwrap();
 512                selection.set_head(&buffer, cursor);
 513                selection.goal_column = None;
 514            }
 515        }
 516        self.changed_selections(ctx);
 517    }
 518
 519    pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 520        if self.single_line {
 521            ctx.propagate_action();
 522        } else {
 523            let app = ctx.app();
 524            let map = self.display_map.as_ref(app);
 525            for selection in &mut self.selections {
 526                let start = selection.start.to_display_point(map, app).unwrap();
 527                let end = selection.end.to_display_point(map, app).unwrap();
 528                if start != end {
 529                    selection.goal_column = None;
 530                }
 531
 532                let (start, goal_column) =
 533                    movement::up(map, start, selection.goal_column, app).unwrap();
 534                let cursor = map.anchor_before(start, Bias::Left, app).unwrap();
 535                selection.start = cursor.clone();
 536                selection.end = cursor;
 537                selection.goal_column = goal_column;
 538                selection.reversed = false;
 539            }
 540            self.changed_selections(ctx);
 541        }
 542    }
 543
 544    pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 545        if self.single_line {
 546            ctx.propagate_action();
 547        } else {
 548            let app = ctx.app();
 549            let buffer = self.buffer.as_ref(app);
 550            let map = self.display_map.as_ref(app);
 551            for selection in &mut self.selections {
 552                let head = selection.head().to_display_point(map, app).unwrap();
 553                let (head, goal_column) =
 554                    movement::up(map, head, selection.goal_column, app).unwrap();
 555                selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap());
 556                selection.goal_column = goal_column;
 557            }
 558            self.changed_selections(ctx);
 559        }
 560    }
 561
 562    pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 563        if self.single_line {
 564            ctx.propagate_action();
 565        } else {
 566            let app = ctx.app();
 567            let map = self.display_map.as_ref(app);
 568            for selection in &mut self.selections {
 569                let start = selection.start.to_display_point(map, app).unwrap();
 570                let end = selection.end.to_display_point(map, app).unwrap();
 571                if start != end {
 572                    selection.goal_column = None;
 573                }
 574
 575                let (start, goal_column) =
 576                    movement::down(map, end, selection.goal_column, app).unwrap();
 577                let cursor = map.anchor_before(start, Bias::Right, app).unwrap();
 578                selection.start = cursor.clone();
 579                selection.end = cursor;
 580                selection.goal_column = goal_column;
 581                selection.reversed = false;
 582            }
 583            self.changed_selections(ctx);
 584        }
 585    }
 586
 587    pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 588        if self.single_line {
 589            ctx.propagate_action();
 590        } else {
 591            let app = ctx.app();
 592            let buffer = self.buffer.as_ref(ctx);
 593            let map = self.display_map.as_ref(ctx);
 594            for selection in &mut self.selections {
 595                let head = selection.head().to_display_point(map, app).unwrap();
 596                let (head, goal_column) =
 597                    movement::down(map, head, selection.goal_column, app).unwrap();
 598                selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap());
 599                selection.goal_column = goal_column;
 600            }
 601            self.changed_selections(ctx);
 602        }
 603    }
 604
 605    pub fn changed_selections(&mut self, ctx: &mut ViewContext<Self>) {
 606        self.merge_selections(ctx.app());
 607        self.pause_cursor_blinking(ctx);
 608        *self.autoscroll_requested.lock() = true;
 609        ctx.notify();
 610    }
 611
 612    fn merge_selections(&mut self, ctx: &AppContext) {
 613        let buffer = self.buffer.as_ref(ctx);
 614        let mut i = 1;
 615        while i < self.selections.len() {
 616            if self.selections[i - 1]
 617                .end
 618                .cmp(&self.selections[i].start, buffer)
 619                .unwrap()
 620                >= Ordering::Equal
 621            {
 622                let removed = self.selections.remove(i);
 623                if removed
 624                    .start
 625                    .cmp(&self.selections[i - 1].start, buffer)
 626                    .unwrap()
 627                    < Ordering::Equal
 628                {
 629                    self.selections[i - 1].start = removed.start;
 630                }
 631                if removed
 632                    .end
 633                    .cmp(&self.selections[i - 1].end, buffer)
 634                    .unwrap()
 635                    > Ordering::Equal
 636                {
 637                    self.selections[i - 1].end = removed.end;
 638                }
 639            } else {
 640                i += 1;
 641            }
 642        }
 643    }
 644
 645    pub fn first_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
 646        self.selections
 647            .first()
 648            .unwrap()
 649            .display_range(self.display_map.as_ref(app), app)
 650    }
 651
 652    pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
 653        self.selections
 654            .last()
 655            .unwrap()
 656            .display_range(self.display_map.as_ref(app), app)
 657    }
 658
 659    pub fn selections_in_range<'a>(
 660        &'a self,
 661        range: Range<DisplayPoint>,
 662        app: &'a AppContext,
 663    ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
 664        let map = self.display_map.as_ref(app);
 665
 666        let start = map.anchor_before(range.start, Bias::Left, app).unwrap();
 667        let start_index = self.selection_insertion_index(&start, app);
 668        let pending_selection = self.pending_selection.as_ref().and_then(|s| {
 669            let selection_range = s.display_range(map, app);
 670            if selection_range.start <= range.end || selection_range.end <= range.end {
 671                Some(selection_range)
 672            } else {
 673                None
 674            }
 675        });
 676        self.selections[start_index..]
 677            .iter()
 678            .map(move |s| s.display_range(map, app))
 679            .take_while(move |r| r.start <= range.end || r.end <= range.end)
 680            .chain(pending_selection)
 681    }
 682
 683    fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize {
 684        let buffer = self.buffer.as_ref(app);
 685
 686        match self
 687            .selections
 688            .binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap())
 689        {
 690            Ok(index) => index,
 691            Err(index) => {
 692                if index > 0
 693                    && self.selections[index - 1].end.cmp(&start, buffer).unwrap()
 694                        == Ordering::Greater
 695                {
 696                    index - 1
 697                } else {
 698                    index
 699                }
 700            }
 701        }
 702    }
 703
 704    pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
 705        log::info!("BufferView::page_up");
 706    }
 707
 708    pub fn page_down(&mut self, _: &(), _: &mut ViewContext<Self>) {
 709        log::info!("BufferView::page_down");
 710    }
 711
 712    pub fn fold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 713        use super::RangeExt;
 714
 715        let mut fold_ranges = Vec::new();
 716
 717        let app = ctx.app();
 718        let map = self.display_map.as_ref(app);
 719        for selection in &self.selections {
 720            let (start, end) = selection.display_range(map, app).sorted();
 721            let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
 722
 723            for row in (0..=end.row()).rev() {
 724                if self.is_line_foldable(row, app) && !map.is_line_folded(row) {
 725                    let fold_range = self.foldable_range_for_line(row, app).unwrap();
 726                    if fold_range.end.row >= buffer_start_row {
 727                        fold_ranges.push(fold_range);
 728                        if row <= start.row() {
 729                            break;
 730                        }
 731                    }
 732                }
 733            }
 734        }
 735
 736        if !fold_ranges.is_empty() {
 737            self.display_map.update(ctx, |map, ctx| {
 738                map.fold(fold_ranges, ctx).unwrap();
 739            });
 740            *self.autoscroll_requested.lock() = true;
 741        }
 742    }
 743
 744    pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 745        use super::RangeExt;
 746
 747        let app = ctx.app();
 748        let map = self.display_map.as_ref(app);
 749        let buffer = self.buffer.as_ref(app);
 750        let ranges = self
 751            .selections
 752            .iter()
 753            .map(|s| {
 754                let (start, end) = s.display_range(map, app).sorted();
 755                let mut start = start.to_buffer_point(map, Bias::Left, app).unwrap();
 756                let mut end = end.to_buffer_point(map, Bias::Left, app).unwrap();
 757                start.column = 0;
 758                end.column = buffer.line_len(end.row).unwrap();
 759                start..end
 760            })
 761            .collect::<Vec<_>>();
 762
 763        self.display_map.update(ctx, |map, ctx| {
 764            map.unfold(ranges, ctx).unwrap();
 765        });
 766        *self.autoscroll_requested.lock() = true;
 767    }
 768
 769    fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool {
 770        let max_point = self.max_point(app);
 771        if display_row >= max_point.row() {
 772            false
 773        } else {
 774            let (start_indent, is_blank) = self.line_indent(display_row, app).unwrap();
 775            if is_blank {
 776                false
 777            } else {
 778                for display_row in display_row + 1..=max_point.row() {
 779                    let (indent, is_blank) = self.line_indent(display_row, app).unwrap();
 780                    if !is_blank {
 781                        return indent > start_indent;
 782                    }
 783                }
 784                false
 785            }
 786        }
 787    }
 788
 789    fn line_indent(&self, display_row: u32, app: &AppContext) -> Result<(usize, bool)> {
 790        let mut indent = 0;
 791        let mut is_blank = true;
 792        for c in self
 793            .display_map
 794            .as_ref(app)
 795            .chars_at(DisplayPoint::new(display_row, 0), app)?
 796        {
 797            if c == ' ' {
 798                indent += 1;
 799            } else {
 800                is_blank = c == '\n';
 801                break;
 802            }
 803        }
 804        Ok((indent, is_blank))
 805    }
 806
 807    fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Result<Range<Point>> {
 808        let map = self.display_map.as_ref(app);
 809        let max_point = self.max_point(app);
 810
 811        let (start_indent, _) = self.line_indent(start_row, app)?;
 812        let start = DisplayPoint::new(start_row, self.line_len(start_row, app)?);
 813        let mut end = None;
 814        for row in start_row + 1..=max_point.row() {
 815            let (indent, is_blank) = self.line_indent(row, app)?;
 816            if !is_blank && indent <= start_indent {
 817                end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app)?));
 818                break;
 819            }
 820        }
 821
 822        let end = end.unwrap_or(max_point);
 823        return Ok(start.to_buffer_point(map, Bias::Left, app)?
 824            ..end.to_buffer_point(map, Bias::Left, app)?);
 825    }
 826
 827    pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 828        self.display_map.update(ctx, |map, ctx| {
 829            let buffer = self.buffer.as_ref(ctx);
 830            let ranges = self
 831                .selections
 832                .iter()
 833                .map(|s| s.range(buffer))
 834                .collect::<Vec<_>>();
 835            map.fold(ranges, ctx).unwrap();
 836        });
 837    }
 838
 839    pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
 840        self.display_map.as_ref(app).line(display_row, app)
 841    }
 842
 843    pub fn line_len(&self, display_row: u32, app: &AppContext) -> Result<u32> {
 844        self.display_map.as_ref(app).line_len(display_row, app)
 845    }
 846
 847    pub fn rightmost_point(&self, app: &AppContext) -> DisplayPoint {
 848        self.display_map.as_ref(app).rightmost_point()
 849    }
 850
 851    pub fn max_point(&self, app: &AppContext) -> DisplayPoint {
 852        self.display_map.as_ref(app).max_point(app)
 853    }
 854
 855    pub fn text(&self, app: &AppContext) -> String {
 856        self.display_map.as_ref(app).text(app)
 857    }
 858
 859    pub fn font_size(&self) -> f32 {
 860        smol::block_on(self.settings.read()).buffer_font_size
 861    }
 862
 863    pub fn font_ascent(&self, font_cache: &FontCache) -> f32 {
 864        let settings = smol::block_on(self.settings.read());
 865        let font_id = font_cache.default_font(settings.buffer_font_family);
 866        let ascent = font_cache.metric(font_id, |m| m.ascent);
 867        font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
 868    }
 869
 870    pub fn font_descent(&self, font_cache: &FontCache) -> f32 {
 871        let settings = smol::block_on(self.settings.read());
 872        let font_id = font_cache.default_font(settings.buffer_font_family);
 873        let ascent = font_cache.metric(font_id, |m| m.descent);
 874        font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
 875    }
 876
 877    pub fn line_height(&self, font_cache: &FontCache) -> f32 {
 878        let settings = smol::block_on(self.settings.read());
 879        let font_id = font_cache.default_font(settings.buffer_font_family);
 880        font_cache
 881            .bounding_box(font_id, settings.buffer_font_size)
 882            .y()
 883    }
 884
 885    pub fn em_width(&self, font_cache: &FontCache) -> f32 {
 886        let settings = smol::block_on(self.settings.read());
 887        let font_id = font_cache.default_font(settings.buffer_font_family);
 888        font_cache.em_width(font_id, settings.buffer_font_size)
 889    }
 890
 891    // TODO: Can we make this not return a result?
 892    pub fn max_line_number_width(
 893        &self,
 894        font_cache: &FontCache,
 895        layout_cache: &TextLayoutCache,
 896        app: &AppContext,
 897    ) -> Result<f32> {
 898        let settings = smol::block_on(self.settings.read());
 899        let font_size = settings.buffer_font_size;
 900        let font_id =
 901            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
 902        let digit_count = ((self.buffer.as_ref(app).max_point().row + 1) as f32)
 903            .log10()
 904            .floor() as usize
 905            + 1;
 906
 907        Ok(layout_cache
 908            .layout_str(
 909                "1".repeat(digit_count).as_str(),
 910                font_size,
 911                &[(0..digit_count, font_id)],
 912            )
 913            .width)
 914    }
 915
 916    pub fn layout_line_numbers(
 917        &self,
 918        viewport_height: f32,
 919        font_cache: &FontCache,
 920        layout_cache: &TextLayoutCache,
 921        app: &AppContext,
 922    ) -> Result<Vec<Arc<text_layout::Line>>> {
 923        let display_map = self.display_map.as_ref(app);
 924
 925        let settings = smol::block_on(self.settings.read());
 926        let font_size = settings.buffer_font_size;
 927        let font_id =
 928            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
 929
 930        let start_row = self.scroll_position().y() as usize;
 931        let end_row = cmp::min(
 932            self.max_point(app).row() as usize,
 933            start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
 934        );
 935        let line_count = end_row - start_row + 1;
 936        let cpus = num_cpus::get();
 937        let chunk_size = (line_count + cpus - 1) / cpus;
 938
 939        let mut layouts = Vec::new();
 940        layouts.resize_with(line_count, Default::default);
 941
 942        Parallel::<Result<()>>::new()
 943            .each(
 944                layouts.chunks_mut(chunk_size).enumerate(),
 945                |(i, layouts)| {
 946                    let mut line_number = String::new();
 947                    let start = start_row + i * chunk_size;
 948                    let line_numbers = display_map.buffer_rows(start as u32)?.take(layouts.len());
 949                    for (j, buffer_row) in line_numbers.enumerate() {
 950                        line_number.clear();
 951                        write!(&mut line_number, "{}", buffer_row + 1).unwrap();
 952                        layouts[j] = layout_cache.layout_str(
 953                            &line_number,
 954                            font_size,
 955                            &[(0..line_number.len(), font_id)],
 956                        );
 957                    }
 958                    Ok(())
 959                },
 960            )
 961            .run()
 962            .into_iter()
 963            .collect::<Result<()>>()?;
 964
 965        Ok(layouts)
 966    }
 967
 968    pub fn layout_lines(
 969        &self,
 970        mut rows: Range<u32>,
 971        font_cache: &FontCache,
 972        layout_cache: &TextLayoutCache,
 973        app: &AppContext,
 974    ) -> Result<Vec<Arc<text_layout::Line>>> {
 975        let display_map = self.display_map.as_ref(app);
 976
 977        rows.end = cmp::min(rows.end, display_map.max_point(app).row() + 1);
 978        if rows.start >= rows.end {
 979            return Ok(Vec::new());
 980        }
 981
 982        let settings = smol::block_on(self.settings.read());
 983        let font_id =
 984            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
 985        let font_size = settings.buffer_font_size;
 986
 987        let cpus = num_cpus::get();
 988        let chunk_size = (rows.len() + cpus - 1) / cpus;
 989
 990        let mut layouts = Vec::new();
 991        layouts.resize_with(rows.len(), Default::default);
 992
 993        Parallel::new()
 994            .each(
 995                layouts.chunks_mut(chunk_size as usize).enumerate(),
 996                |(ix, chunk)| {
 997                    let chunk_start = rows.start as usize + ix * chunk_size;
 998                    let chunk_end = cmp::min(chunk_start + chunk_size, rows.end as usize);
 999
1000                    let mut row = chunk_start;
1001                    let mut line = String::new();
1002                    let mut line_len = 0;
1003                    let chars = display_map
1004                        .chars_at(DisplayPoint::new(chunk_start as u32, 0), app)
1005                        .unwrap();
1006                    for char in chars.chain(Some('\n')) {
1007                        if char == '\n' {
1008                            chunk[(row - chunk_start) as usize] = layout_cache.layout_str(
1009                                &line,
1010                                font_size,
1011                                &[(0..line_len, font_id)],
1012                            );
1013                            line.clear();
1014                            line_len = 0;
1015                            row += 1;
1016                            if row == chunk_end {
1017                                break;
1018                            }
1019                        } else {
1020                            line_len += 1;
1021                            line.push(char);
1022                        }
1023                    }
1024                },
1025            )
1026            .run();
1027
1028        Ok(layouts)
1029    }
1030
1031    pub fn layout_line(
1032        &self,
1033        row: u32,
1034        font_cache: &FontCache,
1035        layout_cache: &TextLayoutCache,
1036        app: &AppContext,
1037    ) -> Result<Arc<text_layout::Line>> {
1038        let settings = smol::block_on(self.settings.read());
1039        let font_id =
1040            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1041
1042        let line = self.line(row, app)?;
1043
1044        Ok(layout_cache.layout_str(
1045            &line,
1046            settings.buffer_font_size,
1047            &[(0..self.line_len(row, app)? as usize, font_id)],
1048        ))
1049    }
1050
1051    fn next_blink_epoch(&mut self) -> usize {
1052        self.blink_epoch += 1;
1053        self.blink_epoch
1054    }
1055
1056    fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext<Self>) {
1057        self.cursors_visible = true;
1058        ctx.notify();
1059
1060        let epoch = self.next_blink_epoch();
1061        ctx.spawn(
1062            async move {
1063                Timer::after(CURSOR_BLINK_INTERVAL).await;
1064                epoch
1065            },
1066            Self::resume_cursor_blinking,
1067        )
1068        .detach();
1069    }
1070
1071    fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1072        if epoch == self.blink_epoch {
1073            self.blinking_paused = false;
1074            self.blink_cursors(epoch, ctx);
1075        }
1076    }
1077
1078    fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1079        if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
1080            self.cursors_visible = !self.cursors_visible;
1081            ctx.notify();
1082
1083            let epoch = self.next_blink_epoch();
1084            ctx.spawn(
1085                async move {
1086                    Timer::after(CURSOR_BLINK_INTERVAL).await;
1087                    epoch
1088                },
1089                Self::blink_cursors,
1090            )
1091            .detach();
1092        }
1093    }
1094
1095    pub fn cursors_visible(&self) -> bool {
1096        self.cursors_visible
1097    }
1098
1099    fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, ctx: &mut ViewContext<Self>) {
1100        ctx.notify();
1101    }
1102
1103    fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, ctx: &mut ViewContext<Self>) {
1104        ctx.notify();
1105    }
1106
1107    fn on_buffer_event(
1108        &mut self,
1109        _: ModelHandle<Buffer>,
1110        event: &buffer::Event,
1111        ctx: &mut ViewContext<Self>,
1112    ) {
1113        match event {
1114            buffer::Event::Edited(_) => ctx.emit(Event::Edited),
1115        }
1116    }
1117}
1118
1119struct Selection {
1120    start: Anchor,
1121    end: Anchor,
1122    reversed: bool,
1123    goal_column: Option<u32>,
1124}
1125
1126pub enum Event {
1127    Activate,
1128    Edited,
1129    Blurred,
1130}
1131
1132impl Entity for BufferView {
1133    type Event = Event;
1134}
1135
1136impl View for BufferView {
1137    fn render<'a>(&self, app: &AppContext) -> ElementBox {
1138        BufferElement::new(self.handle.upgrade(app).unwrap()).boxed()
1139    }
1140
1141    fn ui_name() -> &'static str {
1142        "BufferView"
1143    }
1144
1145    fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
1146        self.focused = true;
1147        self.blink_cursors(self.blink_epoch, ctx);
1148    }
1149
1150    fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
1151        self.focused = false;
1152        self.cursors_visible = false;
1153        ctx.emit(Event::Blurred);
1154        ctx.notify();
1155    }
1156}
1157
1158impl workspace::Item for Buffer {
1159    type View = BufferView;
1160
1161    fn build_view(
1162        buffer: ModelHandle<Self>,
1163        settings: watch::Receiver<Settings>,
1164        ctx: &mut ViewContext<Self::View>,
1165    ) -> Self::View {
1166        BufferView::for_buffer(buffer, settings, ctx)
1167    }
1168}
1169
1170impl workspace::ItemView for BufferView {
1171    fn is_activate_event(event: &Self::Event) -> bool {
1172        match event {
1173            Event::Activate => true,
1174            _ => false,
1175        }
1176    }
1177
1178    fn title(&self, app: &AppContext) -> std::string::String {
1179        if let Some(path) = self.buffer.as_ref(app).path(app) {
1180            path.file_name()
1181                .expect("buffer's path is always to a file")
1182                .to_string_lossy()
1183                .into()
1184        } else {
1185            "untitled".into()
1186        }
1187    }
1188
1189    fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)> {
1190        self.buffer.as_ref(app).entry_id()
1191    }
1192
1193    fn clone_on_split(&self, ctx: &mut ViewContext<Self>) -> Option<Self>
1194    where
1195        Self: Sized,
1196    {
1197        let clone = BufferView::for_buffer(self.buffer.clone(), self.settings.clone(), ctx);
1198        *clone.scroll_position.lock() = *self.scroll_position.lock();
1199        Some(clone)
1200    }
1201}
1202
1203impl Selection {
1204    fn head(&self) -> &Anchor {
1205        if self.reversed {
1206            &self.start
1207        } else {
1208            &self.end
1209        }
1210    }
1211
1212    fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
1213        if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
1214            if !self.reversed {
1215                mem::swap(&mut self.start, &mut self.end);
1216                self.reversed = true;
1217            }
1218            self.start = cursor;
1219        } else {
1220            if self.reversed {
1221                mem::swap(&mut self.start, &mut self.end);
1222                self.reversed = false;
1223            }
1224            self.end = cursor;
1225        }
1226    }
1227
1228    fn tail(&self) -> &Anchor {
1229        if self.reversed {
1230            &self.end
1231        } else {
1232            &self.start
1233        }
1234    }
1235
1236    fn range(&self, buffer: &Buffer) -> Range<Point> {
1237        let start = self.start.to_point(buffer).unwrap();
1238        let end = self.end.to_point(buffer).unwrap();
1239        if self.reversed {
1240            end..start
1241        } else {
1242            start..end
1243        }
1244    }
1245
1246    fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range<DisplayPoint> {
1247        let start = self.start.to_display_point(map, app).unwrap();
1248        let end = self.end.to_display_point(map, app).unwrap();
1249        if self.reversed {
1250            end..start
1251        } else {
1252            start..end
1253        }
1254    }
1255}
1256
1257#[cfg(test)]
1258mod tests {
1259    use super::*;
1260    use crate::{editor::Point, settings, test::sample_text};
1261    use anyhow::Error;
1262    use unindent::Unindent;
1263
1264    #[test]
1265    fn test_selection_with_mouse() {
1266        App::test((), |mut app| async move {
1267            let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n"));
1268            let settings = settings::channel(&app.font_cache()).unwrap().1;
1269            let (_, buffer_view) =
1270                app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
1271
1272            buffer_view.update(&mut app, |view, ctx| {
1273                view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
1274            });
1275
1276            buffer_view.read(&app, |view, app| {
1277                let selections = view
1278                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1279                    .collect::<Vec<_>>();
1280                assert_eq!(
1281                    selections,
1282                    [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
1283                );
1284            });
1285
1286            buffer_view.update(&mut app, |view, ctx| {
1287                view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1288            });
1289
1290            buffer_view.read(&app, |view, app| {
1291                let selections = view
1292                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1293                    .collect::<Vec<_>>();
1294                assert_eq!(
1295                    selections,
1296                    [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
1297                );
1298            });
1299
1300            buffer_view.update(&mut app, |view, ctx| {
1301                view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
1302            });
1303
1304            buffer_view.read(&app, |view, app| {
1305                let selections = view
1306                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1307                    .collect::<Vec<_>>();
1308                assert_eq!(
1309                    selections,
1310                    [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1311                );
1312            });
1313
1314            buffer_view.update(&mut app, |view, ctx| {
1315                view.end_selection(ctx);
1316                view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1317            });
1318
1319            buffer_view.read(&app, |view, app| {
1320                let selections = view
1321                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1322                    .collect::<Vec<_>>();
1323                assert_eq!(
1324                    selections,
1325                    [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1326                );
1327            });
1328
1329            buffer_view.update(&mut app, |view, ctx| {
1330                view.begin_selection(DisplayPoint::new(3, 3), true, ctx);
1331                view.update_selection(DisplayPoint::new(0, 0), Vector2F::zero(), ctx);
1332            });
1333
1334            buffer_view.read(&app, |view, app| {
1335                let selections = view
1336                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1337                    .collect::<Vec<_>>();
1338                assert_eq!(
1339                    selections,
1340                    [
1341                        DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
1342                        DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
1343                    ]
1344                );
1345            });
1346
1347            buffer_view.update(&mut app, |view, ctx| {
1348                view.end_selection(ctx);
1349            });
1350
1351            buffer_view.read(&app, |view, app| {
1352                let selections = view
1353                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1354                    .collect::<Vec<_>>();
1355                assert_eq!(
1356                    selections,
1357                    [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
1358                );
1359            });
1360        });
1361    }
1362
1363    #[test]
1364    fn test_layout_line_numbers() -> Result<()> {
1365        App::test((), |mut app| async move {
1366            let layout_cache = TextLayoutCache::new(app.platform().fonts());
1367            let font_cache = app.font_cache();
1368
1369            let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
1370
1371            let settings = settings::channel(&font_cache).unwrap().1;
1372            let (_, view) =
1373                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1374
1375            view.read(&app, |view, app| {
1376                let layouts = view.layout_line_numbers(1000.0, &font_cache, &layout_cache, app)?;
1377                assert_eq!(layouts.len(), 6);
1378                Result::<()>::Ok(())
1379            })?;
1380
1381            Ok(())
1382        })
1383    }
1384
1385    #[test]
1386    fn test_fold() -> Result<()> {
1387        App::test((), |mut app| async move {
1388            let buffer = app.add_model(|_| {
1389                Buffer::new(
1390                    0,
1391                    "
1392                    impl Foo {
1393                        // Hello!
1394
1395                        fn a() {
1396                            1
1397                        }
1398
1399                        fn b() {
1400                            2
1401                        }
1402                            3
1403                        }
1404                    }
1405                "
1406                    .unindent(),
1407                )
1408            });
1409            let settings = settings::channel(&app.font_cache()).unwrap().1;
1410            let (_, view) =
1411                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1412
1413            view.update(&mut app, |view, ctx| {
1414                view.select_ranges(Some(DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)), ctx)?;
1415                view.fold(&(), ctx);
1416                assert_eq!(
1417                    view.text(ctx.app()),
1418                    "
1419                    impl Foo {
1420                        // Hello!
1421
1422                        fn a() {
1423                            1
1424                        }
1425
1426                        fn b() {…
1427                        }
1428
1429                        fn c() {…
1430                        }
1431                    }
1432                "
1433                    .unindent(),
1434                );
1435
1436                view.fold(&(), ctx);
1437                assert_eq!(
1438                    view.text(ctx.app()),
1439                    "
1440                    impl Foo {…
1441                    }
1442                "
1443                    .unindent(),
1444                );
1445
1446                view.unfold(&(), ctx);
1447                assert_eq!(
1448                    view.text(ctx.app()),
1449                    "
1450                    impl Foo {
1451                        // Hello!
1452
1453                        fn a() {
1454                            1
1455                        }
1456
1457                        fn b() {…
1458                        }
1459
1460                        fn c() {…
1461                        }
1462                    }
1463                "
1464                    .unindent(),
1465                );
1466
1467                view.unfold(&(), ctx);
1468                assert_eq!(view.text(ctx.app()), buffer.as_ref(ctx).text());
1469
1470                Ok::<(), Error>(())
1471            })?;
1472
1473            Ok(())
1474        })
1475    }
1476
1477    #[test]
1478    fn test_move_cursor() -> Result<()> {
1479        App::test((), |mut app| async move {
1480            let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
1481            let settings = settings::channel(&app.font_cache()).unwrap().1;
1482            let (_, view) =
1483                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1484
1485            buffer.update(&mut app, |buffer, ctx| {
1486                buffer.edit(
1487                    vec![
1488                        Point::new(1, 0)..Point::new(1, 0),
1489                        Point::new(1, 1)..Point::new(1, 1),
1490                    ],
1491                    "\t",
1492                    Some(ctx),
1493                )
1494            })?;
1495
1496            view.update(&mut app, |view, ctx| {
1497                view.move_down(&(), ctx);
1498                assert_eq!(
1499                    view.selections(ctx.app()),
1500                    &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
1501                );
1502                view.move_right(&(), ctx);
1503                assert_eq!(
1504                    view.selections(ctx.app()),
1505                    &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
1506                );
1507                Ok::<(), Error>(())
1508            })?;
1509
1510            Ok(())
1511        })
1512    }
1513
1514    impl BufferView {
1515        fn selections(&self, app: &AppContext) -> Vec<Range<DisplayPoint>> {
1516            self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app)
1517                .collect::<Vec<_>>()
1518        }
1519    }
1520}