Grand writer access for winapi commands.

This commit is contained in:
sigmaSd 2020-07-20 12:58:04 +02:00 committed by GitHub
parent 6326795700
commit 32215ec7f5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
7 changed files with 79 additions and 43 deletions

View File

@ -27,7 +27,7 @@ pub trait Command {
///
/// This method does not need to be accessed manually, as it is used by the crossterm's [Command Api](../#command-api)
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()>;
fn execute_winapi(&self, writer: impl FnMut() -> Result<()>) -> Result<()>;
/// Returns whether the ansi code representation of this command is supported by windows.
///
@ -49,8 +49,8 @@ impl<T: Command> Command for &T {
#[inline]
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
T::execute_winapi(self)
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
T::execute_winapi(self, _writer)
}
#[cfg(windows)]

View File

@ -76,7 +76,7 @@ impl Command for MoveTo {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_to(self.0, self.1)
}
}
@ -105,7 +105,7 @@ impl Command for MoveToNextLine {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_to_next_line(self.0)
}
}
@ -134,7 +134,7 @@ impl Command for MoveToPreviousLine {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_to_previous_line(self.0)
}
}
@ -162,7 +162,7 @@ impl Command for MoveToColumn {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_to_column(self.0)
}
}
@ -190,7 +190,7 @@ impl Command for MoveUp {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_up(self.0)
}
}
@ -218,7 +218,7 @@ impl Command for MoveRight {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_right(self.0)
}
}
@ -246,7 +246,7 @@ impl Command for MoveDown {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_down(self.0)
}
}
@ -274,7 +274,7 @@ impl Command for MoveLeft {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::move_left(self.0)
}
}
@ -299,7 +299,7 @@ impl Command for SavePosition {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::save_position()
}
}
@ -324,7 +324,7 @@ impl Command for RestorePosition {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::restore_position()
}
}
@ -346,7 +346,7 @@ impl Command for Hide {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::show_cursor(false)
}
}
@ -368,7 +368,7 @@ impl Command for Show {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::show_cursor(true)
}
}
@ -391,7 +391,7 @@ impl Command for EnableBlinking {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
Ok(())
}
}
@ -414,7 +414,7 @@ impl Command for DisableBlinking {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
Ok(())
}
}

View File

@ -232,7 +232,7 @@ impl Command for EnableMouseCapture {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::windows::enable_mouse_capture()
}
@ -256,7 +256,7 @@ impl Command for DisableMouseCapture {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::windows::disable_mouse_capture()
}

View File

@ -33,7 +33,40 @@ macro_rules! handle_command {
if command.is_ansi_code_supported() {
write_ansi_code!($writer, command.ansi_code())
} else {
command.execute_winapi().map_err($crate::ErrorKind::from)
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)]
@ -160,7 +193,7 @@ macro_rules! impl_display {
(for $($t:ty),+) => {
$(impl ::std::fmt::Display for $t {
fn fmt(&self, f: &mut ::std::fmt::Formatter<'_>) -> ::std::result::Result<(), ::std::fmt::Error> {
$crate::queue!(f, self).map_err(|_| ::std::fmt::Error)
$crate::handle_fmt_command!(f, self).map_err(|_| ::std::fmt::Error)
}
})*
}
@ -312,7 +345,10 @@ mod tests {
self.value
}
fn execute_winapi(&self) -> CrosstermResult<()> {
fn execute_winapi(
&self,
_writer: impl FnMut() -> CrosstermResult<()>,
) -> CrosstermResult<()> {
self.stream.borrow_mut().push(self.value);
Ok(())
}

View File

@ -216,7 +216,7 @@ impl Command for SetForegroundColor {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::windows::set_foreground_color(self.0)
}
}
@ -249,7 +249,7 @@ impl Command for SetBackgroundColor {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::windows::set_background_color(self.0)
}
}
@ -298,7 +298,7 @@ impl Command for SetColors {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
if let Some(color) = self.0.foreground {
sys::windows::set_foreground_color(color)?;
}
@ -334,7 +334,7 @@ impl Command for SetAttribute {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
// attributes are not supported by WinAPI.
Ok(())
}
@ -364,7 +364,7 @@ impl Command for SetAttributes {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
// attributes are not supported by WinAPI.
Ok(())
}
@ -391,7 +391,7 @@ where
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
Ok(())
}
}
@ -412,7 +412,7 @@ impl Command for ResetColor {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::windows::reset()
}
}
@ -431,8 +431,8 @@ impl<T: Display + Clone> Command for Print<T> {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
print!("{}", self.0);
fn execute_winapi(&self, mut writer: impl FnMut() -> Result<()>) -> Result<()> {
writer()?;
Ok(())
}
}

View File

@ -6,7 +6,7 @@ use std::{
};
use crate::{
queue,
handle_fmt_command,
style::{
Attribute, Color, Colorize, ContentStyle, ResetColor, SetAttributes, SetBackgroundColor,
SetForegroundColor, Styler,
@ -96,16 +96,16 @@ impl<D: Display> Display for StyledContent<D> {
let mut reset = false;
if let Some(bg) = self.style.background_color {
queue!(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
handle_fmt_command!(f, SetBackgroundColor(bg)).map_err(|_| fmt::Error)?;
reset = true;
}
if let Some(fg) = self.style.foreground_color {
queue!(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
handle_fmt_command!(f, SetForegroundColor(fg)).map_err(|_| fmt::Error)?;
reset = true;
}
if !self.style.attributes.is_empty() {
queue!(f, SetAttributes(self.style.attributes)).map_err(|_| fmt::Error)?;
handle_fmt_command!(f, SetAttributes(self.style.attributes)).map_err(|_| fmt::Error)?;
reset = true;
}
@ -115,7 +115,7 @@ impl<D: Display> Display for StyledContent<D> {
// color (39m)" and "reset background color (49m)"; consider using
// these.
if reset {
queue!(f, ResetColor).map_err(|_| fmt::Error)?;
handle_fmt_command!(f, ResetColor).map_err(|_| fmt::Error)?;
}
Ok(())

View File

@ -147,7 +147,7 @@ impl Command for EnterAlternateScreen {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
let alternate_screen = ScreenBuffer::create();
alternate_screen.show()?;
Ok(())
@ -187,7 +187,7 @@ impl Command for LeaveAlternateScreen {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
let screen_buffer = ScreenBuffer::from(Handle::current_out_handle()?);
screen_buffer.show()?;
Ok(())
@ -226,7 +226,7 @@ impl Command for ScrollUp {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::scroll_up(self.0)
}
}
@ -247,7 +247,7 @@ impl Command for ScrollDown {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::scroll_down(self.0)
}
}
@ -276,7 +276,7 @@ impl Command for Clear {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::clear(self.0)
}
}
@ -297,7 +297,7 @@ impl Command for SetSize {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::set_size(self.0, self.1)
}
}
@ -318,7 +318,7 @@ impl<'a> Command for SetTitle<'a> {
}
#[cfg(windows)]
fn execute_winapi(&self) -> Result<()> {
fn execute_winapi(&self, _writer: impl FnMut() -> Result<()>) -> Result<()> {
sys::set_window_title(self.0)
}
}