@@ -8,6 +8,82 @@ shows you how to drive the shell.
88
99---
1010
11+ ## v2.9.0 — * the plugin release*
12+
13+ ` man bash ` killed the shell. Not an edge case anyone contrived: a stock
14+ install with the default plugins on, the first time you read a manual
15+ page. oh-my-zsh's colored-man-pages wraps ` man ` in a function that builds
16+ an environment array — ` environment+=( PAGER="${commands[less]:-$PAGER}" ) `
17+ — and hellish took a SIGSEGV on the array element, took the interactive
18+ shell down with it, and left the user at exit 139.
19+
20+ The plugin was innocent, and so was zsh. The bug was that
21+ ` reparse_assignment_words ` promotes ** every** word shaped like
22+ ` NAME=value ` to an assignment node, wherever it stands, but only a simple
23+ command's own children were ever converted back to plain words. A word in
24+ a ` for ` list or inside an array literal therefore reached ` split_words `
25+ still shaped as an assignment — a node whose second child is another word,
26+ where the splitter asserts every child is a token. ` for x in A=1 ` ,
27+ ` e=( A=1 ) ` and ` arr+=( K=$v ) ` all crashed, in both dialects, on both
28+ allocators, for as long as array literals have split like bash.
29+
30+ - ** An assignment-shaped word outside command position is a plain word** ,
31+ which is what bash has always made of it: ` for x in A=$V ` splits and
32+ globs like any other word. One helper, ` clone_as_word ` , flattens the
33+ node on the way into the three read-only expansion drivers, and the
34+ fast path no longer reaches inside a node it cannot read.
35+ - ** ` A=1 e=( B=$A ) ` sees ` A ` .** Array elements now expand with the
36+ command's earlier pre-assignments temporarily applied, exactly as the
37+ scalar path already did; before, they read the old environment and
38+ stored ` B= ` .
39+ - ** ` cd -q ` works in the zsh dialect.** It is zsh's flag for moving
40+ without firing the chpwd hooks, and extract — also on by default — runs
41+ ` builtin cd -q ` four times, including the one that returns you to the
42+ directory you started in. Every archive it opened printed
43+ ` cd: -q: invalid option ` . It stays rejected in bash mode, because bash
44+ rejects it and the golden suite exists to say so.
45+
46+ ### The gap that let it ship
47+
48+ The plugin corpus said colored-man-pages was fine, and it was right: the
49+ file * loaded* , silently, defining its four functions. Nothing ever
50+ ** ran** what it defined. Sourcing a wrapper is not calling it, and the
51+ whole point of that plugin is the ` man ` you type afterwards.
52+
53+ - ` tests/assign_shaped_words ` : 46 bash-diffed cases — for-lists, array
54+ literals, append, quoting, globs, tildes, command substitution,
55+ ` local -a ` , ` declare -a ` , pre-assignment visibility, and the exact
56+ idiom the plugin uses.
57+ - ` tests/hxp_framework_test.py ` : the configuration a user actually ends
58+ up with, not one file at a time. It installs the framework into a
59+ throwaway ` HOME ` (from a checkout, an installed ` ~/.hellish ` , or a
60+ cached tarball — and skips out loud when it has none), loads it, runs
61+ its own suite, answers every management command, then ** uses** what the
62+ plugins define. It fails on the old binary with SIGSEGV, four ways.
63+ - The plugin corpus grew an exercise step: a row may now name one command
64+ that goes through the code the plugin left behind, skipped by name when
65+ the external it needs is missing rather than passing in silence.
66+ - ` cd -q ` is covered on both sides: the bash-mode rejection in the golden
67+ suite, the zsh behaviour (including that ` -q ` suppresses chpwd while a
68+ plain ` cd ` does not) against a real zsh in ` make cd-zsh-test ` .
69+ - ` make hxp-test ` runs the framework gate on its own; `make
70+ plugin-corpus` and CI run it on both the release and the ASan build.
71+
72+ ### Also here
73+
74+ - The dead ` incs/sh_state.h ` is gone: a second, 22-field ` t_shell ` that
75+ nothing had included for a long time, and that a reader could easily
76+ mistake for the real one in ` incs/shell.h ` .
77+ - Five module READMEs (` builtins ` , ` core ` , ` environment ` , ` helpers ` ,
78+ ` lexer ` ) match the code again. They still called the project sh42,
79+ listed seven builtins where the table registers around seventy, claimed
80+ ` env ` was one, quoted the obsolete struct, and named functions
81+ (` execute_ast ` , ` xgetpid ` , ` longest_matching_str ` ) that no longer
82+ exist. ` helpers ` said nothing at all about the parse arena or the word
83+ slab, which is most of what that directory is.
84+
85+ ---
86+
1187## v2.8.10 — * the wait release*
1288
1389The arm64 rung kept failing one golden case after 2.8.9's process-group
0 commit comments