Skip to content

Commit 86cfe56

Browse files
64-bitmanchrisbra
authored andcommitted
patch 9.2.1161: the image feature can be improved
Problem: the image feature can be improved Solution: Refactor the image feature, make use of the pixman library if possible, add image_info(), image_add() and image_discard() functions and the 'imageprotocol' option (Foxe Chen) closes: #21234 Assisted-by: Claude Signed-off-by: Foxe Chen <[email protected]> Signed-off-by: Christian Brabandt <[email protected]>
1 parent 89c0f36 commit 86cfe56

81 files changed

Lines changed: 4766 additions & 4359 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎Filelist‎

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -103,6 +103,10 @@ SRC_ALL = \
103103
src/hashtab.c \
104104
src/help.c \
105105
src/highlight.c \
106+
src/image.c \
107+
src/image.h \
108+
src/image_kitty.c \
109+
src/image_sixel.c \
106110
src/indent.c \
107111
src/insexpand.c \
108112
src/job.c \
@@ -156,9 +160,6 @@ SRC_ALL = \
156160
src/session.c \
157161
src/sha256.c \
158162
src/sign.c \
159-
src/sixel.c \
160-
src/kitty.c \
161-
src/cairo.c \
162163
src/socketserver.c \
163164
src/sound.c \
164165
src/spell.c \
@@ -323,6 +324,9 @@ SRC_ALL = \
323324
src/proto/hashtab.pro \
324325
src/proto/help.pro \
325326
src/proto/highlight.pro \
327+
src/proto/image.pro \
328+
src/proto/image_kitty.pro \
329+
src/proto/image_sixel.pro \
326330
src/proto/indent.pro \
327331
src/proto/insexpand.pro \
328332
src/proto/job.pro \
@@ -361,9 +365,6 @@ SRC_ALL = \
361365
src/proto/session.pro \
362366
src/proto/sha256.pro \
363367
src/proto/sign.pro \
364-
src/proto/sixel.pro \
365-
src/proto/kitty.pro \
366-
src/proto/cairo.pro \
367368
src/proto/socketserver.pro \
368369
src/proto/sound.pro \
369370
src/proto/spell.pro \

‎runtime/doc/builtin.txt‎

Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -340,6 +340,9 @@ hlset({list}) Number set highlight group attributes
340340
hostname() String name of the machine Vim is running on
341341
iconv({expr}, {from}, {to}) String convert encoding of {expr}
342342
id({item}) String get unique identity string of item
343+
image_add({dict}) Number Add an image and return handle to it
344+
image_discard({id}) none Discard an image handle
345+
image_info([{id}]) List Get information about an image
343346
indent({lnum}) Number indent of line {lnum}
344347
index({object}, {expr} [, {start} [, {ic}]])
345348
Number index in {object} where {expr} appears
@@ -6407,6 +6410,81 @@ indexof({object}, {expr} [, {opts}]) *indexof()*
64076410
Return type: |Number|
64086411

64096412

6413+
image_add({dict}) *image_add()*
6414+
Add an image using the given information in {dict}. This does
6415+
not display an image, it simply loads the image data so that
6416+
it can be reference elsewhere (e.g. popup windows) multiple
6417+
times.
6418+
6419+
The {dict} argument must contain the following fields:
6420+
"data" a blob containing RGB or RGBA data, the format
6421+
is automatically detected using the dimensions
6422+
and blob size.
6423+
"width" width of image in pixels
6424+
"height" height of image in pixels
6425+
6426+
*E1584*
6427+
The image may not have more than 2147483647 pixels, that is
6428+
"width" times "height" must fit in a 32-bit signed integer.
6429+
6430+
The return value is an arbitrary ID that can be used to
6431+
reference the image.
6432+
6433+
{only available when compiled with the |+image| feature}
6434+
6435+
Can also be used as a |method|: >
6436+
info->image_add()
6437+
<
6438+
Return type: |Number|
6439+
6440+
6441+
image_discard({id}) *image_discard()*
6442+
Discard an image with ID {id}, internally decreasing its
6443+
reference count. The image will only actually be deleted when
6444+
there are no more references to it left. Note that after this,
6445+
the given image and its ID can not be referenced or modified.
6446+
This function only works on images created with |image_add()|,
6447+
images created directly from popup windows can not be
6448+
discarded or referenced anywhere else.
6449+
6450+
For example, if discarding an image that is still referenced
6451+
by a popup window, the popup window will still display the
6452+
image.
6453+
6454+
It is an error to provide an invalid image ID |E1587|.
6455+
6456+
{only available when compiled with the |+image| feature}
6457+
6458+
Can also be used as a |method|: >
6459+
id->image_discard()
6460+
<
6461+
Return type: void
6462+
6463+
6464+
image_info([{id}]) *image_info()* *E1587*
6465+
Return a list with information about loaded images.
6466+
When {id} is given only information about this image is
6467+
returned. It is an error to use an invalid image ID.
6468+
6469+
When {id} is omitted information about all images is returned.
6470+
6471+
For each image the information is stored in a |Dictionary|
6472+
with these items:
6473+
"id" the image ID
6474+
"data" newly copied blob of the image data
6475+
"width" width of image in pixels
6476+
"height" height of image in pixels
6477+
"alpha" if image has an alpha channel (RGBA)
6478+
"format" image format, either "rgb" or "rgba"
6479+
6480+
{only available when compiled with the |+image| feature}
6481+
6482+
Can also be used as a |method|: >
6483+
GetImage()->image_info()
6484+
<
6485+
Return type: list<dict<any>>
6486+
6487+
64106488
input({prompt} [, {text} [, {completion}]]) *input()*
64116489
The result is a String, which is whatever the user typed on
64126490
the command-line. The {prompt} argument is either a prompt

‎runtime/doc/eval.txt‎

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*eval.txt* For Vim version 9.2. Last change: 2026 Sep 24
1+
*eval.txt* For Vim version 9.2. Last change: 2026 Sep 30
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -2616,6 +2616,14 @@ v:hlsearch Variable that indicates whether search highlighting is on.
26162616
< Note that the value is restored when returning from a
26172617
function. |function-search-undo|.
26182618

2619+
*v:imagebackend*
2620+
v:imagebackend Indicates the current image backend being used, see
2621+
'imageprotocol'. It may have one of the following values:
2622+
"none" no image backend being used
2623+
"gui" GUI specific image backend being used
2624+
"kitty" kitty graphics protocol being used
2625+
"sixel" sixel graphics being used
2626+
26192627
*v:insertmode* *insertmode-variable*
26202628
v:insertmode Used for the |InsertEnter| and |InsertChange| autocommand
26212629
events. Values:

‎runtime/doc/options.txt‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*options.txt* For Vim version 9.2. Last change: 2026 Sep 26
1+
*options.txt* For Vim version 9.2. Last change: 2026 Sep 30
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -5049,6 +5049,24 @@ A jump table for the options with a short description can be found at |Q_op|.
50495049
Note that when using the GTK4 GUI, this option is not supported. The
50505050
only valid value for this option will be an empty string.
50515051

5052+
*'imageprotocol'* *'ipc'*
5053+
'imageprotocol' 'ipc' string (default: see below)
5054+
global *E1585* *E1586*
5055+
{only available when compiled with the |+image| feature}
5056+
Same as the 'keyprotocol' option, but chooses which |image| backend to
5057+
use, see |image-backends|. The supported image protocol names are:
5058+
none No protocol is supported (images will not render)
5059+
sixel The sixel protocol
5060+
kitty Kitty graphics protocol
5061+
5062+
This option is first queried on startup, and then after when the
5063+
'term' option changes. If the option is updated, and the image
5064+
backend changes, then any loaded images will automatically switch
5065+
backends. This includes when switching to the GUI using ":gui".
5066+
5067+
The default value is: >
5068+
kitty:kitty,foot:sixel,ghostty:kitty,wezterm:kitty,xterm:sixel
5069+
<
50525070
*'imcmdline'* *'imc'* *'noimcmdline'* *'noimc'*
50535071
'imcmdline' 'imc' boolean (default off)
50545072
global

‎runtime/doc/popup.txt‎

Lines changed: 64 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
*popup.txt* For Vim version 9.2. Last change: 2026 Jul 29
1+
*popup.txt* For Vim version 9.2. Last change: 2026 Sep 30
22

33

44
VIM REFERENCE MANUAL by Bram Moolenaar
@@ -427,6 +427,11 @@ popup_getoptions({id}) *popup_getoptions()*
427427
"textprop", "textpropid" and "textpropwin" are only present
428428
when "textprop" was set.
429429

430+
The "image" entry is a dictionary with the same fields as
431+
returned by |image_info()|. Note that if the image is created
432+
directly by the popup, the "id" field will not be present, see
433+
|popup-image|.
434+
430435
If popup window {id} is not found an empty Dict is returned.
431436

432437
Can also be used as a |method|: >
@@ -609,6 +614,7 @@ popup_setoptions({id}, {options}) *popup_setoptions()*
609614
firstline
610615
flip
611616
highlight
617+
image
612618
mapping
613619
mask
614620
moved
@@ -801,18 +807,9 @@ The second argument of |popup_create()| is a dictionary with options:
801807
underlying text, making it partially transparent.
802808
Requires 'termguicolors' to be set.
803809
Also see |popup-opacity|.
804-
image Dictionary describing a raw RGB or RGBA pixel buffer
805-
to render inside the popup. When set the popup
806-
auto-sizes its cell box from the image's pixel
807-
dimensions, so "minwidth" / "minheight" / "maxwidth" /
808-
"maxheight" do not need to be set by hand. Keys:
809-
data |Blob| of bytes; length must equal
810-
width*height*3 (RGB) or width*height*4
811-
(RGBA).
812-
width image width in pixels.
813-
height image height in pixels.
814-
Use an empty dictionary to remove a previously set
815-
image. See |popup-image|.
810+
image Dictionary for displaying an image. See |image_add()|
811+
for required fields, or you can provide the "id" field
812+
only, see |popup-image|.
816813
padding List with numbers, defining the padding
817814
above/right/below/left of the popup (similar to CSS).
818815
An empty list uses a padding of 1 all around. The
@@ -1170,44 +1167,60 @@ For example, to make the last 10 columns of the last line transparent:
11701167
To make the four corners transparent:
11711168
[[1, 1, 1, 1], [-1, -1, 1, 1], [1, 1, -1, -1], [-1, -1, -1, -1]]
11721169

1173-
POPUP IMAGE *popup-image*
1174-
1175-
A popup window can render an image instead of (or on top of) text by passing
1176-
an "image" dictionary to |popup_create()| or |popup_setoptions()|. The caller
1177-
supplies an already-decoded raw pixel buffer and Vim emits it through
1178-
whichever backend is available at runtime:
1179-
1180-
sixel DEC sixel DCS sequence on a sixel-capable terminal.
1181-
|+image_sixel|. Detected automatically; the buffer is also
1182-
cropped one cell above the screen edge to avoid sixel-induced
1183-
terminal scrolling.
1184-
kitty kitty graphics protocol APC sequence on terminals that support it
1185-
(kitty, ghostty, WezTerm, Konsole, ...). |+image_kitty|.
1186-
Detected by actively querying the terminal.
1187-
GDI StretchDIBits onto the GUI canvas on the MS-Windows GUI.
1188-
|+image_gdi|.
1189-
Cairo composite onto a cairo_image_surface_t on the GTK GUI
1190-
(covers GTK 2 and GTK 3). |+image_cairo|.
1191-
GDK Use GdkTexture, which uploads the image onto the GPU for faster
1192-
rendering (only for GTK 4). |+image_gdk|
1193-
1194-
Vim itself does NOT link against libpng, libjpeg, libwebp or any image
1195-
decoder. Format decoding is left to the caller, who can pipe the file through
1196-
any external tool (GraphicsMagick, ImageMagick, ffmpeg, a custom converter,
1197-
...) and pass the resulting bytes via a |Blob|.
1198-
1199-
The "image" dictionary accepts:
1200-
data |Blob| of bytes. Length must equal width*height*3 for RGB,
1201-
or width*height*4 for RGBA. RGBA buffers are alpha-composited
1202-
over the popup's background.
1203-
width image width in pixels.
1204-
height image height in pixels.
1205-
1206-
The popup's cell box is derived from the pixel dimensions and the terminal /
1207-
GUI cell metrics, so the caller does not normally have to set "minwidth" /
1208-
"minheight" / "maxwidth" / "maxheight".
1209-
1210-
For RGBA buffers that need to blend cleanly into the editor's actual backdrop
1170+
POPUP IMAGE *image* *popup-image*
1171+
1172+
Vim is capable of displaying graphical images, in both the terminal and GUI.
1173+
To do this, it must link with the pixman library, which you may install via
1174+
your package manager on Unix, or via vcpkg on MS-Windows. You may see if
1175+
images are supported by checking |+image| and |+image_popup|.
1176+
1177+
A popup window may additionally render an image. To do this, pass a field
1178+
named "image" containing a dictionary to |popup_create()| or
1179+
|popup_setoptions()|. The dictionary may either have the same fields as in
1180+
|image_add()|, or it may reference an image via its ID using the "id" field.
1181+
The "id" field is prioritized first, see |image_add()|, |image_discard()|, and
1182+
|image_info()|.
1183+
1184+
When an image is directly created by a popup window (e.g. "id" is not used),
1185+
then it is considered internal and can not be referenced anywhere else.
1186+
1187+
To unset a previously set image from a popup window pass an empty dictionary: >
1188+
call popup_setoptions(winid, #{image: {}})
1189+
<
1190+
*image-backends*
1191+
There are two terminal image protocols supported on all platforms. The
1192+
protocol to use is chosen using the 'imageprotocol' option:
1193+
1194+
sixel Uses the sixel protocol to display images.
1195+
kitty Uses the kitty graphics protocol. This is the recommended
1196+
protocol to use in the terminal if it is available, as it is much
1197+
more performant than sixel.
1198+
1199+
When using the GUI, the GTK4, GTK3, and Win32 versions of Vim are supported.
1200+
1201+
To see what image backend is currently being used, use the |v:imagebackend|
1202+
variable.
1203+
1204+
*image-options*
1205+
When passing an RGBA buffer, Vim expects it to be endian independent and non
1206+
alpha pre-multiplied. For RGB images, each pixel should be exactly 3 bytes,
1207+
a padding byte is not supported by Vim.
1208+
1209+
The dimensions of a popup containing an image are automatically calculated
1210+
based on the image dimensions and terminal/GUI cell size. However, you may
1211+
override it using the "minwidth", "minheight", "maxwidth", and "maxheight"
1212+
fields.
1213+
1214+
Images are not scaled, if a popup window is smaller than the image it
1215+
contains, then the image will be cropped instead.
1216+
1217+
*image-animation*
1218+
The image of a popup window can be changed at runtime using
1219+
|popup_setoptions()|. When the new image has the same format, width, and
1220+
height as the existing image, the existing image will be modified in place.
1221+
This is performant enough for frame-by-frame animation, using a |timer|.
1222+
1223+
For RGBA buffers that need to blend cleanly into the editor's actual backdrop,
12111224
the script can call |getbgcolor()| to obtain the current background colour as
12121225
[r, g, b] and pre-composite anti-aliased edges against it.
12131226

@@ -1232,15 +1245,6 @@ raw RGB bytes: >
12321245
\ line: 1, col: 1, border: [], padding: [0, 0, 0, 0],
12331246
\ })
12341247
1235-
The image can be replaced at runtime via |popup_setoptions()|. When the new
1236-
buffer has the same width and height as the current one the pixels are swapped
1237-
in place, which is fast enough to drive frame-by-frame animation from a
1238-
|timer|. |popup_getoptions()| returns the same dictionary back; the "data"
1239-
entry is a fresh blob copy independent of the popup's internal buffer.
1240-
1241-
To remove a previously set image pass an empty dictionary: >
1242-
call popup_setoptions(winid, #{image: {}})
1243-
12441248
==============================================================================
12451249
4. Examples *popup-examples*
12461250

‎runtime/doc/quickref.txt‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -764,6 +764,7 @@ Short explanation of each option: *option-list*
764764
'ignorecase' 'ic' ignore case in search patterns
765765
'imactivatefunc' 'imaf' function to enable/disable the X input method
766766
'imactivatekey' 'imak' key that activates the X input method
767+
'imageprotocol' 'ipc' image backend to use for what terminal
767768
'imcmdline' 'imc' use IM when starting to edit a command line
768769
'imdisable' 'imd' do not use the IM in any mode
769770
'iminsert' 'imi' use :lmap or IM in Insert mode

0 commit comments

Comments
 (0)