url-select: almost completely rewritten
We're now able to: - Block tty updates while in URL selection mode -> no fuckups in ncurses clients anymore, hooray! - Select multiline URLs as such - Scroll nicely
This commit is contained in:
parent
211a5c8470
commit
8379775412
264
url-select
264
url-select
@ -16,7 +16,7 @@
|
|||||||
# - 'n': select next URL (also with Meta-u)
|
# - 'n': select next URL (also with Meta-u)
|
||||||
# - 'N': select previous URL
|
# - 'N': select previous URL
|
||||||
# - Return: open selected URL in browser and quit selection mode
|
# - Return: open selected URL in browser and quit selection mode
|
||||||
# - 'y': copy selected URL to primary selection and quit selection mode
|
# - 'y': copy (yank) selected URL and quit selection mode
|
||||||
# - Escape: cancel URL selection mode
|
# - Escape: cancel URL selection mode
|
||||||
|
|
||||||
# Options:
|
# Options:
|
||||||
@ -31,24 +31,9 @@ my $url_matcher = qr{(
|
|||||||
[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+[ab-zA-Z0-9\-\@;\/?&=%\$_+!*\x27()~]
|
[ab-zA-Z0-9\-\@;\/?:&=%\$_.+!*\x27(),~#]+[ab-zA-Z0-9\-\@;\/?&=%\$_+!*\x27()~]
|
||||||
)}x;
|
)}x;
|
||||||
|
|
||||||
my $browser;
|
|
||||||
my $underline = 0;
|
|
||||||
|
|
||||||
my $active = 0;
|
|
||||||
my $lastdir;
|
|
||||||
my $row;
|
|
||||||
my $ltext;
|
|
||||||
my $sel_url;
|
|
||||||
my $n;
|
|
||||||
my @beg;
|
|
||||||
my @end;
|
|
||||||
|
|
||||||
my $old_view_start;
|
|
||||||
my $old_sel_text;
|
|
||||||
|
|
||||||
|
|
||||||
sub on_start {
|
sub on_start {
|
||||||
my ($term) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
eval { require Regexp::Common::URI };
|
eval { require Regexp::Common::URI };
|
||||||
if(!$@) {
|
if(!$@) {
|
||||||
@ -58,9 +43,9 @@ sub on_start {
|
|||||||
}
|
}
|
||||||
|
|
||||||
# read resource settings
|
# read resource settings
|
||||||
$browser = $term->x_resource('urlLauncher') || 'x-www-browser';
|
$self->{browser} = $self->x_resource('urlLauncher') || 'x-www-browser';
|
||||||
if ($term->x_resource('underlineURLs') eq 'true') {
|
if ($self->x_resource('underlineURLs') eq 'true') {
|
||||||
$underline = 1;
|
$self->{underline} = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
()
|
()
|
||||||
@ -68,124 +53,105 @@ sub on_start {
|
|||||||
|
|
||||||
|
|
||||||
sub on_line_update {
|
sub on_line_update {
|
||||||
my ($term, $rn) = @_;
|
my ($self, $row) = @_;
|
||||||
|
|
||||||
if ($underline) {
|
if ($self->{underline}) {
|
||||||
my $line = $term->line($rn);
|
my $line = $self->line($row);
|
||||||
my $text = $line->t;
|
my $text = $line->t;
|
||||||
my $rend = $line->r;
|
my $rend = $line->r;
|
||||||
|
|
||||||
while ($text =~ /$url_matcher/g) {
|
while ($text =~ /$url_matcher/g) {
|
||||||
my $url = $1;
|
my $url = $1;
|
||||||
my ($first, $last) = ($-[1], $+[1] - 1);
|
my ($beg, $end) = ($-[1], $+[1] - 1);
|
||||||
--$last if $url =~ /["')]$/;
|
--$end if $url =~ /["')]$/;
|
||||||
|
|
||||||
for (@{$rend}[$first .. $last]) {
|
for (@{$rend}[$beg .. $end]) {
|
||||||
$_ |= urxvt::RS_Uline;
|
$_ |= urxvt::RS_Uline;
|
||||||
}
|
}
|
||||||
$line->r($rend);
|
$line->r($rend);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if ($active) {
|
|
||||||
# workaround for updates in ncurses clients
|
|
||||||
my @sel_beg = $term->selection_beg();
|
|
||||||
my @sel_end = $term->selection_end();
|
|
||||||
if ($sel_beg[0] != $row || $sel_beg[1] != $beg[$n] ||
|
|
||||||
$sel_end[0] != $row || $sel_end[1] != $end[$n]) {
|
|
||||||
$row -= $lastdir;
|
|
||||||
select_next($term, $lastdir, 1);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
sub on_scroll_back {
|
|
||||||
my ($term, $lines, undef) = @_;
|
|
||||||
|
|
||||||
if ($active) {
|
|
||||||
$row -= $lines;
|
|
||||||
}
|
|
||||||
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub on_user_command {
|
sub on_user_command {
|
||||||
my ($term, $cmd) = @_;
|
my ($self, $cmd) = @_;
|
||||||
|
|
||||||
if ($cmd eq 'url-select:select_next') {
|
if ($cmd eq 'url-select:select_next') {
|
||||||
if (not $active) {
|
if (not $self->{active}) {
|
||||||
$old_view_start = $term->view_start();
|
activate($self);
|
||||||
$old_sel_text = $term->selection();
|
|
||||||
}
|
}
|
||||||
select_next($term, -1);
|
select_next($self, -1);
|
||||||
}
|
}
|
||||||
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub on_key_press {
|
sub key_press {
|
||||||
if ($active) {
|
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
()
|
|
||||||
}
|
|
||||||
|
|
||||||
|
sub key_release {
|
||||||
sub on_key_release {
|
my ($self, $event, $keysym) = @_;
|
||||||
my ($term, $event, $keysym, undef) = @_;
|
|
||||||
|
|
||||||
if ($active) {
|
|
||||||
my $char = chr($keysym);
|
my $char = chr($keysym);
|
||||||
|
|
||||||
if ($keysym == 65307) {
|
if ($keysym == 0xff1b) {
|
||||||
# escape
|
# escape
|
||||||
quit_sel_mode($term);
|
deactivate($self);
|
||||||
return 1;
|
return 1;
|
||||||
} elsif ($keysym == 65293) {
|
} elsif ($keysym == 0xff0d) {
|
||||||
# return
|
# return
|
||||||
$term->exec_async($browser, $sel_url);
|
$self->exec_async($self->{browser}, ${$self->{found}[$self->{n}]}[4]);
|
||||||
quit_sel_mode($term);
|
deactivate($self);
|
||||||
return 1;
|
return 1;
|
||||||
} elsif ($char eq 'y') {
|
} elsif ($char eq 'y') {
|
||||||
quit_sel_mode($term);
|
$self->selection(${$self->{found}[$self->{n}]}[4]);
|
||||||
$term->selection($sel_url);
|
$self->selection_grab($event->{time});
|
||||||
|
deactivate($self);
|
||||||
return 1;
|
return 1;
|
||||||
} elsif ($char eq 'n') {
|
} elsif ($char eq 'n') {
|
||||||
select_next($term, -1);
|
select_next($self, -1);
|
||||||
return 1;
|
return 1;
|
||||||
} elsif ($char eq 'N') {
|
} elsif ($char eq 'N') {
|
||||||
select_next($term, 1);
|
select_next($self, 1);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub on_button_release {
|
sub on_button_release {
|
||||||
my ($term, $event) = @_;
|
my ($self, $event) = @_;
|
||||||
|
|
||||||
my $mask = $term->ModLevel3Mask | $term->ModMetaMask |
|
if ($self->{active}) {
|
||||||
|
if ($event->{button} == 4 || $event->{button} == 5) {
|
||||||
|
return;
|
||||||
|
} else {
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
my $mask = $self->ModLevel3Mask | $self->ModMetaMask |
|
||||||
urxvt::ShiftMask | urxvt::ControlMask;
|
urxvt::ShiftMask | urxvt::ControlMask;
|
||||||
|
|
||||||
if ($event->{button} == 2 && ($event->{state} & $mask) == 0) {
|
if ($event->{button} == 2 && ($event->{state} & $mask) == 0) {
|
||||||
my $col = $event->{col};
|
my $col = $event->{col};
|
||||||
my $line = $term->line($event->{row});
|
my $line = $self->line($event->{row});
|
||||||
my $text = $line->t;
|
my $text = $line->t;
|
||||||
|
|
||||||
while ($text =~ /($url_matcher)/g) {
|
while ($text =~ /$url_matcher/g) {
|
||||||
my ($url, $first, $last) = ($1, $-[1], $+[1] - 1);
|
my ($url, $beg, $end) = ($1, $-[0], $+[0]);
|
||||||
|
|
||||||
if ($first <= $col && $last >= $col) {
|
if ($url =~ s/["')]$//) {
|
||||||
$url =~ s/["')]$//;
|
--$end;
|
||||||
$term->exec_async($browser, $url);
|
}
|
||||||
|
if ($col >= $beg && $col <= $end) {
|
||||||
|
$self->exec_async($self->{browser}, $url);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -196,92 +162,110 @@ sub on_button_release {
|
|||||||
|
|
||||||
|
|
||||||
sub select_next {
|
sub select_next {
|
||||||
# $dir < 0: up; > 0: down
|
# $dir < 0: up, > 0: down
|
||||||
my ($term, $dir, $redo) = @_;
|
my ($self, $dir) = @_;
|
||||||
$lastdir = $dir;
|
my $row = $self->{row};
|
||||||
|
|
||||||
if (not $active) {
|
if (($dir < 0 && $self->{n} > 0) ||
|
||||||
$active = 1;
|
($dir > 0 && $self->{n} < $#{ $self->{found} })) {
|
||||||
$row = $term->view_start() + $term->nrow;
|
|
||||||
} elsif (!$redo &&
|
|
||||||
(($dir < 0 && $n > 0) || ($dir > 0 && $n < $#beg))) {
|
|
||||||
# another url on current line
|
# another url on current line
|
||||||
$n += $dir;
|
$self->{n} += $dir;
|
||||||
select_url($term);
|
hilight($self);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@beg = ();
|
while (($dir < 0 && $row > $self->top_row) ||
|
||||||
@end = ();
|
($dir > 0 && $row < $self->nrow - 1)) {
|
||||||
|
my $line = $self->line($row);
|
||||||
|
$row = ($dir < 0 ? $line->beg : $line->end) + $dir;
|
||||||
|
$line = $self->line($row);
|
||||||
|
my $text = $line->t;
|
||||||
|
|
||||||
for (my $i = 0; $i < $term->nrow - $term->top_row; ++$i) {
|
if ($text =~ /$url_matcher/g) {
|
||||||
$row += $dir;
|
delete $self->{found};
|
||||||
if ($dir < 0 && $row < $term->top_row) {
|
|
||||||
$row = $term->nrow - 1;
|
|
||||||
} elsif ($dir > 0 && $row >= $term->nrow) {
|
|
||||||
$row = $term->top_row;
|
|
||||||
}
|
|
||||||
|
|
||||||
my $line = $term->line($row);
|
do {
|
||||||
$ltext = $line->t;
|
my ($beg, $end) = ($-[0], $+[0]);
|
||||||
|
--$end if $& =~ /['")]$/;
|
||||||
|
push @{$self->{found}}, [$line->coord_of($beg),
|
||||||
|
$line->coord_of($end), substr($text, $beg, $end - $beg)];
|
||||||
|
} while ($text =~ /$url_matcher/g);
|
||||||
|
|
||||||
while ($ltext =~ /$url_matcher/g) {
|
$self->{row} = $row;
|
||||||
push @beg, $-[0];
|
$self->{n} = $dir < 0 ? $#{$self->{found}} : 0;
|
||||||
push @end, $+[0];
|
hilight($self);
|
||||||
--$end[$#end] if $& =~ /["')]$/;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (@beg > 0) {
|
|
||||||
$n = $dir < 0 ? $#beg : 0;
|
|
||||||
select_url($term);
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
# no url found
|
deactivate($self) unless $self->{found};
|
||||||
quit_sel_mode($term);
|
|
||||||
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub select_url {
|
sub hilight {
|
||||||
my ($term) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
# select current url
|
if ($self->{found}) {
|
||||||
$term->selection_beg($row, $beg[$n]);
|
if ($self->{row} < $self->view_start() ||
|
||||||
$term->selection_end($row, $end[$n]);
|
$self->{row} >= $self->view_start() + $self->nrow) {
|
||||||
$term->selection_make(0);
|
# scroll selected url into visible area
|
||||||
|
my $top = $self->{row} - ($self->nrow >> 1);
|
||||||
# scroll to make it visible
|
$self->view_start($top < 0 ? $top : 0);
|
||||||
if ($row < $term->view_start()) {
|
|
||||||
$term->view_start($row);
|
|
||||||
} elsif ($row >= $term->view_start() + $term->nrow) {
|
|
||||||
$term->view_start($row - $term->nrow + 1);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
# save url text
|
$self->want_refresh();
|
||||||
$sel_url = substr($ltext, $beg[$n], $end[$n] - $beg[$n]);
|
}
|
||||||
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
sub quit_sel_mode {
|
sub refresh {
|
||||||
my ($term) = @_;
|
my ($self) = @_;
|
||||||
|
|
||||||
$active = 0;
|
if ($self->{found}) {
|
||||||
|
$self->scr_xor_span(@{$self->{found}[$self->{n}]}[0 .. 3], urxvt::RS_RVid);
|
||||||
# select nothing
|
}
|
||||||
$term->selection_beg(1, 0);
|
|
||||||
$term->selection_end(1, 0);
|
()
|
||||||
$term->selection_make(0);
|
}
|
||||||
|
|
||||||
# restore old primary selection
|
sub activate {
|
||||||
$term->selection($old_sel_text);
|
my ($self) = @_;
|
||||||
|
|
||||||
# restore old view start
|
$self->{active} = 1;
|
||||||
$term->view_start($old_view_start);
|
|
||||||
|
$self->{row} = $self->view_start() + $self->nrow;
|
||||||
|
$self->{n} = 0;
|
||||||
|
$self->{view_start} = $self->view_start();
|
||||||
|
$self->{pty_ev_events} = $self->pty_ev_events(urxvt::EV_NONE);
|
||||||
|
|
||||||
|
$self->enable(
|
||||||
|
key_press => \&key_press,
|
||||||
|
key_release => \&key_release,
|
||||||
|
refresh_begin => \&refresh,
|
||||||
|
refresh_end => \&refresh,
|
||||||
|
);
|
||||||
|
|
||||||
|
()
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
sub deactivate {
|
||||||
|
my ($self) = @_;
|
||||||
|
|
||||||
|
$self->disable("key_press", "key_release", "refresh_begin", "refresh_end");
|
||||||
|
$self->view_start($self->{view_start});
|
||||||
|
$self->pty_ev_events($self->{pty_ev_events});
|
||||||
|
|
||||||
|
if ($self->{found}) {
|
||||||
|
delete $self->{found};
|
||||||
|
$self->want_refresh();
|
||||||
|
}
|
||||||
|
|
||||||
|
$self->{active} = 0;
|
||||||
|
|
||||||
()
|
()
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user