1#!/usr/bin/env perl 2# $XTermId: insdelln.pl,v 1.10 2022/10/10 17:05:38 tom Exp $ 3# ----------------------------------------------------------------------------- 4# this file is part of xterm 5# 6# Copyright 2009,2022 by Thomas E. Dickey 7# 8# All Rights Reserved 9# 10# Permission is hereby granted, free of charge, to any person obtaining a 11# copy of this software and associated documentation files (the 12# "Software"), to deal in the Software without restriction, including 13# without limitation the rights to use, copy, modify, merge, publish, 14# distribute, sublicense, and/or sell copies of the Software, and to 15# permit persons to whom the Software is furnished to do so, subject to 16# the following conditions: 17# 18# The above copyright notice and this permission notice shall be included 19# in all copies or substantial portions of the Software. 20# 21# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS 22# OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF 23# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. 24# IN NO EVENT SHALL THE ABOVE LISTED COPYRIGHT HOLDER(S) BE LIABLE FOR ANY 25# CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, 26# TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE 27# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 28# 29# Except as contained in this notice, the name(s) of the above copyright 30# holders shall not be used in advertising or otherwise to promote the 31# sale, use or other dealings in this Software without prior written 32# authorization. 33# ----------------------------------------------------------------------------- 34# Tests insert/delete-line feature in xterm. This applies only to the 35# visible screen (saved-lines are unaffected). 36# 37# TODO: 38# add option to wrap the test-pattern 39# use scrolling-margins to help fill-in a chunk 40use strict; 41use warnings; 42 43use Getopt::Std; 44 45# do this so output from successive calls to this script won't get in the 46# wrong order: 47use IO::Handle; 48STDERR->autoflush(1); 49STDOUT->autoflush(1); 50 51our ( $opt_c, $opt_n, $opt_r, $opt_w ); 52our ( $lineno, $test_string, $term_height, $term_width ); 53 54our @resize; 55 56sub read_resize($) { 57 my $field = shift; 58 my $result = shift; 59 if ( $#resize < 0 ) { 60 open( FP, "resize -u |" ) or exit $!; 61 @resize = <FP>; 62 chomp @resize; 63 close(FP); 64 } 65 for my $n ( 0 .. $#resize ) { 66 if ( $resize[$n] =~ /^$field=/ ) { 67 $result = $resize[$n]; 68 $result =~ s/^[^=]*=//; 69 $result =~ s/;.*//; 70 last; 71 } 72 } 73 return $result; 74} 75 76# returns the number of rows in the screen 77sub screen_height() { 78 return &read_resize( "LINES", 24 ); 79} 80 81# returns the number of columns in the screen 82sub screen_width() { 83 return &read_resize( "COLUMNS", 80 ); 84} 85 86sub set_color($) { 87 my $code = $_[0]; 88 if ( defined($opt_c) ) { 89 if ( $code == 3 ) { 90 printf "\x1b[1;33;42m"; # yellow-on-green 91 } 92 elsif ( $code == 2 ) { 93 printf "\x1b[0;31;45m"; # red-on-magenta 94 } 95 elsif ( $code == 1 ) { 96 printf "\x1b[0;36;44m"; # cyan-on-blue 97 } 98 else { 99 printf "\x1b[0;39;49m"; 100 } 101 } 102} 103 104# returns a string of two-column characters given an ASCII alpha/numeric string 105sub double_cells($) { 106 my $value = $_[0]; 107 $value =~ s/ / /g; 108 pack( 109 "U*", 110 map { 111 ( $_ <= 32 || $_ > 127 ) # if non-ASCII character... 112 ? 32 # ...just show a blank 113 : ( 0xff00 + ( $_ - 32 ) ) # map to "Fullwidth Form" 114 } unpack( "C*", $value ) 115 ); # unpack unsigned-char characters 116} 117 118sub clear_screen() { 119 upper_left(); 120 printf "\x1b[J"; 121} 122 123sub clr_to_eol() { 124 printf "\x1b[K"; 125} 126 127sub lower_left() { 128 printf "\x1b[%dH", $term_height; 129} 130 131sub upper_left() { 132 printf "\x1b[H"; 133} 134 135sub move_to($) { 136 printf "\x1b[%dG", $_[0] + 1; 137} 138 139sub insert_lines($) { 140 141 #lower_left; 142 if ( $_[0] ) { 143 printf "\x1b[%dL", $_[0]; 144 } 145 else { 146 printf "\x1b[L"; 147 } 148} 149 150sub delete_lines($) { 151 if ( $_[0] ) { 152 printf "\x1b[%dM", $_[0]; 153 } 154 else { 155 printf "\x1b[M"; 156 } 157} 158 159sub delete_char() { 160 set_color(2); 161 printf "\x1b[%dP", 1; 162 set_color(1); 163} 164 165sub insert_once($) { 166 my $text = shift; 167 set_color(2); 168 printf "\x1b[%d@", length($text); 169 write_chars($text); 170} 171 172sub insert_mode($) { 173 set_color(2); 174 printf "\x1b[%dP", length( $_[0] ); 175 printf "\x1b[4h"; 176 write_chars( $_[0] ); 177 printf "\x1b[4l"; 178} 179 180sub write_chars($) { 181 set_color(3); 182 printf "%s", $_[0]; 183 set_color(1); 184} 185 186# vary the starting point of each line, to make a more interesting pattern 187sub starts_of($) { 188 my $value = $_[0]; 189 if ( defined($opt_w) ) { 190 191 # 0,1,1,2,2,3,3,... 192 $value = ( ( $value + 1 ) / 2 ) % length($test_string); 193 } 194 else { 195 $value %= length($test_string); 196 } 197 return $value; 198} 199 200# write the text for the given line-number 201sub testit($) { 202 my $number = $_[0]; 203 my $length = $term_width; 204 205 # use delete-lines to "pull" the screen up, like scrolling. 206 select( undef, undef, undef, 0.1 ); 207 if ( ( ( $number / $term_height ) % 2 ) != 0 ) { 208 upper_left; 209 insert_lines(1); 210 } 211 else { 212 upper_left; 213 delete_lines(1); 214 lower_left; 215 } 216 if ( defined($opt_n) ) { 217 printf "%5d ", $number % 99999; 218 $length -= 6; 219 } 220 221 # if we're printing double-column characters, we have half as much 222 # space effectively - but don't forget the remainder, so we can push 223 # the characters by single-columns. 224 if ( defined($opt_c) ) { 225 set_color(1); 226 clr_to_eol(); 227 } 228 my $starts = starts_of($number); 229 if ( defined($opt_w) ) { 230 printf " ", if ( ( $number % 2 ) != 0 ); 231 $length = ( $length - ( ($number) % 2 ) ) / 2; 232 } 233 my $string = substr( $test_string, $starts ); 234 while ( length($string) < $length ) { 235 $string = $string . $test_string; 236 } 237 $string = substr( $string, 0, $length ); 238 if ( defined($opt_w) ) { 239 $string = double_cells($string); 240 } 241 printf "%s", $string; 242 243 # now - within the line - modify it 244 move_to( ( 4 * $term_width ) / 5 ); 245 insert_mode("XX"); 246 move_to( ( 3 * $term_width ) / 5 ); 247 delete_char(); 248 move_to( ( 2 * $term_width ) / 5 ); 249 insert_once('~'); 250 move_to( ( 1 * $term_width ) / 5 ); 251 write_chars('~'); 252 move_to(0); 253 set_color(0); 254} 255 256sub main::HELP_MESSAGE() { 257 printf STDERR <<EOF 258Usage: $0 [options] 259 260Options: 261 262-c use color 263-n write line-numbers 264-r repeat indefinitely 265-w write wide-characters 266EOF 267 ; 268 exit; 269} 270 271&getopts('cnrw') || die(); 272 273$term_height = screen_height(); 274$term_width = screen_width(); 275 276$test_string = 277 "0123456789 abcdefghijklmnopqrstuvwxyz ABCDEFGHIJKLMNOPQRSTUVWXYZ"; 278 279binmode( STDOUT, ":utf8" ); 280clear_screen(); 281if ( defined($opt_r) ) { 282 for ( $lineno = 0 ; ; ++$lineno ) { 283 testit($lineno); 284 } 285} 286else { 287 for ( $lineno = 0 ; $lineno < $term_height * 2 ; ++$lineno ) { 288 testit($lineno); 289 } 290} 291lower_left(); 292clr_to_eol(); 293 294exit; 295