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    executor::BackgroundTask, fonts::Properties as FontProperties, keymap::Binding, text_layout,
   9    App, AppContext, Element, ElementBox, Entity, FontCache, ModelHandle, MutableAppContext, View,
  10    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<'a, T>(&mut self, ranges: T, ctx: &mut ViewContext<Self>) -> Result<()>
 358    where
 359        T: IntoIterator<Item = &'a 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        let buffer = self.buffer.as_ref(ctx);
 431        let map = self.display_map.as_ref(ctx);
 432        for selection in &mut self.selections {
 433            if selection.range(buffer).is_empty() {
 434                let head = selection.head().to_display_point(map, ctx.app()).unwrap();
 435                let cursor = map
 436                    .anchor_before(
 437                        movement::left(map, head, ctx.app()).unwrap(),
 438                        Bias::Left,
 439                        ctx.app(),
 440                    )
 441                    .unwrap();
 442                selection.set_head(&buffer, cursor);
 443                selection.goal_column = None;
 444            }
 445        }
 446        self.changed_selections(ctx);
 447        self.insert(&String::new(), ctx);
 448    }
 449
 450    pub fn move_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 451        {
 452            let app = ctx.app();
 453            let map = self.display_map.as_ref(ctx);
 454            for selection in &mut self.selections {
 455                let start = selection.start.to_display_point(map, app).unwrap();
 456                let end = selection.end.to_display_point(map, app).unwrap();
 457
 458                if start != end {
 459                    selection.end = selection.start.clone();
 460                } else {
 461                    let cursor = map
 462                        .anchor_before(movement::left(map, start, app).unwrap(), Bias::Left, app)
 463                        .unwrap();
 464                    selection.start = cursor.clone();
 465                    selection.end = cursor;
 466                }
 467                selection.reversed = false;
 468                selection.goal_column = None;
 469            }
 470        }
 471        self.changed_selections(ctx);
 472    }
 473
 474    pub fn select_left(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 475        {
 476            let buffer = self.buffer.as_ref(ctx);
 477            let map = self.display_map.as_ref(ctx);
 478            for selection in &mut self.selections {
 479                let head = selection.head().to_display_point(map, ctx.app()).unwrap();
 480                let cursor = map
 481                    .anchor_before(
 482                        movement::left(map, head, ctx.app()).unwrap(),
 483                        Bias::Left,
 484                        ctx.app(),
 485                    )
 486                    .unwrap();
 487                selection.set_head(&buffer, cursor);
 488                selection.goal_column = None;
 489            }
 490        }
 491        self.changed_selections(ctx);
 492    }
 493
 494    pub fn move_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 495        {
 496            let app = ctx.app();
 497            let map = self.display_map.as_ref(app);
 498            for selection in &mut self.selections {
 499                let start = selection.start.to_display_point(map, app).unwrap();
 500                let end = selection.end.to_display_point(map, app).unwrap();
 501
 502                if start != end {
 503                    selection.start = selection.end.clone();
 504                } else {
 505                    let cursor = map
 506                        .anchor_before(movement::right(map, end, app).unwrap(), Bias::Right, app)
 507                        .unwrap();
 508                    selection.start = cursor.clone();
 509                    selection.end = cursor;
 510                }
 511                selection.reversed = false;
 512                selection.goal_column = None;
 513            }
 514        }
 515        self.changed_selections(ctx);
 516    }
 517
 518    pub fn select_right(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 519        {
 520            let buffer = self.buffer.as_ref(ctx);
 521            let app = ctx.app();
 522            let map = self.display_map.as_ref(app);
 523            for selection in &mut self.selections {
 524                let head = selection.head().to_display_point(map, ctx.app()).unwrap();
 525                let cursor = map
 526                    .anchor_before(movement::right(map, head, app).unwrap(), Bias::Right, app)
 527                    .unwrap();
 528                selection.set_head(&buffer, cursor);
 529                selection.goal_column = None;
 530            }
 531        }
 532        self.changed_selections(ctx);
 533    }
 534
 535    pub fn move_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 536        if self.single_line {
 537            ctx.propagate_action();
 538        } else {
 539            let app = ctx.app();
 540            let map = self.display_map.as_ref(app);
 541            for selection in &mut self.selections {
 542                let start = selection.start.to_display_point(map, app).unwrap();
 543                let end = selection.end.to_display_point(map, app).unwrap();
 544                if start != end {
 545                    selection.goal_column = None;
 546                }
 547
 548                let (start, goal_column) =
 549                    movement::up(map, start, selection.goal_column, app).unwrap();
 550                let cursor = map.anchor_before(start, Bias::Left, app).unwrap();
 551                selection.start = cursor.clone();
 552                selection.end = cursor;
 553                selection.goal_column = goal_column;
 554                selection.reversed = false;
 555            }
 556            self.changed_selections(ctx);
 557        }
 558    }
 559
 560    pub fn select_up(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 561        if self.single_line {
 562            ctx.propagate_action();
 563        } else {
 564            let app = ctx.app();
 565            let buffer = self.buffer.as_ref(app);
 566            let map = self.display_map.as_ref(app);
 567            for selection in &mut self.selections {
 568                let head = selection.head().to_display_point(map, app).unwrap();
 569                let (head, goal_column) =
 570                    movement::up(map, head, selection.goal_column, app).unwrap();
 571                selection.set_head(&buffer, map.anchor_before(head, Bias::Left, app).unwrap());
 572                selection.goal_column = goal_column;
 573            }
 574            self.changed_selections(ctx);
 575        }
 576    }
 577
 578    pub fn move_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 579        if self.single_line {
 580            ctx.propagate_action();
 581        } else {
 582            let app = ctx.app();
 583            let map = self.display_map.as_ref(app);
 584            for selection in &mut self.selections {
 585                let start = selection.start.to_display_point(map, app).unwrap();
 586                let end = selection.end.to_display_point(map, app).unwrap();
 587                if start != end {
 588                    selection.goal_column = None;
 589                }
 590
 591                let (start, goal_column) =
 592                    movement::down(map, end, selection.goal_column, app).unwrap();
 593                let cursor = map.anchor_before(start, Bias::Right, app).unwrap();
 594                selection.start = cursor.clone();
 595                selection.end = cursor;
 596                selection.goal_column = goal_column;
 597                selection.reversed = false;
 598            }
 599            self.changed_selections(ctx);
 600        }
 601    }
 602
 603    pub fn select_down(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 604        if self.single_line {
 605            ctx.propagate_action();
 606        } else {
 607            let app = ctx.app();
 608            let buffer = self.buffer.as_ref(ctx);
 609            let map = self.display_map.as_ref(ctx);
 610            for selection in &mut self.selections {
 611                let head = selection.head().to_display_point(map, app).unwrap();
 612                let (head, goal_column) =
 613                    movement::down(map, head, selection.goal_column, app).unwrap();
 614                selection.set_head(&buffer, map.anchor_before(head, Bias::Right, app).unwrap());
 615                selection.goal_column = goal_column;
 616            }
 617            self.changed_selections(ctx);
 618        }
 619    }
 620
 621    pub fn changed_selections(&mut self, ctx: &mut ViewContext<Self>) {
 622        self.merge_selections(ctx.app());
 623        self.pause_cursor_blinking(ctx);
 624        *self.autoscroll_requested.lock() = true;
 625        ctx.notify();
 626    }
 627
 628    fn merge_selections(&mut self, ctx: &AppContext) {
 629        let buffer = self.buffer.as_ref(ctx);
 630        let mut i = 1;
 631        while i < self.selections.len() {
 632            if self.selections[i - 1]
 633                .end
 634                .cmp(&self.selections[i].start, buffer)
 635                .unwrap()
 636                >= Ordering::Equal
 637            {
 638                let removed = self.selections.remove(i);
 639                if removed
 640                    .start
 641                    .cmp(&self.selections[i - 1].start, buffer)
 642                    .unwrap()
 643                    < Ordering::Equal
 644                {
 645                    self.selections[i - 1].start = removed.start;
 646                }
 647                if removed
 648                    .end
 649                    .cmp(&self.selections[i - 1].end, buffer)
 650                    .unwrap()
 651                    > Ordering::Equal
 652                {
 653                    self.selections[i - 1].end = removed.end;
 654                }
 655            } else {
 656                i += 1;
 657            }
 658        }
 659    }
 660
 661    pub fn first_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
 662        self.selections
 663            .first()
 664            .unwrap()
 665            .display_range(self.display_map.as_ref(app), app)
 666    }
 667
 668    pub fn last_selection(&self, app: &AppContext) -> Range<DisplayPoint> {
 669        self.selections
 670            .last()
 671            .unwrap()
 672            .display_range(self.display_map.as_ref(app), app)
 673    }
 674
 675    pub fn selections_in_range<'a>(
 676        &'a self,
 677        range: Range<DisplayPoint>,
 678        app: &'a AppContext,
 679    ) -> impl 'a + Iterator<Item = Range<DisplayPoint>> {
 680        let map = self.display_map.as_ref(app);
 681
 682        let start = map.anchor_before(range.start, Bias::Left, app).unwrap();
 683        let start_index = self.selection_insertion_index(&start, app);
 684        let pending_selection = self.pending_selection.as_ref().and_then(|s| {
 685            let selection_range = s.display_range(map, app);
 686            if selection_range.start <= range.end || selection_range.end <= range.end {
 687                Some(selection_range)
 688            } else {
 689                None
 690            }
 691        });
 692        self.selections[start_index..]
 693            .iter()
 694            .map(move |s| s.display_range(map, app))
 695            .take_while(move |r| r.start <= range.end || r.end <= range.end)
 696            .chain(pending_selection)
 697    }
 698
 699    fn selection_insertion_index(&self, start: &Anchor, app: &AppContext) -> usize {
 700        let buffer = self.buffer.as_ref(app);
 701
 702        match self
 703            .selections
 704            .binary_search_by(|probe| probe.start.cmp(&start, buffer).unwrap())
 705        {
 706            Ok(index) => index,
 707            Err(index) => {
 708                if index > 0
 709                    && self.selections[index - 1].end.cmp(&start, buffer).unwrap()
 710                        == Ordering::Greater
 711                {
 712                    index - 1
 713                } else {
 714                    index
 715                }
 716            }
 717        }
 718    }
 719
 720    pub fn page_up(&mut self, _: &(), _: &mut ViewContext<Self>) {
 721        log::info!("BufferView::page_up");
 722    }
 723
 724    pub fn page_down(&mut self, _: &(), _: &mut ViewContext<Self>) {
 725        log::info!("BufferView::page_down");
 726    }
 727
 728    pub fn fold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 729        use super::RangeExt;
 730
 731        let mut fold_ranges = Vec::new();
 732
 733        let app = ctx.app();
 734        let map = self.display_map.as_ref(app);
 735        for selection in &self.selections {
 736            let (start, end) = selection.display_range(map, app).sorted();
 737            let buffer_start_row = start.to_buffer_point(map, Bias::Left, app).unwrap().row;
 738
 739            for row in (0..=end.row()).rev() {
 740                if self.is_line_foldable(row, app) && !map.is_line_folded(row) {
 741                    let fold_range = self.foldable_range_for_line(row, app).unwrap();
 742                    if fold_range.end.row >= buffer_start_row {
 743                        fold_ranges.push(fold_range);
 744                        if row <= start.row() {
 745                            break;
 746                        }
 747                    }
 748                }
 749            }
 750        }
 751
 752        if !fold_ranges.is_empty() {
 753            self.display_map.update(ctx, |map, ctx| {
 754                map.fold(fold_ranges, ctx).unwrap();
 755            });
 756            *self.autoscroll_requested.lock() = true;
 757        }
 758    }
 759
 760    pub fn unfold(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 761        use super::RangeExt;
 762
 763        let app = ctx.app();
 764        let map = self.display_map.as_ref(app);
 765        let buffer = self.buffer.as_ref(app);
 766        let ranges = self
 767            .selections
 768            .iter()
 769            .map(|s| {
 770                let (start, end) = s.display_range(map, app).sorted();
 771                let mut start = start.to_buffer_point(map, Bias::Left, app).unwrap();
 772                let mut end = end.to_buffer_point(map, Bias::Left, app).unwrap();
 773                start.column = 0;
 774                end.column = buffer.line_len(end.row).unwrap();
 775                start..end
 776            })
 777            .collect::<Vec<_>>();
 778
 779        self.display_map.update(ctx, |map, ctx| {
 780            map.unfold(ranges, ctx).unwrap();
 781        });
 782        *self.autoscroll_requested.lock() = true;
 783    }
 784
 785    fn is_line_foldable(&self, display_row: u32, app: &AppContext) -> bool {
 786        let max_point = self.max_point(app);
 787        if display_row >= max_point.row() {
 788            false
 789        } else {
 790            let (start_indent, is_blank) = self.line_indent(display_row, app).unwrap();
 791            if is_blank {
 792                false
 793            } else {
 794                for display_row in display_row + 1..=max_point.row() {
 795                    let (indent, is_blank) = self.line_indent(display_row, app).unwrap();
 796                    if !is_blank {
 797                        return indent > start_indent;
 798                    }
 799                }
 800                false
 801            }
 802        }
 803    }
 804
 805    fn line_indent(&self, display_row: u32, app: &AppContext) -> Result<(usize, bool)> {
 806        let mut indent = 0;
 807        let mut is_blank = true;
 808        for c in self
 809            .display_map
 810            .as_ref(app)
 811            .chars_at(DisplayPoint::new(display_row, 0), app)?
 812        {
 813            if c == ' ' {
 814                indent += 1;
 815            } else {
 816                is_blank = c == '\n';
 817                break;
 818            }
 819        }
 820        Ok((indent, is_blank))
 821    }
 822
 823    fn foldable_range_for_line(&self, start_row: u32, app: &AppContext) -> Result<Range<Point>> {
 824        let map = self.display_map.as_ref(app);
 825        let max_point = self.max_point(app);
 826
 827        let (start_indent, _) = self.line_indent(start_row, app)?;
 828        let start = DisplayPoint::new(start_row, self.line_len(start_row, app)?);
 829        let mut end = None;
 830        for row in start_row + 1..=max_point.row() {
 831            let (indent, is_blank) = self.line_indent(row, app)?;
 832            if !is_blank && indent <= start_indent {
 833                end = Some(DisplayPoint::new(row - 1, self.line_len(row - 1, app)?));
 834                break;
 835            }
 836        }
 837
 838        let end = end.unwrap_or(max_point);
 839        return Ok(start.to_buffer_point(map, Bias::Left, app)?
 840            ..end.to_buffer_point(map, Bias::Left, app)?);
 841    }
 842
 843    pub fn fold_selected_ranges(&mut self, _: &(), ctx: &mut ViewContext<Self>) {
 844        self.display_map.update(ctx, |map, ctx| {
 845            let buffer = self.buffer.as_ref(ctx);
 846            let ranges = self
 847                .selections
 848                .iter()
 849                .map(|s| s.range(buffer))
 850                .collect::<Vec<_>>();
 851            map.fold(ranges, ctx).unwrap();
 852        });
 853    }
 854
 855    pub fn line(&self, display_row: u32, app: &AppContext) -> Result<String> {
 856        self.display_map.as_ref(app).line(display_row, app)
 857    }
 858
 859    pub fn line_len(&self, display_row: u32, app: &AppContext) -> Result<u32> {
 860        self.display_map.as_ref(app).line_len(display_row, app)
 861    }
 862
 863    pub fn rightmost_point(&self, app: &AppContext) -> DisplayPoint {
 864        self.display_map.as_ref(app).rightmost_point()
 865    }
 866
 867    pub fn max_point(&self, app: &AppContext) -> DisplayPoint {
 868        self.display_map.as_ref(app).max_point(app)
 869    }
 870
 871    pub fn text(&self, app: &AppContext) -> String {
 872        self.display_map.as_ref(app).text(app)
 873    }
 874
 875    pub fn font_size(&self) -> f32 {
 876        smol::block_on(self.settings.read()).buffer_font_size
 877    }
 878
 879    pub fn font_ascent(&self, font_cache: &FontCache) -> f32 {
 880        let settings = smol::block_on(self.settings.read());
 881        let font_id = font_cache.default_font(settings.buffer_font_family);
 882        let ascent = font_cache.metric(font_id, |m| m.ascent);
 883        font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
 884    }
 885
 886    pub fn font_descent(&self, font_cache: &FontCache) -> f32 {
 887        let settings = smol::block_on(self.settings.read());
 888        let font_id = font_cache.default_font(settings.buffer_font_family);
 889        let ascent = font_cache.metric(font_id, |m| m.descent);
 890        font_cache.scale_metric(ascent, font_id, settings.buffer_font_size)
 891    }
 892
 893    pub fn line_height(&self, font_cache: &FontCache) -> f32 {
 894        let settings = smol::block_on(self.settings.read());
 895        let font_id = font_cache.default_font(settings.buffer_font_family);
 896        font_cache
 897            .bounding_box(font_id, settings.buffer_font_size)
 898            .y()
 899    }
 900
 901    pub fn em_width(&self, font_cache: &FontCache) -> f32 {
 902        let settings = smol::block_on(self.settings.read());
 903        let font_id = font_cache.default_font(settings.buffer_font_family);
 904        font_cache.em_width(font_id, settings.buffer_font_size)
 905    }
 906
 907    // TODO: Can we make this not return a result?
 908    pub fn max_line_number_width(
 909        &self,
 910        font_cache: &FontCache,
 911        layout_cache: &TextLayoutCache,
 912        app: &AppContext,
 913    ) -> Result<f32> {
 914        let settings = smol::block_on(self.settings.read());
 915        let font_size = settings.buffer_font_size;
 916        let font_id =
 917            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
 918        let digit_count = ((self.buffer.as_ref(app).max_point().row + 1) as f32)
 919            .log10()
 920            .floor() as usize
 921            + 1;
 922
 923        Ok(layout_cache
 924            .layout_str(
 925                "1".repeat(digit_count).as_str(),
 926                font_size,
 927                &[(0..digit_count, font_id)],
 928            )
 929            .width)
 930    }
 931
 932    pub fn layout_line_numbers(
 933        &self,
 934        viewport_height: f32,
 935        font_cache: &FontCache,
 936        layout_cache: &TextLayoutCache,
 937        app: &AppContext,
 938    ) -> Result<Vec<Arc<text_layout::Line>>> {
 939        let display_map = self.display_map.as_ref(app);
 940
 941        let settings = smol::block_on(self.settings.read());
 942        let font_size = settings.buffer_font_size;
 943        let font_id =
 944            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
 945
 946        let start_row = self.scroll_position().y() as usize;
 947        let end_row = cmp::min(
 948            self.max_point(app).row() as usize,
 949            start_row + (viewport_height / self.line_height(font_cache)).ceil() as usize,
 950        );
 951        let line_count = end_row - start_row + 1;
 952
 953        let mut layouts = Vec::with_capacity(line_count);
 954        let mut line_number = String::new();
 955        for buffer_row in display_map.buffer_rows(start_row as u32)?.take(line_count) {
 956            line_number.clear();
 957            write!(&mut line_number, "{}", buffer_row + 1).unwrap();
 958            layouts.push(layout_cache.layout_str(
 959                &line_number,
 960                font_size,
 961                &[(0..line_number.len(), font_id)],
 962            ));
 963        }
 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 mut layouts = Vec::with_capacity(rows.len());
 988        let mut line = String::new();
 989        let mut line_len = 0;
 990        let mut row = rows.start;
 991        let chars = display_map
 992            .chars_at(DisplayPoint::new(rows.start, 0), app)
 993            .unwrap();
 994        for char in chars.chain(Some('\n')) {
 995            if char == '\n' {
 996                layouts.push(layout_cache.layout_str(&line, font_size, &[(0..line_len, font_id)]));
 997                line.clear();
 998                line_len = 0;
 999                row += 1;
1000                if row == rows.end {
1001                    break;
1002                }
1003            } else {
1004                line_len += 1;
1005                line.push(char);
1006            }
1007        }
1008
1009        Ok(layouts)
1010    }
1011
1012    pub fn layout_line(
1013        &self,
1014        row: u32,
1015        font_cache: &FontCache,
1016        layout_cache: &TextLayoutCache,
1017        app: &AppContext,
1018    ) -> Result<Arc<text_layout::Line>> {
1019        let settings = smol::block_on(self.settings.read());
1020        let font_id =
1021            font_cache.select_font(settings.buffer_font_family, &FontProperties::new())?;
1022
1023        let line = self.line(row, app)?;
1024
1025        Ok(layout_cache.layout_str(
1026            &line,
1027            settings.buffer_font_size,
1028            &[(0..self.line_len(row, app)? as usize, font_id)],
1029        ))
1030    }
1031
1032    fn next_blink_epoch(&mut self) -> usize {
1033        self.blink_epoch += 1;
1034        self.blink_epoch
1035    }
1036
1037    fn pause_cursor_blinking(&mut self, ctx: &mut ViewContext<Self>) {
1038        self.cursors_visible = true;
1039        ctx.notify();
1040
1041        let epoch = self.next_blink_epoch();
1042        ctx.spawn(
1043            async move {
1044                Timer::after(CURSOR_BLINK_INTERVAL).await;
1045                epoch
1046            },
1047            Self::resume_cursor_blinking,
1048        )
1049        .detach();
1050    }
1051
1052    fn resume_cursor_blinking(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1053        if epoch == self.blink_epoch {
1054            self.blinking_paused = false;
1055            self.blink_cursors(epoch, ctx);
1056        }
1057    }
1058
1059    fn blink_cursors(&mut self, epoch: usize, ctx: &mut ViewContext<Self>) {
1060        if epoch == self.blink_epoch && self.focused && !self.blinking_paused {
1061            self.cursors_visible = !self.cursors_visible;
1062            ctx.notify();
1063
1064            let epoch = self.next_blink_epoch();
1065            ctx.spawn(
1066                async move {
1067                    Timer::after(CURSOR_BLINK_INTERVAL).await;
1068                    epoch
1069                },
1070                Self::blink_cursors,
1071            )
1072            .detach();
1073        }
1074    }
1075
1076    pub fn cursors_visible(&self) -> bool {
1077        self.cursors_visible
1078    }
1079
1080    fn on_buffer_changed(&mut self, _: ModelHandle<Buffer>, ctx: &mut ViewContext<Self>) {
1081        ctx.notify();
1082    }
1083
1084    fn on_display_map_changed(&mut self, _: ModelHandle<DisplayMap>, ctx: &mut ViewContext<Self>) {
1085        ctx.notify();
1086    }
1087
1088    fn on_buffer_event(
1089        &mut self,
1090        _: ModelHandle<Buffer>,
1091        event: &buffer::Event,
1092        ctx: &mut ViewContext<Self>,
1093    ) {
1094        match event {
1095            buffer::Event::Edited(_) => ctx.emit(Event::Edited),
1096        }
1097    }
1098}
1099
1100struct Selection {
1101    start: Anchor,
1102    end: Anchor,
1103    reversed: bool,
1104    goal_column: Option<u32>,
1105}
1106
1107pub enum Event {
1108    Activate,
1109    Edited,
1110    Blurred,
1111}
1112
1113impl Entity for BufferView {
1114    type Event = Event;
1115}
1116
1117impl View for BufferView {
1118    fn render<'a>(&self, app: &AppContext) -> ElementBox {
1119        BufferElement::new(self.handle.upgrade(app).unwrap()).boxed()
1120    }
1121
1122    fn ui_name() -> &'static str {
1123        "BufferView"
1124    }
1125
1126    fn on_focus(&mut self, ctx: &mut ViewContext<Self>) {
1127        self.focused = true;
1128        self.blink_cursors(self.blink_epoch, ctx);
1129    }
1130
1131    fn on_blur(&mut self, ctx: &mut ViewContext<Self>) {
1132        self.focused = false;
1133        self.cursors_visible = false;
1134        ctx.emit(Event::Blurred);
1135        ctx.notify();
1136    }
1137}
1138
1139impl workspace::Item for Buffer {
1140    type View = BufferView;
1141
1142    fn build_view(
1143        buffer: ModelHandle<Self>,
1144        settings: watch::Receiver<Settings>,
1145        ctx: &mut ViewContext<Self::View>,
1146    ) -> Self::View {
1147        BufferView::for_buffer(buffer, settings, ctx)
1148    }
1149}
1150
1151impl workspace::ItemView for BufferView {
1152    fn is_activate_event(event: &Self::Event) -> bool {
1153        match event {
1154            Event::Activate => true,
1155            _ => false,
1156        }
1157    }
1158
1159    fn title(&self, app: &AppContext) -> std::string::String {
1160        if let Some(path) = self.buffer.as_ref(app).path(app) {
1161            path.file_name()
1162                .expect("buffer's path is always to a file")
1163                .to_string_lossy()
1164                .into()
1165        } else {
1166            "untitled".into()
1167        }
1168    }
1169
1170    fn entry_id(&self, app: &AppContext) -> Option<(usize, usize)> {
1171        self.buffer.as_ref(app).entry_id()
1172    }
1173
1174    fn clone_on_split(&self, ctx: &mut ViewContext<Self>) -> Option<Self>
1175    where
1176        Self: Sized,
1177    {
1178        let clone = BufferView::for_buffer(self.buffer.clone(), self.settings.clone(), ctx);
1179        *clone.scroll_position.lock() = *self.scroll_position.lock();
1180        Some(clone)
1181    }
1182
1183    fn save(&self, ctx: &mut MutableAppContext) -> Option<BackgroundTask<Result<()>>> {
1184        self.buffer.update(ctx, |buffer, ctx| buffer.save(ctx))
1185    }
1186}
1187
1188impl Selection {
1189    fn head(&self) -> &Anchor {
1190        if self.reversed {
1191            &self.start
1192        } else {
1193            &self.end
1194        }
1195    }
1196
1197    fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
1198        if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
1199            if !self.reversed {
1200                mem::swap(&mut self.start, &mut self.end);
1201                self.reversed = true;
1202            }
1203            self.start = cursor;
1204        } else {
1205            if self.reversed {
1206                mem::swap(&mut self.start, &mut self.end);
1207                self.reversed = false;
1208            }
1209            self.end = cursor;
1210        }
1211    }
1212
1213    fn tail(&self) -> &Anchor {
1214        if self.reversed {
1215            &self.end
1216        } else {
1217            &self.start
1218        }
1219    }
1220
1221    fn range(&self, buffer: &Buffer) -> Range<Point> {
1222        let start = self.start.to_point(buffer).unwrap();
1223        let end = self.end.to_point(buffer).unwrap();
1224        if self.reversed {
1225            end..start
1226        } else {
1227            start..end
1228        }
1229    }
1230
1231    fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range<DisplayPoint> {
1232        let start = self.start.to_display_point(map, app).unwrap();
1233        let end = self.end.to_display_point(map, app).unwrap();
1234        if self.reversed {
1235            end..start
1236        } else {
1237            start..end
1238        }
1239    }
1240}
1241
1242#[cfg(test)]
1243mod tests {
1244    use super::*;
1245    use crate::{editor::Point, settings, test::sample_text};
1246    use anyhow::Error;
1247    use unindent::Unindent;
1248
1249    #[test]
1250    fn test_selection_with_mouse() {
1251        App::test((), |mut app| async move {
1252            let buffer = app.add_model(|_| Buffer::new(0, "aaaaaa\nbbbbbb\ncccccc\ndddddd\n"));
1253            let settings = settings::channel(&app.font_cache()).unwrap().1;
1254            let (_, buffer_view) =
1255                app.add_window(|ctx| BufferView::for_buffer(buffer, settings, ctx));
1256
1257            buffer_view.update(&mut app, |view, ctx| {
1258                view.begin_selection(DisplayPoint::new(2, 2), false, ctx);
1259            });
1260
1261            buffer_view.read(&app, |view, app| {
1262                let selections = view
1263                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1264                    .collect::<Vec<_>>();
1265                assert_eq!(
1266                    selections,
1267                    [DisplayPoint::new(2, 2)..DisplayPoint::new(2, 2)]
1268                );
1269            });
1270
1271            buffer_view.update(&mut app, |view, ctx| {
1272                view.update_selection(DisplayPoint::new(3, 3), Vector2F::zero(), ctx);
1273            });
1274
1275            buffer_view.read(&app, |view, app| {
1276                let selections = view
1277                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1278                    .collect::<Vec<_>>();
1279                assert_eq!(
1280                    selections,
1281                    [DisplayPoint::new(2, 2)..DisplayPoint::new(3, 3)]
1282                );
1283            });
1284
1285            buffer_view.update(&mut app, |view, ctx| {
1286                view.update_selection(DisplayPoint::new(1, 1), Vector2F::zero(), ctx);
1287            });
1288
1289            buffer_view.read(&app, |view, app| {
1290                let selections = view
1291                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1292                    .collect::<Vec<_>>();
1293                assert_eq!(
1294                    selections,
1295                    [DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1)]
1296                );
1297            });
1298
1299            buffer_view.update(&mut app, |view, ctx| {
1300                view.end_selection(ctx);
1301                view.update_selection(DisplayPoint::new(3, 3), 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.begin_selection(DisplayPoint::new(3, 3), true, ctx);
1316                view.update_selection(DisplayPoint::new(0, 0), 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                    [
1326                        DisplayPoint::new(2, 2)..DisplayPoint::new(1, 1),
1327                        DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)
1328                    ]
1329                );
1330            });
1331
1332            buffer_view.update(&mut app, |view, ctx| {
1333                view.end_selection(ctx);
1334            });
1335
1336            buffer_view.read(&app, |view, app| {
1337                let selections = view
1338                    .selections_in_range(DisplayPoint::zero()..view.max_point(app), app)
1339                    .collect::<Vec<_>>();
1340                assert_eq!(
1341                    selections,
1342                    [DisplayPoint::new(3, 3)..DisplayPoint::new(0, 0)]
1343                );
1344            });
1345        });
1346    }
1347
1348    #[test]
1349    fn test_layout_line_numbers() -> Result<()> {
1350        App::test((), |mut app| async move {
1351            let layout_cache = TextLayoutCache::new(app.platform().fonts());
1352            let font_cache = app.font_cache();
1353
1354            let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
1355
1356            let settings = settings::channel(&font_cache).unwrap().1;
1357            let (_, view) =
1358                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1359
1360            view.read(&app, |view, app| {
1361                let layouts = view.layout_line_numbers(1000.0, &font_cache, &layout_cache, app)?;
1362                assert_eq!(layouts.len(), 6);
1363                Result::<()>::Ok(())
1364            })?;
1365
1366            Ok(())
1367        })
1368    }
1369
1370    #[test]
1371    fn test_fold() -> Result<()> {
1372        App::test((), |mut app| async move {
1373            let buffer = app.add_model(|_| {
1374                Buffer::new(
1375                    0,
1376                    "
1377                    impl Foo {
1378                        // Hello!
1379
1380                        fn a() {
1381                            1
1382                        }
1383
1384                        fn b() {
1385                            2
1386                        }
1387
1388                        fn c() {
1389                            3
1390                        }
1391                    }
1392                "
1393                    .unindent(),
1394                )
1395            });
1396            let settings = settings::channel(&app.font_cache()).unwrap().1;
1397            let (_, view) =
1398                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1399
1400            view.update(&mut app, |view, ctx| {
1401                view.select_ranges(&[DisplayPoint::new(8, 0)..DisplayPoint::new(12, 0)], ctx)?;
1402                view.fold(&(), ctx);
1403                assert_eq!(
1404                    view.text(ctx.app()),
1405                    "
1406                    impl Foo {
1407                        // Hello!
1408
1409                        fn a() {
1410                            1
1411                        }
1412
1413                        fn b() {…
1414                        }
1415
1416                        fn c() {…
1417                        }
1418                    }
1419                "
1420                    .unindent(),
1421                );
1422
1423                view.fold(&(), ctx);
1424                assert_eq!(
1425                    view.text(ctx.app()),
1426                    "
1427                    impl Foo {…
1428                    }
1429                "
1430                    .unindent(),
1431                );
1432
1433                view.unfold(&(), ctx);
1434                assert_eq!(
1435                    view.text(ctx.app()),
1436                    "
1437                    impl Foo {
1438                        // Hello!
1439
1440                        fn a() {
1441                            1
1442                        }
1443
1444                        fn b() {…
1445                        }
1446
1447                        fn c() {…
1448                        }
1449                    }
1450                "
1451                    .unindent(),
1452                );
1453
1454                view.unfold(&(), ctx);
1455                assert_eq!(view.text(ctx.app()), buffer.as_ref(ctx).text());
1456
1457                Ok::<(), Error>(())
1458            })?;
1459
1460            Ok(())
1461        })
1462    }
1463
1464    #[test]
1465    fn test_move_cursor() -> Result<()> {
1466        App::test((), |mut app| async move {
1467            let buffer = app.add_model(|_| Buffer::new(0, sample_text(6, 6)));
1468            let settings = settings::channel(&app.font_cache()).unwrap().1;
1469            let (_, view) =
1470                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1471
1472            buffer.update(&mut app, |buffer, ctx| {
1473                buffer.edit(
1474                    vec![
1475                        Point::new(1, 0)..Point::new(1, 0),
1476                        Point::new(1, 1)..Point::new(1, 1),
1477                    ],
1478                    "\t",
1479                    Some(ctx),
1480                )
1481            })?;
1482
1483            view.update(&mut app, |view, ctx| {
1484                view.move_down(&(), ctx);
1485                assert_eq!(
1486                    view.selections(ctx.app()),
1487                    &[DisplayPoint::new(1, 0)..DisplayPoint::new(1, 0)]
1488                );
1489                view.move_right(&(), ctx);
1490                assert_eq!(
1491                    view.selections(ctx.app()),
1492                    &[DisplayPoint::new(1, 4)..DisplayPoint::new(1, 4)]
1493                );
1494                Ok::<(), Error>(())
1495            })?;
1496
1497            Ok(())
1498        })
1499    }
1500
1501    #[test]
1502    fn test_backspace() -> Result<()> {
1503        App::test((), |mut app| async move {
1504            let buffer = app.add_model(|_| {
1505                Buffer::new(0, "one two three\nfour five six\nseven eight nine\nten\n")
1506            });
1507            let settings = settings::channel(&app.font_cache()).unwrap().1;
1508            let (_, view) =
1509                app.add_window(|ctx| BufferView::for_buffer(buffer.clone(), settings, ctx));
1510
1511            view.update(&mut app, |view, ctx| -> Result<()> {
1512                view.select_ranges(
1513                    &[
1514                        // an empty selection - the preceding character is deleted
1515                        DisplayPoint::new(0, 2)..DisplayPoint::new(0, 2),
1516                        // one character selected - it is deleted
1517                        DisplayPoint::new(1, 3)..DisplayPoint::new(1, 4),
1518                        // a line suffix selected - it is deleted
1519                        DisplayPoint::new(2, 6)..DisplayPoint::new(3, 0),
1520                    ],
1521                    ctx,
1522                )?;
1523                view.backspace(&(), ctx);
1524                Ok(())
1525            })?;
1526
1527            buffer.read(&mut app, |buffer, _| -> Result<()> {
1528                assert_eq!(buffer.text(), "oe two three\nfou five six\nseven ten\n");
1529                Ok(())
1530            })?;
1531
1532            Ok(())
1533        })
1534    }
1535
1536    impl BufferView {
1537        fn selections(&self, app: &AppContext) -> Vec<Range<DisplayPoint>> {
1538            self.selections_in_range(DisplayPoint::zero()..self.max_point(app), app)
1539                .collect::<Vec<_>>()
1540        }
1541    }
1542}