| FazBrowse GitHub Viewer | Trending | | Home |
| Tools: [Download Repo ZIP] [Original HTTPS Page] |
1 parent 285d96d commit d466257
6 files changed
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -941,7 +941,8 @@ Window objects | |||
| 941 | 941 | ||
| 942 | 942 | .. versionchanged:: next | |
| 943 | 943 | A character may now be given as a string of a base character followed | |
| 944 | - by combining characters, instead of only a single character. | ||
| 944 | + by combining characters, instead of only a single character, or as a | ||
| 945 | + :class:`complexchar` cell. | ||
| 945 | 946 | ||
| 946 | 947 | ||
| 947 | 948 | .. method:: window.addnstr(str, n[, attr]) | |
@@ -1051,7 +1052,8 @@ Window objects | |||
| 1051 | 1052 | background character. | |
| 1052 | 1053 | ||
| 1053 | 1054 | .. versionchanged:: next | |
| 1054 | - Wide and combining characters are now accepted. | ||
| 1055 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1056 | + accepted. | ||
| 1055 | 1057 | ||
| 1056 | 1058 | ||
| 1057 | 1059 | .. method:: window.bkgdset(ch[, attr]) | |
@@ -1064,7 +1066,8 @@ Window objects | |||
| 1064 | 1066 | the character through any scrolling and insert/delete line/character operations. | |
| 1065 | 1067 | ||
| 1066 | 1068 | .. versionchanged:: next | |
| 1067 | - Wide and combining characters are now accepted. | ||
| 1069 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1070 | + accepted. | ||
| 1068 | 1071 | ||
| 1069 | 1072 | ||
| 1070 | 1073 | .. method:: window.border([ls[, rs[, ts[, bs[, tl[, tr[, bl[, br]]]]]]]]) | |
@@ -1100,7 +1103,8 @@ Window objects | |||
| 1100 | 1103 | +-----------+---------------------+-----------------------+ | |
| 1101 | 1104 | ||
| 1102 | 1105 | .. versionchanged:: next | |
| 1103 | - Wide and combining characters are now accepted. A single call cannot mix | ||
| 1106 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1107 | + accepted. A single call cannot mix | ||
| 1104 | 1108 | them with integer or byte characters. | |
| 1105 | 1109 | ||
| 1106 | 1110 | ||
@@ -1110,7 +1114,8 @@ Window objects | |||
| 1110 | 1114 | *bs* are *horch*. The default corner characters are always used by this function. | |
| 1111 | 1115 | ||
| 1112 | 1116 | .. versionchanged:: next | |
| 1113 | - Wide and combining characters are now accepted. A single call cannot mix | ||
| 1117 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1118 | + accepted. A single call cannot mix | ||
| 1114 | 1119 | them with integer or byte characters. | |
| 1115 | 1120 | ||
| 1116 | 1121 | ||
@@ -1182,7 +1187,8 @@ Window objects | |||
| 1182 | 1187 | on the window. | |
| 1183 | 1188 | ||
| 1184 | 1189 | .. versionchanged:: next | |
| 1185 | - Wide and combining characters are now accepted. | ||
| 1190 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1191 | + accepted. | ||
| 1186 | 1192 | ||
| 1187 | 1193 | ||
| 1188 | 1194 | .. method:: window.enclose(y, x) | |
@@ -1221,6 +1227,20 @@ Window objects | |||
| 1221 | 1227 | Return the given window's current background character/attribute pair. | |
| 1222 | 1228 | ||
| 1223 | 1229 | ||
| 1230 | + .. method:: window.getbkgrnd() | ||
| 1231 | + | ||
| 1232 | + Return the given window's current background as a :class:`complexchar`. | ||
| 1233 | + This is the wide-character variant of :meth:`getbkgd`: the returned object | ||
| 1234 | + carries the background character together with its attributes and color pair, | ||
| 1235 | + and the color pair is not limited to the value that fits in a | ||
| 1236 | + :func:`color_pair`. | ||
| 1237 | + | ||
| 1238 | + This method is only available if Python was built against a wide-character | ||
| 1239 | + version of the underlying curses library. | ||
| 1240 | + | ||
| 1241 | + .. versionadded:: next | ||
| 1242 | + | ||
| 1243 | + | ||
| 1224 | 1244 | .. method:: window.getch([y, x]) | |
| 1225 | 1245 | ||
| 1226 | 1246 | Get a character. Note that the integer returned does *not* have to be in ASCII | |
@@ -1325,7 +1345,8 @@ Window objects | |||
| 1325 | 1345 | of the window if fewer than *n* cells are available. | |
| 1326 | 1346 | ||
| 1327 | 1347 | .. versionchanged:: next | |
| 1328 | - Wide and combining characters are now accepted. | ||
| 1348 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1349 | + accepted. | ||
| 1329 | 1350 | ||
| 1330 | 1351 | ||
| 1331 | 1352 | .. method:: window.idcok(flag) | |
@@ -1356,6 +1377,20 @@ Window objects | |||
| 1356 | 1377 | the character proper, and upper bits are the attributes. | |
| 1357 | 1378 | ||
| 1358 | 1379 | ||
| 1380 | + .. method:: window.in_wch([y, x]) | ||
| 1381 | + | ||
| 1382 | + Return the complex character at the given position in the window as a | ||
| 1383 | + :class:`complexchar`. This is the wide-character variant of :meth:`inch`: | ||
| 1384 | + the returned object carries the cell's text (a spacing character optionally | ||
| 1385 | + followed by combining characters) together with its attributes and color | ||
| 1386 | + pair, none of which :meth:`inch` can represent. | ||
| 1387 | + | ||
| 1388 | + This method is only available if Python was built against a wide-character | ||
| 1389 | + version of the underlying curses library. | ||
| 1390 | + | ||
| 1391 | + .. versionadded:: next | ||
| 1392 | + | ||
| 1393 | + | ||
| 1359 | 1394 | .. method:: window.insch(ch[, attr]) | |
| 1360 | 1395 | window.insch(y, x, ch[, attr]) | |
| 1361 | 1396 | ||
@@ -1365,7 +1400,8 @@ Window objects | |||
| 1365 | 1400 | line being lost. The cursor position does not change. | |
| 1366 | 1401 | ||
| 1367 | 1402 | .. versionchanged:: next | |
| 1368 | - Wide and combining characters are now accepted. | ||
| 1403 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1404 | + accepted. | ||
| 1369 | 1405 | ||
| 1370 | 1406 | ||
| 1371 | 1407 | .. method:: window.insdelln(nlines) | |
@@ -1776,7 +1812,8 @@ Window objects | |||
| 1776 | 1812 | character *ch* with attributes *attr*. | |
| 1777 | 1813 | ||
| 1778 | 1814 | .. versionchanged:: next | |
| 1779 | - Wide and combining characters are now accepted. | ||
| 1815 | + Wide and combining characters, and :class:`complexchar` cells, are now | ||
| 1816 | + accepted. | ||
| 1780 | 1817 | ||
| 1781 | 1818 | ||
| 1782 | 1819 | .. _curses-screen-objects: | |
@@ -1833,6 +1870,49 @@ Screen objects | |||
| 1833 | 1870 | .. versionadded:: next | |
| 1834 | 1871 | ||
| 1835 | 1872 | ||
| 1873 | + .. _curses-complexchar-objects: | ||
| 1874 | + | ||
| 1875 | + Complex character objects | ||
| 1876 | + ------------------------- | ||
| 1877 | + | ||
| 1878 | + .. class:: complexchar(text, /, attr=0, pair=0) | ||
| 1879 | + | ||
| 1880 | + A *complex character* (or *complexchar*) is an immutable styled | ||
| 1881 | + wide-character cell: a spacing character optionally followed by combining | ||
| 1882 | + characters, together with a set of attributes and a color pair. | ||
| 1883 | + | ||
| 1884 | + *text* is the cell's text, *attr* a combination of the | ||
| 1885 | + :ref:`WA_* attributes <curses-wa-constants>` (equivalent to the matching | ||
| 1886 | + ``A_*`` constants), and *pair* a color pair number. Unlike the packed | ||
| 1887 | + :class:`chtype <int>` used by :meth:`~window.inch` and the ``A_*`` methods, | ||
| 1888 | + the color pair is stored separately and is not limited to the value that | ||
| 1889 | + fits in a :func:`color_pair`. | ||
| 1890 | + | ||
| 1891 | + Complex characters are returned by :meth:`window.in_wch` and | ||
| 1892 | + :meth:`window.getbkgrnd`, and are accepted (along with an integer, a byte | ||
| 1893 | + or a string) by the character-cell methods such as :meth:`window.addch`, | ||
| 1894 | + :meth:`window.insch`, :meth:`window.bkgd`, :meth:`window.border`, | ||
| 1895 | + :meth:`window.hline` and :meth:`window.vline`. A complex character already | ||
| 1896 | + carries its own rendition, so it cannot be combined with an explicit *attr* | ||
| 1897 | + argument. | ||
| 1898 | + | ||
| 1899 | + :func:`str` returns the cell's text; two complex characters are equal when | ||
| 1900 | + their text, attributes and color pair all match. | ||
| 1901 | + | ||
| 1902 | + This type is only available if Python was built against a wide-character | ||
| 1903 | + version of the underlying curses library. | ||
| 1904 | + | ||
| 1905 | + .. attribute:: attr | ||
| 1906 | + | ||
| 1907 | + The attributes of the character cell (read-only). | ||
| 1908 | + | ||
| 1909 | + .. attribute:: pair | ||
| 1910 | + | ||
| 1911 | + The color pair number of the character cell (read-only). | ||
| 1912 | + | ||
| 1913 | + .. versionadded:: next | ||
| 1914 | + | ||
| 1915 | + | ||
| 1836 | 1916 | Constants | |
| 1837 | 1917 | --------- | |
| 1838 | 1918 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -138,6 +138,16 @@ curses | |||
| 138 | 138 | attribute value, and the corresponding ``WA_*`` attribute constants. | |
| 139 | 139 | (Contributed by Serhiy Storchaka in :gh:`152219`.) | |
| 140 | 140 | ||
| 141 | + * Add the :class:`curses.complexchar` type, representing a styled | ||
| 142 | + wide-character cell (its text, attributes and color pair), and the window | ||
| 143 | + methods :meth:`~curses.window.in_wch` and :meth:`~curses.window.getbkgrnd` | ||
| 144 | + that return one --- the wide-character counterparts of | ||
| 145 | + :meth:`~curses.window.inch` and :meth:`~curses.window.getbkgd`. The | ||
| 146 | + character-cell methods, such as :meth:`~curses.window.addch` and | ||
| 147 | + :meth:`~curses.window.border`, now also accept a | ||
| 148 | + :class:`~curses.complexchar`. | ||
| 149 | + (Contributed by Serhiy Storchaka in :gh:`152233`.) | ||
| 150 | + | ||
| 141 | 151 | gzip | |
| 142 | 152 | ---- | |
| 143 | 153 | ||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -345,6 +345,36 @@ def test_wide_characters(self): | |||
| 345 | 345 | # border() and box() cannot mix integer and wide-string characters. | |
| 346 | 346 | self.assertRaises(TypeError, stdscr.box, vline, ord('-')) | |
| 347 | 347 | ||
| 348 | + @requires_curses_func('complexchar') | ||
| 349 | + def test_complexchar_in_cell_methods(self): | ||
| 350 | + # Every single-character-cell method also accepts a complexchar, whose | ||
| 351 | + # attributes and color pair come from the cell itself. | ||
| 352 | + stdscr = self.stdscr | ||
| 353 | + cc = curses.complexchar('A', curses.A_BOLD) | ||
| 354 | + v = curses.complexchar('|') | ||
| 355 | + h = curses.complexchar('-') | ||
| 356 | + stdscr.move(0, 0) | ||
| 357 | + stdscr.addch(0, 0, cc) | ||
| 358 | + self.assertEqual(str(stdscr.in_wch(0, 0)), 'A') | ||
| 359 | + self.assertTrue(stdscr.in_wch(0, 0).attr & curses.A_BOLD) | ||
| 360 | + stdscr.insch(1, 0, cc) | ||
| 361 | + stdscr.echochar(cc) | ||
| 362 | + stdscr.bkgdset(cc) | ||
| 363 | + stdscr.bkgd(cc) | ||
| 364 | + stdscr.hline(2, 0, h, 3) | ||
| 365 | + stdscr.vline(3, 0, v, 3) | ||
| 366 | + stdscr.border(v, v, h, h) | ||
| 367 | + stdscr.box(v, h) | ||
| 368 | + # A complexchar already carries its rendition, so combining it with an | ||
| 369 | + # explicit attr argument is rejected. | ||
| 370 | + self.assertRaises(TypeError, stdscr.addch, cc, curses.A_BOLD) | ||
| 371 | + self.assertRaises(TypeError, stdscr.addch, 0, 0, cc, curses.A_BOLD) | ||
| 372 | + self.assertRaises(TypeError, stdscr.insch, cc, curses.A_BOLD) | ||
| 373 | + self.assertRaises(TypeError, stdscr.echochar, cc, curses.A_BOLD) | ||
| 374 | + self.assertRaises(TypeError, stdscr.bkgd, cc, curses.A_BOLD) | ||
| 375 | + self.assertRaises(TypeError, stdscr.bkgdset, cc, curses.A_BOLD) | ||
| 376 | + self.assertRaises(TypeError, stdscr.hline, h, 3, curses.A_BOLD) | ||
| 377 | + self.assertRaises(TypeError, stdscr.vline, v, 3, curses.A_BOLD) | ||
| 348 | 378 | ||
| 349 | 379 | @requires_curses_window_meth('in_wstr') | |
| 350 | 380 | def test_in_wstr(self): | |
@@ -355,6 +385,90 @@ def test_in_wstr(self): | |||
| 355 | 385 | self.assertEqual(stdscr.in_wstr(0, 0, len(s)), s) | |
| 356 | 386 | self.assertIsInstance(stdscr.instr(0, 0, len(s)), bytes) | |
| 357 | 387 | ||
| 388 | + @requires_curses_func('complexchar') | ||
| 389 | + def test_complexchar(self): | ||
| 390 | + # A complexchar is a styled wide-character cell: str() is its text, | ||
| 391 | + # and the attr and pair attributes are its rendition. | ||
| 392 | + cc = curses.complexchar('A', curses.A_BOLD) | ||
| 393 | + self.assertEqual(str(cc), 'A') | ||
| 394 | + self.assertTrue(cc.attr & curses.A_BOLD) | ||
| 395 | + self.assertEqual(cc.pair, 0) | ||
| 396 | + # A spacing character optionally followed by combining characters. | ||
| 397 | + if self._encodable('e\u0301'): | ||
| 398 | + self.assertEqual(str(curses.complexchar('e\u0301')), 'e\u0301') | ||
| 399 | + # Defaults: no attributes, color pair 0. | ||
| 400 | + cc = curses.complexchar('z') | ||
| 401 | + self.assertEqual(str(cc), 'z') | ||
| 402 | + self.assertEqual(cc.attr, 0) | ||
| 403 | + self.assertEqual(cc.pair, 0) | ||
| 404 | + # Immutable rendition. | ||
| 405 | + self.assertRaises(AttributeError, setattr, cc, 'attr', 1) | ||
| 406 | + self.assertRaises(AttributeError, setattr, cc, 'pair', 1) | ||
| 407 | + # Equality and hashing compare text, attributes and color pair. | ||
| 408 | + self.assertEqual(curses.complexchar('A', curses.A_BOLD), | ||
| 409 | + curses.complexchar('A', curses.A_BOLD)) | ||
| 410 | + self.assertEqual(hash(curses.complexchar('A', curses.A_BOLD)), | ||
| 411 | + hash(curses.complexchar('A', curses.A_BOLD))) | ||
| 412 | + self.assertNotEqual(curses.complexchar('A'), | ||
| 413 | + curses.complexchar('A', curses.A_BOLD)) | ||
| 414 | + self.assertNotEqual(curses.complexchar('A'), curses.complexchar('B')) | ||
| 415 | + # repr() shows only a non-default attr/pair, and is a constructor call. | ||
| 416 | + ns = {'_curses': sys.modules[type(cc).__module__]} | ||
| 417 | + self.assertNotIn('attr=', repr(curses.complexchar('z'))) | ||
| 418 | + self.assertNotIn('pair=', repr(curses.complexchar('z'))) | ||
| 419 | + r = repr(curses.complexchar('A', curses.A_BOLD)) | ||
| 420 | + self.assertIn('attr=', r) | ||
| 421 | + self.assertNotIn('pair=', r) | ||
| 422 | + self.assertEqual(eval(r, ns), curses.complexchar('A', curses.A_BOLD)) | ||
| 423 | + # Invalid arguments. | ||
| 424 | + self.assertRaises(TypeError, curses.complexchar, 65) | ||
| 425 | + self.assertRaises(TypeError, curses.complexchar, 'A', 'bold') | ||
| 426 | + self.assertRaises(OverflowError, curses.complexchar, 'A', -1) | ||
| 427 | + self.assertRaises(OverflowError, curses.complexchar, 'A', 1 << 64) | ||
| 428 | + self.assertRaises(ValueError, curses.complexchar, 'A', 0, -1) | ||
| 429 | + self.assertRaises(ValueError, curses.complexchar, 'ab') | ||
| 430 | + | ||
| 431 | + @requires_curses_window_meth('in_wch') | ||
| 432 | + def test_in_wch(self): | ||
| 433 | + # in_wch() returns the styled wide cell as a complexchar -- something | ||
| 434 | + # inch() (a packed chtype) cannot represent. | ||
| 435 | + stdscr = self.stdscr | ||
| 436 | + stdscr.addch(0, 0, curses.complexchar('A', curses.A_UNDERLINE)) | ||
| 437 | + cc = stdscr.in_wch(0, 0) | ||
| 438 | + self.assertEqual(str(cc), 'A') | ||
| 439 | + self.assertTrue(cc.attr & curses.A_UNDERLINE) | ||
| 440 | + if self._encodable('\u00e9'): # precomposed, for a portable round-trip | ||
| 441 | + stdscr.addch(3, 0, curses.complexchar('\u00e9')) | ||
| 442 | + self.assertEqual(str(stdscr.in_wch(3, 0)), '\u00e9') | ||
| 443 | + # in_wch() without coordinates reads at the cursor position. | ||
| 444 | + stdscr.move(0, 0) | ||
| 445 | + self.assertEqual(str(stdscr.in_wch()), 'A') | ||
| 446 | + | ||
| 447 | + @requires_curses_window_meth('in_wch') | ||
| 448 | + @requires_colors | ||
| 449 | + def test_in_wch_color(self): | ||
| 450 | + # Unlike the chtype methods (which pack the pair into the value via | ||
| 451 | + # COLOR_PAIR), a complex character carries its color pair separately. | ||
| 452 | + stdscr = self.stdscr | ||
| 453 | + curses.init_pair(1, curses.COLOR_RED, curses.COLOR_BLACK) | ||
| 454 | + stdscr.addch(0, 0, curses.complexchar('A', curses.A_BOLD, 1)) | ||
| 455 | + cc = stdscr.in_wch(0, 0) | ||
| 456 | + self.assertEqual(str(cc), 'A') | ||
| 457 | + self.assertTrue(cc.attr & curses.A_BOLD) | ||
| 458 | + self.assertEqual(cc.pair, 1) | ||
| 459 | + self.assertEqual(curses.complexchar('A', 0, 1).pair, 1) | ||
| 460 | + | ||
| 461 | + @requires_curses_window_meth('getbkgrnd') | ||
| 462 | + def test_getbkgrnd(self): | ||
| 463 | + # getbkgrnd() returns the background as a complexchar (getbkgd() can | ||
| 464 | + # only return a packed chtype). | ||
| 465 | + stdscr = self.stdscr | ||
| 466 | + stdscr.bkgdset(curses.complexchar(' ', curses.A_DIM)) | ||
| 467 | + stdscr.bkgd(curses.complexchar(' ', curses.A_BOLD)) | ||
| 468 | + cc = stdscr.getbkgrnd() | ||
| 469 | + self.assertEqual(str(cc), ' ') | ||
| 470 | + self.assertTrue(cc.attr & curses.A_BOLD) | ||
| 471 | + | ||
| 358 | 472 | ||
| 359 | 473 | def test_output_character(self): | |
| 360 | 474 | stdscr = self.stdscr | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
@@ -0,0 +1,7 @@ | |||
| 1 | + Add the :class:`curses.complexchar` type, representing a styled wide-character | ||
| 2 | + cell (text, attributes and color pair), and the :mod:`curses` window methods | ||
| 3 | + :meth:`~curses.window.in_wch` and :meth:`~curses.window.getbkgrnd` that return | ||
| 4 | + one. The character-cell methods (:meth:`~curses.window.addch`, | ||
| 5 | + :meth:`~curses.window.bkgd`, :meth:`~curses.window.border`, | ||
| 6 | + :meth:`~curses.window.hline` and others) now also accept a | ||
| 7 | + :class:`~curses.complexchar`. | ||
| Back | FazBrowse Home | New Git URL |
0 commit comments