crossterm/src/shared/screen.rs
2018-07-01 22:43:43 +02:00

104 lines
3.3 KiB
Rust

//! This module contains all the logic for switching between alternate screen and main screen.
//!
//! *Nix style applications often utilize an alternate screen buffer, so that they can modify the entire contents of the buffer, without affecting the application that started them.
//! The alternate buffer is exactly the dimensions of the window, without any scrollback region.
//! For an example of this behavior, consider when vim is launched from bash.
//! Vim uses the entirety of the screen to edit the file, then returning to bash leaves the original buffer unchanged.
//!
//! !! Note: this module is only working for unix and windows 10 terminals only. If you are using windows 10 or lower do not implement this functionality. Work in progress...
//!
use shared::functions;
use state::commands::*;
use Context;
use std::io::{self, Write};
use std::rc::Rc;
pub struct AlternateScreen {
context: Rc<Context>,
command_id: u16,
}
impl AlternateScreen {
/// Get the alternate screen from the context.
/// By calling this method the current screen will be changed to the alternate screen.
/// And you get back an handle for that screen.
pub fn from(context: Rc<Context>) -> Self {
let command_id = get_to_alternate_screen_command(context.clone());
let screen = AlternateScreen {
context: context,
command_id: command_id,
};
screen.to_alternate();
return screen;
}
/// Change the current screen to the mainscreen.
pub fn to_main(&self) {
let mut mutex = &self.context.state_manager;
{
let mut state_manager = mutex.lock().unwrap();
let mut mx = &state_manager.get(self.command_id);
{
let mut command = mx.lock().unwrap();
command.undo();
}
}
}
/// Change the current screen to alternate screen.
pub fn to_alternate(&self) {
let mut mutex = &self.context.state_manager;
{
let mut state_manager = mutex.lock().unwrap();
let mut mx = &state_manager.get(self.command_id);
{
let mut command = mx.lock().unwrap();
command.execute();
}
}
}
}
impl Write for AlternateScreen {
fn write(&mut self, buf: &[u8]) -> io::Result<usize> {
let mut screen = self.context.screen_manager.lock().unwrap();
{
screen.write(buf)
}
}
fn flush(&mut self) -> io::Result<()> {
let mut screen = self.context.screen_manager.lock().unwrap();
{
screen.flush()
}
}
}
impl Drop for AlternateScreen {
fn drop(&mut self) {
use CommandManager;
CommandManager::undo(self.context.clone(), self.command_id);
}
}
// Get the alternate screen command to enable and disable alternate screen based on the current platform
fn get_to_alternate_screen_command(context: Rc<Context>) -> u16 {
#[cfg(target_os = "windows")]
let command_id = functions::get_module::<u16>(
win_commands::ToAlternateScreenBufferCommand::new(context.clone()),
shared_commands::ToAlternateScreenBufferCommand::new(context.clone()),
).unwrap();
#[cfg(not(target_os = "windows"))]
let command_id = shared_commands::ToAlternateScreenBufferCommand::new(context.clone());
return command_id;
}