ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/searchable-scrollback
Revision: 1.29
Committed: Sun Jun 10 17:31:53 2012 UTC (11 years, 11 months ago) by root
Branch: MAIN
Changes since 1.28: +27 -0 lines
Log Message:
move perl docs to extensions

File Contents

# User Rev Content
1 root 1.1 #! perl
2    
3     # this extension implements scrollback buffer search
4    
5 root 1.27 #:META:X_RESOURCE:%:string:activation hotkey keysym
6    
7 root 1.29 =head1 NAME
8    
9     searchable-scrollback<hotkey> - incremental scrollback search (enabled by default)
10    
11     =head1 DESCRIPTION
12    
13     Adds regex search functionality to the scrollback buffer, triggered
14     by a hotkey (default: C<M-s>). While in search mode, normal terminal
15     input/output is suspended and a regex is displayed at the bottom of the
16     screen.
17    
18     Inputting characters appends them to the regex and continues incremental
19     search. C<BackSpace> removes a character from the regex, C<Up> and C<Down>
20     search upwards/downwards in the scrollback buffer, C<End> jumps to the
21     bottom. C<Escape> leaves search mode and returns to the point where search
22     was started, while C<Enter> or C<Return> stay at the current position and
23     additionally stores the first match in the current line into the primary
24     selection if the C<Shift> modifier is active.
25    
26     The regex defaults to "(?i)", resulting in a case-insensitive search. To
27     get a case-sensitive search you can delete this prefix using C<BackSpace>
28     or simply use an uppercase character which removes the "(?i)" prefix.
29    
30     See L<perlre> for more info about perl regular expression syntax.
31    
32     =cut
33    
34 root 1.1 sub on_init {
35     my ($self) = @_;
36    
37 root 1.12 my $hotkey = $self->{argv}[0]
38 root 1.28 || $self->x_resource ("%")
39 root 1.12 || "M-s";
40 root 1.1
41 root 1.4 $self->parse_keysym ($hotkey, "perl:searchable-scrollback:start")
42     or warn "unable to register '$hotkey' as scrollback search start hotkey\n";
43 root 1.1
44     ()
45     }
46    
47 root 1.21 sub on_user_command {
48 root 1.1 my ($self, $cmd) = @_;
49    
50 root 1.8 $cmd eq "searchable-scrollback:start"
51     and $self->enter;
52 root 1.1
53     ()
54     }
55    
56     sub msg {
57     my ($self, $msg) = @_;
58    
59     $self->{overlay} = $self->overlay (0, -1, $self->ncol, 1, urxvt::OVERLAY_RSTYLE, 0);
60     $self->{overlay}->set (0, 0, $self->special_encode ($msg));
61     }
62    
63     sub enter {
64     my ($self) = @_;
65    
66     return if $self->{overlay};
67    
68 root 1.8 $self->{view_start} = $self->view_start;
69 root 1.24 $self->{pty_ev_events} = $self->pty_ev_events (urxvt::EV_NONE);
70 root 1.13 $self->{row} = $self->nrow - 1;
71 root 1.22 $self->{search} = "(?i)";
72 root 1.1
73     $self->enable (
74 root 1.2 key_press => \&key_press,
75 root 1.7 tt_write => \&tt_write,
76 root 1.2 refresh_begin => \&refresh,
77     refresh_end => \&refresh,
78 root 1.1 );
79    
80 root 1.8 $self->{manpage_overlay} = $self->overlay (0, -2, $self->ncol, 1, urxvt::OVERLAY_RSTYLE, 0);
81 root 1.11 $self->{manpage_overlay}->set (0, 0, "scrollback search, see the ${urxvt::RXVTNAME}perl manpage for details");
82 root 1.8
83 root 1.1 $self->idle;
84     }
85    
86     sub leave {
87     my ($self) = @_;
88    
89 root 1.7 $self->disable ("key_press", "tt_write", "refresh_begin", "refresh_end");
90 root 1.8 $self->pty_ev_events ($self->{pty_ev_events});
91 root 1.1
92 root 1.8 delete $self->{manpage_overlay};
93     delete $self->{overlay};
94     delete $self->{history};
95 root 1.13 delete $self->{search};
96 root 1.1 }
97    
98     sub idle {
99     my ($self) = @_;
100    
101 root 1.13 $self->msg ("(escape cancels) /$self->{search}█");
102 root 1.1 }
103    
104     sub search {
105 root 1.13 my ($self, $dir) = @_;
106 root 1.1
107     delete $self->{found};
108 root 1.13 my $row = $self->{row};
109 root 1.1
110 root 1.7 my $search = $self->special_encode ($self->{search});
111    
112 root 1.1 no re 'eval'; # just to be sure
113 root 1.16 if (my $re = eval { qr/$search/ }) {
114 sf-exg 1.25 while ($self->nrow > $row && $row >= $self->top_row) {
115 root 1.16 my $line = $self->line ($row)
116     or last;
117    
118     my $text = $line->t;
119     if ($text =~ /$re/g) {
120     do {
121     push @{ $self->{found} }, [$line->coord_of ($-[0]), $line->coord_of ($+[0])];
122     } while $text =~ /$re/g;
123    
124     $self->{row} = $row;
125 root 1.20 $self->view_start (List::Util::min 0, $row - ($self->nrow >> 1));
126 root 1.16 $self->want_refresh;
127     last;
128     }
129 root 1.1
130 root 1.16 $row = $dir < 0 ? $line->beg - 1 : $line->end + 1;
131 root 1.1 }
132     }
133    
134     $self->scr_bell unless $self->{found};
135     }
136    
137 root 1.2 sub refresh {
138     my ($self) = @_;
139    
140 root 1.18 return unless $self->{found};
141    
142 root 1.15 my $xor = urxvt::RS_RVid | urxvt::RS_Blink;
143 root 1.13 for (@{ $self->{found} }) {
144     $self->scr_xor_span (@$_, $xor);
145     $xor = urxvt::RS_RVid;
146     }
147 root 1.2
148     ()
149     }
150    
151     sub key_press {
152 root 1.1 my ($self, $event, $keysym, $string) = @_;
153    
154 root 1.13 delete $self->{manpage_overlay};
155    
156 root 1.14 if ($keysym == 0xff0d || $keysym == 0xff8d) { # enter
157 ayin 1.23 if ($self->{found} && $event->{state} & urxvt::ShiftMask) {
158 root 1.13 my ($br, $bc, $er, $ec) = @{ $self->{found}[0] };
159     $self->selection_beg ($br, $bc);
160     $self->selection_end ($er, $ec);
161     $self->selection_make ($event->{time});
162     }
163     $self->leave;
164 root 1.14 } elsif ($keysym == 0xff1b) { # escape
165 root 1.13 $self->view_start ($self->{view_start});
166     $self->leave;
167 root 1.14 } elsif ($keysym == 0xff57) { # end
168 root 1.13 $self->{row} = $self->nrow - 1;
169     $self->view_start (0);
170 root 1.14 } elsif ($keysym == 0xff52) { # up
171 root 1.20 $self->{row}-- if $self->{row} > $self->top_row;
172 root 1.13 $self->search (-1);
173 root 1.14 } elsif ($keysym == 0xff54) { # down
174 root 1.13 $self->{row}++ if $self->{row} < $self->nrow;
175     $self->search (+1);
176 root 1.14 } elsif ($keysym == 0xff08) { # backspace
177 root 1.13 substr $self->{search}, -1, 1, "";
178     $self->search;
179     $self->idle;
180 root 1.19 } elsif ($string !~ /[\x00-\x1f\x80-\xaf]/) {
181 root 1.13 return; # pass to tt_write
182 root 1.1 }
183    
184     1
185     }
186    
187 root 1.7 sub tt_write {
188     my ($self, $data) = @_;
189    
190     $self->{search} .= $self->locale_decode ($data);
191 root 1.22
192     $self->{search} =~ s/^\(\?i\)//
193     if $self->{search} =~ /^\(.*[[:upper:]]/;
194 sf-exg 1.26
195 root 1.13 $self->search (-1);
196     $self->idle;
197 root 1.7
198     1
199     }
200    
201 root 1.1