From 79d1af3202981ba30c86f868a56e1a846b6bb3bd Mon Sep 17 00:00:00 2001 From: Nathan Flurry Date: Thu, 2 Jul 2026 22:58:43 -0700 Subject: [PATCH] fix(registry): correct vim terminal rendering in wasm build - isatty delegates to host_tty (PTY fd wrongly reported not-a-tty by wasi-libc) - implement real termcap tgoto() so parameterized caps (cursor motion, scroll region) are emitted under HAVE_TGETENT instead of silently dropped - declare sigprocmask + force-include termios so a clean configure build links --- registry/native/c/vim/compat.h | 10 +++++ registry/native/c/vim/termcap_stub.c | 61 +++++++++++++++++++++++--- registry/native/c/vim/termios_bridge.c | 10 +++++ 3 files changed, 76 insertions(+), 5 deletions(-) diff --git a/registry/native/c/vim/compat.h b/registry/native/c/vim/compat.h index cdf8e9d2a..05477f040 100644 --- a/registry/native/c/vim/compat.h +++ b/registry/native/c/vim/compat.h @@ -5,6 +5,16 @@ #include #include #include +#include +/* Force termios everywhere so TIOCGWINSZ + struct winsize are visible in EVERY + * translation unit (os_unix.c's window-size query is gated on TIOCGWINSZ, which + * is only defined where is included). */ +#include + +/* wasi-libc declares no sigprocmask (no signals), but our posix_stubs.c + * implements it and configure detects it (HAVE_SIGPROCMASK) — declare it so + * os_unix.c's calls compile instead of failing with implicit-declaration. */ +int sigprocmask(int how, const sigset_t *set, sigset_t *oldset); /* waitpid flags (no sys/wait.h with these on wasi) */ #ifndef WNOHANG diff --git a/registry/native/c/vim/termcap_stub.c b/registry/native/c/vim/termcap_stub.c index c8a9dc4d2..18c894d4f 100644 --- a/registry/native/c/vim/termcap_stub.c +++ b/registry/native/c/vim/termcap_stub.c @@ -32,11 +32,62 @@ char *tgetstr(const char *id, char **area) { return (char *)0; } -char *tgoto(const char *cap, int col, int row) { - (void)cap; - (void)col; - (void)row; - return (char *)0; +/* tgoto — expand a parameterized termcap capability (cursor motion T_CM, + * scroll region T_CS, etc.). With HAVE_TGETENT defined, vim routes ALL + * parameterized caps through this external tgoto; a NULL/stub return silently + * drops the escape (so t_cm/t_cs are set but never emitted → linear draw, no + * scroll region, status line on the wrong row). This is vim's own minimal + * tgoto (src/term.c, the #ifndef HAVE_TGETENT branch): parse %i, %d, %+char, + * %%; termcap convention is tgoto(cap, destcol, destline) with %d emitting the + * LINE first, then swapping to the column. */ +char *tgoto(const char *cap, int col, int line) { + static char buf[64]; + char *s = buf; + char *e = buf + sizeof(buf) - 1; + int x = col; + int y = line; + + if (!cap) { + return "OOPS"; + } + for (; s < e && *cap; cap++) { + if (*cap != '%') { + *s++ = *cap; + continue; + } + switch (*++cap) { + case 'd': { + /* emit y as decimal, then swap so the next %d emits x */ + char num[16]; + int n = 0; + unsigned v = (unsigned)(y < 0 ? 0 : y); + do { + num[n++] = (char)('0' + v % 10); + v /= 10; + } while (v && n < (int)sizeof(num)); + while (n > 0 && s < e) { + *s++ = num[--n]; + } + y = x; + break; + } + case 'i': + x++; + y++; + break; + case '+': + *s++ = (char)(*++cap + y); + y = x; + break; + case '%': + *s++ = '%'; + break; + default: + return "OOPS"; + } + } + *s = '\0'; + return buf; } int tputs(const char *str, int affcnt, int (*putc_fn)(int)) { diff --git a/registry/native/c/vim/termios_bridge.c b/registry/native/c/vim/termios_bridge.c index feeb94057..d18e19f8f 100644 --- a/registry/native/c/vim/termios_bridge.c +++ b/registry/native/c/vim/termios_bridge.c @@ -55,6 +55,16 @@ static void ensure_shadow(void) { } } +/* isatty: delegate to the kernel's host_tty view. wasi-libc's isatty inspects + * WASI fdstat (must be CHARACTER_DEVICE with NO seek/tell rights); a PTY fd + * that carries seek/tell rights is wrongly reported as not-a-tty, so terminal + * apps (vim) print "Output is not to a terminal" and refuse full-screen mode. + * host_tty.isatty is the authoritative PTY check the kernel exposes (a strong + * symbol overriding the weak libc alias). */ +int isatty(int fd) { + return __host_tty_isatty((unsigned int)fd) ? 1 : 0; +} + int tcgetattr(int fd, struct termios *t) { (void)fd; if (!t) { errno = EFAULT; return -1; }