newt: implement ned-style address ranges and overhaul h command to suit

This commit is contained in:
stanley lieber 2014-10-28 00:38:58 -04:00
parent 4616c93e8d
commit 6213e137ff
2 changed files with 169 additions and 91 deletions

View file

@ -1,5 +1,6 @@
#!/bin/rc #!/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 rfork en
ramfs ramfs
argv0=$0 argv0=$0
@ -10,7 +11,7 @@ maxposts=30
mnt=/mnt/news mnt=/mnt/news
if(~ $#newtname 0) if(~ $#newtname 0)
newtname=newt@dont-email.me newtname=newt@dont-email.me
fn enterpost{ fn e{
{ {
echo From: $"newtname echo From: $"newtname
echo Newsgroups: `{echo $group | sed 's/\//\./g'} echo Newsgroups: `{echo $group | sed 's/\//\./g'}
@ -18,9 +19,19 @@ fn enterpost{
echo echo
} >/tmp/post } >/tmp/post
eval $editor /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 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{ fn fmtd{
date=`{cat} date=`{cat}
if(! ~ $date(1) [0-9]*) if(! ~ $date(1) [0-9]*)
@ -50,7 +61,7 @@ fn fmtd{
} }
fn geth{ fn geth{
for(i in $*){ 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){ if(! ~ $#from 0 && ! ~ $#from 1){
nfrom=`{ nfrom=`{
for(i in $from){ for(i in $from){
@ -61,16 +72,31 @@ fn geth{
if(! ~ $#nfrom 0) if(! ~ $#nfrom 0)
from=$nfrom from=$nfrom
} }
if(! ~ $#from 0){ if(~ $#from 0)
date=`{awk -F ' ' '{print $4;}' $i/xover >[2]/dev/null | fmtd} from=nil
awk -v date'='$"date -v from'='$from(1) -F ' ' \ date=`{awk -F ' ' '{print $4;}' $rposts($i)^/xover >[2]/dev/null | fmtd}
'{print " " $1 " " date " " from " " substr($2,0,50);}' $i/xover >[2]/dev/null if(~ $#date 0)
} date=nil
if not subject=`{awk -F ' ' '{print substr($2,0,50);}' $rposts($i)^/xover >[2]/dev/null}
echo ' '$"i' nil nil nil' 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 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{ fn k{
kmnt=`{echo $mnt | sed 's/\//\\\//g'} kmnt=`{echo $mnt | sed 's/\//\\\//g'}
f $mnt/$* | f $mnt/$* |
@ -80,17 +106,16 @@ fn k{
} }
fn nshift{ shift; echo $* } fn nshift{ shift; echo $* }
fn printhelp{ fn printhelp{
echo '[0-9]+ print specified message echo 'Commands are of the form [<range>] <command> [args]
b back <range> := <addr> | <addr>','<addr>
<command> :=
b print the next ten headers
e enter message e enter message
f jump to first message
g ... go to specified group g ... go to specified group
h print message headlines h print message headline (,h for all)
help print this help message help print this help message
k ... list sub-groups under specified group k ... list sub-groups under specified group
kf ... grep $home/lib/newsgroups for regexp kf ... grep $home/lib/newsgroups for regexp
l jump to last message
n next
p print message with minimal headers p print message with minimal headers
P print message with full headers P print message with full headers
q quit q quit
@ -101,24 +126,62 @@ y synchronize message list with server
||cmd pipe raw message to a command ||cmd pipe raw message to a command
? print debug information' ? print debug information'
} }
fn printp{ fn p{
if(test -d $mnt/$group/$1){ if(test $1 -le $#rposts && test -f $mnt/$group/$rposts($1)^/body){
{ # don't stutter { # don't stutter
grep -e '(^From|^Newsgroups|^Subject|^Date)' $1/header grep -e '(^From|^Newsgroups|^Subject|^Date)' $rposts($1)^/header
echo echo
cat $1/body cat $rposts($1)^/body
} >/tmp/p } >/tmp/p
cat /tmp/p cat /tmp/p
} }
echo echo
r=$1
post=$1
prompt=$group/$1 prompt=$group/$1
} }
fn printpp{ fn P{
if(test -d $mnt/$group/$1) if(test $1 -le $#rposts && test -f $mnt/$group/$rposts($1)^/article)
cat $1/article cat $rposts($1)^/article
echo echo
r=$1
post=$1
prompt=$group/$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{ fn usage{
echo usage: $argv0 '[ -f newsgroup ] [ -m mountpoint ] [ -p maxposts ]' >[1=2] echo usage: $argv0 '[ -f newsgroup ] [ -m mountpoint ] [ -p maxposts ]' >[1=2]
exit usage exit usage
@ -147,42 +210,42 @@ if(! test -d $mnt/$group){
exit exit
} }
builtin cd $mnt/$group builtin cd $mnt/$group
go=() y
posts=`{getposts}
geth $posts >/tmp/h
post=$posts(1)
echo $#posts messages
while(){ while(){
echo -n $"prompt': ' 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){ switch($cmd){
case [0-9]*
if(grep -s -e '^[0-9]+$' <{echo $cmd(1)}){
post=$cmd(1)
printp $post
}
case b case b
if(! ~ $post $posts(1)){ r=`{seq $r(1) `{echo $r(1)^+10|bc}}
post=`{echo $post^-1 | bc} if(test $r($#r) -gt $posts($#posts))
printp $post 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 case e
enterpost subject=() e
case f
post=$posts(1)
printp $post
case g' '* case g' '*
ngroup=`{nshift $cmd | sed 's/\./\//g'} ngroup=`{nshift $cmd | sed 's/\./\//g'}
if(test -d $mnt/$ngroup){ if(test -d $mnt/$ngroup){
if(grep -s -e '^[0-9]+$' <{ls -p $mnt/$ngroup}){ if(grep -s -e '^[0-9]+$' <{ls -p $mnt/$ngroup}){
group=$ngroup group=$ngroup
builtin cd $mnt/$group builtin cd $mnt/$group
go=() y
posts=`{getposts}
geth $posts >/tmp/h
post=$posts(1)
prompt=$group
echo $#posts messages
} }
if not if not
echo !$ngroup contains no messages echo !$ngroup contains no messages
@ -190,7 +253,10 @@ while(){
if not if not
echo !$ngroup does not exist echo !$ngroup does not exist
case h case h
cat /tmp/h for(i in $r)
h $i
post=$r($#r)
prompt=$post
case help case help
printhelp printhelp
case k case k
@ -200,57 +266,53 @@ while(){
case kf' '* case kf' '*
grep -e `{nshift $cmd} $home/lib/newsgroups | grep -e `{nshift $cmd} $home/lib/newsgroups |
sed 's/^/ g /g' sed 's/^/ g /g'
case l
post=$posts($#posts)
printp $post
case p case p
printp $post for(i in $r)
case p' '* p $i
post=`{nshift $cmd}
printp $post
case P case P
printpp $post for(i in $r)
case P' '* P $i
post=`{nshift $cmd}
printpp $post
case q case q
q=1 y # BUP STOP
exit exit
case r case r
if(test -f $mnt/$group/$post/header){ for(i in $r)
subject='Re: '^`{grep -e '^Subject: ' $mnt/$group/$post/header | sed 's/^Subject: //g'} r $i
enterpost post=$r($#r)
} prompt=$post
if not
echo !message missing
case y case y
posts=`{getposts} y
geth $posts >/tmp/h
echo $#posts messages
case '"' case '"'
printp $post | sed 1d | sed 's/^/> /g' | sed 's/^> >/>>/g' for(i in $r)
'"' $i
post=$r($#r)
prompt=$post
case '||'* case '||'*
cmd=`{echo $"cmd | sed 's/^\|\|//g'} cmd=`{echo $"cmd | sed 's/^\|\|//g'}
cat $mnt/$group/$post/article | eval $cmd cat $mnt/$group/^$rposts($post)^/article | eval $cmd
case '|'* case '|'*
cmd=`{echo $"cmd | sed 's/^\|//g'} cmd=`{echo $"cmd | sed 's/^\|//g'}
cat $mnt/$group/$post/body | eval $cmd cat $mnt/$group/^$rposts($post)^/body | eval $cmd
case '?' case '?'
echo mnt: $mnt echo mnt: $mnt
echo group: $group echo group: $group
echo maxposts: $maxposts echo maxposts: $maxposts
echo rposts: $rposts
echo 'rposts(r):' $rposts($r)
echo posts: $posts echo posts: $posts
echo post: $post echo post: $post
case n * echo r: $r
case *
if(~ $post $posts(1) && ~ $#go 0){ if(~ $post $posts(1) && ~ $#go 0){
go=1 go=1
printp $post p $post
} }
if not if(! ~ $post $posts($#posts)){ if not if(! ~ $post $posts($#posts)){
go=1 go=1
post=`{echo $post^+1 | bc} post=`{echo $post^+1 | bc}
if(test $post -gt $posts($#posts)) if(test $post -gt $posts($#posts))
post=$posts($#posts) post=$posts($#posts)
printp $post p $post
} }
} }
} }

View file

@ -39,10 +39,35 @@ Default is 30.
starts by reading the list of messages in the starts by reading the list of messages in the
.I newsgroup, .I newsgroup,
printing out the number of messages, and then prompting for commands. printing out the number of messages, and then prompting for commands.
The prompt itself presents the name of the group followed by The prompt itself represents the name of the group followed by the
the message number in the form of a file system path, relative to the message number in the form of a file system path, relative to the
.I mountpoint. .I mountpoint.
.PP .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: The commands are:
.PP .PP
.TP .TP
@ -51,7 +76,7 @@ Print message
.I number. .I number.
.TP .TP
.B b .B b
Print the previous message. Print the headers for the next ten messages.
.TP .TP
.B e .B e
Enter a new message, honoring the environment variable Enter a new message, honoring the environment variable
@ -59,9 +84,6 @@ Enter a new message, honoring the environment variable
Default is Default is
.IR hold (1) . .IR hold (1) .
.TP .TP
.B f
Jump to the first message in the group.
.TP
.BI g " newsgroup .BI g " newsgroup
Change to the specified Change to the specified
.I newsgroup. .I newsgroup.
@ -70,9 +92,9 @@ The name of a group may be provided in dotted
.TP .TP
.B h .B h
Print the disposition, date, sender and subject line Print the disposition, date, sender and subject line
of all messages in the group. These lines are suitable of the message. These lines are suitable for selecting
for selecting and sending to the prompt, in order to and sending to the prompt, in order to print messages
print messages either singly or in aggregate. either singly or in aggregate.
.TP .TP
.B help .B help
Print a summary of the available commands. Print a summary of the available commands.
@ -93,12 +115,6 @@ for
.I regexp .I regexp
and prints commands suitable for changing to each match. and prints commands suitable for changing to each match.
.TP .TP
.B l
Jump to the last message in the group.
.TP
.B n, or enter key
Print the next message.
.TP
.B p .B p
Print the current message with minimal headers. Print the current message with minimal headers.
.TP .TP