summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--ChangeLog4
-rw-r--r--Doc/Zsh/params.yo7
-rw-r--r--Src/init.c17
-rw-r--r--Src/params.c5
-rw-r--r--Src/utils.c4
-rw-r--r--Test/D04parameter.ztst17
6 files changed, 52 insertions, 2 deletions
diff --git a/ChangeLog b/ChangeLog
index a8a05ac3d..48b79878b 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,5 +1,9 @@
2026-06-08 dana <dana@dana.is>
+ * 54676: Doc/Zsh/params.yo, Src/init.c, Src/params.c,
+ Src/utils.c, Test/D04parameter.ztst: preserve COLUMNS + LINES
+ from the environment
+
* unposted: NEWS: fix 5.9 changes header
* 54659: Completion/Zsh/Command/_alias,
diff --git a/Doc/Zsh/params.yo b/Doc/Zsh/params.yo
index 933081b34..a4dd1a2ca 100644
--- a/Doc/Zsh/params.yo
+++ b/Doc/Zsh/params.yo
@@ -1265,6 +1265,12 @@ vindex(COLUMNS)
item(tt(COLUMNS) <S>)(
The number of columns for this terminal session.
Used for printing select lists and for the line editor.
+If the shell is non-interactive and a legal value is imported from the
+environment, it is preserved. Otherwise, the value is reset on start-up
+and in response to certain events such as the receipt of a tt(SIGWINCH)
+signal. Explicitly setting it to an illegal value such as tt(0) also
+resets it. (Unsetting the parameter does not have this effect; it
+simply `hides' the value that the shell is tracking internally.)
)
vindex(CORRECT_IGNORE)
item(tt(CORRECT_IGNORE))(
@@ -1471,6 +1477,7 @@ vindex(LINES)
item(tt(LINES) <S>)(
The number of lines for this terminal session.
Used for printing select lists and for the line editor.
+See tt(COLUMNS).
)
vindex(LISTMAX)
item(tt(LISTMAX))(
diff --git a/Src/init.c b/Src/init.c
index eb34b4cab..f36bc332b 100644
--- a/Src/init.c
+++ b/Src/init.c
@@ -1288,6 +1288,23 @@ setupvals(char *cmd, char *runscript, char *zsh_name)
condtab = NULL;
wrappers = NULL;
+ zterm_columns_preserve = zterm_lines_preserve = 0;
+
+ // preserve COLUMNS and LINES from environment when non-interactive
+ if (!isset(INTERACTIVE)) {
+ char *e, *p;
+ zlong v;
+
+ if ((e = zgetenv("COLUMNS")) && (v = zstrtol(e, &p, 10)) > 0 && !*p) {
+ zterm_columns = v;
+ zterm_columns_preserve = 1;
+ }
+ if ((e = zgetenv("LINES")) && (v = zstrtol(e, &p, 10)) > 0 && !*p) {
+ zterm_lines = v;
+ zterm_lines_preserve = 1;
+ }
+ }
+
#ifdef TIOCGWINSZ
adjustwinsize(0);
#else
diff --git a/Src/params.c b/Src/params.c
index 7b55d38f2..05efd19c0 100644
--- a/Src/params.c
+++ b/Src/params.c
@@ -107,6 +107,11 @@ mod_export zlong
ppid, /* $PPID */
zsh_subshell; /* $ZSH_SUBSHELL */
+// whether COLUMNS and LINES should be preserved because they were imported from
+// the environment into a non-interactive shell
+/**/
+mod_export int zterm_columns_preserve, zterm_lines_preserve;
+
/* $FUNCNEST */
/**/
mod_export
diff --git a/Src/utils.c b/Src/utils.c
index 801dabd9b..0b4bb9a82 100644
--- a/Src/utils.c
+++ b/Src/utils.c
@@ -1837,7 +1837,7 @@ adjustlines(int signalled)
int oldlines = zterm_lines;
#ifdef TIOCGWINSZ
- if (signalled || zterm_lines <= 0)
+ if ((signalled && !zterm_lines_preserve) || zterm_lines <= 0)
zterm_lines = shttyinfo.winsize.ws_row;
else
shttyinfo.winsize.ws_row = zterm_lines;
@@ -1862,7 +1862,7 @@ adjustcolumns(int signalled)
int oldcolumns = zterm_columns;
#ifdef TIOCGWINSZ
- if (signalled || zterm_columns <= 0)
+ if ((signalled && !zterm_columns_preserve) || zterm_columns <= 0)
zterm_columns = shttyinfo.winsize.ws_col;
else
shttyinfo.winsize.ws_col = zterm_columns;
diff --git a/Test/D04parameter.ztst b/Test/D04parameter.ztst
index 6a039d483..68c4ec288 100644
--- a/Test/D04parameter.ztst
+++ b/Test/D04parameter.ztst
@@ -3008,3 +3008,20 @@ F:output ignorable as long as not an error
fi
-:ZSH_EXEPATH
*>match: /*
+
+ for 1 in '' -m; do
+ COLUMNS=47 LINES=47 $ZTST_testdir/../Src/zsh $1 -fc '
+ echo $COLUMNS $LINES
+ COLUMNS=74 LINES=74
+ echo $COLUMNS $LINES
+ command true
+ echo $COLUMNS $LINES
+ '
+ done
+-:COLUMNS and LINES preserved from environment when non-interactive
+>47 47
+>74 74
+>74 74
+>47 47
+>74 74
+>74 74