ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/matcher
Revision: 1.2
Committed: Tue Jan 9 16:18:56 2007 UTC (17 years, 4 months ago) by tpope
Branch: MAIN
CVS Tags: rel-8_2
Changes since 1.1: +50 -5 lines
Log Message:
matcher changes

File Contents

# User Rev Content
1 root 1.1 #! perl
2    
3     # Author: Tim Pope <rxvt-unicodeNOSPAM@tpope.info>
4    
5     my $url =
6     qr{
7 tpope 1.2 (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)
8     [a-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27,~#]*
9     (
10     \([a-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27,~#]*\)| # Allow a pair of matched parentheses
11     [a-zA-Z0-9\-\@;\/?:&=%\$_+*~] # exclude some trailing characters (heuristic)
12     )+
13 root 1.1 }x;
14    
15 tpope 1.2 sub on_user_command {
16     my ($self, $cmd) = @_;
17     if($cmd =~ s/^matcher\b//) {
18     $self->most_recent;
19     }
20     my $row = $self->nrow;
21     my @exec;
22     while($row-- > $self->top_row) {
23     #my $line = $self->line ($row);
24     #my $text = $line->t;
25     @exec = $self->command_for($row);
26     last if(@exec);
27     }
28     if(@exec) {
29     return $self->exec_async (@exec);
30     }
31     ()
32     }
33    
34     sub most_recent {
35     my ($self) = shift;
36     ()
37     }
38    
39 root 1.1 sub my_resource {
40     my $self = shift;
41     $self->x_resource("$self->{name}.$_[0]");
42     }
43    
44 tpope 1.2 # turn a rendition spec in the resource into a sub that implements it on $_
45     sub parse_rend {
46     my ($self, $str) = @_;
47     my ($mask, $fg, $bg, $failed) = $str ? urxvt::rend2mask($str)
48     : (urxvt::RS_Uline, undef, undef, []);
49     warn "Failed to parse rendition string: " . join(',', @$failed) if @$failed;
50     my @rend;
51     push @rend, sub { $_ |= $mask } if $mask;
52     push @rend, sub { $_ = urxvt::SET_FGCOLOR($_, $fg) } if defined $fg;
53     push @rend, sub { $_ = urxvt::SET_BGCOLOR($_, $bg) } if defined $bg;
54     sub {
55     for my $s ( @rend ) { &$s };
56     }
57     }
58    
59 root 1.1 sub on_start {
60     my ($self) = @_;
61    
62     ($self->{name} = __PACKAGE__) =~ s/.*:://;
63     $self->{name} =~ tr/_/-/;
64     $self->{launcher} = $self->my_resource("launcher") ||
65     $self->x_resource("urlLauncher") ||
66     "sensible-browser";
67    
68     $self->{button} = 2;
69     $self->{state} = 0;
70     if($self->{argv}[0] || $self->my_resource("button")) {
71     my @mods = split('', $self->{argv}[0] || $self->my_resource("button"));
72     for my $mod (@mods) {
73     if($mod =~ /^\d+$/) {
74     $self->{button} = $mod;
75     } elsif($mod eq "C") {
76     $self->{state} |= urxvt::ControlMask;
77     } elsif($mod eq "S") {
78     $self->{state} |= urxvt::ShiftMask;
79     } elsif($mod eq "M") {
80     $self->{state} |= $self->ModMetaMask;
81     } elsif($mod ne "-" && $mod ne " ") {
82     warn("$mod is invalid in $self->{name}<$self->{argv}[0]>\n");
83     }
84     }
85     }
86    
87     my @defaults = ($url);
88     my @matchers;
89     for (my $idx = 0; defined (my $res = $self->my_resource("pattern.$idx") || $defaults[$idx]); $idx++) {
90     $res = $self->locale_decode ($res);
91     utf8::encode $res;
92     my $launcher = $self->my_resource("launcher.$idx");
93     $launcher =~ s/\$&|\$\{&\}/\${0}/g if ($launcher);
94 tpope 1.2 my $rend = $self->parse_rend($self->my_resource("rend.$idx"));
95     unshift @matchers, [qr($res)x,$launcher,$rend];
96 root 1.1 }
97     $self->{matchers} = \@matchers;
98    
99     ()
100     }
101    
102     sub on_line_update {
103     my ($self, $row) = @_;
104    
105     # fetch the line that has changed
106     my $line = $self->line ($row);
107     my $text = $line->t;
108     my $i = 0;
109    
110     # find all urls (if any)
111     for my $matcher (@{$self->{matchers}}) {
112     while ($text =~ /$matcher->[0]/g) {
113 tpope 1.2 #print "$&\n";
114 root 1.1 my $rend = $line->r;
115    
116     # mark all characters as underlined. we _must_ not toggle underline,
117     # as we might get called on an already-marked url.
118 tpope 1.2 &{$matcher->[2]}
119 root 1.1 for @{$rend}[ $-[0] .. $+[0] - 1];
120    
121     $line->r ($rend);
122     }
123     }
124    
125     ()
126     }
127    
128     sub valid_button {
129     my ($self, $event) = @_;
130     my $mask = $self->ModLevel3Mask | $self->ModMetaMask
131     | urxvt::ShiftMask | urxvt::ControlMask;
132     return ($event->{button} == $self->{button} &&
133     ($event->{state} & $mask) == $self->{state});
134     }
135    
136     sub command_for {
137     my ($self, $row, $col) = @_;
138     my $line = $self->line ($row);
139     my $text = $line->t;
140    
141     for my $matcher (@{$self->{matchers}}) {
142     my $launcher = $matcher->[1] || $self->{launcher};
143     while (($text =~ /$matcher->[0]/g)) {
144     my $match = $&;
145     my @begin = @-;
146     my @end = @+;
147 tpope 1.2 if (!defined($col) || ($-[0] <= $col && $+[0] >= $col)) {
148 root 1.1 if ($launcher !~ /\$/) {
149     return ($launcher,$match);
150     } else {
151     # It'd be nice to just access a list like ($&,$1,$2...),
152     # but alas, m//g behaves differently in list context.
153     my @exec = map { s/\$(\d+)|\$\{(\d+)\}/
154     substr($text,$begin[$1||$2],$end[$1||$2]-$begin[$1||$2])
155     /egx; $_ } split(/\s+/, $launcher);
156     return @exec;
157     }
158     }
159     }
160     }
161    
162     ()
163     }
164    
165     sub on_button_press {
166     my ($self, $event) = @_;
167     if($self->valid_button($event)) {
168     $self->{row} = $event->{row};
169     $self->{col} = $event->{col};
170     } else {
171     delete $self->{row};
172     delete $self->{col};
173     }
174    
175     ()
176     }
177    
178     sub on_button_release {
179     my ($self, $event) = @_;
180    
181     my $row = delete $self->{row};
182     my $col = delete $self->{col};
183    
184     if(defined($row) && $row == $event->{row} && abs($col-$event->{col}) < 2) {
185     if($self->valid_button($event)) {
186    
187     my @exec = $self->command_for($row,$col);
188     if(@exec) {
189     return $self->exec_async (@exec);
190     }
191    
192     }
193     }
194    
195     ()
196     }
197    
198     # vim:set sw=3 sts=3 et: