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