File: Term.pm

package info (click to toggle)
libtickit-perl 0.73-1
  • links: PTS, VCS
  • area: main
  • in suites: bookworm, forky, sid, trixie
  • size: 660 kB
  • sloc: perl: 4,944; makefile: 5
file content (622 lines) | stat: -rw-r--r-- 14,419 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#
#  (C) Paul Evans, 2009-2020 -- leonerd@leonerd.org.uk

package Tickit::Term 0.73;

use v5.14;
use warnings;

use Carp;

# Load the XS code
use Tickit qw( MOD_SHIFT MOD_ALT MOD_CTRL BIND_FIRST );

# We export some constants
use Exporter 'import';

# Old names for these
use constant {
   TERM_CURSORSHAPE_BLOCK    => CURSORSHAPE_BLOCK,
   TERM_CURSORSHAPE_UNDER    => CURSORSHAPE_UNDER,
   TERM_CURSORSHAPE_LEFT_BAR => CURSORSHAPE_LEFT_BAR,
};

push our @EXPORT_OK, qw(
   TERM_CURSORSHAPE_BLOCK TERM_CURSORSHAPE_UNDER TERM_CURSORSHAPE_LEFT_BAR
   MOD_SHIFT MOD_ALT MOD_CTRL
   BIND_FIRST
);

=head1 NAME

C<Tickit::Term> - terminal formatting abstraction

=head1 SYNOPSIS

=head1 DESCRIPTION

Provides terminal control primitives for L<Tickit>; a number of methods that
control the terminal by writing control strings. This object itself performs
no actual IO work; it writes bytes to a delegated object given to the
constructor called the writer.

This object is not normally constructed directly by the containing
application; instead it is used indirectly by other parts of the C<Tickit>
distribution.

Note that a given program may contain multiple objects in this class that all
refer to the same underlying C<TickitTerm> instance from the C library. This
is especially true of the first argument provided to event binding callbacks.
This class overloads numify and stringify operations, so that instances may be
compared using the C<==> or C<eq> operators, or used as keys in hashes, and
they will act as expected. Do not rely on plain C<refaddr> comparison however
as you may get incorrect results.

=cut

use overload
   '0+' => "_xs_addr",
   '""' => sub { sprintf "Tickit::Term=XS(tt=0x%x)", $_[0]->_xs_addr },
   fallback => 1;

=head1 CONSTRUCTOR

=cut

=head2 new

   $term = Tickit::Term->new( %params )

Constructs a new C<Tickit::Term> object.

Takes the following named arguments at construction time:

=over 8

=item UTF8 => BOOL

If defined, overrides locale detection to enable or disable UTF-8 mode. If not
defined then this will be detected from the locale by using Perl's
C<${^UTF8LOCALE}> variable.

=item writer => OBJECT

An object delegated to for sending strings of terminal control bytes to the
terminal itself. This object must support a single method, C<write>, taking
a string of bytes.

 $writer->write( $data )

Such an interface is supported by an C<IO::Handle> object.

=item output_handle => HANDLE

Optional. If supplied, will be used as the terminal filehandle for querying
the size. Even if supplied, all writing operations will use the C<writer>
function rather than performing IO operations on this filehandle.

=item input_handle => HANDLE

Optional. If supplied, will be used as the terminal filehandle for reading
keypress and other events.

=back

=cut

sub new
{
   my $class = shift;
   my %params = @_;

   return $class->_new(
      $ENV{TERM}, @params{qw( input_handle output_handle writer UTF8 )}
   ) || croak "Cannot construct Tickit::Term - $!";
}

=head2 open_stdio

   $term = Tickit::Term->open_stdio

Convenient shortcut for obtaining a L<Tickit::Term> instance bound to the
STDIN and STDOUT streams of the process.

=cut

=head1 METHODS

=cut

=head2 get_input_handle

   $fh = $term->get_input_handle

Returns the input handle set by the C<input_handle> constructor arg.

Note that because L<Tickit::Term> merely wraps an object provided by the
lower-level F<libtickit> C library, it is no longer guaranteed that this
method will return the same perl-level object that was given to the
constructor. The object may be newly-constructed to represent a new perl-level
readable filehandle on the same file number.

=cut

sub get_input_handle
{
   my $self = shift;
   return IO::Handle->new_from_fd( $self->get_input_fd, "r" );
}

=head2 get_output_handle

   $fh = $term->get_output_handle

Returns the output handle set by the C<output_handle> constructor arg.

Note that because L<Tickit::Term> merely wraps an object provided by the
lower-level F<libtickit> C library, it is no longer guaranteed that this
method will return the same perl-level object that was given to the
constructor. The object may be newly-constructed to represent a new perl-level
writable filehandle on the same file number.

=cut

sub get_output_handle
{
   my $self = shift;
   return IO::Handle->new_from_fd( $self->get_output_fd, "w" );
}

=head2 set_output_buffer

   $term->set_output_buffer( $len )

Sets the size of the output buffer

=cut

=head2 await_started

   $term->await_started( $timeout )

Waits for the terminal startup process to complete, up to the timeout given in
seconds.

=cut

=head2 pause

   $term->pause

Suspends operation of the terminal by resetting it to its default state.

=cut

=head2 resume

   $term->resume

Resumes operation of the terminal after a L</pause>.

Typically these two methods are used together, either side of a blocking wait
around a C<SIGSTOP>.

   sub suspend
   {
      $term->pause;
      kill STOP => $$;
      $term->resume;
      $rootwin->expose;
   }

=cut

=head2 teardown

   $term->teardown

Shuts down operation of the terminal entirely, in preparation for terminating
the process.

=cut

=head2 flush

   $term->flush

Flushes the output buffer to the terminal

=cut

=head2 bind_event

   $id = $term->bind_event( $ev, $code, $data )

Installs a new event handler to watch for the event specified by C<$ev>,
invoking the C<$code> reference when it occurs. C<$code> will be invoked with
the given terminal, the event name, an event information object, and the
C<$data> value it was installed with. C<bind_event> returns an ID value that
may be used to remove the handler by calling C<unbind_event_id>.

 $ret = $code->( $term, $ev, $info, $data )

The type of C<$info> will depend on the kind of event that was received, as
indicated by C<$ev>. The information structure types are documented in
L<Tickit::Event>.

=head2 bind_event (with flags)

   $id = $term->bind_event( $ev, $flags, $code, $data )

The C<$code> argument may optionally be preceded by an integer of flag
values. This should be zero to apply default semantics, or a bitmask of one or
more of the following constants:

=over 4

=item TICKIT_BIND_FIRST

Inserts this event handler first in the chain, before any existing ones.

=item TICKIT_BIND_ONESHOT

Remove the event handler after it has been invoked the first time.

=back

=head2 unbind_event_id

   $term->unbind_event_id( $id )

Removes an event handler that returned the given C<$id> value.

=cut

sub bind_event
{
   my $self = shift;
   my $ev = shift;
   my ( $flags, $code, $data ) = ( ref $_[0] ) ? ( 0, @_ ) : @_;

   $self->_bind_event( $ev, $flags, $code, $data );
}

=head2 refresh_size

   $term->refresh_size

If a filehandle was supplied to the constructor, fetch the size of the
terminal and update the cached sizes in the object. May invoke C<on_resize> if
the new size is different.

=cut

=head2 set_size

   $term->set_size( $lines, $cols )

Defines the size of the terminal. Invoke C<on_resize> if the new size is
different.

=cut

=head2 lines

=head2 cols

   $lines = $term->lines

   $cols = $term->cols

Query the size of the terminal, as set by the most recent C<refresh_size> or
C<set_size> operation.

=cut

sub lines { ( shift->get_size )[0] }
sub cols  { ( shift->get_size )[1]  }

=head2 goto

   $success = $term->goto( $line, $col )

Move the cursor to the given position on the screen. If only one parameter is
defined, does not alter the other. Both C<$line> and C<$col> are 0-based.

Note that not all terminals can support these partial moves. This method
returns a boolean indicating success; if the terminal could not perform the
move it will need to be retried using a fully-specified call.

=cut

=head2 move

   $term->move( $downward, $rightward )

Move the cursor relative to where it currently is.

=cut

=head2 scrollrect

   $success = $term->scrollrect( $top, $left, $lines, $cols, $downward, $rightward )

Attempt to scroll the rectangle of the screen defined by the first four
parameters by an amount given by the latter two. Since most terminals cannot
perform arbitrary rectangle scrolling, this method returns a boolean to
indicate if it was successful. The caller should test this return value and
fall back to another drawing strategy if the attempt was unsuccessful.

The cursor may move as a result of calling this method; its location is
undefined if this method returns successful.

=cut

=head2 chpen

   $term->chpen( $pen )

   $term->chpen( %attrs )

Changes the current pen attributes to those given. Any attribute whose value
is given as C<undef> is reset. Any attributes not named are unchanged.

For details of the supported pen attributes, see L<Tickit::Pen>.

=cut

=head2 setpen

   $term->setpen( $pen )

   $term->setpen( %attrs )

Similar to C<chpen>, but completely defines the state of the terminal pen. Any
attribute not given will be reset to its default value.

=cut

=head2 print

   $term->print( $text, [ $pen ] )

Print the given text to the terminal at the current cursor position.

An optional C<Tickit::Pen> may be provided; if present it will be set as if
given to C<setpen> first.

=cut

=head2 clear

   $term->clear( [ $pen ] )

Erase the entire screen.

An optional C<Tickit::Pen> may be provided; if present it will be set as if
given to C<setpen> first.

=cut

=head2 erasech

   $term->erasech( $count, $moveend, [ $pen ] )

Erase C<$count> characters forwards. If C<$moveend> is true, the cursor is
moved to the end of the erased region. If defined but false, the cursor will
remain where it is. If undefined, the terminal will perform whichever of these
behaviours is more efficient, and the cursor will end at some undefined
location.

Using C<$moveend> may be more efficient than separate C<erasech> and C<goto>
calls on terminals that do not have an erase function, as it will be
implemented by printing spaces. This removes the need for two cursor jumps.

An optional C<Tickit::Pen> may be provided; if present it will be set as if
given to C<setpen> first.

=cut

=head2 getctl_int

=head2 setctl_int

   $value = $term->getctl_int( $ctl )

   $success = $term->setctl_int( $ctl, $value )

Gets or sets the value of an integer terminal control option. C<$ctl> should
be one of the following options. They can be specified either as integers,
using the following named constants, or as strings giving the part following
C<TERMCTL_> in lower-case.

On failure, each method returns C<undef>.

=over 8

=item TERMCTL_ALTSCREEN

Enables DEC Alternate Screen mode

=item TERMCTL_CURSORVIS

Enables cursor visible mode

=item TERMCTL_CURSORBLINK

Enables cursor blinking mode

=item TERMCTL_CURSORSHAPE

Sets the shape of the cursor. C<$value> should be one of
C<CURSORSHAPE_BLOCK>, C<CURSORSHAPE_UNDER> or C<CURSORSHAPE_LEFT_BAR>.

=item TERMCTL_KEYPAD_APP

Enables keypad application mode

=item TERMCTL_MOUSE

Enables mouse tracking mode. C<$vaule> should be one of
C<TERM_MOUSEMODE_CLICK>, C<TERM_MOUSEMODE_DRAG>, C<TERM_MOUSEMODE_MOVE> or
C<TERM_MOUSEMODE_OFF>.

=back

=head2 setctl_str

   $success = $term->setctl_str( $ctl, $value )

Sets the value of a string terminal control option. C<$ctrl> should be one of
the following options. They can be specified either as integers or strings, as
for C<setctl_int>.

=over 8

=item TERMCTL_ICON_TEXT

=item TERMCTL_TITLE_TEXT

=item TERMCTL_ICONTITLE_TEXT

Sets the terminal window icon text, title, or both.

=back

=head2 getctl

=head2 setctl

   $value = $term->getctl( $ctl )

   $success = $term->setctl( $ctl, $value )

A newer form of the various typed get and set methods above. This version
will interpret the given value as appropriate, depending on the control type.

=cut

=head2 input_push_bytes

   $term->input_push_bytes( $bytes )

Feeds more bytes of input. May result in C<key> or C<mouse> events.

=cut

=head2 input_readable

   $term->input_readable

Informs the term that the input handle may be readable. Attempts to read more
bytes of input. May result in C<key> or C<mouse> events.

=cut

=head2 input_wait

   $term->input_wait( $timeout )

Block until some input is available, and process it. Returns after one round
of input has been processed. May result in C<key> or C<mouse> events. If
C<$timeout> is defined, it will wait a period of time no longer than this time
before returning, even if no input events were received.

=cut

=head2 check_timeout

   $timeout = $term->check_timeout

Returns a number in seconds to represent when the next timeout should occur on
the terminal, or C<undef> if nothing is waiting. May invoke expired timeouts,
and cause a C<key> event to occur.

=cut

=head2 emit_key

   $term->emit_key(
      type => $type, str => $str, [ mod => $mod ]
   )

Invokes the key event handlers as if an event with the given info had just
been received. The C<mod> argument is optional, a default of 0 will apply if
it is missing.

=cut

sub emit_key
{
   my $self = shift;
   my %args = @_;

   $self->_emit_key( Tickit::Event::Key->_new(
      $args{type}, $args{str}, $args{mod} // 0
   ) );
}

=head2 emit_mouse

   $term->emit_mouse(
      type => $type, button => $button, line => $line, col => $col,
      [ mod => $mod ]
   )

Invokes the mouse event handlers as if an event with the given info had just
been received. The C<mod> argument is optional, a default of 0 will apply if
it is missing.

=cut

sub emit_mouse
{
   my $self = shift;
   my %args = @_;

   $self->_emit_mouse( Tickit::Event::Mouse->_new(
      $args{type}, $args{button}, $args{line}, $args{col}, $args{mod} // 0
   ) );
}

=head1 EVENTS

The following event types are emitted and may be observed by L</bind_event>.

=head2 resize

Emitted when the terminal itself has been resized.

=head2 key

Emitted when a key on the keyboard is pressed.

=head2 mouse

Emitted when a mouse button is pressed or released, the cursor moved while a
button is held (a dragging event), or the wheel is scrolled.

Behaviour of events involving more than one mouse button is not well-specified
by terminals.

=cut

=head1 TODO

=over 4

=item *

Track cursor position, and optimise (or eliminate entirely) C<goto> calls.

=back

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>

=cut

0x55AA;