diff --git a/docs/changelog.txt b/docs/changelog.txt index 0c30f22f5..f5f3c8b1b 100644 --- a/docs/changelog.txt +++ b/docs/changelog.txt @@ -78,6 +78,7 @@ changelog.txt uses a syntax similar to RST, with a few special sequences: - History: added ``dfhack.getCommandHistory(history_id, history_filename)`` and ``dfhack.addCommandToHistory(history_id, history_filename, command)`` so gui scripts can access a commandline history without requiring a terminal. - ``helpdb``: database and query interface for DFHack tool help text - ``tile-material``: fix the order of declarations. The ``GetTileMat`` function now returns the material as intended (always returned nil before). Also changed the license info, with permission of the original author. +- ``utils.df_expr_to_ref()``: fixed some errors that could occur when navigating tables - ``widgets.EditField``: new ``onsubmit2`` callback attribute is called when the user hits Shift-Enter. - ``widgets.EditField``: new function: ``setCursor(position)`` sets the input cursor. - ``widgets.EditField``: new attribute: ``ignore_keys`` lets you ignore specified characters if you want to use them as hotkeys diff --git a/library/lua/utils.lua b/library/lua/utils.lua index 99ca87c6e..1b626f051 100644 --- a/library/lua/utils.lua +++ b/library/lua/utils.lua @@ -613,13 +613,15 @@ function df_expr_to_ref(expr) local obj = df_env[parts[1]] for i = 2, #parts do local key = tonumber(parts[i]) or parts[i] - local cur = obj[key] - if i == #parts and ((type(cur) ~= 'userdata') or - type(cur) == 'userdata' and getmetatable(cur) == nil) then - obj = obj:_field(key) - else - obj = obj[key] + if i == #parts then + local ok, ret = pcall(function() + return obj:_field(key) + end) + if ok then + return ret + end end + obj = obj[key] end return obj end diff --git a/test/library/utils.lua b/test/library/utils.lua index 5261ac913..2434da321 100644 --- a/test/library/utils.lua +++ b/test/library/utils.lua @@ -54,3 +54,40 @@ function test.invert_overwrite() expect.eq(i.b, 2) expect.eq(i.a, 3) end + +function test.df_expr_to_ref() + -- userdata field + expect.eq(utils.df_expr_to_ref('df.global.world.engravings'), df.global.world.engravings) + expect.eq(utils.df_expr_to_ref('df.global.world.engravings'), df.global.world:_field('engravings')) + -- primitive field + expect.eq(utils.df_expr_to_ref('df.global.world.original_save_version'), df.global.world:_field('original_save_version')) + -- table field + expect.eq(utils.df_expr_to_ref('df.global.world'), df.global.world) + expect.eq(utils.df_expr_to_ref('df.global'), df.global) + -- table + expect.eq(utils.df_expr_to_ref('df'), df) + + -- userdata object + expect.eq(utils.df_expr_to_ref('scr'), dfhack.gui.getCurViewscreen()) + + local fake_unit + mock.patch(dfhack.gui, 'getSelectedUnit', function() return fake_unit end, function() + -- lightuserdata field + fake_unit = { + null_field=df.NULL, + } + expect.eq(utils.df_expr_to_ref('unit'), fake_unit) + expect.eq(utils.df_expr_to_ref('unit.null_field'), fake_unit.null_field) + + dfhack.with_temp_object(df.unit:new(), function(u) + fake_unit = u + + -- userdata field + expect.eq(utils.df_expr_to_ref('unit.name'), fake_unit.name) + expect.eq(utils.df_expr_to_ref('unit.name'), fake_unit:_field('name')) + + -- primitive field + expect.eq(utils.df_expr_to_ref('unit.profession'), fake_unit:_field('profession')) + end) + end) +end