1a5ae21e4Smrg#!/usr/bin/env perl
204b94745Smrg# $XTermId: insdelln.pl,v 1.10 2022/10/10 17:05:38 tom Exp $
3a5ae21e4Smrg# -----------------------------------------------------------------------------
4a5ae21e4Smrg# this file is part of xterm
5a5ae21e4Smrg#
65307cd1aSmrg# Copyright 2009,2022 by Thomas E. Dickey
7a5ae21e4Smrg#
8a5ae21e4Smrg#                         All Rights Reserved
9a5ae21e4Smrg#
10a5ae21e4Smrg# Permission is hereby granted, free of charge, to any person obtaining a
11a5ae21e4Smrg# copy of this software and associated documentation files (the
12a5ae21e4Smrg# "Software"), to deal in the Software without restriction, including
13a5ae21e4Smrg# without limitation the rights to use, copy, modify, merge, publish,
14a5ae21e4Smrg# distribute, sublicense, and/or sell copies of the Software, and to
15a5ae21e4Smrg# permit persons to whom the Software is furnished to do so, subject to
16a5ae21e4Smrg# the following conditions:
17a5ae21e4Smrg#
18a5ae21e4Smrg# The above copyright notice and this permission notice shall be included
19a5ae21e4Smrg# in all copies or substantial portions of the Software.
20a5ae21e4Smrg#
21a5ae21e4Smrg# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
22a5ae21e4Smrg# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23a5ae21e4Smrg# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
24a5ae21e4Smrg# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY
25a5ae21e4Smrg# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
26a5ae21e4Smrg# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
27a5ae21e4Smrg# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28a5ae21e4Smrg#
29a5ae21e4Smrg# Except as contained in this notice, the name(s) of the above copyright
30a5ae21e4Smrg# holders shall not be used in advertising or otherwise to promote the
31a5ae21e4Smrg# sale, use or other dealings in this Software without prior written
32a5ae21e4Smrg# authorization.
33a5ae21e4Smrg# -----------------------------------------------------------------------------
34a5ae21e4Smrg# Tests insert/delete-line feature in xterm.  This applies only to the
35a5ae21e4Smrg# visible screen (saved-lines are unaffected).
36a5ae21e4Smrg#
37a5ae21e4Smrg# TODO:
38a5ae21e4Smrg#	add option to wrap the test-pattern
39a5ae21e4Smrg#	use scrolling-margins to help fill-in a chunk
40a5ae21e4Smrguse strict;
415307cd1aSmrguse warnings;
42a5ae21e4Smrg
43a5ae21e4Smrguse Getopt::Std;
44a5ae21e4Smrg
455307cd1aSmrg# do this so output from successive calls to this script won't get in the
46a5ae21e4Smrg# wrong order:
47a5ae21e4Smrguse IO::Handle;
48a5ae21e4SmrgSTDERR->autoflush(1);
49a5ae21e4SmrgSTDOUT->autoflush(1);
50a5ae21e4Smrg
515307cd1aSmrgour ( $opt_c,  $opt_n,       $opt_r,       $opt_w );
525307cd1aSmrgour ( $lineno, $test_string, $term_height, $term_width );
535307cd1aSmrg
545307cd1aSmrgour @resize;
555307cd1aSmrg
565307cd1aSmrgsub read_resize($) {
575307cd1aSmrg    my $field  = shift;
585307cd1aSmrg    my $result = shift;
595307cd1aSmrg    if ( $#resize < 0 ) {
605307cd1aSmrg        open( FP, "resize -u |" ) or exit $!;
615307cd1aSmrg        @resize = <FP>;
625307cd1aSmrg        chomp @resize;
635307cd1aSmrg        close(FP);
645307cd1aSmrg    }
655307cd1aSmrg    for my $n ( 0 .. $#resize ) {
665307cd1aSmrg        if ( $resize[$n] =~ /^$field=/ ) {
675307cd1aSmrg            $result = $resize[$n];
685307cd1aSmrg            $result =~ s/^[^=]*=//;
695307cd1aSmrg            $result =~ s/;.*//;
705307cd1aSmrg            last;
715307cd1aSmrg        }
725307cd1aSmrg    }
735307cd1aSmrg    return $result;
745307cd1aSmrg}
75a5ae21e4Smrg
76a5ae21e4Smrg# returns the number of rows in the screen
77a5ae21e4Smrgsub screen_height() {
785307cd1aSmrg    return &read_resize( "LINES", 24 );
79a5ae21e4Smrg}
80a5ae21e4Smrg
81a5ae21e4Smrg# returns the number of columns in the screen
82a5ae21e4Smrgsub screen_width() {
835307cd1aSmrg    return &read_resize( "COLUMNS", 80 );
84a5ae21e4Smrg}
85a5ae21e4Smrg
86a5ae21e4Smrgsub set_color($) {
875307cd1aSmrg    my $code = $_[0];
885307cd1aSmrg    if ( defined($opt_c) ) {
895307cd1aSmrg        if ( $code == 3 ) {
905307cd1aSmrg            printf "\x1b[1;33;42m";    # yellow-on-green
915307cd1aSmrg        }
925307cd1aSmrg        elsif ( $code == 2 ) {
935307cd1aSmrg            printf "\x1b[0;31;45m";    # red-on-magenta
945307cd1aSmrg        }
955307cd1aSmrg        elsif ( $code == 1 ) {
965307cd1aSmrg            printf "\x1b[0;36;44m";    # cyan-on-blue
975307cd1aSmrg        }
985307cd1aSmrg        else {
995307cd1aSmrg            printf "\x1b[0;39;49m";
1005307cd1aSmrg        }
1015307cd1aSmrg    }
102a5ae21e4Smrg}
103a5ae21e4Smrg
104a5ae21e4Smrg# returns a string of two-column characters given an ASCII alpha/numeric string
105a5ae21e4Smrgsub double_cells($) {
1065307cd1aSmrg    my $value = $_[0];
1075307cd1aSmrg    $value =~ s/ /  /g;
1085307cd1aSmrg    pack(
1095307cd1aSmrg        "U*",
1105307cd1aSmrg        map {
1115307cd1aSmrg            ( $_ <= 32 || $_ > 127 )    # if non-ASCII character...
1125307cd1aSmrg              ? 32                      # ...just show a blank
1135307cd1aSmrg              : ( 0xff00 + ( $_ - 32 ) )    # map to "Fullwidth Form"
1145307cd1aSmrg        } unpack( "C*", $value )
1155307cd1aSmrg    );                                      # unpack unsigned-char characters
116a5ae21e4Smrg}
117a5ae21e4Smrg
118a5ae21e4Smrgsub clear_screen() {
1195307cd1aSmrg    upper_left();
1205307cd1aSmrg    printf "\x1b[J";
121a5ae21e4Smrg}
122a5ae21e4Smrg
123a5ae21e4Smrgsub clr_to_eol() {
1245307cd1aSmrg    printf "\x1b[K";
125a5ae21e4Smrg}
126a5ae21e4Smrg
127a5ae21e4Smrgsub lower_left() {
1285307cd1aSmrg    printf "\x1b[%dH", $term_height;
129a5ae21e4Smrg}
130a5ae21e4Smrg
131a5ae21e4Smrgsub upper_left() {
1325307cd1aSmrg    printf "\x1b[H";
133a5ae21e4Smrg}
134a5ae21e4Smrg
135a5ae21e4Smrgsub move_to($) {
1365307cd1aSmrg    printf "\x1b[%dG", $_[0] + 1;
137a5ae21e4Smrg}
138a5ae21e4Smrg
139a5ae21e4Smrgsub insert_lines($) {
1405307cd1aSmrg
1415307cd1aSmrg    #lower_left;
1425307cd1aSmrg    if ( $_[0] ) {
1435307cd1aSmrg        printf "\x1b[%dL", $_[0];
1445307cd1aSmrg    }
1455307cd1aSmrg    else {
1465307cd1aSmrg        printf "\x1b[L";
1475307cd1aSmrg    }
148a5ae21e4Smrg}
149a5ae21e4Smrg
150a5ae21e4Smrgsub delete_lines($) {
1515307cd1aSmrg    if ( $_[0] ) {
1525307cd1aSmrg        printf "\x1b[%dM", $_[0];
1535307cd1aSmrg    }
1545307cd1aSmrg    else {
1555307cd1aSmrg        printf "\x1b[M";
1565307cd1aSmrg    }
157a5ae21e4Smrg}
158a5ae21e4Smrg
159a5ae21e4Smrgsub delete_char() {
1605307cd1aSmrg    set_color(2);
1615307cd1aSmrg    printf "\x1b[%dP", 1;
1625307cd1aSmrg    set_color(1);
163a5ae21e4Smrg}
164a5ae21e4Smrg
165a5ae21e4Smrgsub insert_once($) {
1665307cd1aSmrg    my $text = shift;
1675307cd1aSmrg    set_color(2);
1685307cd1aSmrg    printf "\x1b[%d@", length($text);
1695307cd1aSmrg    write_chars($text);
170a5ae21e4Smrg}
171a5ae21e4Smrg
172a5ae21e4Smrgsub insert_mode($) {
1735307cd1aSmrg    set_color(2);
1745307cd1aSmrg    printf "\x1b[%dP", length( $_[0] );
1755307cd1aSmrg    printf "\x1b[4h";
1765307cd1aSmrg    write_chars( $_[0] );
1775307cd1aSmrg    printf "\x1b[4l";
178a5ae21e4Smrg}
179a5ae21e4Smrg
180a5ae21e4Smrgsub write_chars($) {
1815307cd1aSmrg    set_color(3);
1825307cd1aSmrg    printf "%s", $_[0];
1835307cd1aSmrg    set_color(1);
184a5ae21e4Smrg}
185a5ae21e4Smrg
186a5ae21e4Smrg# vary the starting point of each line, to make a more interesting pattern
187a5ae21e4Smrgsub starts_of($) {
1885307cd1aSmrg    my $value = $_[0];
1895307cd1aSmrg    if ( defined($opt_w) ) {
1905307cd1aSmrg
1915307cd1aSmrg        # 0,1,1,2,2,3,3,...
1925307cd1aSmrg        $value = ( ( $value + 1 ) / 2 ) % length($test_string);
1935307cd1aSmrg    }
1945307cd1aSmrg    else {
1955307cd1aSmrg        $value %= length($test_string);
1965307cd1aSmrg    }
1975307cd1aSmrg    return $value;
198a5ae21e4Smrg}
199a5ae21e4Smrg
200a5ae21e4Smrg# write the text for the given line-number
201a5ae21e4Smrgsub testit($) {
2025307cd1aSmrg    my $number = $_[0];
2035307cd1aSmrg    my $length = $term_width;
2045307cd1aSmrg
2055307cd1aSmrg    # use delete-lines to "pull" the screen up, like scrolling.
2065307cd1aSmrg    select( undef, undef, undef, 0.1 );
2075307cd1aSmrg    if ( ( ( $number / $term_height ) % 2 ) != 0 ) {
2085307cd1aSmrg        upper_left;
2095307cd1aSmrg        insert_lines(1);
2105307cd1aSmrg    }
2115307cd1aSmrg    else {
2125307cd1aSmrg        upper_left;
2135307cd1aSmrg        delete_lines(1);
2145307cd1aSmrg        lower_left;
2155307cd1aSmrg    }
2165307cd1aSmrg    if ( defined($opt_n) ) {
2175307cd1aSmrg        printf "%5d ", $number % 99999;
2185307cd1aSmrg        $length -= 6;
2195307cd1aSmrg    }
2205307cd1aSmrg
2215307cd1aSmrg    # if we're printing double-column characters, we have half as much
2225307cd1aSmrg    # space effectively - but don't forget the remainder, so we can push
2235307cd1aSmrg    # the characters by single-columns.
2245307cd1aSmrg    if ( defined($opt_c) ) {
2255307cd1aSmrg        set_color(1);
2265307cd1aSmrg        clr_to_eol();
2275307cd1aSmrg    }
2285307cd1aSmrg    my $starts = starts_of($number);
2295307cd1aSmrg    if ( defined($opt_w) ) {
2305307cd1aSmrg        printf " ", if ( ( $number % 2 ) != 0 );
2315307cd1aSmrg        $length = ( $length - ( ($number) % 2 ) ) / 2;
2325307cd1aSmrg    }
2335307cd1aSmrg    my $string = substr( $test_string, $starts );
2345307cd1aSmrg    while ( length($string) < $length ) {
2355307cd1aSmrg        $string = $string . $test_string;
2365307cd1aSmrg    }
2375307cd1aSmrg    $string = substr( $string, 0, $length );
2385307cd1aSmrg    if ( defined($opt_w) ) {
2395307cd1aSmrg        $string = double_cells($string);
2405307cd1aSmrg    }
2415307cd1aSmrg    printf "%s", $string;
2425307cd1aSmrg
2435307cd1aSmrg    # now - within the line - modify it
2445307cd1aSmrg    move_to( ( 4 * $term_width ) / 5 );
2455307cd1aSmrg    insert_mode("XX");
2465307cd1aSmrg    move_to( ( 3 * $term_width ) / 5 );
2475307cd1aSmrg    delete_char();
2485307cd1aSmrg    move_to( ( 2 * $term_width ) / 5 );
2495307cd1aSmrg    insert_once('~');
2505307cd1aSmrg    move_to( ( 1 * $term_width ) / 5 );
2515307cd1aSmrg    write_chars('~');
2525307cd1aSmrg    move_to(0);
2535307cd1aSmrg    set_color(0);
254a5ae21e4Smrg}
255a5ae21e4Smrg
256a5ae21e4Smrgsub main::HELP_MESSAGE() {
2575307cd1aSmrg    printf STDERR <<EOF
258a5ae21e4SmrgUsage: $0 [options]
259a5ae21e4Smrg
260a5ae21e4SmrgOptions:
261a5ae21e4Smrg
262a5ae21e4Smrg-c   use color
263a5ae21e4Smrg-n   write line-numbers
264a5ae21e4Smrg-r   repeat indefinitely
265a5ae21e4Smrg-w   write wide-characters
266a5ae21e4SmrgEOF
2675307cd1aSmrg      ;
2685307cd1aSmrg    exit;
269a5ae21e4Smrg}
270a5ae21e4Smrg
271a5ae21e4Smrg&getopts('cnrw') || die();
272a5ae21e4Smrg
273a5ae21e4Smrg$term_height = screen_height();
2745307cd1aSmrg$term_width  = screen_width();
275a5ae21e4Smrg
2765307cd1aSmrg$test_string =
2775307cd1aSmrg  "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ";
278a5ae21e4Smrg
2795307cd1aSmrgbinmode( STDOUT, ":utf8" );
280a5ae21e4Smrgclear_screen();
281a5ae21e4Smrgif ( defined($opt_r) ) {
2825307cd1aSmrg    for ( $lineno = 0 ; ; ++$lineno ) {
2835307cd1aSmrg        testit($lineno);
2845307cd1aSmrg    }
2855307cd1aSmrg}
2865307cd1aSmrgelse {
2875307cd1aSmrg    for ( $lineno = 0 ; $lineno < $term_height * 2 ; ++$lineno ) {
2885307cd1aSmrg        testit($lineno);
2895307cd1aSmrg    }
290a5ae21e4Smrg}
291a5ae21e4Smrglower_left();
292a5ae21e4Smrgclr_to_eol();
293a5ae21e4Smrg
294a5ae21e4Smrgexit;
295