aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorNicholas Noll <nbnoll@eml.cc>2021-11-08 08:46:56 -0800
committerNicholas Noll <nbnoll@eml.cc>2021-11-08 08:46:56 -0800
commit43688fe7190d0350349d47727c3663421d5618dc (patch)
treeef71d02782dbce316b0481d5751f3fb1d1834527
parent65e84b15a944c83862da736a427636f3e64d3fc2 (diff)
feat(rc): added back functionality of prompt, now unicode aware
-rw-r--r--sys/cmd/rc/input.c155
-rw-r--r--sys/cmd/rc/main.c1
-rw-r--r--sys/cmd/rc/prompt.c7
-rw-r--r--sys/cmd/rc/rc.h7
4 files changed, 148 insertions, 22 deletions
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));
diff --git a/sys/cmd/rc/main.c b/sys/cmd/rc/main.c
index 865bcde..2c0aa42 100644
--- a/sys/cmd/rc/main.c
+++ b/sys/cmd/rc/main.c
@@ -58,6 +58,7 @@ main(int argc, char *argv[])
initpath();
initkeywords();
initshell();
+ inithistory();
enablevi();
xboot(argc, argv);
diff --git a/sys/cmd/rc/prompt.c b/sys/cmd/rc/prompt.c
index ebda9fb..1122d54 100644
--- a/sys/cmd/rc/prompt.c
+++ b/sys/cmd/rc/prompt.c
@@ -19,8 +19,13 @@ prompt(ushort *flag)
runner->flag.eof = 1;
return 0;
}
- write(mapfd(0), "\n\r", 2);
+ if(runner->cmd.io->e[-1] == '\n'){
+ runner->cmd.io->e[-1] = 0;
+ addhistory(runner->cmd.io->b);
+ runner->cmd.io->e[-1] = '\n';
+ }
+ write(mapfd(0), "\n\r", 2);
promptstr = " ";
runner->line++;
diff --git a/sys/cmd/rc/rc.h b/sys/cmd/rc/rc.h
index 32fb639..83c39e9 100644
--- a/sys/cmd/rc/rc.h
+++ b/sys/cmd/rc/rc.h
@@ -172,10 +172,13 @@ void *emalloc(uintptr);
void *erealloc(void*, uintptr);
void efree(void*);
-/* read.c */
+/* input.c */
int readline(char *);
void enablevi(void);
+void inithistory(void);
+int addhistory(char *);
+
/* prompt.c */
void resetprompt(void);
int prompt(ushort *);
@@ -237,7 +240,7 @@ void background(Thread *, int);
/* exec.c */
// XXX: odd place for this
-int count(Word *);
+int count(Word *);
Word *makeword(char *str, Word *link);
void freeword(Word *w);