1use std::convert::TryFrom;
22use std::mem;
23use std::ops::Range;
24
25use crate::index::{Column, Line, Point, Side};
26use crate::term::cell::Flags;
27use crate::term::{Search, Term};
28
29#[derive(Debug, Copy, Clone, PartialEq)]
31pub struct Anchor {
32 point: Point<usize>,
33 side: Side,
34}
35
36impl Anchor {
37 fn new(point: Point<usize>, side: Side) -> Anchor {
38 Anchor { point, side }
39 }
40}
41
42#[derive(Copy, Clone, Debug, Eq, PartialEq)]
44pub struct SelectionRange<L = usize> {
45 pub start: Point<L>,
47 pub end: Point<L>,
49 pub is_block: bool,
51}
52
53impl<L> SelectionRange<L> {
54 pub fn new(start: Point<L>, end: Point<L>, is_block: bool) -> Self {
55 Self { start, end, is_block }
56 }
57
58 pub fn contains(&self, col: Column, line: L) -> bool
59 where
60 L: PartialEq + PartialOrd,
61 {
62 self.start.line <= line
63 && self.end.line >= line
64 && (self.start.col <= col || (self.start.line != line && !self.is_block))
65 && (self.end.col >= col || (self.end.line != line && !self.is_block))
66 }
67}
68
69#[derive(Debug, Copy, Clone, PartialEq)]
71enum SelectionType {
72 Simple,
73 Block,
74 Semantic,
75 Lines,
76}
77
78#[derive(Debug, Clone, PartialEq)]
97pub struct Selection {
98 region: Range<Anchor>,
99 ty: SelectionType,
100}
101
102impl Selection {
103 pub fn simple(location: Point<usize>, side: Side) -> Selection {
104 Self {
105 region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
106 ty: SelectionType::Simple,
107 }
108 }
109
110 pub fn block(location: Point<usize>, side: Side) -> Selection {
111 Self {
112 region: Range { start: Anchor::new(location, side), end: Anchor::new(location, side) },
113 ty: SelectionType::Block,
114 }
115 }
116
117 pub fn semantic(location: Point<usize>) -> Selection {
118 Self {
119 region: Range {
120 start: Anchor::new(location, Side::Left),
121 end: Anchor::new(location, Side::Right),
122 },
123 ty: SelectionType::Semantic,
124 }
125 }
126
127 pub fn lines(location: Point<usize>) -> Selection {
128 Self {
129 region: Range {
130 start: Anchor::new(location, Side::Left),
131 end: Anchor::new(location, Side::Right),
132 },
133 ty: SelectionType::Lines,
134 }
135 }
136
137 pub fn update(&mut self, location: Point<usize>, side: Side) {
138 self.region.end.point = location;
139 self.region.end.side = side;
140 }
141
142 pub fn rotate(
143 mut self,
144 num_lines: usize,
145 num_cols: usize,
146 scrolling_region: &Range<Line>,
147 offset: isize,
148 ) -> Option<Selection> {
149 let region_start = num_lines - scrolling_region.start.0;
151 let region_end = num_lines - scrolling_region.end.0;
152
153 let (mut start, mut end) = (&mut self.region.start, &mut self.region.end);
154 if Self::points_need_swap(start.point, end.point) {
155 mem::swap(&mut start, &mut end);
156 }
157
158 if (start.point.line < region_start || region_start == num_lines)
160 && start.point.line >= region_end
161 {
162 start.point.line = usize::try_from(start.point.line as isize + offset).unwrap_or(0);
163
164 if start.point.line < region_end && end.point.line >= region_end {
166 return None;
167 }
168
169 if start.point.line >= region_start && region_start != num_lines {
171 if self.ty != SelectionType::Block {
172 start.point.col = Column(0);
173 start.side = Side::Left;
174 }
175 start.point.line = region_start - 1;
176 }
177 }
178
179 if (end.point.line < region_start || region_start == num_lines)
181 && end.point.line >= region_end
182 {
183 end.point.line = usize::try_from(end.point.line as isize + offset).unwrap_or(0);
184
185 if end.point.line > start.point.line {
187 return None;
188 }
189
190 if end.point.line < region_end {
192 if self.ty != SelectionType::Block {
193 end.point.col = Column(num_cols - 1);
194 end.side = Side::Right;
195 }
196 end.point.line = region_end;
197 }
198 }
199
200 Some(self)
201 }
202
203 pub fn is_empty(&self) -> bool {
204 match self.ty {
205 SelectionType::Simple => {
206 let (mut start, mut end) = (self.region.start, self.region.end);
207 if Selection::points_need_swap(start.point, end.point) {
208 mem::swap(&mut start, &mut end);
209 }
210
211 start == end
214 || (start.side == Side::Right
215 && end.side == Side::Left
216 && (start.point.line == end.point.line)
217 && start.point.col + 1 == end.point.col)
218 }
219 SelectionType::Block => {
220 let (start, end) = (self.region.start, self.region.end);
221
222 (start.point.col == end.point.col && start.side == end.side)
226 || (start.point.col + 1 == end.point.col
227 && start.side == Side::Right
228 && end.side == Side::Left)
229 || (end.point.col + 1 == start.point.col
230 && start.side == Side::Left
231 && end.side == Side::Right)
232 }
233 SelectionType::Semantic | SelectionType::Lines => false,
234 }
235 }
236
237 pub fn to_range<T>(&self, term: &Term<T>) -> Option<SelectionRange> {
239 let grid = term.grid();
240 let num_cols = grid.num_cols();
241
242 let (mut start, mut end) = (self.region.start, self.region.end);
244 if Self::points_need_swap(start.point, end.point) {
245 mem::swap(&mut start, &mut end);
246 }
247
248 let is_block = self.ty == SelectionType::Block;
250 let (start, end) = Self::grid_clamp(start, end, is_block, grid.len()).ok()?;
251
252 let range = match self.ty {
253 SelectionType::Simple => self.range_simple(start, end, num_cols),
254 SelectionType::Block => self.range_block(start, end),
255 SelectionType::Semantic => Self::range_semantic(term, start.point, end.point),
256 SelectionType::Lines => Self::range_lines(term, start.point, end.point),
257 };
258
259 range.map(|range| Self::range_expand_fullwidth(term, range))
261 }
262
263 fn range_expand_fullwidth<T>(term: &Term<T>, mut range: SelectionRange) -> SelectionRange {
265 let grid = term.grid();
266 let num_cols = grid.num_cols();
267
268 let flag_at = |point: Point<usize>, flag: Flags| -> bool {
270 grid[point.line][point.col].flags.contains(flag)
271 };
272
273 if range.start.col < num_cols {
275 if range.start.line + 1 != grid.len() || range.start.col.0 != 0 {
277 let prev = range.start.sub(num_cols.0, 1, true);
278 if flag_at(range.start, Flags::WIDE_CHAR_SPACER) && flag_at(prev, Flags::WIDE_CHAR)
279 {
280 range.start = prev;
281 }
282 }
283
284 if range.start.line + 1 != grid.len() || range.start.col.0 != 0 {
286 let prev = range.start.sub(num_cols.0, 1, true);
287 if (prev.line + 1 != grid.len() || prev.col.0 != 0)
288 && flag_at(prev, Flags::WIDE_CHAR_SPACER)
289 && !flag_at(prev.sub(num_cols.0, 1, true), Flags::WIDE_CHAR)
290 {
291 range.start = prev;
292 }
293 }
294 }
295
296 if range.end.line != 0 || range.end.col < num_cols {
298 if (range.end.line + 1 != grid.len() || range.end.col.0 != 0)
300 && flag_at(range.end, Flags::WIDE_CHAR_SPACER)
301 && !flag_at(range.end.sub(num_cols.0, 1, true), Flags::WIDE_CHAR)
302 {
303 range.end = range.end.add(num_cols.0, 1, true);
304 }
305
306 if flag_at(range.end, Flags::WIDE_CHAR) {
308 range.end = range.end.add(num_cols.0, 1, true);
309 }
310 }
311
312 range
313 }
314
315 fn points_need_swap(start: Point<usize>, end: Point<usize>) -> bool {
317 start.line < end.line || start.line == end.line && start.col > end.col
318 }
319
320 fn grid_clamp(
322 mut start: Anchor,
323 end: Anchor,
324 is_block: bool,
325 lines: usize,
326 ) -> Result<(Anchor, Anchor), ()> {
327 if start.point.line >= lines {
329 if end.point.line >= lines {
331 return Err(());
332 }
333
334 if !is_block {
336 start.side = Side::Left;
337 start.point.col = Column(0);
338 }
339 start.point.line = lines - 1;
340 }
341
342 Ok((start, end))
343 }
344
345 fn range_semantic<T>(
346 term: &Term<T>,
347 mut start: Point<usize>,
348 mut end: Point<usize>,
349 ) -> Option<SelectionRange> {
350 if start == end {
351 if let Some(matching) = term.bracket_search(start) {
352 if (matching.line == start.line && matching.col < start.col)
353 || (matching.line > start.line)
354 {
355 start = matching;
356 } else {
357 end = matching;
358 }
359
360 return Some(SelectionRange { start, end, is_block: false });
361 }
362 }
363
364 start = term.semantic_search_left(start);
365 end = term.semantic_search_right(end);
366
367 Some(SelectionRange { start, end, is_block: false })
368 }
369
370 fn range_lines<T>(
371 term: &Term<T>,
372 mut start: Point<usize>,
373 mut end: Point<usize>,
374 ) -> Option<SelectionRange> {
375 start = term.line_search_left(start);
376 end = term.line_search_right(end);
377
378 Some(SelectionRange { start, end, is_block: false })
379 }
380
381 fn range_simple(
382 &self,
383 mut start: Anchor,
384 mut end: Anchor,
385 num_cols: Column,
386 ) -> Option<SelectionRange> {
387 if self.is_empty() {
388 return None;
389 }
390
391 if end.side == Side::Left && start.point != end.point {
393 if end.point.col == Column(0) {
395 end.point.col = num_cols - 1;
396 end.point.line += 1;
397 } else {
398 end.point.col -= 1;
399 }
400 }
401
402 if start.side == Side::Right && start.point != end.point {
404 start.point.col += 1;
405 }
406
407 Some(SelectionRange { start: start.point, end: end.point, is_block: false })
408 }
409
410 fn range_block(&self, mut start: Anchor, mut end: Anchor) -> Option<SelectionRange> {
411 if self.is_empty() {
412 return None;
413 }
414
415 if start.point.col > end.point.col {
417 mem::swap(&mut start.side, &mut end.side);
418 mem::swap(&mut start.point.col, &mut end.point.col);
419 }
420
421 if end.side == Side::Left && start.point != end.point && end.point.col.0 > 0 {
423 end.point.col -= 1;
424 }
425
426 if start.side == Side::Right && start.point != end.point {
428 start.point.col += 1;
429 }
430
431 Some(SelectionRange { start: start.point, end: end.point, is_block: true })
432 }
433}
434
435#[cfg(test)]
445mod test {
446 use std::mem;
447
448 use super::{Selection, SelectionRange};
449 use crate::clipboard::Clipboard;
450 use crate::config::MockConfig;
451 use crate::event::{Event, EventListener};
452 use crate::grid::Grid;
453 use crate::index::{Column, Line, Point, Side};
454 use crate::term::cell::{Cell, Flags};
455 use crate::term::{SizeInfo, Term};
456
457 struct Mock;
458 impl EventListener for Mock {
459 fn send_event(&self, _event: Event) {}
460 }
461
462 fn term(width: usize, height: usize) -> Term<Mock> {
463 let size = SizeInfo {
464 width: width as f32,
465 height: height as f32,
466 cell_width: 1.0,
467 cell_height: 1.0,
468 padding_x: 0.0,
469 padding_y: 0.0,
470 dpr: 1.0,
471 };
472 Term::new(&MockConfig::default(), &size, Clipboard::new_nop(), Mock)
473 }
474
475 #[test]
481 fn single_cell_left_to_right() {
482 let location = Point { line: 0, col: Column(0) };
483 let mut selection = Selection::simple(location, Side::Left);
484 selection.update(location, Side::Right);
485
486 assert_eq!(
487 selection.to_range(&term(1, 1)).unwrap(),
488 SelectionRange { start: location, end: location, is_block: false }
489 );
490 }
491
492 #[test]
498 fn single_cell_right_to_left() {
499 let location = Point { line: 0, col: Column(0) };
500 let mut selection = Selection::simple(location, Side::Right);
501 selection.update(location, Side::Left);
502
503 assert_eq!(
504 selection.to_range(&term(1, 1)).unwrap(),
505 SelectionRange { start: location, end: location, is_block: false }
506 );
507 }
508
509 #[test]
515 fn between_adjacent_cells_left_to_right() {
516 let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right);
517 selection.update(Point::new(0, Column(1)), Side::Left);
518
519 assert_eq!(selection.to_range(&term(2, 1)), None);
520 }
521
522 #[test]
528 fn between_adjacent_cells_right_to_left() {
529 let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Left);
530 selection.update(Point::new(0, Column(0)), Side::Right);
531
532 assert_eq!(selection.to_range(&term(2, 1)), None);
533 }
534
535 #[test]
544 fn across_adjacent_lines_upward_final_cell_exclusive() {
545 let mut selection = Selection::simple(Point::new(1, Column(1)), Side::Right);
546 selection.update(Point::new(0, Column(1)), Side::Right);
547
548 assert_eq!(
549 selection.to_range(&term(5, 2)).unwrap(),
550 SelectionRange {
551 start: Point::new(1, Column(2)),
552 end: Point::new(0, Column(1)),
553 is_block: false,
554 }
555 );
556 }
557
558 #[test]
569 fn selection_bigger_then_smaller() {
570 let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Right);
571 selection.update(Point::new(1, Column(1)), Side::Right);
572 selection.update(Point::new(1, Column(0)), Side::Right);
573
574 assert_eq!(
575 selection.to_range(&term(5, 2)).unwrap(),
576 SelectionRange {
577 start: Point::new(1, Column(1)),
578 end: Point::new(0, Column(1)),
579 is_block: false,
580 }
581 );
582 }
583
584 #[test]
585 fn line_selection() {
586 let num_lines = 10;
587 let num_cols = 5;
588 let mut selection = Selection::lines(Point::new(0, Column(1)));
589 selection.update(Point::new(5, Column(1)), Side::Right);
590 selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
591
592 assert_eq!(
593 selection.to_range(&term(num_cols, num_lines)).unwrap(),
594 SelectionRange {
595 start: Point::new(9, Column(0)),
596 end: Point::new(7, Column(4)),
597 is_block: false,
598 }
599 );
600 }
601
602 #[test]
603 fn semantic_selection() {
604 let num_lines = 10;
605 let num_cols = 5;
606 let mut selection = Selection::semantic(Point::new(0, Column(3)));
607 selection.update(Point::new(5, Column(1)), Side::Right);
608 selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
609
610 assert_eq!(
611 selection.to_range(&term(num_cols, num_lines)).unwrap(),
612 SelectionRange {
613 start: Point::new(9, Column(0)),
614 end: Point::new(7, Column(3)),
615 is_block: false,
616 }
617 );
618 }
619
620 #[test]
621 fn simple_selection() {
622 let num_lines = 10;
623 let num_cols = 5;
624 let mut selection = Selection::simple(Point::new(0, Column(3)), Side::Right);
625 selection.update(Point::new(5, Column(1)), Side::Right);
626 selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
627
628 assert_eq!(
629 selection.to_range(&term(num_cols, num_lines)).unwrap(),
630 SelectionRange {
631 start: Point::new(9, Column(0)),
632 end: Point::new(7, Column(3)),
633 is_block: false,
634 }
635 );
636 }
637
638 #[test]
639 fn block_selection() {
640 let num_lines = 10;
641 let num_cols = 5;
642 let mut selection = Selection::block(Point::new(0, Column(3)), Side::Right);
643 selection.update(Point::new(5, Column(1)), Side::Right);
644 selection = selection.rotate(num_lines, num_cols, &(Line(0)..Line(num_lines)), 7).unwrap();
645
646 assert_eq!(
647 selection.to_range(&term(num_cols, num_lines)).unwrap(),
648 SelectionRange {
649 start: Point::new(9, Column(2)),
650 end: Point::new(7, Column(3)),
651 is_block: true
652 }
653 );
654 }
655
656 #[test]
657 fn double_width_expansion() {
658 let mut term = term(10, 1);
659 let mut grid = Grid::new(Line(1), Column(10), 0, Cell::default());
660 grid[Line(0)][Column(0)].flags.insert(Flags::WIDE_CHAR);
661 grid[Line(0)][Column(1)].flags.insert(Flags::WIDE_CHAR_SPACER);
662 grid[Line(0)][Column(8)].flags.insert(Flags::WIDE_CHAR);
663 grid[Line(0)][Column(9)].flags.insert(Flags::WIDE_CHAR_SPACER);
664 mem::swap(term.grid_mut(), &mut grid);
665
666 let mut selection = Selection::simple(Point::new(0, Column(1)), Side::Left);
667 selection.update(Point::new(0, Column(8)), Side::Right);
668
669 assert_eq!(
670 selection.to_range(&term).unwrap(),
671 SelectionRange {
672 start: Point::new(0, Column(0)),
673 end: Point::new(0, Column(9)),
674 is_block: false,
675 }
676 );
677 }
678
679 #[test]
680 fn simple_is_empty() {
681 let mut selection = Selection::simple(Point::new(0, Column(0)), Side::Right);
682 assert!(selection.is_empty());
683 selection.update(Point::new(0, Column(1)), Side::Left);
684 assert!(selection.is_empty());
685 selection.update(Point::new(1, Column(0)), Side::Right);
686 assert!(!selection.is_empty());
687 }
688
689 #[test]
690 fn block_is_empty() {
691 let mut selection = Selection::block(Point::new(0, Column(0)), Side::Right);
692 assert!(selection.is_empty());
693 selection.update(Point::new(0, Column(1)), Side::Left);
694 assert!(selection.is_empty());
695 selection.update(Point::new(0, Column(1)), Side::Right);
696 assert!(!selection.is_empty());
697 selection.update(Point::new(1, Column(0)), Side::Right);
698 assert!(selection.is_empty());
699 selection.update(Point::new(1, Column(1)), Side::Left);
700 assert!(selection.is_empty());
701 selection.update(Point::new(1, Column(1)), Side::Right);
702 assert!(!selection.is_empty());
703 }
704
705 #[test]
706 fn rotate_in_region_up() {
707 let num_lines = 10;
708 let num_cols = 5;
709 let mut selection = Selection::simple(Point::new(2, Column(3)), Side::Right);
710 selection.update(Point::new(5, Column(1)), Side::Right);
711 selection =
712 selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), 4).unwrap();
713
714 assert_eq!(
715 selection.to_range(&term(num_cols, num_lines)).unwrap(),
716 SelectionRange {
717 start: Point::new(8, Column(0)),
718 end: Point::new(6, Column(3)),
719 is_block: false,
720 }
721 );
722 }
723
724 #[test]
725 fn rotate_in_region_down() {
726 let num_lines = 10;
727 let num_cols = 5;
728 let mut selection = Selection::simple(Point::new(5, Column(3)), Side::Right);
729 selection.update(Point::new(8, Column(1)), Side::Left);
730 selection =
731 selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), -5).unwrap();
732
733 assert_eq!(
734 selection.to_range(&term(num_cols, num_lines)).unwrap(),
735 SelectionRange {
736 start: Point::new(3, Column(1)),
737 end: Point::new(1, Column(num_cols - 1)),
738 is_block: false,
739 }
740 );
741 }
742
743 #[test]
744 fn rotate_in_region_up_block() {
745 let num_lines = 10;
746 let num_cols = 5;
747 let mut selection = Selection::block(Point::new(2, Column(3)), Side::Right);
748 selection.update(Point::new(5, Column(1)), Side::Right);
749 selection =
750 selection.rotate(num_lines, num_cols, &(Line(1)..Line(num_lines - 1)), 4).unwrap();
751
752 assert_eq!(
753 selection.to_range(&term(num_cols, num_lines)).unwrap(),
754 SelectionRange {
755 start: Point::new(8, Column(2)),
756 end: Point::new(6, Column(3)),
757 is_block: true,
758 }
759 );
760 }
761}