1use std::{
2 fmt::{Display, Debug},
3 str::FromStr
4};
5
6use crate::TextPosition;
7
8#[derive(Clone, PartialEq, Eq, PartialOrd, Ord)]
10pub struct InsertPosition {
11 line: usize,
12 col: usize,
13}
14
15impl Default for InsertPosition {
16 fn default() -> Self {
17 Self { line: 1, col: 0 }
18 }
19}
20
21impl InsertPosition {
22 pub fn new(line: usize, col: usize) -> Self {
24 assert_ne!(line, 0);
25 InsertPosition { line, col }
26 }
27
28 pub fn line(&self) -> usize { self.line }
33 pub fn col(&self) -> usize { self.col }
39
40 pub fn inc_col(&mut self) {
42 self.col += 1;
43 }
44 pub fn inc_line(&mut self) {
46 self.line += 1;
47 self.col = 0;
48 }
49 pub fn inc(&mut self, c: char) {
53 if c == '\n' {
54 self.inc_line();
55 } else {
56 self.inc_col();
57 }
58 }
59
60 pub(crate) fn text_pos_left(&self) -> TextPosition {
61 TextPosition::new(self.line(), self.col())
62 }
63 pub(crate) fn text_pos_right(&self) -> TextPosition {
64 TextPosition::new(self.line(), self.col()+1)
65 }
66}
67
68impl Display for InsertPosition {
69 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70 write!(f, "{}:{}", self.line(), self.col())
71 }
72}
73impl Debug for InsertPosition {
74 fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
75 write!(f, "{}", self)
76 }
77}
78
79impl FromStr for InsertPosition {
80 type Err = ();
81
82 fn from_str(s: &str) -> Result<Self, Self::Err> {
83 let (line_str, col_str) = s.trim().split_once(':').ok_or(())?;
84 let line: usize = line_str.parse().map_err(|_| ())?;
85 let col: usize = col_str.parse().map_err(|_| ())?;
86
87 if line == 0 { return Err(()); }
89
90 Ok(InsertPosition::new(line, col))
91 }
92}
93
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 #[test]
100 fn initializes_correctly() {
101 let default = InsertPosition::default();
102 assert_eq!(default.line(), 1);
103 assert_eq!(default.col(), 0);
104 }
105
106 #[test]
107 fn increment_methods() {
108 let mut pos = InsertPosition::default();
109
110 pos.inc_col();
111 pos.inc_col();
112 pos.inc_col();
113
114 assert_eq!(pos.line(), 1);
115 assert_eq!(pos.col(), 3);
116
117 pos.inc_col();
118 pos.inc_line();
119 pos.inc_col();
120
121 assert_eq!(pos.line(), 2);
122 assert_eq!(pos.col(), 1);
123
124 pos.inc_col();
125 pos.inc_line();
126 pos.inc_line();
127
128 assert_eq!(pos.line(), 4);
129 assert_eq!(pos.col(), 0);
130 }
131
132 #[test]
133 fn display_print() {
134 let mut pos = InsertPosition::default();
135 pos.inc_col();
136 pos.inc_line();
137
138 let text_repr = format!("{}", pos);
139 assert_eq!(text_repr, "2:0");
140 }
141
142 #[test]
143 fn debug_print() {
144 let mut pos = InsertPosition::default();
145 pos.inc_col();
146 pos.inc_line();
147
148 let text_repr = format!("{:?}", pos);
149 assert_eq!(text_repr, "2:0");
150 }
151
152 #[test]
153 fn ordering_and_eq() {
154 let mut pos1 = InsertPosition::default();
155 pos1.inc_col();
156 pos1.inc_line();
157 pos1.inc_col();
158
159 let mut pos2 = pos1.clone();
160 pos2.inc_line();
161
162 let pos3 = pos2.clone();
163
164 assert!(pos2 > pos1);
165 assert_eq!(pos2, pos3);
166 }
167
168 #[test]
169 fn parsing() {
170 assert_eq!("4:7".parse(), Ok(InsertPosition::new(4, 7)));
171 assert_eq!("1:0".parse(), Ok(InsertPosition::new(1, 0)));
172 assert_eq!("1:-9".parse::<InsertPosition>(), Err(()));
173 assert_eq!("0:6".parse::<InsertPosition>(), Err(()));
174 }
175}