Graphics protocol: Add a new delete mode for deleting images whose ids fall within a range

Useful for bulk deletion. See #7080
This commit is contained in:
Kovid Goyal 2024-02-13 14:12:29 +05:30
parent ad3ab877f8
commit c19488f3be
No known key found for this signature in database
GPG Key ID: 06BC317B515ACE7C
7 changed files with 36 additions and 12 deletions

View File

@ -46,6 +46,8 @@ Detailed list of changes
0.33.0 [future]
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- Graphics protocol: Add a new delete mode for deleting images whose ids fall within a range. Useful for bulk deletion (:iss:`7080`)
- Keyboard protocol: Fix the :kbd:`Enter`, :kbd:`Tab` and :kbd:`Backspace` keys
generating spurious release events even when report all keys as escape codes
is not set (:iss:`7136`)

View File

@ -637,7 +637,7 @@ terminal may apply other heuristics (but it doesn't have to).
It is important to distinguish between virtual image placements and real images
displayed on top of Unicode placeholders. Virtual placements are invisible and only play
the role of prototypes for real images. Virtual placements can be deleted by a
deletion command only when the `d` key is equal to ``i``, ``I``, ``n`` or ``N``.
deletion command only when the `d` key is equal to ``i``, ``I``, ``r``, ``R``, ``n`` or ``N``.
The key values ``a``, ``c``, ``p``, ``q``, ``x``, ``y``, ``z`` and their capital
variants never affect virtual placements because they do not have a physical
location on the screen.
@ -729,13 +729,14 @@ scrollback buffer. The values of the ``x`` and ``y`` keys are the same as cursor
Value of ``d`` Meaning
================= ============
``a`` or ``A`` Delete all placements visible on screen
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key. If you specify a ``p`` key for the placement id as well, then only the placement with the specified image id and placement id will be deleted.
``i`` or ``I`` Delete all images with the specified id, specified using the ``i`` key. If you specify a ``p`` key for the placement id as well, then only the placement with the specified image id and placement id will be deleted.
``n`` or ``N`` Delete newest image with the specified number, specified using the ``I`` key. If you specify a ``p`` key for the
placement id as well, then only the placement with the specified number and placement id will be deleted.
``c`` or ``C`` Delete all placements that intersect with the current cursor position.
``f`` or ``F`` Delete animation frames.
``p`` or ``P`` Delete all placements that intersect a specific cell, the cell is specified using the ``x`` and ``y`` keys
``q`` or ``Q`` Delete all placements that intersect a specific cell having a specific z-index. The cell and z-index is specified using the ``x``, ``y`` and ``z`` keys.
``r`` or ``R`` Delete all images whose id is greater than or equal to the value of the ``x`` key and less than or equal to the value of the ``y`` (added in kitty version 0.33.0).
``x`` or ``X`` Delete all placements that intersect the specified column, specified using the ``x`` key.
``y`` or ``Y`` Delete all placements that intersect the specified row, specified using the ``y`` key.
``z`` or ``Z`` Delete all placements that have the specified z-index, specified using the ``z`` key.
@ -1083,9 +1084,11 @@ Key Value Default Description
**Keys for deleting images**
-----------------------------------------------------------
``d`` Single character. ``a`` What to delete.
``(a, A, c, C, n, N,
i, I, p, P, q, Q, x,
X, y, Y, z, Z)``.
``(
a, A, c, C, n, N,
i, I, p, P, q, Q, r,
R, x, X, y, Y, z, Z
)``.
======= ==================== ========= =================

View File

@ -260,7 +260,7 @@ def graphics_parser() -> None:
flag = frozenset
keymap: KeymapType = {
'a': ('action', flag('tTqpdfac')),
'd': ('delete_action', flag('aAiIcCfFnNpPqQxXyYzZ')),
'd': ('delete_action', flag('aAiIcCfFnNpPqQrRxXyYzZ')),
't': ('transmission_type', flag('dfts')),
'o': ('compressed', flag('z')),
'f': ('format', 'uint'),

View File

@ -2005,6 +2005,13 @@ id_filter_func(const ImageRef *ref, Image *img, const void *data, CellPixelSize
return false;
}
static bool
id_range_filter_func(const ImageRef *ref UNUSED, Image *img, const void *data, CellPixelSize cell UNUSED) {
const GraphicsCommand *g = data;
return img->client_id && g->x_offset <= img->client_id && img->client_id <= g->y_offset;
}
static bool
number_filter_func(const ImageRef *ref, Image *img, const void *data, CellPixelSize cell UNUSED) {
const GraphicsCommand *g = data;
@ -2059,6 +2066,7 @@ handle_delete_command(GraphicsManager *self, const GraphicsCommand *g, Cursor *c
case 0:
D('a', 'A', NULL, clear_filter_func_noncell);
G('i', 'I', id_filter_func);
G('r', 'R', id_range_filter_func);
G('p', 'P', point_filter_func);
G('q', 'Q', point3d_filter_func);
G('x', 'X', x_filter_func);

View File

@ -183,12 +183,13 @@ static inline void parse_graphics_code(PS *self, uint8_t *parser_buf,
if (g.delete_action != 'A' && g.delete_action != 'C' &&
g.delete_action != 'F' && g.delete_action != 'I' &&
g.delete_action != 'N' && g.delete_action != 'P' &&
g.delete_action != 'Q' && g.delete_action != 'X' &&
g.delete_action != 'Y' && g.delete_action != 'Z' &&
g.delete_action != 'a' && g.delete_action != 'c' &&
g.delete_action != 'f' && g.delete_action != 'i' &&
g.delete_action != 'n' && g.delete_action != 'p' &&
g.delete_action != 'q' && g.delete_action != 'x' &&
g.delete_action != 'Q' && g.delete_action != 'R' &&
g.delete_action != 'X' && g.delete_action != 'Y' &&
g.delete_action != 'Z' && g.delete_action != 'a' &&
g.delete_action != 'c' && g.delete_action != 'f' &&
g.delete_action != 'i' && g.delete_action != 'n' &&
g.delete_action != 'p' && g.delete_action != 'q' &&
g.delete_action != 'r' && g.delete_action != 'x' &&
g.delete_action != 'y' && g.delete_action != 'z') {
REPORT_ERROR("Malformed GraphicsCommand control block, unknown flag "
"value for delete_action: 0x%x",

View File

@ -1016,6 +1016,13 @@ def delete(ac=None, **kw):
put_image(s, cw, ch, z=9)
delete('Z', z=9)
self.ae(s.grman.image_count, 0)
put_image(s, cw, ch, id=1)
put_image(s, cw, ch, id=2)
put_image(s, cw, ch, id=3)
delete('R', y=2)
self.ae(s.grman.image_count, 1)
delete('R', x=3, y=3)
self.ae(s.grman.image_count, 0)
self.assertEqual(s.grman.disk_cache.total_size, 0)
# test put + delete + put

View File

@ -116,6 +116,9 @@ const (
GRT_delete_by_cell_zindex // q
GRT_free_by_cell_zindex // Q
GRT_delete_by_range // r
GRT_free_by_range // R
GRT_delete_by_column // x
GRT_free_by_column // X