ViewVC Help
View File | Revision Log | Show Annotations | Download File
/cvs/rxvt-unicode/src/perl/selection
Revision: 1.58
Committed: Sat May 17 13:38:23 2014 UTC (10 years ago) by root
Branch: MAIN
Changes since 1.57: +1 -1 lines
Log Message:
X_RESOURCE => RESOURCE

File Contents

# Content
1 #! perl
2
3 #:META:RESOURCE:%.pattern-0:string:first selection pattern
4
5 =head1 NAME
6
7 selection - more intelligent selection (enabled by default)
8
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 sub on_user_command {
59 my ($self, $cmd) = @_;
60
61 $cmd eq "selection:rot13"
62 and $self->selection (map { y/A-Za-z/N-ZA-Mn-za-m/; $_ } $self->selection);
63
64 ()
65 }
66
67 sub on_keyboard_dispatch {
68 &on_user_command;
69 }
70
71 sub on_init {
72 my ($self) = @_;
73
74 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 for (my $idx = 0; defined (my $res = $self->x_resource ("selection.pattern-$idx")); $idx++) {
80 $res = $self->locale_decode ($res);
81 push @{ $self->{patterns} }, qr/$res/;
82 }
83
84 $self->{enabled} = 1;
85
86 push @{ $self->{term}{option_popup_hook} }, sub {
87 ("new selection" => $self->{enabled}, sub { $self->{enabled} = shift })
88 };
89
90 ()
91 }
92
93 # "find interesting things"-patterns
94 my @mark_patterns = (
95 # qr{ ([[:word:]]+) }x,
96 qr{ ([^[:space:]]+) }x,
97
98 # common types of "parentheses"
99 qr{ (?<![^[:space:]]) [`'] ([^`']+) [`'] (?![^[:space:]]) }x,
100 qr{ (?<![^[:space:]]) ‘ ([^‘’]+) ’ (?![^[:space:]]) }x,
101 qr{ (?<![^[:space:]]) “ ([^“”]+) ” (?![^[:space:]]) }x,
102
103 qr{ (?<![^[:space:]]) (' [^[:space:]] [^']* ') }x,
104 qr{ (' [^']* [^[:space:]] ') (?![^[:space:]]) }x,
105 qr{ (?<![^[:space:]]) (` [^[:space:]] [^']* ') }x,
106 qr{ (` [^']* [^[:space:]] ') (?![^[:space:]]) }x,
107 qr{ (?<![^[:space:]]) (" [^[:space:]] [^"]* ") }x,
108 qr{ (" [^"]* [^[:space:]] ") (?![^[:space:]]) }x,
109
110 qr{ \{ ([^\{\}]+) \} }x,
111 qr{ \( ([^\(\)]+) \) }x,
112 qr{ \[ ([^\[\]]+) \] }x,
113 qr{ \< ([^\<\>]+) \> }x,
114
115 # urls, just a heuristic
116 qr{(
117 (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+
118 [ab-zA-Z0-9\-\@;\/?:&=%\$_+*()~] # exclude some trailing characters (heuristic)
119 )}x,
120
121 # shell-like argument quoting, basically always matches
122 qr{\G [\ \t|&;<>()]* (
123 (?:
124 [^\\"'\ \t|&;<>()]+
125 | \\.
126 | " (?: [^\\"]+ | \\. )* "
127 | ' [^']* '
128 )+
129 )}x,
130 );
131
132 # "correct obvious? crap"-patterns
133 my @simplify_patterns = (
134 qr{^"([^\\"'\ \t|&;<>()*?]+)"$}, # "simple" => simple
135 qr{^(.*)[,\-]$}, # strip off trailing , and -
136 );
137
138 sub on_sel_extend {
139 my ($self, $time) = @_;
140
141 $self->{enabled}
142 or return;
143
144 my ($row, $col) = $self->selection_mark;
145 my $line = $self->line ($row);
146 my $text = $line->t;
147 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
153 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 }
168
169 push @matches, [$ofs, length $match];
170 }
171 }
172 }
173 }
174
175 # whole line
176 push @matches, [0, ($line->end - $line->beg + 1) * $self->ncol];
177
178 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 ()
189 }