When recently I discovered Plan9, the first things I missed were a
non-only-English spell checker, support for other languages in troff
(mostly hyphenation), and other dictionaries for dict.  I've ported
"international ispell" to ape and write aispell, a modified version of
aspell script that work with ispell, I've formatted GCIDE, "Chambers's
Twentieth Century Dictionary", "Diccionario de la Real Academia de la
Lengua Española", "Moby Thesaursus" and "OpenThesaurus-es", and I was
hopping working in troff when I'll learn programming.  The lack of a
web browser capable of deal with today's madness and the portability
limitation of ape (at least for a ignorant like me) forcesme to deal
with other OS I have to install and maintaining, so the simplicity and
cleanness I like so much of plan9 become useless.  Thanks to Russ Cox for P9P!  

I've write a script for p9p too, you only need to install gnu
aspell (or other spell checker with "ispell -a" support) and compile a
slightly modified spout.c with rune support (I've called it uspout), so you can
use the script like native acme's aspell script.  This is from my README.PLAN9 
file:

[...]
In the acme directory are aispell, an equivalent script of aspell and
uspout.c, slighted modified spout.c for UTF-8 runes, needed by aispell
to support non English languages.  You can pass ispell options as
arguments to aispell, for example for use the Spanish dictionary you can put
in the tag:
>aispell -despañol -Tutf8 

Or put 'aispell -despañol -Tutf8 $*' in a script and call
it aispelles, for example.  Defining a function in lib/profile didn't
work for me...  You can use it in any text selected, but for now, if
it doesn't start at the beginning of the buffer, the output's
addresses will be wrong.  This package install American and British
dictionaries.  If you are interested, look at the Spanish_ispell package I've
ported from http://www.datsi.fi.upm.es/~coes.
[...]

In P9P you don't need "-Tutf8".  I was going to ask for a directory in
sources, but I haven't see any interest in those things in the list.  I hope 
that this will help you.
The script and spout's source are small, so I'm going to paste both here.
trebol.

#!/usr/local/plan9/bin/rc
# Don't forget to check the path!
# aispell_p9p

rm -f /tmp/$pid^'.'aispell

spellpgr=aspell
args=()
spellflags=()
for(x){
        switch($x){
        case -d*
                spellflags=($spellflags $x)
        case -p*
                spellflags=($spellflags $x)
        case -T*
                spellflags=($spellflags $x)
        case *
                args=($args $x)
        }
}

id=`{9p read acme/new/ctl}
id=$id(1)

echo 'name '^`{pwd}^/-spell | 9p write acme/$id/ctl

{
        if(~ $#args 0){
                cat > /tmp/$pid^'.'aispell
                args=/tmp/$pid^'.'aispell
                pipe=1
        }
        for(i in $args){
                        name=$i
                        if(~ $pipe 1){
                                name=`{9p read acme/$winid/tag | 9 sed 's/ 
.*//g'}
                                if(~ name '') name=nonamedwindow
                        }
                for(j in `{{cat $i; echo} | uspout | 9 sort -t: -u +2 | 9 sed 
's/$/\!/g' | $spellpgr -a $spellflags | 9 grep '^[&#]' | 9 sed 's/ /_/g'}){
                # {cat $i; echo} is for uspout, needs \n. Also I want to make a 
list of lines, so j can't have spaces 

                        miss=`{ echo $j | awk -F_ '{print $2}'}
                        sug=`{ echo $j | 9 sed 's/^.*://g'} # Can't put 9 grep 
-v '^#' here...
                        {cat $i; echo} |
                        uspout |
                        9 grep '.*:'$miss'$' |
                        9 sed 's/$/ '$sug'/g' | # If I put 9 grep -v '^#' 
above, this 9 sed cuts output, I don't know why ...
                        9 sed 's/#_.*$//g' |
                        9 sed 's/_/ /g' |  # If I put 9 sed 's/_/ /g' above, 
variables don't work in 9 sed.  Again, I don't know why...
                        9 sed s',^,'$name',g' | 9p write acme/$id/body
                }

        }
        rm -f /tmp/$pid^'.'aispell
        echo clean | 9p write acme/$id/ctl
}


------------------------
------------------------
uspout.c's source:
#include <u.h>
#include <libc.h>
#include <ctype.h>
#include <bio.h>

void    spout(int, char*);

Biobuf bout;

void
main(int argc, char *argv[])
{
        int i, fd;

        Binit(&bout, 1, OWRITE);
        if(argc == 1)
                spout(0, "");
        else
                for(i=1; i<argc; i++){
                        fd = open(argv[i], OREAD);
                        if(fd < 0){
                                fprint(2, "spell: can't open %s: %r\n", 
argv[i]);
                                continue;
                        }
                        spout(fd, argv[i]);
                        close(fd);
                }
        exits(nil);
}

Biobuf b;

void
spout(int fd, char *name)
{
        char *s, *t, *w;
        Rune r;
        int inword, wordchar;
        int n, wn, wid, c, m;
        char buf[1024];

        Binit(&b, fd, OREAD);
        n = 0;
        wn = 0;
        while((s = Brdline(&b, '\n')) != nil){
                if(s[0] == '.')
                        for(c=0; c<3 && *s>' '; c++){
                                n++;
                                s++;
                        }
                inword = 0;
                w = s;
                t = s;
                do{
                        c = *(uchar*)t;
                        if(c < Runeself)
                                wid = 1;
                        else{
                                wid = chartorune(&r, t);
                                c = r;
                        }
                        wordchar = 0;
                        if(isalpharune(c))
                                wordchar = 1;
                        if(inword && !wordchar){
                                if(c=='\'' && isalpha(t[1]))
                                        goto Continue;
                                m = t-w;
                                if(m > 1){
                                        memmove(buf, w, m);
                                        buf[m] = 0;
                                        Bprint(&bout, "%s:#%d,#%d:%s\n", name, 
wn, n, buf);
                                }
                                inword = 0;
                        }else if(!inword && wordchar){
                                wn = n;
                                w = t;
                                inword = 1;
                        }
                        if(c=='\\' && (isalpha(t[1]) || t[1]=='(')){
                                switch(t[1]){
                                case '(':
                                        m = 4;
                                        break;
                                case 'f':
                                        if(t[2] == '(')
                                                m = 5;
                                        else
                                                m = 3;
                                        break;
                                case 's':
                                        if(t[2] == '+' || t[2]=='-'){
                                                if(t[3] == '(')
                                                        m = 6;
                                                else
                                                        m = 4;
                                        }else{
                                                if(t[2] == '(')
                                                        m = 5;
                                                else if(t[2]=='1' || t[2]=='2' 
|| t[2]=='3')
                                                        m = 4;
                                                else
                                                        m = 3;
                                        }
                                        break;
                                default:
                                        m = 2;
                                }
                                while(m-- > 0){
                                        if(*t == '\n')
                                                break;
                                        n++;
                                        t++;
                                }
                                continue;
                        }
        Continue:
                        n++;
                        t += wid;
                }while(c != '\n');
        }
        Bterm(&b);
}

Reply via email to