diff --git a/CHANGELOG.md b/CHANGELOG.md
index 253474d..8b0f08f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,7 +1,20 @@
-# Next Version
-
-- Derived 'Copy' for 'KeyEvent'
+# Master
+- `input` module
+ - Derive 'Copy' for 'KeyEvent'
+- `cursor` module
+ - Remove `TerminalCursor`, `cursor`, `Crossterm::cursor()`
+ - Introduce static function `crossterm::cursor::position` in place of `TerminalCursor::pos`
+ - Rename `Goto` to `MoveTo`
+ - Rename `Up` to `MoveLeft`
+ - Rename `Right` to `MoveRight`
+ - Rename `Down` to `MoveDown`
+ - Rename `BlinkOn` to `EnableBlinking`
+ - Rename `BlinkOff` to `DisableBlinking`
+ - Rename `ResetPos` to `ResetPosition`
+ - Rename `SavePos` to `SavePosition`
+ - Remove re-export cursor module types at root level, are now accessible from `crossterm::cursor`
+
# Version 0.12.1
- All the `crossterm_` crates code was moved to the `crossterm` crate
diff --git a/src/crossterm.rs b/src/crossterm.rs
index e25eee7..8a8ad9c 100644
--- a/src/crossterm.rs
+++ b/src/crossterm.rs
@@ -10,12 +10,6 @@ impl Crossterm {
Crossterm
}
- /// Crates a new `TerminalCursor`.
- #[cfg(feature = "cursor")]
- pub fn cursor(&self) -> crate::cursor::TerminalCursor {
- crate::cursor::TerminalCursor::new()
- }
-
/// Creates a new `TerminalInput`.
#[cfg(feature = "input")]
pub fn input(&self) -> crate::input::TerminalInput {
diff --git a/src/cursor.rs b/src/cursor.rs
index 01de11c..58b3f73 100644
--- a/src/cursor.rs
+++ b/src/cursor.rs
@@ -1,6 +1,6 @@
//! # Cursor
//!
-//! The `cursor` module provides a functionality to work with the terminal cursor.
+//! The `cursor` module provides functionality to work with the terminal cursor.
//!
//! This documentation does not contain a lot of examples. The reason is that it's fairly
//! obvious how to use this crate. Although, we do provide
@@ -9,239 +9,79 @@
//!
//! ## Examples
//!
-//! Basic usage:
-//!
-//! ```no_run
-//! // You can replace the following line with `use crossterm::TerminalCursor;`
-//! // if you're using the `crossterm` crate with the `cursor` feature enabled.
-//! use crossterm::{Result, TerminalCursor};
-//!
-//! fn main() -> Result<()> {
-//! // Get a cursor, save position
-//! let cursor = TerminalCursor::new();
-//! cursor.save_position()?;
-//!
-//! // Do something with the cursor
-//! cursor.goto(10, 10)?;
-//! cursor.blink(true)?;
-//!
-//! // Be a good citizen, cleanup
-//! cursor.blink(false)?;
-//! cursor.restore_position()
-//! }
-//! ```
-//!
-//! Commands:
+//! Cursor actions can be performed with commands.
+//! Please have a look at [command documention](../index.html#command-api) for a more detailed documentation.
//!
//! ```no_run
//! use std::io::{stdout, Write};
//!
-//! use crossterm::{BlinkOff, BlinkOn, execute, Goto, ResetPos, Result, SavePos};
-//!
+//! use crossterm::{
+//! ExecutableCommand, execute, Result,
+//! cursor::{DisableBlinking, EnableBlinking, MoveTo, RestorePosition, SavePosition}
+//! };
//!
//! fn main() -> Result<()> {
+//! // with macro
//! execute!(
//! stdout(),
-//! SavePos,
-//! Goto(10, 10),
-//! BlinkOn,
-//! BlinkOff,
-//! ResetPos
-//! )
+//! SavePosition,
+//! MoveTo(10, 10),
+//! EnableBlinking,
+//! DisableBlinking,
+//! RestorePosition
+//! );
+//!
+//! // with function
+//! stdout()
+//! .execute(MoveTo(11,11))?
+//! .execute(RestorePosition);
+//!
+//! Ok(())
//! }
//! ```
-use cursor::ansi::{self, AnsiCursor};
-#[cfg(windows)]
-use cursor::windows::WinApiCursor;
-use cursor::Cursor;
+//!
+//! For manual execution control check out [crossterm::queue](../macro.queue.html).
+
+pub use sys::position;
use crate::impl_display;
#[cfg(windows)]
-use crate::utils::supports_ansi;
-use crate::utils::{Command, Result};
+use crate::utils::Result;
-mod cursor;
-mod sys;
+use crate::utils::Command;
-/// A terminal cursor.
-///
-/// The `TerminalCursor` instance is stateless and does not hold any data.
-/// You can create as many instances as you want and they will always refer to the
-/// same terminal cursor.
-///
-/// The cursor position is 0 based. For example `0` means first column/row, `1`
-/// second column/row, etc.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```no_run
-/// use crossterm::{Result, TerminalCursor};
-///
-/// fn main() -> Result<()> {
-/// let cursor = TerminalCursor::new();
-/// cursor.save_position()?;
-///
-/// cursor.goto(10, 10)?;
-/// cursor.blink(true)?;
-///
-/// cursor.blink(false)?;
-/// cursor.restore_position()
-/// }
-/// ```
-pub struct TerminalCursor {
- #[cfg(windows)]
- cursor: Box<(dyn Cursor + Sync + Send)>,
- #[cfg(unix)]
- cursor: AnsiCursor,
-}
+mod ansi;
+pub(crate) mod sys;
-impl TerminalCursor {
- /// Creates a new `TerminalCursor`.
- pub fn new() -> TerminalCursor {
- #[cfg(windows)]
- let cursor = if supports_ansi() {
- Box::new(AnsiCursor::new()) as Box<(dyn Cursor + Sync + Send)>
- } else {
- Box::new(WinApiCursor::new()) as Box<(dyn Cursor + Sync + Send)>
- };
-
- #[cfg(unix)]
- let cursor = AnsiCursor::new();
-
- TerminalCursor { cursor }
- }
-
- /// Moves the cursor to the given position.
- pub fn goto(&self, column: u16, row: u16) -> Result<()> {
- self.cursor.goto(column, row)
- }
-
- /// Returns the cursor position (`(column, row)` tuple).
- pub fn pos(&self) -> Result<(u16, u16)> {
- self.cursor.pos()
- }
-
- /// Moves the cursor `row_count` times up.
- pub fn move_up(&mut self, row_count: u16) -> Result<&mut TerminalCursor> {
- self.cursor.move_up(row_count)?;
- Ok(self)
- }
-
- /// Moves the cursor `col_count` times right.
- pub fn move_right(&mut self, col_count: u16) -> Result<&mut TerminalCursor> {
- self.cursor.move_right(col_count)?;
- Ok(self)
- }
-
- /// Moves the cursor `row_count` times down.
- pub fn move_down(&mut self, row_count: u16) -> Result<&mut TerminalCursor> {
- self.cursor.move_down(row_count)?;
- Ok(self)
- }
-
- /// Moves the cursor `col_count` times left.
- pub fn move_left(&mut self, col_count: u16) -> Result<&mut TerminalCursor> {
- self.cursor.move_left(col_count)?;
- Ok(self)
- }
-
- /// Saves the cursor position.
- ///
- /// See the [restore_position](struct.TerminalCursor.html#method.restore_position) method.
- ///
- /// # Notes
- ///
- /// The cursor position is stored globally and is not related to the current/any
- /// `TerminalCursor` instance.
- pub fn save_position(&self) -> Result<()> {
- self.cursor.save_position()
- }
-
- /// Restores the saved cursor position.
- ///
- /// See the [save_position](struct.TerminalCursor.html#method.save_position) method.
- pub fn restore_position(&self) -> Result<()> {
- self.cursor.restore_position()
- }
-
- /// Hides the cursor.
- ///
- /// See the [show](struct.TerminalCursor.html#method.show) method.
- pub fn hide(&self) -> Result<()> {
- self.cursor.hide()
- }
-
- /// Shows the cursor.
- ///
- /// See the [hide](struct.TerminalCursor.html#method.hide) method.
- pub fn show(&self) -> Result<()> {
- self.cursor.show()
- }
-
- /// Enables or disables the cursor blinking.
- ///
- /// # Notes
- ///
- /// Windows versions lower than Windows 10 do not support this functionality.
- pub fn blink(&self, blink: bool) -> Result<()> {
- self.cursor.blink(blink)
- }
-}
-
-/// Creates a new `TerminalCursor`.
-///
-/// # Examples
-///
-/// Basic usage:
-///
-/// ```no_run
-/// use crossterm::{cursor, Result};
-///
-/// fn main() -> Result<()> {
-/// let cursor = cursor();
-/// cursor.save_position()?;
-///
-/// cursor.goto(10, 10)?;
-/// cursor.blink(true)?;
-///
-/// cursor.blink(false)?;
-/// cursor.restore_position()
-/// }
-/// ```
-pub fn cursor() -> TerminalCursor {
- TerminalCursor::new()
-}
-
-/// A command to move the cursor to the given position.
+/// A command that moves the terminal cursor to the given position (column, row).
///
/// # Notes
///
-/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct Goto(pub u16, pub u16);
+/// * Top left cell is represented as `0,0`.
+/// * Commands must be executed/queued for execution otherwise they do nothing.
+pub struct MoveTo(pub u16, pub u16);
-impl Command for Goto {
+impl Command for MoveTo {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
- ansi::goto_csi_sequence(self.0, self.1)
+ ansi::move_to_csi_sequence(self.0, self.1)
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().goto(self.0, self.1)
+ sys::move_to(self.0, self.1)
}
}
-/// A command to move the cursor given rows up.
+/// A command that moves the terminal cursor a given number of rows up.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct Up(pub u16);
+pub struct MoveUp(pub u16);
-impl Command for Up {
+impl Command for MoveUp {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
@@ -250,18 +90,18 @@ impl Command for Up {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().move_up(self.0)
+ sys::move_up(self.0)
}
}
-/// A command to move the cursor given rows down.
+/// A command that moves the terminal cursor a given number of rows down.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct Down(pub u16);
+pub struct MoveDown(pub u16);
-impl Command for Down {
+impl Command for MoveDown {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
@@ -270,18 +110,18 @@ impl Command for Down {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().move_down(self.0)
+ sys::move_down(self.0)
}
}
-/// A command to move the cursor given columns left.
+/// A command that moves the terminal cursor a given number of columns to the left.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct Left(pub u16);
+pub struct MoveLeft(pub u16);
-impl Command for Left {
+impl Command for MoveLeft {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
@@ -290,18 +130,28 @@ impl Command for Left {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().move_left(self.0)
+ sys::move_left(self.0)
}
}
-/// A command to move the cursor given columns right.
+/// A command that moves the terminal cursor a given number of columns to the right.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct Right(pub u16);
+pub struct MoveRight(pub u16);
-impl Command for Right {
+/// A command that saves the current terminal cursor position.
+///
+/// See the [RestorePosition](./struct.RestorePosition.html) command.
+///
+/// # Notes
+///
+/// - The cursor position is stored globally.
+/// - Commands must be executed/queued for execution otherwise they do nothing.
+pub struct SavePosition;
+
+impl Command for MoveRight {
type AnsiType = String;
fn ansi_code(&self) -> Self::AnsiType {
@@ -310,21 +160,11 @@ impl Command for Right {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().move_right(self.0)
+ sys::move_right(self.0)
}
}
-/// A command to save the cursor position.
-///
-/// # Notes
-///
-/// The cursor position is stored globally and is not related to the current/any
-/// `TerminalCursor` instance.
-///
-/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct SavePos;
-
-impl Command for SavePos {
+impl Command for SavePosition {
type AnsiType = &'static str;
fn ansi_code(&self) -> Self::AnsiType {
@@ -333,18 +173,21 @@ impl Command for SavePos {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().save_position()
+ sys::save_position()
}
}
-/// A command to restore the saved cursor position.
+/// A command that restores the saved terminal cursor position.
+///
+/// See the [SavePosition](./struct.SavePosition.html) command.
///
/// # Notes
///
-/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct ResetPos;
+/// - The cursor position is stored globally.
+/// - Commands must be executed/queued for execution otherwise they do nothing.
+pub struct RestorePosition;
-impl Command for ResetPos {
+impl Command for RestorePosition {
type AnsiType = &'static str;
fn ansi_code(&self) -> Self::AnsiType {
@@ -353,18 +196,15 @@ impl Command for ResetPos {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().restore_position()
+ sys::restore_position()
}
}
-/// A command to hide the cursor.
+/// A command that hides the terminal cursor.
///
/// # Notes
///
-/// The cursor position is stored globally and is not related to the current/any
-/// `TerminalCursor` instance.
-///
-/// Commands must be executed/queued for execution otherwise they do nothing.
+/// - Commands must be executed/queued for execution otherwise they do nothing.
pub struct Hide;
impl Command for Hide {
@@ -376,18 +216,15 @@ impl Command for Hide {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().hide()
+ sys::show_cursor(false)
}
}
-/// A command to show the cursor.
+/// A command that shows the terminal cursor.
///
/// # Notes
///
-/// The cursor position is stored globally and is not related to the current/any
-/// `TerminalCursor` instance.
-///
-/// Commands must be executed/queued for execution otherwise they do nothing.
+/// - Commands must be executed/queued for execution otherwise they do nothing.
pub struct Show;
impl Command for Show {
@@ -399,24 +236,23 @@ impl Command for Show {
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
- WinApiCursor::new().show()
+ sys::show_cursor(true)
}
}
-/// A command to enable the cursor blinking.
+/// A command that enables blinking of the terminal cursor.
///
/// # Notes
///
-/// Windows versions lower than Windows 10 do not support this functionality.
-///
-/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct BlinkOn;
+/// - Windows versions lower than Windows 10 do not support this functionality.
+/// - Commands must be executed/queued for execution otherwise they do nothing.
+pub struct EnableBlinking;
-impl Command for BlinkOn {
+impl Command for EnableBlinking {
type AnsiType = &'static str;
fn ansi_code(&self) -> Self::AnsiType {
- ansi::BLINKING_ON_CSI_SEQUENCE
+ ansi::ENABLE_BLINKING_CSI_SEQUENCE
}
#[cfg(windows)]
@@ -425,20 +261,19 @@ impl Command for BlinkOn {
}
}
-/// A command to disable the cursor blinking.
+/// A command that disables blinking of the terminal cursor.
///
/// # Notes
///
-/// Windows versions lower than Windows 10 do not support this functionality.
-///
-/// Commands must be executed/queued for execution otherwise they do nothing.
-pub struct BlinkOff;
+/// - Windows versions lower than Windows 10 do not support this functionality.
+/// - Commands must be executed/queued for execution otherwise they do nothing.
+pub struct DisableBlinking;
-impl Command for BlinkOff {
+impl Command for DisableBlinking {
type AnsiType = &'static str;
fn ansi_code(&self) -> Self::AnsiType {
- ansi::BLINKING_OFF_CSI_SEQUENCE
+ ansi::DISABLE_BLINKING_CSI_SEQUENCE
}
#[cfg(windows)]
@@ -447,14 +282,90 @@ impl Command for BlinkOff {
}
}
-impl_display!(for Goto);
-impl_display!(for Up);
-impl_display!(for Down);
-impl_display!(for Left);
-impl_display!(for Right);
-impl_display!(for SavePos);
-impl_display!(for ResetPos);
+impl_display!(for MoveTo);
+impl_display!(for MoveUp);
+impl_display!(for MoveDown);
+impl_display!(for MoveLeft);
+impl_display!(for MoveRight);
+impl_display!(for SavePosition);
+impl_display!(for RestorePosition);
impl_display!(for Hide);
impl_display!(for Show);
-impl_display!(for BlinkOn);
-impl_display!(for BlinkOff);
+impl_display!(for EnableBlinking);
+impl_display!(for DisableBlinking);
+
+#[cfg(test)]
+mod tests {
+ use super::{
+ position, MoveDown, MoveLeft, MoveRight, MoveTo, MoveUp, RestorePosition, SavePosition,
+ };
+ use crate::execute;
+ use std::io::{self, stdout, Write};
+
+ // Test is disabled, because it's failing on Travis
+ #[test]
+ #[ignore]
+ fn test_move_to() {
+ let (saved_x, saved_y) = position().unwrap();
+
+ execute!(stdout(), MoveTo(saved_x + 1, saved_y + 1)).unwrap();
+ assert_eq!(position().unwrap(), (saved_x + 1, saved_y + 1));
+
+ execute!(stdout(), MoveTo(saved_x, saved_y)).unwrap();
+ assert_eq!(position().unwrap(), (saved_x, saved_y));
+ }
+
+ // Test is disabled, because it's failing on Travis
+ #[test]
+ #[ignore]
+ fn test_move_right() {
+ let (saved_x, saved_y) = position().unwrap();
+ execute!(io::stdout(), MoveRight(1)).unwrap();
+ assert_eq!(position().unwrap(), (saved_x + 1, saved_y));
+ }
+
+ // Test is disabled, because it's failing on Travis
+ #[test]
+ #[ignore]
+ fn test_move_left() {
+ execute!(stdout(), MoveTo(2, 0), MoveLeft(2)).unwrap();
+ assert_eq!(position().unwrap(), (0, 0));
+ }
+
+ // Test is disabled, because it's failing on Travis
+ #[test]
+ #[ignore]
+ fn test_move_up() {
+ execute!(stdout(), MoveTo(0, 2), MoveUp(2)).unwrap();
+ assert_eq!(position().unwrap(), (0, 0));
+ }
+
+ // Test is disabled, because it's failing on Travis
+ #[test]
+ #[ignore]
+ fn test_move_down() {
+ execute!(stdout(), MoveTo(0, 0), MoveDown(2)).unwrap();
+
+ assert_eq!(position().unwrap(), (0, 2));
+ }
+
+ // Test is disabled, because it's failing on Travis
+ #[test]
+ #[ignore]
+ fn test_save_restore_position() {
+ let (saved_x, saved_y) = position().unwrap();
+
+ execute!(
+ stdout(),
+ SavePosition,
+ MoveTo(saved_x + 1, saved_y + 1),
+ RestorePosition
+ )
+ .unwrap();
+
+ let (x, y) = position().unwrap();
+
+ assert_eq!(x, saved_x);
+ assert_eq!(y, saved_y);
+ }
+}
diff --git a/src/cursor/ansi.rs b/src/cursor/ansi.rs
new file mode 100644
index 0000000..5045a07
--- /dev/null
+++ b/src/cursor/ansi.rs
@@ -0,0 +1,30 @@
+//! This module provides cursor related ANSI escape codes.
+
+use crate::csi;
+
+pub(crate) fn move_to_csi_sequence(x: u16, y: u16) -> String {
+ format!(csi!("{};{}H"), y + 1, x + 1)
+}
+
+pub(crate) fn move_up_csi_sequence(count: u16) -> String {
+ format!(csi!("{}A"), count)
+}
+
+pub(crate) fn move_right_csi_sequence(count: u16) -> String {
+ format!(csi!("{}C"), count)
+}
+
+pub(crate) fn move_down_csi_sequence(count: u16) -> String {
+ format!(csi!("{}B"), count)
+}
+
+pub(crate) fn move_left_csi_sequence(count: u16) -> String {
+ format!(csi!("{}D"), count)
+}
+
+pub(crate) static SAVE_POSITION_CSI_SEQUENCE: &'static str = "\x1B7";
+pub(crate) static RESTORE_POSITION_CSI_SEQUENCE: &'static str = "\x1B8";
+pub(crate) static HIDE_CSI_SEQUENCE: &'static str = csi!("?25l");
+pub(crate) static SHOW_CSI_SEQUENCE: &'static str = csi!("?25h");
+pub(crate) static ENABLE_BLINKING_CSI_SEQUENCE: &'static str = csi!("?12h");
+pub(crate) static DISABLE_BLINKING_CSI_SEQUENCE: &'static str = csi!("?12l");
diff --git a/src/cursor/cursor.rs b/src/cursor/cursor.rs
deleted file mode 100644
index 331dd9c..0000000
--- a/src/cursor/cursor.rs
+++ /dev/null
@@ -1,45 +0,0 @@
-//! A module that contains all the actions related to cursor movement in the terminal.
-//! Like: moving the cursor position; saving and resetting the cursor position; hiding showing and control
-//! the blinking of the cursor.
-//!
-//! Note that positions of the cursor are 0 -based witch means that the coordinates (cells) starts counting from 0
-
-use crate::utils::Result;
-
-pub(crate) mod ansi;
-#[cfg(windows)]
-pub(crate) mod windows;
-
-///! This trait defines the actions that can be performed with the terminal cursor.
-///! This trait can be implemented so that a concrete implementation of the ITerminalCursor can fulfill
-///! the wishes to work on a specific platform.
-///!
-///! ## For example:
-///!
-///! This trait is implemented for `WinApi` (Windows specific) and `ANSI` (Unix specific),
-///! so that cursor related actions can be performed on both UNIX and Windows systems.
-pub(crate) trait Cursor: Sync + Send {
- /// Goto location (`x`, `y`) in the current terminal window.
- fn goto(&self, x: u16, y: u16) -> Result<()>;
- /// Get the cursor location `(x, y)` in the current terminal window.
- fn pos(&self) -> Result<(u16, u16)>;
- /// Move cursor `n` times up
- fn move_up(&self, count: u16) -> Result<()>;
- /// Move the cursor `n` times to the right.
- fn move_right(&self, count: u16) -> Result<()>;
- /// Move the cursor `n` times down.
- fn move_down(&self, count: u16) -> Result<()>;
- /// Move the cursor `n` times left.
- fn move_left(&self, count: u16) -> Result<()>;
- /// Save cursor position so that its saved position can be recalled later. Note that this position
- /// is stored program based not per instance of the cursor struct.
- fn save_position(&self) -> Result<()>;
- /// Return to saved cursor position
- fn restore_position(&self) -> Result<()>;
- /// Hide the terminal cursor.
- fn hide(&self) -> Result<()>;
- /// Show the terminal cursor
- fn show(&self) -> Result<()>;
- /// Enable or disable the blinking of the cursor.
- fn blink(&self, blink: bool) -> Result<()>;
-}
diff --git a/src/cursor/cursor/ansi.rs b/src/cursor/cursor/ansi.rs
deleted file mode 100644
index 6cefb7d..0000000
--- a/src/cursor/cursor/ansi.rs
+++ /dev/null
@@ -1,166 +0,0 @@
-//! This is an ANSI specific implementation for cursor related action.
-//! This module is used for windows 10 terminals and UNIX terminals by default.
-//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position etc.
-
-use crate::utils::Result;
-use crate::{csi, write_cout};
-
-use super::{
- super::sys::{get_cursor_position, show_cursor},
- Cursor,
-};
-
-pub(crate) fn goto_csi_sequence(x: u16, y: u16) -> String {
- format!(csi!("{};{}H"), y + 1, x + 1)
-}
-
-pub(crate) fn move_up_csi_sequence(count: u16) -> String {
- format!(csi!("{}A"), count)
-}
-
-pub(crate) fn move_right_csi_sequence(count: u16) -> String {
- format!(csi!("{}C"), count)
-}
-
-pub(crate) fn move_down_csi_sequence(count: u16) -> String {
- format!(csi!("{}B"), count)
-}
-
-pub(crate) fn move_left_csi_sequence(count: u16) -> String {
- format!(csi!("{}D"), count)
-}
-
-pub(crate) static SAVE_POSITION_CSI_SEQUENCE: &'static str = csi!("s");
-pub(crate) static RESTORE_POSITION_CSI_SEQUENCE: &'static str = csi!("u");
-pub(crate) static HIDE_CSI_SEQUENCE: &'static str = csi!("?25l");
-pub(crate) static SHOW_CSI_SEQUENCE: &'static str = csi!("?25h");
-pub(crate) static BLINKING_ON_CSI_SEQUENCE: &'static str = csi!("?12h");
-pub(crate) static BLINKING_OFF_CSI_SEQUENCE: &'static str = csi!("?12l");
-
-/// This struct is an ANSI implementation for cursor related actions.
-pub(crate) struct AnsiCursor;
-
-impl AnsiCursor {
- pub(crate) fn new() -> AnsiCursor {
- AnsiCursor
- }
-}
-
-impl Cursor for AnsiCursor {
- fn goto(&self, x: u16, y: u16) -> Result<()> {
- write_cout!(goto_csi_sequence(x, y))?;
- Ok(())
- }
-
- fn pos(&self) -> Result<(u16, u16)> {
- get_cursor_position()
- }
-
- fn move_up(&self, count: u16) -> Result<()> {
- write_cout!(move_up_csi_sequence(count))?;
- Ok(())
- }
-
- fn move_right(&self, count: u16) -> Result<()> {
- write_cout!(move_right_csi_sequence(count))?;
- Ok(())
- }
-
- fn move_down(&self, count: u16) -> Result<()> {
- write_cout!(move_down_csi_sequence(count))?;
- Ok(())
- }
-
- fn move_left(&self, count: u16) -> Result<()> {
- write_cout!(move_left_csi_sequence(count))?;
- Ok(())
- }
-
- fn save_position(&self) -> Result<()> {
- write_cout!(SAVE_POSITION_CSI_SEQUENCE)?;
- Ok(())
- }
-
- fn restore_position(&self) -> Result<()> {
- write_cout!(RESTORE_POSITION_CSI_SEQUENCE)?;
- Ok(())
- }
-
- fn hide(&self) -> Result<()> {
- show_cursor(false)?;
- Ok(())
- }
-
- fn show(&self) -> Result<()> {
- show_cursor(true)?;
- Ok(())
- }
-
- fn blink(&self, blink: bool) -> Result<()> {
- if blink {
- write_cout!(BLINKING_ON_CSI_SEQUENCE)?;
- } else {
- write_cout!(BLINKING_OFF_CSI_SEQUENCE)?;
- }
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{AnsiCursor, Cursor};
-
- // TODO - Test is ingored, because it's stalled on Travis CI
- #[test]
- #[ignore]
- fn test_save_restore_position() {
- if try_enable_ansi() {
- let cursor = AnsiCursor::new();
-
- let (saved_x, saved_y) = cursor.pos().unwrap();
-
- cursor.save_position().unwrap();
- cursor.goto(saved_x + 1, saved_y + 1).unwrap();
- cursor.restore_position().unwrap();
-
- let (x, y) = cursor.pos().unwrap();
-
- assert_eq!(x, saved_x);
- assert_eq!(y, saved_y);
- }
- }
-
- // TODO - Test is ingored, because it's stalled on Travis CI
- #[test]
- #[ignore]
- fn test_goto() {
- if try_enable_ansi() {
- let cursor = AnsiCursor::new();
-
- let (saved_x, saved_y) = cursor.pos().unwrap();
-
- cursor.goto(saved_x + 1, saved_y + 1).unwrap();
- assert_eq!(cursor.pos().unwrap(), (saved_x + 1, saved_y + 1));
-
- cursor.goto(saved_x, saved_y).unwrap();
- assert_eq!(cursor.pos().unwrap(), (saved_x, saved_y));
- }
- }
-
- fn try_enable_ansi() -> bool {
- #[cfg(windows)]
- {
- if cfg!(target_os = "windows") {
- use crate::utils::sys::winapi::ansi::set_virtual_terminal_processing;
-
- // if it is not listed we should try with WinApi to check if we do support ANSI-codes.
- match set_virtual_terminal_processing(true) {
- Ok(_) => return true,
- Err(_) => return false,
- }
- }
- }
-
- true
- }
-}
diff --git a/src/cursor/cursor/windows.rs b/src/cursor/cursor/windows.rs
deleted file mode 100644
index 69c26fc..0000000
--- a/src/cursor/cursor/windows.rs
+++ /dev/null
@@ -1,111 +0,0 @@
-//! This is a WINAPI specific implementation for cursor related actions.
-//! This module is used for Windows terminals that do not support ANSI escape codes.
-//! Note that the cursor position is 0 based. This means that we start counting at 0 when setting the cursor position.
-
-use crate::utils::Result;
-
-use super::{super::sys::windows::ScreenBufferCursor, Cursor};
-
-/// This struct is a windows implementation for cursor related actions.
-pub(crate) struct WinApiCursor;
-
-impl WinApiCursor {
- pub(crate) fn new() -> WinApiCursor {
- WinApiCursor
- }
-}
-
-impl Cursor for WinApiCursor {
- fn goto(&self, x: u16, y: u16) -> Result<()> {
- let cursor = ScreenBufferCursor::new()?;
- cursor.goto(x as i16, y as i16)?;
- Ok(())
- }
-
- fn pos(&self) -> Result<(u16, u16)> {
- let cursor = ScreenBufferCursor::new()?;
- Ok(cursor.position()?.into())
- }
-
- fn move_up(&self, count: u16) -> Result<()> {
- let (xpos, ypos) = self.pos()?;
- self.goto(xpos, ypos - count)?;
- Ok(())
- }
-
- fn move_right(&self, count: u16) -> Result<()> {
- let (xpos, ypos) = self.pos()?;
- self.goto(xpos + count, ypos)?;
- Ok(())
- }
-
- fn move_down(&self, count: u16) -> Result<()> {
- let (xpos, ypos) = self.pos()?;
- self.goto(xpos, ypos + count)?;
- Ok(())
- }
-
- fn move_left(&self, count: u16) -> Result<()> {
- let (xpos, ypos) = self.pos()?;
- self.goto(xpos - count, ypos)?;
- Ok(())
- }
-
- fn save_position(&self) -> Result<()> {
- ScreenBufferCursor::save_cursor_pos()?;
- Ok(())
- }
-
- fn restore_position(&self) -> Result<()> {
- ScreenBufferCursor::restore_cursor_pos()?;
- Ok(())
- }
-
- fn hide(&self) -> Result<()> {
- ScreenBufferCursor::new()?.set_visibility(false)?;
- Ok(())
- }
-
- fn show(&self) -> Result<()> {
- ScreenBufferCursor::new()?.set_visibility(true)?;
- Ok(())
- }
-
- fn blink(&self, _blink: bool) -> Result<()> {
- Ok(())
- }
-}
-
-#[cfg(test)]
-mod tests {
- use super::{Cursor, WinApiCursor};
-
- #[test]
- fn test_goto() {
- let cursor = WinApiCursor::new();
-
- let (saved_x, saved_y) = cursor.pos().unwrap();
-
- cursor.goto(saved_x + 1, saved_y + 1).unwrap();
- assert_eq!(cursor.pos().unwrap(), (saved_x + 1, saved_y + 1));
-
- cursor.goto(saved_x, saved_y).unwrap();
- assert_eq!(cursor.pos().unwrap(), (saved_x, saved_y));
- }
-
- #[test]
- fn test_save_restore_position() {
- let cursor = WinApiCursor::new();
-
- let (saved_x, saved_y) = cursor.pos().unwrap();
-
- cursor.save_position().unwrap();
- cursor.goto(saved_x + 1, saved_y + 1).unwrap();
- cursor.restore_position().unwrap();
-
- let (x, y) = cursor.pos().unwrap();
-
- assert_eq!(x, saved_x);
- assert_eq!(y, saved_y);
- }
-}
diff --git a/src/cursor/sys.rs b/src/cursor/sys.rs
index 466a250..a013e50 100644
--- a/src/cursor/sys.rs
+++ b/src/cursor/sys.rs
@@ -1,11 +1,14 @@
+//! This module provides platform related functions.
+
#[cfg(unix)]
-pub(crate) use self::unix::get_cursor_position;
-#[cfg(unix)]
-pub(crate) use self::unix::show_cursor;
+pub use self::unix::position;
#[cfg(windows)]
-pub(crate) use self::windows::get_cursor_position;
+pub use self::windows::position;
#[cfg(windows)]
-pub(crate) use self::windows::show_cursor;
+pub(crate) use self::windows::{
+ move_down, move_left, move_right, move_to, move_up, restore_position, save_position,
+ show_cursor,
+};
#[cfg(windows)]
pub(crate) mod windows;
diff --git a/src/cursor/sys/unix.rs b/src/cursor/sys/unix.rs
index a74aaab..239a01f 100644
--- a/src/cursor/sys/unix.rs
+++ b/src/cursor/sys/unix.rs
@@ -1,3 +1,5 @@
+//! UNIX related logic to cursor manipulation.
+
use std::io::{self, Write};
use crate::input::{InputEvent, TerminalInput};
@@ -5,38 +7,29 @@ use crate::utils::{
sys::unix::{disable_raw_mode, enable_raw_mode, is_raw_mode_enabled},
Result,
};
-use crate::{csi, write_cout};
-pub(crate) fn get_cursor_position() -> Result<(u16, u16)> {
+/// Returns the cursor position (column, row).
+///
+/// The top left cell is represented `0,0`.
+pub fn position() -> Result<(u16, u16)> {
if is_raw_mode_enabled() {
- pos_raw()
+ read_position_raw()
} else {
- pos()
+ read_position()
}
}
-pub(crate) fn show_cursor(show_cursor: bool) -> Result<()> {
- if show_cursor {
- write_cout!(csi!("?25h"))?;
- } else {
- write_cout!(csi!("?25l"))?;
- }
- Ok(())
-}
-
-fn pos() -> Result<(u16, u16)> {
+fn read_position() -> Result<(u16, u16)> {
enable_raw_mode()?;
- let pos = pos_raw();
+ let pos = read_position_raw();
disable_raw_mode()?;
pos
}
-fn pos_raw() -> Result<(u16, u16)> {
- // Where is the cursor?
- // Use `ESC [ 6 n`.
+fn read_position_raw() -> Result<(u16, u16)> {
+ // Use `ESC [ 6 n` to and retrieve the cursor position.
let mut stdout = io::stdout();
- // Write command
stdout.write_all(b"\x1B[6n")?;
stdout.flush()?;
diff --git a/src/cursor/sys/windows.rs b/src/cursor/sys/windows.rs
index 40b7572..90726e5 100644
--- a/src/cursor/sys/windows.rs
+++ b/src/cursor/sys/windows.rs
@@ -1,4 +1,4 @@
-//! This module handles some logic for cursor interaction in the windows console.
+//! WinApi related logic to cursor manipulation.
use std::io;
use std::sync::Mutex;
@@ -14,7 +14,14 @@ use lazy_static::lazy_static;
use crate::utils::Result;
-pub(crate) fn get_cursor_position() -> Result<(u16, u16)> {
+lazy_static! {
+ static ref SAVED_CURSOR_POS: Mutex