1use crate::edit::Transaction;
10use crate::span::Span;
11
12#[derive(Debug, Clone, Copy, PartialEq, Eq)]
15pub struct Selection {
16 pub anchor: u64,
17 pub focus: u64,
18}
19
20impl Selection {
21 pub const fn collapsed(at: u64) -> Selection {
23 Selection {
24 anchor: at,
25 focus: at,
26 }
27 }
28
29 pub fn span(self) -> Span {
31 Span::ordered(self.anchor, self.focus)
32 }
33
34 pub fn mapped(self, transaction: &Transaction) -> Selection {
41 Selection {
42 anchor: position_after(self.anchor, transaction),
43 focus: position_after(self.focus, transaction),
44 }
45 }
46}
47
48fn position_after(at: u64, transaction: &Transaction) -> u64 {
49 let mut added = 0_u64;
50 let mut removed = 0_u64;
51 for edit in transaction.edits() {
52 let span = edit.span;
53 if at <= span.start() {
54 break;
55 }
56 let written = crate::span::offset(edit.bytes.len());
57 if at < span.end() {
58 return span
59 .start()
60 .saturating_add(added)
61 .saturating_sub(removed)
62 .saturating_add(written);
63 }
64 added = added.saturating_add(written);
65 removed = removed.saturating_add(span.len());
66 }
67 at.saturating_add(added).saturating_sub(removed)
68}
69
70#[cfg(test)]
71#[allow(
72 clippy::unwrap_used,
73 clippy::expect_used,
74 clippy::panic,
75 clippy::indexing_slicing,
76 reason = "test code"
77)]
78mod tests {
79 use kernel::B3Hash;
80
81 use super::*;
82 use crate::edit::Edit;
83
84 fn save(source: &[u8], edits: &[(u64, u64, &[u8])]) -> Transaction {
85 Transaction::new(
86 B3Hash::digest(source),
87 edits
88 .iter()
89 .map(|(start, end, bytes)| Edit {
90 span: Span::new(*start, *end).unwrap(),
91 bytes: bytes.to_vec(),
92 })
93 .collect(),
94 )
95 .unwrap()
96 }
97
98 #[test]
102 fn a_selection_follows_the_text_it_stood_beside() {
103 let source = b"0123456789";
104 let saved = save(source, &[(2, 2, b"ab"), (4, 7, b"x")]);
105 let after = saved.apply(source).unwrap();
106 assert_eq!(after.bytes(), b"01ab23x789");
107 let mapped = |at: u64| Selection::collapsed(at).mapped(&saved).anchor;
108 assert_eq!(mapped(1), 1);
109 assert_eq!(mapped(2), 2);
110 assert_eq!(mapped(3), 5);
111 assert_eq!(mapped(5), 7);
112 assert_eq!(mapped(8), 8);
113 assert_eq!(mapped(10), 10);
114 let drawn = Selection {
115 anchor: 9,
116 focus: 1,
117 }
118 .mapped(&saved);
119 assert_eq!(drawn.span(), Span::new(1, 9).unwrap());
120 }
121}