diff --git a/src/environment.c b/src/environment.c index e2e7e1d..776e785 100644 --- a/src/environment.c +++ b/src/environment.c @@ -376,7 +376,7 @@ env_t *global_env(void) {"map", "Text$map", "func(text:Text, pattern:Pattern, fn:func(match:Match -> Text), recursive=yes -> Text)"}, {"matches", "Text$matches", "func(text:Text, pattern:Pattern -> [Text]?)"}, {"middle_pad", "Text$middle_pad", "func(text:Text, count:Int, pad=' ', language='C' -> Text)"}, - {"quoted", "Text$quoted", "func(text:Text, color=no -> Text)"}, + {"quoted", "Text$quoted", "func(text:Text, color=no, quotation_mark='\"' -> Text)"}, {"repeat", "Text$repeat", "func(text:Text, count:Int -> Text)"}, {"replace", "Text$replace", "func(text:Text, pattern:Pattern, replacement:Text, backref=$/\\/, recursive=yes -> Text)"}, {"replace_all", "Text$replace_all", "func(text:Text, replacements:{Pattern,Text}, backref=$/\\/, recursive=yes -> Text)"}, diff --git a/src/stdlib/c_strings.c b/src/stdlib/c_strings.c index 7987a23..9d0f281 100644 --- a/src/stdlib/c_strings.c +++ b/src/stdlib/c_strings.c @@ -16,7 +16,7 @@ public Text_t CString$as_text(const void *c_string, bool colorize, const TypeInf (void)info; if (!c_string) return Text("CString"); Text_t text = Text$from_str(*(const char**)c_string); - return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), Text$quoted(text, colorize), Text(")")); + return Text$concat(colorize ? Text("\x1b[34mCString\x1b[m(") : Text("CString("), Text$quoted(text, colorize, Text("\"")), Text(")")); } public Text_t CString$as_text_simple(const char *str) diff --git a/src/stdlib/patterns.c b/src/stdlib/patterns.c index e274cba..b7891f8 100644 --- a/src/stdlib/patterns.c +++ b/src/stdlib/patterns.c @@ -1271,12 +1271,30 @@ public Pattern_t Pattern$escape_text(Text_t text) return ret; } +static Text_t Pattern$as_text(const void *obj, bool colorize, const TypeInfo_t *info) +{ + (void)info; + if (!obj) return Text("Pattern"); + + Pattern_t pat = *(Pattern_t*)obj; + Text_t quote = Text$has(pat, Pattern("/")) && !Text$has(pat, Pattern("|")) ? Text("|") : Text("/"); + return Text$concat( colorize ? Text("\x1b[1m$\033[m") : Text("$"), Text$quoted(pat, colorize, quote)); +} + public const TypeInfo_t Pattern$info = { .size=sizeof(Pattern_t), .align=__alignof__(Pattern_t), .tag=TextInfo, .TextInfo={.lang="Pattern"}, - .metamethods=Text$metamethods, + .metamethods={ + .as_text=Pattern$as_text, + .hash=Text$hash, + .compare=Text$compare, + .equal=Text$equal, + .is_none=Text$is_none, + .serialize=Text$serialize, + .deserialize=Text$deserialize, + }, }; static const TypeInfo_t _text_array = { diff --git a/src/stdlib/text.c b/src/stdlib/text.c index 65290bb..27acdfa 100644 --- a/src/stdlib/text.c +++ b/src/stdlib/text.c @@ -70,7 +70,6 @@ #include "arrays.h" #include "integers.h" -#include "patterns.h" #include "tables.h" #include "text.h" @@ -1111,14 +1110,17 @@ public Text_t Text$title(Text_t text, Text_t language) return ret; } -static INLINE Text_t _quoted(Text_t text, bool colorize, char quote_char) +public Text_t Text$quoted(Text_t text, bool colorize, Text_t quotation_mark) { + if (quotation_mark.length != 1) + fail("Invalid quote text: ", quotation_mark, " (must have length == 1)"); + Text_t ret = colorize ? Text("\x1b[35m") : EMPTY_TEXT; - if (quote_char != '"' && quote_char != '\'' && quote_char != '`') + if (!Text$equal_values(quotation_mark, Text("\"")) && !Text$equal_values(quotation_mark, Text("'")) && !Text$equal_values(quotation_mark, Text("`"))) ret = concat2_assuming_safe(ret, Text("$")); - Text_t quote_text = Text$from_strn("e_char, 1); - ret = concat2_assuming_safe(ret, quote_text); + ret = concat2_assuming_safe(ret, quotation_mark); + int32_t quote_char = Text$get_grapheme(quotation_mark, 0); #define add_escaped(str) ({ if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[34;1m")); \ if (!just_escaped) ret = concat2_assuming_safe(ret, Text("$")); \ @@ -1171,7 +1173,7 @@ static INLINE Text_t _quoted(Text_t text, bool colorize, char quote_char) } default: { if (g == quote_char) { - ret = concat2_assuming_safe(ret, quote_text); + ret = concat2_assuming_safe(ret, quotation_mark); } else { ret = concat2_assuming_safe(ret, Text$slice(text, I(i+1), I(i+1))); just_escaped = false; @@ -1182,7 +1184,7 @@ static INLINE Text_t _quoted(Text_t text, bool colorize, char quote_char) } #undef add_escaped - ret = concat2_assuming_safe(ret, quote_text); + ret = concat2_assuming_safe(ret, quotation_mark); if (colorize) ret = concat2_assuming_safe(ret, Text("\x1b[m")); @@ -1195,44 +1197,40 @@ public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *i if (!vtext) return info && info->TextInfo.lang ? Text$from_str(info->TextInfo.lang) : Text("Text"); Text_t text = *(Text_t*)vtext; - char quote_char; - if (info == &Pattern$info) { - quote_char = Text$has(text, Pattern("/")) && !Text$has(text, Pattern("|")) ? '|' : '/'; - } else { - // Figure out the best quotation mark to use: - bool has_dollar = false, has_double_quote = false, has_backtick = false, - has_single_quote = false, needs_escapes = false; - TextIter_t state = NEW_TEXT_ITER_STATE(text); - for (int64_t i = 0; i < text.length; i++) { - int32_t g = Text$get_grapheme_fast(&state, i); - if (g == '$') { - has_dollar = true; - } else if (g == '"') { - has_double_quote = true; - } else if (g == '`') { - has_backtick = true; - } else if (g == (g & 0x7F) && (g == '\'' || g == '\n' || g == '\r' || g == '\t' || !isprint((char)g))) { - needs_escapes = true; - } + // Figure out the best quotation mark to use: + bool has_dollar = false, has_double_quote = false, has_backtick = false, + has_single_quote = false, needs_escapes = false; + TextIter_t state = NEW_TEXT_ITER_STATE(text); + for (int64_t i = 0; i < text.length; i++) { + int32_t g = Text$get_grapheme_fast(&state, i); + if (g == '$') { + has_dollar = true; + } else if (g == '"') { + has_double_quote = true; + } else if (g == '`') { + has_backtick = true; + } else if (g == (g & 0x7F) && (g == '\'' || g == '\n' || g == '\r' || g == '\t' || !isprint((char)g))) { + needs_escapes = true; } - - // If there's dollar signs and/or double quotes in the string, it would - // be nice to avoid needing to escape them by using single quotes, but - // only if we don't have single quotes or need to escape anything else - // (because single quotes don't have interpolation): - if ((has_dollar || has_double_quote) && !has_single_quote && !needs_escapes) - quote_char = '\''; - // If there is a double quote, but no backtick, we can save a bit of - // escaping by using backtick instead of double quote: - else if (has_double_quote && !has_backtick) - quote_char = '`'; - // Otherwise fall back to double quotes as the default quoting style: - else - quote_char = '"'; } - Text_t as_text = _quoted(text, colorize, quote_char); - if (info && info->TextInfo.lang && info != &Text$info && info != &Pattern$info) + Text_t quote; + // If there's dollar signs and/or double quotes in the string, it would + // be nice to avoid needing to escape them by using single quotes, but + // only if we don't have single quotes or need to escape anything else + // (because single quotes don't have interpolation): + if ((has_dollar || has_double_quote) && !has_single_quote && !needs_escapes) + quote = Text("'"); + // If there is a double quote, but no backtick, we can save a bit of + // escaping by using backtick instead of double quote: + else if (has_double_quote && !has_backtick) + quote = Text("`"); + // Otherwise fall back to double quotes as the default quoting style: + else + quote = Text("\""); + + Text_t as_text = Text$quoted(text, colorize, quote); + if (info && info->TextInfo.lang && info != &Text$info) as_text = Text$concat( colorize ? Text("\x1b[1m$") : Text("$"), Text$from_str(info->TextInfo.lang), @@ -1241,11 +1239,6 @@ public Text_t Text$as_text(const void *vtext, bool colorize, const TypeInfo_t *i return as_text; } -public Text_t Text$quoted(Text_t text, bool colorize) -{ - return _quoted(text, colorize, '"'); -} - public Text_t Text$join(Text_t glue, Array_t pieces) { if (pieces.length == 0) return EMPTY_TEXT; diff --git a/src/stdlib/text.h b/src/stdlib/text.h index e5c6a14..4acca8a 100644 --- a/src/stdlib/text.h +++ b/src/stdlib/text.h @@ -47,7 +47,7 @@ Text_t Text$upper(Text_t text, Text_t language); Text_t Text$lower(Text_t text, Text_t language); Text_t Text$title(Text_t text, Text_t language); Text_t Text$as_text(const void *text, bool colorize, const TypeInfo_t *info); -Text_t Text$quoted(Text_t str, bool colorize); +Text_t Text$quoted(Text_t str, bool colorize, Text_t quotation_mark); PUREFUNC bool Text$starts_with(Text_t text, Text_t prefix); PUREFUNC bool Text$ends_with(Text_t text, Text_t suffix); char *Text$as_c_string(Text_t text);