Discussion:
[PATCH 1/4] perl: matcher: remove (some) duplicates from match-list
Michal Nazarewicz
2018-04-14 20:09:54 UTC
Permalink
If two identical URLs appear on the terminal matcher will happily
show them both when displaying the match-list. Change it so that
duplicates appearing next to each other are removed.

For example, let’s say the screen shows the following URLs in order:

ⅰ) https://mina86.com/
ⅱ) https://google.com/
ⅲ) http://software.schmorp.de/pkg/rxvt-unicode.html
ⅳ) https://en.wikipedia.org/wiki/Main_Page
ⅴ) https://en.wikipedia.org/wiki/Main_Page
ⅵ) https://google.com/

Matcher will now display:

0-https://google.com/
1-https://en.wikipedia.org/wiki/Main_Page
2-http://software.schmorp.de/pkg/rxvt-unicode.html
3-https://google.com/
4-https://mina86.com/

Observe that Wikipedia appears only once while Google appears twice.
Thinking behind leaving Google twice is that there may be a big
distance on screen between url ⅲ and ⅳ and user might expecte to
find Google between ⅰ and ⅲ without realising ther’s another
instance at ⅵ.
---
src/perl/matcher | 39 +++++++++++++++++++--------------------
1 file changed, 19 insertions(+), 20 deletions(-)

diff --git a/src/perl/matcher b/src/perl/matcher
index d991d68..17cb1a6 100644
--- a/src/perl/matcher
+++ b/src/perl/matcher
@@ -150,44 +150,43 @@ sub on_action {
sub matchlist {
my ($self) = @_;

- $self->{matches} = [];
my $row = $self->nrow - 1;
- while ($row >= 0 && @{ $self->{matches} } < 10) {
+ my @matches = ();
+ my $width = 0;
+
+ my $text = '';
+ while ($row >= 0 && @matches < 10) {
my $line = $self->line ($row);
- my @matches = $self->find_matches ($row);
+ my @m = $self->find_matches ($row);
+
+ for (sort { $b->[0] <=> $a->[0] or $b->[1] <=> $a->[1] } @m) {
+ next if $_->[4] eq $text;

- for (sort { $b->[0] <=> $a->[0] or $b->[1] <=> $a->[1] } @matches) {
- push @{ $self->{matches} }, $_;
- last if @{ $self->{matches} } == 10;
+ $text = $_->[4];
+ my $w = $self->strwidth (scalar(@matches) . '-' . $text);
+ $width = $w if $w > $width;
+
+ push @matches, $_;
+ last if @matches == 10;
}

$row = $line->beg - 1;
}

- return unless @{ $self->{matches} };
-
- my $width = 0;
-
- my $i = 0;
- for my $match (@{ $self->{matches} }) {
- my $text = $match->[4];
- my $w = $self->strwidth ("$i-$text");
-
- $width = $w if $w > $width;
- $i++;
- }
+ return unless @matches;

$width = $self->ncol - 2 if $width > $self->ncol - 2;

- $self->{overlay} = $self->overlay (0, 0, $width, scalar (@{ $self->{matches} }), urxvt::OVERLAY_RSTYLE, 2);
+ $self->{overlay} = $self->overlay (0, 0, $width, scalar (@matches), urxvt::OVERLAY_RSTYLE, 2);
my $i = 0;
- for my $match (@{ $self->{matches} }) {
+ for my $match (@matches) {
my $text = $match->[4];

$self->{overlay}->set (0, $i, "$i-$text");
$i++;
}

+ $self->{matches} = \@matches;
$self->enable (key_press => \&matchlist_key_press);
}
--
2.16.2
Michal Nazarewicz
2018-04-14 20:09:55 UTC
Permalink
Introduce ‘matcher.matchlist-keys’ resource to the matcher pluging
which configures the set of hotkeys used.

It is often easier to press keys on a home row rather so users may be
inclined to configure the shortcuts for ergonomics, however another
aspect is that the default does not work on keyboard layout when digits
are on shifted positions (most notably classic Dvorak or Programmer
Dvorak layouts) since the overlay closes as soon as shift is pressed.
---
src/perl/matcher | 23 +++++++++++++++--------
1 file changed, 15 insertions(+), 8 deletions(-)

diff --git a/src/perl/matcher b/src/perl/matcher
index 17cb1a6..c738669 100644
--- a/src/perl/matcher
+++ b/src/perl/matcher
@@ -9,6 +9,7 @@
#:META:RESOURCE:%.pattern.:string:extra pattern to match
#:META:RESOURCE:%.launcher.:string:custom launcher for pattern
#:META:RESOURCE:%.rend.:string:custom rendition for pattern
+#:META:RESOURCE:%.matchlist-keys.:string:custom hotkeys on matchlist

=head1 NAME

@@ -32,7 +33,9 @@ The launcher can also be overridden on a per-pattern basis.

It is possible to activate the most recently seen match or a list of matches
from the keyboard. Simply bind a keysym to "matcher:last" or
-"matcher:list" as seen in the example below.
+"matcher:list" as seen in the example below. When displaying the list
+digits from 0 to 9 (or keys specified by C<matcher.matchlist-keys> can
+be used to jump to particular URL).

The C<matcher:select> action enables a mode in which it is possible to
iterate over the matches using the keyboard and either activate them
@@ -106,7 +109,7 @@ sub matchlist_key_press {
delete $self->{overlay};
$self->disable ("key_press");

- my $i = ($keysym == 96 ? 0 : $keysym - 48);
+ my $i = index $self->{matchlist_keys}, $self->locale_decode($octets);
if ($i >= 0 && $i < @{ $self->{matches} }) {
my @exec = @{ $self->{matches}[$i] };
$self->exec_async (@exec[5 .. $#exec]);
@@ -150,12 +153,16 @@ sub on_action {
sub matchlist {
my ($self) = @_;

+ my $keys = $self->{matchlist_keys};
+ my $max = length $keys;
+ $max = $self->nrow - 2 if $max > $self->nrow - 2;
+
my $row = $self->nrow - 1;
my @matches = ();
my $width = 0;

my $text = '';
- while ($row >= 0 && @matches < 10) {
+ while ($row >= 0 && @matches < $max) {
my $line = $self->line ($row);
my @m = $self->find_matches ($row);

@@ -163,11 +170,11 @@ sub matchlist {
next if $_->[4] eq $text;

$text = $_->[4];
- my $w = $self->strwidth (scalar(@matches) . '-' . $text);
+ my $w = $self->strwidth (substr($keys, scalar(@matches), 1) . '-' . $text);
$width = $w if $w > $width;

push @matches, $_;
- last if @matches == 10;
+ last if @matches == $max;
}

$row = $line->beg - 1;
@@ -180,9 +187,7 @@ sub matchlist {
$self->{overlay} = $self->overlay (0, 0, $width, scalar (@matches), urxvt::OVERLAY_RSTYLE, 2);
my $i = 0;
for my $match (@matches) {
- my $text = $match->[4];
-
- $self->{overlay}->set (0, $i, "$i-$text");
+ $self->{overlay}->set (0, $i, substr($keys, $i, 1) . '-' . $match->[4]);
$i++;
}

@@ -262,6 +267,8 @@ sub on_start {
}
$self->{matchers} = \@matchers;

+ $self->{matchlist_keys} = $self->my_resource ("matchlist-keys") // "0123456789";
+
()
}
--
2.16.2
Michal Nazarewicz
2018-04-14 20:09:56 UTC
Permalink
Automatically selecting the last entry in ‘matcher:select’ mode saves
user from having to manually press the ‘up’ arrow.
---
src/perl/matcher | 2 ++
1 file changed, 2 insertions(+)

diff --git a/src/perl/matcher b/src/perl/matcher
index c738669..903499b 100644
--- a/src/perl/matcher
+++ b/src/perl/matcher
@@ -405,6 +405,8 @@ sub select_enter {

$self->{overlay} = $self->overlay (0, -1, $self->ncol, 1, urxvt::OVERLAY_RSTYLE, 0);
$self->{overlay}->set (0, 0, "match-select");
+
+ $self->select_search (-1, $self->nrow - 1);
}

sub select_leave {
--
2.16.2
Michal Nazarewicz
2018-04-14 20:09:57 UTC
Permalink
In addition to arrows et al support more key bindings for navigating
matches in matcher:select mode, in particular:
- ‘j’, ‘k’, ‘g’ and ‘G’ to make Vi users comfortable (this is also what
less is using),
- Ctrl+N, Ctrl+P, Ctrl+J and Ctrl+G to make Emacs users comfortable and
- Ctrl+C which is universally understood as aborting operation.

With those new key bindings it’s possible to use matcher:select mode
without leaving the alphanumeric part of one’s keyboard.
---
src/perl/matcher | 60 +++++++++++++++++++++++++++++++++++++++++++++++++-------
1 file changed, 53 insertions(+), 7 deletions(-)

diff --git a/src/perl/matcher b/src/perl/matcher
index 903499b..120ce5c 100644
--- a/src/perl/matcher
+++ b/src/perl/matcher
@@ -457,29 +457,75 @@ sub select_refresh {
()
}

+{
+ package urxvt::ext::matcher::key;
+
+ sub new {
+ my ($pkg, $event, $keysym) = @_;
+ bless [$keysym, !!($event->{state} & urxvt::ControlMask)], $pkg
+ }
+
+ sub is_enter {
+ my ($keysym, $ctrl) = @{$_[0]};
+ $keysym == 0xff0d || $keysym == 0xff8d || ($ctrl && $keysym == 'j')
+ }
+
+ sub is_yank {
+ my ($keysym) = @{$_[0]};
+ $keysym == ord 'y'
+ }
+
+ sub is_escape {
+ my ($keysym, $ctrl) = @{$_[0]};
+ $keysym == 0xff1b || ($ctrl && ($keysym == ord 'g' || $keysym == ord 'c'))
+ }
+
+ sub is_home {
+ my ($keysym) = @{$_[0]};
+ $keysym == 0xff50 || $keysym == ord 'g'
+ }
+
+ sub is_end {
+ my ($keysym) = @{$_[0]};
+ $keysym == 0xff57 || $keysym == ord 'G'
+ }
+
+ sub is_up {
+ my ($keysym, $ctrl) = @{$_[0]};
+ $keysym == 0xff52 || $keysym == ord 'j' || ($ctrl && $keysym == ord 'p')
+ }
+
+ sub is_down {
+ my ($keysym, $ctrl) = @{$_[0]};
+ $keysym == 0xff52 || $keysym == ord 'k' || ($ctrl && $keysym == ord 'n')
+ }
+}
+
sub select_key_press {
my ($self, $event, $keysym, $string) = @_;

- if ($keysym == 0xff0d || $keysym == 0xff8d) { # enter
+ my $key = new urxvt::ext::matcher::key($event, $keysym);
+
+ if ($key->is_enter) {
if ($self->{matches}) {
my @match = @{ $self->{matches}[$self->{id}] };
$self->exec_async (@match[5 .. $#match]);
}
$self->select_leave;
- } elsif ($keysym == 0x79) { # y
+ } elsif ($key->is_yank) {
if ($self->{matches}) {
$self->selection ($self->{matches}[$self->{id}][4], 1);
$self->selection_grab (urxvt::CurrentTime, 1);
}
$self->select_leave;
- } elsif ($keysym == 0xff1b) { # escape
+ } elsif ($key->is_escape) { # escape
$self->view_start ($self->{view_start});
$self->select_leave;
- } elsif ($keysym == 0xff50) { # home
+ } elsif ($key->is_home) { # home
$self->select_search (+1, $self->top_row)
- } elsif ($keysym == 0xff57) { # end
+ } elsif ($key->is_end) { # end
$self->select_search (-1, $self->nrow - 1)
- } elsif ($keysym == 0xff52) { # up
+ } elsif ($key->is_up) {
if ($self->{id} > 0) {
$self->{id}--;
$self->want_refresh;
@@ -488,7 +534,7 @@ sub select_key_press {
$self->select_search (-1, $line->beg - 1)
if $line->beg > $self->top_row;
}
- } elsif ($keysym == 0xff54) { # down
+ } elsif ($key->is_down) {
if ($self->{id} < @{ $self->{matches} } - 1) {
$self->{id}++;
$self->want_refresh;
--
2.16.2
Loading...