Author | Jamozed <[email protected]> |
Date | 2021-08-19 03:46:23 |
Commit | 61d48de47e99fa859414d8ede55b49257fd1cefb |
Parent | 6e65ba3c9750eae6dff2b5ac06a2c1f8b4de34af |
Add command history
Diffstat
M | src/lineread.c | | | 99 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------- |
M | src/lineread.h | | | 1 | + |
M | src/main.c | | | 2 | +- |
3 files changed, 90 insertions, 12 deletions
diff --git a/src/lineread.c b/src/lineread.c index 24c6022..7180cce 100644 --- a/src/lineread.c +++ b/src/lineread.c @@ -30,6 +30,7 @@ WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. */ +#include "conf.h" #include "lineread.h" #include "lib/error.h" @@ -40,18 +41,25 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. #include <errno.h> #include <stdbool.h> +#include <stddef.h> #include <stdio.h> #include <stdlib.h> #include <string.h> struct line { - char *s; size_t sp, sl, sc; size_t hi; + char *s; size_t sp, sl, sc; char *prompt; size_t pl; size_t cols; }; +struct hist { + struct line *a; size_t ap, ah, at, al, ac; +}; + static struct termios tco, tcn; static bool rawflag = false, ateflag = false; +static struct hist h = { NULL, 0, 0, 0, 0 }; + static char *linentty(void); static char *lineedit(void); static void lineESC(struct line *l, register int c); @@ -78,12 +86,23 @@ static void lineDeleteWordEnd(struct line *l); static void lineDeleteHome(struct line *l); static void lineDeleteEnd(struct line *l); +static int histInit(struct hist *h); +static void histFree(struct hist *h); +static void histMovePrior(struct hist *h); +static void histMoveNext(struct hist *h); +static void histMoveHome(struct hist *h); +static void histMoveEnd(struct hist *h); +static void histPush(struct hist *h, struct line l); + /* Read a line from stdin */ char *lineread(void) { if (!isatty(STDIN_FILENO)) { errno = 0; return linentty(); } else { return lineedit(); } } +/* Free memory allocated by lineread */ +void linefree(void) { histFree(&h); } + /* Read from a non-terminal stdin */ static char *linentty(void) { struct line l; register char *r; @@ -102,15 +121,22 @@ ret:; free(l.s); return r; } +#define l h.a[h.ap] /* Dynamically read a line from stdin */ static char *lineedit(void) { - struct line l; register char *r; + register char *r; - l.sp = 0; l.sl = 0; l.sc = 1024; l.hi = 0; - l.prompt = "$ "; l.pl = strlen(l.prompt); - - if (!(l.cols = getcols())) { return NULL; } - if (!(l.s = malloc(l.sc * sizeof (*l.s)))) { return NULL; } l.s[0] = 0; + { + if (h.a == NULL) { if (histInit(&h)) { return NULL; } } + + struct line m = { NULL, 0, 0, 1024 }; + m.prompt = "$ "; m.pl = strlen(m.prompt); + + if (!(m.cols = getcols())) { return NULL; } + if (!(m.s = malloc(m.sc * sizeof (*m.s)))) { return NULL; } m.s[0] = 0; + + histPush(&h, m); + } tcraw(); fputs(l.prompt, stdout); @@ -151,8 +177,8 @@ static char *lineedit(void) { case '[': switch ((c = fgetc(stdin))) { case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': { lineESC(&l, c); continue; } - case 'A': { /* TODO */ continue; } // UP - case 'B': { /* TODO */ continue; } // DOWN + case 'A': { histMovePrior(&h); continue; } // UP + case 'B': { histMoveNext(&h); continue; } // DOWN case 'C': { lineMoveRight(&l); continue; } // RIGHT case 'D': { lineMoveLeft(&l); continue; } // LEFT case 'F': { lineMoveEnd(&l); continue; } // END @@ -169,8 +195,9 @@ static char *lineedit(void) { end:; r = strndup(l.s, l.sl); ret:; - free(l.s); tcrestore(); fputc('\n', stdout); return r; + tcrestore(); fputc('\n', stdout); return r; } +#undef l // h.a[h.ap] /* Handle an extended ^[ sequence */ static void lineESC(struct line *l, register int c) { @@ -181,6 +208,12 @@ static void lineESC(struct line *l, register int c) { case '3': switch ((c = fgetc(stdin))) { case '~': { lineDelete(l); break; } // DELETE } + case '5': switch ((c = fgetc(stdin))) { + case '~': { histMoveHome(&h); break; } // PAGE UP + } + case '6': switch ((c = fgetc(stdin))) { + case '~': { histMoveEnd(&h); break; } // PAGE DOWN + } } } @@ -330,10 +363,54 @@ static void lineDeleteWordEnd(struct line *l) { static void lineDeleteHome(struct line *l) { memmove(l->s, l->s + l->sp, l->sl - l->sp + 1); l->sl -= l->sp; l->sp = 0; lineRefresh(l); return; - } /* Delete characters from cursor to end */ static void lineDeleteEnd(struct line *l) { l->s[(l->sl = l->sp)] = 0; lineRefresh(l); return; } + +/* Initialise history */ +static int histInit(struct hist *h) { + h->ap = 0; h->ah = 0; h->at = 0; h->al = 0; h->ac = conf_histsize + 1; + if (!(h->a = malloc(h->ac * sizeof (*h->a)))) { return 1; } + /* TODO load history from file */ return 0; +} + +/* Free history */ +static void histFree(struct hist *h) { + for (size_t i = 0; i != h->ac; ++i) { free(h->a[i].s); } free(h->a); +} + +/* Move backwards in history */ +static void histMovePrior(struct hist *h) { + if (h->ap != h->ah) { h->ap == 0 ? h->ap = h->ac - 1 : --h->ap; } + lineRefresh(&h->a[h->ap]); return; +} + +/* Move forwards in history */ +static void histMoveNext(struct hist *h) { + register size_t an = h->ap == h->ac - 1 ? 0 : h->ap + 1; + if (an != h->at) { h->ap = an; } + lineRefresh(&h->a[h->ap]); return; +} + +/* Move to the start of history */ +static void histMoveHome(struct hist *h) { + /* TODO */ + h->ap = h->ah; lineRefresh(&h->a[h->ap]); return; +} + +/* Move to the end of history */ +static void histMoveEnd(struct hist *h) { + /* TODO */ + // h->ap = h->at; lineRefresh(&h->a[h->ap]); return; +} + +/* Push a line onto the end of history */ +static void histPush(struct hist *h, struct line l) { + if (h->al != h->ac) { ++h->al; h->ap = h->at; if (++h->at == h->ac) { h->at = 0; }} + else { h->ap = h->at; if (++h->at == h->ac) { h->at = 0; } h->ah = h->at; } + + free(h->a[h->ap].s); h->a[h->ap] = l; return; +} diff --git a/src/lineread.h b/src/lineread.h index cc5fa15..c3713d9 100644 --- a/src/lineread.h +++ b/src/lineread.h @@ -34,5 +34,6 @@ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS WITH THE SOFTWARE. #define OMKOV_ESH_LINEREAD_H_RPVXY3N7 extern char *lineread(void); +extern void linefree(void); #endif // OMKOV_ESH_LINEREAD_H_RPVXY3N7 diff --git a/src/main.c b/src/main.c index 789bdf7..f8fe7ad 100644 --- a/src/main.c +++ b/src/main.c @@ -89,7 +89,7 @@ int main(int ac, char *av[]) { (void)(ac); A0 = av[0]; } free(line); } while (_loop); - return warned; + linefree(); return warned; } static void reset(int signo) { (void)(signo);