summaryrefslogtreecommitdiff
path: root/src/lib/efl
diff options
context:
space:
mode:
authorDaniel Hirt <hirt.danny@gmail.com>2017-09-25 19:21:21 +0300
committerDaniel Hirt <hirt.danny@gmail.com>2017-09-28 19:32:02 +0300
commit69d0646b33f932194a59f1f3499c45591b92be96 (patch)
tree7ee1f7b35dcaca10224e0ab787df34dfd5f298b9 /src/lib/efl
parentbc8b2857c1c1270d32e1d1014ca93631e7f5dea7 (diff)
Efl text: add Efl.Text.Markup interface
Adds basic markup operations for text objects, and implements it in Efl.Canvas.Text. Also, this adds the Efl.Text.Markup_Util class. This utility class allows basic text-markup conversions. @feature
Diffstat (limited to 'src/lib/efl')
-rw-r--r--src/lib/efl/Efl.h2
-rw-r--r--src/lib/efl/interfaces/efl_interfaces_main.c1
-rw-r--r--src/lib/efl/interfaces/efl_text_markup.eo21
-rw-r--r--src/lib/efl/interfaces/efl_text_markup_util.c500
-rw-r--r--src/lib/efl/interfaces/efl_text_markup_util.eo30
5 files changed, 554 insertions, 0 deletions
diff --git a/src/lib/efl/Efl.h b/src/lib/efl/Efl.h
index 82a1e3d460..1b5a9bcfe7 100644
--- a/src/lib/efl/Efl.h
+++ b/src/lib/efl/Efl.h
@@ -163,6 +163,8 @@ typedef Efl_Gfx_Path_Command_Type Efl_Gfx_Path_Command;
163#include "interfaces/efl_text_format.eo.h" 163#include "interfaces/efl_text_format.eo.h"
164#include "interfaces/efl_text_cursor.eo.h" 164#include "interfaces/efl_text_cursor.eo.h"
165#include "interfaces/efl_text_annotate.eo.h" 165#include "interfaces/efl_text_annotate.eo.h"
166#include "interfaces/efl_text_markup.eo.h"
167#include "interfaces/efl_text_markup_util.eo.h"
166 168
167#else 169#else
168 170
diff --git a/src/lib/efl/interfaces/efl_interfaces_main.c b/src/lib/efl/interfaces/efl_interfaces_main.c
index ded13b6ece..fc80036fb4 100644
--- a/src/lib/efl/interfaces/efl_interfaces_main.c
+++ b/src/lib/efl/interfaces/efl_interfaces_main.c
@@ -19,6 +19,7 @@
19#include "interfaces/efl_text_format.eo.c" 19#include "interfaces/efl_text_format.eo.c"
20#include "interfaces/efl_text_cursor.eo.c" 20#include "interfaces/efl_text_cursor.eo.c"
21#include "interfaces/efl_text_annotate.eo.c" 21#include "interfaces/efl_text_annotate.eo.c"
22#include "interfaces/efl_text_markup.eo.c"
22 23
23#include "interfaces/efl_gfx.eo.c" 24#include "interfaces/efl_gfx.eo.c"
24#include "interfaces/efl_gfx_buffer.eo.c" 25#include "interfaces/efl_gfx_buffer.eo.c"
diff --git a/src/lib/efl/interfaces/efl_text_markup.eo b/src/lib/efl/interfaces/efl_text_markup.eo
new file mode 100644
index 0000000000..99ea34b4ba
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_text_markup.eo
@@ -0,0 +1,21 @@
1interface Efl.Text.Markup(Efl.Text.Cursor) {
2 [[Markup data that populates the text object's style and format
3
4 @since 1.21
5 ]]
6 methods {
7 @property markup {
8 values {
9 markup: string; [[The markup-text representation set to this text.]]
10 }
11 }
12 cursor_markup_insert {
13 [[Inserts a markup text to the text object in a given cursor position]]
14 params {
15 cur: ptr(Efl.Text.Cursor.Cursor); [[Cursor position to insert markup]]
16 @in markup: string; [[The markup text to insert]]
17 }
18 }
19 }
20}
21
diff --git a/src/lib/efl/interfaces/efl_text_markup_util.c b/src/lib/efl/interfaces/efl_text_markup_util.c
new file mode 100644
index 0000000000..9c8a9cf55d
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_text_markup_util.c
@@ -0,0 +1,500 @@
1#include "config.h"
2#include "Efl.h"
3
4#define MY_CLASS EFL_TEXT_MARKUP_UTIL_CLASS
5
6#define ERR(...) EINA_LOG_DOM_ERR(EINA_LOG_DOMAIN_DEFAULT, __VA_ARGS__)
7
8#define _REPLACEMENT_CHAR 0xFFFC
9#define _PARAGRAPH_SEPARATOR 0x2029
10#define _NEWLINE '\n'
11#define _TAB '\t'
12
13#define _REPLACEMENT_CHAR_UTF8 "\xEF\xBF\xBC"
14#define _PARAGRAPH_SEPARATOR_UTF8 "\xE2\x80\xA9"
15#define _NEWLINE_UTF8 "\n"
16#define _TAB_UTF8 "\t"
17#define EVAS_TEXTBLOCK_IS_VISIBLE_FORMAT_CHAR(ch) \
18 (((ch) == _REPLACEMENT_CHAR) || \
19 ((ch) == _NEWLINE) || \
20 ((ch) == _TAB) || \
21 ((ch) == _PARAGRAPH_SEPARATOR))
22
23#define _IS_TAB(item) \
24 (!strcmp(item, "tab") || !strcmp(item, "\t") || !strcmp(item, "\\t"))
25
26#define _IS_LINE_SEPARATOR(item) \
27 (!strcmp(item, "br") || !strcmp(item, "\n") || !strcmp(item, "\\n"))
28
29#define _IS_PARAGRAPH_SEPARATOR_SIMPLE(item) \
30 (!strcmp(item, "ps"))
31
32#define _IS_PARAGRAPH_SEPARATOR(o, item) \
33 (_IS_PARAGRAPH_SEPARATOR_SIMPLE(item) || \
34 (o->legacy_newline && _IS_LINE_SEPARATOR(item))) /* Paragraph separator */
35
36static void
37_markup_get_text_utf8_append(Eina_Strbuf *sbuf, const char *text)
38{
39 int ch, pos = 0, pos2 = 0;
40
41 for (;;)
42 {
43 pos = pos2;
44 ch = eina_unicode_utf8_next_get(text, &pos2);
45 if ((ch <= 0) || (pos2 <= 0)) break;
46
47 if (ch == _NEWLINE)
48 eina_strbuf_append(sbuf, "<br/>");
49 else if (ch == _TAB)
50 eina_strbuf_append(sbuf, "<tab/>");
51 else if (ch == '<')
52 eina_strbuf_append(sbuf, "&lt;");
53 else if (ch == '>')
54 eina_strbuf_append(sbuf, "&gt;");
55 else if (ch == '&')
56 eina_strbuf_append(sbuf, "&amp;");
57 else if (ch == '"')
58 eina_strbuf_append(sbuf, "&quot;");
59 else if (ch == _PARAGRAPH_SEPARATOR)
60 eina_strbuf_append(sbuf, "<ps/>");
61 else if (ch == _REPLACEMENT_CHAR)
62 eina_strbuf_append(sbuf, "&#xfffc;");
63 else if (ch != '\r')
64 {
65 eina_strbuf_append_length(sbuf, text + pos, pos2 - pos);
66 }
67 }
68}
69
70EOLIAN static char*
71_efl_text_markup_util_text_to_markup(Eo *class EINA_UNUSED,
72 void *_pd EINA_UNUSED, const char *text)
73{
74 Eina_Strbuf *sbuf;
75 char *str = NULL;
76
77 if (!text) return NULL;
78
79 sbuf = eina_strbuf_new();
80
81 _markup_get_text_utf8_append(sbuf, text);
82
83 str = eina_strbuf_string_steal(sbuf);
84 eina_strbuf_free(sbuf);
85 return str;
86}
87
88/* table of html escapes (that i can find) this should be ordered with the
89 * most common first as it's a linear search to match - no hash for this.
90 *
91 * these are stored as one large string and one additional array that
92 * contains the offsets to the tokens for space efficiency.
93 */
94/**
95 * @internal
96 * @var escape_strings[]
97 * This string consists of NULL terminated pairs of strings, the first of
98 * every pair is an escape and the second is the value of the escape.
99 */
100static const char escape_strings[] =
101/* most common escaped stuff */
102"&quot;\0" "\x22\0"
103"&amp;\0" "\x26\0"
104"&apos;\0" "\x27\0"
105"&lt;\0" "\x3c\0"
106"&gt;\0" "\x3e\0"
107/* all the rest */
108"&nbsp;\0" "\xc2\xa0\0"
109"&iexcl;\0" "\xc2\xa1\0"
110"&cent;\0" "\xc2\xa2\0"
111"&pound;\0" "\xc2\xa3\0"
112"&curren;\0" "\xc2\xa4\0"
113"&yen;\0" "\xc2\xa5\0"
114"&brvbar;\0" "\xc2\xa6\0"
115"&sect;\0" "\xc2\xa7\0"
116"&uml;\0" "\xc2\xa8\0"
117"&copy;\0" "\xc2\xa9\0"
118"&ordf;\0" "\xc2\xaa\0"
119"&laquo;\0" "\xc2\xab\0"
120"&not;\0" "\xc2\xac\0"
121"&shy;\0" "\xc2\xad\0"
122"&reg;\0" "\xc2\xae\0"
123"&macr;\0" "\xc2\xaf\0"
124"&deg;\0" "\xc2\xb0\0"
125"&plusmn;\0" "\xc2\xb1\0"
126"&sup2;\0" "\xc2\xb2\0"
127"&sup3;\0" "\xc2\xb3\0"
128"&acute;\0" "\xc2\xb4\0"
129"&micro;\0" "\xc2\xb5\0"
130"&para;\0" "\xc2\xb6\0"
131"&middot;\0" "\xc2\xb7\0"
132"&cedil;\0" "\xc2\xb8\0"
133"&sup1;\0" "\xc2\xb9\0"
134"&ordm;\0" "\xc2\xba\0"
135"&raquo;\0" "\xc2\xbb\0"
136"&frac14;\0" "\xc2\xbc\0"
137"&frac12;\0" "\xc2\xbd\0"
138"&frac34;\0" "\xc2\xbe\0"
139"&iquest;\0" "\xc2\xbf\0"
140"&Agrave;\0" "\xc3\x80\0"
141"&Aacute;\0" "\xc3\x81\0"
142"&Acirc;\0" "\xc3\x82\0"
143"&Atilde;\0" "\xc3\x83\0"
144"&Auml;\0" "\xc3\x84\0"
145"&Aring;\0" "\xc3\x85\0"
146"&Aelig;\0" "\xc3\x86\0"
147"&Ccedil;\0" "\xc3\x87\0"
148"&Egrave;\0" "\xc3\x88\0"
149"&Eacute;\0" "\xc3\x89\0"
150"&Ecirc;\0" "\xc3\x8a\0"
151"&Euml;\0" "\xc3\x8b\0"
152"&Igrave;\0" "\xc3\x8c\0"
153"&Iacute;\0" "\xc3\x8d\0"
154"&Icirc;\0" "\xc3\x8e\0"
155"&Iuml;\0" "\xc3\x8f\0"
156"&Eth;\0" "\xc3\x90\0"
157"&Ntilde;\0" "\xc3\x91\0"
158"&Ograve;\0" "\xc3\x92\0"
159"&Oacute;\0" "\xc3\x93\0"
160"&Ocirc;\0" "\xc3\x94\0"
161"&Otilde;\0" "\xc3\x95\0"
162"&Ouml;\0" "\xc3\x96\0"
163"&times;\0" "\xc3\x97\0"
164"&Oslash;\0" "\xc3\x98\0"
165"&Ugrave;\0" "\xc3\x99\0"
166"&Uacute;\0" "\xc3\x9a\0"
167"&Ucirc;\0" "\xc3\x9b\0"
168"&Yacute;\0" "\xc3\x9d\0"
169"&Thorn;\0" "\xc3\x9e\0"
170"&szlig;\0" "\xc3\x9f\0"
171"&agrave;\0" "\xc3\xa0\0"
172"&aacute;\0" "\xc3\xa1\0"
173"&acirc;\0" "\xc3\xa2\0"
174"&atilde;\0" "\xc3\xa3\0"
175"&auml;\0" "\xc3\xa4\0"
176"&aring;\0" "\xc3\xa5\0"
177"&aelig;\0" "\xc3\xa6\0"
178"&ccedil;\0" "\xc3\xa7\0"
179"&egrave;\0" "\xc3\xa8\0"
180"&eacute;\0" "\xc3\xa9\0"
181"&ecirc;\0" "\xc3\xaa\0"
182"&euml;\0" "\xc3\xab\0"
183"&igrave;\0" "\xc3\xac\0"
184"&iacute;\0" "\xc3\xad\0"
185"&icirc;\0" "\xc3\xae\0"
186"&iuml;\0" "\xc3\xaf\0"
187"&eth;\0" "\xc3\xb0\0"
188"&ntilde;\0" "\xc3\xb1\0"
189"&ograve;\0" "\xc3\xb2\0"
190"&oacute;\0" "\xc3\xb3\0"
191"&ocirc;\0" "\xc3\xb4\0"
192"&otilde;\0" "\xc3\xb5\0"
193"&ouml;\0" "\xc3\xb6\0"
194"&divide;\0" "\xc3\xb7\0"
195"&oslash;\0" "\xc3\xb8\0"
196"&ugrave;\0" "\xc3\xb9\0"
197"&uacute;\0" "\xc3\xba\0"
198"&ucirc;\0" "\xc3\xbb\0"
199"&uuml;\0" "\xc3\xbc\0"
200"&yacute;\0" "\xc3\xbd\0"
201"&thorn;\0" "\xc3\xbe\0"
202"&yuml;\0" "\xc3\xbf\0"
203"&alpha;\0" "\xce\x91\0"
204"&beta;\0" "\xce\x92\0"
205"&gamma;\0" "\xce\x93\0"
206"&delta;\0" "\xce\x94\0"
207"&epsilon;\0" "\xce\x95\0"
208"&zeta;\0" "\xce\x96\0"
209"&eta;\0" "\xce\x97\0"
210"&theta;\0" "\xce\x98\0"
211"&iota;\0" "\xce\x99\0"
212"&kappa;\0" "\xce\x9a\0"
213"&lambda;\0" "\xce\x9b\0"
214"&mu;\0" "\xce\x9c\0"
215"&nu;\0" "\xce\x9d\0"
216"&xi;\0" "\xce\x9e\0"
217"&omicron;\0" "\xce\x9f\0"
218"&pi;\0" "\xce\xa0\0"
219"&rho;\0" "\xce\xa1\0"
220"&sigma;\0" "\xce\xa3\0"
221"&tau;\0" "\xce\xa4\0"
222"&upsilon;\0" "\xce\xa5\0"
223"&phi;\0" "\xce\xa6\0"
224"&chi;\0" "\xce\xa7\0"
225"&psi;\0" "\xce\xa8\0"
226"&omega;\0" "\xce\xa9\0"
227"&hellip;\0" "\xe2\x80\xa6\0"
228"&euro;\0" "\xe2\x82\xac\0"
229"&larr;\0" "\xe2\x86\x90\0"
230"&uarr;\0" "\xe2\x86\x91\0"
231"&rarr;\0" "\xe2\x86\x92\0"
232"&darr;\0" "\xe2\x86\x93\0"
233"&harr;\0" "\xe2\x86\x94\0"
234"&larr;\0" "\xe2\x87\x90\0"
235"&rarr;\0" "\xe2\x87\x92\0"
236"&forall;\0" "\xe2\x88\x80\0"
237"&exist;\0" "\xe2\x88\x83\0"
238"&nabla;\0" "\xe2\x88\x87\0"
239"&prod;\0" "\xe2\x88\x8f\0"
240"&sum;\0" "\xe2\x88\x91\0"
241"&and;\0" "\xe2\x88\xa7\0"
242"&or;\0" "\xe2\x88\xa8\0"
243"&int;\0" "\xe2\x88\xab\0"
244"&ne;\0" "\xe2\x89\xa0\0"
245"&equiv;\0" "\xe2\x89\xa1\0"
246"&oplus;\0" "\xe2\x8a\x95\0"
247"&perp;\0" "\xe2\x8a\xa5\0"
248"&dagger;\0" "\xe2\x80\xa0\0"
249"&Dagger;\0" "\xe2\x80\xa1\0"
250"&bull;\0" "\xe2\x80\xa2\0"
251"&zwnj;\0" "\xe2\x80\x8c\0"
252"&zwj;\0" "\xe2\x80\x8d\0"
253"&lrm;\0" "\xe2\x80\x8e\0"
254"&rlm;\0" "\xe2\x80\x8f\0"
255;
256
257static inline void
258_escaped_advance_after_end_of_string(const char **p_buf)
259{
260 while (**p_buf != 0) (*p_buf)++;
261 (*p_buf)++;
262}
263
264static inline int
265_escaped_is_eq_and_advance(const char *s, const char *s_end,
266 const char **p_m, const char *m_end)
267{
268 Eina_Bool reached_end;
269 for (;((s < s_end) && (*p_m < m_end)); s++, (*p_m)++)
270 {
271 if (*s != **p_m)
272 {
273 _escaped_advance_after_end_of_string(p_m);
274 return 0;
275 }
276 }
277
278 reached_end = !**p_m;
279 if (*p_m < m_end)
280 _escaped_advance_after_end_of_string(p_m);
281
282 return ((s == s_end) && reached_end);
283}
284
285static inline const char *
286_escaped_char_get(const char *s, const char *s_end)
287{
288 /* Handle numeric escape codes. */
289 if (s[1] == '#')
290 {
291 static char utf8_escape[7]; /* Support up to 6 bytes utf8 */
292 char ustr[10];
293 Eina_Unicode uchar[2] = { 0, 0 };
294 char *utf8_char;
295 size_t len = 0;
296 int base = 10;
297 s += 2; /* Skip "&#" */
298
299 if ((*s == 'x') && (*s == 'X'))
300 {
301 s++;
302 base = 16;
303 }
304
305 len = s_end - s;
306 if (len > sizeof(ustr))
307 len = sizeof(ustr);
308
309 memcpy(ustr, s, len);
310 ustr[len - 1] = '\0';
311 uchar[0] = strtol(ustr, NULL, base);
312
313 if (uchar[0] == 0)
314 return NULL;
315
316 utf8_char = eina_unicode_unicode_to_utf8(uchar, NULL);
317 // eina_unicode_unicode_to_utf8() always creates a string that
318 // is nul terminated - guaranteed
319 if (utf8_char)
320 {
321 strcpy(utf8_escape, utf8_char);
322 free(utf8_char);
323 }
324
325 return utf8_escape;
326 }
327 else
328 {
329 const char *map_itr, *map_end;
330
331 map_itr = escape_strings;
332 map_end = map_itr + sizeof(escape_strings);
333
334 while (map_itr < map_end)
335 {
336 if (_escaped_is_eq_and_advance(s, s_end, &map_itr, map_end))
337 return map_itr;
338 if (map_itr < map_end)
339 _escaped_advance_after_end_of_string(&map_itr);
340 }
341 }
342
343 return NULL;
344}
345
346static char *
347_text_util_markup_to_text(const char *text)
348{
349 Eina_Strbuf *sbuf;
350 char *s, *p, *ret;
351 char *tag_start, *tag_end, *esc_start, *esc_end;
352
353 if (!text) return NULL;
354
355 tag_start = tag_end = esc_start = esc_end = NULL;
356 sbuf = eina_strbuf_new();
357 p = (char *)text;
358 s = p;
359 /* This loop goes through all of the mark up text until it finds format
360 * tags, escape sequences or the terminating NULL. When it finds either
361 * of those, it appends the text found up until that point to the textblock
362 * proccesses whatever found. It repeats itself until the termainating
363 * NULL is reached. */
364 for (;;)
365 {
366 /* If we got to the end of string or just finished/started tag
367 * or escape sequence handling. */
368 if ((*p == 0) ||
369 (tag_end) || (esc_end) ||
370 (tag_start) || (esc_start))
371 {
372 if (tag_end)
373 {
374 /* If we reached to a tag ending, analyze the tag */
375 char *ttag;
376 size_t ttag_len;
377
378 tag_start++; /* Skip the < */
379 tag_end--; /* Skip the > */
380 if ((tag_end > tag_start) && (*(tag_end - 1) == '/'))
381 {
382 tag_end --; /* Skip the terminating '/' */
383 while (*(tag_end - 1) == ' ')
384 tag_end--; /* skip trailing ' ' */
385 }
386
387 ttag_len = tag_end - tag_start;
388
389 ttag = malloc(ttag_len + 1);
390 if (ttag)
391 {
392 memcpy(ttag, tag_start, ttag_len);
393 ttag[ttag_len] = 0;
394
395 if (_IS_PARAGRAPH_SEPARATOR_SIMPLE(ttag))
396 eina_strbuf_append(sbuf, _PARAGRAPH_SEPARATOR_UTF8);
397 else if (_IS_LINE_SEPARATOR(ttag))
398 eina_strbuf_append(sbuf, _NEWLINE_UTF8);
399 else if (_IS_TAB(ttag))
400 eina_strbuf_append(sbuf, _TAB_UTF8);
401 else if (!strncmp(ttag, "item", 4))
402 eina_strbuf_append(sbuf, _REPLACEMENT_CHAR_UTF8);
403
404 free(ttag);
405 }
406 tag_start = tag_end = NULL;
407 }
408 else if (esc_end)
409 {
410 const char *escape;
411
412 escape = _escaped_char_get(esc_start, esc_end + 1);
413 if (escape) eina_strbuf_append(sbuf, escape);
414 esc_start = esc_end = NULL;
415 }
416 else if (*p == 0)
417 {
418 if (s)
419 {
420 eina_strbuf_append_length(sbuf, s, p - s);
421 s = NULL;
422 }
423 else
424 {
425 ERR("There is a invalid markup tag at positoin '%u'. Please check the text.", (unsigned int) (p - text));
426 }
427 }
428 if (*p == 0)
429 break;
430 }
431 if (*p == '<')
432 {
433 if (!esc_start)
434 {
435 /* Append the text prior to this to the textblock and
436 * mark the start of the tag */
437 tag_start = p;
438 tag_end = NULL;
439 if (s)
440 {
441 eina_strbuf_append_length(sbuf, s, p - s);
442 s = NULL;
443 }
444 else
445 {
446 ERR("There is a invalid markup tag at positoin '%u'. Please check the text.", (unsigned int) (p - text));
447 }
448 }
449 }
450 else if (*p == '>')
451 {
452 if (tag_start)
453 {
454 tag_end = p + 1;
455 s = p + 1;
456 }
457 }
458 else if (*p == '&')
459 {
460 if (!tag_start)
461 {
462 /* Append the text prior to this to the textblock and mark
463 * the start of the escape sequence */
464 esc_start = p;
465 esc_end = NULL;
466 if (s)
467 {
468 eina_strbuf_append_length(sbuf, s, p - s);
469 s = NULL;
470 }
471 else
472 {
473 ERR("There is a invalid markup tag at positoin '%u'. Please check the text.", (unsigned int) (p - text));
474 }
475 }
476 }
477 else if (*p == ';')
478 {
479 if (esc_start)
480 {
481 esc_end = p;
482 s = p + 1;
483 }
484 }
485 p++;
486 }
487
488 ret = eina_strbuf_string_steal(sbuf);
489 eina_strbuf_free(sbuf);
490 return ret;
491}
492
493static EOLIAN char*
494_efl_text_markup_util_markup_to_text(Eo *class EINA_UNUSED,
495 void *_pd EINA_UNUSED, const char *text)
496{
497 return _text_util_markup_to_text(text);
498}
499
500#include "interfaces/efl_text_markup_util.eo.c"
diff --git a/src/lib/efl/interfaces/efl_text_markup_util.eo b/src/lib/efl/interfaces/efl_text_markup_util.eo
new file mode 100644
index 0000000000..304b2cacf9
--- /dev/null
+++ b/src/lib/efl/interfaces/efl_text_markup_util.eo
@@ -0,0 +1,30 @@
1class Efl.Text.Markup_Util () {
2 [[Utility class for markup, such as conversions
3
4 @since 1.21.
5 ]]
6 data: null;
7 methods {
8 text_to_markup @class {
9 [[Converts a given (UTF-8) text to a markup-compatible string.
10 This is used mainly to set a plain text with the $.markup_set
11 property.
12 ]]
13 params {
14 @in text: string; [[The text (UTF-8) to convert to markup]]
15 }
16 return: mstring @owned; [[The markup representation of given text]]
17 }
18 markup_to_text @class {
19 [[Converts a given (UTF-8) text to a markup-compatible string.
20 This is used mainly to set a plain text with the $.markup_set
21 property.
22 ]]
23 params {
24 @in text: string; [[The markup-text to convert to text (UTF-8)]]
25 }
26 return: mstring @owned; [[The text representation of given format]]
27 }
28 }
29}
30