Antsy
view release on metacpan or search on metacpan
lib/Antsy.pm view on Meta::CPAN
=head1 DESCRIPTION
Subroutines to deal with ANSI terminal sequences. You can emit these
without knowing what's coming up.
=head2 Yet another module?
There are several modules that come close to this, but so far
everything is incomplete or requires you to know all of the upcoming
text ahead of time so you can use of it as an argument to a function.
I want to emit the sequence in a stream without knowing what's coming
up.
=over 4
=item * L<Term::ANSIColor>
Wraps ANSI color stuff around text. This comes with Perl v5.10 and
later.
=item * L<Text::ANSI::Util>
Routines for dealing with text that contains ANSI code. For example,
ignore the ANSI sequences in computing length.
=item * L<Text::ANSI::Printf>
I don't really know what this does.
=item * L<Term::ANSIScreen>
=back
=head2 Methods
=over 4
=item * bg_256( N )
=item * bg_rgb
=item * bg_black
=item * bg_blue
=item * bg_cyan
=item * bg_green
=item * bg_magenta
=item * bg_orange
=item * bg_red
=item * bg_white
=item * bg_yellow
Make the background the named color
=item * bg_bright_black
=item * bg_bright_blue
=item * bg_bright_cyan
=item * bg_bright_green
=item * bg_bright_magenta
=item * bg_bright_red
=item * bg_bright_white
=item * bg_bright_yellow
Make the background the named color and bright (however your terminal
does that).
=item * blink
Make the text blink (however your terminal does that).
=item * bold
Turn on bold
=item * clear_line
=item * clear_screen
=item * clear_to_line_end
=item * clear_to_line_start
=item * clear_to_screen_end
=item * clear_to_screen_start
Clear the part of the screen as indicated. Each of these start at the
current cursor position.
=item * conceal
Make the text invisible (if your terminal handles that).
=item * cursor_back( N )
Move the cursor back N positions.
=item * cursor_column( N )
Move the cursor to column N.
=item * cursor_down( N )
Move the cursor down N positions.
=item * cursor_forward( N )
Move the cursor forward N positions.
=item * cursor_next_line( N )
Move the cursor down N lines, to the start of the line
=item * cursor_previous_line( N )
Move the cursor up N lines, to the start of the line
=item * cursor_row_column( N, M )
Move the cursor to row N and column M.
=item * cursor_up
TK: Fill in details
=item * dark
Make the text dark (however your terminal does that).
=item * erase_in_display( [ 0, 1, 2, 3 ] )
TK: Fill in details
=item * erase_in_line( [ 0, 1, 2, 3 ] )
TK: Fill in details
=item * hide_cursor
Hide the cursor. See also C<show_cursor>.
=item * italic
Turn on italic.
=item * reset
Turn off all attributes
=item * restore_cursor
Put the cursor back to where you saved it. See also C<save_cursor>.
=item * reverse
Use the background color for the text color, and the text color
for the background.
=item * save_cursor
Save the current location of the cursor. See also C<save_cursor>.
=item * scroll_down( N )
Scroll down N lines.
=item * scroll_up( N )
Scroll up N lines.
=item * show_cursor
Show the cursor. See also C<hide_cursor>.
=item * text_256( N )
Make the foreground the color N in the xterm 256 color chart.
This dies if N is not a positive number between 0 and 255 (inclusive).
=item * text_black
=item * text_blue
=item * text_cyan
=item * text_green
=item * text_magenta
=item * text_orange
=item * text_red
=item * text_rgb
=item * text_white
=item * text_yellow
Make foreground text the named color.
=item * text_blink
Make the text blink.
=item * text_bright_black
=item * text_bright_blue
=item * text_bright_cyan
=item * text_bright_green
=item * text_bright_magenta
=item * text_bright_red
=item * text_bright_white
=item * text_bright_yellow
Make foreground text the named color and bright (however your terminal
does that).
=item * text_concealed
Conceal the text.
=item * underline
Turn on underlining.
=back
=cut
sub _256 ( $i, $n ) {
carp "Bad 256 $n" unless( int($n) == $n and $n >= 0 and $n <= 255 );
_seq( 'm', $i, 5, $n );
}
sub _bg () { 48 } # a magic number that applies the SGR to the background
sub _erase ( $n, $command ) {
carp "Bad value <$n>. Should be 0, 1, or 2"
unless grep { $_ == $n } qw(0 1 2);
carp "Bad erase command <$command>. Should be J or K"
unless grep { $_ == $n } qw(0 1 2);
_seq( $command, $n );
}
sub _export ( $name, $tag ) {
push @EXPORT_OK, $name;
push $EXPORT_TAGS{all }->@*, $name;
push $EXPORT_TAGS{$tag}->@*, $name;
}
sub _rgb ( $i, $r, $g, $b ) {
carp "Bad RGB $r;$b;$g" unless
3 == grep { int($_) == $_ and $_ >= 0 and $_ <= 255 }
( $r, $b, $g );
_seq( 'm', $i, 2, $r, $g, $b );
}
# _seq forms the ANSI escape sequence. There's the start, some arguments
# separated by `;`, then a string for the argument
sub _seq ( $command, @args ) { join '', "\x1b[", join( ';', @args ), $command }
sub _encode_seq ( $string ) {
local $_ = $string;
s/(.)/sprintf '%02X ', ord($1) /ge;
s/1b /ESC /ig;
s/07 /BEL /ig;
s/31 33 33 37 /1337 /;
s/([2-7A-F][0-9A-F])\x20/ chr( hex($1) ) . ' ' /ge;
$_;
}
sub _start () { "\x1b[" }
sub _text () { 38 } # a magic number that applies the SGR to the text
sub bg_256 ( $n ) { _256( _bg(), $n ) }
sub bg_rgb ( $r, $g, $b ) { _rgb( _bg(), $r, $g, $b ) }
sub cursor_row_column ( $n = 1, $m = 1 ) { _seq( 'H', $n, $m ) }
sub text_256 ( $n ) { _256( _text(), $n ) }
sub text_rgb ( $r, $g, $b ) { _rgb( _text(), $r, $g, $b ) }
# This section takes the subroutines that we've already defined to
# adds them to the export lists.
BEGIN {
my @subs = qw( bg_256 bg_rgb text_256 text_rgb
erase_in_display erase_in_line cursor_row_column
);
lib/Antsy.pm view on Meta::CPAN
}
my @secondary_colors = (
[ 'orange', [ 0xFF, 0x8C, 0x00 ] ],
);
foreach my $tuple ( @secondary_colors ) {
no strict 'refs';
my( $color, $rgb ) = $tuple->@*;
my $name = "text_$color";
my $value = text_rgb( $rgb->@* );
*{$name} = sub () { $value };
_export( $name, 'text' );
$name = "bg_$color";
$value = bg_rgb( $rgb->@* );
_export( $name, 'bg' );
}
}
=head2 Character shortcuts
=over 4
=item * BELL - \007
=item * CSI - ESC [
=item * ESC - \x1b
=item * OSC - ESC ]
=item * ST - BELL or ESC \
=item * SP - literal space
=back
=cut
sub BELL () { "\007" }
sub CSI () { ESC() . '[' }
sub ESC () { "\x1b" }
sub OSC () { ESC() . ']' }
sub SP () { ' ' }
sub ST () { BELL() }
=head2 Editor-specific codes
=head3 iTerm2
iTerm2 supports proprietary
=over 4
=item * iterm_bg_color()
=item * iterm_fg_color() OSC 4 ; -1; ? ST
Returns an array reference of the decimal values for the Red, Green
and Blue components of the background or foreground. These triplets
may be 2 or 4 digits in each component.
=cut
sub _iterm_id { 'iTerm.app' }
sub _is_term_type ( $id ) {
$ENV{TERM_PROGRAM} =~ m/\A\Q$id\E\z/;
}
sub _is_iterm { _is_term_type( _iterm_id() ) }
sub _iterm_seq ( $command, @args ) {
unless( _is_iterm() ) {
my $sub = ( caller(1) )[3];
carp( "$sub only works in iTerm2" );
return;
}
OSC() . join( ';', @args, '' ) . $command . ST();
}
sub _iterm_query ( $command, @args ) {
my $terminal = do {
state $rc = require Term::ReadKey;
chomp( my $tty = `/usr/bin/tty` );
# say "Term: ", $tty;
open my $terminal, '+<', $tty;
my $old = select( $terminal );
$|++;
select( $old );
$terminal;
};
print { $terminal } _iterm_seq( $command, @args );;
Term::ReadKey::ReadMode('raw');
my $response;
my $key;
while( defined ($key = Term::ReadKey::ReadKey(0)) ) {
$response .= $key;
last if ord( $key ) == 3; # Control-C
last if ord( $key ) == 7;
}
Term::ReadKey::ReadMode('normal');
$response;
}
sub _iterm_rgb_query ( $type ) {
state $OSC = qr/ ( \007 | \x1b \\ ) /xn;
my $response = _iterm_query( '?', 4, $type );
my( $r, $g, $b ) = $response =~ m|rgb:(.+?)/(.+?)/(.+?)$OSC|;
[ $r, $g, $b ]
}
sub iterm_bg_color () { _iterm_rgb_query( -2 ) } # OSC 4 ; -2; ? ST
sub iterm_fg_color () { _iterm_rgb_query( -1 ) } # OSC 4 ; -1; ? ST
=item * iterm_start_link( URL [, ID] )
lib/Antsy.pm view on Meta::CPAN
sub hide_cursor_guide () { state $s = _osc_1337( 'HighlightCursorLine=no' ); $s }
sub show_cursor_guide () { state $s = _osc_1337( 'HighlightCursorLine=yes' ); $s }
=item * iterm_attention
Play with the dock icon.
=over 4
=item * fireworks - animation at the cursor
=item * no - stop bouncing the dock icon
=item * once - bounce the dock icon once
=item * yes - bounce the dock indefinitely
=back
=cut
=item * iterm_bounce_dock_icon
Bounce the Dock icon, continuously
=item * iterm_bounce_dock_icon_once
Bounce the Dock icon, only once
=item * iterm_unbounce_dock_icon
Stop bouncing the Dock icon
=item * iterm_fireworks
Show animated fireworks.
=cut
# OSC 1337 ; RequestAttention=[value] ST
sub iterm_attention ( $value ) {
state $allowed = do {
my %hash = map { $_, 1 } qw( fireworks no once yes );
\%hash;
};
unless( exists $allowed->{$value} ) {
carp "iterm_attention argument can be one of <@{[ join ',', sort keys %$allowed ]}>, but you specified <$value>";
return;
}
my $r = _osc_1337( "RequestAttention=$value" );
say _encode_seq( $r );
$r;
}
sub iterm_bounce_dock_icon { iterm_attention( 'yes' ) }
sub iterm_bounce_dock_icon_once { iterm_attention( 'once' ) }
sub iterm_unbounce_dock_icon { iterm_attention( 'no' ) }
sub iterm_fireworks { iterm_attention( 'fireworks' ) }
=item * background_image_file
OSC 1337 ; SetBackgroundImageFile=[base64] ST
The value of [base64] is a base64-encoded filename to display as a background image. If it is an empty string then the background image will be removed. User confirmation is required as a security measure.
=item * report_cell_cell
OSC 1337 ; ReportCellSize ST
The terminal responds with either:
OSC 1337 ; ReportCellSize=[height];[width] ST
Or, in newer versions:
OSC 1337 ; ReportCellSize=[height];[width];[scale] ST
[scale] gives the number of pixels (physical units) to points (logical units). 1.0 means non-retina, 2.0 means retina. It could take other values in the future.
[height] and [width] are floating point values giving the size in points of a single character cell. For example:
OSC 1337 ; ReportCellSize=17.50;8.00;2.0 ST
=item * copy_to_pasteboard
You can place a string in the system's pasteboard with this sequence:
OSC 1337 ; Copy=:[base64] ST
Where [base64] is the base64-encoded string to copy to the pasteboard.
=item * report_variable
Each iTerm2 session has internal variables (as described in Scripting Fundamentals). This escape sequence reports a variable's value:
OSC 1337 ; ReportVariable=[base64] ST
Where [base64] is a base64-encoded variable name, like session.name. It responds with:
OSC 1337 ; ReportVariable=[base64] ST
Where [base64] is a base64-encoded value.
https://iterm2.com/documentation-scripting-fundamentals.html
=item * badge
The badge may be set with the following control sequence:
https://iterm2.com/documentation-badges.html
OSC 1337 ; SetBadgeFormat=Base-64 encoded badge format ST
Here's an example that works in bash:
# Set badge to show the current session name and git branch, if any is set.
printf "\e]1337;SetBadgeFormat=%s\a" \
$(echo -n "\(session.name) \(user.gitBranch)" | base64)
=item * downloads
https://iterm2.com/documentation-images.html
The width and height are given as a number followed by a unit, or the word "auto".
iTerm2 extends the xterm protocol with a set of proprietary escape sequences. In general, the pattern is:
ESC ] 1337 ; key = value ^G
Whitespace is shown here for ease of reading: in practice, no spaces should be used.
For file transfer and inline images, the code is:
( run in 1.786 second using v1.01-cache-2.11-cpan-99c4e6809bf )