File: History.pm

package info (click to toggle)
libtickit-widget-entry-plugin-history-perl 0.01-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid
  • size: 124 kB
  • sloc: perl: 209; makefile: 2
file content (140 lines) | stat: -rw-r--r-- 3,008 bytes parent folder | download
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
#  You may distribute under the terms of either the GNU General Public License
#  or the Artistic License (the same terms as Perl itself)
#
#  (C) Paul Evans, 2020 -- leonerd@leonerd.org.uk

package Tickit::Widget::Entry::Plugin::History 0.01;

use v5.14;
use warnings;

=head1 NAME

C<Tickit::Widget::Entry::Plugin::History> - add readline-like history to a L<Tickit::Widget::Entry>

=head1 SYNOPSIS

   use Tickit::Widget::Entry;
   use Tickit::Widget::Entry::Plugin::History;

   my $entry = Tickit::Widget::Entry->new( ... );
   Tickit::Widget::Entry::Plugin::History->apply( $entry );

   ...

=head1 DESCRIPTION

This package applies code to a L<Tickit::Widget::Entry> instance to implement
a history mechanism, which stores previously-entered values allowing them to
be recalled and reused later.

=cut

=head1 METHODS

=cut

=head2 apply

   Tickit::Widget::Entry::Plugin::History->apply( $entry, %opts )

Applies the plugin code to the given L<Tickit::Widget::Entry> instance.

The following named options are recognised:

=over 4

=item storage => ARRAY

An optional reference to an array to store the history in. If absent, a new
anonymous array will be created.

=item ignore_duplicates => BOOL

If true, an entry will not be pushed into history if it is equal to the most
recent item already there.

=back

=cut

sub apply
{
   my $class = shift;
   my ( $entry, %opts ) = @_;

   my $storage = $opts{storage} // [];
   my $ignore_duplicates = !!$opts{ignore_duplicates};

   my $pending;
   my $history_index;

   $entry->bind_keys(
      Up => sub {
         my ( $entry ) = @_;

         if( !defined $history_index ) {
            $pending = $entry->text;
            return 1 unless @$storage;

            $history_index = $#$storage;
         }
         elsif( $history_index == 0 ) {
            # don't move
            return 1;
         }
         else {
            $history_index--;
         }

         my $line = $storage->[$history_index];
         $entry->set_text( $line );
         $entry->set_position( length $line );

         return 1;
      },

      Down => sub {
         my ( $entry ) = @_;

         return 1 unless defined $history_index;
         if( $history_index < $#$storage ) {
            $history_index++;
         }
         else {
            $entry->set_text( $pending );
            undef $history_index;
            return 1;
         }

         my $line = $storage->[$history_index];
         $entry->set_text( $line );
         $entry->set_position( length $line );

         return 1;
      },
   );

   my $orig_on_enter = $entry->on_enter;
   $entry->set_on_enter( sub {
      my $entry = shift;
      my ( $line ) = @_;

      $entry->$orig_on_enter( $line ) if $orig_on_enter;

      $entry->set_text( "" );

      push @$storage, $line unless $ignore_duplicates and @$storage and $line eq $storage->[-1];
      # TODO: manage history size

      undef $history_index;
   });
}

=head1 AUTHOR

Paul Evans <leonerd@leonerd.org.uk>

=cut

0x55AA;