Replace AnsiType with write_ansi (#523)
This commit is contained in:
parent
52bed07ce8
commit
5be7d18475
@ -2,10 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! cargo run --example event-poll-read
|
//! cargo run --example event-poll-read
|
||||||
|
|
||||||
use std::{
|
use std::{io::stdout, time::Duration};
|
||||||
io::{stdout, Write},
|
|
||||||
time::Duration,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
cursor::position,
|
cursor::position,
|
||||||
|
@ -34,7 +34,7 @@ pub fn read_line() -> Result<String> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return Ok(line);
|
Ok(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
@ -2,7 +2,7 @@
|
|||||||
//!
|
//!
|
||||||
//! cargo run --example event-read
|
//! cargo run --example event-read
|
||||||
|
|
||||||
use std::io::{stdout, Write};
|
use std::io::stdout;
|
||||||
|
|
||||||
use crossterm::{
|
use crossterm::{
|
||||||
cursor::position,
|
cursor::position,
|
||||||
|
@ -1,4 +0,0 @@
|
|||||||
/// Wrapper type for write dynamic ansi string
|
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
|
||||||
#[doc(hidden)]
|
|
||||||
pub struct Ansi<T>(pub T);
|
|
111
src/command.rs
111
src/command.rs
@ -1,6 +1,5 @@
|
|||||||
use std::{fmt::Display, io::Write};
|
use std::fmt;
|
||||||
|
use std::io::{self, Write};
|
||||||
use crate::{execute, queue};
|
|
||||||
|
|
||||||
use super::error::Result;
|
use super::error::Result;
|
||||||
|
|
||||||
@ -11,14 +10,12 @@ use super::error::Result;
|
|||||||
/// In order to understand how to use and execute commands,
|
/// In order to understand how to use and execute commands,
|
||||||
/// it is recommended that you take a look at [Command Api](../#command-api) chapter.
|
/// it is recommended that you take a look at [Command Api](../#command-api) chapter.
|
||||||
pub trait Command {
|
pub trait Command {
|
||||||
type AnsiType: Display;
|
/// Write an ANSI representation of this commmand to the given writer.
|
||||||
|
|
||||||
/// Returns an ANSI code representation of this command.
|
|
||||||
/// An ANSI code can manipulate the terminal by writing it to the terminal buffer.
|
/// An ANSI code can manipulate the terminal by writing it to the terminal buffer.
|
||||||
/// However, only Windows 10 and UNIX systems support this.
|
/// However, only Windows 10 and UNIX systems support this.
|
||||||
///
|
///
|
||||||
/// This method does not need to be accessed manually, as it is used by the crossterm's [Command Api](../#command-api)
|
/// This method does not need to be accessed manually, as it is used by the crossterm's [Command Api](../#command-api)
|
||||||
fn ansi_code(&self) -> Self::AnsiType;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result;
|
||||||
|
|
||||||
/// Execute this command.
|
/// Execute this command.
|
||||||
///
|
///
|
||||||
@ -39,12 +36,9 @@ pub trait Command {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Command> Command for &T {
|
impl<T: Command + ?Sized> Command for &T {
|
||||||
type AnsiType = T::AnsiType;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
(**self).write_ansi(f)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
T::ansi_code(self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
@ -60,23 +54,19 @@ impl<T: Command> Command for &T {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interface for commands that can be queued for further execution.
|
/// An interface for types that can queue commands for further execution.
|
||||||
pub trait QueueableCommand<T: Display>: Sized {
|
pub trait QueueableCommand {
|
||||||
/// Queues the given command for further execution.
|
/// Queues the given command for further execution.
|
||||||
fn queue(&mut self, command: impl Command<AnsiType = T>) -> Result<&mut Self>;
|
fn queue(&mut self, command: impl Command) -> Result<&mut Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An interface for commands that are directly executed.
|
/// An interface for types that can directly execute commands.
|
||||||
pub trait ExecutableCommand<T: Display>: Sized {
|
pub trait ExecutableCommand {
|
||||||
/// Executes the given command directly.
|
/// Executes the given command directly.
|
||||||
fn execute(&mut self, command: impl Command<AnsiType = T>) -> Result<&mut Self>;
|
fn execute(&mut self, command: impl Command) -> Result<&mut Self>;
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> QueueableCommand<A> for T
|
impl<T: Write + ?Sized> QueueableCommand for T {
|
||||||
where
|
|
||||||
A: Display,
|
|
||||||
T: Write,
|
|
||||||
{
|
|
||||||
/// Queues the given command for further execution.
|
/// Queues the given command for further execution.
|
||||||
///
|
///
|
||||||
/// Queued commands will be executed in the following cases:
|
/// Queued commands will be executed in the following cases:
|
||||||
@ -128,17 +118,24 @@ where
|
|||||||
/// and can therefore not be written to the given `writer`.
|
/// and can therefore not be written to the given `writer`.
|
||||||
/// Therefore, there is no difference between [execute](./trait.ExecutableCommand.html)
|
/// Therefore, there is no difference between [execute](./trait.ExecutableCommand.html)
|
||||||
/// and [queue](./trait.QueueableCommand.html) for those old Windows versions.
|
/// and [queue](./trait.QueueableCommand.html) for those old Windows versions.
|
||||||
fn queue(&mut self, command: impl Command<AnsiType = A>) -> Result<&mut Self> {
|
fn queue(&mut self, command: impl Command) -> Result<&mut Self> {
|
||||||
queue!(self, command)?;
|
#[cfg(windows)]
|
||||||
|
if !command.is_ansi_code_supported() {
|
||||||
|
command.execute_winapi(|| {
|
||||||
|
write_command_ansi(self, &command)?;
|
||||||
|
// winapi doesn't support queuing
|
||||||
|
self.flush()?;
|
||||||
|
Ok(())
|
||||||
|
})?;
|
||||||
|
return Ok(self);
|
||||||
|
}
|
||||||
|
|
||||||
|
write_command_ansi(self, command)?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T, A> ExecutableCommand<A> for T
|
impl<T: Write + ?Sized> ExecutableCommand for T {
|
||||||
where
|
|
||||||
A: Display,
|
|
||||||
T: Write,
|
|
||||||
{
|
|
||||||
/// Executes the given command directly.
|
/// Executes the given command directly.
|
||||||
///
|
///
|
||||||
/// The given command its ANSI escape code will be written and flushed onto `Self`.
|
/// The given command its ANSI escape code will be written and flushed onto `Self`.
|
||||||
@ -179,8 +176,56 @@ where
|
|||||||
/// and can therefore not be written to the given `writer`.
|
/// and can therefore not be written to the given `writer`.
|
||||||
/// Therefore, there is no difference between [execute](./trait.ExecutableCommand.html)
|
/// Therefore, there is no difference between [execute](./trait.ExecutableCommand.html)
|
||||||
/// and [queue](./trait.QueueableCommand.html) for those old Windows versions.
|
/// and [queue](./trait.QueueableCommand.html) for those old Windows versions.
|
||||||
fn execute(&mut self, command: impl Command<AnsiType = A>) -> Result<&mut Self> {
|
fn execute(&mut self, command: impl Command) -> Result<&mut Self> {
|
||||||
execute!(self, command)?;
|
self.queue(command)?;
|
||||||
|
self.flush()?;
|
||||||
Ok(self)
|
Ok(self)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Writes the ANSI representation of a command to the given writer.
|
||||||
|
fn write_command_ansi<C: Command>(
|
||||||
|
io: &mut (impl io::Write + ?Sized),
|
||||||
|
command: C,
|
||||||
|
) -> io::Result<()> {
|
||||||
|
struct Adapter<T> {
|
||||||
|
inner: T,
|
||||||
|
res: io::Result<()>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<T: Write> fmt::Write for Adapter<T> {
|
||||||
|
fn write_str(&mut self, s: &str) -> fmt::Result {
|
||||||
|
self.inner.write_all(s.as_bytes()).map_err(|e| {
|
||||||
|
self.res = Err(e);
|
||||||
|
fmt::Error
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
let mut adapter = Adapter {
|
||||||
|
inner: io,
|
||||||
|
res: Ok(()),
|
||||||
|
};
|
||||||
|
|
||||||
|
command
|
||||||
|
.write_ansi(&mut adapter)
|
||||||
|
.map_err(|fmt::Error| match adapter.res {
|
||||||
|
Ok(()) => panic!(
|
||||||
|
"<{}>::write_ansi incorrectly errored",
|
||||||
|
std::any::type_name::<C>()
|
||||||
|
),
|
||||||
|
Err(e) => e,
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Executes the ANSI representation of a command, using the given `fmt::Write`.
|
||||||
|
pub(crate) fn execute_fmt(f: &mut impl fmt::Write, command: impl Command) -> fmt::Result {
|
||||||
|
#[cfg(windows)]
|
||||||
|
if !command.is_ansi_code_supported() {
|
||||||
|
return command
|
||||||
|
.execute_winapi(|| panic!("this writer should not be possible to use here"))
|
||||||
|
.map_err(|_| fmt::Error);
|
||||||
|
}
|
||||||
|
|
||||||
|
command.write_ansi(f)
|
||||||
|
}
|
||||||
|
150
src/cursor.rs
150
src/cursor.rs
@ -46,7 +46,7 @@ pub use sys::position;
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::{impl_display, Ansi, Command};
|
use crate::{impl_display, Command};
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
mod ansi;
|
mod ansi;
|
||||||
@ -61,18 +61,9 @@ pub(crate) mod sys;
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveTo(pub u16, pub u16);
|
pub struct MoveTo(pub u16, pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveTo> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_to_csi_sequence(f, (self.0).0, (self.0).1)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveTo {
|
impl Command for MoveTo {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_to_csi_sequence(f, self.0, self.1)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -90,18 +81,9 @@ impl Command for MoveTo {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveToNextLine(pub u16);
|
pub struct MoveToNextLine(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveToNextLine> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_to_next_line_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveToNextLine {
|
impl Command for MoveToNextLine {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_to_next_line_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -119,18 +101,9 @@ impl Command for MoveToNextLine {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveToPreviousLine(pub u16);
|
pub struct MoveToPreviousLine(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveToPreviousLine> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_to_previous_line_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveToPreviousLine {
|
impl Command for MoveToPreviousLine {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_to_previous_line_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -147,18 +120,9 @@ impl Command for MoveToPreviousLine {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveToColumn(pub u16);
|
pub struct MoveToColumn(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveToColumn> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_to_column_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveToColumn {
|
impl Command for MoveToColumn {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_to_column_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -175,18 +139,9 @@ impl Command for MoveToColumn {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveUp(pub u16);
|
pub struct MoveUp(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveUp> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_up_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveUp {
|
impl Command for MoveUp {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_up_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -203,18 +158,9 @@ impl Command for MoveUp {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveRight(pub u16);
|
pub struct MoveRight(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveRight> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_right_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveRight {
|
impl Command for MoveRight {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_right_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -231,18 +177,9 @@ impl Command for MoveRight {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveDown(pub u16);
|
pub struct MoveDown(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveDown> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_down_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveDown {
|
impl Command for MoveDown {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_down_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -259,18 +196,9 @@ impl Command for MoveDown {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct MoveLeft(pub u16);
|
pub struct MoveLeft(pub u16);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<MoveLeft> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::move_left_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for MoveLeft {
|
impl Command for MoveLeft {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::move_left_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -291,11 +219,8 @@ impl Command for MoveLeft {
|
|||||||
pub struct SavePosition;
|
pub struct SavePosition;
|
||||||
|
|
||||||
impl Command for SavePosition {
|
impl Command for SavePosition {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::SAVE_POSITION_CSI_SEQUENCE)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::SAVE_POSITION_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -316,11 +241,8 @@ impl Command for SavePosition {
|
|||||||
pub struct RestorePosition;
|
pub struct RestorePosition;
|
||||||
|
|
||||||
impl Command for RestorePosition {
|
impl Command for RestorePosition {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::RESTORE_POSITION_CSI_SEQUENCE)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::RESTORE_POSITION_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -338,11 +260,8 @@ impl Command for RestorePosition {
|
|||||||
pub struct Hide;
|
pub struct Hide;
|
||||||
|
|
||||||
impl Command for Hide {
|
impl Command for Hide {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::HIDE_CSI_SEQUENCE)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::HIDE_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -360,11 +279,8 @@ impl Command for Hide {
|
|||||||
pub struct Show;
|
pub struct Show;
|
||||||
|
|
||||||
impl Command for Show {
|
impl Command for Show {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::SHOW_CSI_SEQUENCE)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::SHOW_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -383,11 +299,8 @@ impl Command for Show {
|
|||||||
pub struct EnableBlinking;
|
pub struct EnableBlinking;
|
||||||
|
|
||||||
impl Command for EnableBlinking {
|
impl Command for EnableBlinking {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::ENABLE_BLINKING_CSI_SEQUENCE)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::ENABLE_BLINKING_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -406,11 +319,8 @@ impl Command for EnableBlinking {
|
|||||||
pub struct DisableBlinking;
|
pub struct DisableBlinking;
|
||||||
|
|
||||||
impl Command for DisableBlinking {
|
impl Command for DisableBlinking {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::DISABLE_BLINKING_CSI_SEQUENCE)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::DISABLE_BLINKING_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -436,7 +346,7 @@ impl_display!(for DisableBlinking);
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::io::{self, stdout, Write};
|
use std::io::{self, stdout};
|
||||||
|
|
||||||
use crate::execute;
|
use crate::execute;
|
||||||
|
|
||||||
|
@ -1,13 +1,13 @@
|
|||||||
//! This module provides cursor related ANSI escape codes.
|
//! This module provides cursor related ANSI escape codes.
|
||||||
|
|
||||||
use crate::csi;
|
use crate::csi;
|
||||||
use std::fmt::{self, Formatter};
|
use std::fmt;
|
||||||
|
|
||||||
pub(crate) fn move_to_csi_sequence(f: &mut Formatter, x: u16, y: u16) -> fmt::Result {
|
pub(crate) fn move_to_csi_sequence(f: &mut impl fmt::Write, x: u16, y: u16) -> fmt::Result {
|
||||||
write!(f, csi!("{};{}H"), y + 1, x + 1)
|
write!(f, csi!("{};{}H"), y + 1, x + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_up_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_up_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
if count != 0 {
|
if count != 0 {
|
||||||
write!(f, csi!("{}A"), count)
|
write!(f, csi!("{}A"), count)
|
||||||
} else {
|
} else {
|
||||||
@ -15,7 +15,7 @@ pub(crate) fn move_up_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_right_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_right_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
if count != 0 {
|
if count != 0 {
|
||||||
write!(f, csi!("{}C"), count)
|
write!(f, csi!("{}C"), count)
|
||||||
} else {
|
} else {
|
||||||
@ -23,7 +23,7 @@ pub(crate) fn move_right_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Res
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_down_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_down_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
if count != 0 {
|
if count != 0 {
|
||||||
write!(f, csi!("{}B"), count)
|
write!(f, csi!("{}B"), count)
|
||||||
} else {
|
} else {
|
||||||
@ -31,7 +31,7 @@ pub(crate) fn move_down_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Resu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_left_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_left_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
if count != 0 {
|
if count != 0 {
|
||||||
write!(f, csi!("{}D"), count)
|
write!(f, csi!("{}D"), count)
|
||||||
} else {
|
} else {
|
||||||
@ -39,15 +39,18 @@ pub(crate) fn move_left_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Resu
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_to_column_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_to_column_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
write!(f, csi!("{}G"), count)
|
write!(f, csi!("{}G"), count)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_to_previous_line_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_to_previous_line_csi_sequence(
|
||||||
|
f: &mut impl fmt::Write,
|
||||||
|
count: u16,
|
||||||
|
) -> fmt::Result {
|
||||||
write!(f, csi!("{}F"), count)
|
write!(f, csi!("{}F"), count)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn move_to_next_line_csi_sequence(f: &mut Formatter, count: u16) -> fmt::Result {
|
pub(crate) fn move_to_next_line_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
write!(f, csi!("{}E"), count)
|
write!(f, csi!("{}E"), count)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
13
src/event.rs
13
src/event.rs
@ -70,6 +70,7 @@
|
|||||||
//! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of
|
//! Check the [examples](https://github.com/crossterm-rs/crossterm/tree/master/examples) folder for more of
|
||||||
//! them (`event-*`).
|
//! them (`event-*`).
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
use std::time::Duration;
|
use std::time::Duration;
|
||||||
|
|
||||||
use parking_lot::RwLock;
|
use parking_lot::RwLock;
|
||||||
@ -225,10 +226,8 @@ where
|
|||||||
pub struct EnableMouseCapture;
|
pub struct EnableMouseCapture;
|
||||||
|
|
||||||
impl Command for EnableMouseCapture {
|
impl Command for EnableMouseCapture {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::ENABLE_MOUSE_MODE_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::ENABLE_MOUSE_MODE_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -249,10 +248,8 @@ impl Command for EnableMouseCapture {
|
|||||||
pub struct DisableMouseCapture;
|
pub struct DisableMouseCapture;
|
||||||
|
|
||||||
impl Command for DisableMouseCapture {
|
impl Command for DisableMouseCapture {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::DISABLE_MOUSE_MODE_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::DISABLE_MOUSE_MODE_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
|
@ -231,7 +231,6 @@
|
|||||||
//! [flush]: https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush
|
//! [flush]: https://doc.rust-lang.org/std/io/trait.Write.html#tymethod.flush
|
||||||
|
|
||||||
pub use crate::{
|
pub use crate::{
|
||||||
ansi::Ansi,
|
|
||||||
command::{Command, ExecutableCommand, QueueableCommand},
|
command::{Command, ExecutableCommand, QueueableCommand},
|
||||||
error::{ErrorKind, Result},
|
error::{ErrorKind, Result},
|
||||||
};
|
};
|
||||||
@ -248,7 +247,6 @@ pub mod terminal;
|
|||||||
/// A module to query if the current instance is a tty.
|
/// A module to query if the current instance is a tty.
|
||||||
pub mod tty;
|
pub mod tty;
|
||||||
|
|
||||||
mod ansi;
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
/// A module that exposes one function to check if the current terminal supports ansi sequences.
|
/// A module that exposes one function to check if the current terminal supports ansi sequences.
|
||||||
pub mod ansi_support;
|
pub mod ansi_support;
|
||||||
|
121
src/macros.rs
121
src/macros.rs
@ -5,77 +5,6 @@ macro_rules! csi {
|
|||||||
($( $l:expr ),*) => { concat!("\x1B[", $( $l ),*) };
|
($( $l:expr ),*) => { concat!("\x1B[", $( $l ),*) };
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Writes an ansi code to the given writer.
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! write_ansi_code {
|
|
||||||
($writer:expr, $ansi_code:expr) => {{
|
|
||||||
use std::io::{self, ErrorKind};
|
|
||||||
|
|
||||||
write!($writer, "{}", $ansi_code)
|
|
||||||
.map_err(|e| io::Error::new(ErrorKind::Other, e))
|
|
||||||
.map_err($crate::ErrorKind::IoError)
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
|
||||||
#[allow(unused_imports)]
|
|
||||||
use $crate::{write_ansi_code, Command};
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
let command = $command;
|
|
||||||
if command.is_ansi_code_supported() {
|
|
||||||
write_ansi_code!($writer, command.ansi_code())
|
|
||||||
} else {
|
|
||||||
command
|
|
||||||
.execute_winapi(|| {
|
|
||||||
write!($writer, "{}", command.ansi_code())?;
|
|
||||||
// winapi doesn't support queuing
|
|
||||||
$writer.flush()?;
|
|
||||||
Ok(())
|
|
||||||
})
|
|
||||||
.map_err($crate::ErrorKind::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
write_ansi_code!($writer, $command.ansi_code())
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Offer the same functionality as queue! macro, but is used only internally and with std::fmt::Write as $writer
|
|
||||||
// The difference is in case of winapi we ignore the $writer and use a fake one
|
|
||||||
#[doc(hidden)]
|
|
||||||
#[macro_export]
|
|
||||||
macro_rules! handle_fmt_command {
|
|
||||||
($writer:expr, $command:expr) => {{
|
|
||||||
use $crate::{write_ansi_code, Command};
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
|
||||||
{
|
|
||||||
let command = $command;
|
|
||||||
if command.is_ansi_code_supported() {
|
|
||||||
write_ansi_code!($writer, command.ansi_code())
|
|
||||||
} else {
|
|
||||||
command
|
|
||||||
.execute_winapi(|| panic!("this writer should not be possible to use here"))
|
|
||||||
.map_err($crate::ErrorKind::from)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
#[cfg(unix)]
|
|
||||||
{
|
|
||||||
write_ansi_code!($writer, $command.ansi_code())
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Queues one or more command(s) for further execution.
|
/// Queues one or more command(s) for further execution.
|
||||||
///
|
///
|
||||||
/// Queued commands must be flushed to the underlying device to be executed.
|
/// Queued commands must be flushed to the underlying device to be executed.
|
||||||
@ -129,11 +58,14 @@ macro_rules! handle_fmt_command {
|
|||||||
///
|
///
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! queue {
|
macro_rules! queue {
|
||||||
($writer:expr $(, $command:expr)* $(,)?) => {
|
($writer:expr $(, $command:expr)* $(,)?) => {{
|
||||||
Ok(()) $(
|
use ::std::io::Write;
|
||||||
.and_then(|()| $crate::handle_command!($writer, $command))
|
|
||||||
)*
|
// This allows the macro to take both mut impl Write and &mut impl Write.
|
||||||
}
|
Ok($writer.by_ref())
|
||||||
|
$(.and_then(|writer| $crate::QueueableCommand::queue(writer, $command)))*
|
||||||
|
.map(|_| ())
|
||||||
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Executes one or more command(s).
|
/// Executes one or more command(s).
|
||||||
@ -179,12 +111,15 @@ macro_rules! queue {
|
|||||||
/// and [queue](macro.queue.html) for those old Windows versions.
|
/// and [queue](macro.queue.html) for those old Windows versions.
|
||||||
#[macro_export]
|
#[macro_export]
|
||||||
macro_rules! execute {
|
macro_rules! execute {
|
||||||
($writer:expr $(, $command:expr)* $(,)? ) => {
|
($writer:expr $(, $command:expr)* $(,)? ) => {{
|
||||||
|
use ::std::io::Write;
|
||||||
|
|
||||||
// Queue each command, then flush
|
// Queue each command, then flush
|
||||||
$crate::queue!($writer $(, $command)*).and_then(|()| {
|
$crate::queue!($writer $(, $command)*)
|
||||||
$writer.flush().map_err($crate::ErrorKind::IoError)
|
.and_then(|()| {
|
||||||
|
::std::io::Write::flush($writer.by_ref()).map_err($crate::ErrorKind::IoError)
|
||||||
})
|
})
|
||||||
}
|
}}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[doc(hidden)]
|
#[doc(hidden)]
|
||||||
@ -192,8 +127,8 @@ macro_rules! execute {
|
|||||||
macro_rules! impl_display {
|
macro_rules! impl_display {
|
||||||
(for $($t:ty),+) => {
|
(for $($t:ty),+) => {
|
||||||
$(impl ::std::fmt::Display for $t {
|
$(impl ::std::fmt::Display for $t {
|
||||||
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> {
|
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::fmt::Result {
|
||||||
$crate::handle_fmt_command!(f, self).map_err(|_| ::std::fmt::Error)
|
$crate::command::execute_fmt(f, self)
|
||||||
}
|
}
|
||||||
})*
|
})*
|
||||||
}
|
}
|
||||||
@ -215,6 +150,7 @@ macro_rules! impl_from {
|
|||||||
mod tests {
|
mod tests {
|
||||||
use std::io;
|
use std::io;
|
||||||
use std::str;
|
use std::str;
|
||||||
|
|
||||||
// Helper for execute tests to confirm flush
|
// Helper for execute tests to confirm flush
|
||||||
#[derive(Default, Debug, Clone)]
|
#[derive(Default, Debug, Clone)]
|
||||||
pub(self) struct FakeWrite {
|
pub(self) struct FakeWrite {
|
||||||
@ -239,7 +175,7 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(not(windows))]
|
#[cfg(not(windows))]
|
||||||
mod unix {
|
mod unix {
|
||||||
use std::io::Write;
|
use std::fmt;
|
||||||
|
|
||||||
use super::FakeWrite;
|
use super::FakeWrite;
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
@ -247,10 +183,8 @@ mod tests {
|
|||||||
pub struct FakeCommand;
|
pub struct FakeCommand;
|
||||||
|
|
||||||
impl Command for FakeCommand {
|
impl Command for FakeCommand {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str("cmd")
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
"cmd"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -305,9 +239,10 @@ mod tests {
|
|||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
mod windows {
|
mod windows {
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use std::cell::RefCell;
|
use std::cell::RefCell;
|
||||||
use std::fmt::Debug;
|
use std::fmt::Debug;
|
||||||
use std::io::Write;
|
|
||||||
|
|
||||||
use super::FakeWrite;
|
use super::FakeWrite;
|
||||||
use crate::command::Command;
|
use crate::command::Command;
|
||||||
@ -339,10 +274,8 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
impl<'a> Command for FakeCommand<'a> {
|
impl<'a> Command for FakeCommand<'a> {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(self.value)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
self.value
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn execute_winapi(
|
fn execute_winapi(
|
||||||
@ -379,12 +312,12 @@ mod tests {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// We need this for type inference, for whatever reason.
|
// We need this for type inference, for whatever reason.
|
||||||
const EMPTY_RESULT: [&'static str; 0] = [];
|
const EMPTY_RESULT: [&str; 0] = [];
|
||||||
|
|
||||||
// TODO: confirm that the correct sink was used, based on
|
// TODO: confirm that the correct sink was used, based on
|
||||||
// is_ansi_code_supported
|
// is_ansi_code_supported
|
||||||
match (writer.buffer.is_empty(), stream.is_empty()) {
|
match (writer.buffer.is_empty(), stream.is_empty()) {
|
||||||
(true, true) if stream_result == &EMPTY_RESULT => {}
|
(true, true) if stream_result == EMPTY_RESULT => {}
|
||||||
(true, true) => panic!(
|
(true, true) => panic!(
|
||||||
"Neither the event stream nor the writer were populated. Expected {:?}",
|
"Neither the event stream nor the writer were populated. Expected {:?}",
|
||||||
stream_result
|
stream_result
|
||||||
|
117
src/style.rs
117
src/style.rs
@ -110,12 +110,14 @@
|
|||||||
//! );
|
//! );
|
||||||
//! ```
|
//! ```
|
||||||
|
|
||||||
use std::{env, fmt::Display};
|
use std::{
|
||||||
|
env,
|
||||||
|
fmt::{self, Display},
|
||||||
|
};
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crate::Result;
|
use crate::Result;
|
||||||
use crate::{impl_display, Ansi, Command};
|
use crate::{impl_display, Command};
|
||||||
use std::fmt;
|
|
||||||
|
|
||||||
pub use self::{
|
pub use self::{
|
||||||
attributes::Attributes,
|
attributes::Attributes,
|
||||||
@ -201,18 +203,9 @@ pub fn available_color_count() -> u16 {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct SetForegroundColor(pub Color);
|
pub struct SetForegroundColor(pub Color);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<SetForegroundColor> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::set_fg_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SetForegroundColor {
|
impl Command for SetForegroundColor {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::set_fg_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -234,18 +227,9 @@ impl Command for SetForegroundColor {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct SetBackgroundColor(pub Color);
|
pub struct SetBackgroundColor(pub Color);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<SetBackgroundColor> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::set_bg_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SetBackgroundColor {
|
impl Command for SetBackgroundColor {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::set_bg_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -277,25 +261,16 @@ impl Command for SetBackgroundColor {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct SetColors(pub Colors);
|
pub struct SetColors(pub Colors);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<SetColors> {
|
impl Command for SetColors {
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
if let Some(color) = (self.0).0.foreground {
|
if let Some(color) = self.0.foreground {
|
||||||
ansi::set_fg_csi_sequence(f, color)?;
|
ansi::set_fg_csi_sequence(f, color)?;
|
||||||
}
|
}
|
||||||
if let Some(color) = (self.0).0.background {
|
if let Some(color) = self.0.background {
|
||||||
ansi::set_bg_csi_sequence(f, color)?;
|
ansi::set_bg_csi_sequence(f, color)?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SetColors {
|
|
||||||
type AnsiType = Ansi<Self>;
|
|
||||||
|
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
|
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
|
||||||
@ -319,18 +294,9 @@ impl Command for SetColors {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct SetAttribute(pub Attribute);
|
pub struct SetAttribute(pub Attribute);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<SetAttribute> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::set_attr_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SetAttribute {
|
impl Command for SetAttribute {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::set_attr_csi_sequence(f, self.0)
|
||||||
#[inline]
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -350,17 +316,9 @@ impl Command for SetAttribute {
|
|||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct SetAttributes(pub Attributes);
|
pub struct SetAttributes(pub Attributes);
|
||||||
|
|
||||||
impl fmt::Display for Ansi<SetAttributes> {
|
|
||||||
fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
|
|
||||||
ansi::set_attrs_csi_sequence(f, (self.0).0)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Command for SetAttributes {
|
impl Command for SetAttributes {
|
||||||
type AnsiType = Ansi<Self>;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::set_attrs_csi_sequence(f, self.0)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
Ansi(*self)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -378,16 +336,11 @@ impl Command for SetAttributes {
|
|||||||
///
|
///
|
||||||
/// Commands must be executed/queued for execution otherwise they do nothing.
|
/// Commands must be executed/queued for execution otherwise they do nothing.
|
||||||
#[derive(Debug, Copy, Clone)]
|
#[derive(Debug, Copy, Clone)]
|
||||||
pub struct PrintStyledContent<D: Display + Clone>(pub StyledContent<D>);
|
pub struct PrintStyledContent<D: Display>(pub StyledContent<D>);
|
||||||
|
|
||||||
impl<D> Command for PrintStyledContent<D>
|
impl<D: Display> Command for PrintStyledContent<D> {
|
||||||
where
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
D: Display + Clone,
|
write!(f, "{}", self.0)
|
||||||
{
|
|
||||||
type AnsiType = StyledContent<D>;
|
|
||||||
|
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -405,10 +358,8 @@ where
|
|||||||
pub struct ResetColor;
|
pub struct ResetColor;
|
||||||
|
|
||||||
impl Command for ResetColor {
|
impl Command for ResetColor {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::RESET_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::RESET_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -421,28 +372,22 @@ impl Command for ResetColor {
|
|||||||
///
|
///
|
||||||
/// Commands must be executed/queued for execution otherwise they do nothing.
|
/// Commands must be executed/queued for execution otherwise they do nothing.
|
||||||
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
|
||||||
pub struct Print<T: Display + Clone>(pub T);
|
pub struct Print<T: Display>(pub T);
|
||||||
|
|
||||||
impl<T: Display + Clone> Command for Print<T> {
|
impl<T: Display> Command for Print<T> {
|
||||||
type AnsiType = T;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
write!(f, "{}", self.0)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
self.0.clone()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
fn execute_winapi(&self, mut writer: impl FnMut() -> Result<()>) -> Result<()> {
|
fn execute_winapi(&self, mut writer: impl FnMut() -> Result<()>) -> Result<()> {
|
||||||
writer()?;
|
writer()
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<T: Display + Clone> Display for Print<T> {
|
impl<T: Display> Display for Print<T> {
|
||||||
fn fmt(
|
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||||
&self,
|
self.0.fmt(f)
|
||||||
f: &mut ::std::fmt::Formatter<'_>,
|
|
||||||
) -> ::std::result::Result<(), ::std::fmt::Error> {
|
|
||||||
write!(f, "{}", self.ansi_code())
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -8,19 +8,22 @@ use crate::{
|
|||||||
style::{Attribute, Attributes, Color, Colored},
|
style::{Attribute, Attributes, Color, Colored},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub(crate) fn set_fg_csi_sequence(f: &mut Formatter, fg_color: Color) -> fmt::Result {
|
pub(crate) fn set_fg_csi_sequence(f: &mut impl fmt::Write, fg_color: Color) -> fmt::Result {
|
||||||
write!(f, csi!("{}m"), Colored::ForegroundColor(fg_color))
|
write!(f, csi!("{}m"), Colored::ForegroundColor(fg_color))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_bg_csi_sequence(f: &mut Formatter, bg_color: Color) -> fmt::Result {
|
pub(crate) fn set_bg_csi_sequence(f: &mut impl fmt::Write, bg_color: Color) -> fmt::Result {
|
||||||
write!(f, csi!("{}m"), Colored::BackgroundColor(bg_color))
|
write!(f, csi!("{}m"), Colored::BackgroundColor(bg_color))
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_attr_csi_sequence(f: &mut Formatter, attribute: Attribute) -> fmt::Result {
|
pub(crate) fn set_attr_csi_sequence(f: &mut impl fmt::Write, attribute: Attribute) -> fmt::Result {
|
||||||
write!(f, csi!("{}m"), attribute.sgr())
|
write!(f, csi!("{}m"), attribute.sgr())
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_attrs_csi_sequence(f: &mut Formatter, attributes: Attributes) -> fmt::Result {
|
pub(crate) fn set_attrs_csi_sequence(
|
||||||
|
f: &mut impl fmt::Write,
|
||||||
|
attributes: Attributes,
|
||||||
|
) -> fmt::Result {
|
||||||
for attr in Attribute::iterator() {
|
for attr in Attribute::iterator() {
|
||||||
if attributes.has(attr) {
|
if attributes.has(attr) {
|
||||||
write!(f, csi!("{}m"), attr.sgr())?;
|
write!(f, csi!("{}m"), attr.sgr())?;
|
||||||
@ -32,7 +35,7 @@ pub(crate) fn set_attrs_csi_sequence(f: &mut Formatter, attributes: Attributes)
|
|||||||
pub(crate) const RESET_CSI_SEQUENCE: &str = csi!("0m");
|
pub(crate) const RESET_CSI_SEQUENCE: &str = csi!("0m");
|
||||||
|
|
||||||
impl fmt::Display for Colored {
|
impl fmt::Display for Colored {
|
||||||
fn fmt(&self, f: &mut Formatter) -> fmt::Result {
|
fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
|
||||||
let color;
|
let color;
|
||||||
|
|
||||||
match *self {
|
match *self {
|
||||||
|
@ -6,7 +6,7 @@ use std::{
|
|||||||
};
|
};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
handle_fmt_command,
|
command::execute_fmt,
|
||||||
style::{
|
style::{
|
||||||
Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttributes, SetBackgroundColor,
|
Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttributes, SetBackgroundColor,
|
||||||
SetForegroundColor, Styler,
|
SetForegroundColor, Styler,
|
||||||
@ -98,16 +98,16 @@ impl<D: Display> Display for StyledContent<D> {
|
|||||||
let mut reset = false;
|
let mut reset = false;
|
||||||
|
|
||||||
if let Some(bg) = self.style.background_color {
|
if let Some(bg) = self.style.background_color {
|
||||||
handle_fmt_command!(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
|
execute_fmt(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
|
||||||
reset_background = true;
|
reset_background = true;
|
||||||
}
|
}
|
||||||
if let Some(fg) = self.style.foreground_color {
|
if let Some(fg) = self.style.foreground_color {
|
||||||
handle_fmt_command!(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
|
execute_fmt(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
|
||||||
reset_foreground = true;
|
reset_foreground = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
if !self.style.attributes.is_empty() {
|
if !self.style.attributes.is_empty() {
|
||||||
handle_fmt_command!(f, SetAttributes(self.style.attributes)).map_err(|_| fmt::Error)?;
|
execute_fmt(f, SetAttributes(self.style.attributes)).map_err(|_| fmt::Error)?;
|
||||||
reset = true;
|
reset = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -117,14 +117,14 @@ impl<D: Display> Display for StyledContent<D> {
|
|||||||
// NOTE: This will reset colors even though self has no colors, hence produce unexpected
|
// NOTE: This will reset colors even though self has no colors, hence produce unexpected
|
||||||
// resets.
|
// resets.
|
||||||
// TODO: reset the set attributes only.
|
// TODO: reset the set attributes only.
|
||||||
handle_fmt_command!(f, ResetColor).map_err(|_| fmt::Error)?;
|
execute_fmt(f, ResetColor).map_err(|_| fmt::Error)?;
|
||||||
} else {
|
} else {
|
||||||
// NOTE: Since the above bug, we do not need to reset colors when we reset attributes.
|
// NOTE: Since the above bug, we do not need to reset colors when we reset attributes.
|
||||||
if reset_background {
|
if reset_background {
|
||||||
handle_fmt_command!(f, SetBackgroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
|
execute_fmt(f, SetBackgroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
|
||||||
}
|
}
|
||||||
if reset_foreground {
|
if reset_foreground {
|
||||||
handle_fmt_command!(f, SetForegroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
|
execute_fmt(f, SetForegroundColor(Color::Reset)).map_err(|_| fmt::Error)?;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -81,6 +81,8 @@
|
|||||||
//!
|
//!
|
||||||
//! For manual execution control check out [crossterm::queue](../macro.queue.html).
|
//! For manual execution control check out [crossterm::queue](../macro.queue.html).
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
use crossterm_winapi::{ConsoleMode, Handle, ScreenBuffer};
|
use crossterm_winapi::{ConsoleMode, Handle, ScreenBuffer};
|
||||||
#[cfg(feature = "serde")]
|
#[cfg(feature = "serde")]
|
||||||
@ -121,10 +123,8 @@ pub fn size() -> Result<(u16, u16)> {
|
|||||||
pub struct DisableLineWrap;
|
pub struct DisableLineWrap;
|
||||||
|
|
||||||
impl Command for DisableLineWrap {
|
impl Command for DisableLineWrap {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::DISABLE_LINE_WRAP_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::DISABLE_LINE_WRAP_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -142,10 +142,8 @@ impl Command for DisableLineWrap {
|
|||||||
pub struct EnableLineWrap;
|
pub struct EnableLineWrap;
|
||||||
|
|
||||||
impl Command for EnableLineWrap {
|
impl Command for EnableLineWrap {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::ENABLE_LINE_WRAP_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::ENABLE_LINE_WRAP_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -184,10 +182,8 @@ impl Command for EnableLineWrap {
|
|||||||
pub struct EnterAlternateScreen;
|
pub struct EnterAlternateScreen;
|
||||||
|
|
||||||
impl Command for EnterAlternateScreen {
|
impl Command for EnterAlternateScreen {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::ENTER_ALTERNATE_SCREEN_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::ENTER_ALTERNATE_SCREEN_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -224,10 +220,8 @@ impl Command for EnterAlternateScreen {
|
|||||||
pub struct LeaveAlternateScreen;
|
pub struct LeaveAlternateScreen;
|
||||||
|
|
||||||
impl Command for LeaveAlternateScreen {
|
impl Command for LeaveAlternateScreen {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(ansi::LEAVE_ALTERNATE_SCREEN_CSI_SEQUENCE)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::LEAVE_ALTERNATE_SCREEN_CSI_SEQUENCE
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -263,10 +257,8 @@ pub enum ClearType {
|
|||||||
pub struct ScrollUp(pub u16);
|
pub struct ScrollUp(pub u16);
|
||||||
|
|
||||||
impl Command for ScrollUp {
|
impl Command for ScrollUp {
|
||||||
type AnsiType = String;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::scroll_up_csi_sequence(f, self.0)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::scroll_up_csi_sequence(self.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -284,10 +276,8 @@ impl Command for ScrollUp {
|
|||||||
pub struct ScrollDown(pub u16);
|
pub struct ScrollDown(pub u16);
|
||||||
|
|
||||||
impl Command for ScrollDown {
|
impl Command for ScrollDown {
|
||||||
type AnsiType = String;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::scroll_down_csi_sequence(f, self.0)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::scroll_down_csi_sequence(self.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -307,16 +297,14 @@ impl Command for ScrollDown {
|
|||||||
pub struct Clear(pub ClearType);
|
pub struct Clear(pub ClearType);
|
||||||
|
|
||||||
impl Command for Clear {
|
impl Command for Clear {
|
||||||
type AnsiType = &'static str;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
f.write_str(match self.0 {
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
match self.0 {
|
|
||||||
ClearType::All => ansi::CLEAR_ALL_CSI_SEQUENCE,
|
ClearType::All => ansi::CLEAR_ALL_CSI_SEQUENCE,
|
||||||
ClearType::FromCursorDown => ansi::CLEAR_FROM_CURSOR_DOWN_CSI_SEQUENCE,
|
ClearType::FromCursorDown => ansi::CLEAR_FROM_CURSOR_DOWN_CSI_SEQUENCE,
|
||||||
ClearType::FromCursorUp => ansi::CLEAR_FROM_CURSOR_UP_CSI_SEQUENCE,
|
ClearType::FromCursorUp => ansi::CLEAR_FROM_CURSOR_UP_CSI_SEQUENCE,
|
||||||
ClearType::CurrentLine => ansi::CLEAR_FROM_CURRENT_LINE_CSI_SEQUENCE,
|
ClearType::CurrentLine => ansi::CLEAR_FROM_CURRENT_LINE_CSI_SEQUENCE,
|
||||||
ClearType::UntilNewLine => ansi::CLEAR_UNTIL_NEW_LINE_CSI_SEQUENCE,
|
ClearType::UntilNewLine => ansi::CLEAR_UNTIL_NEW_LINE_CSI_SEQUENCE,
|
||||||
}
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -334,10 +322,8 @@ impl Command for Clear {
|
|||||||
pub struct SetSize(pub u16, pub u16);
|
pub struct SetSize(pub u16, pub u16);
|
||||||
|
|
||||||
impl Command for SetSize {
|
impl Command for SetSize {
|
||||||
type AnsiType = String;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::set_size_csi_sequence(f, self.0, self.1)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::set_size_csi_sequence(self.0, self.1)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -355,10 +341,8 @@ impl Command for SetSize {
|
|||||||
pub struct SetTitle<'a>(pub &'a str);
|
pub struct SetTitle<'a>(pub &'a str);
|
||||||
|
|
||||||
impl<'a> Command for SetTitle<'a> {
|
impl<'a> Command for SetTitle<'a> {
|
||||||
type AnsiType = String;
|
fn write_ansi(&self, f: &mut impl fmt::Write) -> fmt::Result {
|
||||||
|
ansi::set_title_ansi_sequence(f, self.0)
|
||||||
fn ansi_code(&self) -> Self::AnsiType {
|
|
||||||
ansi::set_title_ansi_sequence(self.0)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(windows)]
|
#[cfg(windows)]
|
||||||
@ -374,10 +358,7 @@ impl_display!(for Clear);
|
|||||||
|
|
||||||
#[cfg(test)]
|
#[cfg(test)]
|
||||||
mod tests {
|
mod tests {
|
||||||
use std::{
|
use std::{io::stdout, thread, time};
|
||||||
io::{stdout, Write},
|
|
||||||
thread, time,
|
|
||||||
};
|
|
||||||
|
|
||||||
use crate::execute;
|
use crate::execute;
|
||||||
|
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
//! This module provides terminal related ANSI escape codes.
|
//! This module provides terminal related ANSI escape codes.
|
||||||
|
|
||||||
|
use std::fmt;
|
||||||
|
|
||||||
use crate::csi;
|
use crate::csi;
|
||||||
|
|
||||||
pub(crate) const CLEAR_ALL_CSI_SEQUENCE: &str = csi!("2J");
|
pub(crate) const CLEAR_ALL_CSI_SEQUENCE: &str = csi!("2J");
|
||||||
@ -12,18 +14,22 @@ pub(crate) const LEAVE_ALTERNATE_SCREEN_CSI_SEQUENCE: &str = csi!("?1049l");
|
|||||||
pub(crate) const DISABLE_LINE_WRAP_CSI_SEQUENCE: &str = csi!("?7l");
|
pub(crate) const DISABLE_LINE_WRAP_CSI_SEQUENCE: &str = csi!("?7l");
|
||||||
pub(crate) const ENABLE_LINE_WRAP_CSI_SEQUENCE: &str = csi!("?7h");
|
pub(crate) const ENABLE_LINE_WRAP_CSI_SEQUENCE: &str = csi!("?7h");
|
||||||
|
|
||||||
pub(crate) fn scroll_up_csi_sequence(count: u16) -> String {
|
pub(crate) fn scroll_up_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
format!(csi!("{}S"), count)
|
write!(f, csi!("{}S"), count)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn scroll_down_csi_sequence(count: u16) -> String {
|
pub(crate) fn scroll_down_csi_sequence(f: &mut impl fmt::Write, count: u16) -> fmt::Result {
|
||||||
format!(csi!("{}T"), count)
|
write!(f, csi!("{}T"), count)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_size_csi_sequence(width: u16, height: u16) -> String {
|
pub(crate) fn set_size_csi_sequence(
|
||||||
format!(csi!("8;{};{}t"), height, width)
|
f: &mut impl fmt::Write,
|
||||||
|
width: u16,
|
||||||
|
height: u16,
|
||||||
|
) -> fmt::Result {
|
||||||
|
write!(f, csi!("8;{};{}t"), height, width)
|
||||||
}
|
}
|
||||||
|
|
||||||
pub(crate) fn set_title_ansi_sequence(title: &str) -> String {
|
pub(crate) fn set_title_ansi_sequence(f: &mut impl fmt::Write, title: &str) -> fmt::Result {
|
||||||
format!("\x1B]0;{}\x07", title)
|
write!(f, "\x1B]0;{}\x07", title)
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user