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, writer: impl FnMut() -> Result<()>) -> 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, _writer: impl FnMut() -> Result<()>) -> Result<()> { T::execute_winapi(self, _writer) } #[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) } }