./PaxHeaders/Term-Choose-1.7740000644000000000000000000000013215003446321013015 xustar0030 mtime=1745767633.849076873 30 atime=1745767633.697079682 30 ctime=1745767633.849076873 Term-Choose-1.774/0000755000175000001440000000000015003446321013507 5ustar00mmusers00000000000000Term-Choose-1.774/PaxHeaders/README0000644000000000000000000000013214762006242013622 xustar0030 mtime=1741163682.730300644 30 atime=1745767631.349123065 30 ctime=1745767633.701079608 Term-Choose-1.774/README0000644000175000001440000000107114762006242014373 0ustar00mmusers00000000000000Term-Choose =========== INFO Choose from a list. INSTALLATION To install this module, run the following commands: perl Makefile.PL make make test make install SUPPORT AND DOCUMENTATION After installing, you can find documentation for this module with the perldoc command. perldoc Term::Choose LICENSE AND COPYRIGHT Copyright (C) 2012-2025 Matthäus Kiem This library is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For details, see the full text of the licenses in the file LICENSE. Term-Choose-1.774/PaxHeaders/t0000644000000000000000000000013215003446321013123 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/t/0000755000175000001440000000000015003446321013752 5ustar00mmusers00000000000000Term-Choose-1.774/t/PaxHeaders/01_arguments0000644000000000000000000000013215003446321015430 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/t/01_arguments/0000755000175000001440000000000015003446321016257 5ustar00mmusers00000000000000Term-Choose-1.774/t/01_arguments/PaxHeaders/Data_Test_Arguments.pm0000644000000000000000000000013214772441255021755 xustar0030 mtime=1743405741.621965412 30 atime=1745767631.209125652 30 ctime=1745767633.701079608 Term-Choose-1.774/t/01_arguments/Data_Test_Arguments.pm0000644000175000001440000001126314772441255022532 0ustar00mmusers00000000000000package # hide Data_Test_Arguments; use 5.10.1; use warnings; use strict; sub valid_values { return { beep => [ 0, 1 ], clear_screen => [ 0, 1 ], hide_cursor => [ 0, 1 ], index => [ 0, 1 ], alignment => [ 0, 1, 2 ], layout => [ 0, 1, 2 ], mouse => [ 0, 1 ], order => [ 0, 1 ], page => [ 0, 1, 2], # '[ 1-9 ][ 0-9 ]*' keep => [ 1, 2, 100, 999999, undef ], ll => [ 1, 2, 100, 999999, undef ], max_height => [ 1, 2, 100, 999999, undef ], max_width => [ 1, 2, 100, 999999, undef ], # '[ 0-9 ]+' default => [ 0, 1, 2, 100, 999999, undef ], pad => [ 0, 1, 2, 100, 999999, undef ], # '' empty => [ 0, 'Hello' x 50, '', ' ', 'abc', 'world', undef ], prompt => [ 0, 'Hello' x 50, '', ' ', 'abc', 'world', undef ], undef => [ 0, 'Hello' x 50, '', ' ', 'abc', 'world', undef ], # ARRAY max 2 int tabs_info => [ [ 2, 4 ], [ 8 ], [], undef ], tabs_prompt => [ [ 2, 4 ], [ 8 ], [], undef ], # ARRAY int mark => [ [ 0, 1, 2, 100, 999999 ], [ 1 ], undef ], no_spacebar => [ [ 0, 1, 2, 100, 999999 ], [ 1 ], undef ], }; } sub mixed_options_1 { return { beep => 0, clear_screen => undef, hide_cursor => 1, index => 0, alignment => 0, layout => 0, mouse => 0, order => 1, page => 0, keep => 1, ll => 1, max_height => 19, max_width => 19, default => 9, pad => 3, empty => '', prompt => '', undef => '', tabs_info => [ 1 ], no_spacebar => [ 0 ], mark => [ 3, 4 ] }; } sub mixed_options_2 { return { mark => [ 0 ], no_spacebar => [ 11, 0, 8 ], tabs_prompt => [ 1, 1 ], undef => '', prompt => 'prompt_line', empty => '', pad => 3, default => 9, max_width => 19, max_height => 119, ll => 15, keep => 1, page => 1, order => 1, mouse => 1, layout => 2, alignment => 0, index => 0, hide_cursor => 1, clear_screen => undef, beep => 0, tabs_prompt => [ 4, 4 ] }; } ################################################################################################## sub invalid_values { my @invalid = ( -1, 2, 2 .. 10, 999999, '01', '', 'a', { 1, 1 }, [ 1 ], [ 2 ] ); return{ beep => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], clear_screen => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], hide_cursor => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], index => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], alignment => [ grep { ! /^[ 0 1 2 ]\z/x } @invalid ], layout => [ grep { ! /^[ 0 1 2 ]\z/x } @invalid ], mouse => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], order => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], page => [ grep { ! /^[ 0 1 2 ]\z/x } @invalid ], keep => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], ll => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], max_height => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], max_width => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], default => [ grep { ! /^[ 0-9 ]+\z/x } @invalid ], pad => [ grep { ! /^[ 0-9 ]+\z/x } @invalid ], # '' empty => [ { 1, 1 }, [ 1 ], {}, [], [ 2 ] ], prompt => [ { 1, 1 }, [ 1 ], {}, [], [ 2 ] ], undef => [ { 1, 1 }, [ 1 ], {}, [], [ 2 ] ], # ARRAY max 2 int tabs_info => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 1, 2, 's', ], [ 'a', 'b' ], [ -3, -4 ] ], tabs_prompt => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 1, 2, 'g', ], [ 'a', 'b' ], [ -3, -4 ] ], # ARRAY int mark => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 'a', 'b' ], [ -3, -4 ] ], no_spacebar => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 'a', 'b' ], [ -3, -4 ] ], }; } sub mixed_invalid_1 { return { beep => -1, clear_screen => 2, hide_cursor => 3, index => 4, alignment => '@', layout => 5, mouse => {}, order => 1, page => 'l', keep => -1, ll => -1, max_height => 0, max_width => 0, default => [], pad => 'a', empty => [], prompt => {}, undef => [], lf => 4, no_spacebar => 4, mark => 'o' }; } sub mixed_invalid_2 { return { mark => '', no_spacebar => 'a', lf => 'b', undef => [], prompt => {}, empty => {}, pad => 'd', default => 'e', max_width => -1, max_height => -2, ll => -4, keep => -5, page => -6, order => -7, mouse => 'k', layout => 'e', alignment => [], index => {}, hide_cursor => -1, clear_screen => [], beep => 10 }; } 1; __END__ Term-Choose-1.774/t/01_arguments/PaxHeaders/01_new.t0000644000000000000000000000013214772441246017000 xustar0030 mtime=1743405734.606100392 30 atime=1745767631.117127352 30 ctime=1745767633.701079608 Term-Choose-1.774/t/01_arguments/01_new.t0000644000175000001440000000245414772441246017557 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use Test::Fatal; use Term::Choose; use FindBin qw( $RealBin ); use lib $RealBin; use Data_Test_Arguments; my $new1; my $exception = exception { $new1 = Term::Choose->new() }; ok( ! defined $exception, '$new = Term::Choose->new()' ); ok( $new1, '$new = Term::Choose->new()' ); my $new; $exception = exception { $new = Term::Choose->new( {} ) }; ok( ! defined $exception, '$new = Term::Choose->new( {} )' ); my %new; my $n = 1; # ? my $valid_values = Data_Test_Arguments::valid_values(); for my $opt ( sort keys %$valid_values ) { for my $val ( @{$valid_values->{$opt}}, undef ) { my $exception = exception { $new{$n++} = Term::Choose->new( { $opt => $val } ) }; my $value = defined $val ? $val : 'undef'; ok( ! defined $exception, "\$new = Term::Choose->new( { $opt => $value } )" ); } } my $mixed_options_1 = Data_Test_Arguments::mixed_options_1(); $exception = exception { $new{$n++} = Term::Choose->new( $mixed_options_1 ) }; ok( ! defined $exception, "\$new = Term::Choose->new( { >>> } )" ); my $mixed_options_2 = Data_Test_Arguments::mixed_options_2(); $exception = exception { $new{$n++} = Term::Choose->new( $mixed_options_2 ) }; ok( ! defined $exception, "\$new = Term::Choose->new( { <<< } )" ); done_testing(); Term-Choose-1.774/t/PaxHeaders/00_load0000644000000000000000000000013215003446321014341 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/t/00_load/0000755000175000001440000000000015003446321015170 5ustar00mmusers00000000000000Term-Choose-1.774/t/00_load/PaxHeaders/01-new.t0000644000000000000000000000013214772441234015624 xustar0030 mtime=1743405724.546293937 30 atime=1745767631.041128756 30 ctime=1745767633.701079608 Term-Choose-1.774/t/00_load/01-new.t0000644000175000001440000000026114772441234016375 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use Term::Choose; my $package = 'Term::Choose'; my $new; ok( $new = $package->new(), "$package->new()" ); done_testing; Term-Choose-1.774/t/00_load/PaxHeaders/00-load.t0000644000000000000000000000013114772441226015751 xustar0030 mtime=1743405718.090418143 29 atime=1745767630.96513016 30 ctime=1745767633.701079608 Term-Choose-1.774/t/00_load/00-load.t0000644000175000001440000000030714772441226016524 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More tests => 1; BEGIN { use_ok( 'Term::Choose' ) || print "Bail out!\n"; } diag( "Testing Term::Choose $Term::Choose::VERSION, Perl $], $^X" ); Term-Choose-1.774/t/PaxHeaders/LineFold0000644000000000000000000000013215003446321014617 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/t/LineFold/0000755000175000001440000000000015003446321015446 5ustar00mmusers00000000000000Term-Choose-1.774/t/LineFold/PaxHeaders/02-cut.t0000644000000000000000000000013215003445036016075 xustar0030 mtime=1745766942.166160668 30 atime=1745767631.277124396 30 ctime=1745767633.701079608 Term-Choose-1.774/t/LineFold/02-cut.t0000644000175000001440000000736415003445036016661 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use open qw(:std :utf8); use Test::More; use Term::Choose::LineFold::PP; #my $wide = $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE}; my $wide; # 24.03.2025 if ( exists $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE} ) { # $wide = $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE}; # } # else { # $wide = $ENV{TC_AMBIGUOUS_WIDE}; # } # my @cut_tests = ( [ "\x{61}\x{ff41}\x{4e2d}\x{b7}\x{1f44d}", $wide ? 7 : 6, [ "\x{61}\x{ff41}\x{4e2d}\x{b7}", "\x{1f44d}" ] ], [ "\x{68}\x{65}\x{6c}\x{6c}\x{6f}", 2, [ "\x{68}\x{65}", "\x{6c}\x{6c}\x{6f}" ] ], # "hello" [ "\x{68}\x{e9}\x{6c}\x{6c}\x{6f}", $wide ? 3 : 2, [ "\x{68}\x{e9}", "\x{6c}\x{6c}\x{6f}" ] ], # "héllo" [ "\x{61}\x{3042}\x{62}\x{3044}\x{63}\x{3046}", 2, [ "\x{61}\x{20}", "\x{3042}\x{62}\x{3044}\x{63}\x{3046}" ] ], # "aあbいcう" [ "\x{61}\x{ff}\x{62}\x{63}\x{64}", 2, [ "\x{61}\x{ff}", "\x{62}\x{63}\x{64}" ] ], # "a\x{ff}bcd" [ "\x{0e2a}\x{0e27}\x{0e31}\x{0e2a}\x{0e14}\x{0e35}", 2, [ "\x{0e2a}\x{0e27}\x{0e31}", "\x{0e2a}\x{0e14}\x{0e35}" ] ], # "สวัสดี" [ "\x{61}\x{1f60a}\x{1f60a}\x{1f60a}\x{1f60a}", 4, [ "\x{61}\x{1f60a}\x{20}", "\x{1f60a}\x{1f60a}\x{1f60a}" ] ], # "a😊😊😊😊" [ "\x{61}\x{1f60a}\x{1f60a}\x{1f60a}\x{1f60a}", 5, [ "\x{61}\x{1f60a}\x{1f60a}", "\x{1f60a}\x{1f60a}" ] ], # "a😊😊😊😊" [ "\x{1f60a}\x{1f60a}\x{1f60a}\x{1f60a}", 4, [ "\x{1f60a}\x{1f60a}", "\x{1f60a}\x{1f60a}" ] ], # "😊😊😊😊" [ "\x{1f60a}\x{1f60a}\x{1f60a}\x{1f60a}", 5, [ "\x{1f60a}\x{1f60a}\x{20}", "\x{1f60a}\x{1f60a}" ] ], # "😊😊😊😊" ); for my $d ( @cut_tests ) { my ( $str, $w, $ret ) = @$d; my ( $first, $rem ) = Term::Choose::LineFold::PP::cut_to_printwidth( $str, $w ); is_deeply( [ $first, $rem ], $ret, "cut_to_printwidth( $str, $w ): [ |$first|, |$rem| ] -> [ |$ret->[0]|, |$ret->[0]| ]" ); } for my $d ( @cut_tests ) { my ( $str, $w, $ret ) = @$d; my $cut = Term::Choose::LineFold::PP::cut_to_printwidth( $str, $w ); is( $cut, $ret->[0], "scalar cut_to_printwidth( $str, $w ): |$cut| -> |$ret->[0]|" ); } for my $d ( @cut_tests ) { my ( $str, $w, $ret ) = @$d; my $expected = $ret->[0]; my $adjusted = Term::Choose::LineFold::PP::adjust_to_printwidth( $str, $w ); is( $adjusted, $expected, "adjust_to_printwidth( $str, $w ): |$adjusted| -> |$expected|" ); } my $w = 10; my @pad_tests = ( [ "\x{61}\x{ff41}\x{4e2d}\x{b7}\x{1f44d}", $wide ? 1 : 2 ], [ "\x{68}\x{e9}\x{6c}\x{6c}\x{6f}", $wide ? 4 : 5 ], # "héllo" [ "\x{61}\x{ff}\x{62}\x{63}\x{64}", 5 ], # "a\x{ff}bcd" [ "\x{0e2a}\x{0e27}\x{0e31}\x{0e2a}\x{0e14}\x{0e35}", 6 ], # "สวัสดี" [ "\x{61}\x{1f60a}\x{1f60a}\x{1f60a}\x{1f60a}", 1 ], # "a😊😊😊😊" [ "\x{1f60a}\x{1f60a}\x{1f60a}\x{1f60a}", 2 ], # "😊😊😊😊" [ "", 10 ], ); for my $d ( @pad_tests ) { my ( $str, $trailing_saces ) = @$d; my $expected = $str . ( "\x{20}" x $trailing_saces ); my $adjusted = Term::Choose::LineFold::PP::adjust_to_printwidth( $str, $w ); is( $adjusted, $expected, "adjust_to_printwidth( $str, $w ): |$adjusted| -> |$expected|" ); } done_testing(); Term-Choose-1.774/t/LineFold/PaxHeaders/01-width.t0000644000000000000000000000013215003445021016412 xustar0030 mtime=1745766929.954371432 30 atime=1745767631.233125209 30 ctime=1745767633.701079608 Term-Choose-1.774/t/LineFold/01-width.t0000644000175000001440000000526215003445021017171 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use open qw(:std :utf8); use Test::More; use Term::Choose::LineFold::PP; #my $wide = $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE}; my $wide; # 24.03.2025 if ( exists $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE} ) { # $wide = $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE}; # } # else { # $wide = $ENV{TC_AMBIGUOUS_WIDE}; # } # my @char_tests = ( [ "\x{61}", 1 ], # a [ "\x{ff41}", 2 ], # Full-width a [ "\x{4e2d}", 2 ], # CJK character 中, [ "\x{b7}", $wide ? 2 : 1 ], # Middle dot ·, ambiguous width [ "\x{1f44d}", 2 ], # 👍 [ "\x{20}", 1 ], [ "\x{ff71}", 1 ], # Half-width Katakana ア [ "\x{1f600}", 2 ], # 😀 [ "\x0", 1 ], # Null character, default to 1 [ "\x{11000}", 1 ], # Above Unicode range, defaults to 1 [ "\x{ffe9}", 1 ], # Yen sign ¥ [ "\x{ffe5}", 2 ], # Fullwidth Yen sign ¥ ); for my $d ( @char_tests ) { my ( $char, $expected_w ) = @$d; my $w = Term::Choose::LineFold::PP::char_width( ord $char ); ok( $w == $expected_w, "char_width( ord $char ): $w -> $expected_w" ); } my @str_tests = ( [ "\x{61}\x{ff41}\x{4e2d}\x{b7}\x{1f44d}\x{20}\x{ff71}\x{3042}", $wide ? 13 : 12 ], [ "\x{68}\x{65}\x{6c}\x{6c}\x{6f}", 5 ], # "hello" [ "\x{68}\x{e9}\x{6c}\x{6c}\x{6f}", $wide ? 6 : 5 ], # "héllo" [ "\x{61}\x{3042}\x{62}\x{3044}\x{63}\x{3046}", 9 ], # "aあbいcう", 9], [ "\x{1d11e}\x{1d122}\x{1d12b}", 3 ], # musical symbols [ "\x{61}\x{ff}\x{62}\x{63}\x{64}", 5 ], # "a\x{ff}bcd" malformed UTF-8 [ "\x{ff21}\x{ff22}\x{ff23}\x{ff24}\x{ff25}", 10 ], # "ABCDE" [ "\x{3053}\x{3093}\x{306b}\x{3061}\x{306f}", 10 ], # "こんにちは" [ "\x{c548}\x{b155}\x{d558}\x{c138}\x{c694}", 10 ], # "안녕하세요" [ "\x{0e2a}\x{0e27}\x{0e31}\x{0e2a}\x{0e14}\x{0e35}", 4 ], # "สวัสดี" [ "\x{48}\x{65}\x{6c}\x{6c}\x{6f}\x{20}\x{1f60a}\x{20}", 9 ], # "Hello 😊 " [ "\x{77}\x{6f}\x{72}\x{6c}\x{64}\x{20}\x{1f389}", 8 ], # "world 🎉" ); for my $d (@str_tests) { my ( $str, $expected_w ) = @$d; my $w = Term::Choose::LineFold::PP::print_columns( $str ); ok( $w == $expected_w, "print_columns( $str ): $w -> $expected_w" ); } done_testing(); Term-Choose-1.774/PaxHeaders/MANIFEST0000644000000000000000000000013215003446321014066 xustar0030 mtime=1745767633.897075987 30 atime=1745767633.897075987 30 ctime=1745767633.897075987 Term-Choose-1.774/MANIFEST0000644000175000001440000000323015003446321014636 0ustar00mmusers00000000000000Changes lib/Term/Choose.pm lib/Term/Choose/Constants.pm lib/Term/Choose/LineFold.pm lib/Term/Choose/LineFold/PP.pm lib/Term/Choose/LineFold/PP/CharWidthAmbiguousWide.pm lib/Term/Choose/LineFold/PP/CharWidthDefault.pm lib/Term/Choose/Linux.pm lib/Term/Choose/Opt/Mouse.pm lib/Term/Choose/Opt/Search.pm lib/Term/Choose/Opt/SkipItems.pm lib/Term/Choose/Screen.pm lib/Term/Choose/ValidateOptions.pm lib/Term/Choose/Win32.pm LICENSE Makefile.PL MANIFEST This list of files README t/00_load/00-load.t t/00_load/01-new.t t/01_arguments/01_new.t t/01_arguments/Data_Test_Arguments.pm t/LineFold/01-width.t t/LineFold/02-cut.t tools/build_TCF_char_width_table_modules.pl tools/update_verson.pl tools/xt_prereq.txt xt/01_option.t xt/02_option_error.t xt/cntr_choose.t xt/critic.t xt/Expect/00_get_key_linux.t xt/Expect/get_key_linux.pl xt/Expect/Y3_choose_function.t xt/Expect/Y3_choose_function_invalid.t xt/Expect/Y3_choose_method.t xt/Expect/Y3_choose_method_invalid.t xt/Expect/Y_choose_function_arguments.pl xt/Expect/Y_choose_function_invalid_arguments.pl xt/Expect/Y_choose_method_arguments.pl xt/Expect/Y_choose_method_invalid_arguments.pl xt/Expect/Y_Data_Test_Arguments.pm xt/Expect/Z0_clone_win.t xt/Expect/Z1_hide_cursor.t xt/Expect/Z2_choose.t xt/Expect/Z_choose.pl xt/Expect/Z_Data_Test_Choose.pm xt/manifest.t xt/perl_minimum_version.t xt/perlcriticrc xt/pod-coverage.t xt/pod.t xt/pod_defaults.t xt/prereqs.t xt/spelling.t xt/synopsis.t xt/vars.t xt/version1.t xt/version2.t xt/whitespaces.t xt/year_copyright.t META.yml Module YAML meta-data (added by MakeMaker) META.json Module JSON meta-data (added by MakeMaker) Term-Choose-1.774/PaxHeaders/META.yml0000644000000000000000000000013215003446321014206 xustar0030 mtime=1745767633.761078499 30 atime=1745767633.705079534 30 ctime=1745767633.761078499 Term-Choose-1.774/META.yml0000644000175000001440000000156615003446321014770 0ustar00mmusers00000000000000--- abstract: 'Choose items from a list interactively.' author: - 'Matthaeus Kiem ' build_requires: File::Spec::Functions: '0' FindBin: '0' Test::Fatal: '0' Test::More: '0' lib: '0' open: '0' configure_requires: ExtUtils::MakeMaker: '0' dynamic_config: 1 generated_by: 'ExtUtils::MakeMaker version 7.74, CPAN::Meta::Converter version 2.150010' license: perl meta-spec: url: http://module-build.sourceforge.net/META-spec-v1.4.html version: '1.4' name: Term-Choose no_index: directory: - t - inc requires: Carp: '0' Exporter: '0' Term::Choose::LineFold::XS: '0.001' constant: '0' perl: '5.010001' strict: '0' warnings: '0' resources: bugtracker: https://github.com/kuerbis/Term-Choose/issues repository: https://github.com/kuerbis/Term-Choose.git version: '1.774' x_serialization_backend: 'CPAN::Meta::YAML version 0.020' Term-Choose-1.774/PaxHeaders/tools0000644000000000000000000000013215003446321014020 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/tools/0000755000175000001440000000000015003446321014647 5ustar00mmusers00000000000000Term-Choose-1.774/tools/PaxHeaders/build_TCF_char_width_table_modules.pl0000644000000000000000000000013215003105264023316 xustar0030 mtime=1745652404.860004643 30 atime=1745740526.660356854 30 ctime=1745767633.701079608 Term-Choose-1.774/tools/build_TCF_char_width_table_modules.pl0000755000175000001440000002067515003105264024105 0ustar00mmusers00000000000000#!/usr/bin/env perl use warnings; use 5.014; use utf8; use open qw(:std :utf8); use Data::Dumper; # cpanm --notest Net::SSLeay use LWP::Protocol::https; use WWW::Mechanize::Cached; use Term::Choose; # https://www.unicode.org/Public/UNIDATA/UnicodeData.txt # https://unicode.org/reports/tr44/#UnicodeData.txt # https://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt # https://www.unicode.org/reports/tr11/ # https://www.unicode.org/Public/UNIDATA/extracted/DerivedGeneralCategory.txt' $SIG{__WARN__} = sub { die @_ }; sub unicode_data { my $mech = WWW::Mechanize::Cached->new(); my $res = $mech->get( 'https://www.unicode.org/Public/UNIDATA/UnicodeData.txt' ); if ( ! $res->is_success ) { die $res->status_line; } my $page = $mech->content( format => 'text' ); my $data = [ # https://unicode.org/reports/tr44/#UnicodeData.txt 1-3 #[ qw|Hex Name General_Category Canonical_Combining_Class Bidi_Class| ] ]; my $first; for my $row ( split /\n/, $page ) { my ( $codepoint, $name, $category, $combining_class, $bidi_class ) = ( split /;/, $row, -1 )[0..4]; $codepoint = hex $codepoint; if ( $name =~ /First>\z/ ) { $first = $codepoint; } elsif ( $first ) { if ( $name =~ /Last>\z/ ) { my $last = $codepoint; for my $c ( $first .. $last ) { $data->[$c]{category} = $category; $data->[$c]{bidi_class} = $bidi_class; } $first = undef; $last = undef; } else { die "$codepoint - $name - $category - $combining_class - $bidi_class"; } } else { $data->[$codepoint]{category} = $category; $data->[$codepoint]{bidi_class} = $bidi_class; } } return $data; } sub east_asian_width_table { my $mech = WWW::Mechanize::Cached->new(); my $res = $mech->get( 'https://www.unicode.org/Public/UNIDATA/EastAsianWidth.txt' ); if ( ! $res->is_success ) { die $res->status_line; } my $page = $mech->content( format => 'text' ); my $east_asian_width_table = []; for my $row ( split /\n/, $page ) { if ( $row =~ /^(\S+)\s*;\s*(\S\S?)\s/ ) { my @range = split /\.\./, $1; if ( @range == 1 ) { push @range, $1; } push @$east_asian_width_table, [ @range, $2 ]; } } return $east_asian_width_table; } sub width_east_asian { my ( $east_asian_width_table, $c ) = @_; for my $e ( @$east_asian_width_table ) { my $begin = hex( $e->[0] ); my $end = hex( $e->[1] ); if ( $c >= $begin && $c <= $end ) { return $e->[2]; } } return 'N'; } my $unicode_data = unicode_data(); my $east_asian_width_table = east_asian_width_table(); my $width_normal = []; my $width_ambiguous = []; for my $c ( 0x0 .. 0x10ffff ) { printf "0x%x\n", $c; my $category = $unicode_data->[$c]{category} // ''; my $bidi_class = $unicode_data->[$c]{bidi_class} // ''; my $east_asian_width = width_east_asian( $east_asian_width_table, $c ); my $print_width; if ( $category =~ /^(?:Cc|Cs)\z/ ) { # Other, control # Other, surrogate $print_width = [ -1, -1 ]; } elsif ( $c == 0x00AD ) { # Soft Hyphen (in Cf) # http://unicode.org/reports/tr14/#SoftHyphen but terminals use 1 resp 2 print-width # Ambiguous $print_width = [ 1, 2 ]; } elsif ( $category =~ /^(?:Mn|Me)\z/ ) { # Mn = Mark, nonspacing # Me = Mark, enclosing # categories might not be up to date $print_width = [ 0, 0 ]; } elsif ( $category eq 'Cf' && $bidi_class ne 'AN' ) { # Cf = Other, format # AN = bidi clas arbic number # https://www.unicode.org/versions/Unicode14.0.0/ch09.pdf # 9.2 Arabic -> Signs Spanning Numbers -> Unlike ... $print_width = [ 0, 0 ]; } elsif ( $c >= 0x1160 && $c <= 0x11FF || $c >= 0x0D7B0 && $c <= 0x0D7FF ) { # # https://devblogs.microsoft.com/oldnewthing/20201009-00/?p=104351 $print_width = [ 0, 0 ]; } elsif ( $east_asian_width =~ /^(?:W|F)\z/ ) { # W = Wide, F = Fullwidth # https://www.unicode.org/reports/tr11/ $print_width = [ 2, 2 ]; } elsif ( $east_asian_width eq 'A' ) { # A = Ambiguous, $print_width = [ 1, 2 ]; } else { $print_width = [ 1, 1 ]; } $width_normal->[$c] = $print_width->[0]; $width_ambiguous->[$c] = $print_width->[1]; } sub build_ranges { my ( $width_table ) = @_; my $ranges = []; my $prev = { begin => 0, end => 0, width => 9 }; for my $c ( 0x0 .. 0x10ffff ) { printf "0x%x\n", $c; my $width = $width_table->[$c]; my $range = []; if ( $prev->{width} == $width ) { $range = [ $prev->{begin}, $c ]; } else { $range = [ $c, $c ]; } if ( $range->[0] != $prev->{begin} ) { push @$ranges, $prev; } $prev = { begin => $range->[0], end => $range->[1], width => $width }; } push @$ranges, $prev; # push the last $prev return $ranges; } # # # # # Perl PP # # # # # for my $file_name ( "CharWidthAmbiguousWide.pm", "CharWidthDefault.pm" ) { my $ranges; my $amb; if ( $file_name eq "CharWidthDefault.pm" ) { $amb = 'narrow'; $ranges = build_ranges( $width_normal ); } else { $amb = 'wide'; $ranges = build_ranges( $width_ambiguous ); } open my $fh, '>', $file_name or die $!; my $module = $file_name =~ s/\.pm\z//r; print $fh <<"PP_HEADER"; package Term::Choose::LineFold::$module; use warnings; use strict; use 5.10.1; our \$VERSION = '$Term::Choose::VERSION'; use Exporter qw( import ); our \@EXPORT_OK = qw( table_char_width ); # test with gnome-terminal - ambiguous characters set to $amb # Control characters, non-characters and surrogates are removed before using this table. sub table_char_width { [ PP_HEADER for my $r ( @$ranges ) { my $cm = $r->{width} < 0 ? '#' : ''; # comment out entries with a width of -1: Cc and Cs printf $fh "${cm}[%8s, %8s, %d],\n", sprintf( "0x%x", $r->{begin} ), sprintf( "0x%x", $r->{end} ), $r->{width}; } print $fh "] }\n\n\n1;\n"; close $fh; } # # # # # Perl XS # # # # # for my $file_name ( "charwidth_default.h", "charwidth_ambiguous_is_wide.h" ) { my $ranges; my $macro_name = uc $file_name =~ s/\./_/r; if ( $file_name eq "charwidth_default.h" ) { $ranges = build_ranges( $width_normal ); } else { $ranges = build_ranges( $width_ambiguous ); } open my $fh, '>', $file_name or die $!; print $fh <<"XS_HEADER"; #ifndef $macro_name #define $macro_name typedef struct { unsigned int start; unsigned int end; int width; } WidthRange; static const WidthRange width_table[] = { XS_HEADER for my $r ( @$ranges ) { my $cm = $r->{width} < 0 ? '//' : ''; # comment out entries with a width of -1: Cc and Cs printf $fh "${cm} { %s, %s, %d },\n", sprintf( "0x%x", $r->{begin} ), sprintf( "0x%x", $r->{end} ), $r->{width}; } print $fh <<"XS_FOOTER"; }; static const int width_table_len = sizeof(width_table) / sizeof(width_table[0]); #endif XS_FOOTER close $fh; } # # # # # Rakudo # # # # # for my $file_name ( "CharWidthAmbiguousWide.pm6", "CharWidthDefault.pm6" ) { my $ranges; my $amb; if ( $file_name eq "CharWidthDefault.pm" ) { $amb = 'narrow'; $ranges = build_ranges( $width_normal ); } else { $amb = 'wide'; $ranges = build_ranges( $width_ambiguous ); } open my $fh, '>', $file_name or die $!; my $module = $file_name =~ s/\.pm\z//r; print $fh <<"RAKU_HEADER"; use v6; unit module Term::Choose::LineFold::$module; # test with gnome-terminal - ambiguous characters set to $amb # Control characters, non-characters and surrogates are removed before using this table. # To have less ranges in table_char_width non-characters return 1. sub table_char_width is export { [ RAKU_HEADER for my $r ( @$ranges ) { my $cm = $r->{width} < 0 ? '#' : ''; # comment out entries with a width of -1: Cc and Cs printf $fh "${cm}[%8s, %8s, %d],\n", sprintf( "0x%x", $r->{begin} ), sprintf( "0x%x", $r->{end} ), $r->{width}; } print $fh "] }\n"; close $fh; } Term-Choose-1.774/tools/PaxHeaders/xt_prereq.txt0000644000000000000000000000013215003174245016652 xustar0030 mtime=1745680549.182346785 30 atime=1745767031.044785833 30 ctime=1745767633.701079608 Term-Choose-1.774/tools/xt_prereq.txt0000644000175000001440000000062715003174245017431 0ustar00mmusers00000000000000cpanm Perl::MinimumVersion cpanm Perl::Version cpanm Pod::Coverage cpanm Pod::Coverage::TrustMe cpanm Test::CheckManifest cpanm Test::Fatal cpanm Test::More cpanm Test::Perl::Critic cpanm Test::Pod cpanm Test::Pod::Coverage cpanm Test::Pod::Coverage::TrustMe cpanm Test::Prereq cpanm --force Test::Spelling cpanm Test::Synopsis cpanm Test::Vars cpanm Test::Version cpanm Test::Whitespaces cpanm Time::Piece Term-Choose-1.774/tools/PaxHeaders/update_verson.pl0000644000000000000000000000013215003105212017277 xustar0030 mtime=1745652362.028894563 30 atime=1745740526.664356757 30 ctime=1745767633.701079608 Term-Choose-1.774/tools/update_verson.pl0000755000175000001440000000220715003105212020055 0ustar00mmusers00000000000000#!/usr/bin/env perl use warnings; use 5.10.1; use File::Find; use File::Copy qw(move); use File::Temp qw(tempfile); use FindBin; my $old = '1.773'; my $new = '1.774'; my $pattern_our = qr/^our \$VERSION = '\Q$old\E';/; my $replacement_our = "our \$VERSION = '$new';"; my $pattern_pod = qr/^Version \Q$old\E(?=$)/; my $replacement_pod = "Version $new"; my $directory = "$FindBin::Bin/../lib"; find( \&wanted, $directory ); sub wanted { return unless -f; return unless /\.pm\z/; my $file = $File::Find::name; my $changed = 0; my ( $out, $tempfile ) = tempfile(); open my $in, '<', $file or die "$file: $!"; while ( my $line = <$in> ) { if ( $line =~ $pattern_our ) { $line =~ s/$pattern_our/$replacement_our/; $changed = 1; } if ( $changed && $line =~ $pattern_pod ) { $line =~ s/$pattern_pod/$replacement_pod/; } print $out $line; } close $in; close $out; if ( $changed ) { move( $tempfile, $file ) or die "Can't overwrite $file: $!"; say "Updated: $file"; } else { unlink $tempfile; } } Term-Choose-1.774/PaxHeaders/xt0000644000000000000000000000013215003446321013313 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.697079682 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/0000755000175000001440000000000015003446321014142 5ustar00mmusers00000000000000Term-Choose-1.774/xt/PaxHeaders/critic.t0000644000000000000000000000013214775673705015061 xustar0030 mtime=1744271301.273991645 30 atime=1745740490.489231402 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/critic.t0000644000175000001440000000307114775673705015634 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::Perl::Critic ( -profile => 'xt/perlcriticrc', -exclude => [ qw( BuiltinFunctions::ProhibitComplexMappings CodeLayout::RequireTidyCode CodeLayout::RequireTrailingCommas ControlStructures::ProhibitCascadingIfElse ControlStructures::ProhibitDeepNests ControlStructures::ProhibitPostfixControls Documentation::RequirePodLinksIncludeText Documentation::RequirePodSections InputOutput::ProhibitExplicitStdin InputOutput::ProhibitInteractiveTest InputOutput::ProhibitOneArgSelect InputOutput::RequireBracedFileHandleWithPrint InputOutput::RequireEncodingWithUTF8Layer NamingConventions::Capitalization References::ProhibitDoubleSigils RegularExpressions::ProhibitEnumeratedClasses RegularExpressions::RequireDotMatchAnything RegularExpressions::RequireExtendedFormatting RegularExpressions::RequireLineBoundaryMatching Subroutines::ProhibitExcessComplexity Subroutines::ProhibitSubroutinePrototypes Subroutines::ProhibitUnusedPrivateSubroutines Subroutines::RequireArgUnpacking Subroutines::RequireFinalReturn ValuesAndExpressions::ProhibitEmptyQuotes ValuesAndExpressions::ProhibitInterpolationOfLiterals ValuesAndExpressions::ProhibitMagicNumbers ValuesAndExpressions::ProhibitNoisyQuotes Variables::ProhibitPunctuationVars Variables::RequireLocalizedPunctuationVars ) ], ); all_critic_ok(); Term-Choose-1.774/xt/PaxHeaders/pod-coverage.t0000644000000000000000000000013214775673705016157 xustar0030 mtime=1744271301.273991645 30 atime=1745740490.553229855 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/pod-coverage.t0000644000175000001440000000032314775673705016727 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use Test::Pod::Coverage; use Pod::Coverage; use lib 'lib'; use Term::Choose; #all_pod_coverage_ok(); plan tests => 1; pod_coverage_ok( 'Term::Choose' ); Term-Choose-1.774/xt/PaxHeaders/version2.t0000644000000000000000000000013215003210723015317 xustar0030 mtime=1745686995.516114724 30 atime=1745686995.688111003 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/version2.t0000644000175000001440000000374615003210723016103 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Time::Piece; use Test::More; my $v = -1; my $v_pod = -1; open my $fh, '<', 'lib/Term/Choose.pm' or die $!; while ( my $line = <$fh> ) { if ( $line =~ /^our\s\$VERSION\s=\s'(\d\.\d\d\d(?:_\d\d)?)';/ ) { $v = $1; } if ( $line =~ /^=pod/ .. $line =~ /^=cut/ ) { if ( $line =~ /^\s*Version\s+(\S+)/ ) { $v_pod = $1; } } } close $fh; is( $v, $v_pod, 'Version in POD Term::Choose OK' ); my $lf_v_pod = -1; open $fh, '<', 'lib/Term/Choose/LineFold.pm' or die $!; while ( my $line = <$fh> ) { if ( $line =~ /^=pod/ .. $line =~ /^=cut/ ) { if ( $line =~ /^\s*Version\s+(\S+)/ ) { $lf_v_pod = $1; } } } close $fh; is( $v, $lf_v_pod, 'Version in POD Term::Choose::LineFold OK' ); my @modules = qw( lib/Term/Choose.pm lib/Term/Choose/Constants.pm lib/Term/Choose/LineFold.pm lib/Term/Choose/LineFold/PP.pm lib/Term/Choose/LineFold/PP/CharWidthAmbiguousWide.pm lib/Term/Choose/LineFold/PP/CharWidthDefault.pm lib/Term/Choose/Linux.pm lib/Term/Choose/Opt/Mouse.pm lib/Term/Choose/Opt/Search.pm lib/Term/Choose/Opt/SkipItems.pm lib/Term/Choose/Screen.pm lib/Term/Choose/ValidateOptions.pm lib/Term/Choose/Win32.pm ); for my $module ( @modules ) { my $v_module = -1; open $fh, '<', $module or die $!; while ( my $line = <$fh> ) { if ( $line =~ /^our\s\$VERSION\s=\s'(\d\.\d\d\d(?:_\d\d)?)';/ ) { $v_module = $1; } } close $fh; is( $v, $v_module, 'Version in $module OK' ); } my $release_date = -1; my $v_changes = -1; open my $fh_ch, '<', 'Changes' or die $!; while ( my $line = <$fh_ch> ) { if ( $line =~ /^\s*(\d+\.\d\d\d(?:_\d\d)?)\s+(\d\d\d\d-\d\d-\d\d)\s*\z/ ) { $v_changes = $1; $release_date = $2; last; } } close $fh_ch; is( $v, $v_changes, 'Version in "Changes" OK' ); my $t = localtime; my $today = $t->ymd; is( $release_date, $today, 'Release date in Changes is date from today' ); done_testing(); Term-Choose-1.774/xt/PaxHeaders/manifest.t0000644000000000000000000000013214775673705015412 xustar0030 mtime=1744271301.273991645 30 atime=1745740490.577229275 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/manifest.t0000644000175000001440000000014014775673705016157 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use Test::CheckManifest; ok_manifest(); Term-Choose-1.774/xt/PaxHeaders/02_option_error.t0000644000000000000000000000013214775673705016626 xustar0030 mtime=1744271301.273991645 30 atime=1745740703.564079652 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/02_option_error.t0000644000175000001440000000666114775673705017411 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use utf8; use Test::More; use Test::Fatal; use lib 'lib'; use Term::Choose qw( choose ); no warnings 'redefine'; sub Term::Choose::__get_key { sleep 0.01; return 0x0d }; close STDIN or plan skip_all => "Close STDIN $!"; my $stdin = "eingabe\n"; open STDIN, "<", \$stdin or plan skip_all => "STDIN $!"; close STDOUT or plan skip_all => "Close STDOUT $!"; close STDERR or plan skip_all => "Close STDERR $!"; my ( $tmp_stdout, $tmp_stderr ); open STDOUT, '>', \$tmp_stdout or plan skip_all => "STDOUT $!"; open STDERR, '>', \$tmp_stderr or plan skip_all => "STDERR $!"; my $choices = [ '', 0, undef, 1, 2, 3, 'aa' .. 'zz', '☻☮☺', "\x{263a}\x{263b}", '한글', 'æða' ]; my $d; my $begin_errormessage = qr/^choose:/; my $int = { beep => '[ 0 1 ]', clear_screen => '[ 0 1 ]', hide_cursor => '[ 0 1 ]', index => '[ 0 1 ]', alignment => '[ 0 1 2 ]', layout => '[ 0 1 2 3 ]', mouse => '[ 0 1 2 3 4 ]', order => '[ 0 1 ]', page => '[ 0 1 2 ]', keep => '[ 1-9 ][ 0-9 ]*', ll => '[ 1-9 ][ 0-9 ]*', max_height => '[ 1-9 ][ 0-9 ]*', max_width => '[ 1-9 ][ 0-9 ]*', default => '[ 0-9 ]+', pad => '[ 0-9 ]+', }; my @wrong = ( -1, 2, 2 .. 10, 999999, '01', '', 'a', { 1, 1 }, [ 1 ], {}, [], [ 2 ] ); for my $opt ( sort keys %$int ) { for my $val ( grep { ! /^$int->{$opt}\z/x } @wrong ) { my $exception = exception { $d = choose( $choices, { $opt => $val } ) }; ok( $exception =~ $begin_errormessage ); } } my $string = { empty => '', prompt => '', undef => '', }; my @wrong_string = ( { 1, 1 }, [ 1 ], {}, [], [ 2 ] ); for my $opt ( sort keys %$string ) { for my $val ( grep { ref } @wrong_string ) { my $exception = exception { $d = choose( $choices, { $opt => $val } ) }; ok( $exception =~ $begin_errormessage ); } } my $tabs_prompt = { tabs_prompt => 'Array_Int', }; my @val_tabs_prompt = ( -2, -1, 0, 1, '', 'a', { 1, 1 }, {} ); for my $opt ( sort keys %$tabs_prompt ) { for my $val ( @val_tabs_prompt ) { my $exception = exception { $d = choose( $choices, { $opt => $val } ) }; ok( $exception =~ $begin_errormessage ); } } my $no_spacebar = { no_spacebar => 'Array_Int', }; my @val_no_spacebar = ( -2, -1, 0, 1, '', 'a', { 1, 1 }, {} ); for my $opt ( sort keys %$no_spacebar ) { for my $val ( @val_no_spacebar ) { my $exception = exception { $d = choose( $choices, { $opt => $val } ) }; ok( $exception =~ $begin_errormessage ); } } my $exception = exception { $d = choose( $choices, { beep => -1, clear_screen => 2, hide_cursor => 3, index => 4, alignment => '@', layout => 5, mouse => {}, order => 1, page => 3, keep => -1, ll => -1, max_height => 0, max_width => 0, default => [], pad => 'a', empty => [], prompt => {}, undef => [], tabs_prompt => 4, no_spacebar => 4 } ) }; ok( $exception =~ $begin_errormessage ); $exception = exception { $d = choose( [ 'aaa' .. 'zzz' ], { no_spacebar => 'a', tabs_prompt => 'b', undef => [], prompt => {}, empty => {}, pad => 'd', default => 'e', max_width => -1, max_height => -2, ll => -4, keep => -5, page => -6, order => -7, mouse => 'k', layout => 'e', alignment => [], index => {}, hide_cursor => -1, clear_screen => [], beep => 10 } ) }; ok( $exception =~ $begin_errormessage ); done_testing(); __DATA__ Term-Choose-1.774/xt/PaxHeaders/Expect0000644000000000000000000000013215003446321014543 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/0000755000175000001440000000000015003446321015372 5ustar00mmusers00000000000000Term-Choose-1.774/xt/Expect/PaxHeaders/Y3_choose_function_invalid.t0000644000000000000000000000013214775673730022300 xustar0030 mtime=1744271320.681543913 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y3_choose_function_invalid.t0000644000175000001440000000225714775673730023060 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( 24, 80, undef, undef ); my $command = $^X; my $script = catfile $RealBin, 'Y_choose_function_invalid_arguments.pl'; my @parameters = ( $script ); -r $script or die "$script is NOT readable"; $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; my $expected = ''; my $ret = $exp->expect( 2, [ qr/(?:match(); $result = '' if ! defined $result; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->hard_close(); done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/Y_Data_Test_Arguments.pm0000644000000000000000000000013214775674057021373 xustar0030 mtime=1744271407.795529423 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y_Data_Test_Arguments.pm0000644000175000001440000001075314775674057022153 0ustar00mmusers00000000000000package # hide Y_Data_Test_Arguments; use 5.10.1; use warnings; use strict; sub valid_values { return { beep => [ 0, 1 ], clear_screen => [ 0, 1 ], hide_cursor => [ 0, 1 ], index => [ 0, 1 ], alignment => [ 0, 1, 2 ], layout => [ 0, 1, 2, 3 ], mouse => [ 0, 1 ], order => [ 0, 1 ], page => [ 0, 1 ], # '[ 1-9 ][ 0-9 ]*' keep => [ 1, 2, 100, 999999, undef ], ll => [ 1, 2, 100, 999999, undef ], max_height => [ 1, 2, 100, 999999, undef ], max_width => [ 1, 2, 100, 999999, undef ], # '[ 0-9 ]+' default => [ 0, 1, 2, 100, 999999, undef ], pad => [ 0, 1, 2, 100, 999999, undef ], # '' empty => [ 0, 'Hello' x 50, '', ' ', 'abc', 'world', undef ], prompt => [ 0, 'Hello' x 50, '', ' ', 'abc', 'world', undef ], undef => [ 0, 'Hello' x 50, '', ' ', 'abc', 'world', undef ], # ARRAY int tabs_prompt => [ [ 2, 4 ], [ 8 ], [], undef ], mark => [ [ 0, 1, 2, 100, 999999 ], [ 1 ], undef ], no_spacebar => [ [ 0, 1, 2, 100, 999999 ], [ 1 ], undef ], }; } sub mixed_options_1 { return { beep => 0, clear_screen => undef, hide_cursor => 1, index => 0, alignment => 0, layout => 0, mouse => 0, order => 1, page => 0, keep => 1, ll => 1, max_height => 19, max_width => 19, default => 9, pad => 3, empty => '', prompt => '', undef => '', tabs_prompt => [ 1 ], no_spacebar => [ 0 ], mark => [ 3, 4 ] }; } sub mixed_options_2 { return { mark => [ 0 ], no_spacebar => [ 11, 0, 8 ], tabs_prompt => [ 1, 1 ], undef => '', prompt => 'prompt_line', empty => '', pad => 3, default => 9, max_width => 19, max_height => 119, ll => 15, keep => 1, page => 1, order => 1, mouse => 0, layout => 3, alignment => 0, index => 0, hide_cursor => 1, clear_screen => undef, beep => 0 }; } ################################################################################################## sub invalid_values { my @invalid = ( -1, 2, 2 .. 10, 999999, '01', '', 'a', { 1, 1 }, [ 1 ], [ 2 ] ); return{ beep => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], clear_screen => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], hide_cursor => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], index => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], alignment => [ grep { ! /^[ 0 1 2 ]\z/x } @invalid ], layout => [ grep { ! /^[ 0 1 2 3 ]\z/x } @invalid ], mouse => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], order => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], page => [ grep { ! /^[ 0 1 ]\z/x } @invalid ], keep => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], ll => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], max_height => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], max_width => [ grep { ! /^[ 1-9 ][ 0-9 ]*\z/x } @invalid ], default => [ grep { ! /^[ 0-9 ]+\z/x } @invalid ], pad => [ grep { ! /^[ 0-9 ]+\z/x } @invalid ], # '' empty => [ { 1, 1 }, [ 1 ], {}, [], [ 2 ] ], prompt => [ { 1, 1 }, [ 1 ], {}, [], [ 2 ] ], undef => [ { 1, 1 }, [ 1 ], {}, [], [ 2 ] ], # ARRAY max 2 int tabs_prompt => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 1, 2, 'k', ], [ 'a', 'b' ], [ -3, -4 ] ], # ARRAY int mark => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 'a', 'b' ], [ -3, -4 ] ], no_spacebar => [ -2, -1, 0, 1, '', 'a', { 1, 1 }, {}, [ 'a', 'b' ], [ -3, -4 ] ], }; } sub mixed_invalid_1 { return { beep => -1, clear_screen => 2, hide_cursor => 3, index => 4, alignment => '@', layout => 5, mouse => {}, order => 1, page => 0, keep => -1, ll => -1, max_height => 0, max_width => 0, default => [], pad => 'a', empty => [], prompt => {}, undef => [], tabs_prompt => 4, no_spacebar => 4, mark => 'o' }; } sub mixed_invalid_2 { return { mark => '', no_spacebar => 'a', tabs_prompt => 'b', undef => [], prompt => {}, empty => {}, pad => 'd', default => 'e', max_width => -1, max_height => -2, ll => -4, keep => -5, page => -6, order => -7, mouse => 'k', layout => 'e', alignment => [], index => {}, hide_cursor => -1, clear_screen => [], beep => 10 }; } 1; __END__ Term-Choose-1.774/xt/Expect/PaxHeaders/Y_choose_method_invalid_arguments.pl0000644000000000000000000000013214775674062024104 xustar0030 mtime=1744271410.783459629 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y_choose_method_invalid_arguments.pl0000755000175000001440000000254514775674062024667 0ustar00mmusers00000000000000#!/usr/bin/env perl use 5.10.1; use warnings; use strict; use Term::Choose; use FindBin qw( $RealBin ); use lib $RealBin; use Y_Data_Test_Arguments; my $new = Term::Choose->new(); eval { $new->choose( ); 1 } and die '$new->choose();'; eval { $new->choose( undef ); 1 } and die '$new->choose( undef );'; eval { $new->choose( {} ); 1 } and die '$new->choose( {} );'; eval { $new->choose( undef, {} ); 1 } and die '$new->choose( undef, {} );'; eval { $new->choose( 'a' ); 1 } and die '$new->choose( "a" );'; eval { $new->choose( 1, {} ); 1 } and die '$new->choose( 1, {} );'; eval { $new->choose( [], [] ); 1 } and die '$new->choose( [], [] );'; eval { $new->choose( [], 'b' ); 1 } and die '$new->choose( [], "b" );'; eval { $new->choose( [], { hello => 1, world => 2 } ); 1 } and die '$new->choose( [], { hello => 1, world => 2 } );'; my $valid_values = Y_Data_Test_Arguments::invalid_values(); for my $opt ( sort keys %$valid_values ) { for my $val ( @{$valid_values->{$opt}} ) { eval { $new->choose( [], { $opt => $val } ); 1 } and die "\$new->choose( { $opt => $val } );"; } } eval { $new->choose( [], Y_Data_Test_Arguments::mixed_invalid_1() ); 1 } and die '$new->choose( >>> );'; eval { $new->choose( [], Y_Data_Test_Arguments::mixed_invalid_2() ); 1 } and die '$new->choose( <<< );'; print "\n"; Term-Choose-1.774/xt/Expect/PaxHeaders/Y_choose_function_arguments.pl0000644000000000000000000000013214775674062022743 xustar0030 mtime=1744271410.783459629 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y_choose_function_arguments.pl0000755000175000001440000000103414775674062023516 0ustar00mmusers00000000000000#!/usr/bin/env perl use 5.10.1; use warnings; use strict; use Term::Choose qw( choose ); use FindBin qw( $RealBin ); use lib $RealBin; use Y_Data_Test_Arguments; choose( [] ); choose( [], {} ); my $valid_values = Y_Data_Test_Arguments::valid_values(); for my $opt ( sort keys %$valid_values ) { for my $val ( @{$valid_values->{$opt}}, undef ) { choose( [], { $opt => $val } ); } } choose( [], Y_Data_Test_Arguments::mixed_options_1() ); choose( [], Y_Data_Test_Arguments::mixed_options_2() ); print "\n"; Term-Choose-1.774/xt/Expect/PaxHeaders/Y3_choose_method.t0000644000000000000000000000013214775673730020225 xustar0030 mtime=1744271320.685543821 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y3_choose_method.t0000644000175000001440000000222614775673730021001 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( 24, 80, undef, undef ); my $command = $^X; my $script = catfile $RealBin, 'Y_choose_method_arguments.pl'; my @parameters = ( $script ); -r $script or die "$script is NOT readable"; $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; my $expected = ''; my $ret = $exp->expect( 2, [ qr/.+/ ] ); ok( $ret, 'matched something' ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->hard_close(); done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/Y3_choose_function.t0000644000000000000000000000013214775673730020572 xustar0030 mtime=1744271320.685543821 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y3_choose_function.t0000644000175000001440000000224614775673730021350 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( 24, 80, undef, undef ); my $command = $^X; my $script = catfile $RealBin, 'Y_choose_function_arguments.pl'; my @parameters = ( $script ); -r $script or die "$script is NOT readable"; $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; my $expected = ''; my $ret = $exp->expect( 2, [ qr/(?:match(); $result = '' if ! defined $result; ok( $result =~ $expected, "expected: '$expected', got: '$result'" ); $exp->hard_close(); done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/00_get_key_linux.t0000644000000000000000000000013214775673730020177 xustar0030 mtime=1744271320.681543913 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/00_get_key_linux.t0000644000175000001440000000536514775673730020762 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => "Expect required for $0."; } eval "use Term::ReadKey"; if ( $@ ) { plan skip_all => $@; } use Term::Choose::Constants qw( :all ); my $script = catfile $RealBin, 'get_key_linux.pl'; eval { my $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->slave->set_winsize( 24, 80, undef, undef ); -r $script or die "$script is NOT readable $!"; $exp->spawn( $script ) or die "Spawn '$script' NOT ok $!"; 1; } or plan skip_all => $@; for my $char ( qw( h j k l q ), ' ', "\t" ) { my $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->slave->set_winsize( 24, 80, undef, undef ); $exp->spawn( $script ); $exp->send( $char ); my $expected = '<' . ord( $char ) . '>'; my $ret = $exp->expect( 3, [ qr/...+/ ] ); ok( $ret, 'matched something' ); my $result = $exp->match() // ''; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->soft_close(); } for my $char ( "\cA", "\cB", "\cC", "\cD", "\cE", "\cF", "\cH", "\cI", "\c@" ) { my $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->slave->set_winsize( 24, 80, undef, undef ); $exp->spawn( $script ); $exp->send( $char ); my $expected = '<' . ord( $char ) . '>'; my $ret = $exp->expect( 3, [ qr/...+/ ] ); ok( $ret, 'matched something' ); my $result = $exp->match() // ''; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->soft_close(); } my $array = [ [ [ "\e[A", "\eOA" ], VK_UP ], [ [ "\e[B", "\eOB" ], VK_DOWN ], [ [ "\e[C", "\eOC" ], VK_RIGHT ], [ [ "\e[D", "\eOD" ], VK_LEFT ], [ [ "\e[F", "\eOF" ], VK_END ], [ [ "\e[H", "\eOH" ], VK_HOME ], [ [ "\e[Z", "\eOZ" ], KEY_BTAB ], [ [ "\e[5~" ], VK_PAGE_UP ], [ [ "\e[6~" ], VK_PAGE_DOWN ], ]; for my $elem ( @$array ) { for my $seq ( @{$elem->[0]} ) { my $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->slave->set_winsize( 24, 80, undef, undef ); $exp->spawn( $script ); $exp->send( $seq ); my $expected = '<' . $elem->[1] . '>'; my $ret = $exp->expect( 3, [ qr/...+/ ] ); ok( $ret, 'matched something' ); my $result = $exp->match() // ''; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->soft_close(); } } done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/Z0_clone_win.t0000644000000000000000000000013214775673730017360 xustar0030 mtime=1744271320.689543729 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Z0_clone_win.t0000644000175000001440000000255114775673730020135 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } use lib $RealBin; use Z_Data_Test_Choose; my $type = 'simple'; my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->clone_winsize_from( \*STDIN ); my $command = $^X; my $script = catfile $RealBin, 'Z_choose.pl'; my @parameters = ( $script, $type ); -r $script or die "$script is NOT readable"; $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; my $a_ref = Z_Data_Test_Choose::return_test_data( $type ); my $ref = shift @$a_ref; my $ret = $exp->expect( 2, [ qr/Your choice: .*/ ] ); my $expected = $ref->{expected}; $exp->send( "\r" ); $ret = $exp->expect( 2, [ qr/<.+>/ ] ); ok( $ret, 'matched something' ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $result eq $expected, qq[expected: "$expected", got: "$result"] ); $exp->hard_close(); done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/Y_choose_function_invalid_arguments.pl0000644000000000000000000000013214775674062024451 xustar0030 mtime=1744271410.783459629 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y_choose_function_invalid_arguments.pl0000755000175000001440000000230114775674062025222 0ustar00mmusers00000000000000#!/usr/bin/env perl use 5.10.1; use warnings; use strict; use Term::Choose qw( choose ); use FindBin qw( $RealBin ); use lib $RealBin; use Y_Data_Test_Arguments; eval { choose( ); 1 } and die 'choose();'; eval { choose( undef ); 1 } and die 'choose( undef );'; eval { choose( {} ); 1 } and die 'choose( {} );'; eval { choose( undef, {} ); 1 } and die 'choose( undef, {} );'; eval { choose( 'a' ); 1 } and die 'choose( "a" );'; eval { choose( 1, {} ); 1 } and die 'choose( 1, {} );'; eval { choose( [], [] ); 1 } and die 'choose( [], [] );'; eval { choose( [], 'b' ); 1 } and die 'choose( [], "b" );'; eval { choose( [], { hello => 1, world => 2 } ); 1 } and die 'choose( [], { hello => 1, world => 2 } );'; my $valid_values = Y_Data_Test_Arguments::invalid_values(); for my $opt ( sort keys %$valid_values ) { for my $val ( @{$valid_values->{$opt}} ) { eval { choose( [], { $opt => $val } ); 1 } and die "choose( { $opt => $val } );"; } } eval { choose( [], Y_Data_Test_Arguments::mixed_invalid_1() ); 1 } and die 'choose( >>> );'; eval { choose( [], Y_Data_Test_Arguments::mixed_invalid_2() ); 1 } and die 'choose( <<< );'; print "\n"; Term-Choose-1.774/xt/Expect/PaxHeaders/Z_choose.pl0000644000000000000000000000013214775674062016752 xustar0030 mtime=1744271410.783459629 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Z_choose.pl0000755000175000001440000000063614775674062017534 0ustar00mmusers00000000000000#!/usr/bin/env perl use warnings; use strict; use 5.10.1; use Term::Choose qw( choose ); use FindBin qw( $RealBin ); use lib $RealBin; use Z_Data_Test_Choose; my $type = shift; my $a_ref = Z_Data_Test_Choose::return_test_data( $type ); for my $ref ( @$a_ref ) { my $opt = $ref->{options}; my $list = $ref->{list}; my @choice = choose( $list, $opt ); print "<@choice>\n"; } Term-Choose-1.774/xt/Expect/PaxHeaders/get_key_linux.pl0000644000000000000000000000013214775674062020047 xustar0030 mtime=1744271410.783459629 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/get_key_linux.pl0000755000175000001440000000026114775674062020623 0ustar00mmusers00000000000000#!/usr/bin/env perl use warnings; use strict; use 5.10.1; use Term::Choose::Linux; my $linux = Term::Choose::Linux->new(); my $key = $linux->__get_key_OS( 0 ); say "<$key>"; Term-Choose-1.774/xt/Expect/PaxHeaders/Y3_choose_method_invalid.t0000644000000000000000000000013214775673730021733 xustar0030 mtime=1744271320.685543821 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y3_choose_method_invalid.t0000644000175000001440000000223514775673730022507 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( 24, 80, undef, undef ); my $command = $^X; my $script = catfile $RealBin, 'Y_choose_method_invalid_arguments.pl'; my @parameters = ( $script ); -r $script or die "$script is NOT readable"; $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; my $expected = ''; my $ret = $exp->expect( 2, [ qr/.+/ ] ); ok( $ret, 'matched something' ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->hard_close(); done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/Y_choose_method_arguments.pl0000644000000000000000000000013214775674062022376 xustar0030 mtime=1744271410.783459629 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Y_choose_method_arguments.pl0000755000175000001440000000111514775674062023151 0ustar00mmusers00000000000000#!/usr/bin/env perl use 5.10.1; use warnings; use strict; use Term::Choose; use FindBin qw( $RealBin ); use lib $RealBin; use Y_Data_Test_Arguments; my $new = Term::Choose->new(); $new->choose( [] ); $new->choose( [], {} ); my $valid_values = Y_Data_Test_Arguments::valid_values(); for my $opt ( sort keys %$valid_values ) { for my $val ( @{$valid_values->{$opt}}, undef ) { $new->choose( [], { $opt => $val } ); } } $new->choose( [], Y_Data_Test_Arguments::mixed_options_1() ); $new->choose( [], Y_Data_Test_Arguments::mixed_options_2() ); print "\n"; Term-Choose-1.774/xt/Expect/PaxHeaders/Z1_hide_cursor.t0000644000000000000000000000013214775673730017712 xustar0030 mtime=1744271320.689543729 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Z1_hide_cursor.t0000644000175000001440000000265014775673730020467 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } use lib $RealBin; use Z_Data_Test_Choose; my $type = 'hide_cursor'; my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( 24, 80, undef, undef ); my $command = $^X; my $script = catfile $RealBin, 'Z_choose.pl'; my @parameters = ( $script, $type ); -r $script or die "$script is NOT readable"; $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; my $a_ref = Z_Data_Test_Choose::return_test_data( $type ); my $ref = shift @$a_ref; my $expected = $ref->{expected}; my $ret = $exp->expect( 2, [ 'Your choice: ' => sub { $exp->send( "\r" ); 'exp_continue'; } ], [ $expected => sub {} ], ); ok( $ret, 'matched something' ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $result eq $expected, "expected: '$expected', got: '$result'" ); $exp->hard_close(); done_testing(); Term-Choose-1.774/xt/Expect/PaxHeaders/Z_Data_Test_Choose.pm0000644000000000000000000000013214775674057020647 xustar0030 mtime=1744271407.795529423 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Z_Data_Test_Choose.pm0000644000175000001440000004266114775674057021432 0ustar00mmusers00000000000000package # hide Z_Data_Test_Choose; use 5.10.1; use warnings; use strict; sub key_seq { return { CONTROL_at => "\x{00}", CONTROL_Space => "\x{00}", CONTROL_C => "\x{03}", CONTROL_D => "\x{04}", CONTROL_H => "\x{08}", BTAB => "\x{08}", BSPACE => "\x{7f}", BTAB_Z => "\e[Z", BTAB_OZ => "\eOZ", CONTROL_I => "\x{09}", TAB => "\x{09}", CONTROL_M => "\x{0d}", ENTER => "\x{0d}", SPACE => "\x{20}", Key_q => "\x{71}", Key_k => "\x{6b}", UP => "\e[A", UP_O => "\eOA", Key_j => "\x{6a}", DOWN => "\e[B", DOWN_O => "\eOB", Key_l => "\x{6c}", RIGHT => "\e[C", RIGHT_O => "\eOC", Key_h => "\x{68}", LEFT => "\e[D", LEFT_O => "\eOD", CONTROL_B => "\x{02}", PAGE_UP => "\e[5~", CONTROL_F => "\x{06}", PAGE_DOWN => "\e[6~", CONTROL_A => "\x{01}", HOME => "\e[H", CONTROL_E => "\x{05}", END => "\e[F", } } my $simple = [ { list => [ 2 ], used_keys => [ qw( ENTER ) ], expected => "<2>", options => { prompt => 'Your choice: ', order => 0, layout => 0, hide_cursor => 0, include_highlighted => 1 }, }, ]; my $hide_cursor = [ { list => [ 1 .. 199 ], used_keys => [ qw( ENTER ) ], expected => "<1>", options => { prompt => 'Your choice: ', order => 0, layout => 0, hide_cursor => 1, clear_screen => 0, include_highlighted => 1 } }, ]; # CONTROL_C # KEY_q CONTROL_D my $k_list = [ 0 .. 1999 ]; my $k_options = { default => 1007, order => 0, layout => 0, hide_cursor => 0, include_highlighted => 1 }; my $seq_test = [ #{ list => $k_list, used_keys => [ qw( ENTER ) ], expected => "<1007>", options => $k_options, }, #{ list => $k_list, used_keys => [ qw( CONTROL_M ) ], expected => "<1007>", options => $k_options, }, { list => $k_list, used_keys => [ qw( RIGHT ) ], expected => "<1008>", options => $k_options, }, { list => $k_list, used_keys => [ qw( RIGHT_O ) ], expected => "<1008>", options => $k_options, }, { list => $k_list, used_keys => [ qw( Key_l ) ], expected => "<1008>", options => $k_options, }, { list => $k_list, used_keys => [ qw( LEFT ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( LEFT_O ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( Key_h ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( DOWN ) ], expected => "<1020>", options => $k_options, }, { list => $k_list, used_keys => [ qw( DOWN_O ) ], expected => "<1020>", options => $k_options, }, { list => $k_list, used_keys => [ qw( Key_j ) ], expected => "<1020>", options => $k_options, }, { list => $k_list, used_keys => [ qw( UP ) ], expected => "<994>", options => $k_options, }, { list => $k_list, used_keys => [ qw( UP_O ) ], expected => "<994>", options => $k_options, }, { list => $k_list, used_keys => [ qw( Key_k ) ], expected => "<994>", options => $k_options, }, { list => $k_list, used_keys => [ qw( TAB ) ], expected => "<1008>", options => $k_options, }, { list => $k_list, used_keys => [ qw( CONTROL_I ) ], expected => "<1008>", options => $k_options, }, { list => $k_list, used_keys => [ qw( BSPACE ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( CONTROL_H ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( BTAB ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( BTAB_Z ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( BTAB_OZ ) ], expected => "<1006>", options => $k_options, }, { list => $k_list, used_keys => [ qw( HOME ) ], expected => "<0>", options => $k_options, }, { list => $k_list, used_keys => [ qw( CONTROL_A ) ], expected => "<0>", options => $k_options, }, { list => $k_list, used_keys => [ qw( END ) ], expected => "<1999>", options => $k_options, }, { list => $k_list, used_keys => [ qw( CONTROL_E ) ], expected => "<1999>", options => $k_options, }, { list => $k_list, used_keys => [ qw( PAGE_DOWN ) ], expected => "<1293>", options => $k_options, }, { list => $k_list, used_keys => [ qw( CONTROL_F ) ], expected => "<1293>", options => $k_options, }, { list => $k_list, used_keys => [ qw( PAGE_UP ) ], expected => "<721>", options => $k_options, }, { list => $k_list, used_keys => [ qw( CONTROL_B ) ], expected => "<721>", options => $k_options, }, { list => $k_list, used_keys => [ qw( SPACE ) ], expected => "<1007>", options => $k_options, }, # { list => $k_list, used_keys => [ qw( CONTROL_Space ) ],expected => "<@{[858..1143]}>", options => $k_options , }, { list => $k_list, used_keys => [ qw( CONTROL_at ) ], expected => "<@$k_list>", options => { %$k_options, default => 0 }, }, ]; ############################################################################################################## my $keys = { long => [ qw( SPACE END SPACE HOME SPACE CONTROL_E PAGE_UP SPACE CONTROL_B CONTROL_B CONTROL_B CONTROL_B CONTROL_B CONTROL_B SPACE TAB TAB TAB TAB TAB TAB TAB TAB TAB TAB DOWN DOWN DOWN SPACE RIGHT DOWN_O DOWN_O Key_j SPACE LEFT_O LEFT_O Key_h Key_h SPACE PAGE_DOWN CONTROL_F CONTROL_F SPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE CONTROL_H CONTROL_H CONTROL_H CONTROL_H CONTROL_H BTAB BTAB BTAB_Z BTAB_OZ SPACE UP UP UP UP_O UP_O UP_O Key_k Key_k Key_k SPACE RIGHT_O CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I SPACE PAGE_DOWN PAGE_DOWN PAGE_DOWN PAGE_UP PAGE_UP PAGE_UP PAGE_UP PAGE_UP PAGE_UP SPACE END LEFT ENTER ) ], short => [ qw( SPACE END SPACE HOME SPACE CONTROL_E PAGE_UP SPACE SPACE TAB TAB TAB TAB TAB TAB TAB TAB TAB TAB SPACE RIGHT SPACE LEFT_O LEFT_O Key_h Key_h SPACE PAGE_DOWN SPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE BSPACE CONTROL_H CONTROL_H CONTROL_H CONTROL_H CONTROL_H BTAB BTAB BTAB_Z BTAB_OZ SPACE UP UP UP_O UP_O Key_k Key_k SPACE DOWN DOWN_O Key_j SPACE RIGHT_O CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I CONTROL_I SPACE END LEFT ENTER ) ], }; my $list = { long => [ 0 .. 1999 ], short => [ 0 .. 99 ], long_test_index => [ map { s/^\d/chr( $& + 97 )/e; $_ } 0 .. 1999 ], short_test_index => [ map { s/^\d/chr( $& + 97 )/e; $_ } 0 .. 99 ], ll => [ ( "In" . '.' x 7, "scalar" . '.' x 3, "context" . '.' x 2, "returns" . '.' x 2, "the" . '.' x 6, "number" . '.' x 3, "of" . '.' x 7, "elements" . '.' x 1, "so" . '.' x 7, "generated" , "hello" . '.' x 4, "world" . '.' x 4, "12345678" . '.' x 1, "The" . '.' x 6, "black" . '.' x 4, "cat" . '.' x 6, "jumped" . '.' x 3, "from" . '.' x 5, "the" . '.' x 6, "green" . '.' x 4, "tree" . '.' x 5, "abcdefghi" , ) x 2 ], }; my $options = [ { max_height => undef, max_width => undef, layout => 0, include_highlighted => 1 }, { max_height => 20, max_width => undef, layout => 0, include_highlighted => 1 }, { max_height => undef, max_width => undef, layout => 1, include_highlighted => 1 }, { max_height => 20, max_width => undef, layout => 3, include_highlighted => 1 }, { max_height => undef, max_width => 61, layout => 2, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 0, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 1, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 2, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 3, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 1, prompt => 'Your choice: ', page => 0, pad => 3, order => 1, alignment => 2, keep => 8, clear_screen => 1, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 1, prompt => 'Your choice: ' x 100, page => 0, pad => 3, order => 1, alignment => 2, keep => 8, clear_screen => 1, include_highlighted => 1 }, { prompt => 'abc 12345678 def' x 50, default => 10, empty =>' ', undef => '--', beep => 1, no_spacebar => [ 11 .. 2000 ], tabs_prompt => [ 0, 4 ], keep => 16, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 0, mark => [ 0, 10, 100 ], include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 1, mark => [ 0, 10, 100 ], index => 1, include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 2, mark => [ 0, 10, 35, 100, 1979 ], no_spacebar => [ 35, 1066, 1979 ], include_highlighted => 1 }, { max_height => 20, max_width => 60, layout => 3, mark => [ 0, 10, 100 ], include_highlighted => 1 }, ]; my $c_opt; $c_opt = 0; my $long = [ { list => $list->{long}, used_keys => $keys->{long}, expected => "<83 92 951 1017 1410 1558 1567 1624 1846 1867 1977 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<69 78 943 1003 1402 1550 1559 1610 1846 1859 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<83 92 951 1017 1410 1558 1567 1624 1846 1867 1977 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<1859 1869 1872 1907 1916 1929 1935 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<1052 1118 1307 1316 1799 1843 1845 1849 1852 1909 1977 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<1066 1126 1315 1324 1799 1857 1859 1863 1866 1917 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<1066 1126 1315 1324 1799 1857 1859 1863 1866 1917 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<1066 1126 1315 1324 1799 1857 1859 1863 1866 1917 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<1859 1869 1872 1907 1916 1929 1935 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<86 89 149 312 748 808 1777 1859 1915 1924 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<170 173 197 396 832 856 1777 1943 1963 1972 1991 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<0 10 1846>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<0 10 100 1066 1126 1315 1324 1799 1857 1859 1863 1866 1917 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long_test_index}, used_keys => $keys->{long}, expected => "<0 10 100 1066 1126 1315 1324 1799 1857 1859 1863 1866 1917 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<0 10 35 100 1126 1315 1324 1799 1857 1859 1863 1866 1917 1979 1999>", options => $options->[$c_opt++], }, { list => $list->{long}, used_keys => $keys->{long}, expected => "<0 10 100 1859 1869 1872 1907 1916 1929 1935 1979 1999>", options => $options->[$c_opt++], }, ]; $c_opt = 0; my $short = [ { list => $list->{short}, used_keys => $keys->{short}, expected => "<80 94>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<80 94>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<7 10 12 67 93 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<64 67 70 89 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<35 38 41 69 85 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<7 10 12 67 93 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<41 44 47 50 91 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<35 38 41 69 85 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<64 67 70 89 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<61 64 67 89 96 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<41 44 47 50 91 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<0 7 93>", expected_w81 => "<0 10 93>", # "<0 7 93>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<0 7 12 67 93 99>", options => $options->[$c_opt++], }, { list => $list->{short_test_index}, used_keys => $keys->{short}, expected => "<0 10 41 44 47 50 91 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<0 10 35 38 41 69 85 99>", options => $options->[$c_opt++], }, { list => $list->{short}, used_keys => $keys->{short}, expected => "<0 10 64 67 70 89 99>", options => $options->[$c_opt++], }, ]; my $option_ll = [ { list => $list->{ll}, used_keys => [ ( 'DOWN' ) x 3, 'SPACE', ( 'RIGHT' ) x 3, 'SPACE', 'HOME', 'ENTER' ], expected => "<0 3 30>", options => { ll => 9, layout => 1, include_highlighted => 1 } }, { list => $list->{ll}, used_keys => [ 'END', 'SPACE', 'PAGE_UP', 'SPACE', ( 'UP' ) x 12, 'LEFT', 'ENTER' ], expected => "<9 21 43>", options => { ll => 9, layout => 3, include_highlighted => 1 } }, ]; sub return_test_data { my $type = shift; if ( $type eq 'simple' ) { return $simple; } elsif ( $type eq 'hide_cursor' ) { return $hide_cursor; } elsif ( $type eq 'seq_test' ) { return $seq_test; } elsif ( $type eq 'long' ) { return $long; } elsif ( $type eq 'short' ) { return $short; } elsif ( $type eq 'option_ll' ) { return $option_ll; } } 1; __END__ Term-Choose-1.774/xt/Expect/PaxHeaders/Z2_choose.t0000644000000000000000000000013214775673730016665 xustar0030 mtime=1744271320.689543729 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/Expect/Z2_choose.t0000644000175000001440000000727614775673730017453 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More; use FindBin qw( $RealBin ); use File::Spec::Functions qw( catfile ); BEGIN { if ( $^O eq 'MSWin32' ) { plan skip_all => "MSWin32: Expect not available."; } #if ( ! $ENV{TESTS_USING_EXPECT_OK} ) { # plan skip_all => "Environment variable 'TESTS_USING_EXPECT_OK' not enabled."; #} } eval "use Expect"; if ( $@ ) { plan skip_all => $@; } use lib $RealBin; use Z_Data_Test_Choose; my $command = $^X; my $timeout = 5; my $choose_pl = catfile $RealBin, 'Z_choose.pl'; my $key = Z_Data_Test_Choose::key_seq(); { my $type = 'seq_test'; my $rows = 24; my $cols = 80; my @parameters = ( $choose_pl, $type ); my $exp; eval { $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( $rows, $cols, undef, undef ); $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; 1; } or plan skip_all => $@; subtest 'seq_test', sub { my $a_ref = Z_Data_Test_Choose::return_test_data( $type ); for my $ref ( @$a_ref ) { my $pressed_keys = $ref->{used_keys}; my $expected = $ref->{expected}; $exp->send( @{$key}{@$pressed_keys}, $key->{ENTER} ); my $ret = $exp->expect( $timeout, [ qr/<.+>/ ] ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $expected eq $result, "'@{$ref->{used_keys}}' OK: " . sprintf( "%10.10s - %10.10s", $expected, $result ) ); } $exp->hard_close(); done_testing(); } } my @types = ( qw( long short option_ll ) ); my $rows = 24; my $cols = 80; for my $type ( @types ) { my $a_ref = Z_Data_Test_Choose::return_test_data( $type ); my @parameters = ( $choose_pl, $type ); subtest 'choose ' . $type, sub { my $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( $rows, $cols, undef, undef ); $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; for my $ref ( @$a_ref ) { my $pressed_keys = $ref->{used_keys}; my $expected = $ref->{expected}; $exp->send( @{$key}{@$pressed_keys} ); my $ret = $exp->expect( $timeout, [ qr/<.+>/ ] ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $ret, 'matched something' ); ok( $result eq $expected, "expected: '$expected', got: '$result'" ); } $exp->hard_close(); done_testing(); }; } $rows = 24; $cols = 81; for my $type ( @types ) { my $a_ref = Z_Data_Test_Choose::return_test_data( $type ); my @parameters = ( $choose_pl, $type ); subtest 'choose ' . $type, sub { my $exp = Expect->new(); $exp->raw_pty( 1 ); $exp->log_stdout( 0 ); $exp->slave->set_winsize( $rows, $cols, undef, undef ); $exp->spawn( $command, @parameters ) or die "Spawn '$command @parameters' NOT ok $!"; for my $ref ( @$a_ref ) { my $pressed_keys = $ref->{used_keys}; my $expected = defined $ref->{expected_w81} ? $ref->{expected_w81} : $ref->{expected}; $exp->send( @{$key}{@$pressed_keys} ); my $ret = $exp->expect( $timeout, [ qr/<.+>/ ] ); my $result = $exp->match(); $result = '' if ! defined $result; ok( $ret, 'matched something' ); ok( $result eq $expected, "expected: '$expected', got: '$result'" ); } $exp->hard_close(); done_testing(); }; } done_testing(); Term-Choose-1.774/xt/PaxHeaders/vars.t0000644000000000000000000000013215003353233014527 xustar0030 mtime=1745737371.165341528 30 atime=1745737371.209340556 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/vars.t0000644000175000001440000000124415003353233015302 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::Vars tests => $^O eq 'MSWin32'? 13 : 12; vars_ok( 'lib/Term/Choose/Screen.pm', ignore_vars => [ '$size' ] ); my @modules = qw( lib/Term/Choose.pm lib/Term/Choose/Constants.pm lib/Term/Choose/LineFold.pm lib/Term/Choose/LineFold/PP.pm lib/Term/Choose/LineFold/PP/CharWidthAmbiguousWide.pm lib/Term/Choose/LineFold/PP/CharWidthDefault.pm lib/Term/Choose/Linux.pm lib/Term/Choose/Opt/Mouse.pm lib/Term/Choose/Opt/Search.pm lib/Term/Choose/Opt/SkipItems.pm lib/Term/Choose/ValidateOptions.pm ); if ( $^O eq 'MSWin32' ) { push @modules, 'lib/Term/Choose/Win32.pm'; } for my $module ( @modules ) { vars_ok( $module ); } Term-Choose-1.774/xt/PaxHeaders/whitespaces.t0000644000000000000000000000013214775673705016123 xustar0030 mtime=1744271301.273991645 30 atime=1745740703.636077912 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/whitespaces.t0000644000175000001440000000037714775673705016704 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::Whitespaces { dirs => [ 'lib', 't', 'xt', 'example', ], files => [ 'README', 'Makefile.PL', 'Build.PL', 'Changes', ], }; Term-Choose-1.774/xt/PaxHeaders/perlcriticrc0000644000000000000000000000007412626746534016026 xustar0030 atime=1745740703.640077815 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/perlcriticrc0000644000175000001440000000027112626746534016573 0ustar00mmusers00000000000000severity = 5 verbose = 8 [InputOutput::RequireCheckedSyscalls] functions = :builtins exclude_functions = print [TestingAndDebugging::ProhibitNoWarnings] allow = utf8 uninitialized Term-Choose-1.774/xt/PaxHeaders/01_option.t0000644000000000000000000000013115003222336015362 xustar0030 mtime=1745691870.039290912 29 atime=1745691908.23838152 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/01_option.t0000644000175000001440000001117615003222336016143 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use utf8; use Test::More; use Test::Fatal; use Term::ReadKey; ## use lib 'lib'; use Term::Choose qw( choose ); no warnings 'redefine'; sub Term::Choose::__get_key { sleep 0.01; return 0x0d }; close STDIN or plan skip_all => "Close STDIN $!"; my $stdin = "eingabe\n"; open STDIN, "<", \$stdin or plan skip_all => "STDIN $!"; close STDOUT or plan skip_all => "Close STDOUT $!"; close STDERR or plan skip_all => "Close STDERR $!"; my ( $tmp_stdout, $tmp_stderr ); open STDOUT, '>', \$tmp_stdout or plan skip_all => "STDOUT $!"; open STDERR, '>', \$tmp_stderr or plan skip_all => "STDERR $!"; my $choices = [ '', 0, undef, 1, 2, 3, 'aa' .. 'zz', '☻☮☺', "\x{263a}\x{263b}", '한글', 'æða' ]; my $d; my $int = { beep => [ 0, 1 ], clear_screen => [ 0, 1 ], codepage_mapping => [ 0, 1 ], hide_cursor => [ 0, 1 ], index => [ 0, 1 ], mouse => [ 0, 1 ], order => [ 0, 1 ], page => [ 0, 1 ], alignment => [ 0, 1, 2 ], color => [ 0, 1, 2 ], search => [ 0, 1, 2 ], include_highlighted => [ 0, 1, 2 ], layout => [ 0, 1, 2 ], }; my $f; for my $opt ( sort keys %$int ) { for my $val ( @{$int->{$opt}}, undef ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } my $one_or_greater = { keep => '[ 1-9 ][ 0-9 ]*', ll => '[ 1-9 ][ 0-9 ]*', max_cols => '[ 1-9 ][ 0-9 ]*', max_height => '[ 1-9 ][ 0-9 ]*', max_width => '[ 1-9 ][ 0-9 ]*', }; my @val_one_or_greater = ( 1, 2, 100, 999999, undef ); for my $opt ( sort keys %$one_or_greater ) { for my $val ( @val_one_or_greater ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } my $zero_or_greater = { default => '[ 0-9 ]+', pad => '[ 0-9 ]+', }; my @val_zero_or_greater = ( 0, 1, 2, 100, 999999, undef ); for my $opt ( sort keys %$zero_or_greater ) { for my $val ( @val_zero_or_greater ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } my $string = { empty => '', footer => '', info => '', prompt => '', undef => '', busy_string => '', }; my @val_string = ( 0, 'Hello' x 50, '', ' ', '☻☮☺', "\x{263a}\x{263b}", '한글', undef, 'æða' ); for my $opt ( sort keys %$string ) { for my $val ( @val_string ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } my $tabs = { tabs_info => 'Array_Int', tabs_prompt => 'Array_Int', }; my @val_tabs = ( [ 2, 4 ], [ 8 ], [], undef ); for my $opt ( sort keys %$tabs ) { for my $val ( @val_tabs ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } my $list_opt = { mark => 'Array_Int', meta_items => 'Array_Int', no_spacebar => 'Array_Int', }; my @val_list_opt = ( [ 0, 1, 2, 100, 999999 ], [ 1 ], undef ); for my $opt ( sort keys %$list_opt ) { for my $val ( @val_list_opt ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } my $regex_opt = { skip_items => 'Regexp', }; my @val_regex_opt = ( qr/^\s+\z/, qr/abc/ ); for my $opt ( sort keys %$regex_opt ) { for my $val ( @val_regex_opt ) { ok( ! defined( $f = exception { $d = choose( $choices, { $opt => $val } ) } ), ( "|$f|:" // 'OK' ) . " $opt => $val" ); } } ok( ! defined( exception { $d = choose( $choices, { beep => 0, clear_screen => undef, hide_cursor => 1, index => 0, alignment => 0, layout => 0, mouse => 0, order => 1, page => 0, keep => 1, ll => 1, max_height => 19, max_width => 19, default => 9, skip_items => qr/^\d+\z/, pad => 3, empty => '', prompt => '', undef => '', tabs_prompt => [ 1 ], no_spacebar => [ 0 ], info => 'hello' } ) } ) ); ok( ! defined( exception { $d = choose( [ 'aaa' .. 'zzz' ], { no_spacebar => [ 11, 0, 8 ], tabs_prompt => [ 1, 1 ], undef => '', prompt => 'prompt_line', empty => '', pad => 3, default => 9, max_width => 19, max_height => 119, ll => 15, keep => 1, page => 1, order => 1, skip_items => qr/^\d+\z/, mouse => 0, layout => 2, alignment => 0, index => 0, hide_cursor => 1, clear_screen => undef, beep => 0 } ) } ) ); done_testing(); __DATA__ Term-Choose-1.774/xt/PaxHeaders/synopsis.t0000644000000000000000000000013214775673705015473 xustar0030 mtime=1744271301.273991645 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/synopsis.t0000644000175000001440000000016114775673705016243 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::Synopsis; use lib 'lib'; use Term::Choose; all_synopsis_ok(); Term-Choose-1.774/xt/PaxHeaders/perl_minimum_version.t0000644000000000000000000000013215003444773020030 xustar0030 mtime=1745766907.474759411 30 atime=1745766908.142747883 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/perl_minimum_version.t0000644000175000001440000000305215003444773020602 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Perl::MinimumVersion; use Perl::Version; use File::Find; use Test::More; my $make_minimum; open my $fh_m, '<', 'Makefile.PL' or die $!; while ( my $line = <$fh_m> ) { if ( $line =~ /^\s*MIN_PERL_VERSION\s*=>\s*'([^']+)',/ ) { my $version = Perl::Version->new( $1 ); my $numified = $version->numify; $make_minimum = $numified; last; } } close $fh_m or die $!; my $pod_minimum; open my $fh_p, '<', 'lib/Term/Choose.pm' or die $!; while ( my $line = <$fh_p> ) { if ( $line =~ /^=head2\s+Perl\s+version/ .. $line =~ /^=head2\s+Modules/ ) { if ( $line =~ /Perl\sversion\s(5\.\d\d?\.\d+)\s/ ) { my $version = Perl::Version->new( $1 ); my $numified = $version->numify; $pod_minimum = $numified; last; } } } close $fh_p or die $!; my @files; for my $dir ( 'lib', 't' ) { find( { wanted => sub { my $file = $File::Find::name; return if ! -f $file; push @files, $file; }, no_chdir => 1, }, $dir ); } for my $file ( @files ) { my $object = Perl::MinimumVersion->new( $file ); my $min_exp_v = $object->minimum_explicit_version; my $version = Perl::Version->new( $min_exp_v ); my $numified = $version->numify; cmp_ok( $make_minimum, '==', $numified, "$make_minimum in Makefile.PL == $numified in $file" ); } cmp_ok( $make_minimum, '==', $pod_minimum, "$make_minimum in Makefile.PL == $pod_minimum in pod" ); done_testing(); Term-Choose-1.774/xt/PaxHeaders/version1.t0000644000000000000000000000013215003206045015320 xustar0030 mtime=1745685541.639091569 30 atime=1745685585.052314532 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/version1.t0000644000175000001440000000033515003206045016073 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use Test::Version qw( version_ok ), { # is_strict => 1, has_version => 1, }; #version_all_ok( 'lib' ); version_ok( 'lib/Term/Choose.pm' ); done_testing; Term-Choose-1.774/xt/PaxHeaders/cntr_choose.t0000644000000000000000000000013115003206601016055 xustar0029 mtime=1745685889.76969395 30 atime=1745685890.505675304 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/cntr_choose.t0000644000175000001440000000267715003206601016644 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use File::Basename qw( basename ); use Test::More; for my $file ( qw( lib/Term/Choose.pm lib/Term/Choose/Constants.pm lib/Term/Choose/LineFold.pm lib/Term/Choose/LineFold/PP.pm lib/Term/Choose/LineFold/PP/CharWidthAmbiguousWide.pm lib/Term/Choose/LineFold/PP/CharWidthDefault.pm lib/Term/Choose/Linux.pm lib/Term/Choose/Opt/Mouse.pm lib/Term/Choose/Opt/Search.pm lib/Term/Choose/Opt/SkipItems.pm lib/Term/Choose/Screen.pm lib/Term/Choose/ValidateOptions.pm lib/Term/Choose/Win32.pm ) ) { my $data_dumper = 0; my $warnings = 0; my $use_lib = 0; my $warn_to_fatal = 0; open my $fh, '<', $file or die $!; while ( my $line = <$fh> ) { if ( $line =~ /^\s*use\s+Data::Dumper/s ) { $data_dumper++; } if ( $line =~ /^\s*use\s+warnings\s+FATAL/s ) { $warnings++; } if ( $line =~ /^\s*use\s+lib\s/s ) { $use_lib++; } if ( $line =~ /__WARN__.+die/s ) { $warn_to_fatal++; } } close $fh; is( $data_dumper, 0, 'OK - Data::Dumper in "' . basename( $file ) . '" disabled.' ); is( $warnings, 0, 'OK - warnings FATAL in "' . basename( $file ) . '" disabled.' ); is( $use_lib, 0, 'OK - no "use lib" in "' . basename( $file ) . '"' ); is( $warn_to_fatal, 0, 'OK - no "warn to fatal" in "' . basename( $file ) . '"' ); } done_testing(); Term-Choose-1.774/xt/PaxHeaders/pod_defaults.t0000644000000000000000000000013214775673705016255 xustar0030 mtime=1744271301.273991645 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/pod_defaults.t0000644000175000001440000000454614775673705017040 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use List::Util qw( any ); my @long = qw( pad empty undef ll default max_cols max_height max_width keep no_spacebar mark footer skip_items margin ); my @simple = qw( alignment layout order clear_screen mouse beep hide_cursor index color codepage_mapping search ); # prompt my @all = ( @long, @simple ); my @skip = qw( info prompt include_highlighted meta_items busy_string page tabs_prompt tabs_info ); plan tests => 2 + scalar @all; my $file = 'lib/Term/Choose.pm'; my $fh; my %option_default; open $fh, '<', $file or die $!; while ( my $line = <$fh> ) { if ( $line =~ /^sub _defaults \{/ .. $line =~ /^\}/ ) { if ( $line =~ m|^\s+#?\s*(\w+)\s+=>\s(\S+),| ) { my $op = $1; next if any { $op eq $_ } @skip; $option_default{$op} = $2; $option_default{$op} =~ s/^undef\z/undefined/; $option_default{$op} =~ s/^["']([^'"]+)["']\z/$1/; } } } close $fh; my %pod_default; my %pod; for my $key ( @all ) { next if any { $key eq $_ } @skip; open $fh, '<', $file or die $!; while ( my $line = <$fh> ) { if ( $line =~ /^=head3\s\Q$key\E/ ... $line =~ /^=head/ ) { #head2 chomp $line; next if $line =~ /^\s*\z/; push @{$pod{$key}}, $line; } } close $fh; } for my $key ( @simple ) { next if any { $key eq $_ } @skip; my $opt; for my $line ( @{$pod{$key}} ) { if ( $line =~ /(\d).*\(default\)/ || $line =~ /(\d) - default/ ) { $pod_default{$key} = $1; last; } } } for my $key ( @long ) { next if any { $key eq $_ } @skip; for my $line ( @{$pod{$key}} ) { if ( $line =~ /default:\s["']([^'"]+)["'](?:\)|\s*)/ ) { $pod_default{$key} = $1; last; } if ( $line =~ /default:\s(\w+)(?:\)|\s*)/ ) { $pod_default{$key} = $1; last; } } } is( scalar @all, scalar keys %option_default, 'scalar @all == scalar keys %option_default' ); is( scalar keys %pod_default, scalar keys %option_default, 'scalar keys %pod_default == scalar keys %option_default' ); for my $key ( sort keys %option_default ) { next if any { $key eq $_ } @skip; is( $option_default{$key}, $pod_default{$key}, "option $key: default value in pod matches default value in code" ); } Term-Choose-1.774/xt/PaxHeaders/spelling.t0000644000000000000000000000013214775673705015421 xustar0030 mtime=1744271301.273991645 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/spelling.t0000644000175000001440000000056614775673705016202 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use Test::Spelling; set_spell_cmd('aspell list -l en -p /dev/null'); add_stopwords(); all_pod_files_spelling_ok(); __DATA__ BackSpace Ctrl de EOT hjkl Kiem lf ll markable Matthäus noncharacter OEM PageDown PageUp preselection preselected preselects ReadKey selectable SGR SpaceBar stackoverflow unformatted Term-Choose-1.774/xt/PaxHeaders/year_copyright.t0000644000000000000000000000013214775673705016634 xustar0030 mtime=1744271301.273991645 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/year_copyright.t0000644000175000001440000000145314775673705017411 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use Test::More tests => 1; use Time::Piece; my $t = localtime; my $this_year = $t->year; my @files = ( 'README', 'LICENSE', 'lib/Term/Choose.pm', 'lib/Term/Choose/LineFold.pm', ); my $author = 'Matth..?us Kiem'; my $error = 0; my $diag = ''; for my $file ( @files ) { open my $fh, '<', $file or die $!; while ( my $line = <$fh> ) { if ( $line =~ /copyright(?: \(c\))? .*$author/i ) { if ( $line !~ /copyright(?: \(c\))? 20\d\d-\Q$this_year\E /i && $line !~ /copyright(?: \(c\))? \Q$this_year\E /i ) { $diag .= sprintf( "%15s - line %d: %s\n", $file, $., $line ); $error++; } } } close $fh; } ok( $error == 0, "Copyright year" ) or diag( $diag ); diag( "\n" ); Term-Choose-1.774/xt/PaxHeaders/prereqs.t0000644000000000000000000000013215003223275015237 xustar0030 mtime=1745692349.151884747 30 atime=1745692349.819868847 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/prereqs.t0000644000175000001440000000055515003223275016016 0ustar00mmusers00000000000000use 5.22.0; use warnings; use strict; use Test::More; use Test::Prereq; prereq_ok( undef, [ qw( Term::ReadKey Encode Encode::Locale Win32::Console Win32::Console::ANSI Win32::Console::PatchForRT33513 Term::Form::ReadLine Data_Test_Arguments Data_Test_Choose ) ] ); Term-Choose-1.774/xt/PaxHeaders/pod.t0000644000000000000000000000013214775673705014366 xustar0030 mtime=1744271301.273991645 30 atime=1745740834.516913459 30 ctime=1745767633.701079608 Term-Choose-1.774/xt/pod.t0000644000175000001440000000013314775673705015135 0ustar00mmusers00000000000000use 5.10.1; use strict; use warnings; use Test::More; use Test::Pod; all_pod_files_ok(); Term-Choose-1.774/PaxHeaders/Makefile.PL0000644000000000000000000000013215003361311014702 xustar0030 mtime=1745740489.649251712 30 atime=1745767630.521138365 30 ctime=1745767633.701079608 Term-Choose-1.774/Makefile.PL0000644000175000001440000000351615003361311015461 0ustar00mmusers00000000000000use 5.10.1; use warnings; use strict; use ExtUtils::MakeMaker; my %prereqs_os_specific; if ( $^O eq 'MSWin32' ) { %prereqs_os_specific = ( 'Encode' => 0, 'Encode::Locale' => 0, 'Win32::Console' => 0, 'Win32::Console::ANSI' => 0, 'Win32::Console::PatchForRT33513' => 0, ); } my $has_xs = eval { require Term::Choose::LineFold::XS }; my %prereqs_xs; if ( $has_xs ) { %prereqs_xs = ( 'Term::Choose::LineFold::XS' => '0.001', ); } WriteMakefile( PL_FILES => {}, MIN_PERL_VERSION => '5.10.1', LICENSE => 'perl', META_MERGE => { 'meta-spec' => { version => 2 }, resources => { bugtracker => { web => "https://github.com/kuerbis/Term-Choose/issues", }, repository => { type => 'git', web => 'https://github.com/kuerbis/Term-Choose', url => 'https://github.com/kuerbis/Term-Choose.git', }, }, }, AUTHOR => 'Matthaeus Kiem ', NAME => 'Term::Choose', ABSTRACT_FROM => 'lib/Term/Choose.pm', VERSION_FROM => 'lib/Term/Choose.pm', EXE_FILES => [], BUILD_REQUIRES => { 'lib' => 0, 'open' => 0, 'File::Spec::Functions' => 0, 'FindBin' => 0, 'Test::More' => 0, 'Test::Fatal' => 0, }, PREREQ_PM => { 'constant' => 0, 'strict' => 0, 'warnings' => 0, 'Carp' => 0, 'Exporter' => 0, %prereqs_os_specific, %prereqs_xs, }, test => { TESTS => 't/*/*.t', }, ); Term-Choose-1.774/PaxHeaders/META.json0000644000000000000000000000013215003446321014356 xustar0030 mtime=1745767633.849076873 30 atime=1745767633.761078499 30 ctime=1745767633.849076873 Term-Choose-1.774/META.json0000644000175000001440000000306115003446321015130 0ustar00mmusers00000000000000{ "abstract" : "Choose items from a list interactively.", "author" : [ "Matthaeus Kiem " ], "dynamic_config" : 1, "generated_by" : "ExtUtils::MakeMaker version 7.74, CPAN::Meta::Converter version 2.150010", "license" : [ "perl_5" ], "meta-spec" : { "url" : "http://search.cpan.org/perldoc?CPAN::Meta::Spec", "version" : 2 }, "name" : "Term-Choose", "no_index" : { "directory" : [ "t", "inc" ] }, "prereqs" : { "build" : { "requires" : { "File::Spec::Functions" : "0", "FindBin" : "0", "Test::Fatal" : "0", "Test::More" : "0", "lib" : "0", "open" : "0" } }, "configure" : { "requires" : { "ExtUtils::MakeMaker" : "0" } }, "runtime" : { "requires" : { "Carp" : "0", "Exporter" : "0", "Term::Choose::LineFold::XS" : "0.001", "constant" : "0", "perl" : "5.010001", "strict" : "0", "warnings" : "0" } } }, "release_status" : "stable", "resources" : { "bugtracker" : { "web" : "https://github.com/kuerbis/Term-Choose/issues" }, "repository" : { "type" : "git", "url" : "https://github.com/kuerbis/Term-Choose.git", "web" : "https://github.com/kuerbis/Term-Choose" } }, "version" : "1.774", "x_serialization_backend" : "JSON::PP version 4.16" } Term-Choose-1.774/PaxHeaders/lib0000644000000000000000000000013215003446321013426 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/0000755000175000001440000000000015003446321014255 5ustar00mmusers00000000000000Term-Choose-1.774/lib/PaxHeaders/Term0000644000000000000000000000013215003446321014335 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/0000755000175000001440000000000015003446321015164 5ustar00mmusers00000000000000Term-Choose-1.774/lib/Term/PaxHeaders/Choose0000644000000000000000000000013215003446321015555 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/0000755000175000001440000000000015003446321016404 5ustar00mmusers00000000000000Term-Choose-1.774/lib/Term/Choose/PaxHeaders/Opt0000644000000000000000000000013215003446321016317 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Opt/0000755000175000001440000000000015003446321017146 5ustar00mmusers00000000000000Term-Choose-1.774/lib/Term/Choose/Opt/PaxHeaders/Search.pm0000644000000000000000000000013115002201215020124 xustar0029 mtime=1745420941.00051403 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Opt/Search.pm0000644000175000001440000001120415002201215020675 0ustar00mmusers00000000000000package Term::Choose::Opt::Search; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Term::Choose::Constants qw( ROW COL ); use Term::Choose::Screen qw( up clear_to_end_of_screen show_cursor hide_cursor ); sub __user_input { my ( $self, $prompt, $error, $default ) = @_; $self->{plugin}->__reset_mode( { mouse => $self->{mouse}, hide_cursor => $self->{hide_cursor} } ); if ( $self->{l_margin} ) { $prompt = ( ' ' x $self->{l_margin} ) . $prompt; } my $string; if ( ! eval { require Term::Form::ReadLine; Term::Form::ReadLine->VERSION(0.544); my $term = Term::Form::ReadLine->new(); $string = $term->readline( $prompt, { info => $error, default => $default, hide_cursor => 2, clear_screen => length $error ? 1 : 2, color => $self->{color} } ); 1 } ) { print "\r", clear_to_end_of_screen(); if ( length $error ) { print $error, "\n\r"; } print show_cursor() if ! $self->{hide_cursor}; print $prompt; $string = ; print hide_cursor() if ! $self->{hide_cursor}; chomp $string; } $self->__init_term(); return $string; } sub __search_begin { my ( $self ) = @_; my ($search_regex, $error, $default ); USER_INPUT: while ( 1 ) { my $search_str = $self->Term::Choose::Opt::Search::__user_input( '> search-pattern: ', $error, $default ); $error = ''; if ( ! length $search_str ) { $self->Term::Choose::Opt::Search::__search_end(); return; } if ( ! eval { if ( $self->{search} == 1 ) { $search_regex = qr/$search_str/i; $self->{search_info} = 'm/' . $search_str . '/i'; } else { $search_regex = qr/$search_str/; $self->{search_info} = 'm/' . $search_str . '/'; } 'Teststring' =~ $search_regex; 1 } ) { $error = $@; $default = $default eq $search_str ? '' : $search_str; next USER_INPUT; } last USER_INPUT; } $self->{map_search_list_index} = []; my $filtered_list = []; for my $i ( 0 .. $#{$self->{list}} ) { if ( $self->{list}[$i] =~ $search_regex ) { push @{$self->{map_search_list_index}}, $i; push @$filtered_list, $self->{list}[$i]; } } if ( ! @$filtered_list ) { $filtered_list = [ 'No matches found.' ]; $self->{map_search_list_index} = [ 0 ]; } $self->{mark} = $self->__marked_rc2idx(); $self->{backup_list} = [ @{$self->{list}} ]; $self->{list} = $filtered_list; $self->{backup_width_elements} = [ @{$self->{width_elements}} ]; $self->{backup_col_width} = $self->{col_width}; $self->__length_list_elements(); $self->{default} = 0; for my $opt ( qw(meta_items no_spacebar mark) ) { if ( defined $self->{$opt} ) { $self->{'backup_' . $opt} = [ @{$self->{$opt}} ]; my $tmp = []; for my $orig_idx ( @{$self->{$opt}} ) { for my $i ( 0 .. $#{$self->{map_search_list_index}} ) { if ( $self->{map_search_list_index}[$i] == $orig_idx ) { push @$tmp, $i; } } } $self->{$opt} = $tmp; } } my $up = $self->{i_row} + $self->{count_prompt_lines} + 1; # + 1 => readline print up( $up ) if $up; $self->__wr_first_screen(); } sub __search_end { my ( $self ) = @_; $self->{search_info} = ''; if ( @{$self->{map_search_list_index}||[]} ) { my $curr_idx = $self->{rc2idx}[ $self->{pos}[ROW] ][ $self->{pos}[COL] ]; $self->{default} = $self->{map_search_list_index}[$curr_idx]; $self->{mark} = $self->__marked_rc2idx(); my $tmp_mark = []; for my $i ( @{$self->{mark}} ) { push @$tmp_mark, $self->{map_search_list_index}[$i]; } my %seen; $self->{mark} = [ grep !$seen{$_}++, @$tmp_mark, defined $self->{backup_mark} ? @{$self->{backup_mark}} : () ]; } delete $self->{map_search_list_index}; delete $self->{backup_mark}; for my $key ( qw(list width_elements col_width meta_items no_spacebar) ) { my $key_backup = 'backup_' . $key; $self->{$key} = $self->{$key_backup} if defined $self->{$key_backup}; delete $self->{$key_backup}; } my $up = $self->{i_row} + $self->{count_prompt_lines}; print up( $up ) if $up; print "\r" . clear_to_end_of_screen(); $self->__wr_first_screen(); } 1; __END__ Term-Choose-1.774/lib/Term/Choose/Opt/PaxHeaders/SkipItems.pm0000644000000000000000000000013115002201215020627 xustar0029 mtime=1745420941.00051403 30 atime=1745767630.605136813 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Opt/SkipItems.pm0000644000175000001440000003000115002201215021374 0ustar00mmusers00000000000000package Term::Choose::Opt::SkipItems; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Term::Choose::Constants qw( :all ); sub __key_skipped { my ( $self ) = @_; my $pressed_key = $self->{pressed_key}; if ( ! defined $pressed_key ) { return; } elsif ( $pressed_key == VK_DOWN || $pressed_key == KEY_j ) { my $new_row = $self->Term::Choose::Opt::SkipItems::__next_valid_down(); if ( defined $new_row ) { if ( $new_row > $self->{last_page_row} ) { $self->__set_cell( $self->{rc2idx}[$new_row][$self->{pos}[COL]] ); $self->__wr_screen(); } else { my $old_row = $self->{pos}[ROW]; $self->{pos}[ROW] = $new_row; $self->__wr_cell( $old_row, $self->{pos}[COL] ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } return; } else { return VK_UP; } } elsif ( $pressed_key == VK_UP || $pressed_key == KEY_k ) { my $new_row = $self->Term::Choose::Opt::SkipItems::__next_valid_up(); if ( defined $new_row ) { if ( $new_row < $self->{first_page_row} ) { $self->__set_cell( $self->{rc2idx}[$new_row][$self->{pos}[COL]] ); $self->__wr_screen(); } else { my $old_row = $self->{pos}[ROW]; $self->{pos}[ROW] = $new_row; $self->__wr_cell( $old_row, $self->{pos}[COL] ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } return; } else { return VK_DOWN; } } elsif ( $pressed_key == VK_RIGHT || $pressed_key == KEY_l ) { my $new_col = $self->Term::Choose::Opt::SkipItems::__next_valid_right(); if ( defined $new_col ) { my $old_col = $self->{pos}[COL]; $self->{pos}[COL] = $new_col; $self->__wr_cell( $self->{pos}[ROW], $old_col ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } else { return VK_LEFT; } } elsif ( $pressed_key == VK_LEFT || $pressed_key == KEY_h ) { my $new_col = $self->Term::Choose::Opt::SkipItems::__next_valid_left(); if ( defined $new_col ) { my $old_col = $self->{pos}[COL]; $self->{pos}[COL] = $new_col; $self->__wr_cell( $self->{pos}[ROW], $old_col ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } else { return VK_RIGHT; } } elsif ( $pressed_key == KEY_TAB || $pressed_key == CONTROL_I ) { my ( $new_row, $new_col ) = $self->Term::Choose::Opt::SkipItems::__next_valid_right_down(); if ( defined $new_row && defined $new_col ) { if ( $new_row > $self->{last_page_row} ) { $self->__set_cell( $self->{rc2idx}[$new_row][$new_col] ); $self->__wr_screen(); } else { my $old_row = $self->{pos}[ROW]; my $old_col = $self->{pos}[COL]; $self->{pos}[ROW] = $new_row; $self->{pos}[COL] = $new_col; $self->__wr_cell( $old_row , $old_col ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } } else { return KEY_BSPACE; } } elsif ( $pressed_key == KEY_BSPACE || $pressed_key == CONTROL_H || $pressed_key == KEY_BTAB ) { my ( $new_row, $new_col ) = $self->Term::Choose::Opt::SkipItems::__next_valid_left_up(); if ( defined $new_row && defined $new_col ) { if ( $new_row < $self->{first_page_row} ) { $self->__set_cell( $self->{rc2idx}[$new_row][$new_col] ); $self->__wr_screen(); } else { my $old_row = $self->{pos}[ROW]; my $old_col = $self->{pos}[COL]; $self->{pos}[ROW] = $new_row; $self->{pos}[COL] = $new_col; $self->__wr_cell( $old_row , $old_col ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } } else { return KEY_TAB; } } elsif ( $pressed_key == VK_PAGE_DOWN || $pressed_key == CONTROL_F ) { my $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_up_or_down(); if ( ! defined $id ) { $id = $self->Term::Choose::Opt::SkipItems::__closest_valid_id_within_page(); } if ( ! defined $id ) { $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_from_next_page_to_end_page(); } if ( defined $id ) { $self->__set_cell( $id ); $self->__wr_screen(); return } $self->__beep(); return VK_PAGE_UP; } elsif ( $pressed_key == VK_PAGE_UP || $pressed_key == CONTROL_B ) { my $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_up_or_down(); if ( ! defined $id ) { $id = $self->Term::Choose::Opt::SkipItems::__closest_valid_id_within_page(); } if ( ! defined $id ) { $id = $self->Term::Choose::Opt::SkipItems::__next_valid_id_from_previous_page_to_first_page(); } if ( defined $id ) { $self->__set_cell( $id ); $self->__wr_screen(); return } $self->__beep(); return VK_PAGE_DOWN; } elsif ( $pressed_key == VK_HOME || $pressed_key == CONTROL_A ) { my $id = $self->Term::Choose::Opt::SkipItems::__first_valid_id(); if ( defined $id ) { $self->__set_cell( $id ); $self->__wr_screen(); return } $self->__beep(); return; } elsif ( $pressed_key == VK_END || $pressed_key == CONTROL_E ) { my $id = $self->Term::Choose::Opt::SkipItems::__last_valid_id(); if ( defined $id ) { $self->__set_cell( $id ); $self->__wr_screen(); return } $self->__beep(); return; } return; } sub __next_valid_down { my ( $self ) = @_; my $last_row = $#{$self->{rc2idx}}; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL]; if ( $col > $self->{idx_of_last_col_in_last_row} ) { $last_row--; } while ( ++$row <= $last_row ) { if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { return $row; } } return; } sub __next_valid_up { my ( $self ) = @_; my $first_row = 0; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL]; while ( --$row >= $first_row ) { if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { return $row; } } return; } sub __next_valid_right { my ( $self ) = @_; my $last_col = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL]; while ( ++$col <= $last_col ) { if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { return $col; } } return; } sub __next_valid_left { my ( $self ) = @_; my $first_col = 0; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL]; while ( --$col >= $first_col ) { if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { return $col; } } return; } sub __next_valid_right_down { my ( $self ) = @_; my $last_row = $#{$self->{rc2idx}}; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL] + 1; while ( $row <= $last_row ) { my $last_col = $#{$self->{rc2idx}[$row]}; while ( $col <= $last_col ) { if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { return $row, $col; } ++$col; } ++$row; $col = 0; } return; } sub __next_valid_left_up { my ( $self ) = @_; my $first_row = 0; my $first_col = 0; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL] - 1; while ( $row >= $first_row ) { while ( $col >= $first_col ) { if ( $self->{list}[$self->{rc2idx}[$row][$col]] !~ /$self->{skip_items}/ ) { return $row, $col; } --$col; } --$row; $col = $#{$self->{rc2idx}[$row]}; } return; } sub __next_valid_id_up_or_down { my ( $self ) = @_; my $begin = $self->{first_page_row}; my $end = $self->{last_page_row}; my $row = $self->{pos}[ROW]; my $col = $self->{pos}[COL]; if ( $end == $#{$self->{rc2idx}} && $col > $self->{idx_of_last_col_in_last_row} ) { $end--; } my ( $row_up, $row_down ) = ( $row, $row ); while ( 1 ) { --$row_up; ++$row_down; if ( $row_up >= $begin ) { my $id = $self->{rc2idx}[$row_up][$col]; if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { return $id; } } elsif ( $row_down <= $end ) { my $id = $self->{rc2idx}[$row_down][$col]; if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { return $id; } } else { return; } } } sub __closest_valid_id_within_page { my ( $self ) = @_; return $self->Term::Choose::Opt::SkipItems::__next_valid_id( $self->{rc2idx}[$self->{first_page_row}][ 0 ], $self->{rc2idx}[$self->{last_page_row} ][-1 ], $self->{rc2idx}[$self->{pos}[ROW]] [$self->{pos}[COL]] ); } sub __next_valid_id_from_next_page_to_end_page { my ( $self ) = @_; for my $row ( $self->{last_page_row} + 1 .. $#{$self->{rc2idx}} ) { for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) { my $id = $self->{rc2idx}[$row][$col]; if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { return $id; } } } return; } sub __next_valid_id_from_previous_page_to_first_page { my ( $self ) = @_; for my $row ( reverse( 0 .. $self->{first_page_row} - 1 ) ) { for my $col ( reverse( 0 .. $#{$self->{rc2idx}[$row]} ) ) { my $id = $self->{rc2idx}[$row][$col]; if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { return $id; } } } return; # } sub __first_valid_id { my ( $self ) = @_; for my $id ( 0 .. $#{$self->{list}} ) { if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { return $id; } } return; } sub __last_valid_id { my ( $self ) = @_; for my $id ( reverse( 0 .. $#{$self->{list}} ) ) { if ( $self->{list}[$id] !~ /$self->{skip_items}/ ) { return $id; } } return; } sub __next_valid_id { my ( $self, $begin, $end, $id ) = @_; my ( $id_up, $id_down ) = ( $id, $id ); while ( 1 ) { --$id_up; ++$id_down; if ( $id_up >= $begin ) { return $id_up if $self->{list}[$id_up] !~ /$self->{skip_items}/; } elsif ( $id_down <= $end ) { return $id_down if $self->{list}[$id_down] !~ /$self->{skip_items}/; } else { return; } } } sub __prepare_default { my ( $self ) = @_; if ( $self->{list}[$self->{default} || 0] =~ /$self->{skip_items}/ ) { $self->{default} = $self->Term::Choose::Opt::SkipItems::__next_valid_id( 0, $#{$self->{list}}, $self->{default} || 0 ); } } sub __unmark_skip_items { my ( $self ) = @_; for my $row ( 0 .. $#{$self->{rc2idx}} ) { for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) { if ( $self->{marked}[$row][$col] && $self->{list}[ $self->{rc2idx}[$row][$col] ] =~ /$self->{skip_items}/ ) { $self->{marked}[$row][$col] = 0; } } } } 1; __END__ Term-Choose-1.774/lib/Term/Choose/Opt/PaxHeaders/Mouse.pm0000644000000000000000000000013115002201215020007 xustar0029 mtime=1745420941.00051403 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Opt/Mouse.pm0000644000175000001440000000455215002201215020570 0ustar00mmusers00000000000000package Term::Choose::Opt::Mouse; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Term::Choose::Constants qw( :all ); sub __mouse_info_to_key { my ( $self, $button, $mouse_x, $mouse_y ) = @_; if ( $button == 4 ) { return VK_PAGE_UP; } elsif ( $button == 5 ) { return VK_PAGE_DOWN; } # ..._y, ..._x: absolute position, one-based index my $mouse_row = $mouse_y - 1 - $self->{offset_rows}; my $mouse_col = $mouse_x - 1; if ( $mouse_row < 0 || $mouse_row > $#{$self->{rc2idx}} ) { return NEXT_get_key; } my $matched_col; my $begin_this_col = 0; my $row = $mouse_row + $self->{first_page_row}; COL: for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) { my $begin_next_col; if ( $self->{current_layout} == -1 ) { my $idx = $self->{rc2idx}[$row][$col]; $begin_next_col = $begin_this_col + $self->{width_elements}[$idx] + $self->{pad}; } else { $begin_next_col = $begin_this_col + $self->{col_width_plus}; } if ( $col == 0 ) { $begin_next_col -= int( $self->{pad} / 2 ); } if ( $col == $#{$self->{rc2idx}[$row]} && $begin_next_col > $self->{avail_width} ) { $begin_next_col = $self->{avail_width}; } if ( $mouse_col >= $begin_this_col && $mouse_col < $begin_next_col ) { $matched_col = $col; last COL; } $begin_this_col = $begin_next_col; } if ( ! defined $matched_col ) { return NEXT_get_key; } if ( defined $self->{skip_items} ) { my $idx = $self->{rc2idx}[$row][$matched_col]; if ( $self->{list}[$idx] =~ /$self->{skip_items}/ ) { return NEXT_get_key; } } if ( $button == 1 ) { $self->{pos}[ROW] = $row; # writes to $self $self->{pos}[COL] = $matched_col; # writes to $self return LINE_FEED; } if ( $row != $self->{pos}[ROW] || $matched_col != $self->{pos}[COL] ) { my $not_pos = $self->{pos}; $self->{pos} = [ $row, $matched_col ]; # writes to $self $self->__wr_cell( $not_pos->[0], $not_pos->[1] ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } if ( $button == 3 ) { return KEY_SPACE; } else { return NEXT_get_key; } } 1; __END__ Term-Choose-1.774/lib/Term/Choose/PaxHeaders/ValidateOptions.pm0000644000000000000000000000013215002201214021262 xustar0030 mtime=1745420940.996514082 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/ValidateOptions.pm0000755000175000001440000000306715002201214022045 0ustar00mmusers00000000000000package Term::Choose::ValidateOptions; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( validate_options ); use Carp qw( croak ); sub validate_options { my ( $valid, $opt, $caller ) = @_; return if ! defined $opt; # if ( ! defined $caller ) { # $caller = ''; }; for my $key ( keys %$opt ) { if ( ! exists $valid->{$key} ) { croak "$caller: '$key' is not a valid option name"; } next if ! defined $opt->{$key}; if ( $valid->{$key} =~ /^Array/ ) { croak "$caller: option '$key' => the passed value has to be an ARRAY reference." if ref $opt->{$key} ne 'ARRAY'; if ( $valid->{$key} eq 'Array_Int' ) { for ( @{$opt->{$key}} ) { defined or croak "$caller: option '$key' => undefined array element"; /^[0-9]+\z/ or croak "$caller: option '$key' => $_ is an invalid array element"; } } } elsif ( $valid->{$key} =~ /^Regexp/ ) { croak "$caller: option '$key' => the passed value has to be a regex quoted with the 'qr' operator." if ref $opt->{$key} ne 'Regexp'; } elsif ( ref $opt->{$key} ) { croak "$caller: option '$key' => a reference is not a valid value."; } elsif ( $valid->{$key} eq 'Str' ) { } elsif ( $opt->{$key} !~ m/^$valid->{$key}\z/x ) { croak "$caller: option '$key' => '$opt->{$key}' is not a valid value."; } } } 1; Term-Choose-1.774/lib/Term/Choose/PaxHeaders/Screen.pm0000644000000000000000000000013215002201214017374 xustar0030 mtime=1745420940.996514082 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Screen.pm0000755000175000001440000000651715002201214020162 0ustar00mmusers00000000000000package Term::Choose::Screen; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( down up left right clear_screen clear_to_end_of_screen clear_to_end_of_line reverse_video bold underline bold_underline normal show_cursor hide_cursor bell get_term_size ); our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); use Term::Choose::Constants qw( WIDTH_CURSOR TERM_READKEY ); my ( @up, @down, @right, @left, $reverse, $bold, $underline, $bold_underline, $normal, $bell, $clear_screen, $clr_to_bot, $clr_to_eol, $show_cursor, $hide_cursor, ); BEGIN { if ( $^O eq 'MSWin32' || $ENV{TC_ANSI_ESCAPES} || ! qx(tput cuu 2>/dev/null) ) { @up = ( "\e[", "A" ); @down = ( "\e[", "B" ); @right = ( "\e[", "C" ); @left = ( "\e[", "D" ); $reverse = "\e[7m"; $bold = "\e[1m"; $underline = "\e[4m"; $normal = "\e[0m"; $bell = "\a"; $clear_screen = "\e[H\e[J"; $clr_to_bot = "\e[0J"; $clr_to_eol = "\e[K"; $show_cursor = "\e[?25h"; $hide_cursor = "\e[?25l"; } else { @up = split( '107', qx(tput cuu 107) ); @down = split( '107', qx(tput cud 107) ); @right = split( '107', qx(tput cuf 107) ); @left = split( '107', qx(tput cub 107) ); $reverse = qx(tput rev); $bold = qx(tput bold); $underline = qx(tput smul); $normal = qx(tput sgr0); $bell = qx(tput bel); $clear_screen = qx(tput clear); $clr_to_bot = qx(tput ed); $clr_to_eol = qx(tput el); $show_cursor = qx(tput cnorm); $hide_cursor = qx(tput civis); } } sub down { return $down[0] . $_[0] . $down[1] } sub up { return $up[0] . $_[0] . $up[1] } sub left { return $left[0] . $_[0] . $left[1] } sub right { return $right[0] . $_[0] . $right[1] } sub clear_screen { return $clear_screen } sub clear_to_end_of_screen { return $clr_to_bot } sub clear_to_end_of_line { return $clr_to_eol } sub reverse_video { return $reverse } #sub bold { return $bold } #sub underline { return $underline } sub bold_underline { return $bold . $underline } sub normal { return $normal } sub show_cursor { return $show_cursor } sub hide_cursor { return $hide_cursor } sub bell { return $bell } sub get_term_size { my ( $width, $height, $error ); if ( TERM_READKEY ) { ( $width, $height ) = ( Term::ReadKey::GetTerminalSize() )[ 0, 1 ]; if ( ! $width || ! $height ) { $error = "get_term_size - Term::ReadKey::GetTerminalSize:"; } } elsif( $^O eq 'MSWin32' ) { require Win32::Console; ( $width, $height ) = Win32::Console->new()->Size(); if ( ! $width || ! $height ) { $error = "get_term_size - Win32::Console Size:"; } } else { my $size = qx(stty size); if ( defined $size && $size =~ /(\d+)\s(\d+)/ ) { $width = $2; $height = $1; } if ( ! $width || ! $height ) { $error = "get_term_size - stty size:"; } } if ( $error ) { $error .= " No term width!" if ! $width; $error .= " No term height!" if ! $height; die $error; } return $width - WIDTH_CURSOR, $height; } 1; Term-Choose-1.774/lib/Term/Choose/PaxHeaders/Constants.pm0000644000000000000000000000013215002201214020131 xustar0030 mtime=1745420940.996514082 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Constants.pm0000644000175000001440000000516415002201214020711 0ustar00mmusers00000000000000package Term::Choose::Constants; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( NEXT_get_key CONTROL_SPACE LINE_FEED CARRIAGE_RETURN CONTROL_A CONTROL_B CONTROL_C CONTROL_D CONTROL_E CONTROL_F CONTROL_H CONTROL_I CONTROL_K CONTROL_N CONTROL_P CONTROL_Q CONTROL_R CONTROL_S CONTROL_T CONTROL_U CONTROL_X KEY_BTAB KEY_TAB KEY_ESC KEY_SPACE KEY_h KEY_j KEY_k KEY_l KEY_q KEY_Tilde KEY_BSPACE VK_LEFT VK_RIGHT VK_UP VK_DOWN VK_INSERT VK_DELETE VK_HOME VK_END VK_PAGE_UP VK_PAGE_DOWN VK_F1 VK_F2 VK_F3 VK_F4 ROW COL WIDTH_CURSOR EXTRA_W TERM_READKEY PH SGR_ES ); our %EXPORT_TAGS = ( all => [ @EXPORT_OK ] ); use constant TERM_READKEY => eval { require Term::ReadKey; 1 }; use constant WIDTH_CURSOR => 1; use constant EXTRA_W => $^O eq 'MSWin32' || $^O eq 'cygwin' ? 0 : WIDTH_CURSOR; use constant { PH => "\x{feff}", # zero width placeholder character SGR_ES => '\e\[[\d;]*m', }; use constant { ROW => 0, COL => 1, }; use constant { NEXT_get_key => -1, CONTROL_SPACE => 0x00, CONTROL_A => 0x01, CONTROL_B => 0x02, CONTROL_C => 0x03, CONTROL_D => 0x04, CONTROL_E => 0x05, CONTROL_F => 0x06, # CONTROL_G => 0x07, CONTROL_H => 0x08, KEY_BTAB => 0x08, CONTROL_I => 0x09, KEY_TAB => 0x09, # CONTROL_J => 0x0a, LINE_FEED => 0x0a, CONTROL_K => 0x0b, # CONTROL_L => 0x0c, # CONTROL_M => 0x0d, CARRIAGE_RETURN => 0x0d, CONTROL_N => 0x0e, # CONTROL_O => 0x0f, CONTROL_P => 0x10, CONTROL_Q => 0x11, CONTROL_R => 0x12, # unused CONTROL_S => 0x13, CONTROL_T => 0x14, CONTROL_U => 0x15, # CONTROL_V => 0x16, # CONTROL_W => 0x17, CONTROL_X => 0x18, # CONTROL_Y => 0x19, # CONTROL_Z => 0x1a, KEY_ESC => 0x1b, KEY_SPACE => 0x20, KEY_h => 0x68, KEY_j => 0x6a, KEY_k => 0x6b, KEY_l => 0x6c, KEY_q => 0x71, KEY_Tilde => 0x7e, KEY_BSPACE => 0x7f, VK_PAGE_UP => 333, # VK_CODE_KEY + 300 VK_PAGE_DOWN => 334, VK_END => 335, VK_HOME => 336, VK_LEFT => 337, VK_UP => 338, VK_RIGHT => 339, VK_DOWN => 340, VK_INSERT => 345, VK_DELETE => 346, VK_F1 => 412, VK_F2 => 413, VK_F3 => 414, VK_F4 => 415, }; 1; __END__ Term-Choose-1.774/lib/Term/Choose/PaxHeaders/LineFold.pm0000644000000000000000000000013115003357536017674 xustar0029 mtime=1745739614.51810799 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/LineFold.pm0000755000175000001440000002020515003357536020451 0ustar00mmusers00000000000000package Term::Choose::LineFold; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( char_width print_columns cut_to_printwidth adjust_to_printwidth line_fold ); use Carp qw( croak ); use Term::Choose::Constants qw( PH SGR_ES EXTRA_W ); use Term::Choose::Screen qw( get_term_size ); #BEGIN { # my $module; # eval { # require Term::Choose::LineFold::XS; # Term::Choose::LineFold::XS->VERSION( 0.001 ); # $module = 'Term::Choose::LineFold::XS'; # 1; # } or do { # require Term::Choose::LineFold::PP; # $module = 'Term::Choose::LineFold::PP'; # }; # no strict qw( refs ); # for my $func ( qw( char_width print_columns cut_to_printwidth adjust_to_printwidth ) ) { # *{"Term::Choose::LineFold::$func"} = \&{"${module}::$func"}; # } #} BEGIN { my $module; eval { require Term::Choose::LineFold::XS; Term::Choose::LineFold::XS->VERSION( 0.001 ); $module = 'Term::Choose::LineFold::XS'; 1; } or do { require Term::Choose::LineFold::PP; $module = 'Term::Choose::LineFold::PP'; }; *Term::Choose::LineFold::char_width = \&{"${module}::char_width"}; *Term::Choose::LineFold::print_columns = \&{"${module}::print_columns"}; *Term::Choose::LineFold::cut_to_printwidth = \&{"${module}::cut_to_printwidth"}; *Term::Choose::LineFold::adjust_to_printwidth = \&{"${module}::adjust_to_printwidth"}; } sub line_fold { my ( $str, $opt ) = @_; # copy $str if ( ! length $str ) { return $str; } ################################### 24.03.2025 if ( defined $opt && ! ref $opt ) { my $width = $opt; $opt = $_[2] // {}; $opt->{width} = $width; } ################################### $opt //= {}; $opt->{join} //= 1; if ( ! defined $opt->{width} ) { my ( $term_width, undef ) = get_term_size(); $opt->{width} = $term_width + EXTRA_W; } elsif ( $opt->{width} !~ /^[1-9][0-9]*\z/ ) { croak "Option 'width': '$opt->{width}' is not an Integer 1 or greater!"; } my $max_tab_width = int( $opt->{width} / 2 ); for ( $opt->{init_tab}, $opt->{subseq_tab} ) { if ( length ) { if ( /^[0-9]+\z/ ) { $_ = ' ' x $_; } else { s/\t/ /g; s/\v+/\ \ /g; ## s/[\p{Cc}\p{Noncharacter_Code_Point}\p{Cs}]//g; } if ( length > $max_tab_width ) { $_ = cut_to_printwidth( $_, $max_tab_width ); } } else { $_ = ''; } } my @color; if ( $opt->{color} ) { $str =~ s/${\PH}//g; $str =~ s/(${\SGR_ES})/push( @color, $1 ) && ${\PH}/ge; } if ( $opt->{binary_filter} && substr( $str, 0, 100 ) =~ /[\x00-\x08\x0B-\x0C\x0E-\x1F]/ ) { #$str = $self->{binary_filter} == 2 ? sprintf("%v02X", $_[0]) =~ tr/./ /r : 'BNRY'; # perl 5.14 if ( $opt->{binary_filter} == 2 ) { ( $str = sprintf( "%v02X", $_[0] ) ) =~ tr/./ /; # use unmodified string } else { $str = 'BNRY'; } } $str =~ s/\t/ /g; $str =~ s/[^\v\P{Cc}]//g; # remove control chars but keep vertical spaces $str =~ s/[\p{Noncharacter_Code_Point}\p{Cs}]//g; my @paragraphs; for my $row ( split /\R/, $str, -1 ) { # -1 to keep trailing empty fields my @lines; $row =~ s/\s+\z//; my @words = split( /(?<=\S)(?=\s)/, $row ); my $line = $opt->{init_tab}; for my $i ( 0 .. $#words ) { if ( print_columns( $line . $words[$i] ) <= $opt->{width} ) { $line .= $words[$i]; } else { my $tmp; if ( $i == 0 ) { $tmp = $opt->{init_tab} . $words[$i]; } else { push( @lines, $line ); $words[$i] =~ s/^\s+//; $tmp = $opt->{subseq_tab} . $words[$i]; } ( $line, my $remainder ) = cut_to_printwidth( $tmp, $opt->{width} ); while ( length $remainder ) { push( @lines, $line ); $tmp = $opt->{subseq_tab} . $remainder; ( $line, $remainder ) = cut_to_printwidth( $tmp, $opt->{width} ); } } if ( $i == $#words ) { push( @lines, $line ); } } if ( $opt->{join} ) { push( @paragraphs, join( "\n", @lines ) ); } else { if ( @lines ) { push( @paragraphs, @lines ); } else { push( @paragraphs, '' ); } } } if ( @color ) { my $last_color; for my $paragraph ( @paragraphs ) { if ( ! $opt->{join} ) { if ( $last_color ) { $paragraph = $last_color . $paragraph; } my $count = () = $paragraph =~ /${\PH}/g; if ( $count ) { $last_color = $color[$count - 1]; } } $paragraph =~ s/${\PH}/shift @color/ge; if ( ! @color ) { last; } } $paragraphs[-1] .= "\e[0m"; } if ( $opt->{join} ) { return join( "\n", @paragraphs ); } else { return @paragraphs; } } 1; __END__ =pod =encoding UTF-8 =head1 NAME Term::Choose::LineFold =head1 VERSION Version 1.774 =cut =head1 DESCRIPTION I in this context refers to the number of occupied columns of a character string on a terminal with a monospaced font. By default ambiguous width characters are treated as half width. If the environment variable C is set to a true value, ambiguous width characters are treated as full width. If the optional L module is installed, its functions will be used automatically in place of the pure-Perl implementations, providing faster performance. =head1 EXPORT Nothing by default. use Term::Choose::LineFold qw( print_columns ); =head1 FUNCTIONS =head2 print_columns Get the number of occupied columns of a character string on a terminal. The string passed to this function is a decoded string, free of control characters, non-characters, and surrogates. $print_width = print_columns( $string ); =head2 line_fold Fold a string. This function accepts a decoded string. Control characters (excluding vertical spaces), non-characters, and surrogates are removed before the string is folded. Changes are applied to a copy; the passed string is unchanged. $folded_string = line_fold( $string ); $folded_string = line_fold( $string, { width => 120, color => 1 } ); =head3 Options =over =item width If not set, defaults to the terminal width. I is C<1> or greater. =item init_tab Sets the initial tab inserted at the beginning of paragraphs. If a value consisting of C is provided, the tab will be that number of spaces. Otherwise, the provided value is used directly as the tab. By default, no initial tab is inserted. If the initial tab is longer than half the available width, it will be cut to half the available width. =item subseq_tab Sets the subsequent tab inserted at the beginning of all broken lines (excluding paragraph beginnings). If a value consisting of C is provided, the tab will be that number of spaces. Otherwise, the provided value is used directly as the tab. By default, no subsequent tab is inserted. If the subsequent tab is longer than half the available width, it will be cut to half the available width. =item color Enables support for ANSI SGR escape sequences. If enabled, all zero-width no-break spaces (C<0xfeff>) are removed. I is C<0> or C<1>. =back =head1 AUTHOR Matthäus Kiem =head1 LICENSE AND COPYRIGHT Copyright (C) 2025 Matthäus Kiem. This library is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For details, see the full text of the licenses in the file LICENSE. =cut Term-Choose-1.774/lib/Term/Choose/PaxHeaders/Win32.pm0000644000000000000000000000013215002201214017057 xustar0030 mtime=1745420940.996514082 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Win32.pm0000644000175000001440000001466115002201214017641 0ustar00mmusers00000000000000package Term::Choose::Win32; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Encode qw( decode ); use Encode::Locale qw(); use Win32::Console qw( STD_INPUT_HANDLE ENABLE_PROCESSED_INPUT ENABLE_LINE_INPUT ENABLE_ECHO_INPUT ENABLE_MOUSE_INPUT STD_OUTPUT_HANDLE RIGHT_ALT_PRESSED LEFT_ALT_PRESSED RIGHT_CTRL_PRESSED LEFT_CTRL_PRESSED SHIFT_PRESSED FOREGROUND_INTENSITY BACKGROUND_INTENSITY ); use Win32::Console::PatchForRT33513 qw(); use Term::Choose::Constants qw( :all ); use Term::Choose::Screen qw( hide_cursor show_cursor normal ); use constant { MOUSE_WHEELED => 0x0004, LEFTMOST_BUTTON_PRESSED => 0x0001, RIGHTMOST_BUTTON_PRESSED => 0x0002, FROM_LEFT_2ND_BUTTON_PRESSED => 0x0004, VK_CODE_PAGE_UP => 33, VK_CODE_PAGE_DOWN => 34, VK_CODE_END => 35, VK_CODE_HOME => 36, VK_CODE_LEFT => 37, VK_CODE_UP => 38, VK_CODE_RIGHT => 39, VK_CODE_DOWN => 40, VK_CODE_INSERT => 45, VK_CODE_DELETE => 46, VK_CODE_F1 => 112, VK_CODE_F2 => 113, VK_CODE_F3 => 114, VK_CODE_F4 => 115, }; sub SHIFTED_MASK () { RIGHT_ALT_PRESSED # 0x0001 | LEFT_ALT_PRESSED # 0x0002 | RIGHT_CTRL_PRESSED # 0x0004 | LEFT_CTRL_PRESSED # 0x0008 | SHIFT_PRESSED # 0x0010 } sub new { return bless {}, $_[0]; } sub __get_key_OS { my ( $self, $mouse ) = @_; my @event = $self->{input}->Input; my $event_type = shift @event; return NEXT_get_key if ! defined $event_type; if ( $event_type == 1 ) { my ( $key_down, $repeat_count, $v_key_code, $v_scan_code, $char, $ctrl_key_state ) = @event; return NEXT_get_key if ! $key_down; if ( $char ) { if ( $char == 32 && $ctrl_key_state & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED ) ) { return CONTROL_SPACE; } else { return ord decode( 'console_in', chr( $char & 0xff ) ); } } else{ if ( $ctrl_key_state & SHIFTED_MASK ) { return NEXT_get_key; } elsif ( $v_key_code == VK_CODE_PAGE_UP ) { return VK_PAGE_UP } elsif ( $v_key_code == VK_CODE_PAGE_DOWN ) { return VK_PAGE_DOWN } elsif ( $v_key_code == VK_CODE_END ) { return VK_END } elsif ( $v_key_code == VK_CODE_HOME ) { return VK_HOME } elsif ( $v_key_code == VK_CODE_LEFT ) { return VK_LEFT } elsif ( $v_key_code == VK_CODE_UP ) { return VK_UP } elsif ( $v_key_code == VK_CODE_RIGHT ) { return VK_RIGHT } elsif ( $v_key_code == VK_CODE_DOWN ) { return VK_DOWN } elsif ( $v_key_code == VK_CODE_INSERT ) { return VK_INSERT } elsif ( $v_key_code == VK_CODE_DELETE ) { return VK_DELETE } elsif ( $v_key_code == VK_CODE_F1 ) { return VK_F1 } elsif ( $v_key_code == VK_CODE_F2 ) { return VK_F2 } elsif ( $v_key_code == VK_CODE_F3 ) { return VK_F3 } elsif ( $v_key_code == VK_CODE_F4 ) { return VK_F4 } else { return NEXT_get_key } } } elsif ( $mouse && $event_type == 2 ) { my( $x, $y, $button_state, $control_key, $event_flags ) = @event; my $button; if ( ! $event_flags ) { if ( $button_state & LEFTMOST_BUTTON_PRESSED ) { $button = 1; } elsif ( $button_state & RIGHTMOST_BUTTON_PRESSED ) { $button = 3; } elsif ( $button_state & FROM_LEFT_2ND_BUTTON_PRESSED ) { $button = 2; } else { return NEXT_get_key; } } elsif ( $event_flags & MOUSE_WHEELED ) { $button = $button_state >> 24 ? 5 : 4; } else { return NEXT_get_key; } return [ $button, $x, $y ]; } else { return NEXT_get_key; } } sub __set_mode { my ( $self, $config ) = @_; $self->{input} = Win32::Console->new( STD_INPUT_HANDLE ); $self->{old_in_mode} = $self->{input}->Mode(); if ( $config->{mouse} ) { # To make the mouse mode work, QUICK_EDIT_MODE has to be disabled. # https://docs.microsoft.com/en-us/windows/console/setconsolemode: # To disable this mode (QUICK_EDIT_MODE), use ENABLE_EXTENDED_FLAGS (0x0080) without this flag (QUICK_EDIT_MODE). $self->{input}->Mode( !ENABLE_PROCESSED_INPUT|ENABLE_MOUSE_INPUT|0x0080 ); } else { $self->{input}->Mode( !ENABLE_PROCESSED_INPUT ); } if ( $config->{hide_cursor} ) { print hide_cursor(); } return $config->{mouse}; } sub __reset_mode { my ( $self, $config ) = @_; my $fallback_resetmode = ENABLE_PROCESSED_INPUT|ENABLE_LINE_INPUT|ENABLE_ECHO_INPUT; if ( defined $self->{input} ) { if ( defined $self->{old_in_mode} ) { $self->{input}->Mode( $self->{old_in_mode} ); # old_in_mode == 503 == 0x0001|0x0002|0x0004|0x0010|0x0020|0x0040|0x0080|0x0100 delete $self->{old_in_mode}; } else { $self->{input}->Mode( $fallback_resetmode ); } $self->{input}->Flush; } else { my $input = Win32::Console->new( STD_INPUT_HANDLE ); $input->Mode( $fallback_resetmode ); $input->Flush; } print normal(); if ( $config->{hide_cursor} ) { print show_cursor(); } } sub __get_cursor_row { #my ( $self ) = @_; my $abs_cursor_y = ( Win32::Console->new( STD_OUTPUT_HANDLE )->Cursor() )[1]; return $abs_cursor_y || 1; } # 1.642: Last version which uses Win::Console to create all methods. # Since 1.643 Win32::Console::ANSI and ANSI escapes are used. # ENABLE_PROCESSED_INPUT = 0x0001 win32::Console # ENABLE_LINE_INPUT = 0x0002 Win32::Console # ENABLE_ECHO_INPUT = 0x0004 Win32::Console # ENABLE_WINDOW_INPUT = 0x0008 Win32::Console # ENABLE_MOUSE_INPUT = 0x0010 Win32::Console # ENABLE_INSERT_MODE = 0x0020 # ENABLE_QUICK_EDIT_MODE = 0x0040 # ENABLE_EXTENDED_FLAGS = 0x0080 # ENABLE_AUTO_POSITION = 0x0100 ? # ENABLE_VIRTUAL_TERMINAL_INPUT = 0x0200 1; __END__ Term-Choose-1.774/lib/Term/Choose/PaxHeaders/Linux.pm0000644000000000000000000000013215003222473017267 xustar0030 mtime=1745691963.261071587 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/Linux.pm0000644000175000001440000002125615003222473020047 0ustar00mmusers00000000000000package Term::Choose::Linux; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Term::Choose::Constants qw( :all ); use Term::Choose::Screen qw( hide_cursor show_cursor normal ); use constant { SET_ANY_EVENT_MOUSE_1003 => "\e[?1003h", SET_SGR_EXT_MODE_MOUSE_1006 => "\e[?1006h", UNSET_ANY_EVENT_MOUSE_1003 => "\e[?1003l", UNSET_SGR_EXT_MODE_MOUSE_1006 => "\e[?1006l", }; my $Stty = ''; sub new { return bless {}, $_[0]; } sub _getc_wrapper { my ( $timeout ) = @_; if ( TERM_READKEY ) { return Term::ReadKey::ReadKey( $timeout ); } else { # if ( $timeout ) { # my $rin = ''; # vec( $rin, fileno( STDIN ), 1 ) = 1; # my $nfount = select( $rin, undef, undef, $timeout ); # return if ! $nfount; # } return getc(); } } sub __get_key_OS { my ( $self, $mouse ) = @_; my $c1 = _getc_wrapper( 0 ); return if ! defined $c1; if ( $c1 eq "\e" ) { my $c2 = _getc_wrapper( 0.10 ); if ( ! defined $c2 ) { return KEY_ESC; } # unused #\e elsif ( $c2 eq 'O' ) { my $c3 = _getc_wrapper( 0 ); if ( $c3 eq 'A' ) { return VK_UP; } #\eOA elsif ( $c3 eq 'B' ) { return VK_DOWN; } #\eOB elsif ( $c3 eq 'C' ) { return VK_RIGHT; } #\eOC elsif ( $c3 eq 'D' ) { return VK_LEFT; } #\eOD elsif ( $c3 eq 'F' ) { return VK_END; } #\eOF elsif ( $c3 eq 'H' ) { return VK_HOME; } #\eOH elsif ( $c3 eq 'P' ) { return VK_F1; } #\eOP elsif ( $c3 eq 'Q' ) { return VK_F2; } #\eOQ elsif ( $c3 eq 'R' ) { return VK_F3; } #\eOR elsif ( $c3 eq 'S' ) { return VK_F4; } #\eOS elsif ( $c3 eq 'Z' ) { return KEY_BTAB; } #\eOZ } elsif ( $c2 eq '[' ) { my $c3 = _getc_wrapper( 0 ); if ( $c3 eq 'A' ) { return VK_UP; } #\e[A elsif ( $c3 eq 'B' ) { return VK_DOWN; } #\e[B elsif ( $c3 eq 'C' ) { return VK_RIGHT; } #\e[C elsif ( $c3 eq 'D' ) { return VK_LEFT; } #\e[D elsif ( $c3 eq 'F' ) { return VK_END; } #\e[F elsif ( $c3 eq 'H' ) { return VK_HOME; } #\e[H elsif ( $c3 eq 'Z' ) { return KEY_BTAB; } #\e[Z elsif ( $c3 eq '1' ) { my $c4 = _getc_wrapper( 0 ); if ( $c4 eq 'F' ) { return VK_END; } #\e[1F elsif ( $c4 eq 'H' ) { return VK_HOME; } #\e[1H elsif ( $c4 =~ m/^[1234]$/ ) { my $c5 = _getc_wrapper( 0 ); if ( $c5 eq '~' ) { if ( $c4 eq '1' ) { return VK_F1; } #\e[11~ elsif ( $c4 eq '2' ) { return VK_F2; } #\e[12~ elsif ( $c4 eq '3' ) { return VK_F3; } #\e[13~ elsif ( $c4 eq '4' ) { return VK_F4; } #\e[14~ } } elsif ( $c4 eq '~' ) { return VK_HOME; } #\e[1~ } elsif ( $c3 =~ m/^[23456]$/ ) { my $c4 = _getc_wrapper( 0 ); if ( $c4 eq '~' ) { if ( $c3 eq '2' ) { return VK_INSERT; } #\e[2~ elsif ( $c3 eq '3' ) { return VK_DELETE; } #\e[3~ elsif ( $c3 eq '4' ) { return VK_END; } #\e[4~ # elsif ( $c3 eq '5' ) { return VK_PAGE_UP; } #\e[5~ elsif ( $c3 eq '6' ) { return VK_PAGE_DOWN; } #\e[6~ } } # http://invisible-island.net/xterm/ctlseqs/ctlseqs.html elsif ( $c3 eq 'M' && $mouse ) { my $event_type = ord( _getc_wrapper( 0 ) ) - 32; my $x = ord( _getc_wrapper( 0 ) ) - 32; my $y = ord( _getc_wrapper( 0 ) ) - 32; my $button = $self->__mouse_event_to_button( $event_type ); return NEXT_get_key if $button == NEXT_get_key; return [ $button, $x, $y ]; } elsif ( $c3 eq '<' && $mouse ) { # SGR 1006 my $event_type = ''; my $m1; while ( ( $m1 = _getc_wrapper( 0 ) ) =~ m/^[0-9]$/ ) { $event_type .= $m1; } return NEXT_get_key if $m1 ne ';'; my $x = ''; my $m2; while ( ( $m2 = _getc_wrapper( 0 ) ) =~ m/^[0-9]$/ ) { $x .= $m2; } return NEXT_get_key if $m2 ne ';'; my $y = ''; my $m3; while ( ( $m3 = _getc_wrapper( 0 ) ) =~ m/^[0-9]$/ ) { $y .= $m3; } return NEXT_get_key if $m3 !~ m/^[mM]$/; my $button_released = $m3 eq 'm' ? 1 : 0; return NEXT_get_key if $button_released; my $button = $self->__mouse_event_to_button( $event_type ); return NEXT_get_key if $button == NEXT_get_key; return [ $button, $x, $y ]; } } } else { return ord $c1; } return NEXT_get_key; }; sub __mouse_event_to_button { my ( $self, $event_type ) = @_; my $button_drag = ( $event_type & 0x20 ) >> 5; return NEXT_get_key if $button_drag; my $button; my $low_2_bits = $event_type & 0x03; if ( $low_2_bits == 3 ) { $button = 0; } else { if ( $event_type & 0x40 ) { $button = $low_2_bits + 4; # 4,5 } else { $button = $low_2_bits + 1; # 1,2,3 } } return $button; } sub __set_mode { my ( $self, $config ) = @_; if ( $config->{hide_cursor} ) { print hide_cursor(); } my $mode_stty; if ( ! $config->{mode} ) { die "No mode!"; } elsif ( $config->{mode} eq 'ultra-raw' ) { $mode_stty = 'raw'; } elsif ( $config->{mode} eq 'cbreak' ) { $mode_stty = 'cbreak'; } else { die "Invalid mode!"; } if ( TERM_READKEY ) { Term::ReadKey::ReadMode( $config->{mode} ); } else { $Stty = qx(stty --save); chomp $Stty; system( "stty -echo $mode_stty" ) == 0 or die $?; } if ( $config->{mouse} ) { my $return = binmode STDIN, ':raw'; if ( $return ) { print SET_ANY_EVENT_MOUSE_1003; print SET_SGR_EXT_MODE_MOUSE_1006; } else { $config->{mouse} = 0; warn "binmode STDIN, :raw: $!\nmouse-mode disabled\n"; } } return $config->{mouse}; }; sub __reset_mode { my ( $self, $config ) = @_; if ( $config->{mouse} ) { binmode STDIN, ':encoding(UTF-8)' or warn "binmode STDIN, :encoding(UTF-8): $!\n"; print UNSET_SGR_EXT_MODE_MOUSE_1006; print UNSET_ANY_EVENT_MOUSE_1003; } print normal(); if ( TERM_READKEY ) { Term::ReadKey::ReadMode( 'restore' ); } else { if ( $Stty ) { system( "stty $Stty" ) == 0 or die $?; } else { system( "stty sane" ) == 0 or die $?; } } if ( $config->{hide_cursor} ) { print show_cursor(); } } sub __get_cursor_row { #my ( $self ) = @_; my $abs_curs_y; print "\e[6n"; my $c1 = _getc_wrapper( 0 ); if ( defined $c1 && $c1 eq "\e" ) { my $c2 = _getc_wrapper( 0.10 ); if ( defined $c2 && $c2 eq '[' ) { my $c3 = _getc_wrapper( 0 ); if ( $c3 =~ m/^[0-9]$/ ) { my $c4 = _getc_wrapper( 0 ); if ( $c4 =~ m/^[;0-9]$/ ) { my $curs_y = $c3; my $ry = $c4; while ( $ry =~ m/^[0-9]$/ ) { $curs_y .= $ry; $ry = _getc_wrapper( 0 ); } if ( $ry eq ';' ) { #my $curs_x = ''; # unused my $rx = _getc_wrapper( 0 ); while ( $rx =~ m/^[0-9]$/ ) { #$curs_x .= $rx; $rx = _getc_wrapper( 0 ); } if ( $rx eq 'R' ) { $abs_curs_y = $curs_y; } } } } } } return $abs_curs_y || 1; } 1; __END__ Term-Choose-1.774/lib/Term/Choose/PaxHeaders/LineFold0000644000000000000000000000013215003446321017251 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/LineFold/0000755000175000001440000000000015003446321020100 5ustar00mmusers00000000000000Term-Choose-1.774/lib/Term/Choose/LineFold/PaxHeaders/PP0000644000000000000000000000013215003446321017570 xustar0030 mtime=1745767633.701079608 30 atime=1745767633.701079608 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/LineFold/PP/0000755000175000001440000000000015003446321020417 5ustar00mmusers00000000000000Term-Choose-1.774/lib/Term/Choose/LineFold/PP/PaxHeaders/CharWidthAmbiguousWide.pm0000644000000000000000000000013215002170753024547 xustar0030 mtime=1745416683.137242431 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/LineFold/PP/CharWidthAmbiguousWide.pm0000644000175000001440000007727015002170753025336 0ustar00mmusers00000000000000package Term::Choose::LineFold::PP::CharWidthAmbiguousWide; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( table_char_width ); # test with gnome-terminal - ambiguous characters set to wide # Control characters, non-characters and surrogates are removed before using this table. sub table_char_width { [ #[ 0x0, 0x1f, -1], [ 0x20, 0x7e, 1], #[ 0x7f, 0x9f, -1], [ 0xa0, 0xa0, 1], [ 0xa1, 0xa1, 2], [ 0xa2, 0xa3, 1], [ 0xa4, 0xa4, 2], [ 0xa5, 0xa6, 1], [ 0xa7, 0xa8, 2], [ 0xa9, 0xa9, 1], [ 0xaa, 0xaa, 2], [ 0xab, 0xac, 1], [ 0xad, 0xae, 2], [ 0xaf, 0xaf, 1], [ 0xb0, 0xb4, 2], [ 0xb5, 0xb5, 1], [ 0xb6, 0xba, 2], [ 0xbb, 0xbb, 1], [ 0xbc, 0xbf, 2], [ 0xc0, 0xc5, 1], [ 0xc6, 0xc6, 2], [ 0xc7, 0xcf, 1], [ 0xd0, 0xd0, 2], [ 0xd1, 0xd6, 1], [ 0xd7, 0xd8, 2], [ 0xd9, 0xdd, 1], [ 0xde, 0xe1, 2], [ 0xe2, 0xe5, 1], [ 0xe6, 0xe6, 2], [ 0xe7, 0xe7, 1], [ 0xe8, 0xea, 2], [ 0xeb, 0xeb, 1], [ 0xec, 0xed, 2], [ 0xee, 0xef, 1], [ 0xf0, 0xf0, 2], [ 0xf1, 0xf1, 1], [ 0xf2, 0xf3, 2], [ 0xf4, 0xf6, 1], [ 0xf7, 0xfa, 2], [ 0xfb, 0xfb, 1], [ 0xfc, 0xfc, 2], [ 0xfd, 0xfd, 1], [ 0xfe, 0xfe, 2], [ 0xff, 0x100, 1], [ 0x101, 0x101, 2], [ 0x102, 0x110, 1], [ 0x111, 0x111, 2], [ 0x112, 0x112, 1], [ 0x113, 0x113, 2], [ 0x114, 0x11a, 1], [ 0x11b, 0x11b, 2], [ 0x11c, 0x125, 1], [ 0x126, 0x127, 2], [ 0x128, 0x12a, 1], [ 0x12b, 0x12b, 2], [ 0x12c, 0x130, 1], [ 0x131, 0x133, 2], [ 0x134, 0x137, 1], [ 0x138, 0x138, 2], [ 0x139, 0x13e, 1], [ 0x13f, 0x142, 2], [ 0x143, 0x143, 1], [ 0x144, 0x144, 2], [ 0x145, 0x147, 1], [ 0x148, 0x14b, 2], [ 0x14c, 0x14c, 1], [ 0x14d, 0x14d, 2], [ 0x14e, 0x151, 1], [ 0x152, 0x153, 2], [ 0x154, 0x165, 1], [ 0x166, 0x167, 2], [ 0x168, 0x16a, 1], [ 0x16b, 0x16b, 2], [ 0x16c, 0x1cd, 1], [ 0x1ce, 0x1ce, 2], [ 0x1cf, 0x1cf, 1], [ 0x1d0, 0x1d0, 2], [ 0x1d1, 0x1d1, 1], [ 0x1d2, 0x1d2, 2], [ 0x1d3, 0x1d3, 1], [ 0x1d4, 0x1d4, 2], [ 0x1d5, 0x1d5, 1], [ 0x1d6, 0x1d6, 2], [ 0x1d7, 0x1d7, 1], [ 0x1d8, 0x1d8, 2], [ 0x1d9, 0x1d9, 1], [ 0x1da, 0x1da, 2], [ 0x1db, 0x1db, 1], [ 0x1dc, 0x1dc, 2], [ 0x1dd, 0x250, 1], [ 0x251, 0x251, 2], [ 0x252, 0x260, 1], [ 0x261, 0x261, 2], [ 0x262, 0x2c3, 1], [ 0x2c4, 0x2c4, 2], [ 0x2c5, 0x2c6, 1], [ 0x2c7, 0x2c7, 2], [ 0x2c8, 0x2c8, 1], [ 0x2c9, 0x2cb, 2], [ 0x2cc, 0x2cc, 1], [ 0x2cd, 0x2cd, 2], [ 0x2ce, 0x2cf, 1], [ 0x2d0, 0x2d0, 2], [ 0x2d1, 0x2d7, 1], [ 0x2d8, 0x2db, 2], [ 0x2dc, 0x2dc, 1], [ 0x2dd, 0x2dd, 2], [ 0x2de, 0x2de, 1], [ 0x2df, 0x2df, 2], [ 0x2e0, 0x2ff, 1], [ 0x300, 0x36f, 0], [ 0x370, 0x390, 1], [ 0x391, 0x3a1, 2], [ 0x3a2, 0x3a2, 1], [ 0x3a3, 0x3a9, 2], [ 0x3aa, 0x3b0, 1], [ 0x3b1, 0x3c1, 2], [ 0x3c2, 0x3c2, 1], [ 0x3c3, 0x3c9, 2], [ 0x3ca, 0x400, 1], [ 0x401, 0x401, 2], [ 0x402, 0x40f, 1], [ 0x410, 0x44f, 2], [ 0x450, 0x450, 1], [ 0x451, 0x451, 2], [ 0x452, 0x482, 1], [ 0x483, 0x489, 0], [ 0x48a, 0x590, 1], [ 0x591, 0x5bd, 0], [ 0x5be, 0x5be, 1], [ 0x5bf, 0x5bf, 0], [ 0x5c0, 0x5c0, 1], [ 0x5c1, 0x5c2, 0], [ 0x5c3, 0x5c3, 1], [ 0x5c4, 0x5c5, 0], [ 0x5c6, 0x5c6, 1], [ 0x5c7, 0x5c7, 0], [ 0x5c8, 0x60f, 1], [ 0x610, 0x61a, 0], [ 0x61b, 0x61b, 1], [ 0x61c, 0x61c, 0], [ 0x61d, 0x64a, 1], [ 0x64b, 0x65f, 0], [ 0x660, 0x66f, 1], [ 0x670, 0x670, 0], [ 0x671, 0x6d5, 1], [ 0x6d6, 0x6dc, 0], [ 0x6dd, 0x6de, 1], [ 0x6df, 0x6e4, 0], [ 0x6e5, 0x6e6, 1], [ 0x6e7, 0x6e8, 0], [ 0x6e9, 0x6e9, 1], [ 0x6ea, 0x6ed, 0], [ 0x6ee, 0x70e, 1], [ 0x70f, 0x70f, 0], [ 0x710, 0x710, 1], [ 0x711, 0x711, 0], [ 0x712, 0x72f, 1], [ 0x730, 0x74a, 0], [ 0x74b, 0x7a5, 1], [ 0x7a6, 0x7b0, 0], [ 0x7b1, 0x7ea, 1], [ 0x7eb, 0x7f3, 0], [ 0x7f4, 0x7fc, 1], [ 0x7fd, 0x7fd, 0], [ 0x7fe, 0x815, 1], [ 0x816, 0x819, 0], [ 0x81a, 0x81a, 1], [ 0x81b, 0x823, 0], [ 0x824, 0x824, 1], [ 0x825, 0x827, 0], [ 0x828, 0x828, 1], [ 0x829, 0x82d, 0], [ 0x82e, 0x858, 1], [ 0x859, 0x85b, 0], [ 0x85c, 0x896, 1], [ 0x897, 0x89f, 0], [ 0x8a0, 0x8c9, 1], [ 0x8ca, 0x8e1, 0], [ 0x8e2, 0x8e2, 1], [ 0x8e3, 0x902, 0], [ 0x903, 0x939, 1], [ 0x93a, 0x93a, 0], [ 0x93b, 0x93b, 1], [ 0x93c, 0x93c, 0], [ 0x93d, 0x940, 1], [ 0x941, 0x948, 0], [ 0x949, 0x94c, 1], [ 0x94d, 0x94d, 0], [ 0x94e, 0x950, 1], [ 0x951, 0x957, 0], [ 0x958, 0x961, 1], [ 0x962, 0x963, 0], [ 0x964, 0x980, 1], [ 0x981, 0x981, 0], [ 0x982, 0x9bb, 1], [ 0x9bc, 0x9bc, 0], [ 0x9bd, 0x9c0, 1], [ 0x9c1, 0x9c4, 0], [ 0x9c5, 0x9cc, 1], [ 0x9cd, 0x9cd, 0], [ 0x9ce, 0x9e1, 1], [ 0x9e2, 0x9e3, 0], [ 0x9e4, 0x9fd, 1], [ 0x9fe, 0x9fe, 0], [ 0x9ff, 0xa00, 1], [ 0xa01, 0xa02, 0], [ 0xa03, 0xa3b, 1], [ 0xa3c, 0xa3c, 0], [ 0xa3d, 0xa40, 1], [ 0xa41, 0xa42, 0], [ 0xa43, 0xa46, 1], [ 0xa47, 0xa48, 0], [ 0xa49, 0xa4a, 1], [ 0xa4b, 0xa4d, 0], [ 0xa4e, 0xa50, 1], [ 0xa51, 0xa51, 0], [ 0xa52, 0xa6f, 1], [ 0xa70, 0xa71, 0], [ 0xa72, 0xa74, 1], [ 0xa75, 0xa75, 0], [ 0xa76, 0xa80, 1], [ 0xa81, 0xa82, 0], [ 0xa83, 0xabb, 1], [ 0xabc, 0xabc, 0], [ 0xabd, 0xac0, 1], [ 0xac1, 0xac5, 0], [ 0xac6, 0xac6, 1], [ 0xac7, 0xac8, 0], [ 0xac9, 0xacc, 1], [ 0xacd, 0xacd, 0], [ 0xace, 0xae1, 1], [ 0xae2, 0xae3, 0], [ 0xae4, 0xaf9, 1], [ 0xafa, 0xaff, 0], [ 0xb00, 0xb00, 1], [ 0xb01, 0xb01, 0], [ 0xb02, 0xb3b, 1], [ 0xb3c, 0xb3c, 0], [ 0xb3d, 0xb3e, 1], [ 0xb3f, 0xb3f, 0], [ 0xb40, 0xb40, 1], [ 0xb41, 0xb44, 0], [ 0xb45, 0xb4c, 1], [ 0xb4d, 0xb4d, 0], [ 0xb4e, 0xb54, 1], [ 0xb55, 0xb56, 0], [ 0xb57, 0xb61, 1], [ 0xb62, 0xb63, 0], [ 0xb64, 0xb81, 1], [ 0xb82, 0xb82, 0], [ 0xb83, 0xbbf, 1], [ 0xbc0, 0xbc0, 0], [ 0xbc1, 0xbcc, 1], [ 0xbcd, 0xbcd, 0], [ 0xbce, 0xbff, 1], [ 0xc00, 0xc00, 0], [ 0xc01, 0xc03, 1], [ 0xc04, 0xc04, 0], [ 0xc05, 0xc3b, 1], [ 0xc3c, 0xc3c, 0], [ 0xc3d, 0xc3d, 1], [ 0xc3e, 0xc40, 0], [ 0xc41, 0xc45, 1], [ 0xc46, 0xc48, 0], [ 0xc49, 0xc49, 1], [ 0xc4a, 0xc4d, 0], [ 0xc4e, 0xc54, 1], [ 0xc55, 0xc56, 0], [ 0xc57, 0xc61, 1], [ 0xc62, 0xc63, 0], [ 0xc64, 0xc80, 1], [ 0xc81, 0xc81, 0], [ 0xc82, 0xcbb, 1], [ 0xcbc, 0xcbc, 0], [ 0xcbd, 0xcbe, 1], [ 0xcbf, 0xcbf, 0], [ 0xcc0, 0xcc5, 1], [ 0xcc6, 0xcc6, 0], [ 0xcc7, 0xccb, 1], [ 0xccc, 0xccd, 0], [ 0xcce, 0xce1, 1], [ 0xce2, 0xce3, 0], [ 0xce4, 0xcff, 1], [ 0xd00, 0xd01, 0], [ 0xd02, 0xd3a, 1], [ 0xd3b, 0xd3c, 0], [ 0xd3d, 0xd40, 1], [ 0xd41, 0xd44, 0], [ 0xd45, 0xd4c, 1], [ 0xd4d, 0xd4d, 0], [ 0xd4e, 0xd61, 1], [ 0xd62, 0xd63, 0], [ 0xd64, 0xd80, 1], [ 0xd81, 0xd81, 0], [ 0xd82, 0xdc9, 1], [ 0xdca, 0xdca, 0], [ 0xdcb, 0xdd1, 1], [ 0xdd2, 0xdd4, 0], [ 0xdd5, 0xdd5, 1], [ 0xdd6, 0xdd6, 0], [ 0xdd7, 0xe30, 1], [ 0xe31, 0xe31, 0], [ 0xe32, 0xe33, 1], [ 0xe34, 0xe3a, 0], [ 0xe3b, 0xe46, 1], [ 0xe47, 0xe4e, 0], [ 0xe4f, 0xeb0, 1], [ 0xeb1, 0xeb1, 0], [ 0xeb2, 0xeb3, 1], [ 0xeb4, 0xebc, 0], [ 0xebd, 0xec7, 1], [ 0xec8, 0xece, 0], [ 0xecf, 0xf17, 1], [ 0xf18, 0xf19, 0], [ 0xf1a, 0xf34, 1], [ 0xf35, 0xf35, 0], [ 0xf36, 0xf36, 1], [ 0xf37, 0xf37, 0], [ 0xf38, 0xf38, 1], [ 0xf39, 0xf39, 0], [ 0xf3a, 0xf70, 1], [ 0xf71, 0xf7e, 0], [ 0xf7f, 0xf7f, 1], [ 0xf80, 0xf84, 0], [ 0xf85, 0xf85, 1], [ 0xf86, 0xf87, 0], [ 0xf88, 0xf8c, 1], [ 0xf8d, 0xf97, 0], [ 0xf98, 0xf98, 1], [ 0xf99, 0xfbc, 0], [ 0xfbd, 0xfc5, 1], [ 0xfc6, 0xfc6, 0], [ 0xfc7, 0x102c, 1], [ 0x102d, 0x1030, 0], [ 0x1031, 0x1031, 1], [ 0x1032, 0x1037, 0], [ 0x1038, 0x1038, 1], [ 0x1039, 0x103a, 0], [ 0x103b, 0x103c, 1], [ 0x103d, 0x103e, 0], [ 0x103f, 0x1057, 1], [ 0x1058, 0x1059, 0], [ 0x105a, 0x105d, 1], [ 0x105e, 0x1060, 0], [ 0x1061, 0x1070, 1], [ 0x1071, 0x1074, 0], [ 0x1075, 0x1081, 1], [ 0x1082, 0x1082, 0], [ 0x1083, 0x1084, 1], [ 0x1085, 0x1086, 0], [ 0x1087, 0x108c, 1], [ 0x108d, 0x108d, 0], [ 0x108e, 0x109c, 1], [ 0x109d, 0x109d, 0], [ 0x109e, 0x10ff, 1], [ 0x1100, 0x115f, 2], [ 0x1160, 0x11ff, 0], [ 0x1200, 0x135c, 1], [ 0x135d, 0x135f, 0], [ 0x1360, 0x1711, 1], [ 0x1712, 0x1714, 0], [ 0x1715, 0x1731, 1], [ 0x1732, 0x1733, 0], [ 0x1734, 0x1751, 1], [ 0x1752, 0x1753, 0], [ 0x1754, 0x1771, 1], [ 0x1772, 0x1773, 0], [ 0x1774, 0x17b3, 1], [ 0x17b4, 0x17b5, 0], [ 0x17b6, 0x17b6, 1], [ 0x17b7, 0x17bd, 0], [ 0x17be, 0x17c5, 1], [ 0x17c6, 0x17c6, 0], [ 0x17c7, 0x17c8, 1], [ 0x17c9, 0x17d3, 0], [ 0x17d4, 0x17dc, 1], [ 0x17dd, 0x17dd, 0], [ 0x17de, 0x180a, 1], [ 0x180b, 0x180f, 0], [ 0x1810, 0x1884, 1], [ 0x1885, 0x1886, 0], [ 0x1887, 0x18a8, 1], [ 0x18a9, 0x18a9, 0], [ 0x18aa, 0x191f, 1], [ 0x1920, 0x1922, 0], [ 0x1923, 0x1926, 1], [ 0x1927, 0x1928, 0], [ 0x1929, 0x1931, 1], [ 0x1932, 0x1932, 0], [ 0x1933, 0x1938, 1], [ 0x1939, 0x193b, 0], [ 0x193c, 0x1a16, 1], [ 0x1a17, 0x1a18, 0], [ 0x1a19, 0x1a1a, 1], [ 0x1a1b, 0x1a1b, 0], [ 0x1a1c, 0x1a55, 1], [ 0x1a56, 0x1a56, 0], [ 0x1a57, 0x1a57, 1], [ 0x1a58, 0x1a5e, 0], [ 0x1a5f, 0x1a5f, 1], [ 0x1a60, 0x1a60, 0], [ 0x1a61, 0x1a61, 1], [ 0x1a62, 0x1a62, 0], [ 0x1a63, 0x1a64, 1], [ 0x1a65, 0x1a6c, 0], [ 0x1a6d, 0x1a72, 1], [ 0x1a73, 0x1a7c, 0], [ 0x1a7d, 0x1a7e, 1], [ 0x1a7f, 0x1a7f, 0], [ 0x1a80, 0x1aaf, 1], [ 0x1ab0, 0x1ace, 0], [ 0x1acf, 0x1aff, 1], [ 0x1b00, 0x1b03, 0], [ 0x1b04, 0x1b33, 1], [ 0x1b34, 0x1b34, 0], [ 0x1b35, 0x1b35, 1], [ 0x1b36, 0x1b3a, 0], [ 0x1b3b, 0x1b3b, 1], [ 0x1b3c, 0x1b3c, 0], [ 0x1b3d, 0x1b41, 1], [ 0x1b42, 0x1b42, 0], [ 0x1b43, 0x1b6a, 1], [ 0x1b6b, 0x1b73, 0], [ 0x1b74, 0x1b7f, 1], [ 0x1b80, 0x1b81, 0], [ 0x1b82, 0x1ba1, 1], [ 0x1ba2, 0x1ba5, 0], [ 0x1ba6, 0x1ba7, 1], [ 0x1ba8, 0x1ba9, 0], [ 0x1baa, 0x1baa, 1], [ 0x1bab, 0x1bad, 0], [ 0x1bae, 0x1be5, 1], [ 0x1be6, 0x1be6, 0], [ 0x1be7, 0x1be7, 1], [ 0x1be8, 0x1be9, 0], [ 0x1bea, 0x1bec, 1], [ 0x1bed, 0x1bed, 0], [ 0x1bee, 0x1bee, 1], [ 0x1bef, 0x1bf1, 0], [ 0x1bf2, 0x1c2b, 1], [ 0x1c2c, 0x1c33, 0], [ 0x1c34, 0x1c35, 1], [ 0x1c36, 0x1c37, 0], [ 0x1c38, 0x1ccf, 1], [ 0x1cd0, 0x1cd2, 0], [ 0x1cd3, 0x1cd3, 1], [ 0x1cd4, 0x1ce0, 0], [ 0x1ce1, 0x1ce1, 1], [ 0x1ce2, 0x1ce8, 0], [ 0x1ce9, 0x1cec, 1], [ 0x1ced, 0x1ced, 0], [ 0x1cee, 0x1cf3, 1], [ 0x1cf4, 0x1cf4, 0], [ 0x1cf5, 0x1cf7, 1], [ 0x1cf8, 0x1cf9, 0], [ 0x1cfa, 0x1dbf, 1], [ 0x1dc0, 0x1dff, 0], [ 0x1e00, 0x200a, 1], [ 0x200b, 0x200f, 0], [ 0x2010, 0x2010, 2], [ 0x2011, 0x2012, 1], [ 0x2013, 0x2016, 2], [ 0x2017, 0x2017, 1], [ 0x2018, 0x2019, 2], [ 0x201a, 0x201b, 1], [ 0x201c, 0x201d, 2], [ 0x201e, 0x201f, 1], [ 0x2020, 0x2022, 2], [ 0x2023, 0x2023, 1], [ 0x2024, 0x2027, 2], [ 0x2028, 0x2029, 1], [ 0x202a, 0x202e, 0], [ 0x202f, 0x202f, 1], [ 0x2030, 0x2030, 2], [ 0x2031, 0x2031, 1], [ 0x2032, 0x2033, 2], [ 0x2034, 0x2034, 1], [ 0x2035, 0x2035, 2], [ 0x2036, 0x203a, 1], [ 0x203b, 0x203b, 2], [ 0x203c, 0x203d, 1], [ 0x203e, 0x203e, 2], [ 0x203f, 0x205f, 1], [ 0x2060, 0x2064, 0], [ 0x2065, 0x2065, 1], [ 0x2066, 0x206f, 0], [ 0x2070, 0x2073, 1], [ 0x2074, 0x2074, 2], [ 0x2075, 0x207e, 1], [ 0x207f, 0x207f, 2], [ 0x2080, 0x2080, 1], [ 0x2081, 0x2084, 2], [ 0x2085, 0x20ab, 1], [ 0x20ac, 0x20ac, 2], [ 0x20ad, 0x20cf, 1], [ 0x20d0, 0x20f0, 0], [ 0x20f1, 0x2102, 1], [ 0x2103, 0x2103, 2], [ 0x2104, 0x2104, 1], [ 0x2105, 0x2105, 2], [ 0x2106, 0x2108, 1], [ 0x2109, 0x2109, 2], [ 0x210a, 0x2112, 1], [ 0x2113, 0x2113, 2], [ 0x2114, 0x2115, 1], [ 0x2116, 0x2116, 2], [ 0x2117, 0x2120, 1], [ 0x2121, 0x2122, 2], [ 0x2123, 0x2125, 1], [ 0x2126, 0x2126, 2], [ 0x2127, 0x212a, 1], [ 0x212b, 0x212b, 2], [ 0x212c, 0x2152, 1], [ 0x2153, 0x2154, 2], [ 0x2155, 0x215a, 1], [ 0x215b, 0x215e, 2], [ 0x215f, 0x215f, 1], [ 0x2160, 0x216b, 2], [ 0x216c, 0x216f, 1], [ 0x2170, 0x2179, 2], [ 0x217a, 0x2188, 1], [ 0x2189, 0x2189, 2], [ 0x218a, 0x218f, 1], [ 0x2190, 0x2199, 2], [ 0x219a, 0x21b7, 1], [ 0x21b8, 0x21b9, 2], [ 0x21ba, 0x21d1, 1], [ 0x21d2, 0x21d2, 2], [ 0x21d3, 0x21d3, 1], [ 0x21d4, 0x21d4, 2], [ 0x21d5, 0x21e6, 1], [ 0x21e7, 0x21e7, 2], [ 0x21e8, 0x21ff, 1], [ 0x2200, 0x2200, 2], [ 0x2201, 0x2201, 1], [ 0x2202, 0x2203, 2], [ 0x2204, 0x2206, 1], [ 0x2207, 0x2208, 2], [ 0x2209, 0x220a, 1], [ 0x220b, 0x220b, 2], [ 0x220c, 0x220e, 1], [ 0x220f, 0x220f, 2], [ 0x2210, 0x2210, 1], [ 0x2211, 0x2211, 2], [ 0x2212, 0x2214, 1], [ 0x2215, 0x2215, 2], [ 0x2216, 0x2219, 1], [ 0x221a, 0x221a, 2], [ 0x221b, 0x221c, 1], [ 0x221d, 0x2220, 2], [ 0x2221, 0x2222, 1], [ 0x2223, 0x2223, 2], [ 0x2224, 0x2224, 1], [ 0x2225, 0x2225, 2], [ 0x2226, 0x2226, 1], [ 0x2227, 0x222c, 2], [ 0x222d, 0x222d, 1], [ 0x222e, 0x222e, 2], [ 0x222f, 0x2233, 1], [ 0x2234, 0x2237, 2], [ 0x2238, 0x223b, 1], [ 0x223c, 0x223d, 2], [ 0x223e, 0x2247, 1], [ 0x2248, 0x2248, 2], [ 0x2249, 0x224b, 1], [ 0x224c, 0x224c, 2], [ 0x224d, 0x2251, 1], [ 0x2252, 0x2252, 2], [ 0x2253, 0x225f, 1], [ 0x2260, 0x2261, 2], [ 0x2262, 0x2263, 1], [ 0x2264, 0x2267, 2], [ 0x2268, 0x2269, 1], [ 0x226a, 0x226b, 2], [ 0x226c, 0x226d, 1], [ 0x226e, 0x226f, 2], [ 0x2270, 0x2281, 1], [ 0x2282, 0x2283, 2], [ 0x2284, 0x2285, 1], [ 0x2286, 0x2287, 2], [ 0x2288, 0x2294, 1], [ 0x2295, 0x2295, 2], [ 0x2296, 0x2298, 1], [ 0x2299, 0x2299, 2], [ 0x229a, 0x22a4, 1], [ 0x22a5, 0x22a5, 2], [ 0x22a6, 0x22be, 1], [ 0x22bf, 0x22bf, 2], [ 0x22c0, 0x2311, 1], [ 0x2312, 0x2312, 2], [ 0x2313, 0x2319, 1], [ 0x231a, 0x231b, 2], [ 0x231c, 0x2328, 1], [ 0x2329, 0x232a, 2], [ 0x232b, 0x23e8, 1], [ 0x23e9, 0x23ec, 2], [ 0x23ed, 0x23ef, 1], [ 0x23f0, 0x23f0, 2], [ 0x23f1, 0x23f2, 1], [ 0x23f3, 0x23f3, 2], [ 0x23f4, 0x245f, 1], [ 0x2460, 0x24e9, 2], [ 0x24ea, 0x24ea, 1], [ 0x24eb, 0x254b, 2], [ 0x254c, 0x254f, 1], [ 0x2550, 0x2573, 2], [ 0x2574, 0x257f, 1], [ 0x2580, 0x258f, 2], [ 0x2590, 0x2591, 1], [ 0x2592, 0x2595, 2], [ 0x2596, 0x259f, 1], [ 0x25a0, 0x25a1, 2], [ 0x25a2, 0x25a2, 1], [ 0x25a3, 0x25a9, 2], [ 0x25aa, 0x25b1, 1], [ 0x25b2, 0x25b3, 2], [ 0x25b4, 0x25b5, 1], [ 0x25b6, 0x25b7, 2], [ 0x25b8, 0x25bb, 1], [ 0x25bc, 0x25bd, 2], [ 0x25be, 0x25bf, 1], [ 0x25c0, 0x25c1, 2], [ 0x25c2, 0x25c5, 1], [ 0x25c6, 0x25c8, 2], [ 0x25c9, 0x25ca, 1], [ 0x25cb, 0x25cb, 2], [ 0x25cc, 0x25cd, 1], [ 0x25ce, 0x25d1, 2], [ 0x25d2, 0x25e1, 1], [ 0x25e2, 0x25e5, 2], [ 0x25e6, 0x25ee, 1], [ 0x25ef, 0x25ef, 2], [ 0x25f0, 0x25fc, 1], [ 0x25fd, 0x25fe, 2], [ 0x25ff, 0x2604, 1], [ 0x2605, 0x2606, 2], [ 0x2607, 0x2608, 1], [ 0x2609, 0x2609, 2], [ 0x260a, 0x260d, 1], [ 0x260e, 0x260f, 2], [ 0x2610, 0x2613, 1], [ 0x2614, 0x2615, 2], [ 0x2616, 0x261b, 1], [ 0x261c, 0x261c, 2], [ 0x261d, 0x261d, 1], [ 0x261e, 0x261e, 2], [ 0x261f, 0x262f, 1], [ 0x2630, 0x2637, 2], [ 0x2638, 0x263f, 1], [ 0x2640, 0x2640, 2], [ 0x2641, 0x2641, 1], [ 0x2642, 0x2642, 2], [ 0x2643, 0x2647, 1], [ 0x2648, 0x2653, 2], [ 0x2654, 0x265f, 1], [ 0x2660, 0x2661, 2], [ 0x2662, 0x2662, 1], [ 0x2663, 0x2665, 2], [ 0x2666, 0x2666, 1], [ 0x2667, 0x266a, 2], [ 0x266b, 0x266b, 1], [ 0x266c, 0x266d, 2], [ 0x266e, 0x266e, 1], [ 0x266f, 0x266f, 2], [ 0x2670, 0x267e, 1], [ 0x267f, 0x267f, 2], [ 0x2680, 0x2689, 1], [ 0x268a, 0x268f, 2], [ 0x2690, 0x2692, 1], [ 0x2693, 0x2693, 2], [ 0x2694, 0x269d, 1], [ 0x269e, 0x269f, 2], [ 0x26a0, 0x26a0, 1], [ 0x26a1, 0x26a1, 2], [ 0x26a2, 0x26a9, 1], [ 0x26aa, 0x26ab, 2], [ 0x26ac, 0x26bc, 1], [ 0x26bd, 0x26bf, 2], [ 0x26c0, 0x26c3, 1], [ 0x26c4, 0x26e1, 2], [ 0x26e2, 0x26e2, 1], [ 0x26e3, 0x26e3, 2], [ 0x26e4, 0x26e7, 1], [ 0x26e8, 0x26ff, 2], [ 0x2700, 0x2704, 1], [ 0x2705, 0x2705, 2], [ 0x2706, 0x2709, 1], [ 0x270a, 0x270b, 2], [ 0x270c, 0x2727, 1], [ 0x2728, 0x2728, 2], [ 0x2729, 0x273c, 1], [ 0x273d, 0x273d, 2], [ 0x273e, 0x274b, 1], [ 0x274c, 0x274c, 2], [ 0x274d, 0x274d, 1], [ 0x274e, 0x274e, 2], [ 0x274f, 0x2752, 1], [ 0x2753, 0x2755, 2], [ 0x2756, 0x2756, 1], [ 0x2757, 0x2757, 2], [ 0x2758, 0x2775, 1], [ 0x2776, 0x277f, 2], [ 0x2780, 0x2794, 1], [ 0x2795, 0x2797, 2], [ 0x2798, 0x27af, 1], [ 0x27b0, 0x27b0, 2], [ 0x27b1, 0x27be, 1], [ 0x27bf, 0x27bf, 2], [ 0x27c0, 0x2b1a, 1], [ 0x2b1b, 0x2b1c, 2], [ 0x2b1d, 0x2b4f, 1], [ 0x2b50, 0x2b50, 2], [ 0x2b51, 0x2b54, 1], [ 0x2b55, 0x2b59, 2], [ 0x2b5a, 0x2cee, 1], [ 0x2cef, 0x2cf1, 0], [ 0x2cf2, 0x2d7e, 1], [ 0x2d7f, 0x2d7f, 0], [ 0x2d80, 0x2ddf, 1], [ 0x2de0, 0x2dff, 0], [ 0x2e00, 0x2e7f, 1], [ 0x2e80, 0x2e99, 2], [ 0x2e9a, 0x2e9a, 1], [ 0x2e9b, 0x2ef3, 2], [ 0x2ef4, 0x2eff, 1], [ 0x2f00, 0x2fd5, 2], [ 0x2fd6, 0x2fef, 1], [ 0x2ff0, 0x3029, 2], [ 0x302a, 0x302d, 0], [ 0x302e, 0x303e, 2], [ 0x303f, 0x3040, 1], [ 0x3041, 0x3096, 2], [ 0x3097, 0x3098, 1], [ 0x3099, 0x309a, 0], [ 0x309b, 0x30ff, 2], [ 0x3100, 0x3104, 1], [ 0x3105, 0x312f, 2], [ 0x3130, 0x3130, 1], [ 0x3131, 0x318e, 2], [ 0x318f, 0x318f, 1], [ 0x3190, 0x31e5, 2], [ 0x31e6, 0x31ee, 1], [ 0x31ef, 0x321e, 2], [ 0x321f, 0x321f, 1], [ 0x3220, 0xa48c, 2], [ 0xa48d, 0xa48f, 1], [ 0xa490, 0xa4c6, 2], [ 0xa4c7, 0xa66e, 1], [ 0xa66f, 0xa672, 0], [ 0xa673, 0xa673, 1], [ 0xa674, 0xa67d, 0], [ 0xa67e, 0xa69d, 1], [ 0xa69e, 0xa69f, 0], [ 0xa6a0, 0xa6ef, 1], [ 0xa6f0, 0xa6f1, 0], [ 0xa6f2, 0xa801, 1], [ 0xa802, 0xa802, 0], [ 0xa803, 0xa805, 1], [ 0xa806, 0xa806, 0], [ 0xa807, 0xa80a, 1], [ 0xa80b, 0xa80b, 0], [ 0xa80c, 0xa824, 1], [ 0xa825, 0xa826, 0], [ 0xa827, 0xa82b, 1], [ 0xa82c, 0xa82c, 0], [ 0xa82d, 0xa8c3, 1], [ 0xa8c4, 0xa8c5, 0], [ 0xa8c6, 0xa8df, 1], [ 0xa8e0, 0xa8f1, 0], [ 0xa8f2, 0xa8fe, 1], [ 0xa8ff, 0xa8ff, 0], [ 0xa900, 0xa925, 1], [ 0xa926, 0xa92d, 0], [ 0xa92e, 0xa946, 1], [ 0xa947, 0xa951, 0], [ 0xa952, 0xa95f, 1], [ 0xa960, 0xa97c, 2], [ 0xa97d, 0xa97f, 1], [ 0xa980, 0xa982, 0], [ 0xa983, 0xa9b2, 1], [ 0xa9b3, 0xa9b3, 0], [ 0xa9b4, 0xa9b5, 1], [ 0xa9b6, 0xa9b9, 0], [ 0xa9ba, 0xa9bb, 1], [ 0xa9bc, 0xa9bd, 0], [ 0xa9be, 0xa9e4, 1], [ 0xa9e5, 0xa9e5, 0], [ 0xa9e6, 0xaa28, 1], [ 0xaa29, 0xaa2e, 0], [ 0xaa2f, 0xaa30, 1], [ 0xaa31, 0xaa32, 0], [ 0xaa33, 0xaa34, 1], [ 0xaa35, 0xaa36, 0], [ 0xaa37, 0xaa42, 1], [ 0xaa43, 0xaa43, 0], [ 0xaa44, 0xaa4b, 1], [ 0xaa4c, 0xaa4c, 0], [ 0xaa4d, 0xaa7b, 1], [ 0xaa7c, 0xaa7c, 0], [ 0xaa7d, 0xaaaf, 1], [ 0xaab0, 0xaab0, 0], [ 0xaab1, 0xaab1, 1], [ 0xaab2, 0xaab4, 0], [ 0xaab5, 0xaab6, 1], [ 0xaab7, 0xaab8, 0], [ 0xaab9, 0xaabd, 1], [ 0xaabe, 0xaabf, 0], [ 0xaac0, 0xaac0, 1], [ 0xaac1, 0xaac1, 0], [ 0xaac2, 0xaaeb, 1], [ 0xaaec, 0xaaed, 0], [ 0xaaee, 0xaaf5, 1], [ 0xaaf6, 0xaaf6, 0], [ 0xaaf7, 0xabe4, 1], [ 0xabe5, 0xabe5, 0], [ 0xabe6, 0xabe7, 1], [ 0xabe8, 0xabe8, 0], [ 0xabe9, 0xabec, 1], [ 0xabed, 0xabed, 0], [ 0xabee, 0xabff, 1], [ 0xac00, 0xd7a3, 2], [ 0xd7a4, 0xd7af, 1], [ 0xd7b0, 0xd7ff, 0], #[ 0xd800, 0xdfff, -1], [ 0xe000, 0xfaff, 2], [ 0xfb00, 0xfb1d, 1], [ 0xfb1e, 0xfb1e, 0], [ 0xfb1f, 0xfdff, 1], [ 0xfe00, 0xfe0f, 0], [ 0xfe10, 0xfe19, 2], [ 0xfe1a, 0xfe1f, 1], [ 0xfe20, 0xfe2f, 0], [ 0xfe30, 0xfe52, 2], [ 0xfe53, 0xfe53, 1], [ 0xfe54, 0xfe66, 2], [ 0xfe67, 0xfe67, 1], [ 0xfe68, 0xfe6b, 2], [ 0xfe6c, 0xfefe, 1], [ 0xfeff, 0xfeff, 0], [ 0xff00, 0xff00, 1], [ 0xff01, 0xff60, 2], [ 0xff61, 0xffdf, 1], [ 0xffe0, 0xffe6, 2], [ 0xffe7, 0xfff8, 1], [ 0xfff9, 0xfffb, 0], [ 0xfffc, 0xfffc, 1], [ 0xfffd, 0xfffd, 2], [ 0xfffe, 0x101fc, 1], [ 0x101fd, 0x101fd, 0], [ 0x101fe, 0x102df, 1], [ 0x102e0, 0x102e0, 0], [ 0x102e1, 0x10375, 1], [ 0x10376, 0x1037a, 0], [ 0x1037b, 0x10a00, 1], [ 0x10a01, 0x10a03, 0], [ 0x10a04, 0x10a04, 1], [ 0x10a05, 0x10a06, 0], [ 0x10a07, 0x10a0b, 1], [ 0x10a0c, 0x10a0f, 0], [ 0x10a10, 0x10a37, 1], [ 0x10a38, 0x10a3a, 0], [ 0x10a3b, 0x10a3e, 1], [ 0x10a3f, 0x10a3f, 0], [ 0x10a40, 0x10ae4, 1], [ 0x10ae5, 0x10ae6, 0], [ 0x10ae7, 0x10d23, 1], [ 0x10d24, 0x10d27, 0], [ 0x10d28, 0x10d68, 1], [ 0x10d69, 0x10d6d, 0], [ 0x10d6e, 0x10eaa, 1], [ 0x10eab, 0x10eac, 0], [ 0x10ead, 0x10efb, 1], [ 0x10efc, 0x10eff, 0], [ 0x10f00, 0x10f45, 1], [ 0x10f46, 0x10f50, 0], [ 0x10f51, 0x10f81, 1], [ 0x10f82, 0x10f85, 0], [ 0x10f86, 0x11000, 1], [ 0x11001, 0x11001, 0], [ 0x11002, 0x11037, 1], [ 0x11038, 0x11046, 0], [ 0x11047, 0x1106f, 1], [ 0x11070, 0x11070, 0], [ 0x11071, 0x11072, 1], [ 0x11073, 0x11074, 0], [ 0x11075, 0x1107e, 1], [ 0x1107f, 0x11081, 0], [ 0x11082, 0x110b2, 1], [ 0x110b3, 0x110b6, 0], [ 0x110b7, 0x110b8, 1], [ 0x110b9, 0x110ba, 0], [ 0x110bb, 0x110bc, 1], [ 0x110bd, 0x110bd, 0], [ 0x110be, 0x110c1, 1], [ 0x110c2, 0x110c2, 0], [ 0x110c3, 0x110cc, 1], [ 0x110cd, 0x110cd, 0], [ 0x110ce, 0x110ff, 1], [ 0x11100, 0x11102, 0], [ 0x11103, 0x11126, 1], [ 0x11127, 0x1112b, 0], [ 0x1112c, 0x1112c, 1], [ 0x1112d, 0x11134, 0], [ 0x11135, 0x11172, 1], [ 0x11173, 0x11173, 0], [ 0x11174, 0x1117f, 1], [ 0x11180, 0x11181, 0], [ 0x11182, 0x111b5, 1], [ 0x111b6, 0x111be, 0], [ 0x111bf, 0x111c8, 1], [ 0x111c9, 0x111cc, 0], [ 0x111cd, 0x111ce, 1], [ 0x111cf, 0x111cf, 0], [ 0x111d0, 0x1122e, 1], [ 0x1122f, 0x11231, 0], [ 0x11232, 0x11233, 1], [ 0x11234, 0x11234, 0], [ 0x11235, 0x11235, 1], [ 0x11236, 0x11237, 0], [ 0x11238, 0x1123d, 1], [ 0x1123e, 0x1123e, 0], [ 0x1123f, 0x11240, 1], [ 0x11241, 0x11241, 0], [ 0x11242, 0x112de, 1], [ 0x112df, 0x112df, 0], [ 0x112e0, 0x112e2, 1], [ 0x112e3, 0x112ea, 0], [ 0x112eb, 0x112ff, 1], [ 0x11300, 0x11301, 0], [ 0x11302, 0x1133a, 1], [ 0x1133b, 0x1133c, 0], [ 0x1133d, 0x1133f, 1], [ 0x11340, 0x11340, 0], [ 0x11341, 0x11365, 1], [ 0x11366, 0x1136c, 0], [ 0x1136d, 0x1136f, 1], [ 0x11370, 0x11374, 0], [ 0x11375, 0x113ba, 1], [ 0x113bb, 0x113c0, 0], [ 0x113c1, 0x113cd, 1], [ 0x113ce, 0x113ce, 0], [ 0x113cf, 0x113cf, 1], [ 0x113d0, 0x113d0, 0], [ 0x113d1, 0x113d1, 1], [ 0x113d2, 0x113d2, 0], [ 0x113d3, 0x113e0, 1], [ 0x113e1, 0x113e2, 0], [ 0x113e3, 0x11437, 1], [ 0x11438, 0x1143f, 0], [ 0x11440, 0x11441, 1], [ 0x11442, 0x11444, 0], [ 0x11445, 0x11445, 1], [ 0x11446, 0x11446, 0], [ 0x11447, 0x1145d, 1], [ 0x1145e, 0x1145e, 0], [ 0x1145f, 0x114b2, 1], [ 0x114b3, 0x114b8, 0], [ 0x114b9, 0x114b9, 1], [ 0x114ba, 0x114ba, 0], [ 0x114bb, 0x114be, 1], [ 0x114bf, 0x114c0, 0], [ 0x114c1, 0x114c1, 1], [ 0x114c2, 0x114c3, 0], [ 0x114c4, 0x115b1, 1], [ 0x115b2, 0x115b5, 0], [ 0x115b6, 0x115bb, 1], [ 0x115bc, 0x115bd, 0], [ 0x115be, 0x115be, 1], [ 0x115bf, 0x115c0, 0], [ 0x115c1, 0x115db, 1], [ 0x115dc, 0x115dd, 0], [ 0x115de, 0x11632, 1], [ 0x11633, 0x1163a, 0], [ 0x1163b, 0x1163c, 1], [ 0x1163d, 0x1163d, 0], [ 0x1163e, 0x1163e, 1], [ 0x1163f, 0x11640, 0], [ 0x11641, 0x116aa, 1], [ 0x116ab, 0x116ab, 0], [ 0x116ac, 0x116ac, 1], [ 0x116ad, 0x116ad, 0], [ 0x116ae, 0x116af, 1], [ 0x116b0, 0x116b5, 0], [ 0x116b6, 0x116b6, 1], [ 0x116b7, 0x116b7, 0], [ 0x116b8, 0x1171c, 1], [ 0x1171d, 0x1171d, 0], [ 0x1171e, 0x1171e, 1], [ 0x1171f, 0x1171f, 0], [ 0x11720, 0x11721, 1], [ 0x11722, 0x11725, 0], [ 0x11726, 0x11726, 1], [ 0x11727, 0x1172b, 0], [ 0x1172c, 0x1182e, 1], [ 0x1182f, 0x11837, 0], [ 0x11838, 0x11838, 1], [ 0x11839, 0x1183a, 0], [ 0x1183b, 0x1193a, 1], [ 0x1193b, 0x1193c, 0], [ 0x1193d, 0x1193d, 1], [ 0x1193e, 0x1193e, 0], [ 0x1193f, 0x11942, 1], [ 0x11943, 0x11943, 0], [ 0x11944, 0x119d3, 1], [ 0x119d4, 0x119d7, 0], [ 0x119d8, 0x119d9, 1], [ 0x119da, 0x119db, 0], [ 0x119dc, 0x119df, 1], [ 0x119e0, 0x119e0, 0], [ 0x119e1, 0x11a00, 1], [ 0x11a01, 0x11a0a, 0], [ 0x11a0b, 0x11a32, 1], [ 0x11a33, 0x11a38, 0], [ 0x11a39, 0x11a3a, 1], [ 0x11a3b, 0x11a3e, 0], [ 0x11a3f, 0x11a46, 1], [ 0x11a47, 0x11a47, 0], [ 0x11a48, 0x11a50, 1], [ 0x11a51, 0x11a56, 0], [ 0x11a57, 0x11a58, 1], [ 0x11a59, 0x11a5b, 0], [ 0x11a5c, 0x11a89, 1], [ 0x11a8a, 0x11a96, 0], [ 0x11a97, 0x11a97, 1], [ 0x11a98, 0x11a99, 0], [ 0x11a9a, 0x11c2f, 1], [ 0x11c30, 0x11c36, 0], [ 0x11c37, 0x11c37, 1], [ 0x11c38, 0x11c3d, 0], [ 0x11c3e, 0x11c3e, 1], [ 0x11c3f, 0x11c3f, 0], [ 0x11c40, 0x11c91, 1], [ 0x11c92, 0x11ca7, 0], [ 0x11ca8, 0x11ca9, 1], [ 0x11caa, 0x11cb0, 0], [ 0x11cb1, 0x11cb1, 1], [ 0x11cb2, 0x11cb3, 0], [ 0x11cb4, 0x11cb4, 1], [ 0x11cb5, 0x11cb6, 0], [ 0x11cb7, 0x11d30, 1], [ 0x11d31, 0x11d36, 0], [ 0x11d37, 0x11d39, 1], [ 0x11d3a, 0x11d3a, 0], [ 0x11d3b, 0x11d3b, 1], [ 0x11d3c, 0x11d3d, 0], [ 0x11d3e, 0x11d3e, 1], [ 0x11d3f, 0x11d45, 0], [ 0x11d46, 0x11d46, 1], [ 0x11d47, 0x11d47, 0], [ 0x11d48, 0x11d8f, 1], [ 0x11d90, 0x11d91, 0], [ 0x11d92, 0x11d94, 1], [ 0x11d95, 0x11d95, 0], [ 0x11d96, 0x11d96, 1], [ 0x11d97, 0x11d97, 0], [ 0x11d98, 0x11ef2, 1], [ 0x11ef3, 0x11ef4, 0], [ 0x11ef5, 0x11eff, 1], [ 0x11f00, 0x11f01, 0], [ 0x11f02, 0x11f35, 1], [ 0x11f36, 0x11f3a, 0], [ 0x11f3b, 0x11f3f, 1], [ 0x11f40, 0x11f40, 0], [ 0x11f41, 0x11f41, 1], [ 0x11f42, 0x11f42, 0], [ 0x11f43, 0x11f59, 1], [ 0x11f5a, 0x11f5a, 0], [ 0x11f5b, 0x1342f, 1], [ 0x13430, 0x13440, 0], [ 0x13441, 0x13446, 1], [ 0x13447, 0x13455, 0], [ 0x13456, 0x1611d, 1], [ 0x1611e, 0x16129, 0], [ 0x1612a, 0x1612c, 1], [ 0x1612d, 0x1612f, 0], [ 0x16130, 0x16aef, 1], [ 0x16af0, 0x16af4, 0], [ 0x16af5, 0x16b2f, 1], [ 0x16b30, 0x16b36, 0], [ 0x16b37, 0x16f4e, 1], [ 0x16f4f, 0x16f4f, 0], [ 0x16f50, 0x16f8e, 1], [ 0x16f8f, 0x16f92, 0], [ 0x16f93, 0x16fdf, 1], [ 0x16fe0, 0x16fe3, 2], [ 0x16fe4, 0x16fe4, 0], [ 0x16fe5, 0x16fef, 1], [ 0x16ff0, 0x16ff1, 2], [ 0x16ff2, 0x16fff, 1], [ 0x17000, 0x187f7, 2], [ 0x187f8, 0x187ff, 1], [ 0x18800, 0x18cd5, 2], [ 0x18cd6, 0x18cfe, 1], [ 0x18cff, 0x18d08, 2], [ 0x18d09, 0x1afef, 1], [ 0x1aff0, 0x1aff3, 2], [ 0x1aff4, 0x1aff4, 1], [ 0x1aff5, 0x1affb, 2], [ 0x1affc, 0x1affc, 1], [ 0x1affd, 0x1affe, 2], [ 0x1afff, 0x1afff, 1], [ 0x1b000, 0x1b122, 2], [ 0x1b123, 0x1b131, 1], [ 0x1b132, 0x1b132, 2], [ 0x1b133, 0x1b14f, 1], [ 0x1b150, 0x1b152, 2], [ 0x1b153, 0x1b154, 1], [ 0x1b155, 0x1b155, 2], [ 0x1b156, 0x1b163, 1], [ 0x1b164, 0x1b167, 2], [ 0x1b168, 0x1b16f, 1], [ 0x1b170, 0x1b2fb, 2], [ 0x1b2fc, 0x1bc9c, 1], [ 0x1bc9d, 0x1bc9e, 0], [ 0x1bc9f, 0x1bc9f, 1], [ 0x1bca0, 0x1bca3, 0], [ 0x1bca4, 0x1ceff, 1], [ 0x1cf00, 0x1cf2d, 0], [ 0x1cf2e, 0x1cf2f, 1], [ 0x1cf30, 0x1cf46, 0], [ 0x1cf47, 0x1d166, 1], [ 0x1d167, 0x1d169, 0], [ 0x1d16a, 0x1d172, 1], [ 0x1d173, 0x1d182, 0], [ 0x1d183, 0x1d184, 1], [ 0x1d185, 0x1d18b, 0], [ 0x1d18c, 0x1d1a9, 1], [ 0x1d1aa, 0x1d1ad, 0], [ 0x1d1ae, 0x1d241, 1], [ 0x1d242, 0x1d244, 0], [ 0x1d245, 0x1d2ff, 1], [ 0x1d300, 0x1d356, 2], [ 0x1d357, 0x1d35f, 1], [ 0x1d360, 0x1d376, 2], [ 0x1d377, 0x1d9ff, 1], [ 0x1da00, 0x1da36, 0], [ 0x1da37, 0x1da3a, 1], [ 0x1da3b, 0x1da6c, 0], [ 0x1da6d, 0x1da74, 1], [ 0x1da75, 0x1da75, 0], [ 0x1da76, 0x1da83, 1], [ 0x1da84, 0x1da84, 0], [ 0x1da85, 0x1da9a, 1], [ 0x1da9b, 0x1da9f, 0], [ 0x1daa0, 0x1daa0, 1], [ 0x1daa1, 0x1daaf, 0], [ 0x1dab0, 0x1dfff, 1], [ 0x1e000, 0x1e006, 0], [ 0x1e007, 0x1e007, 1], [ 0x1e008, 0x1e018, 0], [ 0x1e019, 0x1e01a, 1], [ 0x1e01b, 0x1e021, 0], [ 0x1e022, 0x1e022, 1], [ 0x1e023, 0x1e024, 0], [ 0x1e025, 0x1e025, 1], [ 0x1e026, 0x1e02a, 0], [ 0x1e02b, 0x1e08e, 1], [ 0x1e08f, 0x1e08f, 0], [ 0x1e090, 0x1e12f, 1], [ 0x1e130, 0x1e136, 0], [ 0x1e137, 0x1e2ad, 1], [ 0x1e2ae, 0x1e2ae, 0], [ 0x1e2af, 0x1e2eb, 1], [ 0x1e2ec, 0x1e2ef, 0], [ 0x1e2f0, 0x1e4eb, 1], [ 0x1e4ec, 0x1e4ef, 0], [ 0x1e4f0, 0x1e5ed, 1], [ 0x1e5ee, 0x1e5ef, 0], [ 0x1e5f0, 0x1e8cf, 1], [ 0x1e8d0, 0x1e8d6, 0], [ 0x1e8d7, 0x1e943, 1], [ 0x1e944, 0x1e94a, 0], [ 0x1e94b, 0x1f003, 1], [ 0x1f004, 0x1f004, 2], [ 0x1f005, 0x1f0ce, 1], [ 0x1f0cf, 0x1f0cf, 2], [ 0x1f0d0, 0x1f0ff, 1], [ 0x1f100, 0x1f10a, 2], [ 0x1f10b, 0x1f10f, 1], [ 0x1f110, 0x1f12d, 2], [ 0x1f12e, 0x1f12f, 1], [ 0x1f130, 0x1f169, 2], [ 0x1f16a, 0x1f16f, 1], [ 0x1f170, 0x1f1ac, 2], [ 0x1f1ad, 0x1f1ff, 1], [ 0x1f200, 0x1f202, 2], [ 0x1f203, 0x1f20f, 1], [ 0x1f210, 0x1f23b, 2], [ 0x1f23c, 0x1f23f, 1], [ 0x1f240, 0x1f248, 2], [ 0x1f249, 0x1f24f, 1], [ 0x1f250, 0x1f251, 2], [ 0x1f252, 0x1f25f, 1], [ 0x1f260, 0x1f265, 2], [ 0x1f266, 0x1f2ff, 1], [ 0x1f300, 0x1f320, 2], [ 0x1f321, 0x1f32c, 1], [ 0x1f32d, 0x1f335, 2], [ 0x1f336, 0x1f336, 1], [ 0x1f337, 0x1f37c, 2], [ 0x1f37d, 0x1f37d, 1], [ 0x1f37e, 0x1f393, 2], [ 0x1f394, 0x1f39f, 1], [ 0x1f3a0, 0x1f3ca, 2], [ 0x1f3cb, 0x1f3ce, 1], [ 0x1f3cf, 0x1f3d3, 2], [ 0x1f3d4, 0x1f3df, 1], [ 0x1f3e0, 0x1f3f0, 2], [ 0x1f3f1, 0x1f3f3, 1], [ 0x1f3f4, 0x1f3f4, 2], [ 0x1f3f5, 0x1f3f7, 1], [ 0x1f3f8, 0x1f43e, 2], [ 0x1f43f, 0x1f43f, 1], [ 0x1f440, 0x1f440, 2], [ 0x1f441, 0x1f441, 1], [ 0x1f442, 0x1f4fc, 2], [ 0x1f4fd, 0x1f4fe, 1], [ 0x1f4ff, 0x1f53d, 2], [ 0x1f53e, 0x1f54a, 1], [ 0x1f54b, 0x1f54e, 2], [ 0x1f54f, 0x1f54f, 1], [ 0x1f550, 0x1f567, 2], [ 0x1f568, 0x1f579, 1], [ 0x1f57a, 0x1f57a, 2], [ 0x1f57b, 0x1f594, 1], [ 0x1f595, 0x1f596, 2], [ 0x1f597, 0x1f5a3, 1], [ 0x1f5a4, 0x1f5a4, 2], [ 0x1f5a5, 0x1f5fa, 1], [ 0x1f5fb, 0x1f64f, 2], [ 0x1f650, 0x1f67f, 1], [ 0x1f680, 0x1f6c5, 2], [ 0x1f6c6, 0x1f6cb, 1], [ 0x1f6cc, 0x1f6cc, 2], [ 0x1f6cd, 0x1f6cf, 1], [ 0x1f6d0, 0x1f6d2, 2], [ 0x1f6d3, 0x1f6d4, 1], [ 0x1f6d5, 0x1f6d7, 2], [ 0x1f6d8, 0x1f6db, 1], [ 0x1f6dc, 0x1f6df, 2], [ 0x1f6e0, 0x1f6ea, 1], [ 0x1f6eb, 0x1f6ec, 2], [ 0x1f6ed, 0x1f6f3, 1], [ 0x1f6f4, 0x1f6fc, 2], [ 0x1f6fd, 0x1f7df, 1], [ 0x1f7e0, 0x1f7eb, 2], [ 0x1f7ec, 0x1f7ef, 1], [ 0x1f7f0, 0x1f7f0, 2], [ 0x1f7f1, 0x1f90b, 1], [ 0x1f90c, 0x1f93a, 2], [ 0x1f93b, 0x1f93b, 1], [ 0x1f93c, 0x1f945, 2], [ 0x1f946, 0x1f946, 1], [ 0x1f947, 0x1f9ff, 2], [ 0x1fa00, 0x1fa6f, 1], [ 0x1fa70, 0x1fa7c, 2], [ 0x1fa7d, 0x1fa7f, 1], [ 0x1fa80, 0x1fa89, 2], [ 0x1fa8a, 0x1fa8e, 1], [ 0x1fa8f, 0x1fac6, 2], [ 0x1fac7, 0x1facd, 1], [ 0x1face, 0x1fadc, 2], [ 0x1fadd, 0x1fade, 1], [ 0x1fadf, 0x1fae9, 2], [ 0x1faea, 0x1faef, 1], [ 0x1faf0, 0x1faf8, 2], [ 0x1faf9, 0x1ffff, 1], [ 0x20000, 0x2fffd, 2], [ 0x2fffe, 0x2ffff, 1], [ 0x30000, 0x3fffd, 2], [ 0x3fffe, 0xe0000, 1], [ 0xe0001, 0xe0001, 0], [ 0xe0002, 0xe001f, 1], [ 0xe0020, 0xe007f, 0], [ 0xe0080, 0xe00ff, 1], [ 0xe0100, 0xe01ef, 0], [ 0xe01f0, 0xeffff, 1], [ 0xf0000, 0xffffd, 2], [ 0xffffe, 0xfffff, 1], [0x100000, 0x10fffd, 2], [0x10fffe, 0x10ffff, 1], ] } 1; Term-Choose-1.774/lib/Term/Choose/LineFold/PP/PaxHeaders/CharWidthDefault.pm0000644000000000000000000000013215002170762023367 xustar0030 mtime=1745416690.721099532 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/LineFold/PP/CharWidthDefault.pm0000644000175000001440000006046615002170762024155 0ustar00mmusers00000000000000package Term::Choose::LineFold::PP::CharWidthDefault; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( table_char_width ); # test with gnome-terminal - ambiguous characters set to narrow # Control characters, non-characters and surrogates are removed before using this table. sub table_char_width { [ #[ 0x0, 0x1f, -1], [ 0x20, 0x7e, 1], #[ 0x7f, 0x9f, -1], [ 0xa0, 0x2ff, 1], [ 0x300, 0x36f, 0], [ 0x370, 0x482, 1], [ 0x483, 0x489, 0], [ 0x48a, 0x590, 1], [ 0x591, 0x5bd, 0], [ 0x5be, 0x5be, 1], [ 0x5bf, 0x5bf, 0], [ 0x5c0, 0x5c0, 1], [ 0x5c1, 0x5c2, 0], [ 0x5c3, 0x5c3, 1], [ 0x5c4, 0x5c5, 0], [ 0x5c6, 0x5c6, 1], [ 0x5c7, 0x5c7, 0], [ 0x5c8, 0x60f, 1], [ 0x610, 0x61a, 0], [ 0x61b, 0x61b, 1], [ 0x61c, 0x61c, 0], [ 0x61d, 0x64a, 1], [ 0x64b, 0x65f, 0], [ 0x660, 0x66f, 1], [ 0x670, 0x670, 0], [ 0x671, 0x6d5, 1], [ 0x6d6, 0x6dc, 0], [ 0x6dd, 0x6de, 1], [ 0x6df, 0x6e4, 0], [ 0x6e5, 0x6e6, 1], [ 0x6e7, 0x6e8, 0], [ 0x6e9, 0x6e9, 1], [ 0x6ea, 0x6ed, 0], [ 0x6ee, 0x70e, 1], [ 0x70f, 0x70f, 0], [ 0x710, 0x710, 1], [ 0x711, 0x711, 0], [ 0x712, 0x72f, 1], [ 0x730, 0x74a, 0], [ 0x74b, 0x7a5, 1], [ 0x7a6, 0x7b0, 0], [ 0x7b1, 0x7ea, 1], [ 0x7eb, 0x7f3, 0], [ 0x7f4, 0x7fc, 1], [ 0x7fd, 0x7fd, 0], [ 0x7fe, 0x815, 1], [ 0x816, 0x819, 0], [ 0x81a, 0x81a, 1], [ 0x81b, 0x823, 0], [ 0x824, 0x824, 1], [ 0x825, 0x827, 0], [ 0x828, 0x828, 1], [ 0x829, 0x82d, 0], [ 0x82e, 0x858, 1], [ 0x859, 0x85b, 0], [ 0x85c, 0x896, 1], [ 0x897, 0x89f, 0], [ 0x8a0, 0x8c9, 1], [ 0x8ca, 0x8e1, 0], [ 0x8e2, 0x8e2, 1], [ 0x8e3, 0x902, 0], [ 0x903, 0x939, 1], [ 0x93a, 0x93a, 0], [ 0x93b, 0x93b, 1], [ 0x93c, 0x93c, 0], [ 0x93d, 0x940, 1], [ 0x941, 0x948, 0], [ 0x949, 0x94c, 1], [ 0x94d, 0x94d, 0], [ 0x94e, 0x950, 1], [ 0x951, 0x957, 0], [ 0x958, 0x961, 1], [ 0x962, 0x963, 0], [ 0x964, 0x980, 1], [ 0x981, 0x981, 0], [ 0x982, 0x9bb, 1], [ 0x9bc, 0x9bc, 0], [ 0x9bd, 0x9c0, 1], [ 0x9c1, 0x9c4, 0], [ 0x9c5, 0x9cc, 1], [ 0x9cd, 0x9cd, 0], [ 0x9ce, 0x9e1, 1], [ 0x9e2, 0x9e3, 0], [ 0x9e4, 0x9fd, 1], [ 0x9fe, 0x9fe, 0], [ 0x9ff, 0xa00, 1], [ 0xa01, 0xa02, 0], [ 0xa03, 0xa3b, 1], [ 0xa3c, 0xa3c, 0], [ 0xa3d, 0xa40, 1], [ 0xa41, 0xa42, 0], [ 0xa43, 0xa46, 1], [ 0xa47, 0xa48, 0], [ 0xa49, 0xa4a, 1], [ 0xa4b, 0xa4d, 0], [ 0xa4e, 0xa50, 1], [ 0xa51, 0xa51, 0], [ 0xa52, 0xa6f, 1], [ 0xa70, 0xa71, 0], [ 0xa72, 0xa74, 1], [ 0xa75, 0xa75, 0], [ 0xa76, 0xa80, 1], [ 0xa81, 0xa82, 0], [ 0xa83, 0xabb, 1], [ 0xabc, 0xabc, 0], [ 0xabd, 0xac0, 1], [ 0xac1, 0xac5, 0], [ 0xac6, 0xac6, 1], [ 0xac7, 0xac8, 0], [ 0xac9, 0xacc, 1], [ 0xacd, 0xacd, 0], [ 0xace, 0xae1, 1], [ 0xae2, 0xae3, 0], [ 0xae4, 0xaf9, 1], [ 0xafa, 0xaff, 0], [ 0xb00, 0xb00, 1], [ 0xb01, 0xb01, 0], [ 0xb02, 0xb3b, 1], [ 0xb3c, 0xb3c, 0], [ 0xb3d, 0xb3e, 1], [ 0xb3f, 0xb3f, 0], [ 0xb40, 0xb40, 1], [ 0xb41, 0xb44, 0], [ 0xb45, 0xb4c, 1], [ 0xb4d, 0xb4d, 0], [ 0xb4e, 0xb54, 1], [ 0xb55, 0xb56, 0], [ 0xb57, 0xb61, 1], [ 0xb62, 0xb63, 0], [ 0xb64, 0xb81, 1], [ 0xb82, 0xb82, 0], [ 0xb83, 0xbbf, 1], [ 0xbc0, 0xbc0, 0], [ 0xbc1, 0xbcc, 1], [ 0xbcd, 0xbcd, 0], [ 0xbce, 0xbff, 1], [ 0xc00, 0xc00, 0], [ 0xc01, 0xc03, 1], [ 0xc04, 0xc04, 0], [ 0xc05, 0xc3b, 1], [ 0xc3c, 0xc3c, 0], [ 0xc3d, 0xc3d, 1], [ 0xc3e, 0xc40, 0], [ 0xc41, 0xc45, 1], [ 0xc46, 0xc48, 0], [ 0xc49, 0xc49, 1], [ 0xc4a, 0xc4d, 0], [ 0xc4e, 0xc54, 1], [ 0xc55, 0xc56, 0], [ 0xc57, 0xc61, 1], [ 0xc62, 0xc63, 0], [ 0xc64, 0xc80, 1], [ 0xc81, 0xc81, 0], [ 0xc82, 0xcbb, 1], [ 0xcbc, 0xcbc, 0], [ 0xcbd, 0xcbe, 1], [ 0xcbf, 0xcbf, 0], [ 0xcc0, 0xcc5, 1], [ 0xcc6, 0xcc6, 0], [ 0xcc7, 0xccb, 1], [ 0xccc, 0xccd, 0], [ 0xcce, 0xce1, 1], [ 0xce2, 0xce3, 0], [ 0xce4, 0xcff, 1], [ 0xd00, 0xd01, 0], [ 0xd02, 0xd3a, 1], [ 0xd3b, 0xd3c, 0], [ 0xd3d, 0xd40, 1], [ 0xd41, 0xd44, 0], [ 0xd45, 0xd4c, 1], [ 0xd4d, 0xd4d, 0], [ 0xd4e, 0xd61, 1], [ 0xd62, 0xd63, 0], [ 0xd64, 0xd80, 1], [ 0xd81, 0xd81, 0], [ 0xd82, 0xdc9, 1], [ 0xdca, 0xdca, 0], [ 0xdcb, 0xdd1, 1], [ 0xdd2, 0xdd4, 0], [ 0xdd5, 0xdd5, 1], [ 0xdd6, 0xdd6, 0], [ 0xdd7, 0xe30, 1], [ 0xe31, 0xe31, 0], [ 0xe32, 0xe33, 1], [ 0xe34, 0xe3a, 0], [ 0xe3b, 0xe46, 1], [ 0xe47, 0xe4e, 0], [ 0xe4f, 0xeb0, 1], [ 0xeb1, 0xeb1, 0], [ 0xeb2, 0xeb3, 1], [ 0xeb4, 0xebc, 0], [ 0xebd, 0xec7, 1], [ 0xec8, 0xece, 0], [ 0xecf, 0xf17, 1], [ 0xf18, 0xf19, 0], [ 0xf1a, 0xf34, 1], [ 0xf35, 0xf35, 0], [ 0xf36, 0xf36, 1], [ 0xf37, 0xf37, 0], [ 0xf38, 0xf38, 1], [ 0xf39, 0xf39, 0], [ 0xf3a, 0xf70, 1], [ 0xf71, 0xf7e, 0], [ 0xf7f, 0xf7f, 1], [ 0xf80, 0xf84, 0], [ 0xf85, 0xf85, 1], [ 0xf86, 0xf87, 0], [ 0xf88, 0xf8c, 1], [ 0xf8d, 0xf97, 0], [ 0xf98, 0xf98, 1], [ 0xf99, 0xfbc, 0], [ 0xfbd, 0xfc5, 1], [ 0xfc6, 0xfc6, 0], [ 0xfc7, 0x102c, 1], [ 0x102d, 0x1030, 0], [ 0x1031, 0x1031, 1], [ 0x1032, 0x1037, 0], [ 0x1038, 0x1038, 1], [ 0x1039, 0x103a, 0], [ 0x103b, 0x103c, 1], [ 0x103d, 0x103e, 0], [ 0x103f, 0x1057, 1], [ 0x1058, 0x1059, 0], [ 0x105a, 0x105d, 1], [ 0x105e, 0x1060, 0], [ 0x1061, 0x1070, 1], [ 0x1071, 0x1074, 0], [ 0x1075, 0x1081, 1], [ 0x1082, 0x1082, 0], [ 0x1083, 0x1084, 1], [ 0x1085, 0x1086, 0], [ 0x1087, 0x108c, 1], [ 0x108d, 0x108d, 0], [ 0x108e, 0x109c, 1], [ 0x109d, 0x109d, 0], [ 0x109e, 0x10ff, 1], [ 0x1100, 0x115f, 2], [ 0x1160, 0x11ff, 0], [ 0x1200, 0x135c, 1], [ 0x135d, 0x135f, 0], [ 0x1360, 0x1711, 1], [ 0x1712, 0x1714, 0], [ 0x1715, 0x1731, 1], [ 0x1732, 0x1733, 0], [ 0x1734, 0x1751, 1], [ 0x1752, 0x1753, 0], [ 0x1754, 0x1771, 1], [ 0x1772, 0x1773, 0], [ 0x1774, 0x17b3, 1], [ 0x17b4, 0x17b5, 0], [ 0x17b6, 0x17b6, 1], [ 0x17b7, 0x17bd, 0], [ 0x17be, 0x17c5, 1], [ 0x17c6, 0x17c6, 0], [ 0x17c7, 0x17c8, 1], [ 0x17c9, 0x17d3, 0], [ 0x17d4, 0x17dc, 1], [ 0x17dd, 0x17dd, 0], [ 0x17de, 0x180a, 1], [ 0x180b, 0x180f, 0], [ 0x1810, 0x1884, 1], [ 0x1885, 0x1886, 0], [ 0x1887, 0x18a8, 1], [ 0x18a9, 0x18a9, 0], [ 0x18aa, 0x191f, 1], [ 0x1920, 0x1922, 0], [ 0x1923, 0x1926, 1], [ 0x1927, 0x1928, 0], [ 0x1929, 0x1931, 1], [ 0x1932, 0x1932, 0], [ 0x1933, 0x1938, 1], [ 0x1939, 0x193b, 0], [ 0x193c, 0x1a16, 1], [ 0x1a17, 0x1a18, 0], [ 0x1a19, 0x1a1a, 1], [ 0x1a1b, 0x1a1b, 0], [ 0x1a1c, 0x1a55, 1], [ 0x1a56, 0x1a56, 0], [ 0x1a57, 0x1a57, 1], [ 0x1a58, 0x1a5e, 0], [ 0x1a5f, 0x1a5f, 1], [ 0x1a60, 0x1a60, 0], [ 0x1a61, 0x1a61, 1], [ 0x1a62, 0x1a62, 0], [ 0x1a63, 0x1a64, 1], [ 0x1a65, 0x1a6c, 0], [ 0x1a6d, 0x1a72, 1], [ 0x1a73, 0x1a7c, 0], [ 0x1a7d, 0x1a7e, 1], [ 0x1a7f, 0x1a7f, 0], [ 0x1a80, 0x1aaf, 1], [ 0x1ab0, 0x1ace, 0], [ 0x1acf, 0x1aff, 1], [ 0x1b00, 0x1b03, 0], [ 0x1b04, 0x1b33, 1], [ 0x1b34, 0x1b34, 0], [ 0x1b35, 0x1b35, 1], [ 0x1b36, 0x1b3a, 0], [ 0x1b3b, 0x1b3b, 1], [ 0x1b3c, 0x1b3c, 0], [ 0x1b3d, 0x1b41, 1], [ 0x1b42, 0x1b42, 0], [ 0x1b43, 0x1b6a, 1], [ 0x1b6b, 0x1b73, 0], [ 0x1b74, 0x1b7f, 1], [ 0x1b80, 0x1b81, 0], [ 0x1b82, 0x1ba1, 1], [ 0x1ba2, 0x1ba5, 0], [ 0x1ba6, 0x1ba7, 1], [ 0x1ba8, 0x1ba9, 0], [ 0x1baa, 0x1baa, 1], [ 0x1bab, 0x1bad, 0], [ 0x1bae, 0x1be5, 1], [ 0x1be6, 0x1be6, 0], [ 0x1be7, 0x1be7, 1], [ 0x1be8, 0x1be9, 0], [ 0x1bea, 0x1bec, 1], [ 0x1bed, 0x1bed, 0], [ 0x1bee, 0x1bee, 1], [ 0x1bef, 0x1bf1, 0], [ 0x1bf2, 0x1c2b, 1], [ 0x1c2c, 0x1c33, 0], [ 0x1c34, 0x1c35, 1], [ 0x1c36, 0x1c37, 0], [ 0x1c38, 0x1ccf, 1], [ 0x1cd0, 0x1cd2, 0], [ 0x1cd3, 0x1cd3, 1], [ 0x1cd4, 0x1ce0, 0], [ 0x1ce1, 0x1ce1, 1], [ 0x1ce2, 0x1ce8, 0], [ 0x1ce9, 0x1cec, 1], [ 0x1ced, 0x1ced, 0], [ 0x1cee, 0x1cf3, 1], [ 0x1cf4, 0x1cf4, 0], [ 0x1cf5, 0x1cf7, 1], [ 0x1cf8, 0x1cf9, 0], [ 0x1cfa, 0x1dbf, 1], [ 0x1dc0, 0x1dff, 0], [ 0x1e00, 0x200a, 1], [ 0x200b, 0x200f, 0], [ 0x2010, 0x2029, 1], [ 0x202a, 0x202e, 0], [ 0x202f, 0x205f, 1], [ 0x2060, 0x2064, 0], [ 0x2065, 0x2065, 1], [ 0x2066, 0x206f, 0], [ 0x2070, 0x20cf, 1], [ 0x20d0, 0x20f0, 0], [ 0x20f1, 0x2319, 1], [ 0x231a, 0x231b, 2], [ 0x231c, 0x2328, 1], [ 0x2329, 0x232a, 2], [ 0x232b, 0x23e8, 1], [ 0x23e9, 0x23ec, 2], [ 0x23ed, 0x23ef, 1], [ 0x23f0, 0x23f0, 2], [ 0x23f1, 0x23f2, 1], [ 0x23f3, 0x23f3, 2], [ 0x23f4, 0x25fc, 1], [ 0x25fd, 0x25fe, 2], [ 0x25ff, 0x2613, 1], [ 0x2614, 0x2615, 2], [ 0x2616, 0x262f, 1], [ 0x2630, 0x2637, 2], [ 0x2638, 0x2647, 1], [ 0x2648, 0x2653, 2], [ 0x2654, 0x267e, 1], [ 0x267f, 0x267f, 2], [ 0x2680, 0x2689, 1], [ 0x268a, 0x268f, 2], [ 0x2690, 0x2692, 1], [ 0x2693, 0x2693, 2], [ 0x2694, 0x26a0, 1], [ 0x26a1, 0x26a1, 2], [ 0x26a2, 0x26a9, 1], [ 0x26aa, 0x26ab, 2], [ 0x26ac, 0x26bc, 1], [ 0x26bd, 0x26be, 2], [ 0x26bf, 0x26c3, 1], [ 0x26c4, 0x26c5, 2], [ 0x26c6, 0x26cd, 1], [ 0x26ce, 0x26ce, 2], [ 0x26cf, 0x26d3, 1], [ 0x26d4, 0x26d4, 2], [ 0x26d5, 0x26e9, 1], [ 0x26ea, 0x26ea, 2], [ 0x26eb, 0x26f1, 1], [ 0x26f2, 0x26f3, 2], [ 0x26f4, 0x26f4, 1], [ 0x26f5, 0x26f5, 2], [ 0x26f6, 0x26f9, 1], [ 0x26fa, 0x26fa, 2], [ 0x26fb, 0x26fc, 1], [ 0x26fd, 0x26fd, 2], [ 0x26fe, 0x2704, 1], [ 0x2705, 0x2705, 2], [ 0x2706, 0x2709, 1], [ 0x270a, 0x270b, 2], [ 0x270c, 0x2727, 1], [ 0x2728, 0x2728, 2], [ 0x2729, 0x274b, 1], [ 0x274c, 0x274c, 2], [ 0x274d, 0x274d, 1], [ 0x274e, 0x274e, 2], [ 0x274f, 0x2752, 1], [ 0x2753, 0x2755, 2], [ 0x2756, 0x2756, 1], [ 0x2757, 0x2757, 2], [ 0x2758, 0x2794, 1], [ 0x2795, 0x2797, 2], [ 0x2798, 0x27af, 1], [ 0x27b0, 0x27b0, 2], [ 0x27b1, 0x27be, 1], [ 0x27bf, 0x27bf, 2], [ 0x27c0, 0x2b1a, 1], [ 0x2b1b, 0x2b1c, 2], [ 0x2b1d, 0x2b4f, 1], [ 0x2b50, 0x2b50, 2], [ 0x2b51, 0x2b54, 1], [ 0x2b55, 0x2b55, 2], [ 0x2b56, 0x2cee, 1], [ 0x2cef, 0x2cf1, 0], [ 0x2cf2, 0x2d7e, 1], [ 0x2d7f, 0x2d7f, 0], [ 0x2d80, 0x2ddf, 1], [ 0x2de0, 0x2dff, 0], [ 0x2e00, 0x2e7f, 1], [ 0x2e80, 0x2e99, 2], [ 0x2e9a, 0x2e9a, 1], [ 0x2e9b, 0x2ef3, 2], [ 0x2ef4, 0x2eff, 1], [ 0x2f00, 0x2fd5, 2], [ 0x2fd6, 0x2fef, 1], [ 0x2ff0, 0x3029, 2], [ 0x302a, 0x302d, 0], [ 0x302e, 0x303e, 2], [ 0x303f, 0x3040, 1], [ 0x3041, 0x3096, 2], [ 0x3097, 0x3098, 1], [ 0x3099, 0x309a, 0], [ 0x309b, 0x30ff, 2], [ 0x3100, 0x3104, 1], [ 0x3105, 0x312f, 2], [ 0x3130, 0x3130, 1], [ 0x3131, 0x318e, 2], [ 0x318f, 0x318f, 1], [ 0x3190, 0x31e5, 2], [ 0x31e6, 0x31ee, 1], [ 0x31ef, 0x321e, 2], [ 0x321f, 0x321f, 1], [ 0x3220, 0x3247, 2], [ 0x3248, 0x324f, 1], [ 0x3250, 0xa48c, 2], [ 0xa48d, 0xa48f, 1], [ 0xa490, 0xa4c6, 2], [ 0xa4c7, 0xa66e, 1], [ 0xa66f, 0xa672, 0], [ 0xa673, 0xa673, 1], [ 0xa674, 0xa67d, 0], [ 0xa67e, 0xa69d, 1], [ 0xa69e, 0xa69f, 0], [ 0xa6a0, 0xa6ef, 1], [ 0xa6f0, 0xa6f1, 0], [ 0xa6f2, 0xa801, 1], [ 0xa802, 0xa802, 0], [ 0xa803, 0xa805, 1], [ 0xa806, 0xa806, 0], [ 0xa807, 0xa80a, 1], [ 0xa80b, 0xa80b, 0], [ 0xa80c, 0xa824, 1], [ 0xa825, 0xa826, 0], [ 0xa827, 0xa82b, 1], [ 0xa82c, 0xa82c, 0], [ 0xa82d, 0xa8c3, 1], [ 0xa8c4, 0xa8c5, 0], [ 0xa8c6, 0xa8df, 1], [ 0xa8e0, 0xa8f1, 0], [ 0xa8f2, 0xa8fe, 1], [ 0xa8ff, 0xa8ff, 0], [ 0xa900, 0xa925, 1], [ 0xa926, 0xa92d, 0], [ 0xa92e, 0xa946, 1], [ 0xa947, 0xa951, 0], [ 0xa952, 0xa95f, 1], [ 0xa960, 0xa97c, 2], [ 0xa97d, 0xa97f, 1], [ 0xa980, 0xa982, 0], [ 0xa983, 0xa9b2, 1], [ 0xa9b3, 0xa9b3, 0], [ 0xa9b4, 0xa9b5, 1], [ 0xa9b6, 0xa9b9, 0], [ 0xa9ba, 0xa9bb, 1], [ 0xa9bc, 0xa9bd, 0], [ 0xa9be, 0xa9e4, 1], [ 0xa9e5, 0xa9e5, 0], [ 0xa9e6, 0xaa28, 1], [ 0xaa29, 0xaa2e, 0], [ 0xaa2f, 0xaa30, 1], [ 0xaa31, 0xaa32, 0], [ 0xaa33, 0xaa34, 1], [ 0xaa35, 0xaa36, 0], [ 0xaa37, 0xaa42, 1], [ 0xaa43, 0xaa43, 0], [ 0xaa44, 0xaa4b, 1], [ 0xaa4c, 0xaa4c, 0], [ 0xaa4d, 0xaa7b, 1], [ 0xaa7c, 0xaa7c, 0], [ 0xaa7d, 0xaaaf, 1], [ 0xaab0, 0xaab0, 0], [ 0xaab1, 0xaab1, 1], [ 0xaab2, 0xaab4, 0], [ 0xaab5, 0xaab6, 1], [ 0xaab7, 0xaab8, 0], [ 0xaab9, 0xaabd, 1], [ 0xaabe, 0xaabf, 0], [ 0xaac0, 0xaac0, 1], [ 0xaac1, 0xaac1, 0], [ 0xaac2, 0xaaeb, 1], [ 0xaaec, 0xaaed, 0], [ 0xaaee, 0xaaf5, 1], [ 0xaaf6, 0xaaf6, 0], [ 0xaaf7, 0xabe4, 1], [ 0xabe5, 0xabe5, 0], [ 0xabe6, 0xabe7, 1], [ 0xabe8, 0xabe8, 0], [ 0xabe9, 0xabec, 1], [ 0xabed, 0xabed, 0], [ 0xabee, 0xabff, 1], [ 0xac00, 0xd7a3, 2], [ 0xd7a4, 0xd7af, 1], [ 0xd7b0, 0xd7ff, 0], #[ 0xd800, 0xdfff, -1], [ 0xe000, 0xf8ff, 1], [ 0xf900, 0xfaff, 2], [ 0xfb00, 0xfb1d, 1], [ 0xfb1e, 0xfb1e, 0], [ 0xfb1f, 0xfdff, 1], [ 0xfe00, 0xfe0f, 0], [ 0xfe10, 0xfe19, 2], [ 0xfe1a, 0xfe1f, 1], [ 0xfe20, 0xfe2f, 0], [ 0xfe30, 0xfe52, 2], [ 0xfe53, 0xfe53, 1], [ 0xfe54, 0xfe66, 2], [ 0xfe67, 0xfe67, 1], [ 0xfe68, 0xfe6b, 2], [ 0xfe6c, 0xfefe, 1], [ 0xfeff, 0xfeff, 0], [ 0xff00, 0xff00, 1], [ 0xff01, 0xff60, 2], [ 0xff61, 0xffdf, 1], [ 0xffe0, 0xffe6, 2], [ 0xffe7, 0xfff8, 1], [ 0xfff9, 0xfffb, 0], [ 0xfffc, 0x101fc, 1], [ 0x101fd, 0x101fd, 0], [ 0x101fe, 0x102df, 1], [ 0x102e0, 0x102e0, 0], [ 0x102e1, 0x10375, 1], [ 0x10376, 0x1037a, 0], [ 0x1037b, 0x10a00, 1], [ 0x10a01, 0x10a03, 0], [ 0x10a04, 0x10a04, 1], [ 0x10a05, 0x10a06, 0], [ 0x10a07, 0x10a0b, 1], [ 0x10a0c, 0x10a0f, 0], [ 0x10a10, 0x10a37, 1], [ 0x10a38, 0x10a3a, 0], [ 0x10a3b, 0x10a3e, 1], [ 0x10a3f, 0x10a3f, 0], [ 0x10a40, 0x10ae4, 1], [ 0x10ae5, 0x10ae6, 0], [ 0x10ae7, 0x10d23, 1], [ 0x10d24, 0x10d27, 0], [ 0x10d28, 0x10d68, 1], [ 0x10d69, 0x10d6d, 0], [ 0x10d6e, 0x10eaa, 1], [ 0x10eab, 0x10eac, 0], [ 0x10ead, 0x10efb, 1], [ 0x10efc, 0x10eff, 0], [ 0x10f00, 0x10f45, 1], [ 0x10f46, 0x10f50, 0], [ 0x10f51, 0x10f81, 1], [ 0x10f82, 0x10f85, 0], [ 0x10f86, 0x11000, 1], [ 0x11001, 0x11001, 0], [ 0x11002, 0x11037, 1], [ 0x11038, 0x11046, 0], [ 0x11047, 0x1106f, 1], [ 0x11070, 0x11070, 0], [ 0x11071, 0x11072, 1], [ 0x11073, 0x11074, 0], [ 0x11075, 0x1107e, 1], [ 0x1107f, 0x11081, 0], [ 0x11082, 0x110b2, 1], [ 0x110b3, 0x110b6, 0], [ 0x110b7, 0x110b8, 1], [ 0x110b9, 0x110ba, 0], [ 0x110bb, 0x110bc, 1], [ 0x110bd, 0x110bd, 0], [ 0x110be, 0x110c1, 1], [ 0x110c2, 0x110c2, 0], [ 0x110c3, 0x110cc, 1], [ 0x110cd, 0x110cd, 0], [ 0x110ce, 0x110ff, 1], [ 0x11100, 0x11102, 0], [ 0x11103, 0x11126, 1], [ 0x11127, 0x1112b, 0], [ 0x1112c, 0x1112c, 1], [ 0x1112d, 0x11134, 0], [ 0x11135, 0x11172, 1], [ 0x11173, 0x11173, 0], [ 0x11174, 0x1117f, 1], [ 0x11180, 0x11181, 0], [ 0x11182, 0x111b5, 1], [ 0x111b6, 0x111be, 0], [ 0x111bf, 0x111c8, 1], [ 0x111c9, 0x111cc, 0], [ 0x111cd, 0x111ce, 1], [ 0x111cf, 0x111cf, 0], [ 0x111d0, 0x1122e, 1], [ 0x1122f, 0x11231, 0], [ 0x11232, 0x11233, 1], [ 0x11234, 0x11234, 0], [ 0x11235, 0x11235, 1], [ 0x11236, 0x11237, 0], [ 0x11238, 0x1123d, 1], [ 0x1123e, 0x1123e, 0], [ 0x1123f, 0x11240, 1], [ 0x11241, 0x11241, 0], [ 0x11242, 0x112de, 1], [ 0x112df, 0x112df, 0], [ 0x112e0, 0x112e2, 1], [ 0x112e3, 0x112ea, 0], [ 0x112eb, 0x112ff, 1], [ 0x11300, 0x11301, 0], [ 0x11302, 0x1133a, 1], [ 0x1133b, 0x1133c, 0], [ 0x1133d, 0x1133f, 1], [ 0x11340, 0x11340, 0], [ 0x11341, 0x11365, 1], [ 0x11366, 0x1136c, 0], [ 0x1136d, 0x1136f, 1], [ 0x11370, 0x11374, 0], [ 0x11375, 0x113ba, 1], [ 0x113bb, 0x113c0, 0], [ 0x113c1, 0x113cd, 1], [ 0x113ce, 0x113ce, 0], [ 0x113cf, 0x113cf, 1], [ 0x113d0, 0x113d0, 0], [ 0x113d1, 0x113d1, 1], [ 0x113d2, 0x113d2, 0], [ 0x113d3, 0x113e0, 1], [ 0x113e1, 0x113e2, 0], [ 0x113e3, 0x11437, 1], [ 0x11438, 0x1143f, 0], [ 0x11440, 0x11441, 1], [ 0x11442, 0x11444, 0], [ 0x11445, 0x11445, 1], [ 0x11446, 0x11446, 0], [ 0x11447, 0x1145d, 1], [ 0x1145e, 0x1145e, 0], [ 0x1145f, 0x114b2, 1], [ 0x114b3, 0x114b8, 0], [ 0x114b9, 0x114b9, 1], [ 0x114ba, 0x114ba, 0], [ 0x114bb, 0x114be, 1], [ 0x114bf, 0x114c0, 0], [ 0x114c1, 0x114c1, 1], [ 0x114c2, 0x114c3, 0], [ 0x114c4, 0x115b1, 1], [ 0x115b2, 0x115b5, 0], [ 0x115b6, 0x115bb, 1], [ 0x115bc, 0x115bd, 0], [ 0x115be, 0x115be, 1], [ 0x115bf, 0x115c0, 0], [ 0x115c1, 0x115db, 1], [ 0x115dc, 0x115dd, 0], [ 0x115de, 0x11632, 1], [ 0x11633, 0x1163a, 0], [ 0x1163b, 0x1163c, 1], [ 0x1163d, 0x1163d, 0], [ 0x1163e, 0x1163e, 1], [ 0x1163f, 0x11640, 0], [ 0x11641, 0x116aa, 1], [ 0x116ab, 0x116ab, 0], [ 0x116ac, 0x116ac, 1], [ 0x116ad, 0x116ad, 0], [ 0x116ae, 0x116af, 1], [ 0x116b0, 0x116b5, 0], [ 0x116b6, 0x116b6, 1], [ 0x116b7, 0x116b7, 0], [ 0x116b8, 0x1171c, 1], [ 0x1171d, 0x1171d, 0], [ 0x1171e, 0x1171e, 1], [ 0x1171f, 0x1171f, 0], [ 0x11720, 0x11721, 1], [ 0x11722, 0x11725, 0], [ 0x11726, 0x11726, 1], [ 0x11727, 0x1172b, 0], [ 0x1172c, 0x1182e, 1], [ 0x1182f, 0x11837, 0], [ 0x11838, 0x11838, 1], [ 0x11839, 0x1183a, 0], [ 0x1183b, 0x1193a, 1], [ 0x1193b, 0x1193c, 0], [ 0x1193d, 0x1193d, 1], [ 0x1193e, 0x1193e, 0], [ 0x1193f, 0x11942, 1], [ 0x11943, 0x11943, 0], [ 0x11944, 0x119d3, 1], [ 0x119d4, 0x119d7, 0], [ 0x119d8, 0x119d9, 1], [ 0x119da, 0x119db, 0], [ 0x119dc, 0x119df, 1], [ 0x119e0, 0x119e0, 0], [ 0x119e1, 0x11a00, 1], [ 0x11a01, 0x11a0a, 0], [ 0x11a0b, 0x11a32, 1], [ 0x11a33, 0x11a38, 0], [ 0x11a39, 0x11a3a, 1], [ 0x11a3b, 0x11a3e, 0], [ 0x11a3f, 0x11a46, 1], [ 0x11a47, 0x11a47, 0], [ 0x11a48, 0x11a50, 1], [ 0x11a51, 0x11a56, 0], [ 0x11a57, 0x11a58, 1], [ 0x11a59, 0x11a5b, 0], [ 0x11a5c, 0x11a89, 1], [ 0x11a8a, 0x11a96, 0], [ 0x11a97, 0x11a97, 1], [ 0x11a98, 0x11a99, 0], [ 0x11a9a, 0x11c2f, 1], [ 0x11c30, 0x11c36, 0], [ 0x11c37, 0x11c37, 1], [ 0x11c38, 0x11c3d, 0], [ 0x11c3e, 0x11c3e, 1], [ 0x11c3f, 0x11c3f, 0], [ 0x11c40, 0x11c91, 1], [ 0x11c92, 0x11ca7, 0], [ 0x11ca8, 0x11ca9, 1], [ 0x11caa, 0x11cb0, 0], [ 0x11cb1, 0x11cb1, 1], [ 0x11cb2, 0x11cb3, 0], [ 0x11cb4, 0x11cb4, 1], [ 0x11cb5, 0x11cb6, 0], [ 0x11cb7, 0x11d30, 1], [ 0x11d31, 0x11d36, 0], [ 0x11d37, 0x11d39, 1], [ 0x11d3a, 0x11d3a, 0], [ 0x11d3b, 0x11d3b, 1], [ 0x11d3c, 0x11d3d, 0], [ 0x11d3e, 0x11d3e, 1], [ 0x11d3f, 0x11d45, 0], [ 0x11d46, 0x11d46, 1], [ 0x11d47, 0x11d47, 0], [ 0x11d48, 0x11d8f, 1], [ 0x11d90, 0x11d91, 0], [ 0x11d92, 0x11d94, 1], [ 0x11d95, 0x11d95, 0], [ 0x11d96, 0x11d96, 1], [ 0x11d97, 0x11d97, 0], [ 0x11d98, 0x11ef2, 1], [ 0x11ef3, 0x11ef4, 0], [ 0x11ef5, 0x11eff, 1], [ 0x11f00, 0x11f01, 0], [ 0x11f02, 0x11f35, 1], [ 0x11f36, 0x11f3a, 0], [ 0x11f3b, 0x11f3f, 1], [ 0x11f40, 0x11f40, 0], [ 0x11f41, 0x11f41, 1], [ 0x11f42, 0x11f42, 0], [ 0x11f43, 0x11f59, 1], [ 0x11f5a, 0x11f5a, 0], [ 0x11f5b, 0x1342f, 1], [ 0x13430, 0x13440, 0], [ 0x13441, 0x13446, 1], [ 0x13447, 0x13455, 0], [ 0x13456, 0x1611d, 1], [ 0x1611e, 0x16129, 0], [ 0x1612a, 0x1612c, 1], [ 0x1612d, 0x1612f, 0], [ 0x16130, 0x16aef, 1], [ 0x16af0, 0x16af4, 0], [ 0x16af5, 0x16b2f, 1], [ 0x16b30, 0x16b36, 0], [ 0x16b37, 0x16f4e, 1], [ 0x16f4f, 0x16f4f, 0], [ 0x16f50, 0x16f8e, 1], [ 0x16f8f, 0x16f92, 0], [ 0x16f93, 0x16fdf, 1], [ 0x16fe0, 0x16fe3, 2], [ 0x16fe4, 0x16fe4, 0], [ 0x16fe5, 0x16fef, 1], [ 0x16ff0, 0x16ff1, 2], [ 0x16ff2, 0x16fff, 1], [ 0x17000, 0x187f7, 2], [ 0x187f8, 0x187ff, 1], [ 0x18800, 0x18cd5, 2], [ 0x18cd6, 0x18cfe, 1], [ 0x18cff, 0x18d08, 2], [ 0x18d09, 0x1afef, 1], [ 0x1aff0, 0x1aff3, 2], [ 0x1aff4, 0x1aff4, 1], [ 0x1aff5, 0x1affb, 2], [ 0x1affc, 0x1affc, 1], [ 0x1affd, 0x1affe, 2], [ 0x1afff, 0x1afff, 1], [ 0x1b000, 0x1b122, 2], [ 0x1b123, 0x1b131, 1], [ 0x1b132, 0x1b132, 2], [ 0x1b133, 0x1b14f, 1], [ 0x1b150, 0x1b152, 2], [ 0x1b153, 0x1b154, 1], [ 0x1b155, 0x1b155, 2], [ 0x1b156, 0x1b163, 1], [ 0x1b164, 0x1b167, 2], [ 0x1b168, 0x1b16f, 1], [ 0x1b170, 0x1b2fb, 2], [ 0x1b2fc, 0x1bc9c, 1], [ 0x1bc9d, 0x1bc9e, 0], [ 0x1bc9f, 0x1bc9f, 1], [ 0x1bca0, 0x1bca3, 0], [ 0x1bca4, 0x1ceff, 1], [ 0x1cf00, 0x1cf2d, 0], [ 0x1cf2e, 0x1cf2f, 1], [ 0x1cf30, 0x1cf46, 0], [ 0x1cf47, 0x1d166, 1], [ 0x1d167, 0x1d169, 0], [ 0x1d16a, 0x1d172, 1], [ 0x1d173, 0x1d182, 0], [ 0x1d183, 0x1d184, 1], [ 0x1d185, 0x1d18b, 0], [ 0x1d18c, 0x1d1a9, 1], [ 0x1d1aa, 0x1d1ad, 0], [ 0x1d1ae, 0x1d241, 1], [ 0x1d242, 0x1d244, 0], [ 0x1d245, 0x1d2ff, 1], [ 0x1d300, 0x1d356, 2], [ 0x1d357, 0x1d35f, 1], [ 0x1d360, 0x1d376, 2], [ 0x1d377, 0x1d9ff, 1], [ 0x1da00, 0x1da36, 0], [ 0x1da37, 0x1da3a, 1], [ 0x1da3b, 0x1da6c, 0], [ 0x1da6d, 0x1da74, 1], [ 0x1da75, 0x1da75, 0], [ 0x1da76, 0x1da83, 1], [ 0x1da84, 0x1da84, 0], [ 0x1da85, 0x1da9a, 1], [ 0x1da9b, 0x1da9f, 0], [ 0x1daa0, 0x1daa0, 1], [ 0x1daa1, 0x1daaf, 0], [ 0x1dab0, 0x1dfff, 1], [ 0x1e000, 0x1e006, 0], [ 0x1e007, 0x1e007, 1], [ 0x1e008, 0x1e018, 0], [ 0x1e019, 0x1e01a, 1], [ 0x1e01b, 0x1e021, 0], [ 0x1e022, 0x1e022, 1], [ 0x1e023, 0x1e024, 0], [ 0x1e025, 0x1e025, 1], [ 0x1e026, 0x1e02a, 0], [ 0x1e02b, 0x1e08e, 1], [ 0x1e08f, 0x1e08f, 0], [ 0x1e090, 0x1e12f, 1], [ 0x1e130, 0x1e136, 0], [ 0x1e137, 0x1e2ad, 1], [ 0x1e2ae, 0x1e2ae, 0], [ 0x1e2af, 0x1e2eb, 1], [ 0x1e2ec, 0x1e2ef, 0], [ 0x1e2f0, 0x1e4eb, 1], [ 0x1e4ec, 0x1e4ef, 0], [ 0x1e4f0, 0x1e5ed, 1], [ 0x1e5ee, 0x1e5ef, 0], [ 0x1e5f0, 0x1e8cf, 1], [ 0x1e8d0, 0x1e8d6, 0], [ 0x1e8d7, 0x1e943, 1], [ 0x1e944, 0x1e94a, 0], [ 0x1e94b, 0x1f003, 1], [ 0x1f004, 0x1f004, 2], [ 0x1f005, 0x1f0ce, 1], [ 0x1f0cf, 0x1f0cf, 2], [ 0x1f0d0, 0x1f18d, 1], [ 0x1f18e, 0x1f18e, 2], [ 0x1f18f, 0x1f190, 1], [ 0x1f191, 0x1f19a, 2], [ 0x1f19b, 0x1f1ff, 1], [ 0x1f200, 0x1f202, 2], [ 0x1f203, 0x1f20f, 1], [ 0x1f210, 0x1f23b, 2], [ 0x1f23c, 0x1f23f, 1], [ 0x1f240, 0x1f248, 2], [ 0x1f249, 0x1f24f, 1], [ 0x1f250, 0x1f251, 2], [ 0x1f252, 0x1f25f, 1], [ 0x1f260, 0x1f265, 2], [ 0x1f266, 0x1f2ff, 1], [ 0x1f300, 0x1f320, 2], [ 0x1f321, 0x1f32c, 1], [ 0x1f32d, 0x1f335, 2], [ 0x1f336, 0x1f336, 1], [ 0x1f337, 0x1f37c, 2], [ 0x1f37d, 0x1f37d, 1], [ 0x1f37e, 0x1f393, 2], [ 0x1f394, 0x1f39f, 1], [ 0x1f3a0, 0x1f3ca, 2], [ 0x1f3cb, 0x1f3ce, 1], [ 0x1f3cf, 0x1f3d3, 2], [ 0x1f3d4, 0x1f3df, 1], [ 0x1f3e0, 0x1f3f0, 2], [ 0x1f3f1, 0x1f3f3, 1], [ 0x1f3f4, 0x1f3f4, 2], [ 0x1f3f5, 0x1f3f7, 1], [ 0x1f3f8, 0x1f43e, 2], [ 0x1f43f, 0x1f43f, 1], [ 0x1f440, 0x1f440, 2], [ 0x1f441, 0x1f441, 1], [ 0x1f442, 0x1f4fc, 2], [ 0x1f4fd, 0x1f4fe, 1], [ 0x1f4ff, 0x1f53d, 2], [ 0x1f53e, 0x1f54a, 1], [ 0x1f54b, 0x1f54e, 2], [ 0x1f54f, 0x1f54f, 1], [ 0x1f550, 0x1f567, 2], [ 0x1f568, 0x1f579, 1], [ 0x1f57a, 0x1f57a, 2], [ 0x1f57b, 0x1f594, 1], [ 0x1f595, 0x1f596, 2], [ 0x1f597, 0x1f5a3, 1], [ 0x1f5a4, 0x1f5a4, 2], [ 0x1f5a5, 0x1f5fa, 1], [ 0x1f5fb, 0x1f64f, 2], [ 0x1f650, 0x1f67f, 1], [ 0x1f680, 0x1f6c5, 2], [ 0x1f6c6, 0x1f6cb, 1], [ 0x1f6cc, 0x1f6cc, 2], [ 0x1f6cd, 0x1f6cf, 1], [ 0x1f6d0, 0x1f6d2, 2], [ 0x1f6d3, 0x1f6d4, 1], [ 0x1f6d5, 0x1f6d7, 2], [ 0x1f6d8, 0x1f6db, 1], [ 0x1f6dc, 0x1f6df, 2], [ 0x1f6e0, 0x1f6ea, 1], [ 0x1f6eb, 0x1f6ec, 2], [ 0x1f6ed, 0x1f6f3, 1], [ 0x1f6f4, 0x1f6fc, 2], [ 0x1f6fd, 0x1f7df, 1], [ 0x1f7e0, 0x1f7eb, 2], [ 0x1f7ec, 0x1f7ef, 1], [ 0x1f7f0, 0x1f7f0, 2], [ 0x1f7f1, 0x1f90b, 1], [ 0x1f90c, 0x1f93a, 2], [ 0x1f93b, 0x1f93b, 1], [ 0x1f93c, 0x1f945, 2], [ 0x1f946, 0x1f946, 1], [ 0x1f947, 0x1f9ff, 2], [ 0x1fa00, 0x1fa6f, 1], [ 0x1fa70, 0x1fa7c, 2], [ 0x1fa7d, 0x1fa7f, 1], [ 0x1fa80, 0x1fa89, 2], [ 0x1fa8a, 0x1fa8e, 1], [ 0x1fa8f, 0x1fac6, 2], [ 0x1fac7, 0x1facd, 1], [ 0x1face, 0x1fadc, 2], [ 0x1fadd, 0x1fade, 1], [ 0x1fadf, 0x1fae9, 2], [ 0x1faea, 0x1faef, 1], [ 0x1faf0, 0x1faf8, 2], [ 0x1faf9, 0x1ffff, 1], [ 0x20000, 0x2fffd, 2], [ 0x2fffe, 0x2ffff, 1], [ 0x30000, 0x3fffd, 2], [ 0x3fffe, 0xe0000, 1], [ 0xe0001, 0xe0001, 0], [ 0xe0002, 0xe001f, 1], [ 0xe0020, 0xe007f, 0], [ 0xe0080, 0xe00ff, 1], [ 0xe0100, 0xe01ef, 0], [ 0xe01f0, 0x10ffff, 1], ] } 1; Term-Choose-1.774/lib/Term/Choose/LineFold/PaxHeaders/PP.pm0000644000000000000000000000013215002725230020201 xustar0030 mtime=1745595032.985254368 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose/LineFold/PP.pm0000755000175000001440000000731415002725230020763 0ustar00mmusers00000000000000package Term::Choose::LineFold::PP; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter qw( import ); our @EXPORT_OK = qw( char_width print_columns cut_to_printwidth adjust_to_printwidth ); BEGIN { if ( exists $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE} ) { # 24.03.2025 if ( $ENV{TC_AMBIGUOUS_WIDTH_IS_WIDE} ) { require Term::Choose::LineFold::PP::CharWidthAmbiguousWide; Term::Choose::LineFold::PP::CharWidthAmbiguousWide->import( 'table_char_width' ); } else { require Term::Choose::LineFold::PP::CharWidthDefault; Term::Choose::LineFold::PP::CharWidthDefault->import( 'table_char_width' ); } } # else { # if ( $ENV{TC_AMBIGUOUS_WIDE} ) { # require Term::Choose::LineFold::PP::CharWidthAmbiguousWide; # Term::Choose::LineFold::PP::CharWidthAmbiguousWide->import( 'table_char_width' ); # } # else { # require Term::Choose::LineFold::PP::CharWidthDefault; # Term::Choose::LineFold::PP::CharWidthDefault->import( 'table_char_width' ); # } # } # } my $table = table_char_width(); my $cache = {}; sub char_width { #my $c = $_[0]; my $min = 0; my $mid; my $max = $#$table; if ( $_[0] < $table->[0][0] || $_[0] > $table->[$max][1] ) { return 1; } while ( $max >= $min ) { $mid = int( ( $min + $max ) / 2 ); if ( $_[0] > $table->[$mid][1] ) { $min = $mid + 1; } elsif ( $_[0] < $table->[$mid][0] ) { $max = $mid - 1; } else { return $table->[$mid][2]; } } return 1; } sub print_columns { #my $str = $_[0]; my $width = 0; my $c; for my $i ( 0 .. ( length( $_[0] ) - 1 ) ) { $c = ord substr $_[0], $i, 1; $width += ( $cache->{$c} //= char_width( $c ) ); } return $width; } sub cut_to_printwidth { #my ( $str, $avail_width ) = @_; my $str_w = 0; my $c; for my $i ( 0 .. ( length( $_[0] ) - 1 ) ) { $c = ord substr $_[0], $i, 1; if ( ( $str_w += ( $cache->{$c} //= char_width( $c ) ) ) > $_[1] ) { if ( ( $str_w - $cache->{$c} ) < $_[1] ) { return substr( $_[0], 0, $i ) . ' ', substr( $_[0], $i ) if wantarray; return substr( $_[0], 0, $i ) . ' '; } return substr( $_[0], 0, $i ), substr( $_[0], $i ) if wantarray; return substr( $_[0], 0, $i ); } } return $_[0], '' if wantarray; return $_[0]; } sub adjust_to_printwidth { # my ( $str, $width ) = @_; my $str_w = 0; my $c; for my $i ( 0 .. ( length( $_[0] ) - 1 ) ) { $c = ord substr $_[0], $i, 1; if ( ( $str_w += ( $cache->{$c} //= char_width( $c ) ) ) > $_[1] ) { if ( ( $str_w - $cache->{$c} ) < $_[1] ) { return substr( $_[0], 0, $i ) . ' '; } return substr( $_[0], 0, $i ); } } return $_[0] if $str_w == $_[1]; return $_[0] . ' ' x ( $_[1] - $str_w ); } 1; __END__ Term-Choose-1.774/lib/Term/PaxHeaders/Choose.pm0000644000000000000000000000013215003360046016167 xustar0030 mtime=1745739814.413202388 30 atime=1745767630.601136886 30 ctime=1745767633.701079608 Term-Choose-1.774/lib/Term/Choose.pm0000644000175000001440000020762015003360046016750 0ustar00mmusers00000000000000package Term::Choose; use warnings; use strict; use 5.10.1; our $VERSION = '1.774'; use Exporter 'import'; our @EXPORT_OK = qw( choose ); use Carp qw( croak carp ); use Term::Choose::Constants qw( :all ); use Term::Choose::LineFold qw( line_fold print_columns cut_to_printwidth ); use Term::Choose::Screen qw( :all ); use Term::Choose::ValidateOptions qw( validate_options ); my $Plugin; BEGIN { if ( $^O eq 'MSWin32' ) { require Win32::Console::ANSI; require Term::Choose::Win32; $Plugin = 'Term::Choose::Win32'; } else { require Term::Choose::Linux; $Plugin = 'Term::Choose::Linux'; } } END { if ( $? == 255 ) { if( $^O eq 'MSWin32' ) { my $input = Win32::Console->new( Win32::Console::constant( "STD_INPUT_HANDLE", 0 ) ); $input->Mode( 0x0001|0x0002|0x0004 ); $input->Flush; } elsif ( TERM_READKEY ) { Term::ReadKey::ReadMode( 'restore' ); } else { system( "stty sane" ); } print "\n", clear_to_end_of_screen; print show_cursor; } } sub new { my $class = shift; my ( $opt ) = @_; croak "new: called with " . @_ . " arguments - 0 or 1 arguments expected" if @_ > 1; my $instance_defaults = _defaults(); if ( defined $opt ) { croak "new: the (optional) argument must be a HASH reference" if ref $opt ne 'HASH'; validate_options( _valid_options(), $opt, 'new' ); for my $key ( keys %$opt ) { $instance_defaults->{$key} = $opt->{$key} if defined $opt->{$key}; } } my $self = bless $instance_defaults, $class; $self->{backup_instance_defaults} = { %$instance_defaults }; $self->{plugin} = $Plugin->new(); return $self; } sub _valid_options { return { beep => '[ 0 1 ]', clear_screen => '[ 0 1 ]', codepage_mapping => '[ 0 1 ]', hide_cursor => '[ 0 1 ]', index => '[ 0 1 ]', mouse => '[ 0 1 ]', order => '[ 0 1 ]', alignment => '[ 0 1 2 ]', color => '[ 0 1 2 ]', include_highlighted => '[ 0 1 2 ]', layout => '[ 0 1 2 ]', page => '[ 0 1 2 ]', search => '[ 0 1 2 ]', keep => '[ 1-9 ][ 0-9 ]*', ll => '[ 1-9 ][ 0-9 ]*', max_cols => '[ 1-9 ][ 0-9 ]*', max_height => '[ 1-9 ][ 0-9 ]*', max_width => '[ 1-9 ][ 0-9 ]*', default => '[ 0-9 ]+', pad => '[ 0-9 ]+', margin => 'Array_Int', mark => 'Array_Int', meta_items => 'Array_Int', no_spacebar => 'Array_Int', tabs_info => 'Array_Int', tabs_prompt => 'Array_Int', skip_items => 'Regexp', empty => 'Str', footer => 'Str', info => 'Str', prompt => 'Str', undef => 'Str', busy_string => 'Str', }; }; sub _defaults { return { alignment => 0, beep => 0, clear_screen => 0, codepage_mapping => 0, color => 0, #default => undef, empty => '', #footer => undef, hide_cursor => 1, include_highlighted => 0, index => 0, info => '', keep => 5, layout => 1, #ll => undef, #margin => undef, #mark => undef, #max_cols => undef, #max_height => undef, #max_width => undef, #meta_items => undef, mouse => 0, #no_spacebar => undef, order => 1, pad => 2, page => 1, #prompt => undef, search => 1, #skip_items => undef, #tabs_info => undef, #tabs_prompt => undef, undef => '', #busy_string => undef, }; } sub __copy_orig_list { my ( $self, $orig_list_ref ) = @_; if ( $self->{ll} ) { $self->{list} = $orig_list_ref; } else { $self->{list} = [ @$orig_list_ref ]; if ( $self->{color} ) { $self->{orig_list} = $orig_list_ref; } for ( @{$self->{list}} ) { if ( ! $_ ) { $_ = $self->{undef} if ! defined $_; $_ = $self->{empty} if ! length $_; } if ( $self->{color} ) { s/${\PH}//g; s/${\SGR_ES}/${\PH}/g; } s/\t/ /g; s/\v+/\ \ /g; # \p{Cn} might not be up to date and remove assigned codepoints # therefore only \p{Noncharacter_Code_Point} s/[\p{Cc}\p{Noncharacter_Code_Point}\p{Cs}]//g; } } } sub __length_list_elements { my ( $self ) = @_; my $list = $self->{list}; if ( $self->{ll} ) { $self->{col_width} = $self->{ll}; } else { my $length_elements = []; my $longest = 0; for my $i ( 0 .. $#$list ) { $length_elements->[$i] = print_columns( $list->[$i] ); $longest = $length_elements->[$i] if $length_elements->[$i] > $longest; } $self->{width_elements} = $length_elements; $self->{col_width} = $longest; } } sub __init_term { my ( $self ) = @_; my $config = { mode => 'ultra-raw', mouse => $self->{mouse}, hide_cursor => $self->{hide_cursor}, }; $self->{mouse} = $self->{plugin}->__set_mode( $config ); } sub __reset_term { my ( $self, $clear_choose ) = @_; if ( defined $self->{plugin} ) { $self->{plugin}->__reset_mode( { mouse => $self->{mouse}, hide_cursor => $self->{hide_cursor} } ); } if ( $clear_choose ) { my $up = $self->{i_row} + $self->{count_prompt_lines}; print up( $up ) if $up; print "\r" . clear_to_end_of_screen(); } if ( exists $self->{backup_instance_defaults} ) { # backup_instance_defaults exists if ObjectOriented my $instance_defaults = $self->{backup_instance_defaults}; for my $key ( keys %$self ) { if ( $key eq 'plugin' || $key eq 'backup_instance_defaults' ) { next; } elsif ( exists $instance_defaults->{$key} ) { $self->{$key} = $instance_defaults->{$key}; } else { delete $self->{$key}; } } } } sub __get_key { my ( $self ) = @_; my $key; if ( defined $self->{skip_items} ) { my $idx = $self->{rc2idx}[$self->{pos}[ROW]][$self->{pos}[COL]]; if ( $self->{list}[$idx] =~ $self->{skip_items} ) { $key = $self->Term::Choose::Opt::SkipItems::__key_skipped(); } } if ( ! defined $key ) { $key = $self->{plugin}->__get_key_OS( $self->{mouse} ); } return $key if ref $key ne 'ARRAY'; return $self->Term::Choose::Opt::Mouse::__mouse_info_to_key( @$key ); } sub __modify_options { my ( $self ) = @_; if ( defined $self->{max_cols} && $self->{max_cols} == 1 ) { $self->{layout} = 2; } if ( length $self->{footer} && $self->{page} != 2 ) { $self->{page} = 2; } if ( $self->{page} == 2 && ! $self->{clear_screen} ) { $self->{clear_screen} = 1; } if ( $self->{max_cols} && $self->{layout} == 1 ) { $self->{layout} = 0; } if ( ! defined $self->{prompt} ) { $self->{prompt} = defined $self->{wantarray} ? 'Your choice:' : 'Close with ENTER'; } if ( defined $self->{margin} ) { ( $self->{margin_top}, $self->{margin_right}, $self->{margin_bottom}, $self->{margin_left} ) = @{$self->{margin}}; if ( ! defined $self->{tabs_prompt} ) { $self->{tabs_prompt} = [ $self->{margin_left}, $self->{margin_left}, $self->{margin_right} ]; } if ( ! defined $self->{tabs_info} ) { $self->{tabs_info} = [ $self->{margin_left}, $self->{margin_left}, $self->{margin_right} ]; } } } sub choose { if ( ref $_[0] ne __PACKAGE__ ) { my $ob = __PACKAGE__->new(); delete $ob->{backup_instance_defaults}; return $ob->__choose( @_ ); } my $self = shift; return $self->__choose( @_ ); } sub __choose { my $self = shift; my ( $orig_list_ref, $opt ) = @_; croak "choose: called with " . @_ . " arguments - 1 or 2 arguments expected" if @_ < 1 || @_ > 2; croak "choose: the first argument must be an ARRAY reference" if ref $orig_list_ref ne 'ARRAY'; if ( defined $opt ) { croak "choose: the (optional) second argument must be a HASH reference" if ref $opt ne 'HASH'; validate_options( _valid_options(), $opt, 'choose' ); for my $key ( keys %$opt ) { $self->{$key} = $opt->{$key} if defined $opt->{$key}; } } if ( ! @$orig_list_ref ) { return; } local $\ = undef; local $, = undef; local $| = 1; if ( defined $self->{busy_string} ) { print "\r" . clear_to_end_of_line(); print $self->{busy_string}; } $self->{wantarray} = wantarray; $self->__modify_options(); if ( $self->{mouse} ) { require Term::Choose::Opt::Mouse; } if ( $^O eq 'MSWin32' ) { print $opt->{codepage_mapping} ? "\e(K" : "\e(U"; } $self->__copy_orig_list( $orig_list_ref ); $self->__length_list_elements(); if ( defined $self->{skip_items} ) { require Term::Choose::Opt::SkipItems; $self->Term::Choose::Opt::SkipItems::__prepare_default(); } if ( exists $ENV{TC_RESET_AUTO_UP} ) { $ENV{TC_RESET_AUTO_UP} = 0; } local $SIG{INT} = sub { $self->__reset_term(); exit; }; $self->__init_term(); ( $self->{term_width}, $self->{term_height} ) = get_term_size(); $self->__wr_first_screen(); my $fast_page = 10; if ( $self->{pp_count} > 10_000 ) { $fast_page = 20; } my $saved_pos; GET_KEY: while ( 1 ) { my $key = $self->__get_key(); if ( ! defined $key ) { $self->__reset_term( 1 ); carp "EOT: $!"; return; } $self->{pressed_key} = $key; my ( $new_width, $new_height ) = get_term_size(); if ( $new_width != $self->{term_width} || $new_height != $self->{term_height} ) { if ( $self->{ll} ) { $self->__reset_term( 0 ); return -1; } ( $self->{term_width}, $self->{term_height} ) = ( $new_width, $new_height ); $self->__copy_orig_list( $orig_list_ref ); $self->{default} = $self->{rc2idx}[$self->{pos}[ROW]][$self->{pos}[COL]]; if ( $self->{wantarray} && @{$self->{marked}} ) { $self->{mark} = $self->__marked_rc2idx(); } my $up = $self->{i_row} + $self->{count_prompt_lines}; print up( $up ) if $up; print "\r" . clear_to_end_of_screen(); $self->__wr_first_screen(); next GET_KEY; } next GET_KEY if $key == NEXT_get_key; next GET_KEY if $key == KEY_Tilde; if ( exists $ENV{TC_RESET_AUTO_UP} && $ENV{TC_RESET_AUTO_UP} == 0 ) { if ( $key != LINE_FEED && $key != CARRIAGE_RETURN ) { $ENV{TC_RESET_AUTO_UP} = 1; } } my $page_step = 1; if ( $key == VK_INSERT ) { $page_step = $fast_page if $self->{first_page_row} - $fast_page * $self->{avail_height} >= 0; $key = VK_PAGE_UP; } elsif ( $key == VK_DELETE ) { $page_step = $fast_page if $self->{last_page_row} + $fast_page * $self->{avail_height} <= $#{$self->{rc2idx}}; $key = VK_PAGE_DOWN; } if ( $saved_pos && $key != VK_PAGE_UP && $key != CONTROL_B && $key != VK_PAGE_DOWN && $key != CONTROL_F ) { $saved_pos = undef; } # $self->{rc2idx} holds the new list (AoA) formatted in "__list_idx2rc" appropriate to the chosen layout. # $self->{rc2idx} does not hold the values directly but the respective list indexes from the original list. # If the original list would be ( 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h' ) and the new formatted list should be # a d g # b e h # c f # then the $self->{rc2idx} would look like this # 0 3 6 # 1 4 7 # 2 5 # So e.g. the second value in the second row of the new list would be $self->{list}[ $self->{rc2idx}[1][1] ]. # On the other hand the index of the last row of the new list would be $#{$self->{rc2idx}} # or the index of the last column in the first row would be $#{$self->{rc2idx}[0]}. if ( $key == VK_DOWN || $key == KEY_j ) { if ( ! $self->{rc2idx}[$self->{pos}[ROW]+1] || ! $self->{rc2idx}[$self->{pos}[ROW]+1][$self->{pos}[COL]] ) { $self->__beep(); } else { $self->{pos}[ROW]++; if ( $self->{pos}[ROW] <= $self->{last_page_row} ) { $self->__wr_cell( $self->{pos}[ROW] - 1, $self->{pos}[COL] ); $self->__wr_cell( $self->{pos}[ROW] , $self->{pos}[COL] ); } else { $self->{first_page_row} = $self->{last_page_row} + 1; $self->{last_page_row} = $self->{last_page_row} + $self->{avail_height}; $self->{last_page_row} = $#{$self->{rc2idx}} if $self->{last_page_row} > $#{$self->{rc2idx}}; $self->__wr_screen(); } } } elsif ( $key == VK_UP || $key == KEY_k ) { if ( $self->{pos}[ROW] == 0 ) { $self->__beep(); } else { $self->{pos}[ROW]--; if ( $self->{pos}[ROW] >= $self->{first_page_row} ) { $self->__wr_cell( $self->{pos}[ROW] + 1, $self->{pos}[COL] ); $self->__wr_cell( $self->{pos}[ROW] , $self->{pos}[COL] ); } else { $self->{last_page_row} = $self->{first_page_row} - 1; $self->{first_page_row} = $self->{first_page_row} - $self->{avail_height}; $self->{first_page_row} = 0 if $self->{first_page_row} < 0; $self->__wr_screen(); } } } elsif ( $key == KEY_TAB || $key == CONTROL_I ) { # KEY_TAB == CONTROL_I if ( $self->{pos}[ROW] == $#{$self->{rc2idx}} && $self->{pos}[COL] == $#{$self->{rc2idx}[$self->{pos}[ROW]]} ) { $self->__beep(); } else { if ( $self->{pos}[COL] < $#{$self->{rc2idx}[$self->{pos}[ROW]]} ) { $self->{pos}[COL]++; $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] - 1 ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } else { $self->{pos}[ROW]++; if ( $self->{pos}[ROW] <= $self->{last_page_row} ) { $self->{pos}[COL] = 0; $self->__wr_cell( $self->{pos}[ROW] - 1, $#{$self->{rc2idx}[$self->{pos}[ROW] - 1]} ); $self->__wr_cell( $self->{pos}[ROW] , $self->{pos}[COL] ); } else { $self->{first_page_row} = $self->{last_page_row} + 1; $self->{last_page_row} = $self->{last_page_row} + $self->{avail_height}; $self->{last_page_row} = $#{$self->{rc2idx}} if $self->{last_page_row} > $#{$self->{rc2idx}}; $self->{pos}[COL] = 0; $self->__wr_screen(); } } } } elsif ( $key == KEY_BSPACE || $key == KEY_BTAB || $key == CONTROL_H ) { # KEY_BTAB == CONTROL_H if ( $self->{pos}[COL] == 0 && $self->{pos}[ROW] == 0 ) { $self->__beep(); } else { if ( $self->{pos}[COL] > 0 ) { $self->{pos}[COL]--; $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] + 1 ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } else { $self->{pos}[ROW]--; if ( $self->{pos}[ROW] >= $self->{first_page_row} ) { $self->{pos}[COL] = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; $self->__wr_cell( $self->{pos}[ROW] + 1, 0 ); $self->__wr_cell( $self->{pos}[ROW] , $self->{pos}[COL] ); } else { $self->{last_page_row} = $self->{first_page_row} - 1; $self->{first_page_row} = $self->{first_page_row} - $self->{avail_height}; $self->{first_page_row} = 0 if $self->{first_page_row} < 0; $self->{pos}[COL] = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; $self->__wr_screen(); } } } } elsif ( $key == VK_RIGHT || $key == KEY_l ) { if ( $self->{pos}[COL] == $#{$self->{rc2idx}[$self->{pos}[ROW]]} ) { $self->__beep(); } else { $self->{pos}[COL]++; $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] - 1 ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } } elsif ( $key == VK_LEFT || $key == KEY_h ) { if ( $self->{pos}[COL] == 0 ) { $self->__beep(); } else { $self->{pos}[COL]--; $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] + 1 ); $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } } elsif ( $key == VK_PAGE_UP || $key == CONTROL_P ) { if ( $self->{first_page_row} <= 0 ) { $self->__beep(); } else { $self->{first_page_row} = $self->{avail_height} * ( int( $self->{pos}[ROW] / $self->{avail_height} ) - $page_step ); $self->{last_page_row} = $self->{first_page_row} + $self->{avail_height} - 1; if ( $saved_pos ) { $self->{pos}[ROW] = $saved_pos->[ROW] + $self->{first_page_row}; $self->{pos}[COL] = $saved_pos->[COL]; $saved_pos = undef; } else { $self->{pos}[ROW] -= $self->{avail_height} * $page_step; } $self->__wr_screen(); } } elsif ( $key == VK_PAGE_DOWN || $key == CONTROL_N ) { if ( $self->{last_page_row} >= $#{$self->{rc2idx}} ) { $self->__beep(); } else { my $backup_p_begin = $self->{first_page_row}; $self->{first_page_row} = $self->{avail_height} * ( int( $self->{pos}[ROW] / $self->{avail_height} ) + $page_step ); $self->{last_page_row} = $self->{first_page_row} + $self->{avail_height} - 1; $self->{last_page_row} = $#{$self->{rc2idx}} if $self->{last_page_row} > $#{$self->{rc2idx}}; if ( $self->{pos}[ROW] + $self->{avail_height} > $#{$self->{rc2idx}} || $self->{pos}[COL] > $#{$self->{rc2idx}[$self->{pos}[ROW] + $self->{avail_height}]} ) { $saved_pos = [ $self->{pos}[ROW] - $backup_p_begin, $self->{pos}[COL] ]; $self->{pos}[ROW] = $#{$self->{rc2idx}}; if ( $self->{pos}[COL] > $#{$self->{rc2idx}[$self->{pos}[ROW]]} ) { $self->{pos}[COL] = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; } } else { $self->{pos}[ROW] += $self->{avail_height} * $page_step; } $self->__wr_screen(); } } elsif ( $key == VK_HOME || $key == CONTROL_A ) { if ( $self->{pos}[COL] == 0 && $self->{pos}[ROW] == 0 ) { $self->__beep(); } else { $self->{pos}[ROW] = 0; $self->{pos}[COL] = 0; $self->{first_page_row} = 0; $self->{last_page_row} = $self->{first_page_row} + $self->{avail_height} - 1; $self->{last_page_row} = $#{$self->{rc2idx}} if $self->{last_page_row} > $#{$self->{rc2idx}}; $self->__wr_screen(); } } elsif ( $key == VK_END || $key == CONTROL_E ) { if ( $self->{order} == 1 && $self->{idx_of_last_col_in_last_row} < $#{$self->{rc2idx}[0]} ) { if ( $self->{pos}[ROW] == $#{$self->{rc2idx}} - 1 && $self->{pos}[COL] == $#{$self->{rc2idx}[$self->{pos}[ROW]]} ) { $self->__beep(); } else { $self->{first_page_row} = @{$self->{rc2idx}} - ( @{$self->{rc2idx}} % $self->{avail_height} || $self->{avail_height} ); $self->{pos}[ROW] = $#{$self->{rc2idx}} - 1; $self->{pos}[COL] = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; if ( $self->{first_page_row} == $#{$self->{rc2idx}} ) { $self->{first_page_row} = $self->{first_page_row} - $self->{avail_height}; $self->{last_page_row} = $self->{first_page_row} + $self->{avail_height} - 1; } else { $self->{last_page_row} = $#{$self->{rc2idx}}; } $self->__wr_screen(); } } else { if ( $self->{pos}[ROW] == $#{$self->{rc2idx}} && $self->{pos}[COL] == $#{$self->{rc2idx}[$self->{pos}[ROW]]} ) { $self->__beep(); } else { $self->{first_page_row} = @{$self->{rc2idx}} - ( @{$self->{rc2idx}} % $self->{avail_height} || $self->{avail_height} ); $self->{last_page_row} = $#{$self->{rc2idx}}; $self->{pos}[ROW] = $#{$self->{rc2idx}}; $self->{pos}[COL] = $#{$self->{rc2idx}[$self->{pos}[ROW]]}; $self->__wr_screen(); } } } elsif ( $key == KEY_q || $key == CONTROL_Q ) { $self->__reset_term( 1 ); return; } elsif ( $key == CONTROL_C ) { $self->__reset_term( 1 ); print STDERR "^C\n"; exit 1; } elsif ( $key == LINE_FEED || $key == CARRIAGE_RETURN ) { # LINE_FEED == CONTROL_J, CARRIAGE_RETURN == CONTROL_M # ENTER key if ( length $self->{search_info} ) { require Term::Choose::Opt::Search; $self->Term::Choose::Opt::Search::__search_end(); next GET_KEY; } my $opt_index = $self->{index} || $self->{ll}; my $list_idx = $self->{rc2idx}[$self->{pos}[ROW]][$self->{pos}[COL]]; if ( ! defined $self->{wantarray} ) { $self->__reset_term( 1 ); return; } elsif ( $self->{wantarray} ) { if ( $self->{include_highlighted} == 1 ) { $self->{marked}[$self->{pos}[ROW]][$self->{pos}[COL]] = 1; } elsif ( $self->{include_highlighted} == 2 ) { my $chosen = $self->__marked_rc2idx(); if ( ! @$chosen ) { $self->{marked}[$self->{pos}[ROW]][$self->{pos}[COL]] = 1; } } if ( defined $self->{meta_items} && ! $self->{marked}[$self->{pos}[ROW]][$self->{pos}[COL]] ) { for my $meta_item ( @{$self->{meta_items}} ) { if ( $meta_item == $list_idx ) { $self->{marked}[$self->{pos}[ROW]][$self->{pos}[COL]] = 1; last; } } } my $chosen = $self->__marked_rc2idx(); $self->__reset_term( 1 ); return $opt_index ? @$chosen : @{$orig_list_ref}[@$chosen]; } else { my $chosen = $opt_index ? $list_idx : $orig_list_ref->[$list_idx]; $self->__reset_term( 1 ); return $chosen; } } elsif ( $key == KEY_SPACE ) { if ( $self->{wantarray} ) { my $list_idx = $self->{rc2idx}[$self->{pos}[ROW]][$self->{pos}[COL]]; my $locked = 0; if ( defined $self->{no_spacebar} || defined $self->{meta_items} ) { for my $no_spacebar ( @{$self->{no_spacebar}||[]}, @{$self->{meta_items}||[]} ) { if ( $list_idx == $no_spacebar ) { ++$locked; last; } } } if ( $locked ) { $self->__beep(); } else { $self->{marked}[$self->{pos}[ROW]][$self->{pos}[COL]] = ! $self->{marked}[$self->{pos}[ROW]][$self->{pos}[COL]]; $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } } else { $self->__beep(); } } elsif ( $key == CONTROL_SPACE ) { if ( $self->{wantarray} ) { for my $i ( 0 .. $#{$self->{rc2idx}} ) { for my $j ( 0 .. $#{$self->{rc2idx}[$i]} ) { $self->{marked}[$i][$j] = ! $self->{marked}[$i][$j]; } } if ( $self->{skip_items} ) { $self->Term::Choose::Opt::SkipItems::__unmark_skip_items(); } if ( defined $self->{no_spacebar} ) { $self->__marked_idx2rc( $self->{no_spacebar}, 0 ); } if ( defined $self->{meta_items} ) { $self->__marked_idx2rc( $self->{meta_items}, 0 ); } $self->__wr_screen(); } else { $self->__beep(); } } elsif ( $key == CONTROL_F && $self->{search} ) { require Term::Choose::Opt::Search; if ( $self->{ll} ) { $ENV{TC_POS_AT_SEARCH} = $self->{rc2idx}[$self->{pos}[ROW]][$self->{pos}[COL]]; $self->__reset_term( 0 ); return -13; } if ( length $self->{search_info} ) { $self->Term::Choose::Opt::Search::__search_end(); } $self->Term::Choose::Opt::Search::__search_begin(); } else { $self->__beep(); } } } sub __beep { my ( $self, $beep ) = @_; if ( $beep ) { print bell(); } } sub __prepare_info_and_prompt_lines { my ( $self ) = @_; my $info_w = $self->{term_width} + EXTRA_W; if ( $self->{max_width} && $info_w > $self->{max_width} ) { ## $info_w = $self->{max_width}; } my @tmp_prompt; if ( $self->{margin_top} ) { push @tmp_prompt, ( '' ) x $self->{margin_top}; } if ( length $self->{info} ) { my $init = $self->{tabs_info}[0] // 0; my $subseq = $self->{tabs_info}[1] // 0; my $r_margin = $self->{tabs_info}[2] // 0; push @tmp_prompt, line_fold( $self->{info}, { width => $info_w - $r_margin, init_tab => ' ' x $init, subseq_tab => ' ' x $subseq, color => $self->{color}, join => 0 } ); } if ( length $self->{prompt} ) { my $init = $self->{tabs_prompt}[0] // 0; my $subseq = $self->{tabs_prompt}[1] // 0; my $r_margin = $self->{tabs_prompt}[2] // 0; push @tmp_prompt, line_fold( $self->{prompt}, { width => $info_w - $r_margin, init_tab => ' ' x $init, subseq_tab => ' ' x $subseq, color => $self->{color}, join => 0 } ); } if ( length $self->{search_info} ) { push @tmp_prompt, ( $self->{margin_left} ? ' ' x $self->{margin_left} : '' ) . $self->{search_info}; } $self->{count_prompt_lines} = @tmp_prompt; if ( ! $self->{count_prompt_lines} ) { $self->{prompt_copy} = ''; return; } $self->{prompt_copy} = join( "\n\r", @tmp_prompt ) . "\n\r"; # # \n\r -> stty 'raw' mode and Term::Readkey 'ultra-raw' mode don't translate newline to carriage_return/newline } sub __prepare_footer_line { my ( $self ) = @_; if ( exists $self->{footer_fmt} ) { delete $self->{footer_fmt}; } my $pp_total = int( $#{$self->{rc2idx}} / $self->{avail_height} ) + 1; if ( $self->{page} == 0 ) { # nothing to do } elsif ( $self->{page} == 1 && $pp_total == 1 ) { $self->{avail_height}++; } else { my $pp_total_width = length $pp_total; $self->{footer_fmt} = '--- %0' . $pp_total_width . 'd/' . $pp_total . ' --- '; if ( defined $self->{footer} ) { $self->{footer_fmt} .= $self->{footer}; } if ( print_columns( sprintf $self->{footer_fmt}, $pp_total ) > $self->{avail_width} ) { # color $self->{footer_fmt} = '%0' . $pp_total_width . 'd/' . $pp_total; if ( length( sprintf $self->{footer_fmt}, $pp_total ) > $self->{avail_width} ) { $pp_total_width = $self->{avail_width} if $pp_total_width > $self->{avail_width}; $self->{footer_fmt} = '%0' . $pp_total_width . '.' . $pp_total_width . 's'; } } } $self->{pp_count} = $pp_total; } sub __set_cell { my ( $self, $list_idx ) = @_; if ( $self->{current_layout} == 2 ) { $self->{pos} = [ $list_idx, 0 ]; } else { LOOP: for my $i ( 0 .. $#{$self->{rc2idx}} ) { for my $j ( 0 .. $#{$self->{rc2idx}[$i]} ) { if ( $list_idx == $self->{rc2idx}[$i][$j] ) { $self->{pos} = [ $i, $j ]; last LOOP; } } } } $self->{first_page_row} = $self->{avail_height} * int( $self->{pos}[ROW] / $self->{avail_height} ); $self->{last_page_row} = $self->{first_page_row} + $self->{avail_height} - 1; $self->{last_page_row} = $#{$self->{rc2idx}} if $self->{last_page_row} > $#{$self->{rc2idx}}; } sub __wr_first_screen { my ( $self ) = @_; $self->__avail_screen_size(); $self->__current_layout(); $self->__list_idx2rc(); $self->__prepare_footer_line(); $self->{first_page_row} = 0; my $avail_height_idx = $self->{avail_height} - 1; $self->{last_page_row} = $avail_height_idx > $#{$self->{rc2idx}} ? $#{$self->{rc2idx}} : $avail_height_idx; $self->{i_row} = 0; $self->{i_col} = 0; $self->{pos} = [ 0, 0 ]; $self->{marked} = []; if ( $self->{wantarray} && defined $self->{mark} ) { $self->__marked_idx2rc( $self->{mark}, 1 ); } if ( defined $self->{default} && $self->{default} <= $#{$self->{list}} ) { $self->__set_cell( $self->{default} ); } if ( $self->{clear_screen} ) { print clear_screen(); } else { print "\r" . clear_to_end_of_screen(); } if ( $self->{prompt_copy} ne '' ) { print $self->{prompt_copy}; } $self->__wr_screen(); if ( $self->{mouse} ) { my $abs_cursor_y = $self->{plugin}->__get_cursor_row(); $self->{offset_rows} = $abs_cursor_y - 1 - $self->{i_row}; } } sub __wr_screen { my ( $self ) = @_; $self->__goto( 0, 0 ); print "\r" . clear_to_end_of_screen(); if ( defined $self->{footer_fmt} ) { my $pp_line = sprintf $self->{footer_fmt}, int( $self->{first_page_row} / $self->{avail_height} ) + 1; if ( $self->{margin_left} ) { print right( $self->{margin_left} ); } print "\n" x ( $self->{avail_height} ); print $pp_line . "\r"; if ( $self->{margin_bottom} ) { print "\n" x $self->{margin_bottom}; print up( $self->{margin_bottom} ); } print up( $self->{avail_height} ); } elsif ( $self->{margin_bottom} ) { my $count = ( $self->{last_page_row} - $self->{first_page_row} ) + $self->{margin_bottom}; print "\n" x $count; print up( $count ); } if ( $self->{margin_left} ) { print right( $self->{margin_left} ); # left margin after each "\r" } my $pad_str = ' ' x $self->{pad}; for my $row ( $self->{first_page_row} .. $self->{last_page_row} ) { my $line = $self->__prepare_cell( $row, 0 ); if ( $#{$self->{rc2idx}[$row]} ) { # for my $col ( 1 .. $#{$self->{rc2idx}[$row]} ) { $line = $line . $pad_str . $self->__prepare_cell( $row, $col ); } } print $line . "\n\r"; if ( $self->{margin_left} ) { print right( $self->{margin_left} ); } } print up( $self->{last_page_row} - $self->{first_page_row} + 1 ); # relativ cursor pos: 0, 0 $self->__wr_cell( $self->{pos}[ROW], $self->{pos}[COL] ); } sub __prepare_cell { my( $self, $row, $col ) = @_; my $is_current_pos = $row == $self->{pos}[ROW] && $col == $self->{pos}[COL]; my $emphasised = ( $self->{marked}[$row][$col] ? bold_underline() : '' ) . ( $is_current_pos ? reverse_video() : '' ); my $idx = $self->{rc2idx}[$row][$col]; if ( $self->{ll} ) { if ( $self->{color} ) { my $str = $self->{list}[$idx]; if ( $emphasised ) { if ( $is_current_pos && $self->{color} == 1 ) { # no color for the selected cell if color == 1 $str =~ s/${\SGR_ES}//g; } else { # keep marked cells marked after color escapes $str =~ s/(${\SGR_ES})/${1}$emphasised/g; } $str = $emphasised . $str; } return $str . normal(); } else { if ( $emphasised ) { return $emphasised . $self->{list}[$idx] . normal(); } else { return $self->{list}[$idx]; } } } else { my $str = $self->{current_layout} == -1 ? $self->{list}[$idx] : $self->__pad_str_to_colwidth( $idx ); if ( $self->{color} ) { my @color; if ( ! $self->{orig_list}[$idx] ) { if ( ! defined $self->{orig_list}[$idx] ) { @color = $self->{undef} =~ /(${\SGR_ES})/g; } elsif ( ! length $self->{orig_list}[$idx] ) { @color = $self->{empty} =~ /(${\SGR_ES})/g; } } else { @color = $self->{orig_list}[$idx] =~ /(${\SGR_ES})/g; } if ( $emphasised ) { for ( @color ) { # keep marked cells marked after color escapes $_ .= $emphasised; } $str = $emphasised . $str . normal(); if ( $is_current_pos && $self->{color} == 1 ) { # no color for the selected cell if color == 1 @color = (); $str =~ s/${\PH}//g; } } if ( @color ) { $str =~ s/${\PH}/shift @color/ge; if ( ! $emphasised ) { $str .= normal(); } } return $str; } else { if ( $emphasised ) { $str = $emphasised . $str . normal(); } return $str; } } } sub __wr_cell { my( $self, $row, $col ) = @_; my $idx = $self->{rc2idx}[$row][$col]; if ( $self->{current_layout} == -1 ) { my $x = 0; if ( $col > 0 ) { for my $cl ( 0 .. $col - 1 ) { my $i = $self->{rc2idx}[$row][$cl]; $x += $self->{width_elements}[$i] + $self->{pad}; } } $self->__goto( $row - $self->{first_page_row}, $x ); $self->{i_col} = $self->{i_col} + $self->{width_elements}[$idx]; } else { $self->__goto( $row - $self->{first_page_row}, $col * $self->{col_width_plus} ); $self->{i_col} = $self->{i_col} + $self->{col_width}; } print $self->__prepare_cell( $row, $col ); } sub __pad_str_to_colwidth { my ( $self, $idx ) = @_; if ( $self->{width_elements}[$idx] < $self->{col_width} ) { if ( $self->{alignment} == 0 ) { return $self->{list}[$idx] . ( " " x ( $self->{col_width} - $self->{width_elements}[$idx] ) ); } elsif ( $self->{alignment} == 1 ) { return " " x ( $self->{col_width} - $self->{width_elements}[$idx] ) . $self->{list}[$idx]; } elsif ( $self->{alignment} == 2 ) { my $all = $self->{col_width} - $self->{width_elements}[$idx]; my $half = int( $all / 2 ); return ( " " x $half ) . $self->{list}[$idx] . ( " " x ( $all - $half ) ); } } elsif ( $self->{width_elements}[$idx] > $self->{col_width} ) { if ( $self->{col_width} > 6 ) { return cut_to_printwidth( $self->{list}[$idx], $self->{col_width} - 3 ) . '...'; } else { return cut_to_printwidth( $self->{list}[$idx], $self->{col_width} ); } } else { return $self->{list}[$idx]; } } sub __goto { my ( $self, $newrow, $newcol ) = @_; # requires up, down, left or right to be 1 or greater if ( $newrow > $self->{i_row} ) { print down( $newrow - $self->{i_row} ); $self->{i_row} = $newrow; } elsif ( $newrow < $self->{i_row} ) { print up( $self->{i_row} - $newrow ); $self->{i_row} = $newrow; } if ( $newcol > $self->{i_col} ) { print right( $newcol - $self->{i_col} ); $self->{i_col} = $newcol; } elsif ( $newcol < $self->{i_col} ) { print left( $self->{i_col} - $newcol ); $self->{i_col} = $newcol; } } sub __avail_screen_size { my ( $self ) = @_; ( $self->{avail_width}, $self->{avail_height} ) = ( $self->{term_width}, $self->{term_height} ); if ( $self->{margin_left} ) { $self->{avail_width} -= $self->{margin_left}; } if ( $self->{margin_right} ) { $self->{avail_width} -= $self->{margin_right}; } if ( $self->{margin_right} || ( $self->{col_width} > $self->{avail_width} ) ) { $self->{avail_width} += EXTRA_W; # + EXTRA_W: use also the last terminal column if there is only one item-column; # with only one item-column the output doesn't get messed up if an item # reaches the right edge of the terminal on a non-MSWin32-OS (EXTRA_W is 0 if OS is MSWin32) } if ( $self->{max_width} && $self->{avail_width} > $self->{max_width} ) { $self->{avail_width} = $self->{max_width}; } if ( $self->{avail_width} < 1 ) { $self->{avail_width} = 1; } #if ( $self->{ll} && $self->{ll} > $self->{avail_width} ) { # return -2; #} $self->__prepare_info_and_prompt_lines(); if ( $self->{count_prompt_lines} ) { $self->{avail_height} -= $self->{count_prompt_lines}; } if ( $self->{page} ) { $self->{avail_height}--; } if ( $self->{margin_bottom} ) { $self->{avail_height} -= $self->{margin_bottom}; } if ( $self->{avail_height} < $self->{keep} ) { $self->{avail_height} = $self->{term_height} >= $self->{keep} ? $self->{keep} : $self->{term_height}; } if ( $self->{max_height} && $self->{max_height} < $self->{avail_height} ) { $self->{avail_height} = $self->{max_height}; } } sub __current_layout { my ( $self ) = @_; my $all_in_first_row; if ( $self->{layout} <= 1 && ! $self->{ll} && ! $self->{max_cols} ) { my $firstrow_width = 0; for my $list_idx ( 0 .. $#{$self->{list}} ) { $firstrow_width += $self->{width_elements}[$list_idx] + $self->{pad}; if ( $firstrow_width - $self->{pad} > $self->{avail_width} ) { $firstrow_width = 0; last; } } $all_in_first_row = $firstrow_width; } if ( $all_in_first_row ) { $self->{current_layout} = -1; } elsif ( $self->{col_width} >= $self->{avail_width} ) { $self->{current_layout} = 2; $self->{col_width} = $self->{avail_width}; } else { $self->{current_layout} = $self->{layout}; } $self->{col_width_plus} = $self->{col_width} + $self->{pad}; # 'col_width_plus' no effects if layout == 2 } sub __list_idx2rc { my ( $self ) = @_; my $layout = $self->{current_layout}; $self->{rc2idx} = []; if ( $layout == -1 ) { $self->{rc2idx}[0] = [ 0 .. $#{$self->{list}} ]; $self->{idx_of_last_col_in_last_row} = $#{$self->{list}}; } elsif ( $layout == 2 ) { for my $list_idx ( 0 .. $#{$self->{list}} ) { $self->{rc2idx}[$list_idx][0] = $list_idx; $self->{idx_of_last_col_in_last_row} = 0; } } else { my $tmp_avail_width = $self->{avail_width} + $self->{pad}; # auto_format if ( $layout == 1 ) { my $tmc = int( @{$self->{list}} / $self->{avail_height} ); $tmc++ if @{$self->{list}} % $self->{avail_height}; $tmc *= $self->{col_width_plus}; if ( $tmc < $tmp_avail_width ) { $tmc = int( $tmc + ( ( $tmp_avail_width - $tmc ) / 1.5 ) ); $tmp_avail_width = $tmc; } } # order my $cols_per_row = int( $tmp_avail_width / $self->{col_width_plus} ); if ( $self->{max_cols} && $cols_per_row > $self->{max_cols} ) { $cols_per_row = $self->{max_cols}; } $cols_per_row = 1 if $cols_per_row < 1; $self->{idx_of_last_col_in_last_row} = ( @{$self->{list}} % $cols_per_row || $cols_per_row ) - 1; if ( $self->{order} == 1 ) { my $rows = int( ( @{$self->{list}} - 1 + $cols_per_row ) / $cols_per_row ); my @rearranged_idx; my $begin = 0; my $end = $rows - 1 ; for my $c ( 0 .. $cols_per_row - 1 ) { --$end if $c > $self->{idx_of_last_col_in_last_row}; $rearranged_idx[$c] = [ $begin .. $end ]; $begin = $end + 1; $end = $begin + $rows - 1; } for my $r ( 0 .. $rows - 1 ) { my @temp_idx; for my $c ( 0 .. $cols_per_row - 1 ) { next if $r == $rows - 1 && $c > $self->{idx_of_last_col_in_last_row}; push @temp_idx, $rearranged_idx[$c][$r]; } push @{$self->{rc2idx}}, \@temp_idx; } } else { my $begin = 0; my $end = $cols_per_row - 1; $end = $#{$self->{list}} if $end > $#{$self->{list}}; push @{$self->{rc2idx}}, [ $begin .. $end ]; while ( $end < $#{$self->{list}} ) { $begin += $cols_per_row; $end += $cols_per_row; $end = $#{$self->{list}} if $end > $#{$self->{list}}; push @{$self->{rc2idx}}, [ $begin .. $end ]; } } } } sub __marked_idx2rc { my ( $self, $list_of_indexes, $boolean ) = @_; my $last_list_idx = $#{$self->{list}}; if ( $self->{current_layout} == 2 ) { for my $list_idx ( @$list_of_indexes ) { if ( $list_idx > $last_list_idx ) { next; } $self->{marked}[$list_idx][0] = $boolean; } return; } my ( $row, $col ); my $cols_per_row = @{$self->{rc2idx}[0]}; if ( $self->{order} == 0 ) { for my $list_idx ( @$list_of_indexes ) { if ( $list_idx > $last_list_idx ) { next; } $row = int( $list_idx / $cols_per_row ); $col = $list_idx % $cols_per_row; $self->{marked}[$row][$col] = $boolean; } } elsif ( $self->{order} == 1 ) { my $rows_per_col = @{$self->{rc2idx}}; my $col_count_last_row = $self->{idx_of_last_col_in_last_row} + 1; my $last_list_idx_in_cols_full = $rows_per_col * $col_count_last_row - 1; my $first_list_idx_in_cols_short = $last_list_idx_in_cols_full + 1; for my $list_idx ( @$list_of_indexes ) { if ( $list_idx > $last_list_idx ) { next; } if ( $list_idx < $last_list_idx_in_cols_full ) { $row = $list_idx % $rows_per_col; $col = int( $list_idx / $rows_per_col ); } else { my $rows_per_col_short = $rows_per_col - 1; $row = ( $list_idx - $first_list_idx_in_cols_short ) % $rows_per_col_short; $col = int( ( $list_idx - $col_count_last_row ) / $rows_per_col_short ); } $self->{marked}[$row][$col] = $boolean; } } } sub __marked_rc2idx { my ( $self ) = @_; my $list_idx = []; if ( $self->{order} == 1 ) { for my $col ( 0 .. $#{$self->{rc2idx}[0]} ) { for my $row ( 0 .. $#{$self->{rc2idx}} ) { if ( $self->{marked}[$row][$col] ) { push @$list_idx, $self->{rc2idx}[$row][$col]; } } } } else { for my $row ( 0 .. $#{$self->{rc2idx}} ) { for my $col ( 0 .. $#{$self->{rc2idx}[$row]} ) { if ( $self->{marked}[$row][$col] ) { push @$list_idx, $self->{rc2idx}[$row][$col]; } } } } return $list_idx; } 1; __END__ =pod =encoding UTF-8 =head1 NAME Term::Choose - Choose items from a list interactively. =head1 VERSION Version 1.774 =cut =head1 SYNOPSIS Functional interface: use Term::Choose qw( choose ); my $array_ref = [ qw( one two three four five ) ]; my $choice = choose( $array_ref ); # single choice print "$choice\n"; my @choices = choose( [ 1 .. 100 ], { alignment => 1 } ); # multiple choice print "@choices\n"; choose( [ 'Press ENTER to continue' ], { prompt => '' } ); # no choice Object-oriented interface: use Term::Choose; my $array_ref = [ qw( one two three four five ) ]; my $new = Term::Choose->new(); my $choice = $new->choose( $array_ref ); # single choice print "$choice\n"; my @choices = $new->choose( [ 1 .. 100 ] ); # multiple choice print "@choices\n"; my $stopp = Term::Choose->new( { prompt => '' } ); $stopp->choose( [ 'Press ENTER to continue' ] ); # no choice =head1 DESCRIPTION Choose interactively from a list of items. C provides a functional interface (L) and an object-oriented interface (L). =head1 EXPORT Nothing by default. use Term::Choose qw( choose ); =head1 METHODS =head2 new $new = Term::Choose->new( \%options ); This constructor returns a new C object. To set the different options it can be passed a reference to a hash as an optional argument. For detailed information about the options see L. =head2 choose The method C allows the user to choose from a list. The first argument is an array reference which holds the list of the available choices. As a second and optional argument it can be passed a reference to a hash where the keys are the option names and the values the option values. Options set with C overwrite options set with C. Before leaving C restores the overwritten options. $choice = $new->choose( $array_ref, \%options ); @choices= $new->choose( $array_ref, \%options ); $new->choose( $array_ref, \%options ); When in the documentation is mentioned "array" or "list" or "elements" or "items" (of the array/list) than these refer to this array passed as a reference as the first argument. For more information how to use C and its return values see L. =head1 SUBROUTINES =head2 choose The function C allows the user to choose from a list. It takes the same arguments as the method L. $choice = choose( $array_ref, \%options ); @choices= choose( $array_ref, \%options ); choose( $array_ref, \%options ); See the L section for more details about the different options and how to set them. See also the following section L. =head1 USAGE AND RETURN VALUES =over =item * If C is called in a I, the user can choose an item by using the L and confirming with C. C then returns the chosen item. =item * If C is called in an I, the user can also mark an item with the C. C then returns - when C is pressed - the list of marked items (including the highlighted item if the option I is set to C<1>). In I C (or C) inverts the choices: marked items are unmarked and unmarked items are marked. =item * If C is called in an I, the user can move around but mark nothing; the output shown by C can be closed with C. Called in void context C returns nothing. If the first argument refers to an empty array, C returns nothing. =back If the items of the list don't fit on the screen, the user can scroll to the next (previous) page(s). If the window size is changed, then as soon as the user enters a keystroke C rewrites the screen. C returns C or an empty list in list context if the C key (or C) is pressed. If the I mode is enabled, an item can be chosen with the left mouse key, in list context the right mouse key can be used instead the C key. Pressing the C allows one to enter a regular expression so that only the items that match the regular expression are displayed. When going back to the unfiltered menu (C) the item highlighted in the filtered menu keeps the highlighting. Also (in I) marked items retain there markings. The Perl function C is used to read the regular expression if L is not available. See option I. =head2 Keys to move around =over =item * the C keys (or the C keys) to move up and down or to move to the right and to the left, =item * the C key (or C) to move forward, the C key (or C or C) to move backward, =item * the C key (or C) to go to the previous page, the C key (or C) to go to the next page, =item * the C key to go back 10 pages, the C key to go forward 10 pages, =item * the C key (or C) to jump to the beginning of the list, the C key (or C) to jump to the end of the list. =back =head2 Modifications for the output For the output on the screen the array elements are modified. All the modifications are made on a copy of the original array so C returns the chosen elements as they were passed to the function without modifications. Modifications: =over =item * If an element is not defined the value from the option I is assigned to the element. =item * If an element holds an empty string the value from the option I is assigned to the element. =item * Tab characters in elements are replaces with a space. $element =~ s/\t/ /g; =item * Vertical spaces in elements are squashed to two spaces. $element =~ s/\v+/\ \ /g; =item * Code points from the ranges of control, surrogate and noncharacter are removed. $element =~ s/[\p{Cc}\p{Noncharacter_Code_Point}\p{Cs}]//g; =item * If the length of an element is greater than the width of the screen the element is cut and at the end of the string are added three dots. =back =head1 OPTIONS Options which expect a number as their value expect integers. =head3 alignment 0 - elements ordered in columns are aligned to the left (default) 1 - elements ordered in columns are aligned to the right 2 - elements ordered in columns are centered =head3 beep 0 - off (default) 1 - on =head3 clear_screen 0 - off (default) 1 - clears the screen before printing the choices =head3 codepage_mapping This option has only meaning if the operating system is MSWin32. If the OS is MSWin32, L is used. By default C converts the characters from Windows code page to DOS code page (the so-called ANSI to OEM conversion). This conversation is disabled by default in C but one can enable it by setting this option. Setting this option to C<1> enables the codepage mapping offered by L. 0 - disable automatic codepage mapping (default) 1 - keep automatic codepage mapping =head3 color Enable the support for ANSI SGR escape sequences. 0 - off (default) 1 - enabled but the current selected element is not colored. 2 - enabled =head3 default With the option I it can be selected an element, which will be highlighted as the default instead of the first element. I expects a zero indexed value, so e.g. to highlight the third element the value would be I<2>. If the passed value is greater than the index of the last array element the first element is highlighted. Allowed values: 0 or greater (default: undefined) =head3 empty Sets the string displayed on the screen instead an empty string. (default: "") =head3 footer Add a string in the bottom line. If a footer string is passed with this option, the option I is automatically set to C<2>. (default: undefined) =head3 hide_cursor 0 - keep the terminals highlighting of the cursor position 1 - hide the terminals highlighting of the cursor position (default) =head3 info Expects as its value a string. The info text is printed above the prompt string. (default: not set) =head3 index 0 - off (default) 1 - return the index of the chosen element instead of the chosen element respective the indices of the chosen elements instead of the chosen elements. =head3 keep I prevents that all the terminal rows are used by the prompt lines. Setting I ensures that at least I terminal rows are available for printing list rows. If the terminal height is less than I I is set to the terminal height. Allowed values: 1 or greater (default: 5) =head3 layout =over =item * 0 - layout off .----------------------. .----------------------. .----------------------. .----------------------. | .. .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | .. .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | | | .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | | | | | .. .. .. .. .. .. .. | | | | | | | | .. .. .. .. .. .. .. | | | | | | | | .. .. .. .. .. .. .. | '----------------------' '----------------------' '----------------------' '----------------------' =item * 1 - default .----------------------. .----------------------. .----------------------. .----------------------. | .. .. .. .. .. .. .. | | .. .. .. .. .. | | .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | .. .. .. .. .. | | .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | .. .. | | .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | | | .. .. .. .. .. .. | | .. .. .. .. .. .. .. | | | | | | .. .. .. | | .. .. .. .. .. .. .. | | | | | | | | .. .. .. .. .. .. .. | '----------------------' '----------------------' '----------------------' '----------------------' 2 - all in a single column .----------------------. .----------------------. .----------------------. .----------------------. | .. | | .. | | .. | | .. | | .. | | .. | | .. | | .. | | .. | | .. | | .. | | .. | | | | .. | | .. | | .. | | | | | | .. | | .. | | | | | | | | .. | '----------------------' '----------------------' '----------------------' '----------------------' =back If I is set to C<0> or C<1> and the unformatted list items fit in one row, the list items are placed in one row without column formatting. This behavior can be disabled by setting I. =head3 ll If all elements have the same length, the length can be passed with this option. C then doesn't calculate the length of the longest element itself but uses the passed value. I refers here to the number of print columns the element will use on the terminal. If I is set, C returns always the index(es) of the chosen item(s) regardless of how I is set. Undefined list elements are not allowed. The replacements described in L are not applied. If elements contain unsupported characters the output might break. If I is set to a value less than the length of the elements, the output could break. If I is set and the window size has changed, choose returns immediately C<-1>. Allowed values: 1 or greater (default: undefined) =head3 margin The option I allows one to set a margin on all four sides. I expects a reference to an array with four elements in the following order: - top margin (number of terminal lines) - right margin (number of terminal columns) - bottom margin (number of terminal lines) - left margin (number of terminal columns) See also L and L. Allowed values: 0 or greater. Elements beyond the fourth are ignored. (default: undefined) =head3 max_cols Limit the number of columns to I. I set to C<2> has always one column. Allowed values: 1 or greater (default: undefined) =head3 max_height If defined sets the maximal number of rows used for printing list items. If the available height is less than I then I is set to the available height. Height in this context means print rows. I overwrites I if I is set to a value less than I. Allowed values: 1 or greater (default: undefined) =head3 max_width If defined, sets the maximal output width to I if the terminal width is greater than I. To prevent the "auto-format" to use a width less than I set I to C<0>. Width refers here to the number of print columns. Allowed values: 1 or greater (default: undefined) =head3 mouse 0 - off (default) 1 - on. Enables the Any-Event-Mouse-Mode (1003) and the Extended-SGR-Mouse-Mode (1006). If the option I is enabled layers for C are changed. Then before leaving C as a cleanup C is marked as C with C<:encoding(UTF-8)>. This doesn't apply if the OS is MSWin32. If the OS is MSWin32 the mouse is enabled with the help of L. =head3 order If the output has more than one row and more than one column: 0 - elements are ordered horizontally 1 - elements are ordered vertically (default) Default may change in a future release. =head3 pad Sets the number of whitespaces between columns. (default: 2) Allowed values: 0 or greater =head3 page 0 - off 1 - print the page number on the bottom of the screen. If all the choices fit into one page, the page number is not displayed. (default) 2 - the page number is always displayed even with only one page. Setting I to C<2> automatically enables the option L. =head3 prompt If I is undefined, a default prompt-string will be shown. If the I value is an empty string (""), no prompt-line will be shown. default in list and scalar context: C default in void context: C =head3 search Set the behavior of C. 0 - off 1 - case-insensitive search (default) 2 - case-sensitive search =head3 skip_items When navigating through the list, the elements that match the regex pattern passed with this option will be skipped. In list context: these elements cannot be marked. Expected value: a regex quoted with the C operator. (default: undefined) =head3 tabs_info The option I allows one to insert spaces at the beginning and the end of I lines. I expects a reference to an array with one to three elements: - the first element (initial tab) sets the number of spaces inserted at beginning of paragraphs - the second element (subsequent tab) sets the number of spaces inserted at the beginning of all broken lines apart from the beginning of paragraphs - the third element sets the number of spaces used as a right margin. Allowed values: 0 or greater. Elements beyond the third are ignored. default: If I is defined, the initial tab and the subsequent tab are set to left-I and the right margin is set to right-I. If I is not defined, the default is undefined. =head3 tabs_prompt The option I allows one to insert spaces at the beginning and the end of I lines. I expects a reference to an array with one to three elements: - the first element (initial tab) sets the number of spaces inserted at beginning of paragraphs - the second element (subsequent tab) sets the number of spaces inserted at the beginning of all broken lines apart from the beginning of paragraphs - the third element sets the number of spaces used as a right margin. Allowed values: 0 or greater. Elements beyond the third are ignored. default: If I is defined, the initial tab and the subsequent tab are set to left-I and the right margin is set to right-I. If I is not defined, the default is undefined. =head3 undef Sets the string displayed on the screen instead an undefined element. default: "" =head2 Options List Context =head3 include_highlighted In list context when C is pressed 0 - C returns the items marked with the C. (default) 1 - C returns the items marked with the C plus the highlighted item. 2 - C returns the items marked with the C. If no items are marked with the C, the highlighted item is returned. =head3 mark I expects as its value a reference to an array. The elements of the array are list indexes. C preselects the list-elements correlating to these indexes. Elements greater than the last index of the list are ignored. This option has only meaning in list context. (default: undefined) =head3 meta_items I expects as its value a reference to an array. The elements of the array are list indexes. These elements can not be marked with the C or with the right mouse key but if one of these elements is the highlighted item it is added to the chosen items when C is pressed. Elements greater than the last index of the list are ignored. This option has only meaning in list context. (default: undefined) =head3 no_spacebar I expects as its value a reference to an array. The elements of the array are indexes of the list which should not be markable with the C or with the right mouse key. If an element is preselected with the option I and also marked as not selectable with the option I, the user can not remove the preselection of this element. I elements greater than the last index of the list are ignored. This option has only meaning in list context. (default: undefined) =head1 ERROR HANDLING =head2 croak C croaks if passed invalid arguments. =head2 carp If pressing a key results in an undefined value C carps with C and returns I or an empty list in list context. =head1 REQUIREMENTS =head2 Perl version Requires Perl version 5.10.1 or higher. =head2 Optional modules =head3 Term::Choose::LineFold::XS If L is installed, its functions will be used automatically in place of the pure-Perl implementations, providing faster performance. C requires Perl version 5.16.0 or higher. =head3 Term::ReadKey If L is available it is used C to read the user input and C to get the terminal size. Without C C is used to read the input and C to get the terminal size. If the OS is MSWin32 it is used L to read the user input and to get the terminal size. =head2 Decoded strings C expects decoded strings as array elements. =head2 Encoding layer for STDOUT For a correct output it is required an appropriate encoding layer for STDOUT matching the terminal's character set. =head2 Monospaced font It is required a terminal that uses a monospaced font which supports the printed characters. =head2 Ambiguous width characters By default ambiguous width characters are treated as half width. If the environment variable C is set to a true value, ambiguous width characters are treated as full width. The support for the old variable name C will be removed. =head2 Escape sequences By default C uses C to get the appropriate escape sequences. If the environment variable C is set to a true value, hardcoded ANSI escape sequences are used directly without calling C. The escape sequences to enable the I mode are always hardcoded. =head2 Other environment variables If the environment variable C existed when calling C: C is set to C<0> if the C/C key was the only key pressed and C is set to C<1> if other keys than C/C were also pressed. =head2 MSWin32 If the OS is MSWin32 L and L with ANSI escape sequences are used. See also L. =head1 SUPPORT You can find documentation for this module with the perldoc command. perldoc Term::Choose =head1 AUTHOR Matthäus Kiem =head1 CREDITS Based on the C function from the L module. Thanks to the L and the people form L for the help. =head1 LICENSE AND COPYRIGHT Copyright (C) 2012-2025 Matthäus Kiem. This library is free software; you can redistribute it and/or modify it under the same terms as Perl 5.10.0. For details, see the full text of the licenses in the file LICENSE. =cut Term-Choose-1.774/PaxHeaders/Changes0000644000000000000000000000013215003444171014231 xustar0030 mtime=1745766521.697980772 30 atime=1745766522.401967993 30 ctime=1745767633.701079608 Term-Choose-1.774/Changes0000644000175000001440000010521515003444171015007 0ustar00mmusers00000000000000Revision history for Term::Choose 1.774 2025-04-27 - Undone the last 'print_columns' update. - Optional module 'Term::Choose::LineFold::XS'. - New tests for 'Term::Choose::LineFold'. - Update documentation. 1.773 2025-04-10 - Removed expensive shortcut in 'line_fold'. - Updated 'print_columns': less slowdown with long strings. - New function 'adjust_to_printwidth' in LineFold.pm. - Raised Perl minimum version to 5.10.1. - Made 'char_width' exportable. 1.772 2025-03-31 - Refactored 'print_columns' and 'cut_to_printwidth'. - Update documentation Term::Choose::LineFold. 1.771 2025-03-27 - Removed 'cut_to_printwidth' from the public. 1.770 2025-03-26 - Bugfix documentation Term::Choose::LineFold. 1.769 2025-03-24 - Make 'print_columns', 'cut_to_printwidth' and 'line_fold' public. - 'cut_to_printwidth': The context decides whether the remainder is also returned. - 'line_fold': Passing the width is optional. 1.768 2025-03-05 - Refactoring. 1.767 2024-10-28 - Fixed spelling in pod. 1.766 2024-10-28 - Unicode 16. 1.765 2024-05-02 - If the current layout is 2, bypass the loops in '__set_cell'. 1.764 2024-04-20 - Code refactoring. 1.763 2024-01-18 - Unicode 15.1. - Zero width for Hangul Jamo Extended-B. 1.762 2023-05-16 - line_fold: update option color. 1.761 2023-04-28 - line_fold: update option binary_filter. 1.760 2023-04-06 - Option binary_filter for line_fold. 1.759 2023-03-26 - Update table char_width. - Bugfix line_fold. 1.758 2023-03-17 - LineFold.pm: use ansi escape to reset colors. - Uniocde 15.0. - Update documentation. 1.757 2022-07-17 - Constants.pm: removed 'keys' tag. - Check 'get_term_size' for errors. - Update char width tables. - Added 'tools/build_TCF_char_width_table_modules.pl'. 1.756 2022-07-08 - Cache character widths in a hash instead of in an array. - Code refactoring. - Bugfix: _reset_term if changed term size with set option 'll'. - Update documentation. 1.755 2022-07-01 - layout set to 3 now causes choose to die; 1.754 2022-06-04 - Update documentation. - Update defaults 'tabs_prompt' and 'tabs_info'. - Bugfix margin. 1.753 2022-05-19 - Bugfix in info and prompt lines. 1.752 2022-05-14 - Bugfix option 'margin'. - Update ValidateOptions.pm. 1.751 2022-05-07 - Update options 'margin', 'tabs_info' and 'tabs_prompt'. 1.750 2022-05-02 - Option 'margin' expects a reference to an array instead of an integer. 1.749 2022-05-01 - Removed vt52 spezial keys. - 'qr'-operator for the search regexp. - New option 'margin'. 1.748 2022-04-06 - Search: 'readline' is now in Term::From::ReadLine. 1.747 2022-03-26 - Update documentation. - Code refactoring. 1.746 2022-03-13 - Char-width-tables: Arabic numbers in category 'Cf' to print-width 1. - Char-width-tables: update to Unicode 14. - Update year copyright. 1.745 2021-11-11 - Raised Perl minimum version to 5.10.0. - Use '\v' and '\R'. 1.744 2021-11-08 - Bugfix "vertical-space" in line_fold. 1.743 2021-10-18 - Update Documentation. - Search regex: no 'qr'. 1.742 2021-10-02 - Update ValidateOptions. - Update user_input. 1.741 2021-09-30 - Search: eval user input. - Option 'skip_items': croaks if the value is not quoted with the 'qr' operator. 1.740 2021-09-27 - Bugfix in Search.pm: import the required constants. 1.739 2021-09-17 - Undo the previous "bugfix". - Bugfix in current_layout. 1.738 2021-09-17 - Bugfix option layout. 1.737 2021-08-28 - Option 'layout': removed one layout. 1.736 2021-08-24 - renamed the option 'f3' to 'search'. - 'Ctrl-F' instead of 'F3' to open the search prompt. - PageUP/PageDown: 'Ctrl-P'/'Ctrl-N' instead of 'Ctrl-B'/'Ctrl-F'. - search: print filter-string. - Refactoring page/footer row. 1.735 2021-07-12 - prepare_promptline gets its own term_w. 1.734 2021-07-11 - Bugfix: undo the last 'line_fold' update. 1.733 2021-06-22 - Modified footer line. - New option 'max_cols'. - Updates option' skip_items': expects a regex quoted with the 'qr' operator. - Update option 'page': additional mode. - Use Carp again. - Update function 'line_fold'. 1.732 2021-06-17 - Bugfix page count. - Update 'page' and 'footer'. - Added environment variable TC_POS_AT_F3. - Constants.pm and Screen.pm: refactoring export. 1.731 2021-04-25 - Replace 'croak' with 'die' and 'carp' with 'warn'. - Code refactoring. 1.730 2021-04-06 - Removed deprecated option name 'footer_string'. - New experimental option 'skip_items'. - Code refactoring. 1.720 2021-03-04 - Filter choices. - Bugfix in list_idx2rc. - Win32: fixed mouse mode. - Code refactoring. - Update documentation. 1.713 2021-01-01 - Add bugracker info to the Makefile.PL. - Update year copyright. 1.712 2020-10-25 - Removed deprecated options 'justify' and 'lf'. - Option 'mouse': values other than 0 and 1 are no longer allowed. - Renamed 'footer_string' to 'footer'. - New option 'footer'. - Update documentation. 1.711 2020-04-21 - Update unicode table to unicode 13.0. - Update footer_string format. - Update option validation. 1.710 2020-03-08 - 'line_fold': new option 'join'. 1.709 2020-02-24 - Bugfix option 'footer_string'. 1.708 2020-02-24 - Experimental option 'footer_string'. 1.707 2019-11-22 - Update option validation. 1.706 2019-11-21 - Deprecated the option 'lf'. - New options 'tabs_info' and 'tabs_prompt'. - Option 'color': added a valid value (2). 1.705 2019-10-18 - Bugfix in 'busy_string'. 1.704 2019-10-13 - Added 'busy_string'. 1.703 2019-09-21 - Update unicode tables. - Update functional interface. 1.702 2019-09-13 - Option 'lf': fixed documentation. 1.701 2019-09-12 - Issued around `tput`. [GH #6 gregoa] - Bugfix: enable colored output for the 'undef' and 'empty' string. - Set 'col_width_plus' only once. - Bugix in line_fold: make colored output work with a single prompt line. 1.700 2019-09-05 - Option 'mouse': changed from 5 to 2 allowed values. - Renamed option 'justify' to 'alignment'. - Refactored mouse mode. - New file Screen.pm. - Use 'tput' to get the escape sequences. 1.655 2019-08-03 - Announcement changes mouse mode. 1.654 2019-07-07 - Bugfix backup instance defaults. 1.653 2019-07-07 - New file ValidateOptions.pm. - Refactoring options handling. - Removed DESTROY. 1.652 2019-07-04 - Make __validate_and_add_options more portable. 1.651 2019-07-02 - Bugfix constant LINE_FEED. 1.650 2019-07-02 - Replace KEY_ENTER with LINE_FEED/CARRIAGE_RETURN. 1.649 2019-06-30 - Update TC_RESET_AUTO_UP. - Refactoring __goto. - Renaming p_begin to first_page_row. - hide cursor as early as possible, show cursor as late as possible - "line_fold": 'init_tab' and 'subseq_tab' are passed as options; new option 'color'. - Remove color code from _prepare_promptline and use the 'line_fold' option 'color' instead. 1.648 2019-05-06 - Code refactoring. 1.647 2019-05-02 - Initialize env var TC_RESET_AUTO_UP with 0 if exits env var TC_RESET_AUTO_UP. 1.646 2019-04-05 - Add Ctrl-Q and Ctrl-X to the constants. - To return undef: Ctrl-Q instead of Ctrl-D. 1.645 2019-03-31 - Update char-width tables. - Fast forward/backward: 10 instead of 25 pages at once. - Add missing semicolon in 'print_columns'. - Code refactoring. 1.644 2019-01-25 - Option 'll': allow the use of the full term width. 1.643 2019-01-20 - MSWin32: use always Win32::Console::ANSI. - Bugfix mouse mode. 1.642 2018-12-25 - Bugfix "line_fold". 1.641 2018-12-17 - Bugfix "meta_items". 1.640 2018-12-16 - "clear_lines_to_end_of_screen" if not "clear_screen". 1.639 2018-12-14 - Update char-width tables. 1.638 2018-11-30 - Option 'll': don't create a length-array but only assign when required. - Bugfix option 'mouse'. 1.637 2018-11-28 - Bugfix: don't allow to select 'meta_items' with Cntrl-SpaceBar. 1.636 2018-11-25 - Update char-width tables. 1.635 2018-11-24 - Don't enable codepage mapping if 'color' is set to avoid two different defaults. 1.634 2018-11-22 - New option 'codepage_mapping'. - Code cleanup. - Update documentation. 1.633 2018-11-21 - Update option 'color'. 1.632 2018-11-17 - Bugfix string concatenation in substitution. 1.631 2018-11-17 - If 'll' is set, no copy of the passed list is made no matter if 'color' is enabled or not. 1.630 2018-11-16 - Update option 'color'. 1.629 2018-11-16 - If 'll' is set, 'choose' returns -2 if 'll' is greater than the terminal width. - If 'll' is set and 'color' is not set, no copy of the passed list is made. - New option 'color'. 1.628 2018-11-12 - Changed modification of list elements. - 'line_fold': use "\v" instead of "\n" to split the string. - Modified 'CharWidthDefault.pm' and 'CharWidthAmbiguousWide.pm'. - If 'll' is set, all list elements have to be defined. - Removed 'ref' conversation. - Removed "no warnings 'utf8'". - Code refactoring. - Update documentation. 1.627 2018-08-21 - Code refactoring. 1.626 2018-08-21 - Bugfix in 'prepare_page_number'. - Modified "Term::Choose::Linux" and "Term::Choose::Win32" so that "Term::Form" can use them. - Added methods 'hide_cursor', 'show_cursor' and 'clear_screen'; used in "Term::TablePrint". - If OS is MSWin32, use "Win32::Console::PatchForRT33513". 1.625_03 2018-08-18 - Developer release 1.625_02 2018-08-18 - Developer release 1.625_01 2018-08-16 - Developer release - MSWin32 1.625 2018-08-15 - Fixed syntax error in "Term::Choose::Win32". 1.624 2018-08-14 - Undo "1.623". 1.623 2018-08-14 - Added methods 'hide_cursor', 'show_cursor'. 1.622 2018-08-08 - Fixed minor typo in the pod. [GH #2 manwar] 1.621 2018-08-07 - Bugfix page-down saved position. 1.620 2018-08-06 - Added the posibility to move forward/backward 25 pages at once. 1.610 2018-08-03 - Bugfix in page-down. 1.609 2018-07-21 - Set environment variable TC_AMBIGUOUS_WIDE to treat ambiguous characters as full width. 1.608 2018-07-20 - Bugfix key codes Win32. 1.607 2018-07-18 - Modified constant values. 1.606 2018-07-18 - No timeout for 'getc' - would require non-blocking read. 1.605 2018-07-18 - Bugfix "my $Term_ReadKey": don't assign a value. - Timeout for 'getc' with "Time::HiRes". - "Term::Choose::Constants": new tag 'form'. 1.604 2018-07-14 - Removed the optional module "Term::ReadKey" from the Makefile.PL. 1.603 2018-07-14 - Make "Term::ReadKey" optional. - "Term::Choose::Constants": new export tag 'screen'. 1.602 2018-07-12 - Refactoring table character-width. 1.601 2018-07-10 - Bugfix backup self. - Bugfix in 'cut_to_printwidth'. 1.600 2018-07-02 - "Term::Choose" uses now its own function to determine the print width of a character. - Character widths are now cached. - Code refactoring. 1.518 2018-06-20 - Removed 'pad_one_row' info. - Removed deprecated method 'config'. - 'include_highlighted' defaults to 0. - Added undocumented value of the option 'include_highlighted' to the documentation. - If not OO: pass $self directly to '__choose'. 1.517 2018-06-15 - New option 'include_highlighted'. - New option 'meta_items'. - Bugfix backup self. - Update documentation. 1.516 2018-04-20 - Bugfix prompt-line. 1.515 2018-04-06 - Documentation for the option 'info'. 1.514 2018-03-22 - New option 'info'. 1.513 2018-03-06 - Ctrl-Spacebar affects all elements independently of the cursor position. 1.512 2018-02-25 - "line_fold": 'split' with limit -1 preserves trailing empty fields. - Warning if deprecated method "config" is used. - Env var "tc_reset_auto_up". 1.511 2018-02-10 - Bugfix: don't link the original list to a self hash element. - Deprecation: method "config". - Update documentation. 1.510 2018-02-04 - Bugfix: don't overwrite option "layout" - 'cut_to_printwidth': don't copy parameter. 1.509 2018-01-04 - Removed the option "pad_one_row". 1.508 2018-01-04 - Improved language in POD [RT #123890 gregoa]. - Bugix in "all_in_one_row". 1.507 2017-08-09 - Refactoring `line_fold`. 1.506 2017-04-26 - Code refactoring. - Update year copyright. 1.505 2016-08-14 - Don't hide "Term::Choose::Constants" on Pause [https://github.com/kuerbis/Term-Choose_HAE/issues/2 stesachse]. 1.504 2016-03-21 - If ll is set, choose returns always indexes. - If ll is set and the window size has changed, choose returns immediately -1. 1.503 2016-03-11 - Announcement of future new behavior of the option "ll". 1.502 2016-02-29 - Don't hide "Term::Choose::LineFold" from Pause [https://github.com/kuerbis/Term-Choose-Util/issues/2 stepht]. - Code refactoring. 1.501 2016-02-22 - Bugfix in "idx_to_marked". 1.500 2016-02-21 - Update "line_fold". - Bugfix in "cut_to_printwidth". 1.209_02 2016-02-15 - Bugfix in "line_fold" - handle trailing newlines. 1.209_01 2016-02-14 - New module "Term::Choose::LineLineFold". 1.209 2016-01-30 - "mark" and "no_spacebar" - indexes out of range: now dies with an appropriate error message. - Bugfix: with only one row a string can still be to long if there is only one string. - If the option "ll" is enabled: empty strings are no longer replaced. - Code refactoring - Code cleanup. - Update documentation. 1.208 2015-10-21 - Update documentation. 1.207 2015-10-05 - Make "Term::Choose::Constants" visible, so it is available for "Term::Choose_HAE". 1.206 2015-10-02 - Stable release - no changes. 1.205_04 2015-09-26 - Code refactoring. 1.205_03 2015-09-22 - Bugfix "i_col". - Code refactoring. 1.205_02 2015-09-19 - Code refactoring. 1.205_01 2015-09-18 - Code refactoring. 1.205 2015-09-09 - Code refactoring. 1.204 2015-09-09 - Code refactoring. 1.203 2015-09-09 - Reserve one space for the (hidden) terminal cursor: Terminalwidth - 1. 1.202 2015-07-02 - Removed redundant documentation. 1.201 2015-04-27 - Moved "Expect"-tests to the "xt"-folder. 1.200_01 2015-04-25 - One new test and one test modified. 1.200 2015-03-27 - "Ctrl-SpaceBar": all if cursor on first row else current page. 1.120 2015-03-11 - Bugfix in Win32 "__clear_screen". 1.119 2015-02-05 - use constant. - Update year copyright. 1.118 2014-12-08 - Perl minimum version: "5.8.3". - Update build requirements. 1.117 2014-11-20 - Stable release. - Make tests which use "Expect" optional. 1.116_03 2014-11-03 - Bugfix "marked". 1.116_02 2014-11-02 - Keep the cursor position when the screen is resized. - Code refactoring. 1.116_01 2014-10-30 - New option "mark". - Don't reset the marked items if the screen is resized. - Update documentation. 1.116 2014-09-06 - Stable release - no changes. 1.115_01 2014-09-05 - Perl minimum version from "5.10.0" to "5.8.0". - Update documentation. 1.115 2014-09-03 - Stable release - no changes. 1.114_04 2014-08-24 - Bugfix in reset screen. 1.114_03 2014-08-19 - Modified tests. 1.114_02 2014-08-19 - Modified test. 1.114_01 2014-08-14 - Update tests. - Removed option "limit". - Update documentation. 1.114 2014-08-13 - Re-enabled "limit". - Announcement: "limit will be removed". - Removed developer tests. - Update documentation. 1.113_10 2014-08-12 - Removed option "limit". - Update tests. 1.113_09 2014-08-11 - Update tests. 1.113_08 2014-08-09 - Update tests. 1.113_07 2014-08-07 - Update tests. - Perl minimum version "5.10.0". - Removed warning: empty list. 1.113_06 2014-08-06 - Update tests. - Removed "Build.PL". 1.113_05 2014-08-05 - Update tests. 1.113_04 2014-08-05 - Update tests. 1.113_03 2014-08-03 - Update keycodes. - Update tests. 1.113_02 2014-08-03 - Developer test. 1.113_01 2014-08-02 - Added developer tests. - Invalid options are now fatal. - Removed "Win32::Console::ANSI". - Update documentation. - Removed POD from "Term::Choose::Linux", "Term::Choose::Win32" and "Term::Choose::Constants". 1.113 2014-08-02 - Announcement: invalid options will become fatal. - Announcement: "Win32::Console::ANSI" will be removed. - Code refactoring: prepare the announced changes. - Removed developer tests. - Update documentation. 1.112_03 2014-08-01 - Code refactoring. - Replaced test. 1.112_02 2014-07-31 - Bugfix: argument checking if "choose" is called as function. - Modified test. 1.112_01 2014-07-31 - New test. 1.112 2014-07-29 - Removed undocumented behavior. - Update documentation. 1.111 2014-07-15 - It is now possible to disable the 'print "\e(U"' with the TC_KEEP_WINDOWS_MAPPING environment variable. - Announcement: "\e(U" will be removed in a future release. - Update documentation. 1.110 2014-06-28 - Improved argument validation: don't allow references as values for the options "prompt", "empty" and "undef". - Changed the workaround concerning the "\e(U" escape sequence in "Term::Choose::Win32". - Renamed variables and hash keys. 1.109 2014-05-22 - Bugfix warning "invalid option name". - Bugfix option "max_width / improvement layout. - Removed the period at the end of the error messages. - Improved documentation. 1.108 2014-04-17 - Fixed error in variable name in "Term::Choose::Win32". 1.107 2014-04-09 - Documentation: update and bugfix. 1.106 2014-04-09 - Use "Win32::Console" directly to get the terminal size. - Update documentation. - Update Makefile.PL. 1.105 2014-03-18 - Code refactoring and cleanup. 1.104 2014-03-13 - Bugfix cleanup. 1.103 2014-03-08 - Added experimental option "no_spacebar". - Update documentation. 1.102 2014-03-07 - Bugfix option "limit". - Code refactoring. 1.101 2014-03-06 - Change behavior of layout 2. - Fixed documentation. 1.100 2014-03-06 - Rewritten in OO. - OS specific code: plugins "Term::Choose::Linux" and "Term::Choose::Win32". 1.075_01 2014-02-27 - Increased version number to get "prerequisite" warning. 1.074_01 2014-02-26 - Rewritten in OO. - Outsourced OS specific code to "Term::Choose::Linux" and "Term::Choose::Win32". 1.074 2014-02-13 - Added "use warnings;". - Added LICENSE file. - Added release test "year_copyright.t" - Update documentation. 1.073 2014-01-26 - Update release test "compare_Choose_Win32.t" to sync with Term::Choose::Win32 version 0.020. 1.072 2014-01-24 - Prevent references from breaking the output. - Update README. - Update license. 1.071 2014-01-21 - Keep track of the terminal size instead of using "SIGWINCH". - Update documentation. 1.070 2014-01-18 - Default value for option "limit" from 100_000 to not set (undef). - Removed the artificial general upper limit for options with no specific upper limit. - Update documentation. 1.069 2014-01-04 - Update copyright. - Removed example. A bugfixed version of the example-script is now located in the "App::DBBrowser" distribution and is called "db-browser". 1.068 2013-12-25 - Increased the minimum required Perl version from "5.10.0" to "5.10.1". - Update documentation. - Update example. 1.067 2013-12-23 - Bugfix documentation. - Update example. 1.066 2013-12-18 - Update documentation. - Example: bugfix and update. 1.065 2013-12-13 - Removed the deprecated option name "screen_width". - Modified behavior "relative position". - The minimum required version of "Unicode::GCString" is now "2013.10". - Replaced "s/\P{Print}/\x{fffd}/g" with "s/\p{C}//g". - Added "no warnings utf8". - Updated documentation. - Example: bugfixes, updates and refactoring. - Example: Removed the option "Length". 1.064 2013-09-24 - Update/bugfix in: keep relative position when moving page-wise. 1.063 2013-09-23 - Keep the relative row position when moving page-wise. 1.062 2013-09-18 - Code refactoring. 1.061 2013-09-07 - Added option "max_height". - Renamed option "screen_width" to "max_width". - Updated documentation. 1.060 2013-09-06 - Allow installation on Win32 - Term::Choose::Win32 now depends on Term::Choose. - Bugfix example. 1.059 2013-09-04 - Code refactoring. - Updated documentation. - Bugfix example. 1.058 2013-08-25 - Code refactoring. - Imporved documentation. - Updated example. 1.057 2013-08-10 - Example: fixed bug. 1.056 2013-08-10 - Example: update and bug fix. 1.055 2013-06-21 - Example: bug fix. 1.054 2013-06-21 - Removed "experimental" from option "lf" and from option "ll". - Updated documentation. - Example: bug fixes. 1.053 2013-06-17 - Fixed bug: replaced "\N{LINE FEED}" with "\n" (in "_prepare_promptline"). Before Perl v5.16 an occurrence of \N{CHARNAME} doesn't load "charnames" module automatically. 1.052 2013-06-14 - Modified experimental option "lf". - Update documentation. 1.051 2013-06-10 - Fixed bug (size_changed). - Added option "keep". - Removed experimental option "st". - Added experimental option "lf". - Update documentation. 1.050 2013-06-05 - Removed experimental option "head". - Update documentation. - Example: changed local_readline. - Example: bugfix. 1.049 2013-06-03 - Announcements. - Code refactoring. - Update documentation. - Update example. 1.048 2013-05-29 - Code refactoring: reuse the length of strings calculated in "_length_longest". - Removed deprecated option name "keep". - Update documentation. - Removed option "max-depth" from the example. - Update example. 1.047 2013-05-26 - Added experimental option "st". - Code cleanup. - Update documentation. - Update example. 1.046 2013-05-25 - Added support for multi-line prompt. - Added "Text::LineFold" as a required module. - Keep at least 4 list lines. - Code cleanup. - Update documentation. - Example: update and bug fix. 1.045 2013-05-24 - Added extended SGR mouse mode (1006) support. - The mouse wheel scrolls now page-wise instead of line-wise. - Updated documentation. - Updated example. 1.044 2013-05-23 - Experimental option "keep" is now called "head". - Updated documentation. - Example: update and bug bixes. 1.043 2013-05-20 - Replaced "given/when". - Updated documentation. - Example: update and bug fix. 1.042 2013-05-16 - Added the experimental option "keep". - Non printable characters are replaced with "\x{fffd}" instead of a dot. - Buildin "ref" is used instead of "Scalar::Util::reftype" to check arguments. - Removed deprecated option name "length_longest". - Code refactoring. - Example: update and bug fixes. 1.041 2013-05-12 -"_init_scr" is now OO, so that DESTROY does the cleanup. - Added $SIG{'INT'} handler. - Code cleanup. - Fixed bug in example (stringify gcstring). 1.040 2013-05-10 - Removed experimental option "cp_list". -"s/\p{Cntrl}//g;" --> "s/\P{Print}/./g;" - Refactoring "_unicode_cut" (now called "_unicode_trim"). - Strings trimmed with "_unicode_sprintf" don't end with "...". - Code refactoring. - Update documentation. - Update example. 1.039 2013-05-05 - Switched from "Text::CharWidth" back to "Unicode::GCString" ("Unicode::GCString" supports Unicode Version 6.2). - The minimum required version of "Unicode::GCString" is now "2012.10". - Example: update. - Example: adaption to work again with "Unicode::GCString". 1.038 2013-05-02 -Added experimental option "cp_list". -Updated documentation. 1.037 2013-04-29 - Example: fixed bugs. - Example: added progess bar threshold (option). - Example: changed the "binary filter"/ removed the option "Binary filter". 1.036 2013-04-24 - Switched from "Unicode::GCString/columns" to "Text::CharWidth::mbswidth" to determine print columns (faster). - Update documentation. 1.035 2013-04-23 - Refactoring "_unicode_cut" (Text::WideChar::Util::mbtrunc). - Refactoring "_unicode_sprintf" (truncated strings end with "..."). 1.034 2013-04-23 - Code refactoring. - Code cleanup. - Update documentation. 1.033 2013-04-17 - Bugfix (KEY_END). - Bugfix and code cleanup in "_getch". - Reset "$|" before leaving "choose". - Updated documentation. - Example: update. - Example: "binary filter" disabled by default 1.032 2013-04-11 - Removed "autodie" from the tests - perl 5.10.0 doesn't provide autodie. - Fixed "prompt" bug in "_wr_screen". 1.031 2013-04-09 - Option "prompt": the value '' (empty string) means now no promptline. - Skip checking string-length in layout "3" if "length_longest" <= "maxcols". - The option "length_longest" is now called also "ll". - Changed mininum Perl version from "5.10.1" to "5.10.0". - Code cleanup. - Updated documentation. - Updated example. 1.030 2013-04-04 - Removed the undocumented appending of "(multiple choice ...)" to the promptstring in listcontext. - Code cleanup. - Updated documentation. - Example: Added option "expand". 1.029 2013-04-01 - Added experimental feature: "Ctrl-SpaceBar" inverts the choices. - "choose": set "$\" and "$," to "undef". - Code refactoring. - Removed deprecated options from documentation. - Example: Modified "binary filter". 1.028 2013-03-07 - Fixed bug in "_handle_mouse" (all_in_one_row). - Updated "_handle_mouse". - Options: replaced "mouse_mode" with "mouse". - Options: replaced "empty_string" with "empty". - Code refactoring. - Code cleanup. - Imporved documentation. - Example: bug fixes. - Example: updated function "choose_a_number". 1.027 2013-03-05 - Removed "utf8" pragma: only ASCII sourcecode and "utf8::upgrade" does not need "use utf8". - Example: added option "sssc_mode". 1.026 2013-03-02 - Code refactoring. - Improved documentation. - Example: update. 1.025 2013-02-19 - Option "pad_one_row" defaults to the value of the option "pad". - Modified "croak" messages. - Code refactoring. - Updated documentation. - Updated example. 1.024 2013-02-09 - "Home-key" and "End-key": removed status "experimental". - Updated documentation. - Example: bug fixes. - Example: code refactoring. 1.023 2013-02-06 - Added support for the "Home-key" and the "End-key" (experimental). - Updated documentation. - Example: code refactoring. 1.022 2013-01-31 - Example: update and bug fixes. 1.021 2013-01-28 - Removed deprecated options "right_justify" and "vertical". - Updated documentation. - Updated copyright. - Example: switched back to "File::Find". - Example: added postgres. 1.020 2013-01-02 - Added option "index". - Updated documentation. - Updated example. 1.019 2012-12-26 - The "layout" "1" starts more broadly now (if more than one row). - Options: replaced "right_justify" with "justify" (with new value "centered"). - Options: replaced "vertical" with "order". - Updated documentation. - Updated example. 1.018 2012-11-28 - warn "EOT" if "_getch" returns "undef". - Example: added "Union". - Example: update and bug fixes. 1.017 2012-11-15 - Fixed bug in "if size_changed". - Added: Check "ReadKey"/"_getch" if return value is defined. - Added: "Ctrl+D" behaves as the "q" key. - Code cleanup. - Build.PL/Makefile.PL: "die 'No support for OS' if $^O eq 'MSWin32';". - Example: updated and reduced dependencies. 1.016 2012-11-11 - Code refactoring (clear_screen). - Removed "Choose/GC.pm". - Code cleanup. - Improved documentation. - Example: added "Join Tables". - Example: update and bug fixes. 1.015 2012-10-22 - Code cleanup. - Improved documentation. - Example: update and bug fixes. 1.014 2012-10-10 - Code cleanup. - Updated example. 1.013 2012-10-08 - Unicode::GCString: moved from "eval" to "utf8::upgrade". - Improved documentation. - Updated example. 1.012 2012-10-04 - Term::Choose with Unicode support and Term::Choose::GC removed. - Changed "eval" bracketing. - Example: removed "delete" option. - Example: fixed bugs. 1.011 2012-10-02 - Removed/replaced "smartmatch" operators. - Improved documentation. - Example: update and bug fixes. - Example: from "File::Find" to "File::Find::Rule". 1.010 2012-09-26 - Example: update and bug fixes. 1.009 2012-09-25 - Removed deprecated option names "max_list" and "cursor". - Updated documentation. - Example: bug fix and update. 1.008 2012-09-24 - Option "page" now enabled by default. - Option "cursor" is now called "default". - Option "max_list" is now called "limit". - Improved documentation. - Updated example. 1.007 2012-09-07 - Fixed bug in "_size_and_layout" (if "vertical" == 0). - Fixed bug in "_write_first_screen" (condition for calling "_set_this_cell"). - Code refactoring. - Some changes of the allowed option values. - Updated example. - Updated documentation. 1.006 2012-09-06 - Added option "page". - Code refactoring. - Fixed bugs and updated example. - Updated documentation. 1.005 2012-09-01 - Added option "cursor". - Fixed mouse_mode bugs. - Updated documentation. 1.004 2012-08-29 - "_size_and_layout" back to the old position after "_print_promptline". - Code refactoring. - Improved documentation. 1.003 2012-08-28 - Check for existing SIGWINCH handler. - Code refactoring. - Removed $arg->{step} from "_print_promptline" (GC) ("_print_promptline" not available if $arg->{prompt} == 0). - Updated example. - Improved documentation. 1.002 2012-08-23 - Updated Example. - Code refactoring. - Improved documentation. 1.001 2012-08-12 - $VERSION: switched from dotted-integers to decimal numbers ("0.7.16" -> "1.001"). - Changed the maximal allowed value for the option "length_longest" from 999_999_999 to 999. - Updated documentation. 0.7.16 2012-08-12 - From "$XSIG{WINCH}[4]" (Signals::XSIG) to "local $SIG{WINCH}". - Updated "Page Up"/"Page Down". - Removed option "extra_key". - Updated documentation. 0.7.15 2012-08-09 - Added "Page Up" and "Page Down" keys (experimental). 0.7.14 2012-08-08 - Added option "length_longest". - Updated documentation. - Code refactoring. 0.7.13 2012-08-05 - Removed option "length_longest". 0.7.12 2012-08-05 - Code refactoring - "_size_and_layout": don't copy the list but use indexes. - Added option "length_longest". - Changed "_unicode_cut" and "_unicode_sprintf" - Changed optionname "vertical_order" to "vertical". - Changed the order of the values from the option "layout". - Updated example. - Improved documentation. 0.7.11 2012-07-31 - "_size_and_layout": back to version 0.7.9. 0.7.10 2012-07-30 - Code refactoring - "_size_and_layout": don't copy the list. - Fixed bug in example. - Improved documentation. 0.7.9 2012-07-29 - Form "and,or,not" to "&&,||,!". - Minor code changes. - Updated example. - Improved documentation. 0.7.8 2012-07-27 - Added example. - Minor code changes. 0.7.7 2012-07-24 - Fixed bug in _unicode_cut. - Improved documentation. 0.7.6 2012-07-23 - Added Term::Choose::GC. - Code refactoring. - Improved documentation. 0.7.5 2012-07-21 - Don't print control characters. - Improved Documentation. 0.7.4 2012-07-19 - Minor code changes. - Improved Documentation. 0.7.3 2012-07-17 - Make calling "choose" in void context more normal. - Modified error messages. - "max_list": exceeding "max_list" now warns and cuts the used list to max_list instead of dying. - Added bug section. - Improved documentation. 0.7.2 2012-07-14 - Press a key after warnings "not a valid value for option" or "no such option" to continue. - Consideration of the case of calling "choose" in a void context. - Code cleanup. - Documentation cleanup. 0.7.1 2012-07-13 - First release on cpan. Term-Choose-1.774/PaxHeaders/LICENSE0000644000000000000000000000013214762006320013744 xustar0030 mtime=1741163728.313410204 30 atime=1745740083.734899018 30 ctime=1745767633.701079608 Term-Choose-1.774/LICENSE0000644000175000001440000004366114762006320014530 0ustar00mmusers00000000000000This software is copyright (c) 2025 by Matthäus Kiem. This is free software; you can redistribute it and/or modify it under the same terms as the Perl 5 programming language system itself. Terms of the Perl programming language system itself a) the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version, or b) the "Artistic License" --- The GNU General Public License, Version 1, February 1989 --- This software is Copyright (c) 2025 by Matthäus Kiem. This is free software, licensed under: The GNU General Public License, Version 1, February 1989 GNU GENERAL PUBLIC LICENSE Version 1, February 1989 Copyright (C) 1989 Free Software Foundation, Inc. 51 Franklin St, Suite 500, Boston, MA 02110-1335 USA Everyone is permitted to copy and distribute verbatim copies of this license document, but changing it is not allowed. Preamble The license agreements of most software companies try to keep users at the mercy of those companies. By contrast, our General Public License is intended to guarantee your freedom to share and change free software--to make sure the software is free for all its users. The General Public License applies to the Free Software Foundation's software and to any other program whose authors commit to using it. You can use it for your programs, too. When we speak of free software, we are referring to freedom, not price. Specifically, the General Public License is designed to make sure that you have the freedom to give away or sell copies of free software, that you receive source code or can get it if you want it, that you can change the software or use pieces of it in new free programs; and that you know you can do these things. To protect your rights, we need to make restrictions that forbid anyone to deny you these rights or to ask you to surrender the rights. These restrictions translate to certain responsibilities for you if you distribute copies of the software, or if you modify it. For example, if you distribute copies of a such a program, whether gratis or for a fee, you must give the recipients all the rights that you have. You must make sure that they, too, receive or can get the source code. And you must tell them their rights. We protect your rights with two steps: (1) copyright the software, and (2) offer you this license which gives you legal permission to copy, distribute and/or modify the software. Also, for each author's protection and ours, we want to make certain that everyone understands that there is no warranty for this free software. If the software is modified by someone else and passed on, we want its recipients to know that what they have is not the original, so that any problems introduced by others will not reflect on the original authors' reputations. The precise terms and conditions for copying, distribution and modification follow. GNU GENERAL PUBLIC LICENSE TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION 0. This License Agreement applies to any program or other work which contains a notice placed by the copyright holder saying it may be distributed under the terms of this General Public License. The "Program", below, refers to any such program or work, and a "work based on the Program" means either the Program or any work containing the Program or a portion of it, either verbatim or with modifications. Each licensee is addressed as "you". 1. You may copy and distribute verbatim copies of the Program's source code as you receive it, in any medium, provided that you conspicuously and appropriately publish on each copy an appropriate copyright notice and disclaimer of warranty; keep intact all the notices that refer to this General Public License and to the absence of any warranty; and give any other recipients of the Program a copy of this General Public License along with the Program. You may charge a fee for the physical act of transferring a copy. 2. You may modify your copy or copies of the Program or any portion of it, and copy and distribute such modifications under the terms of Paragraph 1 above, provided that you also do the following: a) cause the modified files to carry prominent notices stating that you changed the files and the date of any change; and b) cause the whole of any work that you distribute or publish, that in whole or in part contains the Program or any part thereof, either with or without modifications, to be licensed at no charge to all third parties under the terms of this General Public License (except that you may choose to grant warranty protection to some or all third parties, at your option). c) If the modified program normally reads commands interactively when run, you must cause it, when started running for such interactive use in the simplest and most usual way, to print or display an announcement including an appropriate copyright notice and a notice that there is no warranty (or else, saying that you provide a warranty) and that users may redistribute the program under these conditions, and telling the user how to view a copy of this General Public License. d) You may charge a fee for the physical act of transferring a copy, and you may at your option offer warranty protection in exchange for a fee. Mere aggregation of another independent work with the Program (or its derivative) on a volume of a storage or distribution medium does not bring the other work under the scope of these terms. 3. You may copy and distribute the Program (or a portion or derivative of it, under Paragraph 2) in object code or executable form under the terms of Paragraphs 1 and 2 above provided that you also do one of the following: a) accompany it with the complete corresponding machine-readable source code, which must be distributed under the terms of Paragraphs 1 and 2 above; or, b) accompany it with a written offer, valid for at least three years, to give any third party free (except for a nominal charge for the cost of distribution) a complete machine-readable copy of the corresponding source code, to be distributed under the terms of Paragraphs 1 and 2 above; or, c) accompany it with the information you received as to where the corresponding source code may be obtained. (This alternative is allowed only for noncommercial distribution and only if you received the program in object code or executable form alone.) Source code for a work means the preferred form of the work for making modifications to it. For an executable file, complete source code means all the source code for all modules it contains; but, as a special exception, it need not include source code for modules which are standard libraries that accompany the operating system on which the executable file runs, or for standard header files or definitions files that accompany that operating system. 4. You may not copy, modify, sublicense, distribute or transfer the Program except as expressly provided under this General Public License. Any attempt otherwise to copy, modify, sublicense, distribute or transfer the Program is void, and will automatically terminate your rights to use the Program under this License. However, parties who have received copies, or rights to use copies, from you under this General Public License will not have their licenses terminated so long as such parties remain in full compliance. 5. By copying, distributing or modifying the Program (or any work based on the Program) you indicate your acceptance of this license to do so, and all its terms and conditions. 6. Each time you redistribute the Program (or any work based on the Program), the recipient automatically receives a license from the original licensor to copy, distribute or modify the Program subject to these terms and conditions. You may not impose any further restrictions on the recipients' exercise of the rights granted herein. 7. The Free Software Foundation may publish revised and/or new versions of the General Public License from time to time. Such new versions will be similar in spirit to the present version, but may differ in detail to address new problems or concerns. Each version is given a distinguishing version number. If the Program specifies a version number of the license which applies to it and "any later version", you have the option of following the terms and conditions either of that version or of any later version published by the Free Software Foundation. If the Program does not specify a version number of the license, you may choose any version ever published by the Free Software Foundation. 8. If you wish to incorporate parts of the Program into other free programs whose distribution conditions are different, write to the author to ask for permission. For software which is copyrighted by the Free Software Foundation, write to the Free Software Foundation; we sometimes make exceptions for this. Our decision will be guided by the two goals of preserving the free status of all derivatives of our free software and of promoting the sharing and reuse of software generally. NO WARRANTY 9. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. 10. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH DAMAGES. END OF TERMS AND CONDITIONS Appendix: How to Apply These Terms to Your New Programs If you develop a new program, and you want it to be of the greatest possible use to humanity, the best way to achieve this is to make it free software which everyone can redistribute and change under these terms. To do so, attach the following notices to the program. It is safest to attach them to the start of each source file to most effectively convey the exclusion of warranty; and each file should have at least the "copyright" line and a pointer to where the full notice is found. Copyright (C) 19yy This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 1, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA Also add information on how to contact you by electronic and paper mail. If the program is interactive, make it output a short notice like this when it starts in an interactive mode: Gnomovision version 69, Copyright (C) 19xx name of author Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'. This is free software, and you are welcome to redistribute it under certain conditions; type `show c' for details. The hypothetical commands `show w' and `show c' should show the appropriate parts of the General Public License. Of course, the commands you use may be called something other than `show w' and `show c'; they could even be mouse-clicks or menu items--whatever suits your program. You should also get your employer (if you work as a programmer) or your school, if any, to sign a "copyright disclaimer" for the program, if necessary. Here a sample; alter the names: Yoyodyne, Inc., hereby disclaims all copyright interest in the program `Gnomovision' (a program to direct compilers to make passes at assemblers) written by James Hacker. , 1 April 1989 Ty Coon, President of Vice That's all there is to it! --- The Artistic License 1.0 --- This software is Copyright (c) 2025 by Matthäus Kiem. This is free software, licensed under: The Artistic License 1.0 The Artistic License Preamble The intent of this document is to state the conditions under which a Package may be copied, such that the Copyright Holder maintains some semblance of artistic control over the development of the package, while giving the users of the package the right to use and distribute the Package in a more-or-less customary fashion, plus the right to make reasonable modifications. Definitions: - "Package" refers to the collection of files distributed by the Copyright Holder, and derivatives of that collection of files created through textual modification. - "Standard Version" refers to such a Package if it has not been modified, or has been modified in accordance with the wishes of the Copyright Holder. - "Copyright Holder" is whoever is named in the copyright or copyrights for the package. - "You" is you, if you're thinking about copying or distributing this Package. - "Reasonable copying fee" is whatever you can justify on the basis of media cost, duplication charges, time of people involved, and so on. (You will not be required to justify it to the Copyright Holder, but only to the computing community at large as a market that must bear the fee.) - "Freely Available" means that no fee is charged for the item itself, though there may be fees involved in handling the item. It also means that recipients of the item may redistribute it under the same conditions they received it. 1. You may make and give away verbatim copies of the source form of the Standard Version of this Package without restriction, provided that you duplicate all of the original copyright notices and associated disclaimers. 2. You may apply bug fixes, portability fixes and other modifications derived from the Public Domain or from the Copyright Holder. A Package modified in such a way shall still be considered the Standard Version. 3. You may otherwise modify your copy of this Package in any way, provided that you insert a prominent notice in each changed file stating how and when you changed that file, and provided that you do at least ONE of the following: a) place your modifications in the Public Domain or otherwise make them Freely Available, such as by posting said modifications to Usenet or an equivalent medium, or placing the modifications on a major archive site such as ftp.uu.net, or by allowing the Copyright Holder to include your modifications in the Standard Version of the Package. b) use the modified Package only within your corporation or organization. c) rename any non-standard executables so the names do not conflict with standard executables, which must also be provided, and provide a separate manual page for each non-standard executable that clearly documents how it differs from the Standard Version. d) make other distribution arrangements with the Copyright Holder. 4. You may distribute the programs of this Package in object code or executable form, provided that you do at least ONE of the following: a) distribute a Standard Version of the executables and library files, together with instructions (in the manual page or equivalent) on where to get the Standard Version. b) accompany the distribution with the machine-readable source of the Package with your modifications. c) accompany any non-standard executables with their corresponding Standard Version executables, giving the non-standard executables non-standard names, and clearly documenting the differences in manual pages (or equivalent), together with instructions on where to get the Standard Version. d) make other distribution arrangements with the Copyright Holder. 5. You may charge a reasonable copying fee for any distribution of this Package. You may charge any fee you choose for support of this Package. You may not charge a fee for this Package itself. However, you may distribute this Package in aggregate with other (possibly commercial) programs as part of a larger (possibly commercial) software distribution provided that you do not advertise this Package as a product of your own. 6. The scripts and library files supplied as input to or produced as output from the programs of this Package do not automatically fall under the copyright of this Package, but belong to whomever generated them, and may be sold commercially, and may be aggregated with this Package. 7. C or perl subroutines supplied by you and linked into this Package shall not be considered part of this Package. 8. The name of the Copyright Holder may not be used to endorse or promote products derived from this software without specific prior written permission. 9. THIS PACKAGE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE. The End