|
5 | 5 | #include <ezlibs/ezFile.hpp> |
6 | 6 | #include <ezlibs/ezTime.hpp> |
7 | 7 | #include <ezlibs/ezLog.hpp> |
| 8 | +#include <algorithm> |
8 | 9 | #include <exception> |
9 | 10 | #include <chrono> |
10 | 11 | #include <ctime> |
@@ -329,16 +330,36 @@ void Module::m_ensureCompletionState() { |
329 | 330 | (*m_completionLuaPtr)["ltg"] = m_completionDatasModelPtr; |
330 | 331 | } |
331 | 332 |
|
| 333 | +// Filter out keys that are Lua-internal metamethods (`__name`, `__index`, `__gc`, `__eq`, |
| 334 | +// `__pairs`, `__newindex`, `__type`, ...) and sol2-internal helpers (`class_check`, `class_cast`, |
| 335 | +// `new`). These appear in the metatable iteration but are noise from the user's POV — they |
| 336 | +// don't help write Lua, they expose implementation details. |
| 337 | +static bool s_isCompletionNoise(const std::string& aName) { |
| 338 | + if (aName.size() >= 2 && aName[0] == '_' && aName[1] == '_') { |
| 339 | + return true; // any `__*` metamethod |
| 340 | + } |
| 341 | + if (aName.compare(0, 6, "class_") == 0) { |
| 342 | + return true; // sol2 inheritance bookkeeping (class_check, class_cast) |
| 343 | + } |
| 344 | + if (aName == "new") { |
| 345 | + return true; // sol2 default constructor binding — never useful through `:method()` autocompletion |
| 346 | + } |
| 347 | + return false; |
| 348 | +} |
| 349 | + |
332 | 350 | void Module::m_iterateLuaTable(lua_State* apLua, int aTableIndex, std::vector<Ltg::CompletionEntry>& aoEntries) { |
333 | 351 | // aTableIndex must be an absolute stack index (lua_next manipulates the stack, breaking relative refs). |
334 | 352 | lua_pushnil(apLua); |
335 | 353 | while (lua_next(apLua, aTableIndex) != 0) { |
336 | 354 | // -2 is the key, -1 is the value |
337 | 355 | if (lua_type(apLua, -2) == LUA_TSTRING) { |
338 | | - Ltg::CompletionEntry entry; |
339 | | - entry.name = lua_tostring(apLua, -2); |
340 | | - entry.type = lua_typename(apLua, lua_type(apLua, -1)); |
341 | | - aoEntries.push_back(entry); |
| 356 | + std::string keyName = lua_tostring(apLua, -2); |
| 357 | + if (!s_isCompletionNoise(keyName)) { |
| 358 | + Ltg::CompletionEntry entry; |
| 359 | + entry.name = std::move(keyName); |
| 360 | + entry.type = lua_typename(apLua, lua_type(apLua, -1)); |
| 361 | + aoEntries.push_back(std::move(entry)); |
| 362 | + } |
342 | 363 | } |
343 | 364 | lua_pop(apLua, 1); // pop value, keep key for next iter |
344 | 365 | } |
@@ -368,6 +389,72 @@ void Module::getCompletionEntries(const std::string& aTarget, std::vector<Ltg::C |
368 | 389 | } |
369 | 390 | } |
370 | 391 | lua_settop(L, topBefore); |
| 392 | + |
| 393 | + // alphabetic order — lua_next returns hash-table order which has no stable meaning to the user. |
| 394 | + std::sort(aoEntries.begin(), aoEntries.end(), [](const Ltg::CompletionEntry& aLhs, const Ltg::CompletionEntry& aRhs) { |
| 395 | + return aLhs.name < aRhs.name; |
| 396 | + }); |
| 397 | +} |
| 398 | + |
| 399 | +namespace { |
| 400 | + |
| 401 | +// Hand-maintained signature catalog for the Lua plugin. Must be kept in sync with the bindings |
| 402 | +// in Module::load (and m_ensureCompletionState). For overloaded methods we list the widest |
| 403 | +// variant — the host shows a single line in v1, no overload picker yet. v1 covers `ltg:` |
| 404 | +// methods only; `math.*` / `string.*` curated entries will land next. |
| 405 | +struct CatalogArg { |
| 406 | + const char* name; |
| 407 | + const char* type; |
| 408 | +}; |
| 409 | +struct SignatureEntry { |
| 410 | + const char* target; // "" for globals |
| 411 | + const char* functionName; |
| 412 | + std::vector<CatalogArg> args; |
| 413 | +}; |
| 414 | + |
| 415 | +const std::vector<SignatureEntry>& s_signatureCatalog() { |
| 416 | + static const std::vector<SignatureEntry> catalog = { |
| 417 | + // ltg: usertype methods (cf. new_usertype<LuaDatasModel> in Module::load) |
| 418 | + {"ltg", "stringToEpoch", {{"dateTime","string"}, {"hourOffset","number"}}}, |
| 419 | + {"ltg", "epochToString", {{"epochTime","number"}, {"hourOffset","number"}}}, |
| 420 | + {"ltg", "addSignalTag", {{"epoch","number"}, {"r","number"}, {"g","number"}, {"b","number"}, {"a","number"}, {"name","string"}, {"help","string"}}}, |
| 421 | + {"ltg", "addSignalStatus", {{"category","string"}, {"name","string"}, {"epoch","number"}, {"status","string"}}}, |
| 422 | + {"ltg", "addSignalValue", {{"category","string"}, {"name","string"}, {"epoch","number"}, {"value","number"}, {"desc","string"}}}, |
| 423 | + {"ltg", "addSignalStartZone", {{"category","string"}, {"name","string"}, {"epoch","number"}, {"startMsg","string"}}}, |
| 424 | + {"ltg", "addSignalEndZone", {{"category","string"}, {"name","string"}, {"epoch","number"}, {"endMsg","string"}}}, |
| 425 | + {"ltg", "logInfo", {{"message","string"}}}, |
| 426 | + {"ltg", "logWarning", {{"message","string"}}}, |
| 427 | + {"ltg", "logError", {{"message","string"}}}, |
| 428 | + {"ltg", "logDebug", {{"message","string"}}}, |
| 429 | + {"ltg", "getRowIndex", {}}, |
| 430 | + {"ltg", "getRowCount", {}}, |
| 431 | + }; |
| 432 | + return catalog; |
| 433 | +} |
| 434 | + |
| 435 | +} // namespace |
| 436 | + |
| 437 | +void Module::getSignatureInfo(const std::string& aTarget, const std::string& aFunctionName, Ltg::SignatureInfo& aoSignature) { |
| 438 | + if (aFunctionName.empty()) { |
| 439 | + return; |
| 440 | + } |
| 441 | + for (const auto& entry : s_signatureCatalog()) { |
| 442 | + if (aTarget == entry.target && aFunctionName == entry.functionName) { |
| 443 | + aoSignature.label = entry.target[0] != '\0' |
| 444 | + ? std::string(entry.target) + ":" + entry.functionName |
| 445 | + : entry.functionName; |
| 446 | + aoSignature.args.clear(); |
| 447 | + aoSignature.args.reserve(entry.args.size()); |
| 448 | + for (const auto& catArg : entry.args) { |
| 449 | + Ltg::SignatureArg arg; |
| 450 | + arg.name = catArg.name; |
| 451 | + arg.type = catArg.type; |
| 452 | + aoSignature.args.push_back(std::move(arg)); |
| 453 | + } |
| 454 | + return; |
| 455 | + } |
| 456 | + } |
| 457 | + // not in the catalog — leave aoSignature empty, the host won't open the tooltip |
371 | 458 | } |
372 | 459 |
|
373 | 460 | bool Module::callScriptStart(Ltg::ErrorContainer& vOutErrors) { |
|
0 commit comments