diff --git a/Source/lua/autocomplete.cpp b/Source/lua/autocomplete.cpp index 074efdbc3..2e8fe2c73 100644 --- a/Source/lua/autocomplete.cpp +++ b/Source/lua/autocomplete.cpp @@ -218,15 +218,39 @@ void SuggestionsFromUserdata(UserdataQuery query, std::string_view prefix, } } +bool IsAlnum(char c) +{ + return (c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || (c >= '0' && c <= '9'); +} + +bool IsIdentifierChar(char c) +{ + return IsAlnum(c) || c == '_'; +} + +bool IsIdentifierOrExprChar(char c) +{ + return IsIdentifierChar(c) || c == '-' || c == '+' || c == '*' || c == '/' || c == '='; +} + } // namespace -void GetLuaAutocompleteSuggestions(std::string_view text, const sol::environment &lua, +void GetLuaAutocompleteSuggestions(std::string_view text, size_t cursorPos, const sol::environment &lua, size_t maxSuggestions, std::vector &out) { out.clear(); - if (text.empty()) return; - std::string_view token = GetLastToken(text); - const char prevChar = token.data() == text.data() ? '\0' : *(token.data() - 1); + const std::string_view textPrefix = text.substr(0, cursorPos); + if (textPrefix.empty()) return; + const std::string_view textSuffix = text.substr(cursorPos); + if (!textSuffix.empty()) { + const char c = textSuffix[0]; + if (IsIdentifierOrExprChar(c) || (c == ' ' && textSuffix.size() > 1)) return; + } + if (textPrefix.size() >= 2 && textPrefix.back() == ' ' && IsIdentifierChar(textPrefix[textPrefix.size() - 2])) { + return; + } + std::string_view token = GetLastToken(textPrefix); + const char prevChar = token.data() == textPrefix.data() ? '\0' : *(token.data() - 1); if (prevChar == '(' || prevChar == ',') return; const size_t dotPos = token.find_last_of(".:"); const std::string_view prefix = token.substr(dotPos + 1); @@ -259,7 +283,7 @@ void GetLuaAutocompleteSuggestions(std::string_view text, const sol::environment addSuggestions(obj->as()); } else if (obj->get_type() == sol::type::userdata) { const sol::userdata &data = obj->as(); - SuggestionsFromUserdata(UserdataQuery { &data, completionChar == ':' }, + SuggestionsFromUserdata(UserdataQuery { .obj = &data, .colonAccess = completionChar == ':' }, prefix, maxSuggestions, suggestions); } } diff --git a/Source/lua/autocomplete.hpp b/Source/lua/autocomplete.hpp index 464d40039..6d0cdb63e 100644 --- a/Source/lua/autocomplete.hpp +++ b/Source/lua/autocomplete.hpp @@ -26,7 +26,7 @@ struct LuaAutocompleteSuggestion { }; void GetLuaAutocompleteSuggestions( - std::string_view text, const sol::environment &lua, + std::string_view text, size_t cursorPos, const sol::environment &lua, size_t maxSuggestions, std::vector &out); } // namespace devilution diff --git a/Source/panels/console.cpp b/Source/panels/console.cpp index fb76abbf2..d922e6396 100644 --- a/Source/panels/console.cpp +++ b/Source/panels/console.cpp @@ -560,7 +560,7 @@ void DrawConsole(const Surface &out) if (CurrentInputTextState == InputTextState::RestoredFromHistory) { AutocompleteSuggestions.clear(); } else { - GetLuaAutocompleteSuggestions(originalInputText.substr(0, ConsoleInputCursor.position), GetLuaReplEnvironment(), /*maxSuggestions=*/MaxSuggestions, AutocompleteSuggestions); + GetLuaAutocompleteSuggestions(originalInputText, ConsoleInputCursor.position, GetLuaReplEnvironment(), /*maxSuggestions=*/MaxSuggestions, AutocompleteSuggestions); } AutocompleteSuggestionsMaxWidth = -1; AutocompleteSuggestionFocusIndex = AutocompleteSuggestions.empty() ? -1 : 0;