Feature or enhancement
gh-151757 added wide and combining character support to the curses character-cell write methods (they now accept a str cell), but the module still has no representation for a styled wide cell — a curses cchar_t: a spacing character plus combining marks together with its attributes and color pair. As a result none of the wide-character (*_wch) functions, which take or return a cchar_t or a cchar_t array, are exposed.
The gap is most visible on the read side: window.inch() and window.getbkgd() return a packed chtype integer (8-bit character + A_* attributes + a color pair clamped to COLOR_PAIR()), which cannot represent a wide or combining character and clamps the color pair. There is currently no way to read back a styled wide cell at all. This is the long-standing request in gh-83395 ("Add curses.window.in_wch", with the now-stale PR #17825).
This issue tracks adding the full cchar_t API to the curses module. All of it requires building against a wide-character version of the curses library (ncursesw). The work will land step by step.
1. The cchar_t wrapper and the functions that take/return a single cell
A new immutable curses.complexchar(text, attr=0, pair=0) type. str(cc) is the cell's text; cc.attr and cc.pair are its rendition (read-only). The color pair is stored separately, not packed via COLOR_PAIR(), so it is not limited to the value that fits in a chtype.
Methods that take or return one cell:
- read (return a
complexchar): window.in_wch([y, x]) (wide inch), window.getbkgrnd() (wide getbkgd). These are the only genuinely new entry points needed -- the existing inch/getbkgd return a packed chtype int that cannot represent a wide/combining cell or an unclamped color pair. (This mirrors the existing getch vs get_wch split, justified by the different return type.)
- write: no new methods. Every existing single-cell method simply also accepts a
complexchar (its rendition then comes from the cell, and the method's own attr argument, if any, is ignored): addch, insch, echochar, bkgd, bkgdset, border, box, hline, vline. A complexchar is built explicitly with complexchar(text, attr, pair). This is also how the wide cchar_t form of the line-drawing functions (border_set/box_set/hline_set/vline_set) is reached, without adding *_set methods. Dedicated add_wch/ins_wch/echo_wchar/bkgrnd/bkgrndset are deliberately not added: once the chtype method accepts a complexchar, a parallel wide writer carries no extra capability.
(setcchar/getcchar need not be exposed separately: the complexchar object already packs/unpacks a cell.)
2. Arrays of cells (cchar_t array functions)
The same split applies one level up:
- read (new entry point):
window.in_wchstr([y, x,] n) (a single method with an optional count, like instr/in_wstr), returning the run of styled cells. There is no existing method that returns an array of styled cells (instr returns bytes, in_wstr returns str, both stripping rendition), so it is needed. It returns an immutable curses.complexstr -- the "complex character string" of the X/Open spec, the string counterpart of complexchar (as str is to a single character). It is a dedicated packed type owning the contiguous cchar_t buffer that win_wchnstr() fills directly (no per-cell object allocation on read): it decodes a complexchar lazily on indexing (arr[i]), len(arr) is the cell count, str(arr) joins the cells' text, and slicing/concatenation produce new complexstr instances. Immutable like str, so it is hashable and its raw buffer can be handed straight back to add_wchnstr() -- an array read and re-written is a zero-copy round-trip.
- write: no new methods. Extend the existing
addstr/addnstr/insstr/insnstr to also accept a sequence of cells, in addition to a plain str. A plain str keeps its current meaning; a sequence of cells is written via add_wchnstr -- a complexstr via its raw buffer (zero-copy), or any generic sequence (each item a complexchar or a str) packed into a temporary cchar_t array. So add_wchstr/add_wchnstr are not added, for the same reason add_wch was not. (To build or edit a run, use an ordinary list of complexchar; the packed complexstr is the immutable form you get back from a read.)
Notes
Linked PRs
Feature or enhancement
gh-151757 added wide and combining character support to the
cursescharacter-cell write methods (they now accept astrcell), but the module still has no representation for a styled wide cell — a cursescchar_t: a spacing character plus combining marks together with its attributes and color pair. As a result none of the wide-character (*_wch) functions, which take or return acchar_tor acchar_tarray, are exposed.The gap is most visible on the read side:
window.inch()andwindow.getbkgd()return a packedchtypeinteger (8-bit character +A_*attributes + a color pair clamped toCOLOR_PAIR()), which cannot represent a wide or combining character and clamps the color pair. There is currently no way to read back a styled wide cell at all. This is the long-standing request in gh-83395 ("Add curses.window.in_wch", with the now-stale PR #17825).This issue tracks adding the full
cchar_tAPI to thecursesmodule. All of it requires building against a wide-character version of the curses library (ncursesw). The work will land step by step.1. The
cchar_twrapper and the functions that take/return a single cellA new immutable
curses.complexchar(text, attr=0, pair=0)type.str(cc)is the cell's text;cc.attrandcc.pairare its rendition (read-only). The color pair is stored separately, not packed viaCOLOR_PAIR(), so it is not limited to the value that fits in achtype.Methods that take or return one cell:
complexchar):window.in_wch([y, x])(wideinch),window.getbkgrnd()(widegetbkgd). These are the only genuinely new entry points needed -- the existinginch/getbkgdreturn a packedchtypeint that cannot represent a wide/combining cell or an unclamped color pair. (This mirrors the existinggetchvsget_wchsplit, justified by the different return type.)complexchar(its rendition then comes from the cell, and the method's ownattrargument, if any, is ignored):addch,insch,echochar,bkgd,bkgdset,border,box,hline,vline. Acomplexcharis built explicitly withcomplexchar(text, attr, pair). This is also how the widecchar_tform of the line-drawing functions (border_set/box_set/hline_set/vline_set) is reached, without adding*_setmethods. Dedicatedadd_wch/ins_wch/echo_wchar/bkgrnd/bkgrndsetare deliberately not added: once the chtype method accepts acomplexchar, a parallel wide writer carries no extra capability.(
setcchar/getccharneed not be exposed separately: thecomplexcharobject already packs/unpacks a cell.)2. Arrays of cells (
cchar_tarray functions)The same split applies one level up:
window.in_wchstr([y, x,] n)(a single method with an optional count, likeinstr/in_wstr), returning the run of styled cells. There is no existing method that returns an array of styled cells (instrreturnsbytes,in_wstrreturnsstr, both stripping rendition), so it is needed. It returns an immutablecurses.complexstr-- the "complex character string" of the X/Open spec, the string counterpart ofcomplexchar(asstris to a single character). It is a dedicated packed type owning the contiguouscchar_tbuffer thatwin_wchnstr()fills directly (no per-cell object allocation on read): it decodes acomplexcharlazily on indexing (arr[i]),len(arr)is the cell count,str(arr)joins the cells' text, and slicing/concatenation produce newcomplexstrinstances. Immutable likestr, so it is hashable and its raw buffer can be handed straight back toadd_wchnstr()-- an array read and re-written is a zero-copy round-trip.addstr/addnstr/insstr/insnstrto also accept a sequence of cells, in addition to a plainstr. A plainstrkeeps its current meaning; a sequence of cells is written viaadd_wchnstr-- acomplexstrvia its raw buffer (zero-copy), or any generic sequence (each item acomplexcharor astr) packed into a temporarycchar_tarray. Soadd_wchstr/add_wchnstrare not added, for the same reasonadd_wchwas not. (To build or edit a run, use an ordinarylistofcomplexchar; the packedcomplexstris the immutable form you get back from a read.)Notes
in_wch).addch/insch/echochar/bkgd/bkgdset/border/box/hline/vline) already accept astrcell (Add wide-character (cchar_t) support to the curses module #151757); they now also accept acomplexchar, which is the styledcchar_tform carrying attributes and a color pair.Linked PRs