diff --git a/examples/unbourne.c b/examples/unbourne.c index c92773ee2..a75b15bf2 100644 --- a/examples/unbourne.c +++ b/examples/unbourne.c @@ -5725,13 +5725,12 @@ static void ShellCompletion(const char *p, linenoiseCompletions *c) { } } -static char *ShellHint(const char *p, int *color, int *bold) { +static char *ShellHint(const char *p, const char **ansi1, const char **ansi2) { char *h = 0; linenoiseCompletions c = {0}; ShellCompletion(p, &c); if (c.len == 1) { h = strdup(c.cvec[0] + strlen(p)); - *bold = 2; } linenoiseFreeCompletions(&c); return h; diff --git a/libc/sock/select-nt.c b/libc/sock/select-nt.c index ba21cd6d6..4f358db43 100644 --- a/libc/sock/select-nt.c +++ b/libc/sock/select-nt.c @@ -23,6 +23,7 @@ #include "libc/nt/winsock.h" #include "libc/sock/internal.h" #include "libc/sock/yoink.inc" +#include "libc/sysv/errfuns.h" static int GetFdsPopcnt(int nfds, fd_set *fds) { int i, n = 0; @@ -92,22 +93,38 @@ static struct NtTimeval *TimevalToNtTimeval(struct timeval *tv, } } -int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds, fd_set *exceptfds, - struct timeval *timeout) { +int sys_select_nt(int nfds, fd_set *readfds, fd_set *writefds, + fd_set *exceptfds, struct timeval *timeout) { int n, rc; + struct timespec req, rem; struct NtTimeval nttimeout, *nttimeoutp; struct NtFdSet *ntreadfds, *ntwritefds, *ntexceptfds; - nfds = MIN(ARRAYLEN(readfds->fds_bits), ROUNDUP(nfds, 8)) >> 3; - ntreadfds = FdSetToNtFdSet(nfds, readfds); - ntwritefds = FdSetToNtFdSet(nfds, writefds); - ntexceptfds = FdSetToNtFdSet(nfds, exceptfds); - nttimeoutp = TimevalToNtTimeval(timeout, &nttimeout); - rc = __sys_select_nt(0, ntreadfds, ntwritefds, ntexceptfds, nttimeoutp); - NtFdSetToFdSet(nfds, readfds, ntreadfds); - NtFdSetToFdSet(nfds, writefds, ntwritefds); - NtFdSetToFdSet(nfds, exceptfds, ntexceptfds); - free(ntreadfds); - free(ntwritefds); - free(ntexceptfds); + if (readfds || writefds || exceptfds) { + nfds = MIN(ARRAYLEN(readfds->fds_bits), ROUNDUP(nfds, 8)) >> 3; + ntreadfds = FdSetToNtFdSet(nfds, readfds); + ntwritefds = FdSetToNtFdSet(nfds, writefds); + ntexceptfds = FdSetToNtFdSet(nfds, exceptfds); + nttimeoutp = TimevalToNtTimeval(timeout, &nttimeout); + if ((rc = __sys_select_nt(0, ntreadfds, ntwritefds, ntexceptfds, + nttimeoutp)) != -1) { + NtFdSetToFdSet(nfds, readfds, ntreadfds); + NtFdSetToFdSet(nfds, writefds, ntwritefds); + NtFdSetToFdSet(nfds, exceptfds, ntexceptfds); + } else { + __winsockerr(); + } + free(ntreadfds); + free(ntwritefds); + free(ntexceptfds); + } else if (timeout) { + req.tv_sec = timeout->tv_sec; + req.tv_nsec = timeout->tv_usec * 1000; + if ((rc = sys_nanosleep_nt(&req, &rem)) != -1) { + timeout->tv_sec = rem.tv_sec; + timeout->tv_usec = rem.tv_nsec / 1000; + } + } else { + rc = einval(); + } return rc; } diff --git a/test/libc/sock/select_test.c b/test/libc/sock/select_test.c new file mode 100644 index 000000000..6e4721ee3 --- /dev/null +++ b/test/libc/sock/select_test.c @@ -0,0 +1,43 @@ +/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-│ +│vi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8 :vi│ +╞══════════════════════════════════════════════════════════════════════════════╡ +│ Copyright 2021 Justine Alexandra Roberts Tunney │ +│ │ +│ Permission to use, copy, modify, and/or distribute this software for │ +│ any purpose with or without fee is hereby granted, provided that the │ +│ above copyright notice and this permission notice appear in all copies. │ +│ │ +│ THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL │ +│ WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED │ +│ WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE │ +│ AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL │ +│ DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR │ +│ PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER │ +│ TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR │ +│ PERFORMANCE OF THIS SOFTWARE. │ +╚─────────────────────────────────────────────────────────────────────────────*/ +#include "libc/calls/struct/timeval.h" +#include "libc/sock/select.h" +#include "libc/sock/sock.h" +#include "libc/testlib/testlib.h" +#include "libc/time/time.h" + +TEST(select, allZero) { + /* blocks indefinitely not worth supporting */ + /* EXPECT_SYS(0, 0, select(0, 0, 0, 0, 0)); */ +} + +TEST(select, testSleep) { + int64_t e; + long double n; + struct timeval t = {0, 2000}; + n = nowl(); + EXPECT_SYS(0, 0, select(0, 0, 0, 0, &t)); + e = (nowl() - n) * 1e6; + EXPECT_GT(e, 1000); + if (!IsBsd()) { + /* maybe we should polyfill */ + EXPECT_EQ(0, t.tv_sec); + EXPECT_EQ(0, t.tv_usec); + } +} diff --git a/third_party/linenoise/linenoise.c b/third_party/linenoise/linenoise.c index 452d98651..5d970a955 100644 --- a/third_party/linenoise/linenoise.c +++ b/third_party/linenoise/linenoise.c @@ -59,6 +59,27 @@ │ - Ctrl+R search │ │ - Thompson-Pike Encoding │ │ │ +│ SHORTCUTS │ +│ │ +│ CTRL-L CLEAR SCREEN │ +│ CTRL-N NEXT HISTORY │ +│ CTRL-P PREVIOUS HISTORY │ +│ CTRL-F FORWARD CHAR │ +│ CTRL-B BACKWARD CHAR │ +│ CTRL-A BEGINNING OF LINE │ +│ CTRL-E END OF LINE │ +│ ALT-F FORWARD WORD │ +│ ALT-B BACKWARD WORD │ +│ CTRL-H DELETE CHAR BACKWARDS │ +│ CTRL-ALT-H DELETE WORD BACKWARDS │ +│ ALT-H DELETE WORD BACKWARDS │ +│ CTRL-W DELETE WORD BACKWARDS │ +│ CTRL-D DELETE CHAR FORWARDS │ +│ ALT-D DELETE WORD FORWARDS │ +│ CTRL-T TRANSPOSE CHARS │ +│ CTRL-K DELETE LINE FORWARDS │ +│ CTRL-U DELETE LINE BACKWARDS │ +│ │ │ REFERENCE │ │ │ │ The big scary coding you 𝘮𝘶𝘴𝘵 use curses to abstract. │ @@ -533,25 +554,14 @@ static void abFree(struct abuf *ab) { /* Helper of refreshSingleLine() and refreshMultiLine() to show hints * to the right of the prompt. */ static void refreshShowHints(struct abuf *ab, struct linenoiseState *l, int plen) { - char seq[26], *p; if (hintsCallback && plen+l->len < l->cols) { - int color = 0, bold = 0; - char *hint = hintsCallback(l->buf,&color,&bold); + const char *ansi1 = "\e[90m"; + const char *ansi2 = "\e[39m"; + char *hint = hintsCallback(l->buf,&ansi1,&ansi2); if (hint) { - int hintlen = strlen(hint); - int hintmaxlen = l->cols-(plen+l->len); - if (hintlen > hintmaxlen) hintlen = hintmaxlen; - if (bold && !color) color = 37; - if (color || bold) { - p=stpcpy(seq,"\e["); - p+=int64toarray_radix10(bold&255,p),*p++=';'; - p+=int64toarray_radix10(color&255,p); - p=stpcpy(p,";49m"); - abAppend(ab,seq,p-seq); - } - abAppend(ab,hint,hintlen); - if (color != -1 || bold) - abAppend(ab,"\e[0m",4); + if (ansi1) abAppend(ab,ansi1,strlen(ansi1)); + abAppend(ab,hint,MIN(l->cols-(plen+l->len),strlen(hint))); + if (ansi2) abAppend(ab,ansi2,strlen(ansi2)); /* Call the function to free the hint returned. */ if (freeHintsCallback) { freeHintsCallback(hint); @@ -1061,6 +1071,9 @@ static int linenoiseEdit(int stdin_fd, int stdout_fd, char *buf, size_t buflen, case 'd': /* "\ed" is alt-d */ linenoiseEditDeleteNextWord(&l); break; + case 'h': /* "\e" is alt-h */ + linenoiseEditDeletePrevWord(&l); + break; case CTRL('H'): /* "\e\b" is ctrl-alt-h */ linenoiseEditDeletePrevWord(&l); break; diff --git a/third_party/linenoise/linenoise.h b/third_party/linenoise/linenoise.h index 1b78c5a57..31310cd44 100644 --- a/third_party/linenoise/linenoise.h +++ b/third_party/linenoise/linenoise.h @@ -9,7 +9,8 @@ typedef struct linenoiseCompletions { } linenoiseCompletions; typedef void(linenoiseCompletionCallback)(const char *, linenoiseCompletions *); -typedef char *(linenoiseHintsCallback)(const char *, int *, int *); +typedef char *(linenoiseHintsCallback)(const char *, const char **, + const char **); typedef void(linenoiseFreeHintsCallback)(void *); void linenoiseSetCompletionCallback(linenoiseCompletionCallback *); diff --git a/third_party/python/Programs/python.c b/third_party/python/Programs/python.c index 4462630a2..bb9b3d7b7 100644 --- a/third_party/python/Programs/python.c +++ b/third_party/python/Programs/python.c @@ -778,14 +778,13 @@ TerminalCompletion(const char *p, linenoiseCompletions *c) } static char * -TerminalHint(const char *p, int *color, int *bold) +TerminalHint(const char *p, const char **ansi1, const char **ansi2) { char *h = 0; linenoiseCompletions c = {0}; TerminalCompletion(p, &c); if (c.len == 1) { h = strdup(c.cvec[0] + strlen(p)); - *bold = 2; } linenoiseFreeCompletions(&c); return h;