2019-10-23 01:33:38 +11:00
|
|
|
/// Append a the first few characters of an ANSI escape code to the given string.
|
|
|
|
#[macro_export]
|
2019-11-02 04:09:05 +11:00
|
|
|
#[doc(hidden)]
|
2019-10-23 01:33:38 +11:00
|
|
|
macro_rules! csi {
|
|
|
|
($( $l:expr ),*) => { concat!("\x1B[", $( $l ),*) };
|
|
|
|
}
|
|
|
|
|
2019-12-05 03:26:57 +11:00
|
|
|
/// Writes an ansi code to the given writer.
|
2019-11-02 04:09:05 +11:00
|
|
|
#[doc(hidden)]
|
2019-10-23 01:33:38 +11:00
|
|
|
#[macro_export]
|
2019-12-05 03:26:57 +11:00
|
|
|
macro_rules! write_ansi_code {
|
|
|
|
($writer:expr, $ansi_code:expr) => {{
|
|
|
|
use std::{
|
|
|
|
error::Error,
|
|
|
|
io::{self, ErrorKind},
|
|
|
|
};
|
2019-10-23 01:33:38 +11:00
|
|
|
|
2019-12-05 03:26:57 +11:00
|
|
|
write!($writer, "{}", $ansi_code)
|
|
|
|
.map_err(|e| io::Error::new(ErrorKind::Other, e.description()))
|
|
|
|
.map_err($crate::ErrorKind::IoError)
|
2019-10-23 01:33:38 +11:00
|
|
|
}};
|
2019-12-05 03:26:57 +11:00
|
|
|
}
|
|
|
|
|
|
|
|
/// Writes/executes the given command.
|
|
|
|
#[doc(hidden)]
|
|
|
|
#[macro_export]
|
|
|
|
macro_rules! handle_command {
|
|
|
|
($writer:expr, $command:expr) => {{
|
|
|
|
// Silent warning when the macro is used inside the `command` module
|
2019-10-23 01:33:38 +11:00
|
|
|
#[allow(unused_imports)]
|
2019-12-05 03:26:57 +11:00
|
|
|
use $crate::{write_ansi_code, Command};
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
{
|
|
|
|
// ansi code is not always a string, however it does implement `Display` and `Write`.
|
|
|
|
// In order to check if the code is supported we have to make it a string.
|
|
|
|
let ansi_code = format!("{}", $command.ansi_code());
|
|
|
|
|
|
|
|
if $command.is_ansi_code_supported() {
|
|
|
|
write_ansi_code!($writer, &ansi_code)
|
|
|
|
} else {
|
|
|
|
$command.execute_winapi().map_err($crate::ErrorKind::from)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
#[cfg(unix)]
|
|
|
|
{
|
|
|
|
write_ansi_code!($writer, $command.ansi_code())
|
|
|
|
}
|
2019-10-23 01:33:38 +11:00
|
|
|
}};
|
|
|
|
}
|
|
|
|
|
2019-12-05 03:26:57 +11:00
|
|
|
/// Queues one or more command(s) for further execution.
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
|
|
|
/// Queued commands will be executed in the following cases:
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// * When `flush` is called manually on the given type implementing `io::Write`.
|
|
|
|
/// * The terminal will `flush` automatically if the buffer is full.
|
|
|
|
/// * Each line is flushed in case of `stdout`, because it is line buffered.
|
|
|
|
///
|
|
|
|
/// # Arguments
|
|
|
|
///
|
2019-10-23 01:33:38 +11:00
|
|
|
/// - [std::io::Writer](https://doc.rust-lang.org/std/io/trait.Write.html)
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// ANSI escape codes are written on the given 'writer', after which they are flushed.
|
|
|
|
///
|
2019-10-23 01:33:38 +11:00
|
|
|
/// - [Command](./trait.Command.html)
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// One or more commands
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// # Examples
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// ```rust
|
2019-10-23 01:33:38 +11:00
|
|
|
/// use std::io::{Write, stdout};
|
2019-12-05 03:26:57 +11:00
|
|
|
/// use crossterm::{queue, style::Print};
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// fn main() {
|
|
|
|
/// let mut stdout = stdout();
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// // `Print` will executed executed when `flush` is called.
|
|
|
|
/// queue!(stdout, Print("foo".to_string()));
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// // some other code (no execution happening here) ...
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// // when calling `flush` on `stdout`, all commands will be written to the stdout and therefore executed.
|
|
|
|
/// stdout.flush();
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// // ==== Output ====
|
|
|
|
/// // foo
|
|
|
|
/// }
|
2019-10-23 01:33:38 +11:00
|
|
|
/// ```
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// Have a look over at the [Command API](./#command-api) for more details.
|
|
|
|
///
|
|
|
|
/// # Notes
|
|
|
|
///
|
|
|
|
/// In case of Windows versions lower than 10, a direct WinApi call will be made.
|
|
|
|
/// The reason for this is that Windows versions lower than 10 do not support ANSI codes,
|
|
|
|
/// and can therefore not be written to the given `writer`.
|
|
|
|
/// Therefore, there is no difference between [execute](macro.execute.html)
|
|
|
|
/// and [queue](macro.queue.html) for those old Windows versions.
|
|
|
|
///
|
2019-10-23 01:33:38 +11:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! queue {
|
2019-12-05 03:26:57 +11:00
|
|
|
($writer:expr, $($command:expr), * $(,)?) => {{
|
2019-10-23 01:33:38 +11:00
|
|
|
// Silent warning when the macro is used inside the `command` module
|
|
|
|
#[allow(unused_imports)]
|
2019-12-05 03:26:57 +11:00
|
|
|
use $crate::{Command, handle_command};
|
|
|
|
|
|
|
|
#[allow(unused_assignments)]
|
|
|
|
let mut error = Ok(());
|
2019-10-23 01:33:38 +11:00
|
|
|
|
|
|
|
$(
|
2019-12-05 03:26:57 +11:00
|
|
|
error = handle_command!($writer, $command);
|
2019-10-23 01:33:38 +11:00
|
|
|
)*
|
|
|
|
|
2019-12-05 03:26:57 +11:00
|
|
|
error
|
2019-10-23 01:33:38 +11:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2019-12-05 03:26:57 +11:00
|
|
|
/// Executes one or more command(s).
|
|
|
|
///
|
|
|
|
/// # Arguments
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
|
|
|
/// - [std::io::Writer](https://doc.rust-lang.org/std/io/trait.Write.html)
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// ANSI escape codes are written on the given 'writer', after which they are flushed.
|
|
|
|
///
|
2019-10-23 01:33:38 +11:00
|
|
|
/// - [Command](./trait.Command.html)
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// One or more commands
|
|
|
|
///
|
|
|
|
/// # Examples
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
|
|
|
/// ```rust
|
2019-12-05 03:26:57 +11:00
|
|
|
/// use std::io::{Write, stdout};
|
|
|
|
/// use crossterm::{execute, style::Print};
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// fn main() {
|
|
|
|
/// // will be executed directly
|
|
|
|
/// execute!(stdout(), Print("sum:\n".to_string()));
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// // will be executed directly
|
|
|
|
/// execute!(stdout(), Print("1 + 1= ".to_string()), Print((1+1).to_string()));
|
2019-10-23 01:33:38 +11:00
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// // ==== Output ====
|
|
|
|
/// // sum:
|
|
|
|
/// // 1 + 1 = 2
|
|
|
|
/// }
|
2019-10-23 01:33:38 +11:00
|
|
|
/// ```
|
|
|
|
///
|
2019-12-05 03:26:57 +11:00
|
|
|
/// Have a look over at the [Command API](./#command-api) for more details.
|
|
|
|
///
|
|
|
|
/// # Notes
|
|
|
|
///
|
|
|
|
/// * In the case of UNIX and Windows 10, ANSI codes are written to the given 'writer'.
|
|
|
|
/// * In case of Windows versions lower than 10, a direct WinApi call will be made.
|
|
|
|
/// The reason for this is that Windows versions lower than 10 do not support ANSI codes,
|
|
|
|
/// and can therefore not be written to the given `writer`.
|
|
|
|
/// Therefore, there is no difference between [execute](macro.execute.html)
|
|
|
|
/// and [queue](macro.queue.html) for those old Windows versions.
|
2019-10-23 01:33:38 +11:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! execute {
|
2019-11-14 17:17:10 +11:00
|
|
|
($write:expr, $($command:expr), * $(,)? ) => {{
|
2019-10-23 01:33:38 +11:00
|
|
|
// Silent warning when the macro is used inside the `command` module
|
|
|
|
#[allow(unused_imports)]
|
2019-12-05 03:26:57 +11:00
|
|
|
use $crate::{handle_command, Command};
|
|
|
|
|
|
|
|
#[allow(unused_assignments)]
|
|
|
|
let mut error = Ok(());
|
2019-10-23 01:33:38 +11:00
|
|
|
|
|
|
|
$(
|
2019-12-05 03:26:57 +11:00
|
|
|
if let Err(e) = handle_command!($write, $command) {
|
|
|
|
error = Err(e);
|
|
|
|
}else {
|
|
|
|
$write.flush().map_err($crate::ErrorKind::IoError).unwrap();
|
2019-10-23 01:33:38 +11:00
|
|
|
}
|
|
|
|
)*
|
|
|
|
|
2019-12-05 03:26:57 +11:00
|
|
|
error
|
2019-10-23 01:33:38 +11:00
|
|
|
}}
|
|
|
|
}
|
|
|
|
|
2019-11-02 04:09:05 +11:00
|
|
|
#[doc(hidden)]
|
2019-10-23 01:33:38 +11:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! impl_display {
|
|
|
|
(for $($t:ty),+) => {
|
|
|
|
$(impl ::std::fmt::Display for $t {
|
2019-10-24 00:02:20 +11:00
|
|
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> {
|
2019-12-05 03:26:57 +11:00
|
|
|
$crate::queue!(f, self).map_err(|_| ::std::fmt::Error)
|
2019-10-23 01:33:38 +11:00
|
|
|
}
|
|
|
|
})*
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2019-11-02 04:09:05 +11:00
|
|
|
#[doc(hidden)]
|
2019-10-23 01:33:38 +11:00
|
|
|
#[macro_export]
|
|
|
|
macro_rules! impl_from {
|
|
|
|
($from:path, $to:expr) => {
|
|
|
|
impl From<$from> for ErrorKind {
|
|
|
|
fn from(e: $from) -> Self {
|
|
|
|
$to(e)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|
2019-11-14 17:17:10 +11:00
|
|
|
|
|
|
|
#[cfg(test)]
|
|
|
|
mod tests {
|
|
|
|
use std::io::{stdout, Write};
|
|
|
|
|
|
|
|
use crate::utils::command::Command;
|
|
|
|
#[cfg(windows)]
|
|
|
|
use crate::utils::error::ErrorKind;
|
|
|
|
|
|
|
|
pub struct FakeCommand;
|
|
|
|
|
|
|
|
impl Command for FakeCommand {
|
|
|
|
type AnsiType = &'static str;
|
|
|
|
|
|
|
|
fn ansi_code(&self) -> Self::AnsiType {
|
|
|
|
""
|
|
|
|
}
|
|
|
|
|
|
|
|
#[cfg(windows)]
|
|
|
|
fn execute_winapi(&self) -> Result<(), ErrorKind> {
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_queue() {
|
|
|
|
assert!(queue!(stdout(), FakeCommand,).is_ok());
|
|
|
|
assert!(queue!(stdout(), FakeCommand).is_ok());
|
|
|
|
}
|
|
|
|
|
|
|
|
#[test]
|
|
|
|
fn test_execute() {
|
|
|
|
assert!(execute!(stdout(), FakeCommand,).is_ok());
|
|
|
|
assert!(execute!(stdout(), FakeCommand).is_ok());
|
|
|
|
}
|
|
|
|
}
|