aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-10-29 08:44:47 -0700
committerNicholas Noll <nbnoll@eml.cc>2021-10-29 08:44:47 -0700
commitb12609cd69ff39f8a221b12230becadfe3e1fc57 (patch)
treea6d4eeaf4cdeab53d2f924556bf24a8ce4ff8214
parent079d5d6a214f169fa8b73f2d6f6f741810dbe9fe (diff)
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.
-rw-r--r--sys/cmd/rc/input.c508
-rw-r--r--sys/cmd/rc/lex.c25
-rw-r--r--sys/cmd/rc/rc.h2
-rw-r--r--sys/cmd/rc/rules.mk2
4 files changed, 329 insertions, 208 deletions
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 <termios.h>
#include <sys/ioctl.h>
@@ -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 <u.h>
#include <base.h>
+#include <libunicode.h>
// -----------------------------------------------------------------------
// 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=$(<D)/parse.h --output=$(<D)/parse.c $(<)
# Local rules
-$(BINS_$(d)): $(OBJS_$(d)) $(OBJ_DIR)/sys/base/base.a $(d)/parse.h
+$(BINS_$(d)): $(OBJS_$(d)) $(OBJ_DIR)/sys/libunicode/libunicode.a $(OBJ_DIR)/sys/base/base.a $(d)/parse.h
$(COMPLINK)
include share/pop.mk