NAME

Term::Fabulous::Terminal::Memory - A terminal in memory, for tests

SYNOPSIS

use Test2::V0;
use Term::Fabulous;
use Term::Fabulous::Terminal::Memory;
use Term::Fabulous::Widget::Box;
use Term::Fabulous::Widget::TextField;

my $field = Term::Fabulous::Widget::TextField->new( preferred_columns => 10 );
my $root  = Term::Fabulous::Widget::Box->new;
$root->add_child($field);

my $terminal = Term::Fabulous::Terminal::Memory->new( width => 30, height => 2 );
my $ui       = Term::Fabulous->new( root => $root, width => 30, height => 2, terminal => $terminal );

$ui->step;                                        # opens the terminal, fires Start, draws a frame
$terminal->press_key('Tab')->type_text('Ada');    # focus the field and type
$ui->step;                                        # handles the input as run would, draws

is $field->value, 'Ada', 'the field holds the text';
is [ $terminal->lines ], [ 'Ada       ', '' ], 'what the screen shows';
done_testing;

The text field has a background color, so its ten columns are kept as spaces in "lines". A longer test, with clicks, is in "Test a widget without a terminal" in Term::Fabulous::Cookbook::Output.

DESCRIPTION

A terminal (see Term::Fabulous::Role::Terminal) that exists only in memory. Give it to "new" in Term::Fabulous as terminal, queue input with the methods below, let the application handle it with "step" in Term::Fabulous (or "run" in Term::Fabulous), and read back the screen with "lines" and "cell".

Input goes through everything that real input goes through: the focused widget gets the keys, Tab and Shift+Tab move the focus, a click is hit-tested against the last frame, focuses what it hits and presses and releases it (OnPress, OnRelease), the wheel scrolls, and resizes fire Resize. The events are those termbox2 reports for a real terminal, so key names, mouse buttons and modifiers come out as they do there.

The screen is a Term::Fabulous::Render::Target::Grid ("cell_target"): each frame paints into it as into the terminal. It starts empty, and it keeps the last frame after the session was closed, so a test can look at what "run" in Term::Fabulous left on the screen.

The terminal also records what the application switched on, for the open session: "mouse_enabled", "inline_rows" and "kitty_keyboard_active".

CONSTRUCTOR

new

my $terminal = Term::Fabulous::Terminal::Memory->new( width => 80, height => 24 );
my $terminal = Term::Fabulous::Terminal::Memory->new( width => 80, height => 24, kitty_keyboard => 1 );
my $terminal = Term::Fabulous::Terminal::Memory->new( width => 80, height => 24, sixel_cell_size => [ 10, 20 ] );

width and height are the size of the screen, whole numbers of at least 1; required. kitty_keyboard says whether the terminal speaks the kitty keyboard protocol, so that an application that asks for it gets it; default 0. sixel_cell_size, [width, height] in pixels, makes it a terminal that shows sixel graphics with cells of that size: the pictures of Term::Fabulous::Widget::Sixel are recorded, and "sixels" in Term::Fabulous::Render::Target::Grid on "cell_target" returns those of the last frame. Without it, the default, the terminal shows no sixel graphics. Unknown parameters die.

INPUT

Input is queued until the application reads it: $ui->step reads all of it, and $ui->run watches read_handles (see "read_handles" in Term::Fabulous::Role::Terminal), a pipe that is readable while input waits. Every method returns the terminal, so calls can be chained. After "end_input", queuing more input dies.

type_text

$terminal->type_text('hello');

One key event per character, as typing the text would send.

press_key

$terminal->press_key('Enter');
$terminal->press_key('Ctrl+Shift+Left');
$terminal->press_key('BackTab');    # Shift+Tab
$terminal->press_key('Ctrl+C');

One key, by the name "key_name" in Term::Fabulous::Event::KeyPress gives it; see "KEY NAMES" in Term::Fabulous::Event::KeyPress. A name that key_name never returns dies (see "fields_for_name" in Term::Fabulous::Event::KeyPress).

click

$terminal->click( $x, $y );

A press and a release of the left mouse button on the cell ($x, $y), counted from 0 at the top-left of the screen.

mouse

use Term::Fabulous::Termbox qw(TB_KEY_MOUSE_WHEEL_DOWN TF_KEY_MOUSE_MOVE TB_MOD_MOTION);

$terminal->mouse( key => TB_KEY_MOUSE_WHEEL_DOWN, x => 3, y => 1 );
$terminal->mouse( key => TF_KEY_MOUSE_MOVE, mod => TB_MOD_MOTION, x => 5, y => 2 );

Any other mouse event, with the fields of a Term::Fabulous::Termbox::Event (key, x, y, mod, ch); see Term::Fabulous::Event::Mouse for what they mean. Mouse events are dropped, as a real terminal would not send them, while the session does not report the mouse ("mouse_enabled").

resize

$terminal->resize( 100, 30 );

The terminal changes its size. The application applies it when it reads the event: "step" in Term::Fabulous at once, "run" in Term::Fabulous after its debounce interval. Sizes that are not whole numbers of at least 1 die.

push_event

use Term::Fabulous::Termbox qw(TB_EVENT_KEY);

$terminal->push_event( type => TB_EVENT_KEY, key => 0, ch => ord 'a', mod => 0 );

Any event, with the fields of a Term::Fabulous::Termbox::Event. The type must be TB_EVENT_KEY, TB_EVENT_MOUSE or TB_EVENT_RESIZE. Unknown fields die.

end_input

$terminal->end_input;

The input ends, as when the real terminal goes away: once the queued events are read, input_ended is 1, and "run" in Term::Fabulous and "step" in Term::Fabulous die with Term::Fabulous: the terminal was closed.

OUTPUT

lines

my @lines = $terminal->lines;
my @lines = $terminal->lines( colors => 1 );

The screen as one character string per row: the rows of the layout (the screen's height, or the rows of an inline region), as wide as the screen, with the spaces at the end of a row left out unless they have a background color. With colors true, the rows carry ANSI color sequences as "row_text" in Term::Fabulous::Render::Target::Grid describes; default 0.

cell

my ( $glyph, $fg, $bg ) = @{ $terminal->cell( $x, $y ) // [] };

The cell at ($x, $y) as "cell" in Term::Fabulous::Render::Target::Grid describes it, or undef when the last frame painted nothing there.

cell_target

The Term::Fabulous::Render::Target::Grid the frames are painted into.

STATE

width, height

The size of the screen: the constructor's, or the last size a resize event applied.

kitty_keyboard

The kitty_keyboard constructor parameter.

is_open

1 while a session is open.

session_count

How many sessions were opened so far.

mouse_enabled

1 while the open session reports the mouse.

inline_rows

The rows of the inline region of the open session, or undef in full-screen mode and when no session is open.

kitty_keyboard_active

1 while the open session uses the kitty keyboard protocol: the application asked for it and the terminal speaks it (kitty_keyboard).

TERMINAL METHODS

The methods of Term::Fabulous::Role::Terminal, called by Term::Fabulous: open (dies when a session is open already, and on unknown options), close, size, apply_resize, read_handles, next_event and input_ended. An inline region starts at the first row of the screen.

SEE ALSO

"step" in Term::Fabulous, "TESTING" in Term::Fabulous::Manual::Programs, Term::Fabulous::Role::Terminal, Term::Fabulous::Terminal::Termbox.