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