1
0
Fork 0
mirror of https://github.com/luanti-org/luanti.git synced 2025-09-30 19:22:14 +00:00

Add core.strip_escapes() (#16485)

This commit is contained in:
sfan5 2025-09-14 23:01:43 +02:00 committed by GitHub
parent cc6b56b034
commit d932f34693
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 52 additions and 17 deletions

View file

@ -695,6 +695,17 @@ int ModApiUtil::l_is_valid_player_name(lua_State *L)
return 1;
}
// strip_escapes(str)
int ModApiUtil::l_strip_escapes(lua_State *L)
{
NO_MAP_LOCK_REQUIRED;
auto s = readParam<std::string_view>(L, 1);
auto r = unescape_enriched(s);
lua_pushlstring(L, r.c_str(), r.size());
return 1;
}
void ModApiUtil::Initialize(lua_State *L, int top)
{
API_FCT(log);
@ -746,6 +757,7 @@ void ModApiUtil::Initialize(lua_State *L, int top)
API_FCT(urlencode);
API_FCT(is_valid_player_name);
API_FCT(strip_escapes);
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");
@ -780,6 +792,7 @@ void ModApiUtil::InitializeClient(lua_State *L, int top)
API_FCT(set_last_run_mod);
API_FCT(urlencode);
API_FCT(strip_escapes);
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");
@ -828,6 +841,7 @@ void ModApiUtil::InitializeAsync(lua_State *L, int top)
API_FCT(set_last_run_mod);
API_FCT(urlencode);
API_FCT(strip_escapes);
LuaSettings::create(L, g_settings, g_settings_path);
lua_setfield(L, top, "settings");

View file

@ -127,6 +127,9 @@ private:
// is_valid_player_name(name)
static int l_is_valid_player_name(lua_State *L);
// strip_escapes(str)
static int l_strip_escapes(lua_State *L);
public:
static void Initialize(lua_State *L, int top);
static void InitializeAsync(lua_State *L, int top);

View file

@ -17,7 +17,7 @@ namespace {
public:
MyScriptApi() : ScriptApiBase(ScriptingType::Async) {};
void init();
using ScriptApiBase::getStack;
using ScriptApiBase::getStack; // make public
};
}

View file

@ -335,6 +335,8 @@ void TestUtilities::testRemoveEscapes()
L"abc\x1b(escaped)def") == L"abcdef");
UASSERT(unescape_enriched<wchar_t>(
L"abc\x1b((escaped with parenthesis\\))def") == L"abcdef");
UASSERTEQ(auto, unescape_enriched("abc\x1b(not this\\\\)def"),
"abcdef");
UASSERT(unescape_enriched<wchar_t>(
L"abc\x1b(incomplete") == L"abc");
UASSERT(unescape_enriched<wchar_t>(
@ -342,6 +344,9 @@ void TestUtilities::testRemoveEscapes()
// Nested escapes not supported
UASSERT(unescape_enriched<wchar_t>(
L"abc\x1b(outer \x1b(inner escape)escape)def") == L"abcescape)def");
// Multiple
UASSERTEQ(auto, unescape_enriched("one\x1bX two \x1b(four)three"),
"one two three");
}
void TestUtilities::testWrapRows()

View file

@ -592,27 +592,25 @@ inline std::basic_string<T> unescape_string(const std::basic_string<T> &s)
*/
template <typename T>
[[nodiscard]]
std::basic_string<T> unescape_enriched(const std::basic_string<T> &s)
std::basic_string<T> unescape_enriched(std::basic_string_view<T> s)
{
std::basic_string<T> output;
output.reserve(s.size());
size_t i = 0;
while (i < s.length()) {
if (s[i] == '\x1b') {
if (s[i] == static_cast<T>('\x1b')) {
++i;
if (i == s.length()) continue;
if (s[i] == '(') {
if (i == s.length())
continue;
if (s[i] == static_cast<T>('(')) {
++i;
while (i < s.length() && s[i] != ')') {
if (s[i] == '\\') {
while (i < s.length() && s[i] != static_cast<T>(')')) {
if (s[i] == static_cast<T>('\\'))
++i;
}
++i;
}
++i;
} else {
++i;
}
++i;
continue;
}
output += s[i];
@ -621,6 +619,18 @@ std::basic_string<T> unescape_enriched(const std::basic_string<T> &s)
return output;
}
// (same templating issue here)
[[nodiscard]]
inline std::string unescape_enriched(std::string_view s)
{
return unescape_enriched<char>(s);
}
[[nodiscard]]
inline std::wstring unescape_enriched(std::wstring_view s)
{
return unescape_enriched<wchar_t>(s);
}
template <typename T>
[[nodiscard]]
std::vector<std::basic_string<T> > split(const std::basic_string<T> &s, T delim)