ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/selection
Revision: 1.61
Committed: Mon Jun 9 19:54:26 2014 UTC (9 years, 11 months ago) by sf-exg
Branch: MAIN
CVS Tags: rxvt-unicode-rel-9_26, rxvt-unicode-rel-9_25, rxvt-unicode-rel-9_22, rxvt-unicode-rel-9_21
Changes since 1.60: +9 -0 lines
Log Message:
Restore on_user_command hooks for backward compatibility.

File Contents

# User Rev Content
1 root 1.4 #! perl
2    
3 root 1.58 #:META:RESOURCE:%.pattern-0:string:first selection pattern
4 root 1.54
5 root 1.55 =head1 NAME
6    
7 root 1.56 selection - more intelligent selection (enabled by default)
8 root 1.55
9     =head1 DESCRIPTION
10    
11     This extension tries to be more intelligent when the user extends
12     selections (double-click and further clicks). Right now, it tries to
13     select words, urls and complete shell-quoted arguments, which is very
14     convenient, too, if your F<ls> supports C<--quoting-style=shell>.
15    
16     A double-click usually selects the word under the cursor, further clicks
17     will enlarge the selection.
18    
19     The selection works by trying to match a number of regexes and displaying
20     them in increasing order of length. You can add your own regexes by
21     specifying resources of the form:
22    
23     URxvt.selection.pattern-0: perl-regex
24     URxvt.selection.pattern-1: perl-regex
25     ...
26    
27     The index number (0, 1...) must not have any holes, and each regex must
28     contain at least one pair of capturing parentheses, which will be used for
29     the match. For example, the following adds a regex that matches everything
30     between two vertical bars:
31    
32     URxvt.selection.pattern-0: \\|([^|]+)\\|
33    
34     Another example: Programs I use often output "absolute path: " at the
35     beginning of a line when they process multiple files. The following
36     pattern matches the filename (note, there is a single space at the very
37     end):
38    
39     URxvt.selection.pattern-0: ^(/[^:]+):\
40    
41     You can look at the source of the selection extension to see more
42     interesting uses, such as parsing a line from beginning to end.
43    
44 sf-exg 1.60 This extension also offers the following actions:
45 root 1.55
46     =over 4
47    
48     =item rot13
49    
50 sf-exg 1.60 Rot-13 the selection when activated.
51 root 1.55
52 sf-exg 1.60 Example:
53    
54     URxvt.keysym.C-M-r: selection:rot13
55 root 1.55
56     =back
57    
58     =cut
59    
60 sf-exg 1.61 sub on_user_command {
61     my ($self, $cmd) = @_;
62    
63     $cmd eq "selection:rot13"
64     and $self->selection (map { y/A-Za-z/N-ZA-Mn-za-m/; $_ } $self->selection);
65    
66     ()
67     }
68    
69 sf-exg 1.59 sub on_action {
70     my ($self, $action) = @_;
71 elmex 1.2
72 sf-exg 1.59 $action eq "rot13"
73 root 1.7 and $self->selection (map { y/A-Za-z/N-ZA-Mn-za-m/; $_ } $self->selection);
74 elmex 1.3
75     ()
76 elmex 1.1 }
77 root 1.5
78 root 1.23 sub on_init {
79     my ($self) = @_;
80    
81 root 1.35 if (defined (my $res = $self->resource ("cutchars"))) {
82     $res = $self->locale_decode ($res);
83     push @{ $self->{patterns} }, qr{\G [\Q$res\E[:space:]]* ([^\Q$res\E[:space:]]+) }x;
84     }
85    
86 root 1.23 for (my $idx = 0; defined (my $res = $self->x_resource ("selection.pattern-$idx")); $idx++) {
87 root 1.31 $res = $self->locale_decode ($res);
88 root 1.23 push @{ $self->{patterns} }, qr/$res/;
89     }
90    
91 root 1.37 $self->{enabled} = 1;
92    
93     push @{ $self->{term}{option_popup_hook} }, sub {
94     ("new selection" => $self->{enabled}, sub { $self->{enabled} = shift })
95     };
96    
97 root 1.23 ()
98     }
99    
100 root 1.34 # "find interesting things"-patterns
101 root 1.15 my @mark_patterns = (
102 root 1.49 # qr{ ([[:word:]]+) }x,
103 root 1.42 qr{ ([^[:space:]]+) }x,
104    
105 root 1.24 # common types of "parentheses"
106 root 1.50 qr{ (?<![^[:space:]]) [`'] ([^`']+) [`'] (?![^[:space:]]) }x,
107 root 1.48 qr{ (?<![^[:space:]]) ‘ ([^‘’]+) ’ (?![^[:space:]]) }x,
108     qr{ (?<![^[:space:]]) “ ([^“”]+) ” (?![^[:space:]]) }x,
109 root 1.43
110 root 1.47 qr{ (?<![^[:space:]]) (' [^[:space:]] [^']* ') }x,
111 root 1.43 qr{ (' [^']* [^[:space:]] ') (?![^[:space:]]) }x,
112 root 1.52 qr{ (?<![^[:space:]]) (` [^[:space:]] [^']* ') }x,
113     qr{ (` [^']* [^[:space:]] ') (?![^[:space:]]) }x,
114 root 1.47 qr{ (?<![^[:space:]]) (" [^[:space:]] [^"]* ") }x,
115 root 1.42 qr{ (" [^"]* [^[:space:]] ") (?![^[:space:]]) }x,
116 root 1.43
117 root 1.48 qr{ \{ ([^\{\}]+) \} }x,
118     qr{ \( ([^\(\)]+) \) }x,
119     qr{ \[ ([^\[\]]+) \] }x,
120     qr{ \< ([^\<\>]+) \> }x,
121 root 1.14
122 root 1.20 # urls, just a heuristic
123     qr{(
124 root 1.40 (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+
125     [ab-zA-Z0-9\-\@;\/?:&=%\$_+*()~] # exclude some trailing characters (heuristic)
126 root 1.20 )}x,
127    
128 root 1.17 # shell-like argument quoting, basically always matches
129 root 1.34 qr{\G [\ \t|&;<>()]* (
130 root 1.9 (?:
131 root 1.11 [^\\"'\ \t|&;<>()]+
132 root 1.9 | \\.
133 root 1.13 | " (?: [^\\"]+ | \\. )* "
134 root 1.9 | ' [^']* '
135     )+
136 root 1.14 )}x,
137 root 1.8 );
138    
139 root 1.16 # "correct obvious? crap"-patterns
140 root 1.15 my @simplify_patterns = (
141     qr{^"([^\\"'\ \t|&;<>()*?]+)"$}, # "simple" => simple
142 root 1.16 qr{^(.*)[,\-]$}, # strip off trailing , and -
143 root 1.15 );
144 root 1.14
145 root 1.6 sub on_sel_extend {
146 root 1.21 my ($self, $time) = @_;
147 root 1.8
148 root 1.37 $self->{enabled}
149     or return;
150    
151 root 1.8 my ($row, $col) = $self->selection_mark;
152     my $line = $self->line ($row);
153     my $text = $line->t;
154 root 1.20 my $markofs = $line->offset_of ($row, $col);
155     my $curlen = $line->offset_of ($self->selection_end)
156     - $line->offset_of ($self->selection_beg);
157    
158     my @matches;
159 root 1.8
160 root 1.32 if ($markofs < $line->l) {
161     study $text; # _really_ helps, too :)
162    
163     for my $regex (@mark_patterns, @{ $self->{patterns} }) {
164     while ($text =~ /$regex/g) {
165     if ($-[1] <= $markofs and $markofs <= $+[1]) {
166     my $ofs = $-[1];
167     my $match = $1;
168    
169     for my $regex (@simplify_patterns) {
170     if ($match =~ $regex) {
171     $match = $1;
172     $ofs += $-[1];
173     }
174 root 1.15 }
175 root 1.32
176     push @matches, [$ofs, length $match];
177 root 1.15 }
178 root 1.8 }
179     }
180     }
181    
182 root 1.21 # whole line
183     push @matches, [0, ($line->end - $line->beg + 1) * $self->ncol];
184    
185 root 1.20 for (sort { $a->[1] <=> $b->[1] or $b->[0] <=> $a->[0] } @matches) {
186     my ($ofs, $len) = @$_;
187    
188     next if $len <= $curlen;
189    
190     $self->selection_beg ($line->coord_of ($ofs));
191     $self->selection_end ($line->coord_of ($ofs + $len));
192     return 1;
193     }
194    
195 root 1.21 ()
196 root 1.5 }