fix Ctrl-C swallowing the next line

readline only redraws the prompt on Ctrl-C: the half-typed text
stays in its buffer and the interrupt flag outlives the prompt,
so the line typed next was silently discarded. Register a signal
event hook that empties the line, the way bash does, and clear
the flag around readline instead of eating the line: a Ctrl-C
during a command still aborts the turn, and one during a
multi-line task still abandons it. Two pty-based regression
tests cover the idle-prompt and mid-line cases.
This commit is contained in:
Luxferre
2026-10-04 21:32:50 +03:00
parent 141c6cc414
commit fdd389e452
3 changed files with 84 additions and 6 deletions
+13 -1
View File
@@ -42,6 +42,16 @@ static int GN(json_object *o, const char *k, int d) { json_object *v = G(o, k);
static volatile sig_atomic_t IN;
static void onint(int s) { (void)s; IN = 1; }
/* readline calls this from its input loop, in a safe context, after it has
dealt with a signal caught while it was reading a line. A Ctrl-C only
redraws the prompt: the half-typed text stays in the buffer, so clear it
here, the way bash does. The flag is left set on purpose; the prompt loop
clears it, so a Ctrl-C during a command still aborts the turn, and one
during a multi-line task still abandons it. */
static int ci_hook(void) {
if(IN) { rl_replace_line("", 1); rl_redisplay(); }
return 0;
}
static char *EP, *KEY, *MOD, *RSN, *SF, *TMP, *SYS, *SELF, SH[256] = "/bin/sh";
static int TO = 120, QUIT, CLR = 1;
@@ -402,6 +412,7 @@ int main(int argc, char **argv) {
if(!(e = getenv("SHELL")) || access(e, X_OK)) e = access("/bin/bash", X_OK) ? "/bin/sh" : "/bin/bash";
snprintf(SH, sizeof SH, "%s", e);
signal(SIGINT, onint); signal(SIGPIPE, SIG_IGN);
rl_signal_event_hook = ci_hook;
create(); load();
if((e = getenv("SOLO_MODEL")) && *e) { setstr(&MOD, e); A(SSN, "model", S(e)); }
if((e = getenv("SOLO_TEMP")) && *e) { TEMP = atof(e); A(SSN, "temperature", D(TEMP)); }
@@ -416,8 +427,9 @@ int main(int argc, char **argv) {
free(task);
while(!QUIT) {
snprintf(pb, sizeof pb, "\001%s\002> \001%s\002", CLR ? BLD : "", CLR ? OF : "");
IN = 0; /* a Ctrl-C during a command must not reach the line about to be typed */
if(!(ln = readline(pb))) { puts(""); break; }
if(IN) { IN = 0; free(ln); continue; }
IN = 0; /* a Ctrl-C during the line only cleared that line, not this turn */
ac = ln;
for(;;) {
size_t l = strlen(ac);