From 43688fe7190d0350349d47727c3663421d5618dc Mon Sep 17 00:00:00 2001 From: Nicholas Noll Date: Mon, 8 Nov 2021 08:46:56 -0800 Subject: feat(rc): added back functionality of prompt, now unicode aware --- sys/cmd/rc/input.c | 155 ++++++++++++++++++++++++++++++++++++++++++++++------- 1 file changed, 136 insertions(+), 19 deletions(-) (limited to 'sys/cmd/rc/input.c') diff --git a/sys/cmd/rc/input.c b/sys/cmd/rc/input.c index 7ec8100..cc2383d 100644 --- a/sys/cmd/rc/input.c +++ b/sys/cmd/rc/input.c @@ -32,7 +32,8 @@ static int ascii[256] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, }; -struct Mode { +struct Mode +{ ushort raw : 1; ushort multiline : 1; ushort mask : 1; @@ -43,9 +44,6 @@ struct Mode { } vi ; }; -static struct Mode mode; -static struct termios originalterm; - /* * the structure represents the state during line editing. * we pass this state to functions implementing specific editing functionalities @@ -82,8 +80,22 @@ struct TerminalState } yank; /* yank buffer */ intptr maxrows; /* maximum num of rows used so far (multiline mode) */ + intptr history; /* index of history we are currently editing */ }; +/* + * line history (circular buffer) + */ +struct History +{ + char **bot, **top, *entry[1024]; +}; + +/* globals */ +static struct Mode mode; +static struct History history; +static struct termios originalterm; + enum { KeyNil = 0, /* nil */ @@ -293,14 +305,120 @@ beep(void) fflush(stderr); } -/* =========================== Line editing ================================= */ +// ----------------------------------------------------------------------- +// command history + +void +inithistory(void) +{ + history.bot = history.top = history.entry; +} + +int +addhistory(char *line) +{ + char *copy; + + copy = strdup(line); + if(!copy) + return 0; + + *history.top++ = copy; + if(history.top == arrend(history.entry)) + history.top = history.entry; + + if(history.top == history.bot){ + efree(history.bot); + history.bot++; + } + + return 1; +} + +static +void +pophistory(void) +{ + if(--history.top < history.entry) + history.top = arrend(history.entry)-1; + efree(*history.top); +} + +static void refreshline(struct TerminalState *); -/* We define a very simple "append buffer" structure, that is an heap - * allocated string where we can append to. This is useful in order to +static +char ** +currenthistory(struct TerminalState *term, intptr *size) +{ + char **entry; + intptr len, head; + + if(history.top > history.bot){ + len = history.top - history.bot; + entry = history.top - term->history - 1; + }else if(history.top < history.bot){ + len = (arrend(history.entry) - history.bot) + (history.top - history.entry); + if((head=history.top - history.entry) < term->history) + entry = arrend(history.entry) - head; + else + entry = history.top - term->history - 1; + }else + return nil; + + *size = len; + return entry; +} + +static +void +usehistory(struct TerminalState *term, int d) +{ + rune r; + intptr w, len; + char *b, *e, **entry; + + if(!(entry = currenthistory(term, &len))) + return; + + efree(*entry); + *entry = strdup(term->edit.buf); + + term->history += d; + if(term->history < 0){ + term->history = 0; + return; + }else if(term->history >= len){ + term->history = len - 1; + return; + } + entry = currenthistory(term, &len); + + strncpy(term->edit.buf, *entry, term->edit.cap); + term->edit.buf[term->edit.cap-1] = 0; + + /* update cursor/buffer positions */ + term->edit.len = term->edit.pos = strlen(term->edit.buf); + for(w=0, b=term->edit.buf, e=term->edit.buf+term->edit.len; b < e; ){ + b += utf8·decode(b, &r); + w += utf8·runewidth(r); + } + term->cursor.len = term->cursor.pos = w; + + refreshline(term); +} + +// ----------------------------------------------------------------------- +// line editing + +/* + * we define a very simple "append buffer" structure, that is an heap + * 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. */ + * output in a single call, to avoid flickering effects. + */ -struct Buffer { +struct Buffer +{ int len; char *b; }; @@ -667,14 +785,8 @@ 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 @@ -1223,6 +1335,7 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) term.cursor.cap = columns(ifd, ofd); term.maxrows = 0; + term.history = 0; term.yank.buf = nil; term.yank.cap = term.yank.len = 0; @@ -1231,6 +1344,9 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) term.edit.buf[0] = '\0'; term.edit.cap--; /* make sure there is always space for the nulterm */ + /* push current (empty) command onto history stack */ + addhistory(""); + if(write(term.ofd,prompt,term.prompt.len) == -1) return -1; @@ -1259,6 +1375,7 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) switch(r){ case KeyEnter: + pophistory(); if(mode.multiline) move(&term, END(term)); goto finish; @@ -1300,11 +1417,11 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) break; case KeyCtrlP: /* ctrl-p */ - /* TODO next history */ + usehistory(&term, +1); break; case KeyCtrlN: /* ctrl-n */ - /* TODO prev history */ + usehistory(&term, -1); break; case KeyEsc: /* escape sequence */ @@ -1358,10 +1475,10 @@ interact(int ifd, int ofd, char *buf, intptr len, char *prompt) }else{ switch(esc[1]) { case 'A': /* up */ - movehistory(&term, 1); + usehistory(&term, +1); break; case 'B': /* down */ - movehistory(&term, 0); + usehistory(&term, -1); break; case 'C': /* right */ move(&term, right(&term, 1)); -- cgit v1.2.1