ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/selection
Revision: 1.56
Committed: Tue Sep 4 22:41:12 2012 UTC (11 years, 8 months ago) by root
Branch: MAIN
CVS Tags: rxvt-unicode-rel-9_20, rxvt-unicode-rel-9_19, rxvt-unicode-rel-9_18, rxvt-unicode-rel-9_17, rxvt-unicode-rel-9_16
Changes since 1.55: +1 -1 lines
Log Message:
*** empty log message ***

File Contents

# User Rev Content
1 root 1.4 #! perl
2    
3 root 1.54 #:META:X_RESOURCE:%.pattern-0:string:first selection pattern
4    
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     This extension also offers following bindable keyboard commands:
45    
46     =over 4
47    
48     =item rot13
49    
50     Rot-13 the selection when activated. Used via keyboard trigger:
51    
52     URxvt.keysym.C-M-r: perl:selection:rot13
53    
54     =back
55    
56     =cut
57    
58 root 1.36 sub on_user_command {
59 root 1.7 my ($self, $cmd) = @_;
60 elmex 1.2
61     $cmd eq "selection:rot13"
62 root 1.7 and $self->selection (map { y/A-Za-z/N-ZA-Mn-za-m/; $_ } $self->selection);
63 elmex 1.3
64     ()
65 elmex 1.1 }
66 root 1.5
67 root 1.23 sub on_init {
68     my ($self) = @_;
69    
70 root 1.35 if (defined (my $res = $self->resource ("cutchars"))) {
71     $res = $self->locale_decode ($res);
72     push @{ $self->{patterns} }, qr{\G [\Q$res\E[:space:]]* ([^\Q$res\E[:space:]]+) }x;
73     }
74    
75 root 1.23 for (my $idx = 0; defined (my $res = $self->x_resource ("selection.pattern-$idx")); $idx++) {
76 root 1.31 $res = $self->locale_decode ($res);
77 root 1.23 push @{ $self->{patterns} }, qr/$res/;
78     }
79    
80 root 1.37 $self->{enabled} = 1;
81    
82     push @{ $self->{term}{option_popup_hook} }, sub {
83     ("new selection" => $self->{enabled}, sub { $self->{enabled} = shift })
84     };
85    
86 root 1.23 ()
87     }
88    
89 root 1.34 # "find interesting things"-patterns
90 root 1.15 my @mark_patterns = (
91 root 1.49 # qr{ ([[:word:]]+) }x,
92 root 1.42 qr{ ([^[:space:]]+) }x,
93    
94 root 1.24 # common types of "parentheses"
95 root 1.50 qr{ (?<![^[:space:]]) [`'] ([^`']+) [`'] (?![^[:space:]]) }x,
96 root 1.48 qr{ (?<![^[:space:]]) ‘ ([^‘’]+) ’ (?![^[:space:]]) }x,
97     qr{ (?<![^[:space:]]) “ ([^“”]+) ” (?![^[:space:]]) }x,
98 root 1.43
99 root 1.47 qr{ (?<![^[:space:]]) (' [^[:space:]] [^']* ') }x,
100 root 1.43 qr{ (' [^']* [^[:space:]] ') (?![^[:space:]]) }x,
101 root 1.52 qr{ (?<![^[:space:]]) (` [^[:space:]] [^']* ') }x,
102     qr{ (` [^']* [^[:space:]] ') (?![^[:space:]]) }x,
103 root 1.47 qr{ (?<![^[:space:]]) (" [^[:space:]] [^"]* ") }x,
104 root 1.42 qr{ (" [^"]* [^[:space:]] ") (?![^[:space:]]) }x,
105 root 1.43
106 root 1.48 qr{ \{ ([^\{\}]+) \} }x,
107     qr{ \( ([^\(\)]+) \) }x,
108     qr{ \[ ([^\[\]]+) \] }x,
109     qr{ \< ([^\<\>]+) \> }x,
110 root 1.14
111 root 1.20 # urls, just a heuristic
112     qr{(
113 root 1.40 (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+
114     [ab-zA-Z0-9\-\@;\/?:&=%\$_+*()~] # exclude some trailing characters (heuristic)
115 root 1.20 )}x,
116    
117 root 1.17 # shell-like argument quoting, basically always matches
118 root 1.34 qr{\G [\ \t|&;<>()]* (
119 root 1.9 (?:
120 root 1.11 [^\\"'\ \t|&;<>()]+
121 root 1.9 | \\.
122 root 1.13 | " (?: [^\\"]+ | \\. )* "
123 root 1.9 | ' [^']* '
124     )+
125 root 1.14 )}x,
126 root 1.8 );
127    
128 root 1.16 # "correct obvious? crap"-patterns
129 root 1.15 my @simplify_patterns = (
130     qr{^"([^\\"'\ \t|&;<>()*?]+)"$}, # "simple" => simple
131 root 1.16 qr{^(.*)[,\-]$}, # strip off trailing , and -
132 root 1.15 );
133 root 1.14
134 root 1.6 sub on_sel_extend {
135 root 1.21 my ($self, $time) = @_;
136 root 1.8
137 root 1.37 $self->{enabled}
138     or return;
139    
140 root 1.8 my ($row, $col) = $self->selection_mark;
141     my $line = $self->line ($row);
142     my $text = $line->t;
143 root 1.20 my $markofs = $line->offset_of ($row, $col);
144     my $curlen = $line->offset_of ($self->selection_end)
145     - $line->offset_of ($self->selection_beg);
146    
147     my @matches;
148 root 1.8
149 root 1.32 if ($markofs < $line->l) {
150     study $text; # _really_ helps, too :)
151    
152     for my $regex (@mark_patterns, @{ $self->{patterns} }) {
153     while ($text =~ /$regex/g) {
154     if ($-[1] <= $markofs and $markofs <= $+[1]) {
155     my $ofs = $-[1];
156     my $match = $1;
157    
158     for my $regex (@simplify_patterns) {
159     if ($match =~ $regex) {
160     $match = $1;
161     $ofs += $-[1];
162     }
163 root 1.15 }
164 root 1.32
165     push @matches, [$ofs, length $match];
166 root 1.15 }
167 root 1.8 }
168     }
169     }
170    
171 root 1.21 # whole line
172     push @matches, [0, ($line->end - $line->beg + 1) * $self->ncol];
173    
174 root 1.20 for (sort { $a->[1] <=> $b->[1] or $b->[0] <=> $a->[0] } @matches) {
175     my ($ofs, $len) = @$_;
176    
177     next if $len <= $curlen;
178    
179     $self->selection_beg ($line->coord_of ($ofs));
180     $self->selection_end ($line->coord_of ($ofs + $len));
181     return 1;
182     }
183    
184 root 1.21 ()
185 root 1.5 }