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
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
use std::{fmt::Display, io::Write};

use crate::{execute, queue};

use super::error::Result;

/// An interface for a command that performs an action on the terminal.
///
/// Crossterm provides a set of commands,
/// and there is no immediate reason to implement a command yourself.
/// In order to understand how to use and execute commands,
/// it is recommended that you take a look at [Command Api](../#command-api) chapter.
pub trait Command {
    type AnsiType: Display;

    /// Returns an ANSI code representation of this command.
    /// An ANSI code can manipulate the terminal by writing it to the terminal buffer.
    /// However, only Windows 10 and UNIX systems support this.
    ///
    /// This method does not need to be accessed manually, as it is used by the crossterm's [Command Api](../#command-api)
    fn ansi_code(&self) -> Self::AnsiType;

    /// Execute this command.
    ///
    /// Windows versions lower than windows 10 do not support ANSI escape codes,
    /// therefore a direct WinAPI call is made.
    ///
    /// This method does not need to be accessed manually, as it is used by the crossterm's [Command Api](../#command-api)
    #[cfg(windows)]
    fn execute_winapi(&self) -> Result<()>;

    /// Returns whether the ansi code representation of this command is supported by windows.
    ///
    /// A list of supported ANSI escape codes
    /// can be found [here](https://docs.microsoft.com/en-us/windows/console/console-virtual-terminal-sequences).
    #[cfg(windows)]
    fn is_ansi_code_supported(&self) -> bool {
        super::ansi_support::supports_ansi()
    }
}

impl<T: Command> Command for &T {
    type AnsiType = T::AnsiType;

    #[inline]
    fn ansi_code(&self) -> Self::AnsiType {
        T::ansi_code(self)
    }

    #[inline]
    #[cfg(windows)]
    fn execute_winapi(&self) -> Result<()> {
        T::execute_winapi(self)
    }

    #[cfg(windows)]
    #[inline]
    fn is_ansi_code_supported(&self) -> bool {
        T::is_ansi_code_supported(self)
    }
}

/// An interface for commands that can be queued for further execution.
pub trait QueueableCommand<T: Display>: Sized {
    /// Queues the given command for further execution.
    fn queue(&mut self, command: impl Command<AnsiType = T>) -> Result<&mut Self>;
}

/// An interface for commands that are directly executed.
pub trait ExecutableCommand<T: Display>: Sized {
    /// Executes the given command directly.
    fn execute(&mut self, command: impl Command<AnsiType = T>) -> Result<&mut Self>;
}

impl<T, A> QueueableCommand<A> for T
where
    A: Display,
    T: Write,
{
    /// Queues the given command for further execution.
    ///
    /// Queued commands will be executed in the following cases:
    ///
    /// * When `flush` is called manually on the given type implementing `io::Write`.
    /// * The terminal will `flush` automatically if the buffer is full.
    /// * Each line is flushed in case of `stdout`, because it is line buffered.
    ///
    /// # Arguments
    ///
    /// - [Command](./trait.Command.html)
    ///
    ///     The command that you want to queue for later execution.
    ///
    /// # Examples
    ///
    /// ```rust
    /// use std::io::{Write, stdout};
    /// use crossterm::{Result, QueueableCommand, style::Print};
    ///
    ///  fn main() -> Result<()> {
    ///     let mut stdout = stdout();
    ///
    ///     // `Print` will executed executed when `flush` is called.
    ///     stdout
    ///         .queue(Print("foo 1\n".to_string()))?
    ///         .queue(Print("foo 2".to_string()))?;
    ///
    ///     // some other code (no execution happening here) ...
    ///
    ///     // when calling `flush` on `stdout`, all commands will be written to the stdout and therefore executed.
    ///     stdout.flush()?;
    ///
    ///     Ok(())
    ///
    ///     // ==== Output ====
    ///     // foo 1
    ///     // foo 2
    /// }
    /// ```
    ///
    /// Have a look over at the [Command API](./#command-api) for more details.
    ///
    /// # Notes
    ///
    /// * In the case of UNIX and Windows 10, ANSI codes are written to the given 'writer'.
    /// * In case of Windows versions lower than 10, a direct WinApi call will be made.
    ///     The reason for this is that Windows versions lower than 10 do not support ANSI codes,
    ///     and can therefore not be written to the given `writer`.
    ///     Therefore, there is no difference between [execute](./trait.ExecutableCommand.html)
    ///     and [queue](./trait.QueueableCommand.html) for those old Windows versions.
    fn queue(&mut self, command: impl Command<AnsiType = A>) -> Result<&mut Self> {
        queue!(self, command)?;
        Ok(self)
    }
}

impl<T, A> ExecutableCommand<A> for T
where
    A: Display,
    T: Write,
{
    /// Executes the given command directly.
    ///
    /// The given command its ANSI escape code will be written and flushed onto `Self`.
    ///
    /// # Arguments
    ///
    /// - [Command](./trait.Command.html)
    ///
    ///     The command that you want to execute directly.
    ///
    /// # Example
    ///
    /// ```rust
    /// use std::io::{Write, stdout};
    /// use crossterm::{Result, ExecutableCommand, style::Print};
    ///
    ///  fn main() -> Result<()> {
    ///      // will be executed directly
    ///       stdout()
    ///         .execute(Print("sum:\n".to_string()))?
    ///         .execute(Print(format!("1 + 1= {} ", 1 + 1)))?;
    ///
    ///       Ok(())
    ///
    ///      // ==== Output ====
    ///      // sum:
    ///      // 1 + 1 = 2
    ///  }
    /// ```
    ///
    /// Have a look over at the [Command API](./#command-api) for more details.
    ///
    /// # Notes
    ///
    /// * In the case of UNIX and Windows 10, ANSI codes are written to the given 'writer'.
    /// * In case of Windows versions lower than 10, a direct WinApi call will be made.
    ///     The reason for this is that Windows versions lower than 10 do not support ANSI codes,
    ///     and can therefore not be written to the given `writer`.
    ///     Therefore, there is no difference between [execute](./trait.ExecutableCommand.html)
    ///     and [queue](./trait.QueueableCommand.html) for those old Windows versions.
    fn execute(&mut self, command: impl Command<AnsiType = A>) -> Result<&mut Self> {
        execute!(self, command)?;
        Ok(self)
    }
}