Commit graph

1512 commits

Author SHA1 Message Date
Kovid Goyal
7cde77ef2c
Get freezing of slang on linux working 2026-08-05 05:32:50 +05:30
Kovid Goyal
879697e4c5
Move specialisations into compiler code
Allows for dynamic specialisations
2026-08-05 05:32:49 +05:30
Kovid Goyal
9261295448
Fix failing tests 2026-08-05 05:32:49 +05:30
copilot-swe-agent[bot]
a36b259d45
Fix parser to strip semicolons from module/import names; update tests 2026-08-05 05:32:49 +05:30
copilot-swe-agent[bot]
d8041066bf
Add slang parser corner case tests and implement test_slang_ordering 2026-08-05 05:32:49 +05:30
Kovid Goyal
dbfa720387
Work on generating build tree for slang files 2026-08-05 05:32:49 +05:30
Kovid Goyal
b3781f4fa1
Use the slangc binary instead trying to get the C++ extension working everywhere is too fragile 2026-08-05 05:32:48 +05:30
Kovid Goyal
c38b43b496
Add build test for loading slangc 2026-08-05 05:32:48 +05:30
Kovid Goyal
7f2d577a94
... 2026-08-05 05:32:48 +05:30
Francis Lavoie
86c5e13816
Wayland: do not ignore the scroll wheel after reversing direction
A high resolution wheel delivers one physical detent as several VALUE120
events, so pending_scroll_pixels accumulates fractions of a line and carries
the remainder to the next event. Detents do not reliably total 120 units, so
that carry is load bearing: it is what lets an undersized detent still scroll
a line.

It breaks down when the scroll direction changes, because the residual then
has the wrong sign and the first detent of the new direction is spent
cancelling it rather than scrolling. Measured on a Logitech MX Master 3 under
GNOME/Wayland, against a terminal program that had requested mouse events,
47% of detents that reversed direction scrolled nothing, against 2% of
detents continuing in the same direction.

Discard the residual when the direction changes, and leave the carry alone
otherwise, so scrolling in a single direction is unaffected.

The accumulator state also moves from Screen to OSWindow, since scroll events
are delivered to an OS Window rather than to a particular terminal window.
2026-08-02 15:47:31 -04:00
Kovid Goyal
75bd9d7979
Improve fade style for vertical tab bar 2026-08-02 21:54:56 +05:30
Kovid Goyal
70bdd4e96e
Fix quadratic algorithms in previous PR 2026-08-02 21:14:03 +05:30
Chance Zibolski
e7d8d17755 Vertical tabs: test wrapping combined with the line limit
Wrapping and tab_title_max_lines already compose, since wrapping runs before the
line limit is applied. Cover the combinations that were only checked by hand:
explicit newlines wrapped independently of each other, a wrap width wider than
the tab bar being clamped to it, and wrapped tabs packing by the lines they use
until the overflow ellipsis takes over.
2026-08-01 09:18:15 -07:00
Chance Zibolski
51ebfe4912 Vertical tabs: add tab_title_wrap to wrap long titles
A tab title too wide for the sidebar could only be truncated, which is wasteful
now that a title may use several lines. Add tab_title_wrap, accepting no (the
default, truncate as before), yes to wrap at the width of the tab bar, or a
number to wrap at that many cells.

Wrapping happens on grapheme boundaries so a line break can never land inside a
multi-codepoint grapheme, and SGR escapes are treated as zero width so colors
from tab_title_template neither consume cells nor get split in half. Wrapping is
bounded by tab_title_max_lines, and when a title needs more lines than it is
allowed the last line it gets is truncated with an ellipsis, which also makes
dropped lines visible for titles containing explicit newlines.

Only vertical tab bars are affected, since wrapping requires more than one row.
2026-08-01 09:18:15 -07:00
Chance Zibolski
4ccb98058b Vertical tabs: fill the tab background for the full width of the tab bar
Each line of a vertical tab was only painted as far as its text reached, so the
tab background ended mid row and the sidebar showed a ragged right edge. This
was already the case for single line titles, but multi-line titles make it
obvious, since the lines of one title rarely have the same length.

Paint the tab's full width before drawing the title over it, so every line a tab
occupies is filled in that tab's colors.
2026-08-01 09:18:15 -07:00
Chance Zibolski
26032a4802 Vertical tabs: support multi-line tab titles
Newlines in tab_title_template were drawn as a linefeed without a carriage
return, so each line started where the previous one ended, staircasing to the
right. Titles also collided with the tab below them after two lines, because
update_vertical assumed a fixed two line stride per tab.

Set LNM on the tab bar screen so a newline returns to the start of the next
line, measure how many lines each title actually occupies, and pack tabs at
cumulative offsets.

The blank line between tabs is preserved: one is inserted between tabs while
there is room, and dropped automatically once the tabs need the space, as
before. Previously this fell out of every tab reserving two lines, which is no
longer true now that a tab occupies only as many lines as its title needs.

The number of lines a title may use is limited by the new tab_title_max_lines
option, defaulting to 1 so existing configurations render as before. Lines
beyond the limit are dropped rather than bleeding into the next tab, and a title
is never allowed to use more lines than remain below it, since drawing past the
last line would scroll the tab bar and lose the tabs already drawn.

Only vertical tab bars are affected; horizontal tab bars share a single row.
2026-08-01 09:17:55 -07:00
Kovid Goyal
5cd6072570
Function to get memory used by processes rooted at pid 2026-07-29 13:25:51 +05:30
Tim Culverhouse
365f1a6b37
terminal: add visibility reports
Allow terminal applications to detect when their view is not observable so they can avoid unnecessary rendering work.

Implement mode 2033 and the visibility status query, and report changes from tab, pane, window, and platform occlusion state.
2026-07-28 14:25:12 -05:00
Kovid Goyal
0816716c72
Add support for DECSTR soft screen reset escape code
Some checks are pending
CI / Linux (python=3.14 cc=clang sanitize=1) (push) Waiting to run
CI / Linux (python=3.12 cc=gcc sanitize=0) (push) Waiting to run
CI / Linux (python=3.13 cc=gcc sanitize=1) (push) Waiting to run
CI / Linux package (push) Waiting to run
CI / Bundle test (macos-latest) (push) Waiting to run
CI / Bundle test (ubuntu-latest) (push) Waiting to run
CI / macOS Brew (push) Waiting to run
CI / Test ./dev.sh and benchmark (push) Waiting to run
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, macos-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Waiting to run
Depscan / Scan dependencies for vulnerabilities (push) Waiting to run
This escape code is largely undefined. There is no specification for how
it affects alternate screen mode, overriden colors, kitty keyboard
state, paused rendering, etc. Do what I feel is sensible in these cases.

Fixes #10263
2026-07-15 09:28:51 +05:30
Jeff Quast
efeb4aead0 Fix erroneous scroll when using X/Y offsets in images
Problem
-------

In update_dest_rect() when both num_cols and num_rows are 0
(auto-computed, ``a=T``), the first block computes num_cols with
cell_x_offset, but, then the second block mismatches num_cols, causing
it to compute width_px from num_cols and adds cell_x_offset a second
time. The returned value is large enough that it often causes scrolling,
depending on size and location of the screen.

A sample visual program:

```python
import zlib, base64, time
from functools import partial
echo = partial(print, end='', flush=True)

echo('\033[H\033[J')

base = bytes([0, 128, 0, 255]) * 640 * 576
k = zlib.compress(keyframe, 3)
echo(f'\033[8;60H\033_Ga=T,i=1,q=1,f=32,s=640,v=576,o=z,N=1;{base64.b64encode(k).decode()}\033\\')
time.sleep(1)

delta = bytes([200, 0, 0, 255]) * 32 * 512
d = zlib.compress(delta, 3)
echo(f'\033[9;67H\033_Ga=T,i=100,q=1,f=32,s=32,v=512,o=z,N=1,X=9,Y=25;{base64.b64encode(d).decode()}\033\\')

time.sleep(1)
print()
```

Solution
--------

Add 'auto_cols' and 'auto_rows' to remember the original read-only
values before exercising their auto-calculated size. 'auto_rows' isn't
technically necessary given the logic branching but it describes in code
better.

Before and After video
----------------------

A video will be attached shortly, here.
2026-07-12 18:22:40 -04:00
Sinity
b2d5a36283
Garbage collect the text cache periodically so unique cell texts do not grow memory without bound
The TextCache interns every unique multi-codepoint cell text for the
lifetime of the window with no eviction, so a stream of unique texts
(for example random combining mark sequences) grows memory without
bound, several hundred MB/hour at moderate throughput.

Mirror the existing hyperlink pool garbage collection: every 8192
newly interned entries, steal the cache contents and have the Screen
remap the index in every live cell (history buffer, main and alt line
buffers, paused rendering snapshot and overlay line), re-interning
only entries still referenced by some cell. Entries whose last
reference scrolled out of the history buffer are freed.

See #10249

Co-Authored-By: Claude <noreply@anthropic.com>
2026-07-11 20:40:02 +02:00
Kovid Goyal
89781759e4
...
Some checks are pending
CI / Linux (python=3.14 cc=clang sanitize=1) (push) Waiting to run
CI / Linux (python=3.12 cc=gcc sanitize=0) (push) Waiting to run
CI / Linux (python=3.13 cc=gcc sanitize=1) (push) Waiting to run
CI / Linux package (push) Waiting to run
CI / Bundle test (macos-latest) (push) Waiting to run
CI / Bundle test (ubuntu-latest) (push) Waiting to run
CI / macOS Brew (push) Waiting to run
CI / Test ./dev.sh and benchmark (push) Waiting to run
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, macos-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Waiting to run
Depscan / Scan dependencies for vulnerabilities (push) Waiting to run
2026-07-04 09:23:16 +05:30
Kovid Goyal
a65b4c70a7
Migrate type checker to ty
Much faster than mypy. Matches usage of ruff from same developer.
2026-07-04 09:18:00 +05:30
Kovid Goyal
9cd2c60064
Clean previous PR
Some checks are pending
CI / Linux (python=3.13 cc=clang sanitize=1) (push) Waiting to run
CI / Linux (python=3.11 cc=gcc sanitize=0) (push) Waiting to run
CI / Linux (python=3.12 cc=gcc sanitize=1) (push) Waiting to run
CI / Linux package (push) Waiting to run
CI / Bundle test (macos-latest) (push) Waiting to run
CI / Bundle test (ubuntu-latest) (push) Waiting to run
CI / macOS Brew (push) Waiting to run
CI / Test ./dev.sh and benchmark (push) Waiting to run
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, macos-latest) (push) Waiting to run
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Waiting to run
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Waiting to run
Depscan / Scan dependencies for vulnerabilities (push) Waiting to run
2026-06-29 06:17:08 +05:30
amoena
207b22aa80
fix(erase_last_command): erase the most recent command even empty output
erase_last_command selected the region to erase via find_cmd_output(..., -1),
which anchors on OUTPUT_START (OSC, 133;C). Commands that produce no output
(an empty Enter, a comment, cd, export, etc. -- never emit 133;C, so they were
skipped and an older command-with-output was erased instead. "Erase the last
command" therefore did not erase the last command whenever the most recent ones
has no output.

Select the region by prompt marks instead: erase the prompt block immediately
above the current (live) prompt, whatever it contains. Every submittd command
is now one unit, removed newest-first, one prompt block per invocation.

This also fixes two latent defects in the previous implementation:

* The on-screen deletion was anchored at `cursor->y - count`, which
  assumes the region ends exactly one row above the cursor.
  Multi-line prompts and skipped rows broke that assumption and left
  residual lines. Anchor at the top of the region instead.

* When part of the erased region was in the scrollback, the lines
  were removed from the history buffer but no redraw was signalled,
  so the deletion of the off-screen lines only became visible after
  the next scroll event recomputed the history viewport. Clamp
  scrolled_by to the new history length and call dirty_scroll()
  after shrinking the buffer.

include_prompt is retained for API compatibility but is now a no-op: the
unit erased is always the whole prompt block.
2026-06-28 11:17:01 -03:00
copilot-swe-agent[bot]
c2e7ee19d2
Change set_uint_at_address to use METH_FASTCALL, skip ctypes test on intel macs 2026-06-25 10:49:19 +00:00
copilot-swe-agent[bot]
c35ff2e843
Replace ctypes in marks.py with C-level set_uint_at_address function 2026-06-25 10:35:11 +00:00
copilot-swe-agent[bot]
bf7689b211
Enable ASAN for macOS CI builds in ci.py 2026-06-24 10:01:29 +05:30
Kovid Goyal
54a7841d18
Merge branch 'bvolpato/vertical-tab-bar-side' of https://github.com/bvolpato/kitty 2026-06-21 13:18:10 +05:30
copilot-swe-agent[bot]
051a5b72e0
Preferentially evict transient images before non-transient ones under storage pressure 2026-06-19 06:48:39 +00:00
Kovid Goyal
a2104d3755
Merge branch 'feat/10090-graphics-cache-dir' of https://github.com/Mekann2904/kitty 2026-06-19 10:16:10 +05:30
Matsumoto Kotaro
89946ebc07 graphics: make N a transient usage-hints bitmask
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.
2026-06-19 13:22:01 +09:00
Strykar
fc23ef57ec
fonts: make the color emoji regression test environment-independent
The coverage threshold (0.5 in fbd4e5ad1, lowered to 0.3 in d4106ef2d to
get CI green) is environment-dependent: a correctly sized emoji covers
~0.84 of its cell on one box but ~0.39 in CI, while the buggy render is
~0.28, so the margin is thin and font/cell dependent.

Render the same font two ways at one size instead: via its fontconfig
descriptor (which carries the size-fixup matrix) and via its file path
(which does not). They must come out the same size; the bug shrinks the
descriptor one. Only the matrix differs, so the check no longer depends
on the environment or the emoji artwork.
2026-06-14 21:00:12 +05:30
Kovid Goyal
d4106ef2db
Lower threshold for color emoji shrinkage test as at least in CI the font results in a smaller emoji 2026-06-14 20:48:59 +05:30
Strykar
fbd4e5ad1f
freetype: do not apply the fontconfig size-fixup matrix to color glyphs
ee937bdd1b routed FC_MATRIX through the cairo font matrix so synthetic
slant reaches color glyphs. But FC_MATRIX is also how fontconfig encodes
the pixel-size fixup of fixed-size faces. Noto Color Emoji is a ~109px
bitmap strike and fontconfig hands consumers a matrix scaling it to the
requested size (factor = requested_px / strike_px). cairo_set_font_size()
already brings the strike to the requested size, so feeding that matrix
into cairo_set_font_matrix() in apply_cairo_font_size() scales it down
again by the fixup factor. At terminal cell sizes that is a large shrink,
up to ~9x for small cells (easing to 1x as the cell nears the strike), so
color emoji render as a dot; fit_cairo_glyph() only shrinks, so it never
grows them back.

Only the shear carries synthetic slant; the diagonal is the size, which
cairo_set_font_size() and fit_cairo_glyph() already handle. Apply only
the shear and fall through to cairo_set_font_size() when there is no
shear. Pure-slant matrices are unchanged. This carries only the shear to
color glyphs, so a non-uniform diagonal scale from a hand-built FC_MATRIX
is dropped on that path; the stock fixup is uniform, so dropping it is
the intended behaviour.

Add a regression test that renders a color emoji and checks it fills its
cells, skipped unless a fixed-size color font with a fontconfig fixup
matrix is present.

Fixes #10144
2026-06-14 15:14:04 +05:30
Kovid Goyal
aa4e94cef5
Merge branch 'render-time-matrix' of https://github.com/Strykar/kitty 2026-06-13 12:49:05 +05:30
Strykar
8be2a10b29
fonts: attach synthetic-italic FC_MATRIX to found roman faces
fontconfig's FcFontList omits FC_MATRIX from its object set
(kitty/fontconfig.c), so a roman font that find_best_match finds there
(e.g. Fira Code, which ships no italic, in both its static and variable
builds) carries no synthetic-italic shear and its "italic" renders upright.
A family that is not found is substituted, and when the substitute
resolves through the listed faces those descriptors are equally
matrix-less, so this attach covers them too. Only raw fc_match
descriptors (runtime glyph-fallback faces via create_fallback_face, and
find_best_match's last-resort return) already carry the matrix from
substitution.

The italic intent for the configured faces exists only during selection,
not at face construction, so attach the matrix at the end of
get_font_files: for an italic slot whose chosen face is upright and has no
matrix, ask fc_match what fontconfig would do. fc_match returns a synthetic
matrix only when there is no real italic to use (no italic face and no
slanted named instance or variable slant axis), so a font that is already
italic, static or variable, is never double-slanted. Face construction
applies the matrix via FT_Set_Transform; the previous commit makes it
survive the size specialization step the render path builds faces from.
Only the matrix is taken, so selection is unchanged.

FontConfigPattern declared matrix as a required key, but pattern_as_dict
sets it only when the pattern has one, so declare it NotRequired. With
that and narrowing on descriptor_type the attach needs no cast.

Add a regression test (test_synthetic_italic_matrix): a roman no-italic
font gets a non-identity matrix on its italic slot while a real-italic
control does not, and the matrix survives specialize_font_descriptor. It
asserts the invariant rather than the exact shear (the value is
fontconfig's, version-dependent) and skips when the synthetic rule is
inactive.

Covers the four configured faces. Limitation: fc_match re-matches by family
name, so under an uncommon config (a multi-face family key plus a user
per-font FC_MATRIX rule keyed on width/style) it can attach a matrix
computed for a different face; the 90-synthetic shear this targets is
weight-independent and unaffected. A production version should re-match the
selected face by path+index+slant.
2026-06-11 00:57:59 +05:30
Kovid Goyal
11c2ccf00f
Add tests for splits layout serialization 2026-06-10 07:41:02 +05:30
Matsumoto Kotaro
cc2d7a1789 graphics: add memory-only storage for graphics data
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.
2026-05-30 18:46:24 +09:00
Mark Stuart
852fc4a662 Add equalize action and equalize_on_close option to Splits layout
Adds an `equalize` layout action that redistributes split sizes so each
window receives a proportional share of space along each axis.

Also adds an `equalize_on_close` layout option that automatically
equalizes splits whenever a window is closed, keeping the remaining
windows balanced without requiring an explicit key binding.

These two features compose well. For example, to keep splits balanced
at all times - equalizing on every open and close:

    enabled_layouts splits:equalize_on_close=true
    map ctrl+' combine : launch --location=hsplit --cwd=current : layout_action equalize
    map ctrl+/ combine : launch --location=vsplit --cwd=current : layout_action equalize

A standalone key binding for manual rebalancing is also supported:

    map ctrl+shift+e layout_action equalize
2026-05-29 20:02:42 +01:00
Kovid Goyal
3fc5bed364
Merge branch 'decst8c' of https://github.com/aymanbagabas/kitty
Some checks failed
CI / Linux (python=3.13 cc=clang sanitize=1) (push) Has been cancelled
CI / Linux (python=3.11 cc=gcc sanitize=0) (push) Has been cancelled
CI / Linux (python=3.12 cc=gcc sanitize=1) (push) Has been cancelled
CI / Linux package (push) Has been cancelled
CI / Bundle test (macos-latest) (push) Has been cancelled
CI / Bundle test (ubuntu-latest) (push) Has been cancelled
CI / macOS Brew (push) Has been cancelled
CI / Test ./dev.sh and benchmark (push) Has been cancelled
CodeQL / CodeQL-Build (actions, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (c, macos-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (c, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (go, ubuntu-latest) (push) Has been cancelled
CodeQL / CodeQL-Build (python, ubuntu-latest) (push) Has been cancelled
Depscan / Scan dependencies for vulnerabilities (push) Has been cancelled
2026-05-27 08:38:45 +05:30
Kovid Goyal
c7622683c8
Cleanup previous PR 2026-05-27 08:31:41 +05:30
Ayman Bagabas
c68a1654d3 feat(vt): add support for DECST8C escape sequence
Recognize CSI ? 5 W as DECST8C, which resets the active screen's tab
stops to the default of every 8 columns. Other CSI W variants continue
to produce a parse error.

Signed-off-by: Ayman Bagabas <aymanbagabas@gmail.com>
2026-05-26 21:12:27 -04:00
Ayman Bagabas
3138ae4aad fix(screen): preserve tab stops across window resizes
Previously, every window resize reinitialised the tab stops to the
default of every 8 columns, discarding any stops set via HTS or cleared
via TBC. ECMA-48 only treats RIS, DECSTR, and DECCOLM as events that
reset tab stops, and other terminal emulators all preserve user-set
stops across an interactive resize.

Copy the surviving prefix of the previous tab stops into the freshly
allocated array on both main and alt screens. Newly added columns when
growing the window keep the default every 8 columns pattern. Also point
the active tabstops pointer at the alt screen's array when a resize
happens while the alt screen is active, instead of unconditionally
resetting it to the main screen's array.

Signed-off-by: Ayman Bagabas <aymanbagabas@gmail.com>
2026-05-26 21:12:27 -04:00
Hassan Raza
f413f528af
Preserve copy_or_noop passthrough 2026-05-20 11:15:49 +05:00
Hassan Raza
d77c94e3aa
Avoid shell quoting in ssh login fallback 2026-05-19 23:14:08 +05:00
Hassan Raza
c0db371afe
Quote ssh bootstrap symlink moves 2026-05-19 16:54:02 +05:00
copilot-swe-agent[bot]
d5a6c072d9
Add data URI support to dnd kitten parse_uri_list
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/dd371733-fa08-484e-888a-8d0ebdadb853

Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
2026-05-18 07:54:57 +00:00
copilot-swe-agent[bot]
0062495e96
fix drop_update_mimes: use exact MIME matching and correct sentinel value
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/c41c0c3f-f9c8-4638-a4c4-64961b030f35

Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
2026-05-17 16:45:07 +00:00
copilot-swe-agent[bot]
05b288e754
Address code review: use PATH_MAX buffer and move os import to top
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/da8b4577-3de8-4784-afc0-c1967f605dec

Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
2026-05-17 15:34:56 +00:00