wez / wezterm

A GPU-accelerated cross-platform terminal emulator and multiplexer written by @wez and implemented in Rust
https://wezfurlong.org/wezterm/
Other
16.8k stars 755 forks source link

Tables assigned to wezterm.GLOBAL become "userdata" #4802

Open keturiosakys opened 8 months ago

keturiosakys commented 8 months ago

What Operating System(s) are you seeing this problem on?

macOS

Which Wayland compositor or X11 Window manager(s) are you using?

No response

WezTerm version

20231228-084719-ff274374

Did you try the latest nightly build to see if the issue is better (or worse!) than your current version?

Yes, and I updated the version box above to show the version of the nightly that I tried

Describe the bug

The documentation for wezterm.GLOBAL says that we can use it as a persistent in-memory cache for use across threads in WezTerm including tables (table type).

However, it looks like that wezterm.GLOBAL converts the assigned tables to type userdata that doesn't allow any normal table operations on it (next(), pairs() etc.). Any of these operations will throw:

runtime error: <location> bad argument #1 to 'next' (table expected, got Value)

For my specific use-case, I can probably implement a work-around by serializing/de-serializing the table to string but would be nice if we could make use of normal table operations in wezterm.GLOBAL (or we should update the documentation to notify other users)

To Reproduce

  1. Create a simple table (can be empty): local myTable = { ["foo"] = "bar"} -- type(myTable): "table"
  2. Assign it to wezterm.GLOBAL: wezterm.GLOBAL.myTable = myTable
  3. Try a next() operation on wezterm.GLOBAL.myTable (e.g.: to check if it's empty): next(wezterm.GLOBAL.myTable)
  4. See the error in the debug overlay
  5. Inspect the type of wezterm.GLOBAL: type(wezterm.GLOBAL.myTable) -- "userdata"

Configuration

no config

Expected Behavior

I expected to be able to use next() and pairs() operations on table values assigned to wezterm.GLOBAL

Logs

No response

Anything else?

No response

wez commented 8 months ago

The values need to be userdata in order to allow reference updates to work. I think it is reasonable to want pairs/ipairs to function.

In the meantime, as a workaround, try adding in an extra layer to your table. So:

local myTable = {
  data = {
    ["foo"] = "bar"
  }
}

wezterm.GLOBAL.myTable = myTable

then when you access it:

next(wezterm.GLOBAL.myTable.data)

I can't remember if I was "smart" and make every access work as a reference or not; if I wasn't too smart for my own good, that second level access will read as a normal lua table value.

sakuro commented 8 months ago

I am new to Lua but is the following difference in behaviors of plain table list and wezterm.GLOBAL.list comes from this issue?

wezterm version: 20240121-180215-76028ca1 aarch64-apple-darwin
Window Environment: macOS 14.2.1 (23C71)
WebGPU: name=Apple M1 Pro, device_type=IntegratedGpu, backend=Metal, vendor=0, device=0
Enter lua statements or expressions and hit Enter.
Press ESC or CTRL-D to exit
> list = {}
> for a,b in pairs(list) do print(a,b) end -- prints nothing, OK
> for a,b in ipairs(list) do print(a,b) end -- prints nothing, OK
> wezterm.GLOBAL.list = {}
> for a,b in pairs(wezterm.GLOBAL.list) do print(a,b) end -- prints nothing, OK
> for a,b in ipairs(wezterm.GLOBAL.list) do print(a,b) end -- ERROR!
can only index objects using string values
stack traceback:
        [C]: in ?
        [C]: in for iterator 'for iterator'
        [string "repl"]:1: in main chunk

(In my actual use in my config, I wrapped the loop with size check to avoid errors.)

halostatue commented 3 weeks ago
next(wezterm.GLOBAL.myTable.data)

I can't remember if I was "smart" and make every access work as a reference or not; if I wasn't too smart for my own good, that second level access will read as a normal lua table value.

Unfortunately…you were too smart for your own good in this case. In theory, one could make a __pairs and/or __ipairs iterator for the userdata, but as of right now the values in wezterm.GLOBAL cannot be iterated over, even with the indirection layer suggested.