fix(editor): follow live terminal size in external editor
All checks were successful
CI Code / Check spelling (pull_request) Successful in 14s
CI Code / Check coding style (pull_request) Successful in 23s
CI Code / Code Coverage (pull_request) Successful in 3m26s
CI Code / Linux (debian) (pull_request) Successful in 5m19s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m23s
CI Code / Linux (arch) (pull_request) Successful in 7m17s
All checks were successful
CI Code / Check spelling (pull_request) Successful in 14s
CI Code / Check coding style (pull_request) Successful in 23s
CI Code / Code Coverage (pull_request) Successful in 3m26s
CI Code / Linux (debian) (pull_request) Successful in 5m19s
CI Code / Linux (ubuntu) (pull_request) Successful in 5m23s
CI Code / Linux (arch) (pull_request) Successful in 7m17s
The compose editor is spawned via fork+execvp and inherits profanity's LINES/COLUMNS, which hold the size captured at startup and are never refreshed on resize. A curses editor (nano, vim, ...) honors them over the real window, so it renders at the launch-time size after a resize. Drop LINES/COLUMNS from the child's environment before forking so its curses falls back to ioctl(TIOCGWINSZ). Assembling the env in the parent lets the child only reassign environ instead of calling unsetenv() between fork and exec, keeping it clear of unsetenv()'s allocator work in the multithreaded fork->exec window. profanity itself is unaffected.
This commit is contained in:
@@ -25,6 +25,8 @@
|
||||
#include "ui/ui.h"
|
||||
#include "xmpp/xmpp.h"
|
||||
|
||||
extern char** environ;
|
||||
|
||||
typedef struct EditorContext
|
||||
{
|
||||
gchar* filename;
|
||||
@@ -140,6 +142,22 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
|
||||
GSource* sigchld_warmup = g_child_watch_source_new(getpid());
|
||||
g_source_unref(sigchld_warmup);
|
||||
|
||||
// Build the editor's env without LINES/COLUMNS pre-fork, so the child only
|
||||
// reassigns environ instead of calling unsetenv() between fork and exec.
|
||||
// The editor's (n)curses then reads the live window via ioctl(TIOCGWINSZ).
|
||||
gsize env_len = 0;
|
||||
while (environ[env_len]) {
|
||||
env_len++;
|
||||
}
|
||||
gchar** editor_env = g_new0(gchar*, env_len + 1);
|
||||
gsize env_kept = 0;
|
||||
for (gsize i = 0; i < env_len; i++) {
|
||||
if (g_str_has_prefix(environ[i], "LINES=") || g_str_has_prefix(environ[i], "COLUMNS=")) {
|
||||
continue;
|
||||
}
|
||||
editor_env[env_kept++] = environ[i];
|
||||
}
|
||||
|
||||
pid_t pid = fork();
|
||||
if (pid == -1) {
|
||||
log_error("[Editor] Failed to fork: %s", strerror(errno));
|
||||
@@ -148,12 +166,15 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
|
||||
ui_resize();
|
||||
cons_show_error("Failed to start editor: %s", strerror(errno));
|
||||
g_strfreev(editor_argv);
|
||||
g_free(editor_env); // array only; strings are borrowed from environ
|
||||
g_free(ctx->filename);
|
||||
g_free(ctx);
|
||||
return TRUE;
|
||||
} else if (pid == 0) {
|
||||
// Child process: Inherits TTY from parent
|
||||
|
||||
environ = editor_env; // live TIOCGWINSZ size, not the inherited LINES/COLUMNS
|
||||
|
||||
// SIGTSTP=SIG_DFL lets vim's :stop / Ctrl-Z work; profanity catches
|
||||
// the STOPPED state via editor_check_stopped() and drops to the shell.
|
||||
signal(SIGINT, SIG_DFL);
|
||||
@@ -170,6 +191,7 @@ launch_editor(gchar* initial_content, void (*callback)(gchar* content, void* dat
|
||||
editor_pid = pid;
|
||||
g_child_watch_add((GPid)pid, _editor_exit_cb, ctx);
|
||||
g_strfreev(editor_argv);
|
||||
g_free(editor_env); // frees the parent's array only; the child keeps its own COW copy until execvp
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user