allow extending a match after search mode
[fcscs/fcscs.git] / bin / fcscs
index 7543a9df7807c10ed3a89dda3a89f714f8b9e0f9..95a769a40d0225ade2fd7b0a2c205500e80ff60e 100755 (executable)
--- a/bin/fcscs
+++ b/bin/fcscs
@@ -401,7 +401,7 @@ sub get_regex_matches {
 
         my ($x, $y) = input_match_offset_to_coordinates($input->{width},
                                                         $offset);
-        push @matches, { x => $x, y => $y, string => $1 };
+        push @matches, { x => $x, y => $y, offset => $offset, string => $1 };
     }
     return @matches;
 }
@@ -543,6 +543,8 @@ sub select_match {
         $screen->refresh;
     }
 
+    $screen->draw_matches($config, $matches, []); # remove matches
+
     foreach (@{$matches}) {
         return { match => $_ } if $_->{id} == $number;
     }
@@ -550,6 +552,86 @@ sub select_match {
     return { match => undef };
 }
 
+sub extend_match_regex_left {
+    my ($line, $match, $regex) = @_;
+
+    my $s = reverse substr $line, 0, $match->{x};
+    if ($s =~ /^($regex)/) {
+        $match->{string}  = reverse($1) . $match->{string};
+        $match->{x}      -= length $1;
+        $match->{offset} -= length $1;
+    }
+    return;
+}
+sub extend_match_regex_right {
+    my ($line, $match, $regex) = @_;
+
+    my $s = substr $line, $match->{x} + length $match->{string};
+    if ($s =~ /^($regex)/) {
+        $match->{string} .= $1;
+    }
+    return;
+}
+sub extend_match {
+    my ($screen, $config, $input, $match) = @_;
+
+    debug $config, 'extend_match', 'started';
+
+    $screen->prompt(name => 'extend', value => undef);
+    $screen->draw_prompt($config);
+
+    delete $match->{id}; # don't draw any match ids
+    $screen->draw_matches($config, [], [$match]);
+    $screen->refresh;
+
+    my $line = $input->{lines}[$match->{y}];
+
+    while (1) {
+        my $match_old = \%{$match};
+
+        my $char = $screen->getch;
+        if ($char eq "\n") { # accept match
+            last;
+
+        } elsif ($char eq 'w') { # select current word (both directions)
+            extend_match_regex_left($line,  $match, qr/\w+/);
+            extend_match_regex_right($line, $match, qr/\w+/);
+        } elsif ($char eq 'b') { # select current word (only left)
+            extend_match_regex_left($line,  $match, qr/\w+/);
+        } elsif ($char eq 'e') { # select current word (only right)
+            extend_match_regex_right($line, $match, qr/\w+/);
+
+        } elsif ($char eq 'W') { # select current WORD (both directions)
+            extend_match_regex_left($line,  $match, qr/\S+/);
+            extend_match_regex_right($line, $match, qr/\S+/);
+        } elsif ($char eq 'B') { # select current WORD (only left)
+            extend_match_regex_left($line,  $match, qr/\S+/);
+        } elsif ($char eq 'E') { # select current WORD (only right)
+            extend_match_regex_right($line, $match, qr/\S+/);
+
+        } elsif ($char eq '^') { # select to beginning of line
+            extend_match_regex_left($line, $match, qr/.+/);
+        } elsif ($char eq '$') { # select to end of line
+            extend_match_regex_right($line, $match, qr/.+/);
+
+        # Allow mode changes if not overwritten by local mappings.
+        } elsif (defined $config->{mapping}{mode}{$char}) {
+            $screen->draw_matches($config, [$match_old], []); # clear match
+            return { key => $char };
+
+        } else {
+            next; # ignore unknown mappings
+        }
+
+        $screen->draw_matches($config, [$match_old], [$match]);
+        $screen->refresh;
+    }
+
+    debug $config, 'extend_match', 'done';
+
+    return { match => $match };
+}
+
 
 sub mapping_paste {
     my ($key, $screen, $config, $input) = @_;
@@ -659,6 +741,7 @@ sub mapping_mode_search {
     return {
         select  => 'search',
         matches => \@last_matches,
+        extend  => 1,
         handler => $config->{handler}{yank},
     };
 }
@@ -1214,6 +1297,13 @@ RESULT:
                                 $screen, \%config, $input,
                                 $result->{matches});
             $result->{handler} = $tmp->{handler};
+            $result->{extend}  = $tmp->{extend};
+            goto RESULT; # reprocess special entries in result
+        }
+        if (defined $result->{extend}) {
+            debug \%config, 'input', 'extending match';
+            $result = extend_match($screen, \%config, $input,
+                                   $result->{match});
             goto RESULT; # reprocess special entries in result
         }
         if (defined $result->{match}) {