on master help sign in
Add support for custom character width table installation
74a7c55Jonathan Daugherty
cbits/mk_wcwidth.c+115−1
@@ -60,6 +60,24 @@
60 */
60 */
61
61
62#include <HsFFI.h>
62#include <HsFFI.h>
63+#include <stdlib.h>
64+#include <string.h>
65+
66+// The maximum size for a custom character width table is the total
67+// number of possible characters as dictated by the compiler.
68+#define MAX_CUSTOM_TABLE_SIZE (HS_CHAR_MAX + 1)
69+
70+// The pointer to the start of the custom character width table, if any.
71+// If this is NULL, the built-in tree search logic is used.
72+static uint8_t* custom_table = NULL;
73+
74+// The size of the custom table. This should only be set if custom_table
75+// is not NULL. Its value should be the size of the custom_table array.
76+static uint32_t custom_table_size = 0;
77+
78+// A flag indicating whether the custom table is ready for use. This
79+// should only be set once the table has been allocated and initialized.
80+static uint8_t custom_table_ready = 0;
63
81
64struct interval {
82struct interval {
65 int first;
83 int first;
@@ -119,7 +137,7 @@ static int vty_bisearch(HsChar ucs, const struct interval *table, int max) {
119 * in ISO 10646.
137 * in ISO 10646.
120 */
138 */
121
139
122−HsInt vty_mk_wcwidth(HsChar ucs)
140+HsInt builtin_wcwidth(HsChar ucs)
123{
141{
124 /* sorted list of non-overlapping intervals of non-spacing characters */
142 /* sorted list of non-overlapping intervals of non-spacing characters */
125 /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
143 /* generated by "uniset +cat=Me +cat=Mn +cat=Cf -00AD +1160-11FF +200B c" */
@@ -202,3 +220,99 @@ HsInt vty_mk_wcwidth(HsChar ucs)
202 (ucs >= 0x20000 && ucs <= 0x2fffd) ||
220 (ucs >= 0x20000 && ucs <= 0x2fffd) ||
203 (ucs >= 0x30000 && ucs <= 0x3fffd)));
221 (ucs >= 0x30000 && ucs <= 0x3fffd)));
204}
222}
223+
224+// Return the width, in terminal cells, of the specified character.
225+//
226+// If the global custom width table is present, that table will be
227+// consulted for the character's width. If the character is not in
228+// the table, zero will be returned. If the custom width table is not
229+// present, the built-in width table will be used.
230+HsInt vty_mk_wcwidth(HsChar ch)
231+{
232+ if (custom_table != NULL) {
233+ if (ch >= 0 && ch < custom_table_size) {
234+ return custom_table[ch];
235+ } else {
236+ return 0;
237+ }
238+ } else {
239+ return builtin_wcwidth(ch);
240+ }
241+}
242+
243+// Initialize a custom character width table.
244+//
245+// This allocates a new character width table of the specified size
246+// (in characters). If a custom table has already been allocated, this
247+// returns 1. Otherwise it allocates a new table, initializes all of its
248+// entries to zero, and returns zero.
249+//
250+// Note that this does *not* mark the table as ready for use. Until the
251+// table is marked ready, it will not be used by vty_mk_wcwidth. To mark
252+// the table as ready, call vty_activate_custom_table() after the table
253+// has been set up with calls to vty_set_custom_table_range.
254+int vty_init_custom_table(int size)
255+{
256+ if (custom_table == NULL) {
257+ if (size > 0 && size <= MAX_CUSTOM_TABLE_SIZE) {
258+ custom_table_ready = 0;
259+ custom_table = malloc(size);
260+ bzero(custom_table, size);
261+ custom_table_size = size;
262+ return 0;
263+ } else {
264+ return 1;
265+ }
266+ } else {
267+ return 1;
268+ }
269+}
270+
271+// Set the specified character range in the custom width table to the
272+// specified width.
273+//
274+// This function sets 'width' as the character width for all entries
275+// in the custom character table starting at the 'start' entry and
276+// including all entries up to and including 'start + size - 1'.
277+//
278+// If this succeeds, it returns zero. If it fails, it returns 1. It
279+// fails if the table is not allocated, marked as ready (i.e. it is in
280+// use and has already been populated), or if the start or size values
281+// are not in bounds for the table.
282+int vty_set_custom_table_range(uint32_t start, uint32_t size, uint8_t width)
283+{
284+ if (custom_table == NULL) {
285+ return 1;
286+ } else if ((start + size - 1) >= custom_table_size) {
287+ return 1;
288+ } else if (custom_table_ready) {
289+ return 1;
290+ } else {
291+ memset(custom_table + start, (uint8_t) width, size);
292+ return 0;
293+ }
294+}
295+
296+// Mark the allocated custom character width table as ready for use.
297+//
298+// After this call, further calls to vty_set_custom_table_range will
299+// fail.
300+//
301+// This function returns 0 if it succeeds. If it fails, it returns 1.
302+// It fails if the custom table is already ready or if it has not been
303+// allocated.
304+int vty_activate_custom_table()
305+{
306+ if (custom_table_ready || (custom_table == NULL)) {
307+ return 1;
308+ } else {
309+ custom_table_ready = 1;
310+ return 0;
311+ }
312+}
313+
314+// Returns whether a custom character width table has been marked ready.
315+int vty_custom_table_ready()
316+{
317+ return ((custom_table != NULL) && custom_table_ready);
318+}
src/Graphics/Vty/UnicodeWidthTable/Install.hsnew file+69
@@ -0,0 +1,69 @@
1+{-# LANGUAGE ForeignFunctionInterface #-}
2+module Graphics.Vty.UnicodeWidthTable.Install
3+ ( installUnicodeWidthTable
4+
5+ , isCustomTableReady
6+ )
7+where
8+
9+import Control.Monad (when, forM_)
10+import Data.Word (Word8, Word32)
11+
12+import Graphics.Vty.UnicodeWidthTable.Types
13+
14+foreign import ccall unsafe "vty_init_custom_table"
15+ initCustomTable :: Int -> IO Int
16+
17+foreign import ccall unsafe "vty_set_custom_table_range"
18+ setCustomTableRange :: Word32 -> Word32 -> Word8 -> IO Int
19+
20+foreign import ccall unsafe "vty_activate_custom_table"
21+ activateCustomTable :: IO Int
22+
23+-- | Returns 1 if and only if a custom table has been allocated and
24+-- marked as ready for use. Returns 0 otherwise.
25+foreign import ccall unsafe "vty_custom_table_ready"
26+ isCustomTableReady :: IO Int
27+
28+-- This is the size of the allocated custom character width table, in
29+-- character slots. It's important that this be large enough to hold all
30+-- possible Unicode character values. At the time of this writing, the
31+-- valid Unicode range is 0 - 0x10ffff, hence this value.
32+tableSize :: Int
33+tableSize = 0x110000
34+
35+-- | Install a custom unicode character width table.
36+--
37+-- This affects the behavior of the 'wcwidth' function and functions
38+-- that call it. It does so by changing global state available to the C
39+-- implementation of 'wcwidth'. To ensure that your program gets consistent
40+-- results from evaluating calls to 'wcwidth', the installation of a
41+-- custom table should be performed before you call 'wcwidth' in your
42+-- program. This is best done at Vty startup. It's also important to
43+-- note that once a custom table has been installed, it is permanent for
44+-- the life of the process. No new table can be installed, and the new
45+-- custom table cannot be removed.
46+--
47+-- If this function fails for any reason -- if the table cannot be
48+-- installed or is invalid, or if a custom table already exists -- this
49+-- will raise an exception by calling 'error'.
50+installUnicodeWidthTable :: UnicodeWidthTable -> IO ()
51+installUnicodeWidthTable table = do
52+ initResult <- initCustomTable tableSize
53+ when (initResult /= 0) $
54+ error $ "installUnicodeWidthTable: error initializing " <>
55+ "custom table, status " <> show initResult
56+
57+ forM_ (unicodeWidthTableRanges table) $ \r -> do
58+ result <- setCustomTableRange (rangeStart r)
59+ (rangeSize r)
60+ (rangeColumns r)
61+
62+ when (result /= 0) $
63+ error $ "installUnicodeWidthTable: error installing range " <>
64+ show r <> ", status " <> show result
65+
66+ actResult <- activateCustomTable
67+ when (actResult /= 0) $
68+ error $ "installUnicodeWidthTable: error activating custom " <>
69+ "table, status " <> show actResult
vty.cabal+2−1
@@ -104,6 +104,7 @@ library
104 Graphics.Vty.UnicodeWidthTable.Types
104 Graphics.Vty.UnicodeWidthTable.Types
105 Graphics.Vty.UnicodeWidthTable.IO
105 Graphics.Vty.UnicodeWidthTable.IO
106 Graphics.Vty.UnicodeWidthTable.Query
106 Graphics.Vty.UnicodeWidthTable.Query
107+ Graphics.Vty.UnicodeWidthTable.Install
107
108
108 other-modules: Graphics.Vty.Attributes.Color240
109 other-modules: Graphics.Vty.Attributes.Color240
109 Graphics.Vty.Debug.Image
110 Graphics.Vty.Debug.Image
@@ -130,7 +131,7 @@ executable vty-build-table
130 hs-source-dirs: tools
131 hs-source-dirs: tools
131
132
132 default-language: Haskell2010
133 default-language: Haskell2010
133− ghc-options: -threaded
134+ ghc-options: -threaded -Wall
134
135
135 build-depends: vty,
136 build-depends: vty,
136 base >= 4.8 && < 5
137 base >= 4.8 && < 5