fix(editor): Ctrl-Z aborts editor and returns to profanity
Some checks failed
CI Code / Check spelling (pull_request) Successful in 16s
CI Code / Check coding style (pull_request) Failing after 34s
CI Code / Code Coverage (pull_request) Successful in 3m1s
CI Code / Linux (debian) (pull_request) Successful in 4m43s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m55s
CI Code / Linux (arch) (pull_request) Successful in 6m55s
Some checks failed
CI Code / Check spelling (pull_request) Successful in 16s
CI Code / Check coding style (pull_request) Failing after 34s
CI Code / Code Coverage (pull_request) Successful in 3m1s
CI Code / Linux (debian) (pull_request) Successful in 4m43s
CI Code / Linux (ubuntu) (pull_request) Successful in 4m55s
CI Code / Linux (arch) (pull_request) Successful in 6m55s
Replaces the SIGTSTP=SIG_IGN inheritance approach (was commit 8) with a detect-and-abort design that matches user expectation: Ctrl-Z inside the editor brings you back to profanity instead of leaving the session suspended. - src/tools/editor.c: SIGTSTP reset back to SIG_DFL in the child so vim's :stop / Ctrl-Z actually stop the editor (revert previous SIG_IGN inheritance). - src/tools/editor.c: new editor_check_stopped() — non-reaping waitpid poll for WIFSTOPPED. Lets prof_run detect Ctrl-Z / :stop / gdb-attach on the editor child. - src/tools/editor.c: editor_emergency_kill() now sends SIGCONT before SIGTERM so the abort works on a STOPPED child too. - src/tools/editor.c: _editor_exit_cb handles WIFSIGNALED cleanly with "Editor session cancelled." instead of printing garbage via WEXITSTATUS on a signaled child. - src/profanity.c: SIGTSTP / SIGCONT signal handlers set flags consumed by the main loop. Editor STOPPED -> editor_emergency_kill (returns to the chat with the pre-alt+c readline buffer intact). Plain Ctrl-Z with no editor -> mutt-style drop the process group to the shell. SIGCONT -> refresh curses with clearok + ui_resize. While editor is active, swallow suspend_requested (race: vim's kill(0,SIGTSTP) beats waitpid seeing STOPPED — next poll catches it). - src/tools/editor.h: declare editor_check_stopped and editor_is_active. Verbose comment blocks across the branch tightened to one to two lines.
This commit is contained in:
@@ -20,6 +20,7 @@
|
||||
#include <string.h>
|
||||
|
||||
#include <glib.h>
|
||||
#include <glib-unix.h>
|
||||
|
||||
#include "profanity.h"
|
||||
#include "common.h"
|
||||
@@ -70,6 +71,12 @@ static void _connect_default(const char* const account);
|
||||
pthread_mutex_t lock;
|
||||
static gboolean force_quit = FALSE;
|
||||
|
||||
// Signal-driven flags consumed by the main loop. SIGTSTP and a STOPPED editor
|
||||
// child → drop the process group to the shell (mutt-style). SIGCONT →
|
||||
// refresh curses on return.
|
||||
static volatile sig_atomic_t suspend_requested = FALSE;
|
||||
static volatile sig_atomic_t cont_requested = FALSE;
|
||||
|
||||
void
|
||||
prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_file, gchar* theme_name, gchar** commands)
|
||||
{
|
||||
@@ -93,6 +100,36 @@ prof_run(gchar* log_level, gchar* account_name, gchar* config_file, gchar* log_f
|
||||
int waittime = 0;
|
||||
while (cont && !force_quit) {
|
||||
log_stderr_handler();
|
||||
|
||||
// Resume from fg after SIGSTOP. Vim handles its own refresh.
|
||||
if (cont_requested) {
|
||||
cont_requested = FALSE;
|
||||
if (!editor_is_active()) {
|
||||
clearok(stdscr, TRUE);
|
||||
ui_resize();
|
||||
}
|
||||
}
|
||||
|
||||
// Editor STOPPED → abort. Plain Ctrl-Z → drop to shell. While editor
|
||||
// is active, swallow suspend_requested (race: vim's kill(0,SIGTSTP)
|
||||
// beats waitpid seeing STOPPED) — next poll catches it.
|
||||
if (editor_check_stopped()) {
|
||||
log_info("[Editor] stopped; aborting back to profanity");
|
||||
suspend_requested = FALSE;
|
||||
editor_emergency_kill();
|
||||
} else if (suspend_requested) {
|
||||
suspend_requested = FALSE;
|
||||
if (editor_is_active()) {
|
||||
log_info("[Editor] SIGTSTP from vim group; deferring to next poll");
|
||||
} else {
|
||||
log_info("[Suspend] dropping to shell");
|
||||
if (!isendwin()) {
|
||||
endwin();
|
||||
}
|
||||
kill(0, SIGSTOP);
|
||||
}
|
||||
}
|
||||
|
||||
session_check_autoaway();
|
||||
|
||||
line = commands ? *commands : inp_readline();
|
||||
@@ -182,6 +219,27 @@ sigterm_handler(int sig)
|
||||
force_quit = TRUE;
|
||||
}
|
||||
|
||||
// SIGUSR1 escape for an alive-but-stuck editor (WUNTRACED can't catch it).
|
||||
// Dispatched in the main loop. Trigger: `pkill -USR1 profanity`.
|
||||
static gboolean
|
||||
_emergency_resume_handler(gpointer data)
|
||||
{
|
||||
editor_emergency_kill();
|
||||
return G_SOURCE_CONTINUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sigtstp_handler(int sig)
|
||||
{
|
||||
suspend_requested = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
sigcont_handler(int sig)
|
||||
{
|
||||
cont_requested = TRUE;
|
||||
}
|
||||
|
||||
static void
|
||||
_init(char* log_level, char* config_file, char* log_file, char* theme_name)
|
||||
{
|
||||
@@ -189,10 +247,12 @@ _init(char* log_level, char* config_file, char* log_file, char* theme_name)
|
||||
// ignore SIGPIPE
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
signal(SIGINT, SIG_IGN);
|
||||
signal(SIGTSTP, SIG_IGN);
|
||||
signal(SIGTSTP, sigtstp_handler);
|
||||
signal(SIGCONT, sigcont_handler);
|
||||
signal(SIGWINCH, ui_sigwinch_handler);
|
||||
signal(SIGTERM, sigterm_handler);
|
||||
signal(SIGHUP, sigterm_handler);
|
||||
g_unix_signal_add(SIGUSR1, _emergency_resume_handler, NULL);
|
||||
if (pthread_mutex_init(&lock, NULL) != 0) {
|
||||
log_error("Mutex init failed");
|
||||
exit(1);
|
||||
|
||||
Reference in New Issue
Block a user