use crate::console::{Console, Renderable};
use crate::text::Text;
impl Console {
pub fn render_widget_to_text<R: Renderable + ?Sized>(&mut self, renderable: &R) -> Text {
self.begin_capture();
self.print(renderable);
Text::from_ansi(&self.end_capture())
}
pub fn begin_capture(&mut self) {
self.capture_buffer = Some(Vec::new());
}
pub fn end_capture(&mut self) -> String {
let segments = self.capture_buffer.take().unwrap_or_default();
self.render_buffer(&segments)
}
pub fn is_capturing(&self) -> bool {
self.capture_buffer.is_some()
}
pub fn capture_guard(&mut self) -> CaptureGuard<'_> {
self.begin_capture();
CaptureGuard { console: self }
}
pub fn screen_guard(&mut self) -> ScreenGuard<'_> {
self.enter_screen(true);
ScreenGuard { console: self }
}
}
pub struct CaptureGuard<'a> {
console: &'a mut Console,
}
impl CaptureGuard<'_> {
pub fn end(self) -> String {
let text = self.console.end_capture();
let text_owned = text;
std::mem::forget(self);
text_owned
}
}
impl Drop for CaptureGuard<'_> {
fn drop(&mut self) {
self.console.end_capture();
}
}
impl std::ops::Deref for CaptureGuard<'_> {
type Target = Console;
fn deref(&self) -> &Console {
self.console
}
}
impl std::ops::DerefMut for CaptureGuard<'_> {
fn deref_mut(&mut self) -> &mut Console {
self.console
}
}
pub struct ScreenGuard<'a> {
console: &'a mut Console,
}
impl Drop for ScreenGuard<'_> {
fn drop(&mut self) {
self.console.exit_screen(true);
}
}
impl std::ops::Deref for ScreenGuard<'_> {
type Target = Console;
fn deref(&self) -> &Console {
self.console
}
}
impl std::ops::DerefMut for ScreenGuard<'_> {
fn deref_mut(&mut self) -> &mut Console {
self.console
}
}
#[cfg(test)]
mod tests {
use super::*;
fn test_console() -> Console {
Console::builder()
.width(80)
.height(25)
.quiet(false)
.markup(false)
.no_color(true)
.force_terminal(true)
.build()
}
#[test]
fn capture_guard_end_returns_text() {
let mut console = test_console();
let mut guard = console.capture_guard();
guard.print_text("guard_text");
let captured = guard.end();
assert!(
captured.contains("guard_text"),
"expected 'guard_text' in output, got: {:?}",
captured
);
}
#[test]
fn capture_guard_drop_restores_state() {
let mut console = test_console();
{
let _guard = console.capture_guard();
} assert!(
!console.is_capturing(),
"capture should be inactive after guard drop"
);
console.begin_capture();
console.print_text("after_guard");
let text = console.end_capture();
assert!(text.contains("after_guard"));
}
#[test]
fn capture_guard_deref_mut_works() {
let mut console = test_console();
let mut guard = console.capture_guard();
guard.print_text("deref_mut_text");
let text = guard.end();
assert!(text.contains("deref_mut_text"));
}
#[test]
fn screen_guard_drop_exits_alt_screen() {
let mut console = test_console();
{
let _guard = console.screen_guard();
} assert!(
!console.is_alt_screen,
"expected alt-screen to be inactive after guard drop"
);
}
#[test]
fn screen_guard_exit_sequence_emitted() {
let mut console = Console::builder()
.width(80)
.height(25)
.quiet(false)
.markup(false)
.no_color(true)
.force_terminal(true)
.build();
console.begin_capture();
{
let _guard = console.screen_guard();
}
let captured = console.end_capture();
assert!(
captured.contains("\x1b[?1049l"),
"expected exit-alt-screen sequence in output, got: {:?}",
captured
);
}
}