From 36b1de62c371746603ef0221103aa10787ae40b3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Wed, 26 May 2021 22:45:09 +0200 Subject: mum: Use GNU Readline Technically, Term::ReadLine doesn't require GNU Readline specifically, but whatever. I may fix it in the future. --- src/mum | 162 ++++++++++++++++++++++++++++++++++++++++++---------------------- 1 file 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 <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 (/^(? \d*) (? (\+\+?|--?)) \Z/x) { + # +/- -- next/previous message + elsif (/^(? \d*) (? [+-]) \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)? \| (?.+) $d/x) { print "|\n"; } - # ! + # ! -- run shell command elsif (/^!/) { $cmd =~ s/!//; system $cmd; - print "!\n"; } - # r[a] - elsif (/^ra? \s+ (? .*)/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+ (? .+))? \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"; -- cgit v1.2.3