selection.rs

  1use crate::{
  2    editor::{
  3        buffer::{Anchor, Buffer, Point, ToOffset as _, ToPoint as _},
  4        display_map::DisplayMap,
  5        Bias, DisplayPoint,
  6    },
  7    time,
  8};
  9use gpui::AppContext;
 10use std::{cmp::Ordering, mem, ops::Range};
 11
 12pub type SelectionSetId = time::Lamport;
 13pub type SelectionsVersion = usize;
 14
 15#[derive(Copy, Clone, Debug, Eq, PartialEq)]
 16pub enum SelectionGoal {
 17    None,
 18    Column(u32),
 19    ColumnRange { start: u32, end: u32 },
 20}
 21
 22#[derive(Clone, Debug, Eq, PartialEq)]
 23pub struct Selection {
 24    pub id: usize,
 25    pub start: Anchor,
 26    pub end: Anchor,
 27    pub reversed: bool,
 28    pub goal: SelectionGoal,
 29}
 30
 31impl Selection {
 32    pub fn head(&self) -> &Anchor {
 33        if self.reversed {
 34            &self.start
 35        } else {
 36            &self.end
 37        }
 38    }
 39
 40    pub fn set_head(&mut self, buffer: &Buffer, cursor: Anchor) {
 41        if cursor.cmp(self.tail(), buffer).unwrap() < Ordering::Equal {
 42            if !self.reversed {
 43                mem::swap(&mut self.start, &mut self.end);
 44                self.reversed = true;
 45            }
 46            self.start = cursor;
 47        } else {
 48            if self.reversed {
 49                mem::swap(&mut self.start, &mut self.end);
 50                self.reversed = false;
 51            }
 52            self.end = cursor;
 53        }
 54    }
 55
 56    pub fn tail(&self) -> &Anchor {
 57        if self.reversed {
 58            &self.end
 59        } else {
 60            &self.start
 61        }
 62    }
 63
 64    pub fn point_range(&self, buffer: &Buffer) -> Range<Point> {
 65        let start = self.start.to_point(buffer);
 66        let end = self.end.to_point(buffer);
 67        if self.reversed {
 68            end..start
 69        } else {
 70            start..end
 71        }
 72    }
 73
 74    pub fn offset_range(&self, buffer: &Buffer) -> Range<usize> {
 75        let start = self.start.to_offset(buffer);
 76        let end = self.end.to_offset(buffer);
 77        if self.reversed {
 78            end..start
 79        } else {
 80            start..end
 81        }
 82    }
 83
 84    pub fn display_range(&self, map: &DisplayMap, app: &AppContext) -> Range<DisplayPoint> {
 85        let start = self.start.to_display_point(map, app);
 86        let end = self.end.to_display_point(map, app);
 87        if self.reversed {
 88            end..start
 89        } else {
 90            start..end
 91        }
 92    }
 93
 94    pub fn buffer_rows_for_display_rows(
 95        &self,
 96        include_end_if_at_line_start: bool,
 97        map: &DisplayMap,
 98        ctx: &AppContext,
 99    ) -> (Range<u32>, Range<u32>) {
100        let display_start = self.start.to_display_point(map, ctx);
101        let buffer_start =
102            DisplayPoint::new(display_start.row(), 0).to_buffer_point(map, Bias::Left, ctx);
103
104        let mut display_end = self.end.to_display_point(map, ctx);
105        if !include_end_if_at_line_start
106            && display_end.row() != map.max_point(ctx).row()
107            && display_start.row() != display_end.row()
108            && display_end.column() == 0
109        {
110            *display_end.row_mut() -= 1;
111        }
112        let buffer_end = DisplayPoint::new(display_end.row(), map.line_len(display_end.row(), ctx))
113            .to_buffer_point(map, Bias::Left, ctx);
114
115        (
116            buffer_start.row..buffer_end.row + 1,
117            display_start.row()..display_end.row() + 1,
118        )
119    }
120}