diff --git a/docs/config/lua/wezterm.table/count.md b/docs/config/lua/wezterm.table/count.md index 6efa831a02e..36de9e30bba 100644 --- a/docs/config/lua/wezterm.table/count.md +++ b/docs/config/lua/wezterm.table/count.md @@ -2,11 +2,12 @@ {{since('nightly')}} -This function returns the number of non-nil elements of a Lua table (or array) passed to it. +This function returns the number of non-nil elements of any Lua table passed to it. Note: The Lua function `#` also returns the length of an array, but `#` only works for array-style tables with contiguous integer keys starting with index `1`, and not sparse arrays (with gaps in -their integer keys), or object or other style of tables with non-integer keys. +their integer keys), or object or other style of tables with non-integer keys. `wezterm.table.count` +can instead be used for such tables. ```lua local wezterm = require 'wezterm' diff --git a/lua-api-crates/table-funcs/src/lib.rs b/lua-api-crates/table-funcs/src/lib.rs index 230439f4fdb..449e201cef3 100644 --- a/lua-api-crates/table-funcs/src/lib.rs +++ b/lua-api-crates/table-funcs/src/lib.rs @@ -1,5 +1,5 @@ use config::lua::get_or_create_sub_module; -use config::lua::mlua::{self, Lua, Table, Value as LuaValue}; +use config::lua::mlua::{self, Lua, Table, Value as LuaValue, MultiValue as LuaMultiValue}; use luahelper::impl_lua_conversion_dynamic; use wezterm_dynamic::{FromDynamic, ToDynamic}; @@ -29,6 +29,16 @@ enum ConflictMode { } impl_lua_conversion_dynamic!(ConflictMode); +#[derive(Default, Debug, FromDynamic, ToDynamic, Clone, PartialEq, Eq, Copy)] +enum DepthMode { + /// Take the latest value + #[default] + Top, + /// Raise an error + Deep, +} +impl_lua_conversion_dynamic!(DepthMode); + // merge tables // (in case of overlap of the tables, we default to taking the key-value pair from the last table) // Note that we don't use a HashMap since we want to keep the order of the tables, which @@ -104,28 +114,41 @@ fn deep_extend<'lua>( Ok(tbl) } -fn clone<'lua>(lua: &'lua Lua, table: Table<'lua>) -> mlua::Result> { +fn clone<'lua>(lua: &'lua Lua, (table, behavior): (Table<'lua>, Option)) -> mlua::Result> { let res: Table<'lua> = lua.create_table()?; + let behavior = behavior.unwrap_or_default(); for pair in table.pairs::() { let (key, value) = pair?; - if let LuaValue::Table(tbl) = value { - res.set(key, clone(lua, tbl)?)?; - } else { - res.set(key, value)?; + match behavior { + DepthMode::Top => { + res.set(key, value)? + } + DepthMode::Deep => { + if let LuaValue::Table(tbl) = value { + res.set(key, clone(lua, (tbl, Some(behavior)))?)? + } else { + res.set(key, value)?; + } + } } } Ok(res) } -fn flatten<'lua>(lua: &'lua Lua, arrays: Vec>) -> mlua::Result>> { +fn flatten<'lua>(lua: &'lua Lua, (arrays, behavior): (Vec>, Option)) -> mlua::Result>> { let mut flat_vec: Vec = vec![]; + let behavior = behavior.unwrap_or_default(); for item in arrays { match item { LuaValue::Table(tbl) => { - let tbl_as_vec = tbl.sequence_values().filter_map(|x| x.ok()).collect(); - let mut flat = flatten(lua, tbl_as_vec)?; - flat_vec.append(&mut flat); + if behavior == DepthMode::Deep { + let tbl_as_vec = tbl.sequence_values().filter_map(|x| x.ok()).collect(); + let mut flat = flatten(lua, (tbl_as_vec, Some(behavior)))?; + flat_vec.append(&mut flat); + } else { + flat_vec.push(LuaValue::Table(tbl)); + } } LuaValue::Nil => (), other => {