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}