NAME

Tickit::Widget::Term - runs a process in a window, using terminal emulation that makes VT100 look like advanced technology

VERSION

version 0.001

SYNOPSIS

#!/usr/bin/env perl
use strict;
use warnings;
use Tickit::Async;
use Tickit::Widget::Term;
use IO::Async::Loop;
use Log::Any qw($log);
use Log::Any::Adapter qw(Stderr);
use Tickit::Widget::Frame;

my $loop = IO::Async::Loop->new;
$loop->add(
	my $tickit = Tickit::Async->new
);
my $frame = Tickit::Widget::Frame->new(
	child => my $term = Tickit::Widget::Term->new(
		command => ['/bin/bash'],
		loop => $loop
	),
	title => 'shell',
	style => {
		linetype => 'single'
	},
);
$tickit->set_root_widget(
	$frame
);
$term->take_focus;
$tickit->run;

DESCRIPTION

In principle, a terminal widget would provide an abstraction for running any terminal application under Tickit. This would include full support for attributes, cursor movement, scrolling, mouse/keyboard input, and if used as the root window should be indistinguishable from running the code directly from the parent terminal itself.

What you get with this module is a minimum-viable implementation for running a tiny subset of the basic shell commands. It's a hack using cargo-culted IO::Pty pieces, manual forking under IO::Async, and a vague understanding of terminal control codes based on watching low-budget police shows. It redraws everything at the slightest excuse. You'd have to run reset(1) before you can even get your own keyboard input echoing back. The code spends most of its time logging the endless list of features that aren't supported.

Having said that, here are some things you can expect to work:

  • ls (partly)

  • some of the letters

  • maybe the enter key

Unlikely scenarios:

  • anything which does more than move the cursor or select one of the 8 colours.

At this point, it's customary to mention that the module and API are experimental and likely to change. Careful readers will already have noticed that this is a placeholder module and "likely to change" is somewhat understated.

Logging

This module uses Log::Any to generate copious amounts of unhelpful diagnostics. Future versions may add even more!

METHODS

new

This creates a new instance. I'd recommend against using it.

Tickit::Widget::Term->new(
 command => ['/bin/bash'],
 loop => $loop
)

window_gained

Sets up cursor position and notifies the child process via WINCH when we get a window.

loop

Accessor for the IO::Async::Loop instance.

pty

Accessor for the IO::Pty instance.

lines

How many lines we're expecting to use. This value was carefully researched from a wide selection of popular terminal applications, and is not just the highest number I can count to on one hand.

cols

Default number of columns. The number 80 seemed appropriate here.

render_to_rb

Renders things. You don't call this, Tickit does.

command

Returns the command to execute plus any args, as an arrayref.

init

Calling this yourself is probably not needed, so documenting it would be even less useful.

on_key

This will be called when we get a key. Its purpose is mostly to emit unhappy log messages about how few of those keys we're passing along.

pen

Returns a pen. Probably one that matches the currently-requested attributes.

csi_map

Dispatch table thing for handling control sequence introducers. They do things like set colours, apparently.

handle_terminal_output

This takes bytes from the PTY handle, then throws most of them away. Since the method no longer fits on my screen I have no idea what any of it really does.

find_next_tab

Returns the next tab stop after our current position.

push_state

Stores current state, including things like colours.

pop_state

Restores the previous state.

terminal_line

Which line the terminal thinks it's on. Usually zero-based.

terminal_col

Which column the terminal thinks it's on. Also zero-based.

push_text

Takes some text characters and puts them into the write operation queue.

available_lines

Guesses how many lines we have.

available_cols

Does the same for columns.

terminal_next_line

Moves to the next line - if we're at the end of the screen then it'll attempt to scroll.

scroll

Does some sort of scrolling.

update_cursor

Moves the window cursor to the terminal cursor position.

You might be wondering why there are two cursors - that's possibly due to the misguided notion that this code should be able to run the PTY quietly in the background even when we have no window.

SEE ALSO

  • libvterm - if I had the patience for C, I would have started with bindings to this

  • http://invisibleisland.net - xterm docs

  • console_codes(4) - Linux console terminal codes

  • screen, tmux, term.js - they're probably doing it properly. If I wasn't on a plane while writing this, that's the source code I'd be reading first.

INHERITED METHODS

Tickit::Widget

get_style_pen, get_style_text, get_style_values, key_focus_next_after, key_focus_next_before, on_pen_changed, parent, redraw, requested_cols, requested_lines, requested_size, reshape, resized, set_parent, set_pen, set_requested_size, set_style, set_style_tag, set_window, style_classes, take_focus, window, window_lost

AUTHOR

Tom Molesworth <cpan@perlsite.co.uk>

LICENSE

Copyright Tom Molesworth 2015. Licensed under the same terms as Perl itself.