1# You may distribute under the terms of either the GNU General Public License 2# or the Artistic License (the same terms as Perl itself) 3# 4# (C) Paul Evans, 2009-2020 -- leonerd@leonerd.org.uk 5 6package Tickit::Term 0.72; 7 8use v5.14; 9use warnings; 10 11use Carp; 12 13# Load the XS code 14use Tickit qw( MOD_SHIFT MOD_ALT MOD_CTRL BIND_FIRST ); 15 16# We export some constants 17use Exporter 'import'; 18 19# Old names for these 20use constant { 21 TERM_CURSORSHAPE_BLOCK => CURSORSHAPE_BLOCK, 22 TERM_CURSORSHAPE_UNDER => CURSORSHAPE_UNDER, 23 TERM_CURSORSHAPE_LEFT_BAR => CURSORSHAPE_LEFT_BAR, 24}; 25 26push our @EXPORT_OK, qw( 27 TERM_CURSORSHAPE_BLOCK TERM_CURSORSHAPE_UNDER TERM_CURSORSHAPE_LEFT_BAR 28 MOD_SHIFT MOD_ALT MOD_CTRL 29 BIND_FIRST 30); 31 32=head1 NAME 33 34C<Tickit::Term> - terminal formatting abstraction 35 36=head1 SYNOPSIS 37 38=head1 DESCRIPTION 39 40Provides terminal control primitives for L<Tickit>; a number of methods that 41control the terminal by writing control strings. This object itself performs 42no actual IO work; it writes bytes to a delegated object given to the 43constructor called the writer. 44 45This object is not normally constructed directly by the containing 46application; instead it is used indirectly by other parts of the C<Tickit> 47distribution. 48 49Note that a given program may contain multiple objects in this class that all 50refer to the same underlying C<TickitTerm> instance from the C library. This 51is especially true of the first argument provided to event binding callbacks. 52This class overloads numify and stringify operations, so that instances may be 53compared using the C<==> or C<eq> operators, or used as keys in hashes, and 54they will act as expected. Do not rely on plain C<refaddr> comparison however 55as you may get incorrect results. 56 57=cut 58 59use overload 60 '0+' => "_xs_addr", 61 '""' => sub { sprintf "Tickit::Term=XS(tt=0x%x)", $_[0]->_xs_addr }, 62 fallback => 1; 63 64=head1 CONSTRUCTOR 65 66=cut 67 68=head2 new 69 70 $term = Tickit::Term->new( %params ) 71 72Constructs a new C<Tickit::Term> object. 73 74Takes the following named arguments at construction time: 75 76=over 8 77 78=item UTF8 => BOOL 79 80If defined, overrides locale detection to enable or disable UTF-8 mode. If not 81defined then this will be detected from the locale by using Perl's 82C<${^UTF8LOCALE}> variable. 83 84=item writer => OBJECT 85 86An object delegated to for sending strings of terminal control bytes to the 87terminal itself. This object must support a single method, C<write>, taking 88a string of bytes. 89 90 $writer->write( $data ) 91 92Such an interface is supported by an C<IO::Handle> object. 93 94=item output_handle => HANDLE 95 96Optional. If supplied, will be used as the terminal filehandle for querying 97the size. Even if supplied, all writing operations will use the C<writer> 98function rather than performing IO operations on this filehandle. 99 100=item input_handle => HANDLE 101 102Optional. If supplied, will be used as the terminal filehandle for reading 103keypress and other events. 104 105=back 106 107=cut 108 109sub new 110{ 111 my $class = shift; 112 my %params = @_; 113 114 return $class->_new( 115 $ENV{TERM}, @params{qw( input_handle output_handle writer UTF8 )} 116 ) || croak "Cannot construct Tickit::Term - $!"; 117} 118 119=head2 open_stdio 120 121 $term = Tickit::Term->open_stdio 122 123Convenient shortcut for obtaining a L<Tickit::Term> instance bound to the 124STDIN and STDOUT streams of the process. 125 126=cut 127 128=head1 METHODS 129 130=cut 131 132=head2 get_input_handle 133 134 $fh = $term->get_input_handle 135 136Returns the input handle set by the C<input_handle> constructor arg. 137 138Note that because L<Tickit::Term> merely wraps an object provided by the 139lower-level F<libtickit> C library, it is no longer guaranteed that this 140method will return the same perl-level object that was given to the 141constructor. The object may be newly-constructed to represent a new perl-level 142readable filehandle on the same file number. 143 144=cut 145 146sub get_input_handle 147{ 148 my $self = shift; 149 return IO::Handle->new_from_fd( $self->get_input_fd, "r" ); 150} 151 152=head2 get_output_handle 153 154 $fh = $term->get_output_handle 155 156Returns the output handle set by the C<output_handle> constructor arg. 157 158Note that because L<Tickit::Term> merely wraps an object provided by the 159lower-level F<libtickit> C library, it is no longer guaranteed that this 160method will return the same perl-level object that was given to the 161constructor. The object may be newly-constructed to represent a new perl-level 162writable filehandle on the same file number. 163 164=cut 165 166sub get_output_handle 167{ 168 my $self = shift; 169 return IO::Handle->new_from_fd( $self->get_output_fd, "w" ); 170} 171 172=head2 set_output_buffer 173 174 $term->set_output_buffer( $len ) 175 176Sets the size of the output buffer 177 178=cut 179 180=head2 await_started 181 182 $term->await_started( $timeout ) 183 184Waits for the terminal startup process to complete, up to the timeout given in 185seconds. 186 187=cut 188 189=head2 pause 190 191 $term->pause 192 193Suspends operation of the terminal by resetting it to its default state. 194 195=cut 196 197=head2 resume 198 199 $term->resume 200 201Resumes operation of the terminal after a L</pause>. 202 203Typically these two methods are used together, either side of a blocking wait 204around a C<SIGSTOP>. 205 206 sub suspend 207 { 208 $term->pause; 209 kill STOP => $$; 210 $term->resume; 211 $rootwin->expose; 212 } 213 214=cut 215 216=head2 teardown 217 218 $term->teardown 219 220Shuts down operation of the terminal entirely, in preparation for terminating 221the process. 222 223=cut 224 225=head2 flush 226 227 $term->flush 228 229Flushes the output buffer to the terminal 230 231=cut 232 233=head2 bind_event 234 235 $id = $term->bind_event( $ev, $code, $data ) 236 237Installs a new event handler to watch for the event specified by C<$ev>, 238invoking the C<$code> reference when it occurs. C<$code> will be invoked with 239the given terminal, the event name, an event information object, and the 240C<$data> value it was installed with. C<bind_event> returns an ID value that 241may be used to remove the handler by calling C<unbind_event_id>. 242 243 $ret = $code->( $term, $ev, $info, $data ) 244 245The type of C<$info> will depend on the kind of event that was received, as 246indicated by C<$ev>. The information structure types are documented in 247L<Tickit::Event>. 248 249=head2 bind_event (with flags) 250 251 $id = $term->bind_event( $ev, $flags, $code, $data ) 252 253The C<$code> argument may optionally be preceded by an integer of flag 254values. This should be zero to apply default semantics, or a bitmask of one or 255more of the following constants: 256 257=over 4 258 259=item TICKIT_BIND_FIRST 260 261Inserts this event handler first in the chain, before any existing ones. 262 263=item TICKIT_BIND_ONESHOT 264 265Remove the event handler after it has been invoked the first time. 266 267=back 268 269=head2 unbind_event_id 270 271 $term->unbind_event_id( $id ) 272 273Removes an event handler that returned the given C<$id> value. 274 275=cut 276 277sub bind_event 278{ 279 my $self = shift; 280 my $ev = shift; 281 my ( $flags, $code, $data ) = ( ref $_[0] ) ? ( 0, @_ ) : @_; 282 283 $self->_bind_event( $ev, $flags, $code, $data ); 284} 285 286=head2 refresh_size 287 288 $term->refresh_size 289 290If a filehandle was supplied to the constructor, fetch the size of the 291terminal and update the cached sizes in the object. May invoke C<on_resize> if 292the new size is different. 293 294=cut 295 296=head2 set_size 297 298 $term->set_size( $lines, $cols ) 299 300Defines the size of the terminal. Invoke C<on_resize> if the new size is 301different. 302 303=cut 304 305=head2 lines 306 307=head2 cols 308 309 $lines = $term->lines 310 311 $cols = $term->cols 312 313Query the size of the terminal, as set by the most recent C<refresh_size> or 314C<set_size> operation. 315 316=cut 317 318sub lines { ( shift->get_size )[0] } 319sub cols { ( shift->get_size )[1] } 320 321=head2 goto 322 323 $success = $term->goto( $line, $col ) 324 325Move the cursor to the given position on the screen. If only one parameter is 326defined, does not alter the other. Both C<$line> and C<$col> are 0-based. 327 328Note that not all terminals can support these partial moves. This method 329returns a boolean indicating success; if the terminal could not perform the 330move it will need to be retried using a fully-specified call. 331 332=cut 333 334=head2 move 335 336 $term->move( $downward, $rightward ) 337 338Move the cursor relative to where it currently is. 339 340=cut 341 342=head2 scrollrect 343 344 $success = $term->scrollrect( $top, $left, $lines, $cols, $downward, $rightward ) 345 346Attempt to scroll the rectangle of the screen defined by the first four 347parameters by an amount given by the latter two. Since most terminals cannot 348perform arbitrary rectangle scrolling, this method returns a boolean to 349indicate if it was successful. The caller should test this return value and 350fall back to another drawing strategy if the attempt was unsuccessful. 351 352The cursor may move as a result of calling this method; its location is 353undefined if this method returns successful. 354 355=cut 356 357=head2 chpen 358 359 $term->chpen( $pen ) 360 361 $term->chpen( %attrs ) 362 363Changes the current pen attributes to those given. Any attribute whose value 364is given as C<undef> is reset. Any attributes not named are unchanged. 365 366For details of the supported pen attributes, see L<Tickit::Pen>. 367 368=cut 369 370=head2 setpen 371 372 $term->setpen( $pen ) 373 374 $term->setpen( %attrs ) 375 376Similar to C<chpen>, but completely defines the state of the terminal pen. Any 377attribute not given will be reset to its default value. 378 379=cut 380 381=head2 print 382 383 $term->print( $text, [ $pen ] ) 384 385Print the given text to the terminal at the current cursor position. 386 387An optional C<Tickit::Pen> may be provided; if present it will be set as if 388given to C<setpen> first. 389 390=cut 391 392=head2 clear 393 394 $term->clear( [ $pen ] ) 395 396Erase the entire screen. 397 398An optional C<Tickit::Pen> may be provided; if present it will be set as if 399given to C<setpen> first. 400 401=cut 402 403=head2 erasech 404 405 $term->erasech( $count, $moveend, [ $pen ] ) 406 407Erase C<$count> characters forwards. If C<$moveend> is true, the cursor is 408moved to the end of the erased region. If defined but false, the cursor will 409remain where it is. If undefined, the terminal will perform whichever of these 410behaviours is more efficient, and the cursor will end at some undefined 411location. 412 413Using C<$moveend> may be more efficient than separate C<erasech> and C<goto> 414calls on terminals that do not have an erase function, as it will be 415implemented by printing spaces. This removes the need for two cursor jumps. 416 417An optional C<Tickit::Pen> may be provided; if present it will be set as if 418given to C<setpen> first. 419 420=cut 421 422=head2 getctl_int 423 424=head2 setctl_int 425 426 $value = $term->getctl_int( $ctl ) 427 428 $success = $term->setctl_int( $ctl, $value ) 429 430Gets or sets the value of an integer terminal control option. C<$ctl> should 431be one of the following options. They can be specified either as integers, 432using the following named constants, or as strings giving the part following 433C<TERMCTL_> in lower-case. 434 435On failure, each method returns C<undef>. 436 437=over 8 438 439=item TERMCTL_ALTSCREEN 440 441Enables DEC Alternate Screen mode 442 443=item TERMCTL_CURSORVIS 444 445Enables cursor visible mode 446 447=item TERMCTL_CURSORBLINK 448 449Enables cursor blinking mode 450 451=item TERMCTL_CURSORSHAPE 452 453Sets the shape of the cursor. C<$value> should be one of 454C<CURSORSHAPE_BLOCK>, C<CURSORSHAPE_UNDER> or C<CURSORSHAPE_LEFT_BAR>. 455 456=item TERMCTL_KEYPAD_APP 457 458Enables keypad application mode 459 460=item TERMCTL_MOUSE 461 462Enables mouse tracking mode. C<$vaule> should be one of 463C<TERM_MOUSEMODE_CLICK>, C<TERM_MOUSEMODE_DRAG>, C<TERM_MOUSEMODE_MOVE> or 464C<TERM_MOUSEMODE_OFF>. 465 466=back 467 468=head2 setctl_str 469 470 $success = $term->setctl_str( $ctl, $value ) 471 472Sets the value of a string terminal control option. C<$ctrl> should be one of 473the following options. They can be specified either as integers or strings, as 474for C<setctl_int>. 475 476=over 8 477 478=item TERMCTL_ICON_TEXT 479 480=item TERMCTL_TITLE_TEXT 481 482=item TERMCTL_ICONTITLE_TEXT 483 484Sets the terminal window icon text, title, or both. 485 486=back 487 488=head2 getctl 489 490=head2 setctl 491 492 $value = $term->getctl( $ctl ) 493 494 $success = $term->setctl( $ctl, $value ) 495 496A newer form of the various typed get and set methods above. This version 497will interpret the given value as appropriate, depending on the control type. 498 499=cut 500 501=head2 input_push_bytes 502 503 $term->input_push_bytes( $bytes ) 504 505Feeds more bytes of input. May result in C<key> or C<mouse> events. 506 507=cut 508 509=head2 input_readable 510 511 $term->input_readable 512 513Informs the term that the input handle may be readable. Attempts to read more 514bytes of input. May result in C<key> or C<mouse> events. 515 516=cut 517 518=head2 input_wait 519 520 $term->input_wait( $timeout ) 521 522Block until some input is available, and process it. Returns after one round 523of input has been processed. May result in C<key> or C<mouse> events. If 524C<$timeout> is defined, it will wait a period of time no longer than this time 525before returning, even if no input events were received. 526 527=cut 528 529=head2 check_timeout 530 531 $timeout = $term->check_timeout 532 533Returns a number in seconds to represent when the next timeout should occur on 534the terminal, or C<undef> if nothing is waiting. May invoke expired timeouts, 535and cause a C<key> event to occur. 536 537=cut 538 539=head2 emit_key 540 541 $term->emit_key( 542 type => $type, str => $str, [ mod => $mod ] 543 ) 544 545Invokes the key event handlers as if an event with the given info had just 546been received. The C<mod> argument is optional, a default of 0 will apply if 547it is missing. 548 549=cut 550 551sub emit_key 552{ 553 my $self = shift; 554 my %args = @_; 555 556 $self->_emit_key( Tickit::Event::Key->_new( 557 $args{type}, $args{str}, $args{mod} // 0 558 ) ); 559} 560 561=head2 emit_mouse 562 563 $term->emit_mouse( 564 type => $type, button => $button, line => $line, col => $col, 565 [ mod => $mod ] 566 ) 567 568Invokes the mouse event handlers as if an event with the given info had just 569been received. The C<mod> argument is optional, a default of 0 will apply if 570it is missing. 571 572=cut 573 574sub emit_mouse 575{ 576 my $self = shift; 577 my %args = @_; 578 579 $self->_emit_mouse( Tickit::Event::Mouse->_new( 580 $args{type}, $args{button}, $args{line}, $args{col}, $args{mod} // 0 581 ) ); 582} 583 584=head1 EVENTS 585 586The following event types are emitted and may be observed by L</bind_event>. 587 588=head2 resize 589 590Emitted when the terminal itself has been resized. 591 592=head2 key 593 594Emitted when a key on the keyboard is pressed. 595 596=head2 mouse 597 598Emitted when a mouse button is pressed or released, the cursor moved while a 599button is held (a dragging event), or the wheel is scrolled. 600 601Behaviour of events involving more than one mouse button is not well-specified 602by terminals. 603 604=cut 605 606=head1 TODO 607 608=over 4 609 610=item * 611 612Track cursor position, and optimise (or eliminate entirely) C<goto> calls. 613 614=back 615 616=head1 AUTHOR 617 618Paul Evans <leonerd@leonerd.org.uk> 619 620=cut 621 6220x55AA; 623