aboutsummaryrefslogtreecommitdiff
path: root/dwim
blob: e63b107c2f7121d680890d9c5830511295d4d746 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/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 arguments/;

my ($phrase, %o) = arguments "usage: $0 parse\n", 1, d => 0;
$phrase = `xsel -o` if not defined $phrase;

my @LAUNCHER       = split /\s/, env OPENER => "urxvtc -e";
my @EDITOR         = split /\s/, env EDITOR => "vi";
my @MAILER         = split /\s/, env MAILER => "mutt";
my @BROWSER        = split /\s/, env BROWSER => "firefox";
my @FILE_BROWSER   = split /\s/, env FILE_BROWSER => "ranger";
my @MAILDIR_VIEWER = split /\s/, env MAILDIR_VIEWER => "mutt -f";
my $MAILROOT       = env MAILROOT => "/home/john/mail/";

our $handler;

for ($phrase) {
	if (/^(https?:\/?\/?.+)$/) {
		handle "web address";
		exec "firefox", "$1"
	}

	if (/^(mailto:.+)$/ or /^(.+@.+\.\w+)$/) {
		handle "e-mail address";
		exec @MAILER, "$1"
	}

	if (/^(.+):(\d+)(:.*?)?$/) {
		handle "{file}:{line} (like grep -n)";
		my $p = path $1;
		exec @LAUNCHER, @EDITOR, "-c", ":$2", "$p"
	}

	if (/^(.+) line (\d+)\.?$/) {
		handle "{file} line {line} (like perl)";
		my $p = path $1;
		exec @LAUNCHER, @EDITOR, "-c", ":$2", "$p"
	}

	if (/^(.+):(.+)$/) {
		handle "{file}:{query} (like grep)";
		my $p = path $1;
		exec @LAUNCHER, @EDITOR, "-c", "/$2", "$p" if -e $p;
		fail "file not found" if $o{d};
		# otherwise fall through
	}

	if (/^([^\s]+)$/) {
		handle "maildir / directory / file";
		my $p = path $1;
		exec @LAUNCHER, @MAILDIR_VIEWER, "$p" if $p =~ /^$MAILROOT/; # maildir
		exec @LAUNCHER, @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;
	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";
}

# 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;
}