The SIGUSR1 -> editor_emergency_kill wiring was a contrived escape
hatch. A console user with a stuck editor reaches for kill / pkill /
SIGKILL on the editor, not undocumented signals on the chat client.
editor_emergency_kill() stays for the internal Ctrl-Z abort path.
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.
The synchronous `get_message_from_editor` blocked the main loop (`prof_run`) while launching an external editor like `vim`, halting network I/O in `session_process_events` and preventing incoming message reception.
Introduced `get_message_from_editor_async` for `cmd_editor` to run the editor asynchronously. It forks and execs the editor in a thread (`editor_thread`), suspending NCurses to free the terminal. The main loop skips `inp_readline` and `ui_update` via a new `background_mode` flag while the editor runs, allowing `session_process_events` to keep the connection alive.
On editor completion, `editor_process` (called per loop iteration) resumes NCurses with `ui_resize`, inserts the result into the readline buffer and clears `background_mode`.
Retained synchronous `get_message_from_editor` for ~20 existing code paths (e.g., `vcard_nickname`) to avoid breaking them.
Tested with `vim` and `nano`: confirms no rendering conflicts, messages received during editing, and seamless resume. Edge cases like editor crashes handled via error logging and seamless resume.