App-optex-scroll

 view release on metacpan or  search on metacpan

lib/App/optex/scroll.pm  view on Meta::CPAN

    wait     => \(our $wait = 1),
    debug    => \(our $debug = undef),
    timeout  => \(our $timeout = 0.1),
    interval => 0,
);

sub hash_to_spec {
    pairmap {
	$a = "$a|${\(uc(substr($a, 0, 1)))}";
	my $ref = ref $b;
	if    (not defined $b)   { "$a!"  }
	elsif ($ref eq 'SCALAR') { "$a!"  }
	elsif (is_number($b))    { "$a=i" }
	else                     { "$a=s" }
    } shift->%*;
}

sub flush {
    STDERR->printflush(@_);
}

sub set_region {
    flush join('',
	       csi_code('DECSC'),
	       csi_code('STBM', @_),
	       csi_code('DECRC'));
}

END {
    close STDOUT if $wait;
    set_region();
}

sub finalize {
    our($mod, $argv) = @_;
    #
    # private option handling
    #
    if (@$argv and $argv->[0] !~ /^-M/ and
	defined(my $i = first { $argv->[$_] eq '--' } keys @$argv)) {
	splice @$argv, $i, 1; # remove '--'
	if (local @ARGV = splice @$argv, 0, $i) {
	    use Getopt::Long qw(GetOptionsFromArray);
	    Getopt::Long::Configure qw(bundling);
	    GetOptions \%opt, hash_to_spec \%opt or die "Option parse error.\n";
	}
    }
    my $i = first { $argv->[$_] eq '--' } keys @$argv;
    if (defined $i and $argv->[0] !~ /^-M/) {
	splice @$argv, $i, 1; # remove '--'
	if (local @ARGV = splice @$argv, 0, $i) {
	    use Getopt::Long qw(GetOptionsFromArray);
	    Getopt::Long::Configure qw(bundling);
	    GetOptions \%opt, hash_to_spec \%opt or die "Option parse error.\n";
	}
    }

    my $region = $opt{line};
    flush "\n" x $region;
    flush csi_code(CPL => $region); # CPL: Cursor Previous Line
    my($l, $c) = cursor_position() or return;
    set_region($l, $l + $region);

    if (my $time = $opt{interval}) {
	interval(time => $time);
    }
}

sub cursor_position {
    my $answer = ask(csi_code(DSR => 6), qr/R\z/); # DSR: Device Status Report
    csi_report(CPR => 2, $answer);                 # CPR: Cursor Position Report
}

sub uncntrl {
    $_[0] =~ s/([^\040-\176])/sprintf "\\%03o", ord $1/gear;
}

sub ask {
    my($request, $end_re) = @_;
    if ($debug) {
	flush sprintf "[%s] Request: %s\n",
	    __PACKAGE__,
	    uncntrl $request;
    }
    open my $tty, "+<", "/dev/tty" or return;
    ReadMode "cbreak", $tty;
    $tty->printflush($request);
    my $answer = '';
    while (defined (my $key = ReadKey $timeout, $tty)) {
	if ($debug) {
	    flush sprintf "[%s] ReadKey: \"%s\"\n",
		__PACKAGE__,
		$key =~ /\P{Cc}/ ? $key : uncntrl $key;
	}
	$answer .= $key;
	last if $answer =~ /$end_re/;
    }
    ReadMode "restore", $tty;
    if ($debug) {
	flush sprintf "[%s] Answer:  %s\n",
	    __PACKAGE__,
	    uncntrl $answer;
    }
    return $answer;
}

sub set {
    pairmap {
	if (ref $opt{$a} eq 'SCALAR') {
	    $opt{$a}->$* = $b;
	}
	elsif (ref $opt{$a} eq 'ARRAY') {
	    push $opt{$a}->@*, $b;
	}
	else {
	    $opt{$a} = $b;
	}
    } @_;
}

1;

__END__

=encoding utf-8

=head1 NAME

App::optex::scroll - optex scroll region module

=head1 SYNOPSIS

optex -Mscroll [ options -- ] command

=head1 VERSION

Version 0.9902

=head1 DESCRIPTION

B<optex>'s B<scroll> module prevents a command that produces output
longer than terminal hight from causing the executed command line to
scroll out from the screen.

It sets the scroll region for the output of the command it executes.
The output of the command scrolls by default 10 lines from the cursor
position where it was executed.

=head1 OPTIONS

=over 7

=item B<--line>=I<n>

Set scroll region lines to I<n>.
Default is 10.

=item B<--interval>=I<sec>

Specifies the interval time in seconds between outputting each line.
Default is 0 seconds.

=back

=head1 EXAMPLES

    optex -Mscroll ping localhost

    optex -Mscroll seq 100000

    optex -Mscroll tail -f /var/log/system.log

=begin html

<p><img width="750" src="https://raw.githubusercontent.com/kaz-utashiro/optex-scroll/main/images/ping.png">

=end html

    optex -Mpingu -Mscroll --line 20 -- ping --pingu -i0.2 -c75 localhost

=begin html

<p>
<a href="https://www.youtube.com/watch?v=C3LoPAe7YB8">
<img width="750" src="https://raw.githubusercontent.com/kaz-utashiro/optex-scroll/main/images/pingu.png">
</a>

=end html

=head1 INSTALL

Use L<cpanminus(1)> command:

    cpanm App::optex::scroll

=head1 SEE ALSO

L<App::optex>,
L<https://github.com/kaz-utashiro/optex/>

L<App::optex::scroll>,
L<https://github.com/kaz-utashiro/optex-scroll/>

L<App::optex::pingu>,
L<https://github.com/kaz-utashiro/optex-pingu/>



( run in 1.102 second using v1.01-cache-2.11-cpan-cdf2f3d4e48 )