File Coverage

blib/lib/Term/ReadLine/Simple.pm
Criterion Covered Total %
statement 81 538 15.0
branch 18 284 6.3
condition 2 84 2.3
subroutine 26 46 56.5
pod 4 12 33.3
total 131 964 13.5


line stmt bran cond sub pod time code
1             package Term::ReadLine::Simple;
2              
3 4     4   87654 use warnings;
  4         9  
  4         124  
4 4     4   22 use strict;
  4         8  
  4         79  
5 4     4   80 use 5.008003;
  4         18  
6              
7             our $VERSION = '0.308';
8              
9 4     4   21 use Carp qw( croak carp );
  4         7  
  4         282  
10 4     4   3625 use Encode qw( encode );
  4         45150  
  4         328  
11 4     4   27 use List::Util qw( any );
  4         6  
  4         409  
12              
13 4     4   3040 use Encode::Locale qw();
  4         17155  
  4         95  
14 4     4   3114 use Text::LineFold qw();
  4         97346  
  4         111  
15 4     4   32 use Unicode::GCString qw();
  4         8  
  4         140  
16              
17 4     4   2553 use Term::ReadLine::Simple::Constants qw( :rl );
  4         11  
  4         1084  
18              
19             my $Plugin_Package;
20              
21             BEGIN {
22 4 50   4   23 if ( $^O eq 'MSWin32' ) {
23 0         0 require Term::ReadLine::Simple::Win32;
24 0         0 $Plugin_Package = 'Term::ReadLine::Simple::Win32';
25             }
26             else {
27 4         2408 require Term::ReadLine::Simple::Linux;
28 4         15236 $Plugin_Package = 'Term::ReadLine::Simple::Linux';
29             }
30             }
31              
32 1     1 0 19 sub ReadLine { 'Term::ReadLine::Simple' }
33       1 0   sub IN {}
34       1 0   sub OUT {}
35       1 0   sub MinLine {}
36 1     1 0 4 sub Attribs { {} }
37 1     1 0 6 sub Features { { no_features => 1 } }
38       1 0   sub addhistory {}
39       1 0   sub ornaments {}
40              
41              
42             sub new {
43 3     3 1 2153 my $class = shift;
44 3         9 my ( $name ) = @_;
45 3         12 my $self = bless {
46             name => $name,
47             }, $class;
48 3         14 $self->__set_defaults();
49 3         27 $self->{plugin} = $Plugin_Package->new();
50 3         14 return $self;
51             }
52              
53              
54             sub DESTROY {
55 3     3   1133 my ( $self ) = @_;
56 3         12 $self->__reset_term();
57             }
58              
59              
60             sub __set_defaults {
61 3     3   8 my ( $self ) = @_;
62             # compat : undef ok
63             # reinit_encoding: undef ok
64             # no_echo : false ok
65 3         18 $self->{default} = '';
66              
67             # prompt : undef ok
68             # mark_curr: false ok
69             # back : undef ok
70 3         8 $self->{auto_up} = 0;
71 3         8 $self->{back} = '';
72 3         7 $self->{confirm} = '<<';
73 3         11 $self->{ro} = [];
74             }
75              
76              
77             sub __validate_options {
78 53     53   101 my ( $self, $opt, $valid ) = @_;
79 53 50       131 if ( ! defined $opt ) {
80 0         0 $opt = {};
81 0         0 return;
82             }
83 53         351 my $sub = ( caller( 1 ) )[3];
84 53         412 $sub =~ s/^.+::([^:]+)\z/$1/;
85              
86             ####
87 53 0 33     229 if ( exists $opt->{sep} && ! $self->{called_sep_message} && $sub ne 'readline' ) { # remove
      33        
88 0         0 print " '$sub' called with the option 'sep'.\n";
89 0         0 print " The option 'sep' has been removed.\n";
90 0         0 print " Write an email to cuer2s\x{0040}gmail.com with the subject\n";
91 0         0 print " 'keep opt sep' if you want back the option 'sep'.\n";
92 0         0 print " Press ENTER to continue: ";
93 0         0 ;
94 0         0 $self->{called_sep_message} = 1;
95             }
96             ####
97              
98 53         178 for my $key ( keys %$opt ) {
99 80 100       222 if ( ! exists $valid->{$key} ) {
100 1         126 croak $sub . ": '$key' is not a valid option name";
101             }
102 79 100       206 if ( ! defined $opt->{$key} ) {
103 11         32 next;
104             }
105 68 100       184 if ( ref $opt->{$key} ) {
106 15 50       44 if ( $valid->{$key} eq 'ARRAY' ) {
107 0         0 next;
108             }
109 15         1908 croak $sub . ": option '$key' : a reference is not a valid value.";
110             }
111 53 100       147 if ( $valid->{$key} eq '' ) {
112 24         60 next;
113             }
114 29 100       414 if ( $opt->{$key} !~ m/^$valid->{$key}\z/x ) {
115 9         1199 croak $sub . ": option '$key' : '$opt->{$key}' is not a valid value.";
116             }
117             }
118             }
119              
120              
121             sub __init_term {
122 0     0   0 my ( $self ) = @_;
123 0         0 $self->{plugin}->__set_mode();
124 0 0       0 if ( $self->{reinit_encoding} ) {
125 0         0 Encode::Locale::reinit( $self->{reinit_encoding} );
126             }
127             }
128              
129              
130             sub __reset_term {
131 3     3   7 my ( $self ) = @_;
132 3 50       14 delete $self->{enter_row} if exists $self->{enter_row};
133 3 50       12 delete $self->{enter_col} if exists $self->{enter_col};
134 3 50       14 if ( defined $self->{plugin} ) {
135 3         21 $self->{plugin}->__reset_mode();
136             }
137             }
138              
139              
140             sub config {
141 53     53 1 23804 my ( $self, $opt ) = @_;
142 53 50       178 if ( defined $opt ) {
143 53 50       162 if ( ref $opt ne 'HASH' ) {
144 0         0 croak "config: the (optional) argument must be a HASH reference";
145             }
146 53         453 my $valid = {
147             no_echo => '[ 0 1 2 ]',
148             compat => '[ 0 1 ]',
149             reinit_encoding => '',
150             default => '',
151             prompt => '',
152             back => '',
153             confirm => '',
154             auto_up => '[ 0 1 2 ]',
155             mark_curr => '[ 0 1 ]',
156             ro => 'ARRAY',
157             ####
158             sep => '', # remove
159             ####
160             };
161 53         164 $self->__validate_options( $opt, $valid );
162 28         85 for my $option ( keys %$opt ) {
163 42         213 $self->{$option} = $opt->{$option};
164             }
165             }
166             }
167              
168              
169             sub readline {
170 0     0 1   my ( $self, $prompt, $opt ) = @_;
171 0 0         if ( defined $prompt ) {
172 0 0         croak "readline: a reference is not a valid prompt." if ref $prompt;
173             }
174             else {
175 0           $prompt = '';
176             }
177 0 0         if ( defined $opt ) {
178 0 0         if ( ! ref $opt ) {
    0          
179 0           $opt = { default => $opt };
180             }
181             elsif ( ref $opt ne 'HASH' ) {
182 0           croak "readline: the (optional) second argument must be a string or a HASH reference";
183             }
184             }
185 0           my $valid = {
186             no_echo => '[ 0 1 2 ]',
187             default => '',
188             };
189 0           $self->__validate_options( $opt, $valid );
190 0 0         $opt->{default} = $self->{default} if ! defined $opt->{default};
191 0 0         $opt->{no_echo} = $self->{no_echo} if ! defined $opt->{no_echo};
192 0           $self->{sep} = '';
193 0           my $list = [ [ $prompt, $self->{default} ] ];
194 0           $self->{curr_row} = 0;
195 0           $self->{length_key}[0] = Unicode::GCString->new( $prompt )->columns;
196 0           $self->{len_longest_key} = $self->{length_key}[0];
197 0           $self->{length_prompt} = $self->{len_longest_key} + length $self->{sep};
198 0           my $str = Unicode::GCString->new( $opt->{default} );
199 0           my $pos = $str->length();
200 0           local $| = 1;
201 0           $self->__init_term();
202              
203 0           while ( 1 ) {
204 0 0         if ( $self->{beep} ) {
205 0           $self->{plugin}->__beep();
206 0           $self->{beep} = 0;
207             }
208 0           my ( $term_width ) = $self->{plugin}->__term_buff_size();
209 0           $self->{avail_width} = $term_width - 1;
210 0           $self->{avail_width_value} = $self->{avail_width} - $self->{length_prompt};
211 0           $self->__print_readline( $opt, $list, $str, $pos );
212 0           my $key = $self->{plugin}->__get_key();
213 0 0         if ( ! defined $key ) {
214 0           $self->__reset_term();
215 0           carp "EOT: $!";
216 0           return;
217             }
218 0 0         next if $key == NEXT_get_key;
219 0 0         next if $key == KEY_TAB;
220 0 0 0       if ( $key == KEY_BSPACE || $key == CONTROL_H ) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
221 0 0         if ( $pos ) {
222 0           $pos--;
223 0           $str->substr( $pos, 1, '' );
224             }
225             else {
226 0           $self->{beep} = 1;
227             }
228             }
229             elsif ( $key == CONTROL_U ) {
230 0 0         if ( $pos ) {
231 0           $str->substr( 0, $pos, '' );
232 0           $pos = 0;
233             }
234             else {
235 0           $self->{beep} = 1;
236             }
237             }
238             elsif ( $key == CONTROL_K ) {
239 0 0         if ( $pos < $str->length() ) {
240 0           $str->substr( $pos, $str->length() - $pos, '' );
241             }
242             else {
243 0           $self->{beep} = 1;
244             }
245             }
246             elsif ( $key == VK_DELETE || $key == CONTROL_D ) {
247 0 0         if ( $str->length() ) {
248 0 0         if ( $pos < $str->length() ) {
249 0           $str->substr( $pos, 1, '' );
250             }
251             else {
252 0           $self->{beep} = 1;
253             }
254             }
255             else {
256 0           print "\n";
257 0           $self->__reset_term();
258 0           return;
259             }
260             }
261             elsif ( $key == VK_RIGHT || $key == CONTROL_F ) {
262 0 0         if ( $pos < $str->length() ) {
263 0           $pos++;
264             }
265             else {
266 0           $self->{beep} = 1;
267             }
268             }
269             elsif ( $key == VK_LEFT || $key == CONTROL_B ) {
270 0 0         if ( $pos ) {
271 0           $pos--;
272             }
273             else {
274 0           $self->{beep} = 1;
275             }
276             }
277             elsif ( $key == VK_END || $key == CONTROL_E ) {
278 0 0         if ( $pos < $str->length() ) {
279 0           $pos = $str->length();
280             }
281             else {
282 0           $self->{beep} = 1;
283             }
284             }
285             elsif ( $key == VK_HOME || $key == CONTROL_A ) {
286 0 0         if ( $pos > 0 ) {
287 0           $pos = 0;
288             }
289             else {
290 0           $self->{beep} = 1;
291             }
292             }
293             elsif ( $key == VK_UP || $key == VK_DOWN ) {
294 0           $self->{beep} = 1;
295             }
296             else {
297 0           $key = chr $key;
298 0           utf8::upgrade $key;
299 0 0 0       if ( $key eq "\n" || $key eq "\r" ) { #
300 0           print "\n";
301 0           $self->__reset_term();
302 0 0 0       if ( $self->{compat} || ! defined $self->{compat} && $ENV{READLINE_SIMPLE_COMPAT} ) {
      0        
303 0           return encode( 'console_in', $str->as_string );
304             }
305 0           return $str->as_string;
306             }
307             else {
308 0           $str->substr( $pos, 0, $key );
309 0           $pos++;
310             }
311             }
312             }
313             }
314              
315              
316             sub __print_readline {
317 0     0     my ( $self, $opt, $list, $str, $pos ) = @_;
318 0           my $print_str = $str->copy;
319 0           my $print_pos = $pos;
320 0           my $n = 1;
321 0           my ( $b, $e );
322 0           while ( $print_str->columns > $self->{avail_width_value} ) {
323 0 0         if ( $print_str->substr( 0, $print_pos )->columns > $self->{avail_width_value} / 4 ) {
324 0           $print_str->substr( 0, $n, '' );
325 0           $print_pos -= $n;
326 0           $b = 1;
327             }
328             else {
329 0           $print_str->substr( -$n, $n, '' );
330 0           $e = 1;
331             }
332             }
333 0 0         if ( $b ) {
334 0           $print_str->substr( 0, 1, '<' );
335             }
336 0 0         if ( $e ) {
337 0           $print_str->substr( $print_str->length(), 1, '>' );
338             }
339 0           my $key = $self->__padded_or_trimed_key( $list, $self->{curr_row} );
340 0           $self->{plugin}->__clear_line();
341 0 0         if ( $opt->{mark_curr} ) {
342 0           $self->{plugin}->__mark_current();
343 0           print "\r", $key;
344 0           $self->{plugin}->__reset();
345             }
346             else {
347 0           print "\r", $key;
348             }
349 0           my $sep = $self->{sep};
350 0 0   0     if ( any { $_ == $self->{curr_row} - @{$self->{pre_list}} } @{$opt->{ro}} ) {
  0            
  0            
  0            
351 0           $sep = $self->{sep_ro};
352             }
353 0 0         if ( $opt->{no_echo} ) {
354 0 0         if ( $opt->{no_echo} == 2 ) {
355 0           print $sep;
356 0           return;
357             }
358 0           print $sep, '*' x $print_str->length(), "\r";
359             }
360             else {
361 0           print $sep, $print_str->as_string, "\r";
362             }
363 0           $self->{plugin}->__right( $self->{length_prompt} + $print_str->substr( 0, $print_pos )->columns );
364              
365             }
366              
367              
368             sub __length_longest_key {
369 0     0     my ( $self, $list ) = @_;
370 0           my $len = []; #
371 0           my $longest = 0;
372 0           for my $i ( 0 .. $#$list ) {
373 0           my $gcs = Unicode::GCString->new( $list->[$i][0] );
374 0           $len->[$i] = $gcs->columns;
375 0 0         if ( $i < @{$self->{pre_list}} ) {
  0            
376 0           next;
377             }
378 0 0         $longest = $len->[$i] if $len->[$i] > $longest;
379             }
380 0           $self->{len_longest_key} = $longest;
381 0           $self->{length_key} = $len;
382             }
383              
384              
385             sub __prepare_size {
386 0     0     my ( $self, $opt, $list, $maxcols, $maxrows ) = @_;
387 0           $self->{avail_width} = $maxcols - 1;
388 0           $self->{avail_height} = $maxrows;
389 0 0         if ( defined $opt->{main_prompt} ) {
390 0           $self->__nr_prompt_lines( $opt );
391 0           my $backup_height = $self->{avail_height};
392 0           $self->{avail_height} -= $self->{nr_prompt_lines};
393 0           my $min_avail_height = 5;
394 0 0         if ( $self->{avail_height} < $min_avail_height ) {
395 0 0         if ( $backup_height > $min_avail_height ) {
396 0           $self->{avail_height} = $min_avail_height;
397             }
398             else {
399 0           $self->{avail_height} = $backup_height;
400             }
401             }
402             }
403 0 0         if ( @$list > $self->{avail_height} ) {
404 0           $self->{pages} = int @$list / ( $self->{avail_height} - 1 );
405 0 0         if ( @$list % ( $self->{avail_height} - 1 ) ) {
406 0           $self->{pages}++;
407             }
408 0           $self->{avail_height}--;
409             }
410             else {
411 0           $self->{pages} = 1;
412             }
413 0           return;
414             }
415              
416              
417             sub __nr_prompt_lines {
418 0     0     my ( $self, $opt ) = @_;
419 0           my $prompt = $opt->{main_prompt};
420 0 0         if ( $prompt eq '' ) {
421 0           $self->{nr_prompt_lines} = 0;
422 0           return;
423             }
424             #$self->{main_prompt} =~ s/[^\n\P{Space}]/ /g;
425             #$self->{main_prompt} =~ s/[^\n\P{C}]//g;
426 0 0 0       if ( $prompt !~ /\n/ && Unicode::GCString->new( $prompt )->columns <= $self->{avail_width} ) {
427 0           $self->{nr_prompt_lines} = 1;
428             }
429             else {
430             my $line_fold = Text::LineFold->new(
431             Charset=> 'utf-8',
432             ColMax => $self->{avail_width},
433 0           OutputCharset => '_UNICODE_',
434             Urgent => 'FORCE'
435             );
436             #if ( defined $self->{lf} ) {
437             # $self->{prompt_copy} = $line_fold->fold( ' ' x $self->{lf}[0], ' ' x $self->{lf}[1], $self->{main_prompt} );
438             #}
439             #else {
440 0           $opt->{main_prompt} = $line_fold->fold( $prompt, 'PLAIN' );
441             #}
442 0           $opt->{main_prompt} =~ s/\n\z//;
443 0           $self->{nr_prompt_lines} = $opt->{main_prompt} =~ s/\n/\n\r/g; # #
444 0           $self->{nr_prompt_lines} += 1;
445             }
446             }
447              
448              
449             sub __gcstring_and_pos {
450 0     0     my ( $self, $list ) = @_;
451 0           my $default = $list->[$self->{curr_row}][1];
452 0 0         if ( ! defined $default ) {
453 0           $default = '';
454             }
455 0           my $str = Unicode::GCString->new( $default );
456 0           return $str, $str->length();
457             }
458              
459              
460             sub __print_current_row {
461 0     0     my ( $self, $opt, $list, $str, $pos ) = @_;
462 0           $self->{plugin}->__clear_line();
463 0 0         if ( $self->{curr_row} < @{$self->{pre_list}} ) {
  0            
464 0           $self->{plugin}->__reverse();
465 0           print $list->[$self->{curr_row}][0];
466 0           $self->{plugin}->__reset();
467             }
468             else {
469 0           $self->__print_readline( $opt, $list, $str, $pos );
470 0           $list->[$self->{curr_row}][1] = $str->as_string;
471             }
472             }
473              
474              
475             sub __print_row {
476 0     0     my ( $self, $opt, $list, $idx ) = @_;
477 0 0         if ( $idx < @{$self->{pre_list}} ) {
  0            
478 0           return $list->[$idx][0];
479             }
480             else {
481 0 0         my $val = defined $list->[$idx][1] ? $list->[$idx][1] : '';
482 4     4   4501 $val =~ s/\p{Space}/ /g;
  4         51  
  4         78  
  0            
483 0           $val =~ s/\p{C}//g;
484 0           my $sep = $self->{sep};
485 0 0   0     if ( any { $_ == $idx - @{$self->{pre_list}} } @{$opt->{ro}} ) {
  0            
  0            
  0            
486 0           $sep = $self->{sep_ro};
487             }
488             return
489             $self->__padded_or_trimed_key( $list, $idx ) . $sep .
490 0           $self->__unicode_trim( Unicode::GCString->new( $val ), $self->{avail_width_value} );
491             }
492             }
493              
494              
495             sub __write_screen {
496 0     0     my ( $self, $opt, $list ) = @_;
497 0           print join "\n", map { $self->__print_row( $opt, $list, $_ ) } $self->{begin_row} .. $self->{end_row};
  0            
498 0 0         if ( $self->{pages} > 1 ) {
499 0 0         if ( $self->{avail_height} - ( $self->{end_row} + 1 - $self->{begin_row} ) ) {
500 0           print "\n" x ( $self->{avail_height} - ( $self->{end_row} - $self->{begin_row} ) - 1 );
501             }
502 0           $self->{page} = int( $self->{end_row} / $self->{avail_height} ) + 1;
503 0           my $page_number = sprintf '- Page %d/%d -', $self->{page}, $self->{pages};
504 0 0         if ( length $page_number > $self->{avail_width} ) {
505 0           $page_number = substr sprintf( '%d/%d', $self->{page}, $self->{pages} ), 0, $self->{avail_width};
506             }
507 0           print "\n", $page_number;
508 0           $self->{plugin}->__up( $self->{avail_height} - ( $self->{curr_row} - $self->{begin_row} ) );
509             }
510             else {
511 0           $self->{page} = 1;
512 0           my $up_curr = $self->{end_row} - $self->{curr_row};
513 0           $self->{plugin}->__up( $up_curr );
514             }
515             }
516              
517              
518             sub __write_first_screen {
519 0     0     my ( $self, $opt, $list, $curr_row ) = @_;
520 0 0         if ( $self->{len_longest_key} > $self->{avail_width} / 3 ) {
521 0           $self->{len_longest_key} = int( $self->{avail_width} / 3 );
522             }
523 0           my $len_separator = Unicode::GCString->new( $self->{sep} )->columns;
524 0 0         if ( @{$opt->{ro}} ) {
  0            
525 0           my $tmp = Unicode::GCString->new( $self->{sep_ro} )->columns;
526 0 0         $len_separator = $tmp if $tmp > $len_separator;
527             }
528 0           $self->{length_prompt} = $self->{len_longest_key} + $len_separator;
529 0           $self->{avail_width_value} = $self->{avail_width} - $self->{length_prompt};
530 0 0         $self->{curr_row} = $opt->{auto_up} == 2 ? $curr_row : @{$self->{pre_list}};
  0            
531 0           $self->{begin_row} = 0;
532 0           $self->{end_row} = ( $self->{avail_height} - 1 );
533 0 0         if ( $self->{end_row} > $#$list ) {
534 0           $self->{end_row} = $#$list;
535             }
536 0 0         if ( defined $opt->{main_prompt} ) {
537 0           print $opt->{main_prompt}, "\n";
538             }
539 0           $self->__write_screen( $opt, $list );
540             }
541              
542              
543             sub fill_form {
544 0     0 1   my ( $self, $orig_list, $opt ) = @_;
545 0 0         if ( ! defined $orig_list ) {
    0          
546 0           croak "'fill_form' called with no argument.";
547             }
548             elsif ( ref $orig_list ne 'ARRAY' ) {
549 0           croak "'fill_form' requires an ARRAY reference as its argument.";
550             }
551 0 0 0       if ( defined $opt && ref $opt ne 'HASH' ) {
552 0           croak "'fill_form': the (optional) second argument must be a HASH reference";
553             }
554 0           my $valid = {
555             prompt => '',
556             back => '',
557             confirm => '',
558             auto_up => '[ 0 1 2 ]',
559             mark_curr => '[ 0 1 ]',
560             ro => 'ARRAY',
561             ####
562             sep => '', # remove
563             ####
564             };
565 0           my $list = [ map { [ @$_ ] } @$orig_list ];
  0            
566 0           $self->__validate_options( $opt, $valid );
567 0 0         $opt->{prompt} = $self->{prompt} if ! defined $opt->{prompt};
568 0 0         $opt->{back} = $self->{back} if ! defined $opt->{back};
569 0 0         $opt->{confirm} = $self->{confirm} if ! defined $opt->{confirm};
570 0 0         $opt->{auto_up} = $self->{auto_up} if ! defined $opt->{auto_up};
571 0 0         $opt->{ro} = $self->{ro} if ! defined $opt->{ro};
572 0           $opt->{main_prompt} = $opt->{prompt};
573 0           $self->{sep} = ': ';
574 0           $self->{sep_ro} = '| ';
575 0           $self->{pre_list} = [ [ $opt->{confirm} ] ];
576 0 0         if ( length $opt->{back} ) {
577 0           unshift @{$self->{pre_list}}, [ $opt->{back} ];
  0            
578             }
579 0           unshift @$list, @{$self->{pre_list}};
  0            
580 0           $self->__length_longest_key( $list );
581 0           $self->__init_term();
582 0           local $| = 1;
583 0           my ( $maxcols, $maxrows ) = $self->{plugin}->__term_buff_size();
584 0           $self->__prepare_size( $opt, $list, $maxcols, $maxrows );
585 0           $self->__write_first_screen( $opt, $list, 0 );
586 0           my ( $str, $pos ) = $self->__gcstring_and_pos( $list );
587              
588 0           LINE: while ( 1 ) {
589 0           my $locked = 0;
590 0 0   0     if ( any { $_ == $self->{curr_row} - @{$self->{pre_list}} } @{$opt->{ro}} ) {
  0            
  0            
  0            
591 0           $locked = 1;
592             }
593 0 0         if ( $self->{beep} ) {
594 0           $self->{plugin}->__beep();
595 0           $self->{beep} = 0;
596             }
597             else {
598 0           $self->__print_current_row( $opt, $list, $str, $pos );
599             }
600 0           my $key = $self->{plugin}->__get_key();
601 0 0         if ( ! defined $key ) {
602 0           $self->__reset_term();
603 0           carp "EOT: $!";
604 0           return;
605             }
606 0 0         next if $key == NEXT_get_key;
607 0 0         next if $key == KEY_TAB;
608 0           my ( $tmp_maxcols, $tmp_maxrows ) = $self->{plugin}->__term_buff_size();
609 0 0 0       if ( $tmp_maxcols != $maxcols || $tmp_maxrows != $maxrows && $tmp_maxrows < ( @$list + 1 ) ) {
      0        
610 0           ( $maxcols, $maxrows ) = ( $tmp_maxcols, $tmp_maxrows );
611 0           $self->__prepare_size( $opt, $list, $maxcols, $maxrows );
612 0           $self->{plugin}->__clear_screen();
613 0           $self->__write_first_screen( $opt, $list, 1 );
614 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
615             }
616 0 0 0       if ( $key == KEY_BSPACE || $key == CONTROL_H ) {
    0 0        
    0 0        
    0 0        
    0 0        
    0 0        
    0          
    0          
    0          
    0          
    0          
    0          
617 0 0         if ( $locked ) {
    0          
618 0           $self->{beep} = 1;
619             }
620             elsif ( $pos ) {
621 0           $pos--;
622 0           $str->substr( $pos, 1, '' );
623             }
624             else {
625 0           $self->{beep} = 1;
626             }
627             }
628             elsif ( $key == CONTROL_U ) {
629 0 0         if ( $locked ) {
    0          
630 0           $self->{beep} = 1;
631             }
632             elsif ( $pos ) {
633 0           $str->substr( 0, $pos, '' );
634 0           $pos = 0;
635             }
636             else {
637 0           $self->{beep} = 1;
638             }
639             }
640             elsif ( $key == CONTROL_K ) {
641 0 0         if ( $locked ) {
    0          
642 0           $self->{beep} = 1;
643             }
644             elsif ( $pos < $str->length() ) {
645 0           $str->substr( $pos, $str->length() - $pos, '' );
646             }
647             else {
648 0           $self->{beep} = 1;
649             }
650             }
651             elsif ( $key == VK_DELETE || $key == CONTROL_D ) {
652 0 0         if ( $str->length() ) {
653 0 0         if ( $locked ) {
    0          
654 0           $self->{beep} = 1;
655             }
656             elsif ( $pos < $str->length() ) {
657 0           $str->substr( $pos, 1, '' );
658             }
659             else {
660 0           $self->{beep} = 1;
661             }
662             }
663             else {
664 0           print "\n";
665 0           $self->__reset_term();
666 0           return;
667             }
668             }
669             elsif ( $key == VK_RIGHT ) {
670 0 0         if ( $pos < $str->length() ) {
671 0           $pos++;
672             }
673             else {
674 0           $self->{beep} = 1;
675             }
676             }
677             elsif ( $key == VK_LEFT ) {
678 0 0         if ( $pos ) {
679 0           $pos--;
680             }
681             else {
682 0           $self->{beep} = 1;
683             }
684             }
685             elsif ( $key == VK_END || $key == CONTROL_E ) {
686 0 0         if ( $pos < $str->length() ) {
687 0           $pos = $str->length();
688             }
689             else {
690 0           $self->{beep} = 1;
691             }
692             }
693             elsif ( $key == VK_HOME || $key == CONTROL_A ) {
694 0 0         if ( $pos > 0 ) {
695 0           $pos = 0;
696             }
697             else {
698 0           $self->{beep} = 1;
699             }
700             }
701             elsif ( $key == VK_UP ) {
702 0 0         if ( $self->{curr_row} == 0 ) {
703 0           $self->{beep} = 1;
704             }
705             else {
706 0           $self->{curr_row}--;
707 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
708 0 0         if ( $self->{curr_row} >= $self->{begin_row} ) {
709 0           $self->__reset_previous_row( $opt, $list, $self->{curr_row} + 1 );
710 0           $self->{plugin}->__up( 1 );
711             }
712             else {
713 0           $self->__print_previous_page( $opt, $list );
714             }
715             }
716             }
717             elsif ( $key == VK_DOWN ) {
718 0 0         if ( $self->{curr_row} == $#$list ) {
719 0           $self->{beep} = 1;
720             }
721             else {
722 0           $self->{curr_row}++;
723 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
724 0 0         if ( $self->{curr_row} <= $self->{end_row} ) {
725 0           $self->__reset_previous_row( $opt, $list, $self->{curr_row} - 1 );
726 0           $self->{plugin}->__down( 1 );
727             }
728             else {
729 0           $self->{plugin}->__up( $self->{end_row} - $self->{begin_row} );
730 0           $self->__print_next_page( $opt, $list );
731             }
732             }
733             }
734             elsif ( $key == VK_PAGE_UP || $key == CONTROL_B ) {
735 0 0         if ( $self->{page} == 1 ) {
736 0 0         if ( $self->{curr_row} == 0 ) {
737 0           $self->{beep} = 1;
738             }
739             else {
740 0           $self->__reset_previous_row( $opt, $list, $self->{curr_row} );
741 0           $self->{plugin}->__up( $self->{curr_row} );
742 0           $self->{curr_row} = 0;
743 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
744             }
745             }
746             else {
747 0           $self->{plugin}->__up( $self->{curr_row} - $self->{begin_row} );
748 0           $self->{curr_row} = $self->{begin_row} - $self->{avail_height};
749 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
750 0           $self->__print_previous_page( $opt, $list );
751             }
752             }
753             elsif ( $key == VK_PAGE_DOWN || $key == CONTROL_F ) {
754 0 0         if ( $self->{page} == $self->{pages} ) {
755 0 0         if ( $self->{curr_row} == $#$list ) {
756 0           $self->{beep} = 1;
757             }
758             else {
759 0           $self->__reset_previous_row( $opt, $list, $self->{curr_row} );
760 0           $self->{plugin}->__down( $self->{end_row} - $self->{curr_row} );
761 0           $self->{curr_row} = $self->{end_row};
762 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
763             }
764             }
765             else {
766 0           $self->{plugin}->__up( $self->{curr_row} - $self->{begin_row} );
767 0           $self->{curr_row} = $self->{end_row} + 1;
768 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
769 0           $self->__print_next_page( $opt, $list );
770             }
771             }
772             else {
773 0           $key = chr $key;
774 0           utf8::upgrade $key;
775 0 0 0       if ( $key eq "\n" || $key eq "\r" ) { #
776 0           my $up = $self->{curr_row} - $self->{begin_row};
777 0 0         $up += $self->{nr_prompt_lines} if $self->{nr_prompt_lines};
778 0 0         if ( $list->[$self->{curr_row}][0] eq $opt->{back} ) {
    0          
779 0           $self->{plugin}->__up( $up );
780 0           $self->{plugin}->__clear_lines_to_end_of_screen();
781 0           $self->__reset_term();
782 0           return;
783             }
784             elsif ( $list->[$self->{curr_row}][0] eq $opt->{confirm} ) {
785 0           $self->{plugin}->__up( $up );
786 0           $self->{plugin}->__clear_lines_to_end_of_screen();
787 0           $self->__reset_term();
788 0           splice @$list, 0, @{$self->{pre_list}};
  0            
789 0 0 0       if ( $self->{compat} || ! defined $self->{compat} && $ENV{READLINE_SIMPLE_COMPAT} ) {
      0        
790 0           return [ map { [ $_->[0], encode( 'console_in', $_->[1] ) ] } @$list ];
  0            
791             }
792 0           return $list;
793             }
794 0 0         if ( $opt->{auto_up} == 2 ) {
    0          
795 0 0         if ( $self->{curr_row} == 0 ) {
796 0           $self->{beep} = 1;
797             }
798             else {
799 0           $self->{plugin}->__up( $up );
800 0           $self->{plugin}->__clear_lines_to_end_of_screen();
801 0           ( $str, $pos ) = $self->__write_first_screen( $opt, $list, 0 );
802 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
803             }
804             }
805             elsif ( $self->{curr_row} == $#$list ) {
806 0           $self->{plugin}->__up( $up );
807 0           $self->{plugin}->__clear_lines_to_end_of_screen();
808 0           ( $str, $pos ) = $self->__write_first_screen( $opt, $list, scalar @{$self->{pre_list}} );
  0            
809 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
810 0           $self->{enter_col} = $pos;
811 0           $self->{enter_row} = $self->{curr_row};
812             }
813             else {
814 0 0         if ( $opt->{auto_up} == 1 ) {
815 0 0 0       if ( defined $self->{enter_row} && $self->{enter_row} == $self->{curr_row}
      0        
      0        
816             && defined $self->{enter_col} && $self->{enter_col} == $pos
817             ) {
818 0           $self->{beep} = 1;
819 0           next;
820             }
821             else {
822 0           delete $self->{enter_row};
823 0           delete $self->{enter_col};
824             }
825             }
826 0           $self->{curr_row}++;
827 0           ( $str, $pos ) = $self->__gcstring_and_pos( $list );
828 0 0         if ( $self->{curr_row} <= $self->{end_row} ) {
829 0           $self->__reset_previous_row( $opt, $list, $self->{curr_row} - 1 );
830 0           $self->{plugin}->__down( 1 );
831             }
832             else {
833 0           $self->{plugin}->__up( $up );
834 0           $self->__print_next_page( $opt, $list );
835             }
836             }
837             }
838             else {
839 0 0         if ( $locked ) {
840 0           $self->{beep} = 1;
841             }
842             else {
843 0           $str->substr( $pos, 0, $key );
844 0           $pos++;
845             }
846             }
847             }
848             }
849             }
850              
851              
852             sub __reset_previous_row {
853 0     0     my ( $self, $opt, $list, $idx ) = @_;
854 0           $self->{plugin}->__clear_line();
855 0           print $self->__print_row( $opt, $list, $idx );
856             }
857              
858              
859             sub __print_next_page {
860 0     0     my ( $self, $opt, $list ) = @_;
861 0           $self->{begin_row} = $self->{end_row} + 1;
862 0           $self->{end_row} = $self->{end_row} + $self->{avail_height};
863 0 0         $self->{end_row} = $#$list if $self->{end_row} > $#$list;
864 0           $self->{plugin}->__clear_lines_to_end_of_screen();
865 0           $self->__write_screen( $opt, $list );
866             }
867              
868              
869             sub __print_previous_page {
870 0     0     my ( $self, $opt, $list ) = @_;
871 0           $self->{end_row} = $self->{begin_row} - 1;
872 0           $self->{begin_row} = $self->{begin_row} - $self->{avail_height};
873 0 0         $self->{begin_row} = 0 if $self->{begin_row} < 0;
874 0           $self->{plugin}->__clear_lines_to_end_of_screen();
875 0           $self->__write_screen( $opt, $list );
876             }
877              
878              
879             sub __padded_or_trimed_key {
880 0     0     my ( $self, $list, $idx ) = @_;
881 0           my $unicode;
882 0           my $key_length = $self->{length_key}[$idx];
883 0           my $key = $list->[$idx][0];
884 0           $key =~ s/\p{Space}/ /g;
885 0           $key =~ s/\p{C}//g;
886 0 0         if ( $key_length > $self->{len_longest_key} ) {
    0          
887 0           my $gcs = Unicode::GCString->new( $key );
888 0           $unicode = $self->__unicode_trim( $gcs, $self->{len_longest_key} );
889             }
890             elsif ( $key_length < $self->{len_longest_key} ) {
891 0           $unicode = " " x ( $self->{len_longest_key} - $key_length ) . $key;
892             }
893             else {
894 0           $unicode = $key;
895             }
896 0           return $unicode;
897             }
898              
899              
900             sub __unicode_trim {
901 0     0     my ( $self, $gcs, $len ) = @_;
902 0 0         if ( $gcs->columns <= $len ) {
903 0           return $gcs->as_string;
904             }
905 0           my $pos = $gcs->pos;
906 0           $gcs->pos( 0 );
907 0           my $cols = 0;
908 0           my $gc;
909 0           while ( defined( $gc = $gcs->next ) ) {
910 0 0         if ( ( $len - 3 ) < ( $cols += $gc->columns ) ) {
911 0           my $ret = $gcs->substr( 0, $gcs->pos - 1 );
912 0           $gcs->pos( $pos );
913 0           return $ret->as_string . '...';
914             }
915             }
916             }
917              
918              
919             # use utf8;
920             # use open qw( :std :utf8 );
921              
922             # use Term::ReadLine::Simple;
923             # use Term::ReadLine; # 1.14
924             # use Devel::Peek;
925              
926             # my $default = 'ü'; # "\x{fc}"
927             # character read with readline: 'ä' # "\x{e4}"
928              
929              
930             #-----------------------------------------------------------
931              
932             # my $tr = Term::ReadLine->new( 'Stub' ); # default not supported
933              
934             #-----------------------------------------------------------
935              
936             # my $tr = Term::ReadLine->new( 'Perl' );
937             # my $line = $tr->readline( ': ' );
938              
939             ### ä "\303\244"\0
940              
941             #-----------------------------------------------------------
942              
943             # my $tr = Term::ReadLine->new( 'Perl' );
944             # my $line = $tr->readline( ': ', $default );
945              
946             ### üä "\303\274\303\203\302\244"\0 [UTF8 "\x{fc}\x{c3}\x{a4}"]
947              
948             #-----------------------------------------------------------
949              
950             # my $tr = Term::ReadLine->new( 'Perl', *STDIN, *STDOUT );
951             # my $line = $tr->readline( ': ', $default );
952              
953             ### üä "\303\274\303\244"\0 [UTF8 "\x{fc}\x{e4}"]
954              
955             #-----------------------------------------------------------
956              
957             # my $tr = Term::ReadLine->new( 'Gnu 1.26' );
958             # my $line = $tr->readline( ': ', $default );
959              
960             ### üä "\303\274\303\244"\0
961              
962             #-----------------------------------------------------------
963              
964             # my $tr = Term::ReadLine->new( 'Gnu 1.26', *STDIN, *STDOUT );
965             # my $line = $tr->readline( ': ', $default );
966              
967             ### üä "\303\274\303\244"\0
968              
969             #-----------------------------------------------------------
970              
971             # my $tr = Term::ReadLine::Simple->new();
972             # $tr->config( { compat => 0 } );
973             # my $line = $tr->readline( ': ', $default );
974              
975             ### üä "\303\274\303\244"\0 [UTF8 "\x{fc}\x{e4}"]
976              
977             #-----------------------------------------------------------
978              
979             # my $tr = Term::ReadLine::Simple->new();
980             # $tr->config( { compat => 1 } );
981             # my $line = $tr->readline( ': ', $default );
982              
983             ### üä "\303\274\303\244"\0
984              
985              
986             1;
987              
988             __END__