6.0 KiB
What is the Context
all about? This Context
has several reasons why it is introduced into crossterm version 0.2.3
.
These points are related to the features like Alternatescreen
and managing the terminal state.
-
At first
Terminal state
:Because this is a terminal manipulating library there will be made changes to terminal when running an process. If you stop the process you want the terminal back in its original state. Therefore, I need to track the changes made to the terminal.
-
At second
Handle to the console
In Rust we can call
stdout()
to get an handle to the current default console handle. For example when in unix systems you want to print something to the main screen you can use the following code:write!(std::io::stdout(), "{}", "some text").
But things change when we are in alternate screen modes. We can not simply use
stdout()
to get a handle to the alternate screen, since this call returns the current default console handle (mainscreen).Instead we need to store an handle to the screen output. This handle could be used to put into alternate screen modes and back into main screen modes. Through this stored handle Crossterm can execute its command on the current screen whether it be alternate screen or main screen.
For unix systems we store the handle gotten from
stdout()
for windows systems that are not supporting ANSI escape codes we store WinApiHANDLE
struct witch will provide access to the current screen.
So to recap this Context
struct is a wrapper for a type that manges terminal state changes.
When this Context
goes out of scope all changes made will be undone.
Also is this Context
is a wrapper for access to the current console screen.
Because Crossterm needs access to the above to types quite often I have chosen to add those two in one struct called Context
so that this type could be shared throughout library.
Check this link for more info: cleanup of the changes.
Now the user has to pass an context type to the modules of Crossterm like this:
let context = Context::new();
let cursor = cursor(&context);
let terminal = terminal(&context);
let color = color(&context);
Check the documentation of AlternateScreen
for more info about how to properly manage the Context
of the terminal.
If you don't use alternate screen functionalist's please checkout the Crossterm
documentation whits will make things easier for you.
Because this looks a little odd I will provide a type withs will manage the Context
for you. You can call the different modules like the following:
let crossterm = Crossterm::new();
let color = crossterm.color();
let cursor = crossterm.cursor();
let terminal = crossterm.terminal();
When you want to switch to alternate screen there are a couple of things to keep in mind for it to work correctly. First off some code of how to switch to Alternate screen, for more info check the example folder at github
Create alternate screen from Context
// create context.
let context = crossterm::Context::new();
// create instance of Alternatescreen by the given context, this wil also switch to it.
let mut screen = crossterm::AlternateScreen::from(context.clone());
// write to the alternate screen.
write!(screen, "test");
Create alternate screen from Crossterm
:
// create context.
let crossterm = ::crossterm::Crossterm::new();
// create instance of Alternatescreen by the given refrence to crossterm, this wil also switch to it.
let mut screen = crossterm::AlternateScreen::from(&crossterm);
// write to the alternate screen.
write!(screen, "test");
When using alternate screen there is one thing to keep in mind.
To get the functionalities of cursor, color, terminal
also working on alternate screen.
You need to pass it the same Context
as you have passed to the previous three functions,
If you don't use the same Context
the cursor(), color(), terminal()
these modules will be using main screen to write to.
So you will see nothing on alternate screen.
Please check the documentation of Context
for more info.
But basically this Context is a wrapper for a type that provides access to the current screen whether it would be the main screen or alternate screen.
An example of what I mean by that:
// create context.
let context = crossterm::Context::new();
let mut cursor = ::crossterm::cursor::cursor(&context);
cursor.goto(10,10);
// create instance of Alternatescreen by the given refrence to crossterm, this wil also switch to it.
let mut screen = crossterm::AlternateScreen::from(&context);
// now this cursor will be moving on the alternate screen sice it is using the same context as we have passed to the alternatescreen.
cursor.goto(5,4)
To make things easier you can better use Crossterm
type for the interactions with alternate screen.
This type will manage the Context
internally.
So when using this type to switch to AlternateScreen. It will use the Context
from the type Crossterm
for the AlternateSceen
.
For example:
// create crossterm instance.
let crossterm = ::crossterm::Crossterm::new();
let mut cursor = crossterm.cursor();
cursor.goto(10,10);
// create instance of Alternatescreen by the given refrence to crossterm, this wil also switch to it.
let mut screen = crossterm::AlternateScreen::from(&crossterm);
// this cursor will be moving on the alternate screen since the current screen is the alternate screen.
let mut cursor = crossterm.cursor();
cursor.goto(10,10);
As you can see because we are using Crossterm
we won't have to bother about the Context
.