aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorSterling Camden <sterling@camdensoftware.com>2010-09-10 20:03:22 -0700
committerSterling Camden <sterling@camdensoftware.com>2010-09-10 20:03:22 -0700
commit6771d56ee4c2f28ca1d50e5f93e447819b61a582 (patch)
tree520d5194a7bad9825c085dcd18b4b8072413a79e
Initial version.
-rw-r--r--README65
-rw-r--r--url-picker150
2 files changed, 215 insertions, 0 deletions
diff --git a/README b/README
new file mode 100644
index 0000000..97c0a23
--- /dev/null
+++ b/README
@@ -0,0 +1,65 @@
+NAME url-picker
+
+SITE http://chipstips.com/?tag=plurlpicker
+ http://bitbucket.org/sterlingcamden/urlpicker
+
+AUTHOR Chip Camden
+
+DATE September, 2010
+
+DESCRIPTION
+
+Perl extension for rxvt-unicode (aka urxvt) to enable quick keyboard
+navigation of URLs shown in the terminal window. The design is similar
+to the 'follow hints' feature of Vimperator
+(http://vimperator.org/vimperator).
+
+INSTALLATION
+
+See the man page for urxvtperl(3) for a full discussion of Perl
+extensions. Enable this extension using one of the methods documented
+there. For instance, you could place the script url-picker in
+/usr/local/lib/urxvt/perl, then add the following to .Xdefaults:
+
+URxvt.perl-ext: default,matcher,url-picker
+URxvt.keysym.C-0xff0d: perl:url-picker
+
+I find that url-picker works well in combination with matcher, but you
+can leave out the latter if you don't care for it. The above enables, in
+addition to the default behavior, the matcher extension and url-picker.
+It directs the key combination of ctrl+enter to call the on_user_command
+function of url-picker.
+
+OPERATION
+
+If no URLs are visible on the screen, url-picker just pops up an overlay
+window that warns "no URLs found on screen". The overlay disappears
+after five seconds, but the terminal is immediately operable.
+
+If the terminal display contains only one URL, that URL is launched to
+the browser. The browser is determined by X resources
+url-picker.launcher if defined, otherwise URxvt.urlLauncher. If neither
+of these are defined, the 'sensible-browser' is used. The URL will be
+passed as the first argument.
+
+If more than one URL is visible in the terminal window, url-picker places
+numbered labels over the first characters of each URL on the screen. A
+prompt "Follow: " appears at the bottom of the terminal window, at which
+you can type only numbers, backspace, enter, or escape (all other input is
+ignored).
+
+Escape exits this mode and removes all overlay windows, without doing
+anything.
+
+Enter launches the URL associated with the number that has been typed, of
+that number matches one of the URL labels. Otherwise, nothing happens.
+
+When typing numbers, if the number typed so far uniquely identifies a
+URL, that URL is launched immediately. Otherwise, the labels that do not
+match the numbers typed so far will be hidden.
+
+The backspace key erases the last number typed, if there is one.
+
+When a URL is launched, all overlay windows are removed and the cursor
+position is restored to where it was in the terminal window before
+url-picker was invoked.
diff --git a/url-picker b/url-picker
new file mode 100644
index 0000000..8036a8d
--- /dev/null
+++ b/url-picker
@@ -0,0 +1,150 @@
+#! perl
+
+# Author: Chip Camden <sterling@camdensoftware.com>
+
+my $url =
+ qr{
+ (?:https?://|ftp://|news://|mailto:|file://|\bwww\.)
+ [a-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27,~#]*
+ (
+ \([a-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27,~#]*\)| # Allow a pair of matched parentheses
+ [a-zA-Z0-9\-\@;\/?:&=%\$_+*~] # exclude some trailing characters (heuristic)
+ )+
+ }x;
+
+sub on_user_command {
+ my ($self, $cmd) = @_;
+ if($cmd =~ s/^url-picker\b//) {
+ my $labels = {};
+ my $hrefs = {};
+ my $row = -1;
+ my $num = 0;
+ while ($row++ < $self->nrow) {
+ my $text = $self->line($row)->t;
+ while ($text =~ /$url/g)
+ {
+ my $col = $-[0];
+ my $href = $&;
+ $num++;
+ my $overlay = $self->overlay($col, $row, $self->strwidth($num), 1, urxvt::OVERLAY_RSTYLE, 0);
+ $overlay->set(0,0,$num);
+ $labels->{$num} = $overlay;
+ $hrefs->{$num} = $href;
+ }
+ }
+
+ if ($num < 1) {
+ my $ermsg = $self->overlay(0,-1,35,1,urxvt::OVERLAY_RSTYLE,0);
+ $ermsg->set(0,0,"url-picker: no URLs found on screen");
+ $self->{ermsg} = $ermsg;
+ $self->{timer} = urxvt::timer
+ ->new
+ ->after (5)
+ ->cb (sub {
+ $self->{ermsg} = ();
+ $self->{timer} = ();
+ });
+ }
+ else {
+ my $url_picker = {};
+ $url_picker->{prompt} = $self->overlay(0,-1,8,1,urxvt::OVERLAY_RSTYLE, 0);
+ $url_picker->{prompt}->set(0,0,"Follow:");
+ $url_picker->{labels} = $labels;
+ $url_picker->{hrefs} = $hrefs;
+ $url_picker->{num} = $num;
+ $url_picker->{buffer} = '';
+ my ($crow,$ccol) = $self->screen_cur;
+ $url_picker->{crow} = $crow;
+ $url_picker->{ccol} = $ccol;
+ $self->{url_picker} = $url_picker;
+ $self->update($url_picker);
+ }
+ }
+ ()
+}
+
+sub on_key_press {
+ my ($self, $event, $keysym) = @_;
+ my $p = $self->{url_picker};
+ if ($p) {
+ if ($keysym == 0xff1b) { # escape
+ $self->screen_cur($p->{crow},$p->{ccol});
+ $self->{url_picker} = ();
+ } elsif ($keysym == 0xff08) { # backspace
+ if (length($p->{buffer}) > 0) {
+ $p->{buffer} = substr($p->{buffer},0,-1);
+ $self->update($p);
+ }
+ } elsif (($keysym >= 48) && ($keysym <= 57)) {
+ $p->{buffer} = $p->{buffer} . ($keysym - 48);
+ $self->update($p);
+ } elsif ($keysym == 0xff0d) { # CR
+ my $num = $p->{buffer};
+ my $hrefs = $p->{hrefs};
+ if (($num > 0) && ($num <= $p->{num})) {
+ my $href = $hrefs->{$num};
+ $self->launch($href);
+ }
+ }
+ return 1;
+ }
+ ()
+}
+
+sub update {
+ my ($self, $p) = @_;
+ $p->{typing} = $self->overlay(8,-1,length($p->{buffer}),1,urxvt::DEFAULT_RSTYLE,0);
+ $p->{typing}->set(0,0,$p->{buffer});
+ my $ndx = 0;
+ my $labels = $p->{labels};
+ my $hrefs = $p->{hrefs};
+ my $len = length($p->{buffer});
+ my $size = $p->{num};
+ my @matches;
+ while (++$ndx <= $size) {
+ my $overlay = $labels->{$ndx};
+ if (($len == 0) || (($len <= length($ndx)) && (substr($ndx,0,$len) eq $p->{buffer}))) {
+ $overlay->show;
+ unshift @matches,$hrefs->{$ndx};
+ } else {
+ $overlay->hide;
+ }
+ }
+ if (scalar(@matches) == 1) {
+ $self->launch(@matches[0]);
+ } else {
+ $self->screen_cur($self->nrow,8+$len);
+ }
+}
+
+sub launch {
+ my ($self, $href) = @_;
+ my $launcher = $self->{launcher};
+ $self->exec_async ($launcher,$href);
+ my $p = $self->{url_picker};
+ $self->screen_cur($p->{crow},$p->{ccol});
+ $self->{url_picker} = ();
+}
+
+sub on_key_release {
+ my ($self, $event, $keysym) = @_;
+ $self->{url_picker};
+}
+
+sub my_resource {
+ my ($self) = @_;
+ $self->x_resource ("$self->{name}.$_[0]");
+}
+
+sub on_start {
+ my ($self) = @_;
+
+ ($self->{name} = __PACKAGE__) =~ s/.*:://;
+ $self->{name} =~ tr/_/-/;
+ $self->{launcher} = $self->my_resource("launcher") ||
+ $self->x_resource("urlLauncher") ||
+ "sensible-browser";
+ $self->{url_picker} = ();
+}
+
+# vim:set sw=3 sts=3 et: