Since coreutils 9.12, env shell-quotes values written to a terminal
by default (a pty counts as one, see coreutils issue #355 for the
history: https://github.com/coreutils/coreutils/issues/355).
This makes the literal, unquoted match for TSET= in
test_ssh_env_vars no longer find the value, so the test times out
waiting for it and eventually surfaces as an EIO reading from the pty
once the child has already exited. Accept the shlex-quoted form of
the value as well, since the ssh kitten's own env-passing code does
not use env and is unaffected.
Observed failure (Fedora rawhide buildroot with coreutils-9.12-1.fc46):
======================================================================
ERROR: test_ssh_env_vars (kitty_tests.ssh.SSHKitten.test_ssh_env_vars)
----------------------------------------------------------------------
Traceback (most recent call last):
File "kitty_tests/__init__.py", line 461, in wait_till
self.process_input_from_child(timeout=end_time - time.monotonic())
File "kitty_tests/__init__.py", line 449, in process_input_from_child
data = os.read(self.master_fd, io.DEFAULT_BUFFER_SIZE)
OSError: [Errno 5] Input/output error
The above exception was the direct cause of the following exception:
Traceback (most recent call last):
File "kitty_tests/__init__.py", line 250, in wrapper
return func(*args, **kwargs)
File "kitty_tests/ssh.py", line 146, in test_ssh_env_vars
pty.wait_till(lambda: 'TSET={}'.format(tset.replace('$A', 'AAA')) in pty.screen_contents())
File "kitty_tests/__init__.py", line 464, in wait_till
raise Exception(f'Failed to read from pty with error: {e}. {self.screen_contents_for_error()}') from e
Exception: Failed to read from pty with error: [Errno 5] Input/output error. Screen contents as repr:
'...\nA=AAA\nTSET=\'AAA-$(echo no)-`echo no2` !Q5 "something else"\'\n...'
Ran 337 tests in 19.341s
FAILED (errors=1, skipped=3)
Assisted-By: Claude Sonnet 5
write_escaped_ch compares the decoded rune against utf8.RuneError to
detect invalid UTF-8, but a literal U+FFFD decodes to that same rune, so
an escaped replacement character was silently deleted. The size returned
by DecodeRuneInString already tells the two apart: invalid bytes decode
with a size of one, a real U+FFFD with a size of three. Keep the rune
when the size is greater than one.
The AVX-512 implementations in simd-string-512.c are built only for
x86-64, on other platforms they are stubs that call fatal(). However,
init_simd() enables them whenever the CPU reports AVX-512 support, which
it also does when running a 32-bit x86 build. That build then exits as
soon as it decodes any UTF-8 or draws any text.
Never select the AVX-512 implementations on platforms for which they are
not built, whether detected at runtime or requested via KITTY_SIMD=512.
CompleteExecutablesInPath excluded directories with e.IsDir(), but that is false
for a symlink pointing at a directory. Directories are executable in the
access(2) sense, so such a symlink sitting in a PATH entry passed the X_OK check
and was offered as a command. Use the existing is_dir_or_symlink_to_dir helper,
which already makes this distinction elsewhere in the file.
complete_by_mimepat called mime.TypeByExtension directly, so it saw only the
extensions the Go standard library knows about. Everything else in kitty that
needs a mime type goes through utils.GuessMimeType, which also consults the
user's mime.types, kitty's builtin types and KnownExtensions. As a result
files like foo.py or foo.toml were not offered when completing arguments that
ask for text/*, even though kitten pager opens them as text.
Fixes found while reviewing #10471:
- A window squeezed to zero size (by maximize or an extreme bias) was
indistinguishable from a removed one, so closing an unrelated window
handed its share to windows in sub-trees that lost nothing. Track
survivors separately from the numeric weight.
- Pruning a batch of windows gave a different layout than closing them
one by one, since a perpendicular sub-tree stops being perpendicular
once removals collapse it. Apply the policy one window at a time.
- Windows reconciled by do_layout(), rather than split off an existing
window, bypassed the policy entirely. Route them through it too.
Also fix two pre-existing bugs on the same code paths:
- collapse_redundant_pairs() collapsed top down, so a pair whose
children only became empty during the recursion was never
re-examined and was left in the tree, consuming its share of the
space.
- do_layout() kept using a stale pairs root when removing windows
collapsed the tree, so windows added in the same relayout were
attached to the discarded root and vanished for a frame.
Completion patterns are lowercased in make_completer and file names are
lowercased before being matched against them, but the names of files inside
a directory were passed to the matcher unchanged. A directory whose only
matching file was named something like B.CONF was therefore never offered as
a completion candidate for a *.conf pattern, while the same file named
b.conf worked.
These two code points have Grapheme_Cluster_Break=SpacingMark but a
width of one, the only such code points in Unicode. Grapheme
segmentation (GB9a) adds them to the previous cell, so "จำ" occupied a
single cell in kitty while wcwidth() based programs count two. As a
result the SARA AA glyph was clipped, only the nikhahit was visible and
the cursor drifted right by one cell per AM.
Now, when such a code point combines into a plain one cell wide cell,
the cell is widened to two cells, using the same mechanism as U+FE0F
does for narrow emoji. The C and Go wcswidth() implementations are
updated to match so that kitty's own width calculations agree with the
screen.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>