1. Sterling Camden
  2. urlpicker

Commits

Sterling Camden  committed 9c74339

Initial version.

  • Participants
  • Branches default

Comments (0)

Files changed (2)

File README

View file
+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.

File url-picker

View file
+#! 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: