1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
//! This module helps move and set the cursor position.

use std::fmt::{Display, Formatter};
use crate::control::ControlSequence;
use crate::control::format::TabulationControl;

/// # CTC - Cursor tabulation control
///
/// CTC causes one or more tabulation stops to be set or cleared in the presentation component.
pub fn tabulation_control(tabulation_control: TabulationControl) -> ControlSequence {
    ControlSequence::new(&[&tabulation_control.to_string()], "W")
}

/// # CPR - Active position report
///
/// If the DEVICE COMPONENT SELECT MODE (DCSM) is set to PRESENTATION, CPR is used to
/// report the active presentation position of the sending device as residing in the presentation component at
/// the `l`-th line position according to the line progression and at the `c`-th character.
///
/// If the DEVICE COMPONENT SELECT MODE (DCSM) is set to DATA, CPR is used to report the
/// active data position of the sending device as residing in the data component at the `l`-th line position
/// according to the line progression and at the `c`-th character position according to the character
/// progression.
///
/// CPR may be solicited by a DEVICE STATUS REPORT (DSR) or be sent unsolicited.
pub fn position_report(l: usize, c: usize) -> ControlSequence {
    ControlSequence::new(&[&l.to_string(), &c.to_string()], "H")
}

/// # CUP - Cursor position
///
/// CUP causes the active presentation position to be moved in the presentation component to the n-th line
/// position according to the line progression and to the m-th character position according to the character
/// path, where n equals the value of `l` and m equals the value of `c`.
pub fn set_position(l: usize, c: usize) -> ControlSequence {
    ControlSequence::new(&[&l.to_string(), &c.to_string()], "H")
}

/// A struct representing the cursor directions.
///
/// To use with the function [move_cursor].
#[derive(Copy, Clone, Debug)]
pub enum Direction {
    /// # CUU - Cursor up
    ///
    /// CUU causes the active presentation position to be moved upwards in the presentation component by n
    /// line positions if the character path is horizontal, or by n character positions if the character path is vertical.
    Up,

    /// # CUD - Cursor down
    ///
    /// CUD causes the active presentation position to be moved downwards in the presentation component by n
    /// line positions if the character path is horizontal, or by n character positions if the character path is  vertical.
    Down,

    /// # CUF - Cursor forward
    ///
    /// CUF causes the active presentation position to be moved rightwards in the presentation component by n
    /// character positions if the character path is horizontal, or by n line positions if the character path is  vertical.
    Forward,

    /// # CUB - Cursor backward
    ///
    /// CUB causes the active presentation position to be moved leftwards in the presentation component by n
    /// character positions if the character path is horizontal, or by n line positions if the character path is vertical.
    Backward,

    /// # CNL - Cursor next line
    ///
    /// CNL causes the active presentation position to be moved to the first character position of the n-th following line in the presentation component.
    NextLine,

    /// # CPL - Cursor preceding line
    ///
    /// CPL causes the active presentation position to be moved to the first character position of the n-th preceding line in the presentation component.
    PreviousLine,
}

impl Display for Direction {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", match self {
            Direction::Up => "A",
            Direction::Down => "B",
            Direction::Forward => "C",
            Direction::Backward => "D",
            Direction::NextLine => "E",
            Direction::PreviousLine => "F",
        })
    }
}

/// # Move cursor
/// Moves the cursor in a direction relative to its current position.
///
/// This function can perform the following cursor control functions :
///
/// - CUU - Cursor up with [Direction::Up],
/// - CUD - Cursor down with [Direction::Down],
/// - CUF - Cursor forward with [Direction::Forward],
/// - CUB - Cursor backward with [Direction::Backward],
/// - CNL - Cursor next line with [Direction::NextLine],
/// - CPL - Cursor preceding line with [Direction::PreviousLine],
pub fn move_cursor(direction: Direction, n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], &direction.to_string())
}

/// # CBT - Cursor backward tabulation
///
/// CBT causes the active presentation position to be moved to the character position corresponding to the
/// `n`-th preceding character tabulation stop in the presentation component, according to the character path.
pub fn tabulation_backward(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], "Z")
}

/// # CHT - Cursor forward tabulation
///
/// CHT causes the active presentation position to be moved to the character position corresponding to the
/// `n`-th following character tabulation stop in the presentation component, according to the character path.
pub fn tabulation_forward(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], "I")
}

/// # CVT - Cursor line tabulation
///
/// CVT causes the active presentation position to be moved to the corresponding character position of the
/// line corresponding to the `n`-th following line tabulation stop in the presentation component.
pub fn line_tabulation(n: usize) -> ControlSequence {
    ControlSequence::new(&[&n.to_string()], "Y")
}

#[derive(Copy, Clone, Debug)]
pub enum MovementDirection {
    Same,
    Opposite,
}

impl Display for MovementDirection {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", match self {
            MovementDirection::Same => "0",
            MovementDirection::Opposite => "1",
        })
    }
}

/// # SIMD - Select implicit movement direction
/// 
/// SIMD is used to select the direction of implicit movement of the data position relative to the character
/// progression. The direction selected remains in effect until the next occurrence of SIMD.
pub fn select_implicit(movement_direction: MovementDirection) -> ControlSequence {
    ControlSequence::new(&[&movement_direction.to_string()], "^")
}