aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authoruser <user@clank>2026-09-02 16:24:41 +0200
committeruser <user@clank>2026-09-02 16:24:41 +0200
commitc58a875ef3bcb464cdbea72bdbd0a874b6f93729 (patch)
treef2000cae2b8ca1f110f344080dde1d70114b15ea
parentslosh --install-terminfo: the binary carries its own terminfo entry (diff)
downloadslosh-c58a875ef3bcb464cdbea72bdbd0a874b6f93729.tar.gz
slosh-c58a875ef3bcb464cdbea72bdbd0a874b6f93729.tar.xz
slosh-c58a875ef3bcb464cdbea72bdbd0a874b6f93729.zip
pty: install the terminfo entry implicitly when it is missing everywhere
The lookup miss now writes the embedded entry to ~/.terminfo and uses it, so a bare box gets the full TERM with no step at all. An entry that exists anywhere is respected -- possibly newer, certainly somebody's -- and a HOME that cannot be written leaves the xterm-256color fallback standing. --install-terminfo stays as the by-hand spelling; the writer moved to pty.c where the panes are.
-rw-r--r--docs/slosh.127
-rw-r--r--include/slosh.h4
-rw-r--r--src/main.c56
-rw-r--r--src/pty.c46
4 files changed, 71 insertions, 62 deletions
diff --git a/docs/slosh.1 b/docs/slosh.1
index cce0b64..6436f6a 100644
--- a/docs/slosh.1
+++ b/docs/slosh.1
@@ -152,12 +152,9 @@ Write the
.B xterm-ghostty
terminfo entry the binary carries into
.I ~/.terminfo
-(no root, no package), so panes on a machine without ghostty's entry
-get the full
-.B TERM
-instead of the
-.B xterm-256color
-fallback.
+(no root, no package).
+Sessions do this on their own when the entry is missing everywhere; the
+flag is the by-hand spelling, for provisioning and for saying so.
See ENVIRONMENT.
.TP
.BI \-\-server\ name
@@ -364,14 +361,16 @@ Set in every pane:
.TP
.B TERM
.B xterm-ghostty
-when the machine's terminfo database has the entry (it ships with ghostty),
-.B xterm-256color
-when it does not: an entry curses cannot find makes editors exit on
-the spot and backspace guess.
-.B slosh \-\-install\-terminfo
-puts the real entry in
-.IR ~/.terminfo ;
-new sessions then use it.
+\(en found in the machine's terminfo database, or, when it is missing
+everywhere, installed into
+.I ~/.terminfo
+from the copy the binary carries (an entry curses cannot find makes
+editors exit on the spot and backspace guess).
+Only when even that write fails (no
+.BR $HOME ,
+read-only) do panes get
+.BR xterm-256color ,
+and everything still works.
.TP
.B SLOSH
.B 1
diff --git a/include/slosh.h b/include/slosh.h
index 75aa658..47d8220 100644
--- a/include/slosh.h
+++ b/include/slosh.h
@@ -162,6 +162,10 @@ typedef struct {
/* `cell_w`/`cell_h` are the client's cell size in pixels, so the pty's
* winsize carries real pixel dimensions: a program that draws images asks the
* tty how big a cell is, and zeroes there mean it cannot size one. */
+/* Write the embedded xterm-ghostty terminfo into ~/.terminfo (0 on
+ * success). Panes do this on their own when the entry is missing
+ * everywhere; `slosh --install-terminfo` is the by-hand spelling. */
+int pty_terminfo_install(void);
int pty_spawn(pty_t *p, const char *const argv[], uint16_t cols, uint16_t rows,
const char *cwd, uint16_t cell_w, uint16_t cell_h);
int pty_resize(pty_t *p, uint16_t cols, uint16_t rows, uint16_t cell_w,
diff --git a/src/main.c b/src/main.c
index 3fdbfe6..838d6f7 100644
--- a/src/main.c
+++ b/src/main.c
@@ -26,58 +26,18 @@
#include "version.h"
#ifndef _WIN32
-#include <errno.h>
-#include <sys/stat.h>
-
-#include "terminfo.h"
-
-/* Write the embedded xterm-ghostty terminfo entry into ~/.terminfo, which
- * is the first place curses looks: no root, no package, no conflict with a
- * ghostty the machine may install later (its own entry in the system
- * database simply stops being needed). Written under every name the entry
- * answers to, in the letter layout and Darwin's hashed one, because the
- * lookup is by filename. */
+/* The write itself lives in pty.c (pty_terminfo_install), because panes do
+ * it on their own when the entry is missing everywhere. This flag is the
+ * by-hand spelling, with a report around it. */
static int install_terminfo(void) {
- const char *home = getenv("HOME");
- if (!home || !*home) {
- fputs("slosh: no $HOME to install into\n", stderr);
+ if (pty_terminfo_install() != 0) {
+ fputs("slosh: could not write ~/.terminfo (no $HOME, or not writable)\n",
+ stderr);
return 1;
}
- /* dir, then name inside it: x/ and 78/ for xterm-ghostty, g/ and 67/ for
- * the ghostty alias. */
- static const char *const spots[][2] = {
- {"x", "xterm-ghostty"},
- {"78", "xterm-ghostty"},
- {"g", "ghostty"},
- {"67", "ghostty"},
- };
- char path[1024];
- snprintf(path, sizeof path, "%s/.terminfo", home);
- if (mkdir(path, 0755) != 0 && errno != EEXIST) {
- fprintf(stderr, "slosh: mkdir %s: %s\n", path, strerror(errno));
- return 1;
- }
- for (size_t i = 0; i < sizeof spots / sizeof *spots; i++) {
- snprintf(path, sizeof path, "%s/.terminfo/%s", home, spots[i][0]);
- if (mkdir(path, 0755) != 0 && errno != EEXIST) {
- fprintf(stderr, "slosh: mkdir %s: %s\n", path, strerror(errno));
- return 1;
- }
- snprintf(path, sizeof path, "%s/.terminfo/%s/%s", home, spots[i][0],
- spots[i][1]);
- FILE *f = fopen(path, "wb");
- if (!f || fwrite(TERMINFO_GHOSTTY, 1, sizeof TERMINFO_GHOSTTY, f) !=
- sizeof TERMINFO_GHOSTTY) {
- fprintf(stderr, "slosh: write %s: %s\n", path, strerror(errno));
- if (f) fclose(f);
- return 1;
- }
- fclose(f);
- }
- printf("installed xterm-ghostty (and the ghostty alias) into %s/.terminfo\n"
+ printf("installed xterm-ghostty (and the ghostty alias) into ~/.terminfo\n"
"new sessions use it; a session already running keeps the TERM it\n"
- "chose at startup until it is restarted\n",
- home);
+ "chose at startup until it is restarted\n");
return 0;
}
#endif
diff --git a/src/pty.c b/src/pty.c
index f715acc..00fa190 100644
--- a/src/pty.c
+++ b/src/pty.c
@@ -8,6 +8,9 @@
#include "slosh.h"
#include <errno.h>
+#include <sys/stat.h>
+
+#include "terminfo.h"
#include <fcntl.h>
#include <signal.h>
#include <stdio.h>
@@ -33,6 +36,41 @@
* lookup happens where it matters: panes run on the server's machine.
*
* Computed once, in the parent, before the first fork. */
+/* Write the embedded xterm-ghostty terminfo entry into ~/.terminfo, which
+ * is the first place curses looks: no root, no package, no conflict with a
+ * ghostty the machine may install later. Written under every name the
+ * entry answers to, in the letter layout and Darwin's hashed one, because
+ * the lookup is by filename. Quiet: pty_term() below calls this on its own
+ * when the entry is nowhere to be found, and `--install-terminfo` is the
+ * same write with a friendly report around it. */
+int pty_terminfo_install(void) {
+ const char *home = getenv("HOME");
+ if (!home || !*home) return -1;
+ static const char *const spots[][2] = {
+ {"x", "xterm-ghostty"},
+ {"78", "xterm-ghostty"},
+ {"g", "ghostty"},
+ {"67", "ghostty"},
+ };
+ char path[1024];
+ snprintf(path, sizeof path, "%s/.terminfo", home);
+ if (mkdir(path, 0755) != 0 && errno != EEXIST) return -1;
+ for (size_t i = 0; i < sizeof spots / sizeof *spots; i++) {
+ snprintf(path, sizeof path, "%s/.terminfo/%s", home, spots[i][0]);
+ if (mkdir(path, 0755) != 0 && errno != EEXIST) return -1;
+ snprintf(path, sizeof path, "%s/.terminfo/%s/%s", home, spots[i][0],
+ spots[i][1]);
+ FILE *f = fopen(path, "wb");
+ if (!f || fwrite(TERMINFO_GHOSTTY, 1, sizeof TERMINFO_GHOSTTY, f) !=
+ sizeof TERMINFO_GHOSTTY) {
+ if (f) fclose(f);
+ return -1;
+ }
+ fclose(f);
+ }
+ return 0;
+}
+
static bool term_add(char *dirs, size_t cap, size_t *n, const char *d) {
if (!d || !*d) return false;
int w = snprintf(dirs + *n, cap - *n, "%s%s", *n ? ":" : "", d);
@@ -74,6 +112,14 @@ static const char *pty_term(void) {
break;
}
}
+
+ /* Nowhere at all: put our own copy in ~/.terminfo and use it. The write
+ * happens only when the entry is missing everywhere -- an entry that
+ * exists is somebody's, possibly newer than ours, and stays theirs. On a
+ * $HOME that cannot be written the fallback stands, and everything still
+ * works at xterm-256color. */
+ if (strcmp(cached, "xterm-256color") == 0 && pty_terminfo_install() == 0)
+ cached = "xterm-ghostty";
return cached;
}