1 //! # Cursor 2 //! 3 //! The `cursor` module provides functionality to work with the terminal cursor. 4 //! 5 //! This documentation does not contain a lot of examples. The reason is that it's fairly 6 //! obvious how to use this crate. Although, we do provide 7 //! [examples](https://github.com/crossterm-rs/examples) repository 8 //! to demonstrate the capabilities. 9 //! 10 //! ## Examples 11 //! 12 //! Cursor actions can be performed with commands. 13 //! Please have a look at [command documention](../index.html#command-api) for a more detailed documentation. 14 //! 15 //! ```no_run 16 //! use std::io::{stdout, Write}; 17 //! 18 //! use crossterm::{ 19 //! ExecutableCommand, execute, Result, 20 //! cursor::{DisableBlinking, EnableBlinking, MoveTo, RestorePosition, SavePosition} 21 //! }; 22 //! 23 //! fn main() -> Result<()> { 24 //! // with macro 25 //! execute!( 26 //! stdout(), 27 //! SavePosition, 28 //! MoveTo(10, 10), 29 //! EnableBlinking, 30 //! DisableBlinking, 31 //! RestorePosition 32 //! ); 33 //! 34 //! // with function 35 //! stdout() 36 //! .execute(MoveTo(11,11))? 37 //! .execute(RestorePosition); 38 //! 39 //! Ok(()) 40 //! } 41 //! ``` 42 //! 43 //! For manual execution control check out [crossterm::queue](../macro.queue.html). 44 45 pub use sys::position; 46 47 use crate::impl_display; 48 use crate::utils::Command; 49 #[cfg(windows)] 50 use crate::utils::Result; 51 52 mod ansi; 53 pub(crate) mod sys; 54 55 /// A command that moves the terminal cursor to the given position (column, row). 56 /// 57 /// # Notes 58 /// 59 /// * Top left cell is represented as `0,0`. 60 /// * Commands must be executed/queued for execution otherwise they do nothing. 61 pub struct MoveTo(pub u16, pub u16); 62 63 impl Command for MoveTo { 64 type AnsiType = String; 65 ansi_code(&self) -> Self::AnsiType66 fn ansi_code(&self) -> Self::AnsiType { 67 ansi::move_to_csi_sequence(self.0, self.1) 68 } 69 70 #[cfg(windows)] execute_winapi(&self) -> Result<()>71 fn execute_winapi(&self) -> Result<()> { 72 sys::move_to(self.0, self.1) 73 } 74 } 75 76 /// A command that moves the terminal cursor a given number of rows up. 77 /// 78 /// # Notes 79 /// 80 /// Commands must be executed/queued for execution otherwise they do nothing. 81 pub struct MoveUp(pub u16); 82 83 impl Command for MoveUp { 84 type AnsiType = String; 85 ansi_code(&self) -> Self::AnsiType86 fn ansi_code(&self) -> Self::AnsiType { 87 ansi::move_up_csi_sequence(self.0) 88 } 89 90 #[cfg(windows)] execute_winapi(&self) -> Result<()>91 fn execute_winapi(&self) -> Result<()> { 92 sys::move_up(self.0) 93 } 94 } 95 96 /// A command that moves the terminal cursor a given number of rows down. 97 /// 98 /// # Notes 99 /// 100 /// Commands must be executed/queued for execution otherwise they do nothing. 101 pub struct MoveDown(pub u16); 102 103 impl Command for MoveDown { 104 type AnsiType = String; 105 ansi_code(&self) -> Self::AnsiType106 fn ansi_code(&self) -> Self::AnsiType { 107 ansi::move_down_csi_sequence(self.0) 108 } 109 110 #[cfg(windows)] execute_winapi(&self) -> Result<()>111 fn execute_winapi(&self) -> Result<()> { 112 sys::move_down(self.0) 113 } 114 } 115 116 /// A command that moves the terminal cursor a given number of columns to the left. 117 /// 118 /// # Notes 119 /// 120 /// Commands must be executed/queued for execution otherwise they do nothing. 121 pub struct MoveLeft(pub u16); 122 123 impl Command for MoveLeft { 124 type AnsiType = String; 125 ansi_code(&self) -> Self::AnsiType126 fn ansi_code(&self) -> Self::AnsiType { 127 ansi::move_left_csi_sequence(self.0) 128 } 129 130 #[cfg(windows)] execute_winapi(&self) -> Result<()>131 fn execute_winapi(&self) -> Result<()> { 132 sys::move_left(self.0) 133 } 134 } 135 136 /// A command that moves the terminal cursor a given number of columns to the right. 137 /// 138 /// # Notes 139 /// 140 /// Commands must be executed/queued for execution otherwise they do nothing. 141 pub struct MoveRight(pub u16); 142 143 /// A command that saves the current terminal cursor position. 144 /// 145 /// See the [RestorePosition](./struct.RestorePosition.html) command. 146 /// 147 /// # Notes 148 /// 149 /// - The cursor position is stored globally. 150 /// - Commands must be executed/queued for execution otherwise they do nothing. 151 pub struct SavePosition; 152 153 impl Command for MoveRight { 154 type AnsiType = String; 155 ansi_code(&self) -> Self::AnsiType156 fn ansi_code(&self) -> Self::AnsiType { 157 ansi::move_right_csi_sequence(self.0) 158 } 159 160 #[cfg(windows)] execute_winapi(&self) -> Result<()>161 fn execute_winapi(&self) -> Result<()> { 162 sys::move_right(self.0) 163 } 164 } 165 166 impl Command for SavePosition { 167 type AnsiType = &'static str; 168 ansi_code(&self) -> Self::AnsiType169 fn ansi_code(&self) -> Self::AnsiType { 170 ansi::SAVE_POSITION_CSI_SEQUENCE 171 } 172 173 #[cfg(windows)] execute_winapi(&self) -> Result<()>174 fn execute_winapi(&self) -> Result<()> { 175 sys::save_position() 176 } 177 } 178 179 /// A command that restores the saved terminal cursor position. 180 /// 181 /// See the [SavePosition](./struct.SavePosition.html) command. 182 /// 183 /// # Notes 184 /// 185 /// - The cursor position is stored globally. 186 /// - Commands must be executed/queued for execution otherwise they do nothing. 187 pub struct RestorePosition; 188 189 impl Command for RestorePosition { 190 type AnsiType = &'static str; 191 ansi_code(&self) -> Self::AnsiType192 fn ansi_code(&self) -> Self::AnsiType { 193 ansi::RESTORE_POSITION_CSI_SEQUENCE 194 } 195 196 #[cfg(windows)] execute_winapi(&self) -> Result<()>197 fn execute_winapi(&self) -> Result<()> { 198 sys::restore_position() 199 } 200 } 201 202 /// A command that hides the terminal cursor. 203 /// 204 /// # Notes 205 /// 206 /// - Commands must be executed/queued for execution otherwise they do nothing. 207 pub struct Hide; 208 209 impl Command for Hide { 210 type AnsiType = &'static str; 211 ansi_code(&self) -> Self::AnsiType212 fn ansi_code(&self) -> Self::AnsiType { 213 ansi::HIDE_CSI_SEQUENCE 214 } 215 216 #[cfg(windows)] execute_winapi(&self) -> Result<()>217 fn execute_winapi(&self) -> Result<()> { 218 sys::show_cursor(false) 219 } 220 } 221 222 /// A command that shows the terminal cursor. 223 /// 224 /// # Notes 225 /// 226 /// - Commands must be executed/queued for execution otherwise they do nothing. 227 pub struct Show; 228 229 impl Command for Show { 230 type AnsiType = &'static str; 231 ansi_code(&self) -> Self::AnsiType232 fn ansi_code(&self) -> Self::AnsiType { 233 ansi::SHOW_CSI_SEQUENCE 234 } 235 236 #[cfg(windows)] execute_winapi(&self) -> Result<()>237 fn execute_winapi(&self) -> Result<()> { 238 sys::show_cursor(true) 239 } 240 } 241 242 /// A command that enables blinking of the terminal cursor. 243 /// 244 /// # Notes 245 /// 246 /// - Windows versions lower than Windows 10 do not support this functionality. 247 /// - Commands must be executed/queued for execution otherwise they do nothing. 248 pub struct EnableBlinking; 249 250 impl Command for EnableBlinking { 251 type AnsiType = &'static str; 252 ansi_code(&self) -> Self::AnsiType253 fn ansi_code(&self) -> Self::AnsiType { 254 ansi::ENABLE_BLINKING_CSI_SEQUENCE 255 } 256 257 #[cfg(windows)] execute_winapi(&self) -> Result<()>258 fn execute_winapi(&self) -> Result<()> { 259 Ok(()) 260 } 261 } 262 263 /// A command that disables blinking of the terminal cursor. 264 /// 265 /// # Notes 266 /// 267 /// - Windows versions lower than Windows 10 do not support this functionality. 268 /// - Commands must be executed/queued for execution otherwise they do nothing. 269 pub struct DisableBlinking; 270 271 impl Command for DisableBlinking { 272 type AnsiType = &'static str; 273 ansi_code(&self) -> Self::AnsiType274 fn ansi_code(&self) -> Self::AnsiType { 275 ansi::DISABLE_BLINKING_CSI_SEQUENCE 276 } 277 278 #[cfg(windows)] execute_winapi(&self) -> Result<()>279 fn execute_winapi(&self) -> Result<()> { 280 Ok(()) 281 } 282 } 283 284 impl_display!(for MoveTo); 285 impl_display!(for MoveUp); 286 impl_display!(for MoveDown); 287 impl_display!(for MoveLeft); 288 impl_display!(for MoveRight); 289 impl_display!(for SavePosition); 290 impl_display!(for RestorePosition); 291 impl_display!(for Hide); 292 impl_display!(for Show); 293 impl_display!(for EnableBlinking); 294 impl_display!(for DisableBlinking); 295 296 #[cfg(test)] 297 mod tests { 298 use std::io::{self, stdout, Write}; 299 300 use crate::execute; 301 302 use super::{ 303 position, MoveDown, MoveLeft, MoveRight, MoveTo, MoveUp, RestorePosition, SavePosition, 304 }; 305 306 // Test is disabled, because it's failing on Travis 307 #[test] 308 #[ignore] test_move_to()309 fn test_move_to() { 310 let (saved_x, saved_y) = position().unwrap(); 311 312 execute!(stdout(), MoveTo(saved_x + 1, saved_y + 1)).unwrap(); 313 assert_eq!(position().unwrap(), (saved_x + 1, saved_y + 1)); 314 315 execute!(stdout(), MoveTo(saved_x, saved_y)).unwrap(); 316 assert_eq!(position().unwrap(), (saved_x, saved_y)); 317 } 318 319 // Test is disabled, because it's failing on Travis 320 #[test] 321 #[ignore] test_move_right()322 fn test_move_right() { 323 let (saved_x, saved_y) = position().unwrap(); 324 execute!(io::stdout(), MoveRight(1)).unwrap(); 325 assert_eq!(position().unwrap(), (saved_x + 1, saved_y)); 326 } 327 328 // Test is disabled, because it's failing on Travis 329 #[test] 330 #[ignore] test_move_left()331 fn test_move_left() { 332 execute!(stdout(), MoveTo(2, 0), MoveLeft(2)).unwrap(); 333 assert_eq!(position().unwrap(), (0, 0)); 334 } 335 336 // Test is disabled, because it's failing on Travis 337 #[test] 338 #[ignore] test_move_up()339 fn test_move_up() { 340 execute!(stdout(), MoveTo(0, 2), MoveUp(2)).unwrap(); 341 assert_eq!(position().unwrap(), (0, 0)); 342 } 343 344 // Test is disabled, because it's failing on Travis 345 #[test] 346 #[ignore] test_move_down()347 fn test_move_down() { 348 execute!(stdout(), MoveTo(0, 0), MoveDown(2)).unwrap(); 349 350 assert_eq!(position().unwrap(), (0, 2)); 351 } 352 353 // Test is disabled, because it's failing on Travis 354 #[test] 355 #[ignore] test_save_restore_position()356 fn test_save_restore_position() { 357 let (saved_x, saved_y) = position().unwrap(); 358 359 execute!( 360 stdout(), 361 SavePosition, 362 MoveTo(saved_x + 1, saved_y + 1), 363 RestorePosition 364 ) 365 .unwrap(); 366 367 let (x, y) = position().unwrap(); 368 369 assert_eq!(x, saved_x); 370 assert_eq!(y, saved_y); 371 } 372 } 373