#!/usr/bin/perl # dwim (do what i mean) is my own plan9-like plumber use v5.24; use warnings; use strict; use subs qw/arguments dir env fail handle path run/; my ($DEBUG, $handler, $phrase); while ($_ = shift @ARGV) { if (/^-d$/) { $DEBUG = 1; } elsif (/^-/) { die "usage: $0 [-d] [phrase]\n"; } else { $phrase = $_; } } $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 = ('rox'); my @MAILDIR_VIEWER = (@OPENER, 'mutt -f'); my $MAILROOT = env MAILROOT => '/home/john/mail/'; 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 $DEBUG; # otherwise fall through } if (/^([-_A-Za-z]+)\((\d+)\)[):,.]*$/) { handle 'manual(section)'; run @MAN_VIEWER, $2, $1; } if (/^([-_A-Za-z]+)\.([1-9])$/) { handle 'manual.section'; my $p = path "$1.$2"; run @MAN_VIEWER, $p if -e $p; run @MAN_VIEWER, $2, $1; } if (/^([A-Za-z_][A-Za-z0-9_]*)\(/) { handle 'function(call'; my $dir = dir; s/\(.*//; for (`grep -n '^$_' "$dir"/*.c "$dir"/*.h`) { run @EDITOR, "+$2", $1 if /([^:]+):(\d+):/; } } 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+)$/) { 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 $DEBUG; # otherwise fall through } # otherwise die "no handler matched by: $phrase\n" } sub dir { for (`xtitle`) { chomp; s/.*\(([^(]+)\)$/$1/; s,^~([^/]+),/home/$1,; s,^~,/home/$ENV{USER},; die "couldn't retrieve current directory\n" if ! -d $_ and ! -d ($_ = dirname($_)); return $_; } die "couldn't retrieve current directory: xtitle not installed\n"; } sub path { my $n = shift; $n =~ s,^~([^/]+),/home/$1,; $n =~ s,^~,/home/$ENV{USER},; return $n if $n =~ /^\// or $n =~ /^~/; return dir . "/$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 $DEBUG; } sub fail { my $msg = shift; print STDERR "$handler FAILED: $msg\n"; } sub run { if ($DEBUG) { my @argv = @_; s/(\s)/\\$1/g for @argv; # escape whitespace print STDERR "@argv\n"; } system "@_ &"; exit; } sub dirname { my $path = shift; $path =~ s,/[^/]+,,; return $path; }