diff --git a/doc/lua_api.md b/doc/lua_api.md index 4020645cc..b08f7356d 100644 --- a/doc/lua_api.md +++ b/doc/lua_api.md @@ -3535,10 +3535,12 @@ Markup language used in `hypertext[]` elements uses tags that look like HTML tag The markup language is currently unstable and subject to change. Use with caution. Some tags can enclose text, they open with `` and close with ``. Tags can have attributes, in that case, attributes are in the opening tag in -form of a key/value separated with equal signs. Attribute values should not be quoted. +form of a key/value separated with equal signs. +Attribute values should be quoted using either " or '. -If you want to insert a literal greater-than sign or a backslash into the text, -you must escape it by preceding it with a backslash. +If you want to insert a literal greater-than, less-than, or a backslash into the text, +you must escape it by preceding it with a backslash. In a quoted attribute value, you +can insert a literal quote mark by preceding it with a backslash. These are the technically basic tags but see below for usual tags. Base tags are: diff --git a/games/devtest/mods/testformspec/formspec.lua b/games/devtest/mods/testformspec/formspec.lua index 758bad631..c2074e6e0 100644 --- a/games/devtest/mods/testformspec/formspec.lua +++ b/games/devtest/mods/testformspec/formspec.lua @@ -69,9 +69,9 @@ local hypertext_basic = [[A hypertext element This is a normal text. style test - - . - + + . + Tag test normal @@ -88,20 +88,20 @@ This is a normal text. Custom tag test - - - - + + + + color=green -Action: color=green -Action: hovercolor=yellow -Action URL: open URL +Action: color=green +Action: hovercolor=yellow +Action URL: open URL size=24 font=mono color=green font=mono size=24 action test -action +action img test Normal: diff --git a/src/gui/guiHyperText.cpp b/src/gui/guiHyperText.cpp index 3db6f0071..45e5d6e98 100644 --- a/src/gui/guiHyperText.cpp +++ b/src/gui/guiHyperText.cpp @@ -421,14 +421,16 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor) AttrsList attrs; while (c != L'>') { std::string attr_name = ""; - core::stringw attr_val = L""; + std::wstring attr_val = L""; + // Consume whitespace while (c == ' ') { c = text[++cursor]; if (c == L'\0' || c == L'=') return 0; } + // Read attribute name while (c != L' ' && c != L'=') { attr_name += (char)c; c = text[++cursor]; @@ -436,28 +438,51 @@ u32 ParsedText::parseTag(const wchar_t *text, u32 cursor) return 0; } + // Consume whitespace while (c == L' ') { c = text[++cursor]; if (c == L'\0' || c == L'>') return 0; } + // Skip equals if (c != L'=') return 0; - c = text[++cursor]; - if (c == L'\0') return 0; - while (c != L'>' && c != L' ') { - attr_val += c; + // Read optional quote + wchar_t quote_used = 0; + if (c == L'"' || c == L'\'') { + quote_used = c; c = text[++cursor]; if (c == L'\0') return 0; } - attrs[attr_name] = stringw_to_utf8(attr_val); + // Read attribute value + bool escape = false; + while (escape || (quote_used && c != quote_used) || (!quote_used && c != L'>' && c != L' ')) { + if (quote_used && !escape && c == L'\\') { + escape = true; + } else { + escape = false; + attr_val += c; + } + c = text[++cursor]; + if (c == L'\0') + return 0; + } + + // Remove quote + if (quote_used) { + if (c != quote_used) + return 0; + c = text[++cursor]; + } + + attrs[attr_name] = wide_to_utf8(attr_val); } ++cursor; // Last ">"