ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/selection
Revision: 1.57
Committed: Sat Apr 26 20:51:12 2014 UTC (10 years, 1 month ago) by root
Branch: MAIN
Changes since 1.56: +4 -0 lines
Log Message:
for discussion

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.57 sub on_keyboard_dispatch {
68     &on_user_command;
69     }
70    
71 root 1.23 sub on_init {
72     my ($self) = @_;
73    
74 root 1.35 if (defined (my $res = $self->resource ("cutchars"))) {
75     $res = $self->locale_decode ($res);
76     push @{ $self->{patterns} }, qr{\G [\Q$res\E[:space:]]* ([^\Q$res\E[:space:]]+) }x;
77     }
78    
79 root 1.23 for (my $idx = 0; defined (my $res = $self->x_resource ("selection.pattern-$idx")); $idx++) {
80 root 1.31 $res = $self->locale_decode ($res);
81 root 1.23 push @{ $self->{patterns} }, qr/$res/;
82     }
83    
84 root 1.37 $self->{enabled} = 1;
85    
86     push @{ $self->{term}{option_popup_hook} }, sub {
87     ("new selection" => $self->{enabled}, sub { $self->{enabled} = shift })
88     };
89    
90 root 1.23 ()
91     }
92    
93 root 1.34 # "find interesting things"-patterns
94 root 1.15 my @mark_patterns = (
95 root 1.49 # qr{ ([[:word:]]+) }x,
96 root 1.42 qr{ ([^[:space:]]+) }x,
97    
98 root 1.24 # common types of "parentheses"
99 root 1.50 qr{ (?<![^[:space:]]) [`'] ([^`']+) [`'] (?![^[:space:]]) }x,
100 root 1.48 qr{ (?<![^[:space:]]) ‘ ([^‘’]+) ’ (?![^[:space:]]) }x,
101     qr{ (?<![^[:space:]]) “ ([^“”]+) ” (?![^[:space:]]) }x,
102 root 1.43
103 root 1.47 qr{ (?<![^[:space:]]) (' [^[:space:]] [^']* ') }x,
104 root 1.43 qr{ (' [^']* [^[:space:]] ') (?![^[:space:]]) }x,
105 root 1.52 qr{ (?<![^[:space:]]) (` [^[:space:]] [^']* ') }x,
106     qr{ (` [^']* [^[:space:]] ') (?![^[:space:]]) }x,
107 root 1.47 qr{ (?<![^[:space:]]) (" [^[:space:]] [^"]* ") }x,
108 root 1.42 qr{ (" [^"]* [^[:space:]] ") (?![^[:space:]]) }x,
109 root 1.43
110 root 1.48 qr{ \{ ([^\{\}]+) \} }x,
111     qr{ \( ([^\(\)]+) \) }x,
112     qr{ \[ ([^\[\]]+) \] }x,
113     qr{ \< ([^\<\>]+) \> }x,
114 root 1.14
115 root 1.20 # urls, just a heuristic
116     qr{(
117 root 1.40 (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+
118     [ab-zA-Z0-9\-\@;\/?:&=%\$_+*()~] # exclude some trailing characters (heuristic)
119 root 1.20 )}x,
120    
121 root 1.17 # shell-like argument quoting, basically always matches
122 root 1.34 qr{\G [\ \t|&;<>()]* (
123 root 1.9 (?:
124 root 1.11 [^\\"'\ \t|&;<>()]+
125 root 1.9 | \\.
126 root 1.13 | " (?: [^\\"]+ | \\. )* "
127 root 1.9 | ' [^']* '
128     )+
129 root 1.14 )}x,
130 root 1.8 );
131    
132 root 1.16 # "correct obvious? crap"-patterns
133 root 1.15 my @simplify_patterns = (
134     qr{^"([^\\"'\ \t|&;<>()*?]+)"$}, # "simple" => simple
135 root 1.16 qr{^(.*)[,\-]$}, # strip off trailing , and -
136 root 1.15 );
137 root 1.14
138 root 1.6 sub on_sel_extend {
139 root 1.21 my ($self, $time) = @_;
140 root 1.8
141 root 1.37 $self->{enabled}
142     or return;
143    
144 root 1.8 my ($row, $col) = $self->selection_mark;
145     my $line = $self->line ($row);
146     my $text = $line->t;
147 root 1.20 my $markofs = $line->offset_of ($row, $col);
148     my $curlen = $line->offset_of ($self->selection_end)
149     - $line->offset_of ($self->selection_beg);
150    
151     my @matches;
152 root 1.8
153 root 1.32 if ($markofs < $line->l) {
154     study $text; # _really_ helps, too :)
155    
156     for my $regex (@mark_patterns, @{ $self->{patterns} }) {
157     while ($text =~ /$regex/g) {
158     if ($-[1] <= $markofs and $markofs <= $+[1]) {
159     my $ofs = $-[1];
160     my $match = $1;
161    
162     for my $regex (@simplify_patterns) {
163     if ($match =~ $regex) {
164     $match = $1;
165     $ofs += $-[1];
166     }
167 root 1.15 }
168 root 1.32
169     push @matches, [$ofs, length $match];
170 root 1.15 }
171 root 1.8 }
172     }
173     }
174    
175 root 1.21 # whole line
176     push @matches, [0, ($line->end - $line->beg + 1) * $self->ncol];
177    
178 root 1.20 for (sort { $a->[1] <=> $b->[1] or $b->[0] <=> $a->[0] } @matches) {
179     my ($ofs, $len) = @$_;
180    
181     next if $len <= $curlen;
182    
183     $self->selection_beg ($line->coord_of ($ofs));
184     $self->selection_end ($line->coord_of ($ofs + $len));
185     return 1;
186     }
187    
188 root 1.21 ()
189 root 1.5 }