X-Git-Url: https://ruderich.org/simon/gitweb/?p=fcscs%2Ffcscs.git;a=blobdiff_plain;f=bin%2Ffcscs;h=7543a9df7807c10ed3a89dda3a89f714f8b9e0f9;hp=25a530207447007fd5a17ee8d3eecbcb08fe4b8f;hb=37b381833bdc7b8479c61d1dffe5947f6c666532;hpb=d5259dcf27ca06470f01b1a26b3834f23dc9380c diff --git a/bin/fcscs b/bin/fcscs index 25a5302..7543a9d 100755 --- a/bin/fcscs +++ b/bin/fcscs @@ -344,7 +344,18 @@ package Screen { sub debug { my ($config, $module, @args) = @_; - say STDERR "$module: @args" if $config->{setting}{debug}; + return if not $config->{setting}{debug}; + + state $fh; # only open the file once per run + if (not defined $fh) { + # Ignore errors if the directory doesn't exist. + if (not open $fh, '>', "$ENV{HOME}/.config/fcscs/log") { + $fh = undef; # a failed open still writes a value to $fh + return; + } + } + + say $fh "$module: @args"; return; } @@ -461,9 +472,6 @@ sub run_in_background { my $pid = fork; defined $pid or die $!; if ($pid == 0) { # child - # Disable debug mode as writing will fail with closed STDERR. - $config->{setting}{debug} = 0; - $sub->(); } exit; @@ -548,7 +556,7 @@ sub mapping_paste { debug $config, 'mapping_paste', 'started'; - $config->{state}{handler} = \&handler_paste; + $config->{state}{handler} = $config->{handler}{paste}; $screen->prompt(flags => 'P'); # paste $screen->draw_prompt($config); @@ -561,7 +569,7 @@ sub mapping_yank { debug $config, 'mapping_yank', 'started'; - $config->{state}{handler} = \&handler_yank; + $config->{state}{handler} = $config->{handler}{yank}; $screen->prompt(flags => 'Y'); # yank $screen->draw_prompt($config); @@ -580,7 +588,7 @@ sub mapping_mode_path { return { select => 'path select', matches => \@matches, - handler => \&handler_yank, + handler => $config->{handler}{yank}, }; } sub mapping_mode_url { @@ -592,7 +600,7 @@ sub mapping_mode_url { return { select => 'url select', matches => \@matches, - handler => \&handler_url, + handler => $config->{handler}{url}, }; } @@ -651,7 +659,7 @@ sub mapping_mode_search { return { select => 'search', matches => \@last_matches, - handler => \&handler_yank, + handler => $config->{handler}{yank}, }; } @@ -673,7 +681,7 @@ sub handler_yank { # Use a temporary file to prevent leaking the yanked data to other users # with the command line, e.g. ps aux or top. my ($fh, $tmp) = File::Temp::tempfile(); # dies on its own - print $fh $screen->encode($match->{string}); + print $fh $screen->encode($match->{value}); close $fh or die $!; if ($config->{setting}{multiplexer} eq 'screen') { @@ -729,16 +737,12 @@ sub handler_paste { sub handler_url { my ($screen, $config, $match) = @_; - debug $config, 'handler_url', 'started'; + debug $config, 'handler_url', "opening $match->{value}"; run_in_background($config, sub { - my $url = defined $match->{url} - ? $match->{url} - : $match->{string}; - my @cmd = map { $screen->encode($_) } ( @{$config->{setting}{browser}}, - $url, + $match->{value}, ); run_command($config, \@cmd); }); @@ -908,7 +912,7 @@ Defaults in parentheses. =over -=item B enable debug mode (redirect stderr when enabling) (C<0>) +=item B enable debug mode, writes to I<~/.config/fcscs/log> (C<0>) =item B start in this mode, must be a valid mode mapping (C<\&mapping_mode_url>) @@ -967,6 +971,44 @@ my %regex = ( path => qr{(~?[a-zA-Z0-9_./-]*/[a-zA-Z0-9_./-]+)}, ); +=head2 HANDLERS + +Handlers are used to perform actions on the selected string. + +The following handlers are available, defaults in parentheses. + +=over + +=item B used to yank (copy) selection to paste buffer (C<\&handler_yank>) + +=item B used to paste selection into window (C<\&handler_paste>) + +=item B used to open URLs (e.g. in a browser) (C<\&handler_url>) + +=back + +Example: + + # Download YouTube videos with a custom wrapper, handle all other URLs + # with the default URL handler. + $config{handler}{url} = sub { + my ($screen, $config, $match) = @_; + + if ($match->{value} =~ m{^https://www.youtube.com/}) { + return run_in_background($config, sub { + run_command($config, ['youtube-dl-wrapper', $match->{value}]); + }); + } + handler_url(@_); + }; + +=cut +my %handler = ( + yank => \&handler_yank, + paste => \&handler_paste, + url => \&handler_url, +); + my %state = ( initial => 1, # used by select_match() for 'initial_mode' handler => undef, @@ -998,10 +1040,9 @@ Used as mappings, see L above. handler_paste() handler_url() -Used as handler to yank, paste selection or open URL in browser. They are -either set by the matching mapping function (C, etc.) or -configured by the current mode. +Used as handler to yank, paste selection or open URL in browser. + debug() get_regex_matches() select_match() run_command() @@ -1034,6 +1075,8 @@ package Fcscs { sub handler_paste { return main::handler_paste(@_); } sub handler_url { return main::handler_url(@_); } + sub debug { return main::debug(@_); } + sub get_regex_matches { return main::get_regex_matches(@_); } sub select_match { return main::select_match(@_); } @@ -1055,6 +1098,7 @@ $config{mapping}{simple} = \%mapping_simple; $config{attribute} = \%attribute; $config{setting} = \%setting; $config{regex} = \%regex; +$config{handler} = \%handler; $config{state} = \%state; package Fcscs { @@ -1173,11 +1217,25 @@ RESULT: goto RESULT; # reprocess special entries in result } if (defined $result->{match}) { + if (not defined $result->{match}->{value}) { + $result->{match}->{value} = $result->{match}->{string}; + } + debug \%config, 'input', 'running handler'; - my $handler = $config{state}{handler}; # set by user - $handler = $result->{handler} unless defined $handler; # set by mapping - $handler = \&handler_yank unless defined $handler; # fallback - $handler->($screen, \%config, $result->{match}); + + # Choose handler with falling priority. + my @handlers = ( + $config{state}{handler}, # set by user + $result->{match}->{handler}, # set by match + $result->{handler}, # set by mapping + $config{handler}{yank}, # fallback + ); + foreach my $handler (@handlers) { + next unless defined $handler; + + $handler->($screen, \%config, $result->{match}); + last; + } last; }