1 //! State management for a selection in the grid.
2 //!
3 //! A selection should start when the mouse is clicked, and it should be
4 //! finalized when the button is released. The selection should be cleared
5 //! when text is added/removed/scrolled on the screen. The selection should
6 //! also be cleared if the user clicks off of the selection.
7 
8 use std::cmp::min;
9 use std::mem;
10 use std::ops::{Bound, Range, RangeBounds};
11 
12 use crate::ansi::CursorShape;
13 use crate::grid::{Dimensions, GridCell, Indexed};
14 use crate::index::{Boundary, Column, Line, Point, Side};
15 use crate::term::cell::{Cell, Flags};
16 use crate::term::Term;
17 
18 /// A Point and side within that point.
19 #[derive(Debug, Copy, Clone, PartialEq)]
20 struct Anchor {
21     point: Point,
22     side: Side,
23 }
24 
25 impl Anchor {
new(point: Point, side: Side) -> Anchor26     fn new(point: Point, side: Side) -> Anchor {
27         Anchor { point, side }
28     }
29 }
30 
31 /// Represents a range of selected cells.
32 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
33 pub struct SelectionRange {
34     /// Start point, top left of the selection.
35     pub start: Point,
36     /// End point, bottom right of the selection.
37     pub end: Point,
38     /// Whether this selection is a block selection.
39     pub is_block: bool,
40 }
41 
42 impl SelectionRange {
new(start: Point, end: Point, is_block: bool) -> Self43     pub fn new(start: Point, end: Point, is_block: bool) -> Self {
44         Self { start, end, is_block }
45     }
46 }
47 
48 impl SelectionRange {
49     /// Check if a point lies within the selection.
contains(&self, point: Point) -> bool50     pub fn contains(&self, point: Point) -> bool {
51         self.start.line <= point.line
52             && self.end.line >= point.line
53             && (self.start.column <= point.column
54                 || (self.start.line != point.line && !self.is_block))
55             && (self.end.column >= point.column || (self.end.line != point.line && !self.is_block))
56     }
57 
58     /// Check if the cell at a point is part of the selection.
contains_cell( &self, indexed: &Indexed<&Cell>, point: Point, shape: CursorShape, ) -> bool59     pub fn contains_cell(
60         &self,
61         indexed: &Indexed<&Cell>,
62         point: Point,
63         shape: CursorShape,
64     ) -> bool {
65         // Do not invert block cursor at selection boundaries.
66         if shape == CursorShape::Block
67             && point == indexed.point
68             && (self.start == indexed.point
69                 || self.end == indexed.point
70                 || (self.is_block
71                     && ((self.start.line == indexed.point.line
72                         && self.end.column == indexed.point.column)
73                         || (self.end.line == indexed.point.line
74                             && self.start.column == indexed.point.column))))
75         {
76             return false;
77         }
78 
79         // Point itself is selected.
80         if self.contains(indexed.point) {
81             return true;
82         }
83 
84         // Check if a wide char's trailing spacer is selected.
85         indexed.cell.flags().contains(Flags::WIDE_CHAR)
86             && self.contains(Point::new(indexed.point.line, indexed.point.column + 1))
87     }
88 }
89 
90 /// Different kinds of selection.
91 #[derive(Debug, Copy, Clone, PartialEq)]
92 pub enum SelectionType {
93     Simple,
94     Block,
95     Semantic,
96     Lines,
97 }
98 
99 /// Describes a region of a 2-dimensional area.
100 ///
101 /// Used to track a text selection. There are four supported modes, each with its own constructor:
102 /// [`simple`], [`block`], [`semantic`], and [`lines`]. The [`simple`] mode precisely tracks which
103 /// cells are selected without any expansion. [`block`] will select rectangular regions.
104 /// [`semantic`] mode expands the initial selection to the nearest semantic escape char in either
105 /// direction. [`lines`] will always select entire lines.
106 ///
107 /// Calls to [`update`] operate different based on the selection kind. The [`simple`] and [`block`]
108 /// mode do nothing special, simply track points and sides. [`semantic`] will continue to expand
109 /// out to semantic boundaries as the selection point changes. Similarly, [`lines`] will always
110 /// expand the new point to encompass entire lines.
111 ///
112 /// [`simple`]: enum.Selection.html#method.simple
113 /// [`block`]: enum.Selection.html#method.block
114 /// [`semantic`]: enum.Selection.html#method.semantic
115 /// [`lines`]: enum.Selection.html#method.lines
116 /// [`update`]: enum.Selection.html#method.update
117 #[derive(Debug, Clone, PartialEq)]
118 pub struct Selection {
119     pub ty: SelectionType,
120     region: Range<Anchor>,
121 }
122 
123 impl Selection {
new(ty: SelectionType, location: Point, side: Side) -> Selection124     pub fn new(ty: SelectionType, location: Point, side: Side) -> Selection {
125         Self {
126             region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
127             ty,
128         }
129     }
130 
131     /// Update the end of the selection.
update(&mut self, point: Point, side: Side)132     pub fn update(&mut self, point: Point, side: Side) {
133         self.region.end = Anchor::new(point, side);
134     }
135 
rotate<D: Dimensions>( mut self, dimensions: &D, range: &Range<Line>, delta: i32, ) -> Option<Selection>136     pub fn rotate<D: Dimensions>(
137         mut self,
138         dimensions: &D,
139         range: &Range<Line>,
140         delta: i32,
141     ) -> Option<Selection> {
142         let bottommost_line = dimensions.bottommost_line();
143         let range_bottom = range.end;
144         let range_top = range.start;
145 
146         let (mut start, mut end) = (&mut self.region.start, &mut self.region.end);
147         if start.point > end.point {
148             mem::swap(&mut start, &mut end);
149         }
150 
151         // Rotate start of selection.
152         if (start.point.line >= range_top || range_top == 0) && start.point.line < range_bottom {
153             start.point.line = min(start.point.line - delta, bottommost_line);
154 
155             // If end is within the same region, delete selection once start rotates out.
156             if start.point.line >= range_bottom && end.point.line < range_bottom {
157                 return None;
158             }
159 
160             // Clamp selection to start of region.
161             if start.point.line < range_top && range_top != 0 {
162                 if self.ty != SelectionType::Block {
163                     start.point.column = Column(0);
164                     start.side = Side::Left;
165                 }
166                 start.point.line = range_top;
167             }
168         }
169 
170         // Rotate end of selection.
171         if (end.point.line >= range_top || range_top == 0) && end.point.line < range_bottom {
172             end.point.line = min(end.point.line - delta, bottommost_line);
173 
174             // Delete selection if end has overtaken the start.
175             if end.point.line < start.point.line {
176                 return None;
177             }
178 
179             // Clamp selection to end of region.
180             if end.point.line >= range_bottom {
181                 if self.ty != SelectionType::Block {
182                     end.point.column = dimensions.last_column();
183                     end.side = Side::Right;
184                 }
185                 end.point.line = range_bottom - 1;
186             }
187         }
188 
189         Some(self)
190     }
191 
is_empty(&self) -> bool192     pub fn is_empty(&self) -> bool {
193         match self.ty {
194             SelectionType::Simple => {
195                 let (mut start, mut end) = (self.region.start, self.region.end);
196                 if start.point > end.point {
197                     mem::swap(&mut start, &mut end);
198                 }
199 
200                 // Simple selection is empty when the points are identical
201                 // or two adjacent cells have the sides right -> left.
202                 start == end
203                     || (start.side == Side::Right
204                         && end.side == Side::Left
205                         && (start.point.line == end.point.line)
206                         && start.point.column + 1 == end.point.column)
207             },
208             SelectionType::Block => {
209                 let (start, end) = (self.region.start, self.region.end);
210 
211                 // Block selection is empty when the points' columns and sides are identical
212                 // or two cells with adjacent columns have the sides right -> left,
213                 // regardless of their lines
214                 (start.point.column == end.point.column && start.side == end.side)
215                     || (start.point.column + 1 == end.point.column
216                         && start.side == Side::Right
217                         && end.side == Side::Left)
218                     || (end.point.column + 1 == start.point.column
219                         && start.side == Side::Left
220                         && end.side == Side::Right)
221             },
222             SelectionType::Semantic | SelectionType::Lines => false,
223         }
224     }
225 
226     /// Check whether selection contains any point in a given range.
intersects_range<R: RangeBounds<Line>>(&self, range: R) -> bool227     pub fn intersects_range<R: RangeBounds<Line>>(&self, range: R) -> bool {
228         let mut start = self.region.start.point.line;
229         let mut end = self.region.end.point.line;
230 
231         if start > end {
232             mem::swap(&mut start, &mut end);
233         }
234 
235         let range_top = match range.start_bound() {
236             Bound::Included(&range_start) => range_start,
237             Bound::Excluded(&range_start) => range_start + 1,
238             Bound::Unbounded => Line(i32::min_value()),
239         };
240 
241         let range_bottom = match range.end_bound() {
242             Bound::Included(&range_end) => range_end,
243             Bound::Excluded(&range_end) => range_end - 1,
244             Bound::Unbounded => Line(i32::max_value()),
245         };
246 
247         range_bottom >= start && range_top <= end
248     }
249 
250     /// Expand selection sides to include all cells.
include_all(&mut self)251     pub fn include_all(&mut self) {
252         let (start, end) = (self.region.start.point, self.region.end.point);
253         let (start_side, end_side) = match self.ty {
254             SelectionType::Block
255                 if start.column > end.column
256                     || (start.column == end.column && start.line > end.line) =>
257             {
258                 (Side::Right, Side::Left)
259             },
260             SelectionType::Block => (Side::Left, Side::Right),
261             _ if start > end => (Side::Right, Side::Left),
262             _ => (Side::Left, Side::Right),
263         };
264 
265         self.region.start.side = start_side;
266         self.region.end.side = end_side;
267     }
268 
269     /// Convert selection to grid coordinates.
to_range<T>(&self, term: &Term<T>) -> Option<SelectionRange>270     pub fn to_range<T>(&self, term: &Term<T>) -> Option<SelectionRange> {
271         let grid = term.grid();
272         let columns = grid.columns();
273 
274         // Order start above the end.
275         let mut start = self.region.start;
276         let mut end = self.region.end;
277 
278         if start.point > end.point {
279             mem::swap(&mut start, &mut end);
280         }
281 
282         // Clamp selection to within grid boundaries.
283         if end.point.line < term.topmost_line() {
284             return None;
285         }
286         start.point = start.point.grid_clamp(term, Boundary::Grid);
287 
288         match self.ty {
289             SelectionType::Simple => self.range_simple(start, end, columns),
290             SelectionType::Block => self.range_block(start, end),
291             SelectionType::Semantic => Some(Self::range_semantic(term, start.point, end.point)),
292             SelectionType::Lines => Some(Self::range_lines(term, start.point, end.point)),
293         }
294     }
295 
range_semantic<T>(term: &Term<T>, mut start: Point, mut end: Point) -> SelectionRange296     fn range_semantic<T>(term: &Term<T>, mut start: Point, mut end: Point) -> SelectionRange {
297         if start == end {
298             if let Some(matching) = term.bracket_search(start) {
299                 if (matching.line == start.line && matching.column < start.column)
300                     || (matching.line > start.line)
301                 {
302                     start = matching;
303                 } else {
304                     end = matching;
305                 }
306 
307                 return SelectionRange { start, end, is_block: false };
308             }
309         }
310 
311         let start = term.semantic_search_left(start);
312         let end = term.semantic_search_right(end);
313 
314         SelectionRange { start, end, is_block: false }
315     }
316 
range_lines<T>(term: &Term<T>, start: Point, end: Point) -> SelectionRange317     fn range_lines<T>(term: &Term<T>, start: Point, end: Point) -> SelectionRange {
318         let start = term.line_search_left(start);
319         let end = term.line_search_right(end);
320 
321         SelectionRange { start, end, is_block: false }
322     }
323 
range_simple( &self, mut start: Anchor, mut end: Anchor, columns: usize, ) -> Option<SelectionRange>324     fn range_simple(
325         &self,
326         mut start: Anchor,
327         mut end: Anchor,
328         columns: usize,
329     ) -> Option<SelectionRange> {
330         if self.is_empty() {
331             return None;
332         }
333 
334         // Remove last cell if selection ends to the left of a cell.
335         if end.side == Side::Left && start.point != end.point {
336             // Special case when selection ends to left of first cell.
337             if end.point.column == 0 {
338                 end.point.column = Column(columns - 1);
339                 end.point.line -= 1;
340             } else {
341                 end.point.column -= 1;
342             }
343         }
344 
345         // Remove first cell if selection starts at the right of a cell.
346         if start.side == Side::Right && start.point != end.point {
347             start.point.column += 1;
348 
349             // Wrap to next line when selection starts to the right of last column.
350             if start.point.column == columns {
351                 start.point.column = Column(0);
352                 start.point.line += 1;
353             }
354         }
355 
356         Some(SelectionRange { start: start.point, end: end.point, is_block: false })
357     }
358 
range_block(&self, mut start: Anchor, mut end: Anchor) -> Option<SelectionRange>359     fn range_block(&self, mut start: Anchor, mut end: Anchor) -> Option<SelectionRange> {
360         if self.is_empty() {
361             return None;
362         }
363 
364         // Always go top-left -> bottom-right.
365         if start.point.column > end.point.column {
366             mem::swap(&mut start.side, &mut end.side);
367             mem::swap(&mut start.point.column, &mut end.point.column);
368         }
369 
370         // Remove last cell if selection ends to the left of a cell.
371         if end.side == Side::Left && start.point != end.point && end.point.column.0 > 0 {
372             end.point.column -= 1;
373         }
374 
375         // Remove first cell if selection starts at the right of a cell.
376         if start.side == Side::Right && start.point != end.point {
377             start.point.column += 1;
378         }
379 
380         Some(SelectionRange { start: start.point, end: end.point, is_block: true })
381     }
382 }
383 
384 /// Tests for selection.
385 ///
386 /// There are comments on all of the tests describing the selection. Pictograms
387 /// are used to avoid ambiguity. Grid cells are represented by a [  ]. Only
388 /// cells that are completely covered are counted in a selection. Ends are
389 /// represented by `B` and `E` for begin and end, respectively.  A selected cell
390 /// looks like [XX], [BX] (at the start), [XB] (at the end), [XE] (at the end),
391 /// and [EX] (at the start), or [BE] for a single cell. Partially selected cells
392 /// look like [ B] and [E ].
393 #[cfg(test)]
394 mod tests {
395     use super::*;
396 
397     use crate::config::MockConfig;
398     use crate::index::{Column, Point, Side};
399     use crate::term::{SizeInfo, Term};
400 
term(height: usize, width: usize) -> Term<()>401     fn term(height: usize, width: usize) -> Term<()> {
402         let size = SizeInfo::new(width as f32, height as f32, 1.0, 1.0, 0.0, 0.0, false);
403         Term::new(&MockConfig::default(), size, ())
404     }
405 
406     /// Test case of single cell selection.
407     ///
408     /// 1. [  ]
409     /// 2. [B ]
410     /// 3. [BE]
411     #[test]
single_cell_left_to_right()412     fn single_cell_left_to_right() {
413         let location = Point::new(Line(0), Column(0));
414         let mut selection = Selection::new(SelectionType::Simple, location, Side::Left);
415         selection.update(location, Side::Right);
416 
417         assert_eq!(selection.to_range(&term(1, 2)).unwrap(), SelectionRange {
418             start: location,
419             end: location,
420             is_block: false
421         });
422     }
423 
424     /// Test case of single cell selection.
425     ///
426     /// 1. [  ]
427     /// 2. [ B]
428     /// 3. [EB]
429     #[test]
single_cell_right_to_left()430     fn single_cell_right_to_left() {
431         let location = Point::new(Line(0), Column(0));
432         let mut selection = Selection::new(SelectionType::Simple, location, Side::Right);
433         selection.update(location, Side::Left);
434 
435         assert_eq!(selection.to_range(&term(1, 2)).unwrap(), SelectionRange {
436             start: location,
437             end: location,
438             is_block: false
439         });
440     }
441 
442     /// Test adjacent cell selection from left to right.
443     ///
444     /// 1. [  ][  ]
445     /// 2. [ B][  ]
446     /// 3. [ B][E ]
447     #[test]
between_adjacent_cells_left_to_right()448     fn between_adjacent_cells_left_to_right() {
449         let mut selection =
450             Selection::new(SelectionType::Simple, Point::new(Line(0), Column(0)), Side::Right);
451         selection.update(Point::new(Line(0), Column(1)), Side::Left);
452 
453         assert_eq!(selection.to_range(&term(1, 2)), None);
454     }
455 
456     /// Test adjacent cell selection from right to left.
457     ///
458     /// 1. [  ][  ]
459     /// 2. [  ][B ]
460     /// 3. [ E][B ]
461     #[test]
between_adjacent_cells_right_to_left()462     fn between_adjacent_cells_right_to_left() {
463         let mut selection =
464             Selection::new(SelectionType::Simple, Point::new(Line(0), Column(1)), Side::Left);
465         selection.update(Point::new(Line(0), Column(0)), Side::Right);
466 
467         assert_eq!(selection.to_range(&term(1, 2)), None);
468     }
469 
470     /// Test selection across adjacent lines.
471     ///
472     /// 1.  [  ][  ][  ][  ][  ]
473     ///     [  ][  ][  ][  ][  ]
474     /// 2.  [  ][ B][  ][  ][  ]
475     ///     [  ][  ][  ][  ][  ]
476     /// 3.  [  ][ B][XX][XX][XX]
477     ///     [XX][XE][  ][  ][  ]
478     #[test]
across_adjacent_lines_upward_final_cell_exclusive()479     fn across_adjacent_lines_upward_final_cell_exclusive() {
480         let mut selection =
481             Selection::new(SelectionType::Simple, Point::new(Line(0), Column(1)), Side::Right);
482         selection.update(Point::new(Line(1), Column(1)), Side::Right);
483 
484         assert_eq!(selection.to_range(&term(2, 5)).unwrap(), SelectionRange {
485             start: Point::new(Line(0), Column(2)),
486             end: Point::new(Line(1), Column(1)),
487             is_block: false,
488         });
489     }
490 
491     /// Test selection across adjacent lines.
492     ///
493     /// 1.  [  ][  ][  ][  ][  ]
494     ///     [  ][  ][  ][  ][  ]
495     /// 2.  [  ][  ][  ][  ][  ]
496     ///     [  ][ B][  ][  ][  ]
497     /// 3.  [  ][ E][XX][XX][XX]
498     ///     [XX][XB][  ][  ][  ]
499     /// 4.  [ E][XX][XX][XX][XX]
500     ///     [XX][XB][  ][  ][  ]
501     #[test]
selection_bigger_then_smaller()502     fn selection_bigger_then_smaller() {
503         let mut selection =
504             Selection::new(SelectionType::Simple, Point::new(Line(1), Column(1)), Side::Right);
505         selection.update(Point::new(Line(0), Column(1)), Side::Right);
506         selection.update(Point::new(Line(0), Column(0)), Side::Right);
507 
508         assert_eq!(selection.to_range(&term(2, 5)).unwrap(), SelectionRange {
509             start: Point::new(Line(0), Column(1)),
510             end: Point::new(Line(1), Column(1)),
511             is_block: false,
512         });
513     }
514 
515     #[test]
line_selection()516     fn line_selection() {
517         let size = (10, 5);
518         let mut selection =
519             Selection::new(SelectionType::Lines, Point::new(Line(9), Column(1)), Side::Left);
520         selection.update(Point::new(Line(4), Column(1)), Side::Right);
521         selection = selection.rotate(&size, &(Line(0)..Line(size.0 as i32)), 4).unwrap();
522 
523         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
524             start: Point::new(Line(0), Column(0)),
525             end: Point::new(Line(5), Column(4)),
526             is_block: false,
527         });
528     }
529 
530     #[test]
semantic_selection()531     fn semantic_selection() {
532         let size = (10, 5);
533         let mut selection =
534             Selection::new(SelectionType::Semantic, Point::new(Line(9), Column(3)), Side::Left);
535         selection.update(Point::new(Line(4), Column(1)), Side::Right);
536         selection = selection.rotate(&size, &(Line(0)..Line(size.0 as i32)), 4).unwrap();
537 
538         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
539             start: Point::new(Line(0), Column(1)),
540             end: Point::new(Line(5), Column(3)),
541             is_block: false,
542         });
543     }
544 
545     #[test]
simple_selection()546     fn simple_selection() {
547         let size = (10, 5);
548         let mut selection =
549             Selection::new(SelectionType::Simple, Point::new(Line(9), Column(3)), Side::Right);
550         selection.update(Point::new(Line(4), Column(1)), Side::Right);
551         selection = selection.rotate(&size, &(Line(0)..Line(size.0 as i32)), 4).unwrap();
552 
553         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
554             start: Point::new(Line(0), Column(2)),
555             end: Point::new(Line(5), Column(3)),
556             is_block: false,
557         });
558     }
559 
560     #[test]
block_selection()561     fn block_selection() {
562         let size = (10, 5);
563         let mut selection =
564             Selection::new(SelectionType::Block, Point::new(Line(9), Column(3)), Side::Right);
565         selection.update(Point::new(Line(4), Column(1)), Side::Right);
566         selection = selection.rotate(&size, &(Line(0)..Line(size.0 as i32)), 4).unwrap();
567 
568         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
569             start: Point::new(Line(0), Column(2)),
570             end: Point::new(Line(5), Column(3)),
571             is_block: true
572         });
573     }
574 
575     #[test]
simple_is_empty()576     fn simple_is_empty() {
577         let mut selection =
578             Selection::new(SelectionType::Simple, Point::new(Line(1), Column(0)), Side::Right);
579         assert!(selection.is_empty());
580         selection.update(Point::new(Line(1), Column(1)), Side::Left);
581         assert!(selection.is_empty());
582         selection.update(Point::new(Line(0), Column(0)), Side::Right);
583         assert!(!selection.is_empty());
584     }
585 
586     #[test]
block_is_empty()587     fn block_is_empty() {
588         let mut selection =
589             Selection::new(SelectionType::Block, Point::new(Line(1), Column(0)), Side::Right);
590         assert!(selection.is_empty());
591         selection.update(Point::new(Line(1), Column(1)), Side::Left);
592         assert!(selection.is_empty());
593         selection.update(Point::new(Line(1), Column(1)), Side::Right);
594         assert!(!selection.is_empty());
595         selection.update(Point::new(Line(0), Column(0)), Side::Right);
596         assert!(selection.is_empty());
597         selection.update(Point::new(Line(0), Column(1)), Side::Left);
598         assert!(selection.is_empty());
599         selection.update(Point::new(Line(0), Column(1)), Side::Right);
600         assert!(!selection.is_empty());
601     }
602 
603     #[test]
rotate_in_region_up()604     fn rotate_in_region_up() {
605         let size = (10, 5);
606         let mut selection =
607             Selection::new(SelectionType::Simple, Point::new(Line(7), Column(3)), Side::Right);
608         selection.update(Point::new(Line(4), Column(1)), Side::Right);
609         selection = selection.rotate(&size, &(Line(1)..Line(size.0 as i32 - 1)), 4).unwrap();
610 
611         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
612             start: Point::new(Line(1), Column(0)),
613             end: Point::new(Line(3), Column(3)),
614             is_block: false,
615         });
616     }
617 
618     #[test]
rotate_in_region_down()619     fn rotate_in_region_down() {
620         let size = (10, 5);
621         let mut selection =
622             Selection::new(SelectionType::Simple, Point::new(Line(4), Column(3)), Side::Right);
623         selection.update(Point::new(Line(1), Column(1)), Side::Left);
624         selection = selection.rotate(&size, &(Line(1)..Line(size.0 as i32 - 1)), -5).unwrap();
625 
626         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
627             start: Point::new(Line(6), Column(1)),
628             end: Point::new(Line(8), size.last_column()),
629             is_block: false,
630         });
631     }
632 
633     #[test]
rotate_in_region_up_block()634     fn rotate_in_region_up_block() {
635         let size = (10, 5);
636         let mut selection =
637             Selection::new(SelectionType::Block, Point::new(Line(7), Column(3)), Side::Right);
638         selection.update(Point::new(Line(4), Column(1)), Side::Right);
639         selection = selection.rotate(&size, &(Line(1)..Line(size.0 as i32 - 1)), 4).unwrap();
640 
641         assert_eq!(selection.to_range(&term(size.0, size.1)).unwrap(), SelectionRange {
642             start: Point::new(Line(1), Column(2)),
643             end: Point::new(Line(3), Column(3)),
644             is_block: true,
645         });
646     }
647 
648     #[test]
range_intersection()649     fn range_intersection() {
650         let mut selection =
651             Selection::new(SelectionType::Lines, Point::new(Line(3), Column(1)), Side::Left);
652         selection.update(Point::new(Line(6), Column(1)), Side::Right);
653 
654         assert!(selection.intersects_range(..));
655         assert!(selection.intersects_range(Line(2)..));
656         assert!(selection.intersects_range(Line(2)..=Line(4)));
657         assert!(selection.intersects_range(Line(2)..=Line(7)));
658         assert!(selection.intersects_range(Line(4)..=Line(5)));
659         assert!(selection.intersects_range(Line(5)..Line(8)));
660 
661         assert!(!selection.intersects_range(..=Line(2)));
662         assert!(!selection.intersects_range(Line(7)..=Line(8)));
663     }
664 }
665