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
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
#![deny(unused_imports, unused_must_use)]

//! # Screen
//!
//! **The `crossterm_screen` crate is deprecated and no longer maintained. The GitHub repository will
//! be archived soon. All the code is being moved to the `crossterm`
//! [crate](https://github.com/crossterm-rs/crossterm). You can learn more in
//! the [Merge sub-crates to the crossterm crate](https://github.com/crossterm-rs/crossterm/issues/265)
//! issue.**
//!
//! The `crossterm_screen` crate provides the functionality to work with the terminal screen.
//!
//! 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
//! [examples](https://github.com/crossterm-rs/examples) repository
//! to demonstrate the capabilities.
//!
//! ## Screen Buffer
//!
//! A screen buffer is a two-dimensional array of characters and color data to be output in a console window.
//! A terminal can have multiple of those screen buffers, and the active screen buffer is the one that is
//! displayed on the screen.
//!
//! Crossterm allows you to switch between those buffers; the screen you are working in is called the
//! 'main screen'. We call the other screen the 'alternate screen'. One note to take is that crossterm
//! does not support the creation and switching between several buffers.
//!
//! ### Alternate Screen
//!
//! Normally you are working on the main screen but an alternate screen is somewhat different from a
//! normal screen. For example, it has the exact dimensions of the terminal window, without any
//! scroll back region. An example of this is vim when it is launched from bash.
//!
//! Vim uses the entirety of the screen to edit the file, then exits to bash leaving the original buffer unchanged.
//!
//! Crossterm provides the ability to switch to the alternate screen, make some changes, and then go back
//! to the main screen. The main screen will still have its original data since we made all the edits on
//! the alternate screen.
//!
//! ### Raw Mode
//!
//! By default, the terminal behaves in a certain way.
//! You can think of going to a new line if the input is at the end of the current line, or interpreting backspace
//! to remove letters. Sometimes it can be useful to disable these modes because this is undesirable.
//! This may be undesirable if your application wants to read the input without it being shown on the screen.
//! Raw modes are the modes to create this possibility.
//
//! Those modes will be set when enabling raw modes:
//!
//! - Input will not be forwarded to screen
//! - Input will not be processed on enter press
//! - Input will not be line buffered (input sent byte-by-byte to input buffer)
//! - Special keys like backspace and CTL+C will not be processed by terminal driver
//! - New line character will not be processed therefore `println!` can't be used, use `write!` instead

// This brings the trait into scope, so we're able to call enter()/leave(),
// but it it's false positive for unused_imports check
#[allow(unused_imports)]
use alternate::AlternateScreen as _;
#[doc(no_inline)]
pub use crossterm_utils::{
    execute, queue, Command, ErrorKind, ExecutableCommand, QueueableCommand, Result,
};

pub use self::raw::{IntoRawMode, RawScreen};

mod alternate;
mod raw;
mod sys;

/// An alternate screen.
///
/// With this type, you will be able to switch to the alternate screen and then back to
/// the main screen.
///
/// Be aware that you'll be switched back to the main screen when you drop the
/// `AlternateScreen` value.
///
/// It's recommended to use the command API. See the
/// [`EnterAlternateScreen`](struct.EnterAlternateScreen.html)
/// and [`LeaveAlternateScreen`](struct.LeaveAlternateScreen.html)
/// commands documentation for more info.
///
/// # Examples
///
/// Alternate screen with raw mode enabled:
///
/// ```no_run
/// use crossterm_screen::AlternateScreen;
/// use crossterm_utils::Result;
///
/// fn main() -> Result<()> {
///     let _alternate = AlternateScreen::to_alternate(true)?;
///
///     // Do something on the alternate screen in the raw mode
///
///     Ok(())
/// } // `_alternate` dropped here <- raw mode disabled & back to main screen
/// ```
pub struct AlternateScreen {
    #[cfg(windows)]
    alternate: Box<(dyn alternate::AlternateScreen + Sync + Send)>,
    #[cfg(unix)]
    alternate: alternate::AnsiAlternateScreen,
    raw_screen: Option<RawScreen>,
}

impl AlternateScreen {
    /// Switches to the alternate screen.
    ///
    /// # Arguments
    ///
    /// * `raw_mode` - `true` enables the raw mode as well
    ///
    /// # Notes
    ///
    /// You'll be automatically switched to the main screen if this function
    /// fails.
    pub fn to_alternate(raw_mode: bool) -> Result<AlternateScreen> {
        let alternate = alternate::alternate_screen();
        alternate.enter()?;

        let mut alternate = AlternateScreen {
            alternate,
            raw_screen: None,
        };

        if raw_mode {
            // If into_raw_mode fails, `alternate` will be dropped and
            // we'll switch back to the main screen.
            alternate.raw_screen = Some(RawScreen::into_raw_mode()?);
        }

        Ok(alternate)
    }

    /// Switches to the main screen.
    pub fn to_main(&self) -> Result<()> {
        self.alternate.leave()
    }
}

impl Drop for AlternateScreen {
    fn drop(&mut self) {
        let _ = self.to_main();
    }
}

/// A command to switch to the alternate screen.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
///
/// # Examples
///
/// ```no_run
/// use std::io::{stdout, Write};
/// use crossterm_screen::{execute, Result, EnterAlternateScreen, LeaveAlternateScreen};
///
/// fn main() -> Result<()> {
///     execute!(stdout(), EnterAlternateScreen)?;
///
///     // Do anything on the alternate screen
///
///     execute!(stdout(), LeaveAlternateScreen)
/// }
/// ```
pub struct EnterAlternateScreen;

impl Command for EnterAlternateScreen {
    type AnsiType = &'static str;

    fn ansi_code(&self) -> Self::AnsiType {
        alternate::ansi::ENTER_ALTERNATE_SCREEN_CSI_SEQUENCE
    }

    #[cfg(windows)]
    fn execute_winapi(&self) -> Result<()> {
        let alternate = alternate::alternate_screen();
        alternate.enter()
    }
}

/// A command to switch back to the main screen.
///
/// # Notes
///
/// Commands must be executed/queued for execution otherwise they do nothing.
///
/// # Examples
///
/// ```no_run
/// use std::io::{stdout, Write};
/// use crossterm_screen::{execute, Result, EnterAlternateScreen, LeaveAlternateScreen};
///
/// fn main() -> Result<()> {
///     execute!(stdout(), EnterAlternateScreen)?;
///
///     // Do anything on the alternate screen
///
///     execute!(stdout(), LeaveAlternateScreen)
/// }
/// ```
pub struct LeaveAlternateScreen;

impl Command for LeaveAlternateScreen {
    type AnsiType = &'static str;

    fn ansi_code(&self) -> Self::AnsiType {
        alternate::ansi::LEAVE_ALTERNATE_SCREEN_CSI_SEQUENCE
    }

    #[cfg(windows)]
    fn execute_winapi(&self) -> Result<()> {
        let alternate = alternate::alternate_screen();
        alternate.leave()
    }
}