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.
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>
Port the fix from 2093fb131 in the C shlex implementation to the Go one.
Previously an argument such as "" or '' was silently dropped, since an
empty word was also used to signal EOF. So "launch --title '' vim" in the
kitty shell was parsed as "launch --title vim". EOF is now signalled with
a negative Pos.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MA8JGs7pCoXFL2W6jEJ8sD
SplitForCompletion computed the position of the new empty word as if
the previous word were one byte long, so tab completing after a space
following a multi-character word replaced part of that word. For example,
completing "launch --type " in the kitten @ shell produced
"launch --window ". The new word starts at the end of the input.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01MA8JGs7pCoXFL2W6jEJ8sD
Reconcile the three ported kittens with 529 upstream commits. Only conflicts
were in the shrunk resize_window/broadcast/remote_file main.py stubs (upstream
reformatted their OPTIONS strings); resolved by keeping upstream's formatting
plus the Go-port stubs (shrunk main, remote_file handle_result shim, dropped
-h alias). Go build + kitten tests pass; dev build regenerates CLI cleanly;
Python suite at baseline (1 pre-existing unrelated failure).
Adds kittens/remote_file/main.go (ask menu, hostname-mismatch prompt,
save-path prompt with tab completion, edit/open/save actions) on top of the
ControlMaster/ssh helpers from the previous two commits, registers it in
tools/cmd/tool/main.go, and adds remote_file to shell-integration/ssh/kitty's
wrapped_kittens list so both `kitty +kitten remote_file` and ssh-session
invocations exec the Go binary directly. main.py is shrunk to option_text
(kept importable by kitty/cli_stub.py and used for --doc/--help generation),
is_ssh_kitten_sentinel (kept importable by kitty/window.py), and the
handle_result shim boss.py runs in-process to open the returned file.
Also drops the dead `-h` alias on --hostname: Python's CLI layer always
special-cases -h/--help ahead of user options, so it never worked as a
hostname shorthand, but the Go CLI layer hard-errors on the collision; removing
it is a no-op for existing behavior (boss.py only ever passes --hostname) and
unblocks `kitten remote-file --help`. Also adds the same reset_terminal()
calls Python makes between UI phases (ask menu -> action, hostname-mismatch
prompt, overwrite prompt, $EDITOR handoff) so the Go and Python screens match.
Manually verified parity against Python (ask menu, cancel, open/edit/save
download+upload round-trips, hostname-mismatch Y/N, save-path prompt and
overwrite O/A/R/N) using a fake-ssh test double, and confirmed post-wrap that
`kitty +kitten remote_file` execs the Go kitten binary.
Add a benchmark stream containing 262,144 distinct base-plus-combining-mark cells per repetition so TextCache collection cost remains visible instead of collapsing into cache hits.
Co-Authored-By: Claude <noreply@anthropic.com>
- Python (kitty/launch.py): Track editor PID via monitor_pid to capture
exit code when editor window closes. Send exit code as data in the DONE
message instead of sending no data.
- Go (tools/cmd/edit_in_kitty/main.go): Parse exit code from DONE message
data and use lp.Quit(exit_code) to exit with the editor's exit code.
- Go (tools/cmd/tool/confirm_and_run_shebang.go): Check exit code when
running edit-in-kitty as a subprocess; abort execution on editor failure.
Change the graphics protocol N key from a boolean into a usage-hints
bitmask. Define the first bit as a transient hint, allowing the terminal
to treat the image data as short-lived and apply optimizations such as
skipping disk cache writes.
Propagate the transient hint through frame coalescing and composition, so
a composed frame is transient if any contributing frame is transient.
- Merge TestWatchForConfigChangesIncludeAdded and
TestWatchForConfigChangesIncludeRemoved into the main
TestWatchForConfigChanges function, which now starts the watcher
once and shares it across all integration subtests.
- Add prime_watcher helper that retries writes until an action fires,
replacing the blind time.Sleep(200ms) watcher-startup wait.
- Add new subtest "include added to already-included file adds its
parent dir": writes an include directive into sub/included.conf
(itself included from kitty.conf), then verifies that changes to
the newly referenced file trigger the action, confirming its parent
directory was added to the watch set.
- Fix TestWatchForConfigChangesDebounce to use prime_watcher instead
of time.Sleep for startup; capture before_burst baseline before the
burst loop so the burst-action count is computed correctly.
Add a new graphics protocol key, N=1, to request that transmitted
image/frame data is kept only in memory and not written to the graphics
disk cache file.
This is useful for transient high-frequency updates such as video-like
streams, where the latest frame is the only useful data and persisting
each frame to the disk cache causes unnecessary write traffic.
The implementation keeps the existing graphics cache abstraction intact:
memory-only entries can still be read back by animation, composition, and
frame coalescing paths. Only persistence to the disk cache file is skipped.
The default behavior is unchanged when N is omitted or set to zero.
When kitten --help is run in a terminal and less is not available,
ShowHelpInPager silently discards the error from pager.Run(), resulting
in no output and a zero exit code. Fall back to writing help text
directly to stdout when the pager fails, matching the behavior of the
Python equivalent in kitty/cli.py which catches FileNotFoundError and
prints the text as a fallback.
Signed-off-by: Xuyiyang23333 <xuyiyang23333@gmail.com>