#!/usr/bin/perl # dwim (do what i mean) is my own plan9-like plumber use v5.24; use warnings; use strict; use Path::ExpandTilde; use subs qw/path env handle fail run arguments/; my ($phrase, %o) = arguments "usage: $0 parse\n", 1, d => 0; $phrase = `xsel -o` if not defined $phrase; my @OPENER = ("xtopen"); my @EDITOR = (@OPENER, "vi"); my @PDF_VIEWER = ("xpdf"); my @MAN_VIEWER = (@OPENER, "man"); my @MAILER = (@OPENER, "mutt"); my @BROWSER = (@OPENER, "w3m -title"); my @FILE_BROWSER = (@OPENER, "noice"); my @MAILDIR_VIEWER = (@OPENER, "mutt -f"); my $MAILROOT = env MAILROOT => "/home/john/mail/"; our $handler; for ($phrase) { if (/^(https?:\/?\/?\S+)$/) { handle "web address"; run @BROWSER, "$1" } if (/^(mailto:\S+)$/ or /^(\S+@.+\.\w+)$/) { handle "e-mail address"; run @MAILER, "$1" } if (/^(.+?):(\d+).*?$/) { handle "file:line (like grep -n)"; my $p = path $1; run @EDITOR, "+$2", "$p" } if (/^(.+) line (\d+)\.?$/) { handle "FILE line LINE (like perl)"; my $p = path $1; run @EDITOR, "+$2", "$p" } if (/^(.+):(.+)$/) { handle "file:query (like grep)"; my $p = path $1; run @EDITOR, "+/$2", "$p" if -e $p; fail "file not found" if $o{d}; # otherwise fall through } if (/^(\S+)\((\S+)\)[,.]?/) { handle "manpage(section)"; run @MAN_VIEWER, $2, $1; } if (/^(\S+)\.([1-9])/) { handle "manpage.section"; my $p = path "$1.$2"; run @MAN_VIEWER, $p if -e $p; run @MAN_VIEWER, $2, $1; } if (/^<(\S+)>$/) { handle ""; open my $h, 'find / -maxdepth 3 -type d -name include 2>&-|' or fail "could not search include directories"; while (<$h>) { chomp; if (-e "$_/$1") { close $h; run @EDITOR, "$_/$1"; } } close $h; fail "header file not found"; } if (/^(\S+-[\d.]+_\d+)$/) { handle "xbps package"; run @OPENER, "in-shell", "sudo", "xbps-install", "-S", $1; } if (/^(\S+)$/) { handle "maildir / directory / file"; my $p = path $1; run @MAILDIR_VIEWER, "$p" if $p =~ /^$MAILROOT/; # maildir run @FILE_BROWSER, "$p" if -d $p; # directory run @PDF_VIEWER, "$p" if -e $p and $p =~ /\.pdf$/; # pdf run @EDITOR, "$p" if -e $p; # file fail "file not found" if $o{d}; # otherwise fall through } # otherwise die "no handler matched by: $phrase\n" } sub path { my $n = shift; $n = expand_tilde($n); return $n if $n =~ /^\// or $n =~ /^~/; my $d = `xtitle`; chomp $d; $d =~ s/.*\(([^(]+)\)$/$1/; $d =~ s,^~([^/]+),/home/$1,; $d =~ s,^~,/home/$ENV{USER},; die "couldn't retrieve current directory\n" if ! -d $d and ! -d ($d = dirname($d)); return "$d/$n"; } # take K => V and return environment variable K if defined, otherwise V sub env { my %h = @_; my $k = (keys %h)[0]; return $ENV{$k} if defined ${ENV}{$k}; return $h{$k}; } sub handle { $handler = shift; print STDERR "$handler MATCHED\n" if $o{d}; } sub fail { my $msg = shift; print STDERR "$handler FAILED: $msg\n"; } sub run { if ($o{d}) { my @argv = @_; s/(\s)/\\$1/g for @argv; # escape whitespace print STDERR "@argv\n"; } exec @_; } sub dirname { my $path = shift; $path =~ s,/[^/]+,,; return $path; } # parse ARGV and return list of positionals and hash of option values sub arguments { my $usage = shift; # usage string my $n = shift; # number of positional arguments my %options = @_; # option specification # parse options (end upon --) while ($_ = shift @ARGV) { last if /^--$/; unshift @ARGV, $_ and last if not /^-/; s/^-//; if (defined $options{$_}) { $options{$_} = 1 } else { die $usage; } } # fill @positionals with $n strings (with undef upon empty ARGV) my @positionals; my $i = 0; while (++$i <= $n) { if ($_ = shift @ARGV) { push @positionals, $_ } else { push @positionals, undef } } die $usage if @ARGV; # all processing should be done return @positionals, %options; }