screen_draw_overlay_line accessed self->linebuf->line->cpu_cells
without ever calling linebuf_init_line on the shared view. Render
paths that initialize a stack-local Line via render_line_for_virtual_y
left the view's cpu_cells as NULL (the value set by alloc_line via
PyType_GenericAlloc), and the multicell-trim loop then dereferenced
NULL + xstart * sizeof(CPUCell), producing a SIGSEGV at a small
address (e.g. 0x1e for xstart=2). The crash was reachable any time
an IME pre-edit overlay was rendered with the cursor not in column 0
on a screen whose linebuf->line had not been re-pointed by some
unrelated prior call.
Fix by initializing the view at the overlay row on entry. Add a
test_draw_overlay_line method on Screen so the behavior can be
exercised directly from a regression test.
Bug fixes in dnd.c:
- mktempdir_in_cache: add missing 'return ans' after successful strdup
- mktempdir_in_cache (utils.py): use O_RDONLY instead of O_RDWR for directories
- remote_items allocation: use mi.num_uris instead of ds.num_mimes
- Off-by-one: uri_item_idx > changed to >= for bounds checks
- Off-by-one: entry_num > changed to >= for bounds checks
- populate_dir_entries: fix missing last entry after final null separator
- add_payload directory finalization: create directory on disk with mkdirat
- get_errno_name: add EFBIG, EISDIR, ENOSPC error codes
Test infrastructure:
- Add dnd_test_force_drag_dropped() to simulate DROPPED state
- Make notify_drag_data_ready() succeed in test mode
Comprehensive t=k tests added:
- Single file, empty file, single symlink transfer
- Chunked file transfer with m=1
- Single directory with children
- Directory with symlinks
- Multiple URIs
- Deep directory trees (breadth-first and depth-first, 3+ levels)
- Mixed file/dir/symlink at top level
- Completion signal
- Error handling (client errors, invalid state)
- DoS limits (REMOTE_DRAG_LIMIT, PRESENT_DATA_CAP)
- Invalid input (bad base64, too large chunks, invalid indices/handles)
- URI list with comments
- Multiple chunks for directory listing
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/9da0bff7-6a1a-490f-a4c5-8cb328e056ce
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
Always do a roundtrip at kitten exit, except for special purpose
kittens. This slows down exit by one round trip time (capped at 2
seconds), however it ensures that we never get terminal response leak.
Fixes#9839
- dnd.c: drop_send_dir_listing now uses drop_append_request_keys (echoes
all request keys including Y for sub-dirs) and emits :X=handle instead
of :Y=handle:X=2. Directory handles are now the X value itself.
- dnd.c: drop_alloc_dir_handle starts handle counter at 1 so first
handle is 2, keeping 0 (absent) and 1 (symlink) reserved as per protocol.
- dnd.py: add is_dir_event() / dir_handle() helpers; update all tests to
use int(X) > 1 as directory indicator and X as the handle value.
- dnd.py: rename test_Y_key_in_dir_listing_response to
test_X_key_is_handle_in_dir_listing_response with updated assertions.
- dnd.py: test_uri_directory_transfer_tree expanded to verify unambiguous
identification (Y=parent, x=entry echoed) at all three directory levels.
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/6973699c-a979-4d97-8213-1a4a501044a1
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
- Remove unique identifier (device:inode) from directory listings
- Change directory entry indexing from 1-based to 0-based
- Add symlink handling in directories: respond with t=r:X=1 and target
- Update parser to default cell_y to -1 for close handle detection
- Update and extend tests for all new behaviors
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/d09883e5-f460-471d-9dcf-e64e7b96882f
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
- Add 37 new tests covering the drag source side of the DND protocol
- Test drag offer registration/unregistration (t=o, t=O)
- Test drag MIME type offering with various operations (copy/move/both)
- Test pre-sent data for valid/invalid indices, chunked data, multiple MIMEs
- Test image thumbnails: valid RGBA/RGB, invalid formats, dimensions, chunking
- Test drag start failures (no window, no offer, image size mismatches)
- Test drag cancellation from client (t=E:y=-1)
- Test offer replacement, cleanup, and error propagation
- Test client_id propagation for drag operations
- Test resource cleanup on window close during drag build
- Fix double-free in drag_free_built_data: set ds.items=NULL after free
- Add drag_free_offer to destroy_fake_window_contents for proper cleanup
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/f9868553-29a2-48c4-85c2-b6b8f686dccc
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
Add continue_word_upwards_scrollback() and continue_word_downwards_offscreen()
to extend word selection beyond viewport boundaries, mirroring the line
selection fix. Add tests for word selection wrapping into scrollback and
below viewport.
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/58191e45-d925-4996-b0d5-8b1bd4baa8d5
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
Similar to commit 625e984 which fixed extending into scrollback (above viewport),
this fix extends line selection below the viewport when a wrapped line continues
past the bottom edge. Adds continue_line_downwards_offscreen() and applies it
in both the initial selection and extending selection code paths.
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/e548ce84-fdb7-4fd1-b3df-e1166b45f5bd
Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
Users who define action_alias or kitten_alias in kitty.conf had no way
to discover or trigger these custom commands from the command palette.
Aliased keybindings were miscategorized (landing in "Miscellaneous"
with no help text), and combine bindings had the same problem.
Changes:
- Resolve aliases via opts.alias_map to get correct action names,
categories, and help text for aliased keybindings
- Add dedicated "Action aliases" and "Kitten aliases" sections that
list all user-defined aliases, with bound aliases showing their key
and unbound aliases browsable as unmapped entries
- Add a "Combined actions" section for combine keybindings
- Make alias names searchable in the Go TUI so users can find
bindings by typing the alias name
- Fix action column highlight positions to match the scored text,
preventing visual corruption when searching for alias names
Also refactors collect_keys_data into focused single-responsibility
functions and reduces nesting depth across both Python and Go.
Add --allow-fallback option to the map command that controls shifted
and ascii (alternate_key) fallback for individual key mappings.
For non-Latin keyboard layouts, when the current layout key is
non-ascii (codepoint > 127 and < 0xE000), the alternate_key from
the base layout is used for matching if the mapping opts in via
--allow-fallback=shifted,ascii.
Default kitty bindings use --allow-fallback=shifted,ascii so they
work out of the box with non-Latin layouts. User custom mappings
default to --allow-fallback=shifted (preserving existing shifted_key
behavior without ascii fallback).
--allow-fallback=none disables all fallback for a mapping.
Python side: parse_options_for_map() in options/utils.py handles flag
parsing, ShortcutMapping uses it in __init__. get_shortcut() filters
candidates by per-mapping allow_fallback.
Go side: ParseMap() handles --allow-fallback, KeyAction stores
AllowFallback, ShortcutTracker.Match passes it to matching.
MatchesParsedShortcut defaults to shifted,ascii for hardcoded shortcuts.
Migrated kittens (themes, command_palette, diff, choose_files) to
use ShortcutTracker with configurable map entries.
Tests added for Python (5 test methods) and Go (ParseMap + key matching).
The RC approach sent actions targeting the overlay window itself rather
than the underlying window. Switch to the standard kitten output pattern:
the Go kitten outputs the selected action definition via
KittenOutputSerializer, and handle_result in Python calls boss.combine()
with the correct target window after the overlay closes.
Add a Go-based command_palette kitten that provides a searchable,
interactive overlay for browsing and triggering keyboard shortcuts
and actions.
- New Go kitten at kittens/command_palette/ with FZF fuzzy search,
grouped/flat views, and remote control action triggering
- Python collect_keys_data() does data collection, passed via stdin
- Navigation: arrows, ctrl+j/k (vim), ctrl+n/p (emacs), page up/down
- Enter triggers the selected action via RC command
- Help text displayed in footer for selected binding
- Added Go tests (main_test.go) and Python tests (command_palette.py)
Note this only fixes the test, there is still the actual issue of
the selection not being rendered for the top most line if that line is
partially scrolled offscreen
Implements modern wide gamut color formats with CSS Color Module Level 4
gamut mapping, addressing PR feedback with Go implementation, performance
benchmarks, and reorganized documentation.
Features:
- OKLCH (perceptually uniform color space)
- CIE LAB (device-independent color space)
- CSS Color 4 compliant gamut mapping algorithm
- Inline comment support in color config parsing
Addressing PR Feedback:
1. Go Implementation (tools/utils/style/):
- Complete OKLCH and LAB parsing with gamut mapping
- Matches Python implementation structure
- Comprehensive test suite (all tests passing)
- Performance benchmarks showing acceptable overhead
2. Performance Benchmarks:
- OKLCH: ~4.6 µs/op
- LAB: ~1.5 µs/op
- 10 mixed colors: ~13 µs total
- Typical config (50 colors): <0.5ms startup impact
3. Documentation Reorganization:
- Moved detailed color docs to docs/wide-gamut-colors.rst
- Configuration docs now link to separate documentation
- Reduces size of main configuration documentation
Gamut Mapping:
- Binary search chroma reduction from CSS Color Module Level 4
- Preserves lightness and hue while reducing chroma for out-of-gamut colors
- Uses deltaE OK (JND threshold: 0.02) for perceptual difference
- Ensures graceful degradation on sRGB displays
Python Implementation:
- parse_oklch(): OKLCH color parsing with gamut mapping
- parse_lab(): CIE LAB parsing with gamut mapping via OKLCH conversion
- lab_to_oklch(): LAB to OKLCH conversion for consistent gamut mapping
- oklch_to_srgb_gamut_map(): CSS Color 4 gamut mapping algorithm
- srgb_to_oklab(): Reverse conversion for deltaE calculations
- deltaE_ok(): Perceptual color difference in OKLab space
Go Implementation:
- colorspaces.go: All color space conversions and gamut mapping
- wrapper.go: ParseColor() updated to support OKLCH and LAB
- Comprehensive test coverage with benchmarks
- Matches Python implementation behavior
Robustness:
- NaN and infinity validation in all color parsing functions
- Defense-in-depth with validation at parsing and gamut mapping levels
- Returns None/error for invalid input (consistent error handling)
- Validates before clamping operations to prevent NaN propagation
Files changed:
- Python: kitty/rgb.py, kitty_tests/datatypes.py (+250 lines)
- Go: tools/utils/style/colorspaces.go, wrapper.go (+350 lines, tests)
- Docs: docs/wide-gamut-colors.rst (moved from inline)
- Config: kitty/options/definition.py (simplified, links to docs)
References:
- CSS Color Module Level 4: https://www.w3.org/TR/css-color-4/
- OKLCH Color Space: https://bottosson.github.io/posts/oklab/🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude Sonnet 4.5 <noreply@anthropic.com>
Modified `start_classification` in `utf8_decode_to_esc` in `simd-string-impl.h`, which now:
Rejects `0xC0`, `0xC1` and `0xF5..0xFF` lead bytes in UTF-8 subsequences.
Enforces special ranges for the second subsequence bytes after `0xE0`, `0xED`, `0xF0` and `0xF4` bytes to prevent overlong sequences, surrogates, and code points above U+10FFFF.
Accumulates UTF-8 validation errors in a single vector to avoid many conditional branches.
Worsens unicode benchmark performance by about 4%.
Previously, if the last character was `'` parsing would fail: from `abc'`
it would produce the literal `'''abc''''`, which has one too many
unescaped single quote at the end.
This also fixes the issue for solo `'''`, where before it would produce
`''''\\'''''`, again with one too many single quote at the end.
I added tests for both cases.
This was needed to fix various corner cases when doing blending of colors
in linear space. The new architecture has the same performance as the
old in the common case of opaque rendering with no UI layers or images.
In the case of only positive z-index images there is a performance
decrease as the OS Window is now rendered to a offscreen texture and
then blitted to screen. However, in the future when we move to Vulkan or
I can figure out how to get Wayland to accept buffers with colors in
linear space, this performance penalty can be removed. The performance
penalty was not significant on my system but this is highly GPU
dependent. Modern GPUs are supposedly optimised for rendering to
offscreen buffers, so we will see. The awrit project might be a good
test case.
Now either we have 1-shot rendering for the case of opaque with only ext
or all the various pieces are rendered in successive draw calls into an
offscreen buffer that is blitted to the output buffer after all drawing
is done.
Fixes#8869
There are apparently some applications that want to only turn on OSC52
if they can be sure the terminal supports it.
https://github.com/contour-terminal/vt-extensions/blob/master/clipboard-extension.md
Seems harmless enough, though IMO the correct query mechanism for
runtime controllable settings is XTGETTCAP, but, let's be a
good citizen and co-operate. The overhead is not too large and I
have more important windmills to tilt at.
Fixes#8788
Can now set bool values explicitly with =
Handle multi short flag args like -abc
Add unit tests for CLI parsing
Generate go code to serialize CLI options as a cmdline
TODO: Implement setting of bool vals in C and Go parsing code
TODO: Help/rst output should somehow indicate this feature