URI: 
       t9term, win: better echo cancellation - plan9port - [fork] Plan 9 from user space
  HTML git clone git://src.adamsgaard.dk/plan9port
   DIR Log
   DIR Files
   DIR Refs
   DIR README
   DIR LICENSE
       ---
   DIR commit ef5c6a6edaf3dcf2cddd46841dc0dd8fce2bf967
   DIR parent a208917e7a935c019095acd1acd8165f08a54b7a
  HTML Author: Russ Cox <rsc@swtch.com>
       Date:   Fri,  3 Sep 2010 10:21:16 -0400
       
       9term, win: better echo cancellation
       
       Also just drop \r from output.
       It's a losing battle to keep turning it off.
       
       R=rsc
       http://codereview.appspot.com/2128042
       
       Diffstat:
         M src/cmd/9term/9term.c               |      14 +++++++-------
         M src/cmd/9term/SunOS.c               |      19 -------------------
         M src/cmd/9term/bsdpty.c              |      23 -----------------------
         M src/cmd/9term/rcstart.c             |      72 ++++++++++++++++++++++++++++++-
         M src/cmd/9term/term.h                |       4 +++-
         M src/cmd/9term/win.c                 |      58 ++++++++++++++++++++++++++-----
       
       6 files changed, 129 insertions(+), 61 deletions(-)
       ---
   DIR diff --git a/src/cmd/9term/9term.c b/src/cmd/9term/9term.c
       t@@ -22,7 +22,6 @@ int plumbfd;
        int rcpid;
        int rcfd;
        int sfd;
       -int noecho;
        Window *w;
        char *fontname;
        
       t@@ -412,6 +411,9 @@ rcoutputproc(void *arg)
                                        fprint(2, "9term: rc read error: %r\n");
                                threadexitsall("eof on rc output");
                        }
       +                n = echocancel(data+cnt, n);
       +                if(n == 0)
       +                        continue;
                        cnt += n;
                        r = runemalloc(cnt);
                        cvttorunes(data, cnt-UTFmax, r, &nb, &nr, nil);
       t@@ -428,7 +430,7 @@ rcoutputproc(void *arg)
                        nr = label(r, nr);
                        if(nr == 0)
                                continue;
       -
       +                
                        recv(w->conswrite, &cwm);
                        pair.s = r;
                        pair.ns = nr;
       t@@ -499,7 +501,6 @@ void
        rcinputproc(void *arg)
        {
                static char data[9000];
       -        int s;
                Consreadmesg crm;
                Channel *c1, *c2;
                Stringpair pair;
       t@@ -513,12 +514,11 @@ rcinputproc(void *arg)
                        pair.ns = sizeof data;
                        send(c1, &pair);
                        recv(c2, &pair);
       -                
       -                s = setecho(sfd, 0);
       +
       +                if(isecho(sfd))
       +                        echoed(pair.s, pair.ns);
                        if(write(rcfd, pair.s, pair.ns) < 0)
                                threadexitsall(nil);
       -                if(s)
       -                        setecho(sfd, s);
                }
        }
        
   DIR diff --git a/src/cmd/9term/SunOS.c b/src/cmd/9term/SunOS.c
       t@@ -78,25 +78,6 @@ isecho(int fd)
        }
        
        int
       -setecho(int fd, int newe)
       -{
       -        int old;
       -
       -        if(tcgetattr(fd, &ttmode) < 0)
       -                fprint(2, "tcgetattr: %r\n");
       -        old = (ttmode.c_lflag&ECHO)==ECHO;
       -        if(old != newe){
       -                if(newe)
       -                        ttmode.c_lflag |= ECHO;
       -                else
       -                        ttmode.c_lflag &= ~ECHO;
       -                if(tcsetattr(fd, TCSANOW, &ttmode) < 0)
       -                        fprint(2, "tcsetattr: %r\n");
       -        }
       -        return old;
       -}
       -
       -int
        getintr(int fd)
        {
                if(tcgetattr(fd, &ttmode) < 0)
   DIR diff --git a/src/cmd/9term/bsdpty.c b/src/cmd/9term/bsdpty.c
       t@@ -97,29 +97,6 @@ isecho(int fd)
        }
        
        int
       -setecho(int fd, int newe)
       -{
       -        int old;
       -
       -        if(tcgetattr(fd, &ttmode) < 0)
       -                fprint(2, "tcgetattr: %r\n");
       -        old = ttmode.c_lflag & ECHO;
       -        if(old != newe){
       -                ttmode.c_lflag &= ~ECHO;
       -                ttmode.c_lflag |= newe;
       -                /*
       -                 * I tried using TCSADRAIN here, but that causes
       -                 * hangs if there is any output waiting for us.
       -                 * I guess TCSADRAIN is intended for use by our
       -                 * clients, not by us.
       -                 */
       -                if(tcsetattr(fd, 0, &ttmode) < 0)
       -                        fprint(2, "tcsetattr: %r\n");
       -        }
       -        return old;
       -}
       -
       -int
        getintr(int fd)
        {
                if(tcgetattr(fd, &ttmode) < 0)
   DIR diff --git a/src/cmd/9term/rcstart.c b/src/cmd/9term/rcstart.c
       t@@ -87,8 +87,6 @@ rcstart(int argc, char **argv, int *pfd, int *tfd)
                        dup(sfd, 2);
                        sys("stty tabs -onlcr icanon echo erase '^h' intr '^?'", 0);
                        sys("stty onocr", 1);        /* not available on mac */
       -                if(noecho)
       -                        sys("stty -echo", 0);
                        for(i=3; i<100; i++)
                                close(i);
                        signal(SIGINT, SIG_DFL);
       t@@ -111,3 +109,73 @@ rcstart(int argc, char **argv, int *pfd, int *tfd)
                return pid;
        }
        
       +struct {
       +        Lock l;
       +        char buf[1<<20];
       +        int r, w;
       +} echo;
       +
       +void
       +echoed(char *p, int n)
       +{
       +        lock(&echo.l);
       +        if(echo.r > 0) {
       +                memmove(echo.buf, echo.buf+echo.r, echo.w-echo.r);
       +                echo.w -= echo.r;
       +                echo.r = 0;
       +        }
       +        if(echo.w+n > sizeof echo.buf)
       +                echo.r = echo.w = 0;
       +        if(echo.w+n > sizeof echo.buf)
       +                n = 0;
       +        memmove(echo.buf+echo.w, p, n);
       +        echo.w += n;        
       +        unlock(&echo.l);
       +}
       +
       +int
       +echocancel(char *p, int n)
       +{
       +        int i;
       +
       +        lock(&echo.l);
       +        for(i=0; i<n; i++) {
       +                if(echo.r < echo.w) {
       +                        if(echo.buf[echo.r] == p[i]) {
       +                                echo.r++;
       +                                continue;
       +                        }
       +                        if(echo.buf[echo.r] == '\n' && p[i] == '\r')
       +                                continue;
       +                        if(p[i] == 0x08) {
       +                                if(i+2 <= n && p[i+1] == ' ' && p[i+2] == 0x08)
       +                                        i += 2;
       +                                continue;
       +                        }
       +                }
       +                echo.r = echo.w;
       +                break;
       +        }
       +        unlock(&echo.l);
       +        if(i > 0)
       +                memmove(p, p+i, n-i);
       +        return n-i;
       +}
       +
       +int
       +dropcrnl(char *p, int n)
       +{
       +        char *r, *w;
       +
       +        for(r=w=p; r<p+n; r++) {
       +                if(r+1<p+n && *r == '\r' && *(r+1) == '\n')
       +                        continue;
       +                if(*r == 0x08) {
       +                        if(r+2<=p+n && *(r+1) == ' ' && *(r+2) == 0x08)
       +                                r += 2;
       +                        continue;
       +                }
       +                *w++ = *r;
       +        }
       +        return w-p;
       +}
   DIR diff --git a/src/cmd/9term/term.h b/src/cmd/9term/term.h
       t@@ -4,7 +4,9 @@ extern void updatewinsize(int, int, int, int);
        extern int rcfd;
        extern int rcstart(int, char*[], int*, int*);
        extern int isecho(int);
       -extern int setecho(int, int);
        extern int noecho;
        extern int getintr(int);
        extern int loginshell;
       +extern void echoed(char*, int);
       +extern int echocancel(char*, int);
       +extern int dropcrnl(char*, int);
   DIR diff --git a/src/cmd/9term/win.c b/src/cmd/9term/win.c
       t@@ -5,7 +5,6 @@
        #include <9pclient.h>
        #include "term.h"
        
       -int noecho = 1;
        
        #define        EVENTSIZE        256
        #define        STACK        32768
       t@@ -71,6 +70,7 @@ void        sende(Event*, int, CFid*, CFid*, CFid*, int);
        char        *onestring(int, char**);
        int        delete(Event*);
        void        deltype(uint, uint);
       +void        sendbs(int, int);
        void        runproc(void*);
        
        int
       t@@ -349,6 +349,7 @@ stdinproc(void *v)
                CFid *afd = addrfd;
                int fd0 = rcfd;
                Event e, e2, e3, e4;
       +        int n;
        
                USED(v);
        
       t@@ -411,7 +412,10 @@ stdinproc(void *v)
                                        break;
        
                                case 'D':
       -                                q.p -= delete(&e);
       +                                n = delete(&e);
       +                                q.p -= n;
       +                                if(!isecho(fd0))
       +                                        sendbs(fd0, n);
                                        break;
        
                                case 'x':
       t@@ -491,6 +495,14 @@ stdoutproc(void *v)
                        n = read(fd1, buf+npart, 8192);
                        if(n <= 0)
                                error(nil);
       +                
       +                n = echocancel(buf+npart, n);
       +                if(n == 0)
       +                        continue;
       +                
       +                n = dropcrnl(buf+npart, n);
       +                if(n == 0)
       +                        continue;
        
                        /* squash NULs */
                        s = memchr(buf+npart, 0, n);
       t@@ -525,8 +537,10 @@ stdoutproc(void *v)
                                qlock(&q.lk);
                                m = sprint(x, "#%d", q.p);
                                if(fswrite(afd, x, m) != m){
       -                                fprint(2, "stdout writing address: %r; resetting\n");
       -                                fswrite(afd, "$", 1);
       +                                fprint(2, "stdout writing address %s: %r; resetting\n", x);
       +                                if(fswrite(afd, "$", 1) < 0)
       +                                        fprint(2, "reset: %r\n");
       +                                fsseek(afd, 0, 0);
                                        m = fsread(afd, x, sizeof x-1);
                                        if(m >= 0){
                                                x[m] = 0;
       t@@ -660,13 +674,18 @@ addtype(int c, uint p0, char *b, int nb, int nr)
        void
        sendtype(int fd0)
        {
       -        int i, n, nr;
       -
       -        while(ntypebreak){
       +        int i, n, nr, raw;
       +        
       +        raw = !isecho(fd0);
       +        while(ntypebreak || (raw && ntypeb > 0)){
                        for(i=0; i<ntypeb; i++)
       -                        if(typing[i]=='\n' || typing[i]==0x04){
       +                        if(typing[i]=='\n' || typing[i]==0x04 || (i==ntypeb-1 && raw)){
       +                                if((typing[i] == '\n' || typing[i] == 0x04) && ntypebreak > 0)
       +                                        ntypebreak--;
                                        n = i+1;
                                        i++;
       +                                if(isecho(fd0))
       +                                        echoed(typing, n);
                                        if(write(fd0, typing, n) != n)
                                                error("sending to program");
                                        nr = nrunes(typing, i);
       t@@ -674,7 +693,6 @@ sendtype(int fd0)
                                        ntyper -= nr;
                                        ntypeb -= i;
                                        memmove(typing, typing+i, ntypeb);
       -                                ntypebreak--;
                                        goto cont2;
                                }
                        print("no breakchar\n");
       t@@ -684,6 +702,22 @@ cont2:;
        }
        
        void
       +sendbs(int fd0, int n)
       +{
       +        char buf[128];
       +        int m;
       +
       +        memset(buf, 0x08, sizeof buf);
       +        while(n > 0) {
       +                m = sizeof buf;
       +                if(m > n)
       +                        m = n;
       +                n -= m;
       +                write(fd0, buf, m);
       +        }
       +}
       +
       +void
        deltype(uint p0, uint p1)
        {
                int w;
       t@@ -738,6 +772,12 @@ type(Event *e, int fd0, CFid *afd, CFid *dfd)
                                m += nr;
                        }
                }
       +        if(!isecho(fd0)) {
       +                n = sprint(buf, "#%d,#%d", e->q0, e->q1);
       +                fswrite(afd, buf, n);
       +                fswrite(dfd, "", 0);
       +                q.p -= e->q1 - e->q0;
       +        }
                sendtype(fd0);
        }