crossterm/docs/command.html
2019-10-02 12:03:37 +02:00

374 lines
16 KiB
HTML

<!DOCTYPE HTML>
<html lang="en" class="sidebar-visible no-js">
<head>
<!-- Book generated using mdBook -->
<meta charset="UTF-8">
<title>Command API - </title>
<meta content="text/html; charset=utf-8" http-equiv="Content-Type">
<meta name="description" content="">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#ffffff" />
<link rel="shortcut icon" href="favicon.png">
<link rel="stylesheet" href="css/variables.css">
<link rel="stylesheet" href="css/general.css">
<link rel="stylesheet" href="css/chrome.css">
<link rel="stylesheet" href="css/print.css" media="print">
<!-- Fonts -->
<link rel="stylesheet" href="FontAwesome/css/font-awesome.css">
<link href="https://fonts.googleapis.com/css?family=Open+Sans:300italic,400italic,600italic,700italic,800italic,400,300,600,700,800" rel="stylesheet" type="text/css">
<link href="https://fonts.googleapis.com/css?family=Source+Code+Pro:500" rel="stylesheet" type="text/css">
<!-- Highlight.js Stylesheets -->
<link rel="stylesheet" href="highlight.css">
<link rel="stylesheet" href="tomorrow-night.css">
<link rel="stylesheet" href="ayu-highlight.css">
<!-- Custom theme stylesheets -->
</head>
<body class="light">
<!-- Provide site root to javascript -->
<script type="text/javascript">
var path_to_root = "";
var default_theme = "light";
</script>
<!-- Work around some values being stored in localStorage wrapped in quotes -->
<script type="text/javascript">
try {
var theme = localStorage.getItem('mdbook-theme');
var sidebar = localStorage.getItem('mdbook-sidebar');
if (theme.startsWith('"') && theme.endsWith('"')) {
localStorage.setItem('mdbook-theme', theme.slice(1, theme.length - 1));
}
if (sidebar.startsWith('"') && sidebar.endsWith('"')) {
localStorage.setItem('mdbook-sidebar', sidebar.slice(1, sidebar.length - 1));
}
} catch (e) { }
</script>
<!-- Set the theme before any content is loaded, prevents flash -->
<script type="text/javascript">
var theme;
try { theme = localStorage.getItem('mdbook-theme'); } catch(e) { }
if (theme === null || theme === undefined) { theme = default_theme; }
document.body.className = theme;
document.querySelector('html').className = theme + ' js';
</script>
<!-- Hide / unhide sidebar before it is displayed -->
<script type="text/javascript">
var html = document.querySelector('html');
var sidebar = 'hidden';
if (document.body.clientWidth >= 1080) {
try { sidebar = localStorage.getItem('mdbook-sidebar'); } catch(e) { }
sidebar = sidebar || 'visible';
}
html.classList.remove('sidebar-visible');
html.classList.add("sidebar-" + sidebar);
</script>
<nav id="sidebar" class="sidebar" aria-label="Table of contents">
<ol class="chapter"><li><a href="feature_flags.html"><strong aria-hidden="true">1.</strong> Feature Flags</a></li><li><a href="command.html" class="active"><strong aria-hidden="true">2.</strong> Command API</a></li><li><a href="styling.html"><strong aria-hidden="true">3.</strong> Styling Output</a></li><li><a href="input.html"><strong aria-hidden="true">4.</strong> Reading Input Events</a></li><li><a href="screen.html"><strong aria-hidden="true">5.</strong> Alternate, Raw Screen</a></li></ol>
</nav>
<div id="page-wrapper" class="page-wrapper">
<div class="page">
<div id="menu-bar" class="menu-bar">
<div id="menu-bar-sticky-container">
<div class="left-buttons">
<button id="sidebar-toggle" class="icon-button" type="button" title="Toggle Table of Contents" aria-label="Toggle Table of Contents" aria-controls="sidebar">
<i class="fa fa-bars"></i>
</button>
<button id="theme-toggle" class="icon-button" type="button" title="Change theme" aria-label="Change theme" aria-haspopup="true" aria-expanded="false" aria-controls="theme-list">
<i class="fa fa-paint-brush"></i>
</button>
<ul id="theme-list" class="theme-popup" aria-label="Themes" role="menu">
<li role="none"><button role="menuitem" class="theme" id="light">Light (default)</button></li>
<li role="none"><button role="menuitem" class="theme" id="rust">Rust</button></li>
<li role="none"><button role="menuitem" class="theme" id="coal">Coal</button></li>
<li role="none"><button role="menuitem" class="theme" id="navy">Navy</button></li>
<li role="none"><button role="menuitem" class="theme" id="ayu">Ayu</button></li>
</ul>
<button id="search-toggle" class="icon-button" type="button" title="Search. (Shortkey: s)" aria-label="Toggle Searchbar" aria-expanded="false" aria-keyshortcuts="S" aria-controls="searchbar">
<i class="fa fa-search"></i>
</button>
</div>
<h1 class="menu-title"></h1>
<div class="right-buttons">
<a href="print.html" title="Print this book" aria-label="Print this book">
<i id="print-button" class="fa fa-print"></i>
</a>
</div>
</div>
</div>
<div id="search-wrapper" class="hidden">
<form id="searchbar-outer" class="searchbar-outer">
<input type="search" name="search" id="searchbar" name="searchbar" placeholder="Search this book ..." aria-controls="searchresults-outer" aria-describedby="searchresults-header">
</form>
<div id="searchresults-outer" class="searchresults-outer hidden">
<div id="searchresults-header" class="searchresults-header"></div>
<ul id="searchresults">
</ul>
</div>
</div>
<!-- Apply ARIA attributes after the sidebar and the sidebar toggle button are added to the DOM -->
<script type="text/javascript">
document.getElementById('sidebar-toggle').setAttribute('aria-expanded', sidebar === 'visible');
document.getElementById('sidebar').setAttribute('aria-hidden', sidebar !== 'visible');
Array.from(document.querySelectorAll('#sidebar a')).forEach(function(link) {
link.setAttribute('tabIndex', sidebar === 'visible' ? 0 : -1);
});
</script>
<div id="content" class="content">
<main>
<a class="header" href="#command-api" id="command-api"><h1>Command API</h1></a>
<blockquote>
<p><strong>WARNING</strong>: This book is deprecated, no longer maintained and will be
removed soon.</p>
</blockquote>
<p>The command API makes the use of crossterm much easier and offers more control over when and how a command such as moving the cursor is executed.</p>
<p>The command API offers:</p>
<ul>
<li>Better Performance</li>
<li>Complete control over when to flush</li>
<li>Complete control over where the ANSI escape commands are executed to</li>
<li>Way easier and nicer API</li>
</ul>
<p>There are two ways to use the API command:</p>
<ul>
<li>
<p>By using functions</p>
<p>The functions can execute commands on types that implement <code>Write</code>.
Functions are easier to use and debug. There is a disadvantage, and that is that there is a boilerplate code involved.</p>
</li>
<li>
<p>By using macros</p>
<p>Macros are generally seen as more difficult but offer an API with less boilerplate code.
If you are not afraid of macros, this is a recommendation.</p>
</li>
</ul>
<a class="header" href="#commands" id="commands"><h2>Commands</h2></a>
<p>Crossterm provides the following commands that can be used to perform actions with:</p>
<p><em>cursor commands</em></p>
<ul>
<li>Goto (x, y)</li>
<li>UP (number of time)</li>
<li>Down (number of time)</li>
<li>Left (number of time)</li>
<li>Right (number of time)</li>
<li>SavePos</li>
<li>ResetPos</li>
<li>Hide</li>
<li>Show</li>
<li>Blink On</li>
<li>Blink Off</li>
</ul>
<p><em>style commands</em></p>
<ul>
<li>SetFg (Color)</li>
<li>SetBg (Color)</li>
<li>SetAttr (attr)</li>
<li>Print Styled Text (text)</li>
</ul>
<p><em>terminal command</em></p>
<ul>
<li>Clear (ClearType)</li>
<li>Scroll Up (number of time)</li>
<li>Scroll Down (number of time)</li>
<li>SetSize (width, height)</li>
</ul>
<p><em>other</em></p>
<ul>
<li>Output (text)</li>
</ul>
<p>Each crossterm crate provides its command when using crossterm you can use them all at once.
When using a single crate or a feature flag, you can only use certain commands.</p>
<p>Before crossterm 10.0 was released, crossterm had some performance issues. It did a <code>flush</code> after each command (cursor movement).
A <code>flush</code> is heavy action on the terminal, and if it is done more often the performance will go down quickly.</p>
<p>Linux and Windows 10 systems support ANSI escape codes.
Those ANSI escape codes are strings or rather a byte sequence.
When we <code>write</code> and <code>flush</code> those to the terminal we can perform some action.</p>
<a class="header" href="#imports" id="imports"><h3>Imports</h3></a>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
use crossterm::{execute, queue, ExecutableCommand, QueueableCommand};
#}</code></pre></pre>
<a class="header" href="#lazy-execution" id="lazy-execution"><h3>Lazy Execution</h3></a>
<p>Because <code>flush</code> is a heavy system call we can instead <code>write</code> the commands to the <code>stdout</code> without flushing.
When can do a <code>flush</code> we do want to execute the commands.</p>
<p>If you create a terminal editor or TUI, it is wise to use this option.
For example, you can write commands to the terminal <code>stdout</code> and flush the <code>stdout</code> at every frame.
By doing this you can make efficient use of the terminal buffer and get better performance because you are not calling <code>flush</code> after every command.</p>
<a class="header" href="#examples" id="examples"><h4>Examples</h4></a>
<p><em>functions</em></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
let mut stdout = stdout();
stdout.queue(Goto(5,5))?;
// some other code ...
stdout.flush();
#}</code></pre></pre>
<p>The <code>queue</code> function returns itself, therefore you can use this to queue another command.
Like <code>stdout.queue(Goto(5,5)).queue(Clear(ClearType::All))</code></p>
<p><em>macro's</em></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
let mut stdout = stdout();
queue!(stdout, Goto(5, 5));
// some other code ...
// flush when you want to execute the 'queued' commands
stdout.flush();
#}</code></pre></pre>
<p>You can pass more than one command into the macro like: <code>queue!(stdout, Goto(5, 5), Clear(ClearType::All));</code>; they will be executed in the given order from left to right.</p>
<a class="header" href="#direct-execution" id="direct-execution"><h3>Direct Execution</h3></a>
<p>If you want to execute commands directly, this is also possible. You don't have to flush the 'stdout', as described above.
This is fine if you are not executing lots of commands.</p>
<p><em>functions</em></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
stdout().execute(Goto(5,5))?;
#}</code></pre></pre>
<p>The <code>execute</code> function returns it self, therefore you are able to use this to execute another command
like <code>stdout.execute(Goto(5,5))?.execute(Clear(ClearType::All))?</code></p>
<p><em>macro's</em></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
execute!(stdout, Goto(5, 5));
#}</code></pre></pre>
<p>You can pass more than one command into the macro like: <code>queue!(stdout, Goto(5, 5), Clear(ClearType::All));</code>; they will be executed in the given order from left to right.</p>
<a class="header" href="#short-examples" id="short-examples"><h2>Short Examples</h2></a>
<p>Print a rectangle colored with magenta and use both direct execution and lazy execution.</p>
<p><em>rectangle with command functions</em></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
use crossterm::{ExecutableCommand, QueueableCommand, Color, PrintStyledFont, Colorize};
use std::io::stdout();
let mut stdout = stdout();
stdout.execute(Clear(ClearType::All))?;
for y in 0..40 {
for x in 0..150 {
if (y == 0 || y == 40 - 1) || (x == 0 || x == 150 - 1) {
stdout
.queue(Goto(x,y))?
.queue(PrintStyledFont( &quot;&quot;.magenta()))?;
}
}
stdout.flush();
}
#}</code></pre></pre>
<p><em>rectangle with the macros</em></p>
<pre><pre class="playpen"><code class="language-rust">
# #![allow(unused_variables)]
#fn main() {
use crossterm::{execute, queue, Color, PrintStyledFont, Colorize};
use std::io::stdout();
let mut stdout = stdout();
execute!(stdout, Clear(ClearType::All));
for y in 0..40 {
for x in 0..150 {
if (y == 0 || y == 40 - 1) || (x == 0 || x == 150 - 1) {
queue!(stdout, Goto(x,y), PrintStyledFont( &quot;&quot;.magenta()));
}
}
stdout.flush();
}
#}</code></pre></pre>
</main>
<nav class="nav-wrapper" aria-label="Page navigation">
<!-- Mobile navigation buttons -->
<a rel="prev" href="feature_flags.html" class="mobile-nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a rel="next" href="styling.html" class="mobile-nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
<div style="clear: both"></div>
</nav>
</div>
</div>
<nav class="nav-wide-wrapper" aria-label="Page navigation">
<a href="feature_flags.html" class="nav-chapters previous" title="Previous chapter" aria-label="Previous chapter" aria-keyshortcuts="Left">
<i class="fa fa-angle-left"></i>
</a>
<a href="styling.html" class="nav-chapters next" title="Next chapter" aria-label="Next chapter" aria-keyshortcuts="Right">
<i class="fa fa-angle-right"></i>
</a>
</nav>
</div>
<script src="elasticlunr.min.js" type="text/javascript" charset="utf-8"></script>
<script src="mark.min.js" type="text/javascript" charset="utf-8"></script>
<script src="searcher.js" type="text/javascript" charset="utf-8"></script>
<script src="clipboard.min.js" type="text/javascript" charset="utf-8"></script>
<script src="highlight.js" type="text/javascript" charset="utf-8"></script>
<script src="book.js" type="text/javascript" charset="utf-8"></script>
<!-- Custom JS scripts -->
</body>
</html>