some quality of life features for using global vars

This commit is contained in:
whosit 2025-03-20 12:43:45 +03:00
parent 9c76127516
commit bf99ec97bc
3 changed files with 75 additions and 2 deletions

View File

@ -18,6 +18,7 @@ Outputs this:
This also just works:
```
> x = 2*2
> x
| 4
```
@ -44,6 +45,7 @@ No need to use `core.chat_send_player()`, just use `print()` - it will do the ri
```
> objs = core.get_objects_inside_radius(here, 10)
> for i,o in ipairs(objs) do print(i, (o:get_luaentity() or {}).name, o:get_pos()) end
< 1 nil (-98.0, 15.5, 33.4)
< 2 mobs_animal:kitten (-101.0, 16.5, 30.0)
@ -80,9 +82,12 @@ Show indices for easier manual access:
| [1] = #<player: "singleplayer">,
| [2] = #<luaentity: "mobs_animal:kitten">,
| }
> _[2]
| #<luaentity: "mobs_animal:kitten">
> pos = _:get_pos()
> pos
| {
| x = 123.5,
@ -91,3 +96,42 @@ Show indices for easier manual access:
| }
```
### Accessing and changing global variables
You can save some keypresses by not typing `local` in front of every
variable. Assigning to globals won't clobber them, instead using your personal
environment. But you can still read globals as usual.
```
> print(myvar)
* Accessing undeclared variable: "myvar"
< nil
> myvar = 1
| Done.
> print(myvar)
< 1
| Done.
```
If you want to create a new global or actually overwrite existing one,
you can access global environment through usual `_G` or `global`
variables. Using them will print a message telling you if global var
already existed.
```
> cmd_eval = nil
| Done.
> cmd_eval -- accesses real global
{
e = { ... }, ...
}
> global.cmd_eval = nil
* Overwriting global: "cmd_eval"
| Done.
> cmd_eval
| nil -- wiped for real
```

View File

@ -11,6 +11,11 @@ _G[MODNAME] = api
api.e = {}
local function orange_fmt(...)
return core.colorize("#FFA91F", string.format(...))
end
local function create_shared_environment(player_name)
local magic_keys = {
-- These are _functions_ pretending to be _variables_, they will
@ -53,6 +58,21 @@ local function create_shared_environment(player_name)
}
local g = {} -- "do not warn again" flags
local global_proxy = setmetatable(
{"<proxy>"},
{
__index = _G,
__newindex = function(t, k, v)
if _G[k] then
core.chat_send_player(player_name, orange_fmt("* Overwriting global: %s", dump(k)))
else
core.chat_send_player(player_name, orange_fmt("* Creating new global: %s", dump(k)))
end
_G[k] = v
end,
}
)
local eval_env = setmetatable(
{
my_name = player_name,
@ -64,22 +84,29 @@ local function create_shared_environment(player_name)
end
core.chat_send_player(player_name, msg)
end,
dump = repl_dump,
--global = _G, -- this works, but dumps whole global env if you just print `cmd_eval` value
_G = global_proxy, -- use our proxy to get warnings
global = global_proxy, -- just a different name for globals
--dump = repl_dump,
},
{
__index = function(self, key)
-- we give warnings on accessing undeclared var because it's likely a typo
local res = rawget(_G, key)
if res == nil then
local magic = magic_keys[key]
if magic then
return magic()
elseif not g[key] then
core.chat_send_player(player_name, string.format("* Accessing undeclared variable: '%s'", key))
core.chat_send_player(player_name, orange_fmt("* Accessing undeclared variable: %s", dump(key)))
g[key] = true -- warn only once
end
end
return res
end
-- there's no __newindex method because we allow assigning
-- "globals" inside snippets, since those will be only
-- accessible to eval and stored in `eval_env`
}
)
return eval_env

View File

@ -16,3 +16,5 @@ copy relevant parts from there.
* add proper REPL
Register on chat message and let executing multiple commands without
typing `/eval`. Maybe via `/repl` command...
* add a "pager" for long output
To not spam the chat and prevent "Internal error: String too long"