coded_chars/cursor.rs
1//! This module helps move and set the cursor position.
2
3use std::fmt::{Display, Formatter};
4use crate::control::ControlSequence;
5use crate::format::TabulationControl;
6
7/// # CTC - Cursor tabulation control
8///
9/// CTC causes one or more tabulation stops to be set or cleared in the presentation component.
10pub fn tabulation_control(tabulation_control: TabulationControl) -> ControlSequence {
11 ControlSequence::new(&[&tabulation_control.to_string()], "W")
12}
13
14/// # CPR - Active position report
15///
16/// If the DEVICE COMPONENT SELECT MODE (DCSM) is set to PRESENTATION, CPR is used to
17/// report the active presentation position of the sending device as residing in the presentation component at
18/// the `l`-th line position according to the line progression and at the `c`-th character.
19///
20/// If the DEVICE COMPONENT SELECT MODE (DCSM) is set to DATA, CPR is used to report the
21/// active data position of the sending device as residing in the data component at the `l`-th line position
22/// according to the line progression and at the `c`-th character position according to the character
23/// progression.
24///
25/// CPR may be solicited by a DEVICE STATUS REPORT (DSR) or be sent unsolicited.
26pub fn position_report(l: usize, c: usize) -> ControlSequence {
27 ControlSequence::new(&[&l.to_string(), &c.to_string()], "R")
28}
29
30/// # CUP - Cursor position
31///
32/// CUP causes the active presentation position to be moved in the presentation component to the n-th line
33/// position according to the line progression and to the m-th character position according to the character
34/// path, where n equals the value of `l` and m equals the value of `c`.
35pub fn set_position(l: usize, c: usize) -> ControlSequence {
36 ControlSequence::new(&[&l.to_string(), &c.to_string()], "H")
37}
38
39/// A struct representing the cursor directions.
40///
41/// To use with the function [move_cursor].
42#[derive(Copy, Clone, Debug)]
43pub enum Direction {
44 /// # CUU - Cursor up
45 ///
46 /// CUU causes the active presentation position to be moved upwards in the presentation component by n
47 /// line positions if the character path is horizontal, or by n character positions if the character path is vertical.
48 Up,
49
50 /// # CUD - Cursor down
51 ///
52 /// CUD causes the active presentation position to be moved downwards in the presentation component by n
53 /// line positions if the character path is horizontal, or by n character positions if the character path is vertical.
54 Down,
55
56 /// # CUF - Cursor forward
57 ///
58 /// CUF causes the active presentation position to be moved rightwards in the presentation component by n
59 /// character positions if the character path is horizontal, or by n line positions if the character path is vertical.
60 Forward,
61
62 /// # CUB - Cursor backward
63 ///
64 /// CUB causes the active presentation position to be moved leftwards in the presentation component by n
65 /// character positions if the character path is horizontal, or by n line positions if the character path is vertical.
66 Backward,
67
68 /// # CNL - Cursor next line
69 ///
70 /// CNL causes the active presentation position to be moved to the first character position of the n-th following line in the presentation component.
71 NextLine,
72
73 /// # CPL - Cursor preceding line
74 ///
75 /// CPL causes the active presentation position to be moved to the first character position of the n-th preceding line in the presentation component.
76 PreviousLine,
77}
78
79impl Display for Direction {
80 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
81 write!(f, "{}", match self {
82 Direction::Up => "A",
83 Direction::Down => "B",
84 Direction::Forward => "C",
85 Direction::Backward => "D",
86 Direction::NextLine => "E",
87 Direction::PreviousLine => "F",
88 })
89 }
90}
91
92/// # Move cursor
93/// Moves the cursor in a direction relative to its current position.
94///
95/// This function can perform the following cursor control functions :
96///
97/// - CUU - Cursor up with [Direction::Up],
98/// - CUD - Cursor down with [Direction::Down],
99/// - CUF - Cursor forward with [Direction::Forward],
100/// - CUB - Cursor backward with [Direction::Backward],
101/// - CNL - Cursor next line with [Direction::NextLine],
102/// - CPL - Cursor preceding line with [Direction::PreviousLine],
103pub fn move_cursor(direction: Direction, n: usize) -> ControlSequence {
104 ControlSequence::new(&[&n.to_string()], &direction.to_string())
105}
106
107/// # CBT - Cursor backward tabulation
108///
109/// CBT causes the active presentation position to be moved to the character position corresponding to the
110/// `n`-th preceding character tabulation stop in the presentation component, according to the character path.
111pub fn tabulation_backward(n: usize) -> ControlSequence {
112 ControlSequence::new(&[&n.to_string()], "Z")
113}
114
115/// # CHT - Cursor forward tabulation
116///
117/// CHT causes the active presentation position to be moved to the character position corresponding to the
118/// `n`-th following character tabulation stop in the presentation component, according to the character path.
119pub fn tabulation_forward(n: usize) -> ControlSequence {
120 ControlSequence::new(&[&n.to_string()], "I")
121}
122
123/// # CVT - Cursor line tabulation
124///
125/// CVT causes the active presentation position to be moved to the corresponding character position of the
126/// line corresponding to the `n`-th following line tabulation stop in the presentation component.
127pub fn line_tabulation(n: usize) -> ControlSequence {
128 ControlSequence::new(&[&n.to_string()], "Y")
129}
130
131
132#[cfg(test)]
133mod tests {
134 use super::*;
135
136 #[test]
137 fn test_position_report() {
138 let control = position_report(5, 10);
139 assert_eq!(control.to_string(), "\x1b[5;10R");
140 }
141
142 #[test]
143 fn test_set_position() {
144 let control = set_position(10, 20);
145 assert_eq!(control.to_string(), "\x1b[10;20H");
146 }
147
148 #[test]
149 fn test_move_cursor_up() {
150 let control = move_cursor(Direction::Up, 3);
151 assert_eq!(control.to_string(), "\x1b[3A");
152 }
153
154 #[test]
155 fn test_move_cursor_down() {
156 let control = move_cursor(Direction::Down, 4);
157 assert_eq!(control.to_string(), "\x1b[4B");
158 }
159
160 #[test]
161 fn test_move_cursor_forward() {
162 let control = move_cursor(Direction::Forward, 6);
163 assert_eq!(control.to_string(), "\x1b[6C");
164 }
165
166 #[test]
167 fn test_move_cursor_backward() {
168 let control = move_cursor(Direction::Backward, 2);
169 assert_eq!(control.to_string(), "\x1b[2D");
170 }
171
172 #[test]
173 fn test_move_cursor_nextline() {
174 let control = move_cursor(Direction::NextLine, 5);
175 assert_eq!(control.to_string(), "\x1b[5E");
176 }
177
178 #[test]
179 fn test_move_cursor_previousline() {
180 let control = move_cursor(Direction::PreviousLine, 3);
181 assert_eq!(control.to_string(), "\x1b[3F");
182 }
183
184 #[test]
185 fn test_tabulation_backward() {
186 let control = tabulation_backward(2);
187 assert_eq!(control.to_string(), "\x1b[2Z");
188 }
189
190 #[test]
191 fn test_tabulation_forward() {
192 let control = tabulation_forward(4);
193 assert_eq!(control.to_string(), "\x1b[4I");
194 }
195
196 #[test]
197 fn test_line_tabulation() {
198 let control = line_tabulation(3);
199 assert_eq!(control.to_string(), "\x1b[3Y");
200 }
201
202 #[test]
203 fn test_direction_display() {
204 assert_eq!(Direction::Up.to_string(), "A");
205 assert_eq!(Direction::Down.to_string(), "B");
206 assert_eq!(Direction::Forward.to_string(), "C");
207 assert_eq!(Direction::Backward.to_string(), "D");
208 assert_eq!(Direction::NextLine.to_string(), "E");
209 assert_eq!(Direction::PreviousLine.to_string(), "F");
210 }
211}