From b12609cd69ff39f8a221b12230becadfe3e1fc57 Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Fri, 29 Oct 2021 08:44:47 -0700 Subject: Prototype of unicode readline support The readline functionality operated on the assumption that 1 byte = 1 character. This is obviously wrong if you input a non-ascii character. This commit temporarily removes a lot of functionality but parses input bytes in a unicode-aware manner. The outstanding problem now is 1 unicode rune != 1 column. There are double wide characters, as well as zero width runes, that further break our assumption that 1 rune = 1 character = 1 column. This is the next iteration. --- sys/cmd/rc/input.c | 508 ++++++++++++++++++++++++++++++++-------------------- sys/cmd/rc/lex.c | 25 ++- sys/cmd/rc/rc.h | 2 +- sys/cmd/rc/rules.mk | 2 +- 4 files changed, 329 insertions(+), 208 deletions(-) (limited to 'sys/cmd') diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c index 56f1780..8ca3145 100644 --- a/sys/cmd/rc/input.c +++ b/sys/cmd/rc/input.c @@ -1,4 +1,5 @@ #include "rc.h" + #include #include @@ -54,25 +55,33 @@ struct TerminalState int ifd; /* terminal stdin file descriptor. */ int ofd; /* terminal stdout file descriptor. */ - char *buf; /* edited line buffer. */ - intptr buflen; /* edited line buffer size. */ + struct{ + char *s; /* raw UTF-8 bytes */ + int len; /* number of bytes in prompt */ + int size; /* number of (printed) runes in prompt */ + } prompt; - struct { - int cap, len; + struct{ + intptr cap; /* capacity of edit buffer */ + intptr len; /* current number of bytes stored */ + intptr pos; /* position within edit buffer */ + char *buf; + } edit; /* edit buffer */ + + struct{ + intptr cap; /* number of columns in terminal */ + intptr len; /* current edited line length (in runes) */ + intptr pos; /* current cursor position (in runes) */ + intptr old; /* previous refresh cursor position (in runes) */ + } cursor; + + struct{ + intptr cap; + intptr len; char *buf; } yank; /* yank buffer */ - char *prompt; /* prompt to display. */ - intptr plen; /* prompt length. */ - - intptr pos; /* current cursor position. */ - intptr oldpos; /* previous refresh cursor position. */ - - intptr len; /* current edited line length. */ - intptr cols; /* number of columns in terminal. */ - intptr maxrows; /* maximum num of rows used so far (multiline mode) */ - int history_index; /* the history index we are currently editing. */ }; enum @@ -101,8 +110,14 @@ enum static void doatexit(void); /* vi operations */ -typedef intptr (*Noun)(struct TerminalState*, int); -typedef void (*Verb)(struct TerminalState*, intptr); +typedef struct +{ + intptr buffer; + intptr cursor; +} Position; + +typedef Position (*Noun)(struct TerminalState*, int); +typedef void (*Verb)(struct TerminalState*, Position); static void @@ -136,6 +151,7 @@ enterraw(int fd) goto fatal; raw = originalterm; /* modify the original mode */ + /* input modes: no break, no CR to NL, no parity check, no strip char, * no start/stop output control. */ raw.c_iflag &= ~(BRKINT | ICRNL | INPCK | ISTRIP | IXON); @@ -203,8 +219,7 @@ cursorposition(int ifd, int ofd) return cols; } -/* Try to get the number of columns in the current terminal, or assume 80 - * if it fails. */ +/* try to get the number of columns in the current terminal, or assume 80 if it fails. */ static int columns(int ifd, int ofd) @@ -250,7 +265,7 @@ clear(void) ; } -/* Beep, used for completion when there is nothing to complete or when all +/* beep: used for completion when there is nothing to complete or when all * the choices were already shown. */ static void @@ -266,6 +281,7 @@ beep(void) * allocated string where we can append to. This is useful in order to * write all the escape sequences in a buffer and flush them to the standard * output in a single call, to avoid flickering effects. */ + struct Buffer { int len; char *b; @@ -298,9 +314,9 @@ freebuffer(struct Buffer *ab) free(ab->b); } -/* Single line low level line refresh. +/* single line low level line refresh. * - * Rewrite the currently edited line accordingly to the buffer content, + * rewrite the currently edited line accordingly to the buffer content, * cursor position, and number of columns of the terminal. */ static void @@ -309,29 +325,40 @@ refreshsingleline(struct TerminalState *term) char esc[64]; struct Buffer ab; - intptr plen = term->plen; - int fd = term->ofd; - char *buf = term->buf; - intptr len = term->len; - intptr pos = term->pos; + int n; + rune r; + int fd = term->ofd; + intptr off = term->prompt.size; + char *buf = term->edit.buf; + intptr len = term->edit.len; + intptr pos = term->cursor.pos; + intptr col = term->cursor.len; + + assert(col); + assert(off); + + while((off+pos) >= term->cursor.cap){ + n = utf8·decode(buf, &r); + buf+=n, len-=n; + pos--, col--; + } - while((plen+pos) >= term->cols) { - buf++; - len--; - pos--; + assert(buf <= term->edit.buf + len); + + while(off+col > term->cursor.cap){ + n = utf8·decodeprev(buf+len-1, &r); + len-=n, col--; } - while(plen+len > term->cols) - len--; + assert(len >= 0); - // TODO: do we need so much malloc pressure? - initbuffer(&ab); + initbuffer(&ab); // TODO: do we need so much malloc pressure? /* move cursor to left edge */ snprintf(esc,64,"\r"); append(&ab,"\r",1); /* write the prompt and the current buffer content */ - append(&ab,term->prompt,strlen(term->prompt)); + append(&ab, term->prompt.s, term->prompt.len); if(mode.mask == 1) while(len--) @@ -339,20 +366,19 @@ refreshsingleline(struct TerminalState *term) else append(&ab,buf,len); - snprintf(esc,64,"\x1b[0K"); // erase to right append(&ab,esc,strlen(esc)); - snprintf(esc,64,"\r\x1b[%dC", (int)(pos+plen)); // move cursor to original position + snprintf(esc,64,"\r\x1b[%dC", (int)(off+pos)); // move cursor to original position append(&ab,esc,strlen(esc)); - if(write(fd,ab.b,ab.len) == -1) /* Can't recover from write error. */ + if(write(fd,ab.b,ab.len) == -1) /* can't recover from write error. */ ; freebuffer(&ab); } -/* Multi line low level line refresh. +/* multi line low level line refresh. * * Rewrite the currently edited line accordingly to the buffer content, * cursor position, and number of columns of the terminal. */ @@ -360,6 +386,7 @@ static void refreshmultilines(struct TerminalState *term) { +#if 0 char esc[64]; int plen = term->plen; int rows = (plen+term->len+term->cols-1)/term->cols; /* rows used by current buf. */ @@ -434,6 +461,7 @@ refreshmultilines(struct TerminalState *term) ; freebuffer(&ab); +#endif } /* Calls the two low level functions refreshSingleLine() or @@ -448,55 +476,78 @@ refreshline(struct TerminalState *term) refreshsingleline(term); } -/* insert the character 'c' at cursor current position. +/* insert the rune 'c' at cursor current position. * on error writing to the terminal -1 is returned, otherwise 0. */ int -insertchar(struct TerminalState *term, char c) +insertrune(struct TerminalState *term, int n, char *c) { - char d; - if(term->len < term->buflen){ - if(term->len == term->pos){ - term->buf[term->pos] = c; - term->pos++; - term->len++; - term->buf[term->len] = '\0'; - if((!mode.multiline && term->plen+term->len < term->cols)){ - d = (mode.mask==1) ? '*' : c; - if(write(term->ofd,&d,1) == -1) + rune r; + + if(term->edit.len + n <= term->edit.cap){ + if(term->edit.pos == term->edit.len){ + memcpy(term->edit.buf+term->edit.pos, c, n); + + term->edit.pos+=n, term->edit.len+=n; + term->cursor.pos++, term->cursor.len++; + + utf8·decode(c, &r); + if(wcwidth(r) < 1){ + exit(1); + } + + term->edit.buf[term->edit.len] = '\0'; + + if(!mode.multiline && ((term->prompt.size+term->cursor.pos+n) <= term->cursor.cap)){ + if(mode.mask){ + c = "*"; + n = 1; + } + if(write(term->ofd, c, n) == -1) return 0; - }else - refreshline(term); + } + refreshline(term); }else{ - memmove(term->buf+term->pos+1,term->buf+term->pos,term->len-term->pos); - term->buf[term->pos] = c; - term->len++; - term->pos++; - term->buf[term->len] = '\0'; + memmove(term->edit.buf+term->edit.len+n, term->edit.buf+term->edit.len, term->edit.len-term->edit.pos); + memcpy(term->edit.buf+term->edit.pos, c, n); + + term->edit.pos+=n, term->edit.len+=n; + term->cursor.pos++, term->cursor.len++; + + term->edit.buf[term->edit.len] = '\0'; refreshline(term); } } + return 1; } int -insertchars(struct TerminalState *term, int len, char *buf) +insertbytes(struct TerminalState *term, int len, char *buf) { - if(term->len + len > term->buflen) - len = term->buflen - term->len; - - if(term->len == term->pos){ - memcpy(term->buf, buf, len); - term->pos += len; - term->len += len; - term->buf[term->len] = '\0'; - // transfer the modeline here? + int nr; + if(term->edit.len + len > term->edit.cap){ + len = term->edit.cap - term->edit.len; + buf[len] = 0; + } + nr = utf8·len(buf); + + if(term->edit.pos == term->cursor.len){ + memcpy(term->edit.buf+term->edit.len, buf, len); + + term->edit.pos += len, term->edit.len += len; + term->cursor.pos += nr, term->cursor.len += nr; + + // XXX: transfer the modeline here? + term->edit.buf[term->edit.len] = '\0'; refreshline(term); }else{ - memmove(term->buf+term->pos+len,term->buf+term->pos,term->len-term->pos); - memcpy(term->buf+term->pos, buf, len); - term->pos += len; - term->len += len; - term->buf[term->len] = '\0'; + memmove(term->edit.buf+term->edit.pos+len,term->edit.buf+term->edit.pos,term->edit.len-term->edit.pos); + memcpy(term->edit.buf+term->edit.pos, buf, len); + + term->edit.pos += len, term->edit.len += len; + term->cursor.pos += nr, term->cursor.len += nr; + + term->edit.buf[term->edit.len] = '\0'; refreshline(term); } @@ -528,29 +579,30 @@ insertmode(int fd) static void -move(struct TerminalState *term, intptr to) +move(struct TerminalState *term, Position to) { - if(to != term->pos){ - term->pos = to; + if(to.buffer != term->edit.pos){ + term->edit.pos = to.buffer; + term->cursor.pos = to.cursor; refreshline(term); } } static void -yank(struct TerminalState *term, intptr to) +yank(struct TerminalState *term, Position to) { intptr len, off; - if(to == term->pos) + if(to.buffer == term->edit.pos) return; // noop - if(to > term->pos){ - len = to - term->pos; - off = term->pos; + if(to.buffer > term->edit.pos){ + len = to.buffer - term->edit.pos; + off = term->edit.pos; }else{ - len = term->pos - to; - off = to; + len = term->edit.pos - to.buffer; + off = to.buffer; } if(term->yank.cap < len+1){ @@ -559,109 +611,138 @@ yank(struct TerminalState *term, intptr to) term->yank.buf = emalloc(len+1); } term->yank.len = len; - memcpy(term->yank.buf, term->buf+off, len); + memcpy(term->yank.buf, term->edit.buf+off, len); term->yank.buf[len] = 0; } static void -delete(struct TerminalState *term, intptr to) +delete(struct TerminalState *term, Position to) { intptr diff; // delete characters in front of us (exclusive) - if(to > term->pos){ - diff = to - term->pos; - memmove(term->buf+term->pos, term->buf+to, term->len-to+1); - term->len -= diff; + if(to.buffer > term->edit.pos){ + diff = to.buffer - term->edit.pos; + memmove(term->edit.buf+term->edit.pos, term->edit.buf+to.buffer, term->edit.len-to.buffer+1); + term->edit.len -= diff; + + diff = to.cursor - term->cursor.pos; goto refresh; } // delete characters behind us - if(to < term->pos){ - diff = term->pos - to; - memmove(term->buf+to, term->buf+term->pos, term->len-term->pos+1); - term->pos = to; - term->len -= diff; + if(to.buffer < term->edit.pos){ + diff = term->edit.pos - to.buffer; + memmove(term->edit.buf+to.buffer, term->edit.buf+term->edit.pos, term->edit.len-term->edit.pos+1); + term->edit.pos = to.buffer; + term->edit.len -= diff; + + diff = term->cursor.pos - to.cursor; + term->cursor.pos = to.cursor; goto refresh; } // do nothing return; refresh: + term->cursor.len -= diff; refreshline(term); } /* movements */ +void +movehistory(struct TerminalState *term, int dir) +{ +} + +#define CURRENT(term) (Position){ .buffer=(term)->edit.pos, .cursor=(term)->cursor.pos }; + // move cursor to the left n boxes static -intptr +Position left(struct TerminalState *term, int n) { - intptr d; - d = term->pos - n; - return MAX(d, 0); + rune r; + Position pos = CURRENT(term); + char *buf = term->edit.buf + term->edit.pos; + + pos.cursor = MAX(pos.cursor-n, 0); + + while(n-- > 0 && buf > term->edit.buf) + buf -= utf8·decodeprev(buf-1, &r); + + pos.buffer = MAX(buf-term->edit.buf, 0); + return pos; } // move cursor to the right n boxes static -intptr +Position right(struct TerminalState *term, int n) { - intptr d; - d = term->pos + n; - return MIN(d, term->len); -} + rune r; + Position pos = CURRENT(term); + char *end = term->edit.buf + term->edit.len; + char *buf = term->edit.buf + term->edit.pos; -void -movehistory(struct TerminalState *term, int dir) -{ + pos.cursor = MIN(pos.cursor+n, term->cursor.len); + + while(n-- > 0 && buf < end) + buf += utf8·decode(buf, &r); + + pos.buffer = MIN(buf-term->edit.buf, term->edit.len); + return pos; } +#define HOME(term) (Position){0} + +#if 0 static -intptr +Position prevword(struct TerminalState *term, int n) { int c; - char *it = term->buf + term->pos; + Position pos = CURRENT(term); + char *buf = term->edit.buf + term->edit.pos; - while(n-- > 0 && it > term->buf){ - while(it > term->buf && ascii[it[-1]] == Space) - --it; + while(n-- > 0 && buf > term->edit.buf){ + while(buf > term->edit.buf && ascii[buf[-1]] == Space) + --buf; - c = ascii[it[-1]]; - while(it > term->buf && ascii[it[-1]] == c) - --it; + c = ascii[buf[-1]]; + while(buf> term->edit.buf && ascii[buf[-1]] == c) + --buf; } - return it-term->buf; + return buf-term->edit.buf; } static -intptr +Position prevWord(struct TerminalState *term, int n) { - char *it = term->buf + term->pos; + char *it = term->edit.buf + term->edit.pos; - while(n-- > 0 && it > term->buf){ - while(it > term->buf && ascii[it[-1]] == Space) + while(n-- > 0 && it > term->edit.buf){ + while(it > term->edit.buf && ascii[it[-1]] == Space) --it; - while(it > term->buf && ascii[it[-1]] != Space) + while(it > term->edit.buf && ascii[it[-1]] != Space) --it; } - return it-term->buf; + return it-term->edit.buf; } static -intptr +Position nextword(struct TerminalState *term, int n) { int c; - char *it = term->buf + term->pos; - char *end = term->buf + term->len; + char *it = term->edit.buf + term->edit.pos; + char *end = term->edit.buf + term->edit.len; while(n-- > 0 && it < end){ c = ascii[*it]; @@ -672,15 +753,15 @@ nextword(struct TerminalState *term, int n) ++it; } - return it-term->buf; + return it-term->edit.buf; } static -intptr +Position nextWord(struct TerminalState *term, int n) { - char *it = term->buf + term->pos; - char *end = term->buf + term->len; + char *it = term->edit.buf + term->edit.pos; + char *end = term->edit.buf + term->edit.len; while(n-- > 0 && it < end){ while(it < end && ascii[*it] != Space) @@ -690,16 +771,16 @@ nextWord(struct TerminalState *term, int n) ++it; } - return it-term->buf; + return it-term->edit.buf; } static -intptr +Position nextend(struct TerminalState *term, int n) { int c; - char *it = term->buf + term->pos; - char *end = term->buf + term->len; + char *it = term->edit.buf + term->edit.pos; + char *end = term->edit.buf + term->edit.len; while(n-- > 0 && it+1 < end){ while(it+1 < end && ascii[it[1]] == Space) @@ -710,15 +791,15 @@ nextend(struct TerminalState *term, int n) ++it; } - return it-term->buf; + return it-term->edit.buf; } static -intptr +Position nextEnd(struct TerminalState *term, int n) { - char *it = term->buf + term->pos; - char *end = term->buf + term->len; + char *it = term->edit.buf + term->edit.pos; + char *end = term->edit.buf + term->edit.len; while(n-- > 0 && it+1 < end){ while(it+1 < end && ascii[it[1]] == Space) @@ -728,9 +809,11 @@ nextEnd(struct TerminalState *term, int n) ++it; } - return it-term->buf; + return it-term->edit.buf; } +#define END(term) (Position){(term)->edit.len, (term)->cursor.len} + static int vi(struct TerminalState *term, char c) @@ -755,8 +838,8 @@ action: /* composable actions */ case 'l': verb(term, right(term, n)); break; case 'h': verb(term, left(term, n)); break; - case '0': verb(term, 0); break; - case '$': verb(term, term->len); break; + case '0': verb(term, HOME(term)); break; + case '$': verb(term, END(term)); break; case 'b': verb(term, prevword(term,n)); break; case 'B': verb(term, prevWord(term,n)); break; case 'w': verb(term, nextword(term,n)); break; @@ -772,8 +855,8 @@ action: /* special cases */ switch(c){ case 'd': - move(term, 0); - delete(term, term->len); + move(term, HOME(term)); + delete(term, END(term)); return 0; default: goto action; @@ -785,13 +868,13 @@ action: /* special cases */ switch(c){ case 'y': - if(term->yank.cap < term->len+1){ + if(term->yank.cap < term->edit.len+1){ efree(term->yank.buf); - term->yank.len = term->len; - term->yank.cap = term->len+1; + term->yank.len = term->edit.len; + term->yank.cap = term->edit.len+1; term->yank.buf = emalloc(term->yank.cap); } - memcpy(term->yank.buf, term->buf, term->len+1); + memcpy(term->yank.buf, term->edit.buf, term->edit.len+1); break; default: goto action; @@ -799,7 +882,7 @@ action: break; case 'p': // put - insertchars(term, term->yank.len, term->yank.buf); + insertbytes(term, term->yank.len, term->yank.buf); refreshline(term); return 0; @@ -814,20 +897,20 @@ action: case 'I': if(verb != move) goto unrecognized; - move(term, 0); + move(term, HOME(term)); goto insertmode; case 'a': if(verb != move) goto unrecognized; - if(term->pos < term->len){ - term->pos++; + if(term->edit.pos < term->edit.len){ + term->edit.pos++; refreshline(term); } goto insertmode; case 'A': if(verb != move) goto unrecognized; - move(term, term->len); + move(term, END(term)); goto insertmode; case 'x': @@ -846,7 +929,7 @@ action: return -1; if(c < ' ') break; - term->buf[term->pos] = c; + term->edit.buf[term->edit.pos] = c; refreshline(term); break; @@ -868,8 +951,8 @@ action: case 'D': if(verb != move) goto unrecognized; deleteln: - term->len = term->pos; - term->buf[term->pos] = 0; + term->edit.len = term->edit.pos; + term->edit.buf[term->edit.pos] = 0; refreshline(term); break; @@ -880,7 +963,10 @@ action: return 0; } +#undef END +#endif +#define END(term) (Position){(term).edit.len, (term).cursor.len} /* this function is the core of the line editing capability of linenoise. * it expects 'fd' to be already in "raw mode" so that every key pressed @@ -894,9 +980,10 @@ static int interact(int ifd, int ofd, char *buf, intptr len, char *prompt) { - char c; - int n; + int n, aux; char esc[3]; + char c[UTFmax+1] = { 0 }; + rune r; struct TerminalState term; /* @@ -905,35 +992,59 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) */ term.ifd = ifd; term.ofd = ofd; - term.buf = buf; - term.buflen = len; - term.prompt = prompt; - term.plen = strlen(prompt); - term.oldpos = term.pos = 0; - term.len = 0; - term.cols = columns(ifd, ofd); + + term.edit.buf = buf; + term.edit.cap = len; + term.edit.len = 0; + term.edit.pos = 0; + + term.prompt.s = prompt; + term.prompt.len = strlen(prompt); + term.prompt.size = utf8·len(prompt); + + term.cursor.pos = 0; + term.cursor.len = 0; + term.cursor.cap = columns(ifd, ofd); + term.maxrows = 0; - term.history_index = 0; term.yank.buf = nil; term.yank.cap = term.yank.len = 0; /* buffer starts empty. */ - term.buf[0] = '\0'; - term.buflen--; /* make sure there is always space for the nulterm */ + term.edit.buf[0] = '\0'; + term.edit.cap--; /* make sure there is always space for the nulterm */ - if(write(term.ofd,prompt,term.plen) == -1) + if(write(term.ofd,prompt,term.prompt.len) == -1) return -1; for(;;){ - n = read(term.ifd,&c,1); + n = read(term.ifd,c,1); if(n <= 0) goto finish; - switch(c){ + /* partition input by rune */ + if(utf8·onebyte(c[0])){ + r = c[0]; + }else if(utf8·twobyte(c[0])){ + n = read(term.ifd,c+1,1); + if(n < 1 || (n=utf8·decode(c, &r)) != 2) + goto finish; + }else if(utf8·threebyte(c[0])){ + n = read(term.ifd,c+1,2); + if(n < 2 || (n=utf8·decode(c, &r)) != 3) + goto finish; + }else if(utf8·fourbyte(c[0])){ + n = read(term.ifd,c+1,3); + if(n < 3 || (n=utf8·decode(c, &r)) != 4) + goto finish; + }else + goto finish; + + switch(r){ case KeyEnter: if(mode.multiline) - move(&term, term.len); + move(&term, END(term)); goto finish; case KeyCtrlC: @@ -946,16 +1057,20 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) break; case KeyCtrlD: - if(term.len > 0) + if(term.edit.len > 0) delete(&term, right(&term, 1)); break; case KeyCtrlT: - if(term.pos > 0 && term.pos < term.len){ - int aux = buf[term.pos-1]; - buf[term.pos-1] = buf[term.pos]; - buf[term.pos] = aux; - if (term.pos != term.len-1) term.pos++; + if(term.edit.pos > 0 && term.edit.pos < term.edit.len){ + aux = buf[term.edit.pos-1]; + + buf[term.edit.pos-1] = buf[term.edit.pos]; + buf[term.edit.pos] = aux; + + if(term.edit.pos != term.edit.len-1) + term.edit.pos++; + refreshline(&term); } break; @@ -988,24 +1103,26 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) if(mode.vi.on){ if(mode.vi.insert){ normalmode(term.ofd); - if(term.pos > 0){ - --term.pos; + if(term.edit.pos > 0){ + --term.edit.pos; refreshline(&term); } continue; } } case 1: +#if 0 if(mode.vi.on){ if(mode.vi.insert){ normalmode(term.ofd); if(vi(&term,esc[0]) < 0){ - term.len = -1; + term.edit.len = -1; goto finish; } continue; } } +#endif default: // 2 ; } @@ -1039,10 +1156,10 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) move(&term, left(&term, 1)); break; case 'H': /* home */ - move(&term, 0); + move(&term, HOME(term)); break; case 'F': /* end*/ - move(&term, term.len); + move(&term, END(term)); break; } } @@ -1051,10 +1168,10 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) else if(esc[0] == 'O'){ switch(esc[1]) { case 'H': /* home */ - move(&term, 0); + move(&term, HOME(term)); break; case 'F': /* end*/ - move(&term, term.len); + move(&term, END(term)); break; } } @@ -1062,35 +1179,44 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) break; default: +#if 0 if(mode.vi.on && !mode.vi.insert){ if(vi(&term,c) < 0){ - term.len = -1; + term.edit.len = -1; goto finish; } }else if(!insertchar(&term,c)){ - term.len = -1; + term.edit.len = -1; + goto finish; + } +#endif + if(!insertrune(&term, n, c)){ + term.edit.len = -1; goto finish; } + break; case KeyCtrlU: /* Ctrl+u, delete the whole line. */ buf[0] = '\0'; - term.pos = term.len = 0; + term.edit.pos = term.edit.len = 0; + term.cursor.pos = term.cursor.len = 0; refreshline(&term); break; case KeyCtrlK: /* Ctrl+k, delete from current to end of line. */ - buf[term.pos] = '\0'; - term.len = term.pos; + buf[term.edit.pos] = '\0'; + term.edit.len = term.edit.pos; + term.cursor.len = term.cursor.pos; refreshline(&term); break; case KeyCtrlA: /* Ctrl+a, go to the start of the line */ - move(&term, 0); + move(&term, HOME(term)); break; case KeyCtrlE: /* ctrl+e, go to the end of the line */ - move(&term, term.len); + move(&term, END(term)); break; case KeyCtrlL: /* ctrl+term, clear screen */ @@ -1099,13 +1225,13 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) break; case KeyCtrlW: /* ctrl+w, delete previous word */ - delete(&term, prevword(&term,1)); + /* delete(&term, prevword(&term,1)); */ break; } } finish: efree(term.yank.buf); - return term.len; + return term.edit.len; } /* diff --git a/sys/cmd/rc/lex.c b/sys/cmd/rc/lex.c index 9a58f21..9ca2453 100644 --- a/sys/cmd/rc/lex.c +++ b/sys/cmd/rc/lex.c @@ -142,28 +142,23 @@ putbyte(char *buf, int c) return buf; } -#define onebyte(c) ((c&0x80)==0x00) -#define twobyte(c) ((c&0xe0)==0xc0) -#define threebyte(c) ((c&0xf0)==0xe0) -#define fourbyte(c) ((c&0xf8)==0xf0) - static char * putrune(char *buf, int c) { buf = putbyte(buf, c); - if(onebyte(c)) + if(utf8·onebyte(c)) return buf; - if(twobyte(c)) - return putbyte(buf,c); - if(threebyte(c)){ - buf = putbyte(buf,c); - return putbyte(buf,c); + if(utf8·twobyte(c)) + return putbyte(buf,advance()); + if(utf8·threebyte(c)){ + buf = putbyte(buf,advance()); + return putbyte(buf,advance()); } - if(fourbyte(c)){ - buf = putbyte(buf,c); - buf = putbyte(buf,c); - return putbyte(buf,c); + if(utf8·fourbyte(c)){ + buf = putbyte(buf,advance()); + buf = putbyte(buf,advance()); + return putbyte(buf,advance()); } fatal("malformed utf8 stream"); diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h index eaf668a..32fb639 100644 --- a/sys/cmd/rc/rc.h +++ b/sys/cmd/rc/rc.h @@ -1,7 +1,7 @@ -#pragma once #include #include +#include // ----------------------------------------------------------------------- // types diff --git a/sys/cmd/rc/rules.mk b/sys/cmd/rc/rules.mk index 991fb2e..ceec50b 100644 --- a/sys/cmd/rc/rules.mk +++ b/sys/cmd/rc/rules.mk @@ -25,7 +25,7 @@ $(d)/parse.h $(d)/parse.c: $(d)/syntax.y yacc --header=$(