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}