ref: 6213e137ff2e0636284dc294017a39f916f1f3a9
parent: 4616c93e8d5fbb9fbedf3b2c16f5b86a21e834ac
author: stanley lieber <stanley.lieber@gmail.com>
date: Mon Oct 27 20:38:58 EDT 2014
newt: implement ned-style address ranges and overhaul h command to suit
--- a/rc/bin/newt
+++ b/rc/bin/newt
@@ -1,5 +1,6 @@
#!/bin/rc
-# bloated, featureful usenet reader for use with nntpfs
+# NEWT, their six-year-old daughter, yells from the back...
+# use with nntpfs
rfork en
ramfs
argv0=$0
@@ -10,7 +11,7 @@
mnt=/mnt/news
if(~ $#newtname 0)
newtname=newt@dont-email.me
-fn enterpost{
+fn e{
{
echo From: $"newtname
echo Newsgroups: `{echo $group | sed 's/\//\./g'}
@@ -18,9 +19,19 @@
echo
} >/tmp/post
eval $editor /tmp/post
- cat /tmp/post >$mnt/$group/post
+ yn send
+ if(~ $yn y)
+ cat /tmp/post >$mnt/$group/post
}
fn f { du -a $* | sed 's/^.* //g' }
+fn flag{
+ if(~ $1 [\+][aDdfrSs] [-][aDdfrSs]){
+ if(test $2 -le $#rposts && test -f $rposts($2)^/flags)
+ echo $1 >$rposts($2)^/flags
+ if not
+ echo !address
+ }
+}
fn fmtd{
date=`{cat}
if(! ~ $date(1) [0-9]*)
@@ -50,7 +61,7 @@
}
fn geth{
for(i in $*){
- from=`{awk -F ' ' '{print $3;}' $i/xover}
+ from=`{awk -F ' ' '{print $3;}' $rposts($i)^/xover >[2]/dev/null}
if(! ~ $#from 0 && ! ~ $#from 1){
nfrom=`{
for(i in $from){
@@ -61,16 +72,31 @@
if(! ~ $#nfrom 0)
from=$nfrom
}
- if(! ~ $#from 0){
- date=`{awk -F ' ' '{print $4;}' $i/xover >[2]/dev/null | fmtd}
- awk -v date'='$"date -v from'='$from(1) -F ' ' \
- '{print " " $1 " " date " " from " " substr($2,0,50);}' $i/xover >[2]/dev/null
- }
- if not
- echo ' '$"i' nil nil nil'
+ if(~ $#from 0)
+ from=nil
+ date=`{awk -F ' ' '{print $4;}' $rposts($i)^/xover >[2]/dev/null | fmtd}
+ if(~ $#date 0)
+ date=nil
+ subject=`{awk -F ' ' '{print substr($2,0,50);}' $rposts($i)^/xover >[2]/dev/null}
+ if(~ $#subject 0)
+ subject=nil
+ # unicode 00a0 divides message number from headline.
+ # command input ignores everything after unicode 00a0.
+ # these lines may be selected and sent to the prompt.
+ echo ' '$"i' '$"date' '$"from' '$"subject
}
}
fn getposts{ ls | grep -e '^[0-9]+$' | sort -n | tail -$maxposts }
+fn getr{
+ switch($*){
+ case ,; echo $posts
+ case ,*; seq 1 `{echo $* | sed 's/,//g'}
+ case *,; seq `{echo $* | sed 's/,//g'} $posts($#posts)
+ case *,*; seq `{echo $* | sed 's/,/ /g'}
+ case *; echo $*
+ }
+}
+fn h{ sed -n $1^p /tmp/h }
fn k{
kmnt=`{echo $mnt | sed 's/\//\\\//g'}
f $mnt/$* |
@@ -80,17 +106,16 @@
}
fn nshift{ shift; echo $* }
fn printhelp{
-echo '[0-9]+ print specified message
-b back
+echo 'Commands are of the form [<range>] <command> [args]
+<range> := <addr> | <addr>','<addr>
+<command> :=
+b print the next ten headers
e enter message
-f jump to first message
g ... go to specified group
-h print message headlines
+h print message headline (,h for all)
help print this help message
k ... list sub-groups under specified group
kf ... grep $home/lib/newsgroups for regexp
-l jump to last message
-n next
p print message with minimal headers
P print message with full headers
q quit
@@ -101,24 +126,62 @@
||cmd pipe raw message to a command
? print debug information'
}
-fn printp{
- if(test -d $mnt/$group/$1){
+fn p{
+ if(test $1 -le $#rposts && test -f $mnt/$group/$rposts($1)^/body){
{ # don't stutter
- grep -e '(^From|^Newsgroups|^Subject|^Date)' $1/header
+ grep -e '(^From|^Newsgroups|^Subject|^Date)' $rposts($1)^/header
echo
- cat $1/body
+ cat $rposts($1)^/body
} >/tmp/p
cat /tmp/p
}
echo
+ r=$1
+ post=$1
prompt=$group/$1
}
-fn printpp{
- if(test -d $mnt/$group/$1)
- cat $1/article
+fn P{
+ if(test $1 -le $#rposts && test -f $mnt/$group/$rposts($1)^/article)
+ cat $rposts($1)^/article
echo
+ r=$1
+ post=$1
prompt=$group/$1
}
+fn r{
+ if(test $1 -le $#rposts && test -f $mnt/$group/$rposts($1)^/header){
+ subject=`{grep -e '^Subject: ' $mnt/$group/$rposts($1)^/header | sed 's/^Subject: //g'}
+ if(! ~ $subject RE:* Re:* re:*)
+ subject=(Re: $subject)
+ e
+ }
+ if not
+ echo !message missing
+}
+fn y{
+ go=()
+ r=$post
+ if(! ~ $q 1){
+ rposts=`{getposts}
+ posts=`{seq 1 $#rposts}
+ post=$posts(1)
+ prompt=$post
+ geth $posts >/tmp/h
+ echo $#posts messages
+ }
+}
+fn yn{
+ echo
+ echo -n $* ' (y, n) '
+ yn=`{read}
+ switch($yn){
+ case y n
+ ;
+ case *
+ yn
+ }
+}
+fn '"' {{p $1 | sed 1d | sed 's/^/> /g' | sed 's/^> >/>>/g' | sed '$d'; echo}}
fn usage{
echo usage: $argv0 '[ -f newsgroup ] [ -m mountpoint ] [ -p maxposts ]' >[1=2]
exit usage
@@ -147,30 +210,35 @@
exit
}
builtin cd $mnt/$group
-go=()
-posts=`{getposts}
-geth $posts >/tmp/h
-post=$posts(1)
-echo $#posts messages
+y
while(){
echo -n $"prompt': '
- cmd=`{read}
+ # command input ignores everything after unicode 00a0.
+ rcmd=`{read | sed 's/[ ].*$//g' | sed 's/^([0-9]+)?(,)?([0-9]+)?/& /g'}
+ switch($rcmd){
+ case ,* [0-9]*
+ r=`{getr $rcmd(1)}
+ cmd=`{nshift $rcmd}
+ if(~ $#cmd 0)
+ cmd=p
+ case *
+ r=$post
+ cmd=$rcmd
+ }
switch($cmd){
- case [0-9]*
- if(grep -s -e '^[0-9]+$' <{echo $cmd(1)}){
- post=$cmd(1)
- printp $post
- }
case b
- if(! ~ $post $posts(1)){
- post=`{echo $post^-1 | bc}
- printp $post
+ r=`{seq $r(1) `{echo $r(1)^+10|bc}}
+ if(test $r($#r) -gt $posts($#posts))
+ r=`{seq $r(1) $posts($#posts)}
+ if(! ~ $#r 0 && test $r(1) -le $posts($#posts)){
+ sed -n $r(1)^,$r($#r)^p /tmp/h
+ post=$r($#r)
+ prompt=$post
}
+ if not
+ echo !address
case e
- enterpost
- case f
- post=$posts(1)
- printp $post
+ subject=() e
case g' '*
ngroup=`{nshift $cmd | sed 's/\./\//g'}
if(test -d $mnt/$ngroup){
@@ -177,12 +245,7 @@
if(grep -s -e '^[0-9]+$' <{ls -p $mnt/$ngroup}){
group=$ngroup
builtin cd $mnt/$group
- go=()
- posts=`{getposts}
- geth $posts >/tmp/h
- post=$posts(1)
- prompt=$group
- echo $#posts messages
+ y
}
if not
echo !$ngroup contains no messages
@@ -190,7 +253,10 @@
if not
echo !$ngroup does not exist
case h
- cat /tmp/h
+ for(i in $r)
+ h $i
+ post=$r($#r)
+ prompt=$post
case help
printhelp
case k
@@ -200,50 +266,46 @@
case kf' '*
grep -e `{nshift $cmd} $home/lib/newsgroups |
sed 's/^/ g /g'
- case l
- post=$posts($#posts)
- printp $post
case p
- printp $post
- case p' '*
- post=`{nshift $cmd}
- printp $post
+ for(i in $r)
+ p $i
case P
- printpp $post
- case P' '*
- post=`{nshift $cmd}
- printpp $post
+ for(i in $r)
+ P $i
case q
+ q=1 y # BUP STOP
exit
case r
- if(test -f $mnt/$group/$post/header){
- subject='Re: '^`{grep -e '^Subject: ' $mnt/$group/$post/header | sed 's/^Subject: //g'}
- enterpost
- }
- if not
- echo !message missing
+ for(i in $r)
+ r $i
+ post=$r($#r)
+ prompt=$post
case y
- posts=`{getposts}
- geth $posts >/tmp/h
- echo $#posts messages
+ y
case '"'
- printp $post | sed 1d | sed 's/^/> /g' | sed 's/^> >/>>/g'
+ for(i in $r)
+ '"' $i
+ post=$r($#r)
+ prompt=$post
case '||'*
cmd=`{echo $"cmd | sed 's/^\|\|//g'}
- cat $mnt/$group/$post/article | eval $cmd
+ cat $mnt/$group/^$rposts($post)^/article | eval $cmd
case '|'*
cmd=`{echo $"cmd | sed 's/^\|//g'}
- cat $mnt/$group/$post/body | eval $cmd
+ cat $mnt/$group/^$rposts($post)^/body | eval $cmd
case '?'
echo mnt: $mnt
echo group: $group
echo maxposts: $maxposts
+ echo rposts: $rposts
+ echo 'rposts(r):' $rposts($r)
echo posts: $posts
- echo post: $post
- case n *
+ echo post: $post
+ echo r: $r
+ case *
if(~ $post $posts(1) && ~ $#go 0){
go=1
- printp $post
+ p $post
}
if not if(! ~ $post $posts($#posts)){
go=1
@@ -250,7 +312,7 @@
post=`{echo $post^+1 | bc}
if(test $post -gt $posts($#posts))
post=$posts($#posts)
- printp $post
+ p $post
}
}
}
--- a/sys/man/1/newt
+++ b/sys/man/1/newt
@@ -39,10 +39,35 @@
starts by reading the list of messages in the
.I newsgroup,
printing out the number of messages, and then prompting for commands.
-The prompt itself presents the name of the group followed by
-the message number in the form of a file system path, relative to the
+The prompt itself represents the name of the group followed by the
+message number in the form of a file system path, relative to the
.I mountpoint.
.PP
+Commands, as in
+.IR ed (1),
+are of the form
+.RI `[ range ]
+.I command
+.RI [ arguments ]'.
+The command is applied to each message in the (optional) range.
+.PD
+.PP
+The address range can be:
+.TP 1.4i
+.I address
+to indicate a single message header.
+.PD
+.TP
+.IB address , address
+to indicate a range of contiguous message headers.
+.PD
+.PP
+The addresses can be:
+.TP 1.4i
+.I number
+to indicate a particular message.
+.PD
+.PP
The commands are:
.PP
.TP
@@ -51,7 +76,7 @@
.I number.
.TP
.B b
-Print the previous message.
+Print the headers for the next ten messages.
.TP
.B e
Enter a new message, honoring the environment variable
@@ -59,9 +84,6 @@
Default is
.IR hold (1) .
.TP
-.B f
-Jump to the first message in the group.
-.TP
.BI g " newsgroup
Change to the specified
.I newsgroup.
@@ -70,9 +92,9 @@
.TP
.B h
Print the disposition, date, sender and subject line
-of all messages in the group. These lines are suitable
-for selecting and sending to the prompt, in order to
-print messages either singly or in aggregate.
+of the message. These lines are suitable for selecting
+and sending to the prompt, in order to print messages
+either singly or in aggregate.
.TP
.B help
Print a summary of the available commands.
@@ -92,12 +114,6 @@
for
.I regexp
and prints commands suitable for changing to each match.
-.TP
-.B l
-Jump to the last message in the group.
-.TP
-.B n, or enter key
-Print the next message.
.TP
.B p
Print the current message with minimal headers.