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
//! # Intro //! `term_cursor` is a crate for handling terminal cursor movement in a platform independent way. //! The supported platforms are: //! //! - `Windows` //! - `Linux` //! - `macOS` //! - `FreeBSD` //! - `OpenBSD` //! //! Throughout this crate X and Y are used to denote the coordinates of the cursor. //! X corresponds to columns and Y corresponds to rows. //! All tuples like `(i32, i32)` are interpreted as `(X, Y)`. //! //! # API //! This crate provides 2 APIs that can be used to achieve the same effects: //! //! - A functions based approach that provides very simple functions to directly interact with the terminal (see the functions `set_pos`, `get_pos` and `clear`). //! - A newtype pattern based approach that provies a bunch of types which all implement `std::fmt::Display` (see the structs section below). //! These types call the `set_pos`, `get_pos` and `clear` functions internally, when they get formatted. //! //! # Watch out! //! - Both APIs **always** operate on the "default" terminal that is bound to the process. //! In other words, on Windows `GetStdHandle(STD_OUTPUT_HANDLE)` is used, and on *NIX, the ANSI terminal communcation is done through `stdout` / `stdin`. //! - Drawing outside the boundaries of the buffer / terminal is **undefined behaviour**. use std::fmt::{Display, Formatter, Result as FmtResult, Error as FmtError}; use std::io; mod platform; /// The error generated by operations on the terminal. #[derive(Debug)] pub enum Error { /// A generic io error. Io(io::Error), /// An opaque, platform-implementation-specific error. PlatformSpecific, } impl From<io::Error> for Error { fn from(err: io::Error) -> Self { Error::Io(err) } } impl From<Error> for FmtError { fn from(_: Error) -> Self { FmtError } } /// A type that when `Display`ed, moves the cursor to the specified coordinates. #[derive(Clone, Copy)] pub struct Goto(pub i32, pub i32); impl Display for Goto { fn fmt(&self, _fmt: &mut Formatter) -> FmtResult { let Goto(x, y) = *self; platform::set_cursor_pos(x, y)?; Ok(()) } } /// A type that when `Display`ed, moves the cursor by the specified amounts. /// /// This moves the cursor to the specified coordinates, relative to it's previous position. #[derive(Clone, Copy)] pub struct Relative(pub i32, pub i32); impl Display for Relative { fn fmt(&self, _fmt: &mut Formatter) -> FmtResult { let (cur_x, cur_y) = platform::get_cursor_pos()?; let Relative(x, y) = *self; let (x, y) = (x + cur_x, y + cur_y); platform::set_cursor_pos(x, y)?; Ok(()) } } /// A type that when `Display`ed, moves the cursor left by the specified amount. /// /// This is identical to a `Relative(-val, 0)`. #[derive(Clone, Copy)] pub struct Left(pub i32); impl Display for Left { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { Relative(-self.0, 0).fmt(fmt) } } /// A type that when `Display`ed, moves the cursor right by the specified amount. /// /// This is identical to a `Relative(val, 0)`. #[derive(Clone, Copy)] pub struct Right(pub i32); impl Display for Right { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { Relative(self.0, 0).fmt(fmt) } } /// A type that when `Display`ed, moves the cursor up by the specified amount. /// /// This is identical to a `Relative(0, -val)`. #[derive(Clone, Copy)] pub struct Up(pub i32); impl Display for Up { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { Relative(0, -self.0).fmt(fmt) } } /// A type that when `Display`ed, moves the cursor down by the specified amount. /// /// This is identical to a `Relative(0, val)`. #[derive(Clone, Copy)] pub struct Down(pub i32); impl Display for Down { fn fmt(&self, fmt: &mut Formatter) -> FmtResult { Relative(0, self.0).fmt(fmt) } } /// A type that when `Display`ed, clears the entire terminal screen. /// /// In effect, this sets every terminal cell to a space `' '`. #[derive(Clone, Copy)] pub struct Clear; impl Display for Clear { fn fmt(&self, _fmt: &mut Formatter) -> FmtResult { platform::clear()?; Ok(()) } } /// Set the cursor position to the specified coordinates. pub fn set_pos(x: i32, y: i32) -> Result<(), Error> { platform::set_cursor_pos(x, y) } /// Get the current cursor position. /// /// The tuple returned contains the (x, y) coordinates of the cursor position. pub fn get_pos() -> Result<(i32, i32), Error> { platform::get_cursor_pos() } /// Clear the screen, i.e. setting every character in the terminal to a space `' '`. pub fn clear() -> Result<(), Error> { platform::clear() }