summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2021-05-26 22:45:09 +0200
committerJohn Ankarström <john@ankarstrom.se>2021-05-26 22:45:09 +0200
commit36b1de62c371746603ef0221103aa10787ae40b3 (patch)
treec0ed710d83fd8779bddae06b79f40b1abcc43256
parent393f6ef84459656d27c08ef8a0d571a0b209a309 (diff)
downloadmum-36b1de62c371746603ef0221103aa10787ae40b3.tar.gz
mum: Use GNU Readline
Technically, Term::ReadLine doesn't require GNU Readline specifically, but whatever. I may fix it in the future.
-rwxr-xr-xsrc/mum162
1 files changed, 107 insertions, 55 deletions
diff --git a/src/mum b/src/mum
index 4ee6f2a..cac3abe 100755
--- a/src/mum
+++ b/src/mum
@@ -5,6 +5,12 @@ use strict;
use warnings;
use Data::Dumper;
+use Getopt::Std;
+use POSIX qw/sigaction SIGINT/;
+use Term::ReadLine;
+use Term::ReadLine::Gnu ();
+
+our $VERSION = '0.01';
# Define range syntax
@@ -40,51 +46,68 @@ my $d = qr{
# Define program state
-my $MESSAGE = 0; # selected message
-my $INDEX = ''; # loaded mbox index
-my $MBOX = ''; # associated mbox
-my @MESSAGES; # loaded messages
-my %MARKS; # saved marks
-my $SEARCH; # last search regex
+my $MESSAGE = 0; # selected message
+my $INDEX = ''; # loaded mbox index
+my $MBOX = ''; # associated mbox
+my @MESSAGES; # loaded messages
+my %MARKS; # saved marks
+my $SEARCH; # last search regex
# Open TTY for reading and writing
open my $tty, '+<:unix', '/dev/tty' or die "Could not open /dev/tty: $!";
+# Parse arguments
+
+my %opt;
+$Getopt::Std::STANDARD_HELP_VERSION = 1;
+getopts('r:', \%opt);
+
+sub HELP_MESSAGE {
+ print STDERR <<USAGE;
+usage: $0 [-r mbox.i]
+USAGE
+}
+
+if ($opt{r}) {
+ load($opt{r});
+}
+
# Run main loop
+my $term = Term::ReadLine->new('repl', $tty, $tty);
+$term->ornaments(0);
+
+sigaction SIGINT, new POSIX::SigAction sub {
+ print $tty "\n";
+ $term->on_new_line();
+ $term->replace_line('');
+ $term->redisplay();
+};
+
while () {
$MESSAGE = 1 if $MESSAGE < 1;
$MESSAGE = @MESSAGES if $MESSAGE > @MESSAGES;
- print $tty "$MBOX:$MESSAGE& ";
-
# Read next command from user
- my $cmd = <$tty>;
- $cmd = '' if not $cmd;
+ my $cmd = $term->readline("$MBOX:$MESSAGE& ");
+ last if not defined $cmd;
+
chomp $cmd;
$cmd =~ s/^\s+|\s+$//g;
+ $term->addhistory($cmd) if $cmd =~ /\S/;
# Parse user-given command
for ($cmd) {
- # q
+ # q -- quit
if (/^q$/) {
exit;
}
- # range without command
- elsif (/^(?&range) \Z $d/x) {
- # select last message in range
- my ($a, $b);
- $a = toloc(0, shift @RANGE) or next if @RANGE > 1;
- $b = toloc($a, shift @RANGE) or next;
- $MESSAGE = $b;
- }
-
- # +/- (++/--)
- elsif (/^(?<num> \d*) (?<dir> (\+\+?|--?)) \Z/x) {
+ # +/- -- next/previous message
+ elsif (/^(?<num> \d*) (?<dir> [+-]) \Z/x) {
my $num = $+{num} || 1;
for ($+{dir}) {
$MESSAGE += $num if /\+/;
@@ -93,18 +116,29 @@ while () {
}
}
- # c
+ # c -- change working directory
elsif (/^c\s+(.*)/) {
chdir $1;
}
- # h
+ # h -- print summary of headers
elsif (/^ (?&range)? h \Z $d/x) {
h:
print "h\n";
}
- # p
+ # i -- print headers verbatim
+ elsif (/^ (&range)? i \Z $d/x) {
+ my ($a, $b);
+ $a = toloc(0, shift @RANGE) or next if @RANGE > 1;
+ $b = toloc($a, shift @RANGE) or next if @RANGE;
+ $b = $MESSAGE if not $b;
+ $a = $b if not $a;
+
+ print "$_" for @MESSAGES[$a-1..$b-1];
+ }
+
+ # p -- print message(s)
elsif (/^ (?&range)? p \Z $d/x) {
my ($a, $b);
$a = toloc(0, shift @RANGE) or next if @RANGE > 1;
@@ -112,10 +146,10 @@ h:
$b = $MESSAGE if not $b;
$a = $b if not $a;
- print "$_\n" for get($a, $b);
+ print "$_\n" for mbox($a, $b);
}
- # l
+ # l -- view message(s) in pager
elsif (/^ (?&range)? l \Z $d/x) {
my ($a, $b);
$a = toloc(0, shift @RANGE) or next if @RANGE > 1;
@@ -132,39 +166,29 @@ h:
close $pager;
}
- # |
+ # | -- pipe message(s)
elsif (/^ (?&range)? \| (?<rest>.+) $d/x) {
print "|\n";
}
- # !
+ # ! -- run shell command
elsif (/^!/) {
$cmd =~ s/!//;
system $cmd;
- print "!\n";
}
- # r[a]
- elsif (/^ra? \s+ (?<index> .*)/x) {
- my $idx = $+{index};
- $idx =~ s/\.i$//;
- $idx .= '.i'; # be sure to open index and not mbox
- open my $h, '<', $idx or do {
- warn "failed to open $idx: $!\n";
- next;
- };
- $INDEX = $idx;
- ($MBOX = $INDEX) =~ s/\.i$//;
- local $/ = '';
- @MESSAGES = () if not $cmd =~ /^ra/; # overwrite
- my $offset = 0;
- while (<$h>) {
- s/^From .*\n/$&M-Index-Offset: $offset\n/;
- push @MESSAGES, $_;
- $offset += length $_;
- }
- close $h;
- print scalar @MESSAGES, " messages\n";
+ # r -- read message headers from mbox index
+ elsif (/^r (\s+ (?<index> .+))? \Z/x) {
+ load($+{index} || $INDEX);
+ }
+
+ # range without command
+ elsif (/^(?&range) \Z $d/x) {
+ # select last message in range
+ my ($a, $b);
+ $a = toloc(0, shift @RANGE) or next if @RANGE > 1;
+ $b = toloc($a, shift @RANGE) or next;
+ $MESSAGE = $b;
}
# empty command
@@ -260,10 +284,36 @@ found:
return $loc;
}
-# Read messages from mbox
-sub get {
- my ($a, $b) = @_; # range to read
- my @messages; # messages to return
+# Load message headers from index
+sub load {
+ my $idx = shift; # index file to read
+
+ $idx =~ s/\.i$//;
+ $idx .= '.i'; # be sure to open index and not mbox
+ open my $h, '<', $idx or do {
+ warn "failed to open $idx: $!\n";
+ next;
+ };
+
+ $INDEX = $idx;
+ ($MBOX = $INDEX) =~ s/\.i$//;
+
+ @MESSAGES = ();
+ local $/ = '';
+ my $offset = 0;
+ while (<$h>) {
+ s/^From .*\n/$&M-Index-Offset: $offset\n/;
+ push @MESSAGES, $_;
+ $offset += length $_;
+ }
+ close $h;
+ print scalar @MESSAGES, " messages\n";
+}
+
+# Read full messages from mbox
+sub mbox {
+ my ($a, $b) = @_; # range to read
+ my @messages; # messages to return
open my $mbox, '<', $MBOX or do {
warn "failed to open $MBOX: $!\n";
@@ -294,3 +344,5 @@ sub get {
return @messages;
}
+
+print $tty "\n";