From 5bcb0de442cb9635927529ba67bb2deb20d72207 Mon Sep 17 00:00:00 2001 From: Wez Furlong Date: Sat, 18 Jun 2022 21:31:53 -0700 Subject: [PATCH] lua: add wezterm.GLOBAL --- Cargo.lock | 12 +++++++ docs/changelog.md | 1 + docs/config/lua/wezterm/GLOBAL.md | 50 ++++++++++++++++++++++++++++ env-bootstrap/Cargo.toml | 1 + env-bootstrap/src/lib.rs | 1 + lua-api-crates/share-data/Cargo.toml | 13 ++++++++ lua-api-crates/share-data/src/lib.rs | 42 +++++++++++++++++++++++ 7 files changed, 120 insertions(+) create mode 100644 docs/config/lua/wezterm/GLOBAL.md create mode 100644 lua-api-crates/share-data/Cargo.toml create mode 100644 lua-api-crates/share-data/src/lib.rs diff --git a/Cargo.lock b/Cargo.lock index ca6588310..6232bfbb3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -1113,6 +1113,7 @@ dependencies = [ "logging", "mux-lua", "objc", + "share-data", "spawn-funcs", "ssh-funcs", "termwiz", @@ -3659,6 +3660,17 @@ dependencies = [ "opaque-debug 0.3.0", ] +[[package]] +name = "share-data" +version = "0.1.0" +dependencies = [ + "anyhow", + "config", + "lazy_static", + "luahelper", + "wezterm-dynamic", +] + [[package]] name = "shared_library" version = "0.1.9" diff --git a/docs/changelog.md b/docs/changelog.md index 4ea0b4f9c..b3b858406 100644 --- a/docs/changelog.md +++ b/docs/changelog.md @@ -47,6 +47,7 @@ As features stabilize some brief notes about them will accumulate here. * [window_background_gradient](config/lua/config/window_background_gradient.md) now also supports `Linear` gradients with an angle of your choice. Thanks to [@erf](https://github.com/erf)! [#2038](https://github.com/wez/wezterm/pull/2038) * RPM and DEB packages now install zsh and bash `wezterm` CLI completions * `Grey-green`, `Neon` and `Oceanic-Next` color schemes +* [wezterm.GLOBAL](config/lua/wezterm/GLOBAL.md) for persisting lua data across config reloads #### Updated * Bundled harfbuzz to 4.3.0 diff --git a/docs/config/lua/wezterm/GLOBAL.md b/docs/config/lua/wezterm/GLOBAL.md new file mode 100644 index 000000000..9f3a41f45 --- /dev/null +++ b/docs/config/lua/wezterm/GLOBAL.md @@ -0,0 +1,50 @@ +# `wezterm.GLOBAL` + +*Since: nightly builds only* + +Provides global, in-process, in-memory, data storage for json-like variables +that persists across config reloads. + +wezterm's lua files may be re-loading and re-evaluated multiple times in +different contexts or in different threads. If you'd like to keep track +of state that lasts for the lifetime of your wezterm process then you +cannot simply use global variables in the lua script. + +`wezterm.GLOBAL` is a special userdata value that acts like a table. +Writing to keys will copy the data that you assign into a global in-memory +table and allow it to be read back later. + +Reads and writes from/to `wezterm.GLOBAL` are thread-safe but don't currently +provide synchronization primitives for managing read-modify-write operations. + +The following example shows the number of times that the config has been +loaded in the right status bar. Watch it increase when you press the +[ReloadConfiguration](../keyassignment/ReloadConfiguration.md) key assignment +(`CTRL-SHIFT-R`): + +```lua +local wezterm = require 'wezterm' + +-- Count how many times the lua config has been loaded +wezterm.GLOBAL.parse_count = (wezterm.GLOBAL.parse_count or 0) + 1 + +wezterm.on("update-right-status", function(window, pane) + window:set_right_status("Reloads=" .. tostring(wezterm.GLOBAL.parse_count)) +end) + +return {} +``` + +Note that the reload counter goes up by more than 1 when you reload: that is +because the config is evaluated multiple times in different threads as part of +safely validating and setting up the configuration. + +You may store values with the following types: + +* string +* number +* table +* boolean + +Attempting to assign other types will raise an error. + diff --git a/env-bootstrap/Cargo.toml b/env-bootstrap/Cargo.toml index 6b449f1e9..931e5e202 100644 --- a/env-bootstrap/Cargo.toml +++ b/env-bootstrap/Cargo.toml @@ -21,6 +21,7 @@ termwiz-funcs = { path = "../lua-api-crates/termwiz-funcs" } logging = { path = "../lua-api-crates/logging" } mux-lua = { path = "../lua-api-crates/mux" } filesystem = { path = "../lua-api-crates/filesystem" } +share-data = { path = "../lua-api-crates/share-data" } ssh-funcs = { path = "../lua-api-crates/ssh-funcs" } spawn-funcs = { path = "../lua-api-crates/spawn-funcs" } diff --git a/env-bootstrap/src/lib.rs b/env-bootstrap/src/lib.rs index 45caec259..ef864870b 100644 --- a/env-bootstrap/src/lib.rs +++ b/env-bootstrap/src/lib.rs @@ -167,6 +167,7 @@ fn register_lua_modules() { filesystem::register, ssh_funcs::register, spawn_funcs::register, + share_data::register, ] { config::lua::add_context_setup_func(func); } diff --git a/lua-api-crates/share-data/Cargo.toml b/lua-api-crates/share-data/Cargo.toml new file mode 100644 index 000000000..e92c31874 --- /dev/null +++ b/lua-api-crates/share-data/Cargo.toml @@ -0,0 +1,13 @@ +[package] +name = "share-data" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] +anyhow = "1.0" +config = { path = "../../config" } +wezterm-dynamic = { path = "../../wezterm-dynamic" } +lazy_static = "1.4" +luahelper = { path = "../../luahelper" } diff --git a/lua-api-crates/share-data/src/lib.rs b/lua-api-crates/share-data/src/lib.rs new file mode 100644 index 000000000..f0f7f425b --- /dev/null +++ b/lua-api-crates/share-data/src/lib.rs @@ -0,0 +1,42 @@ +use config::lua::get_or_create_module; +use config::lua::mlua::{self, Lua, UserData, UserDataMethods}; +use std::collections::HashMap; +use std::sync::Mutex; +use wezterm_dynamic::Value; + +lazy_static::lazy_static! { + static ref GLOBALS: Mutex> = Mutex::new(HashMap::new()); +} + +struct Global {} + +impl UserData for Global { + fn add_methods<'lua, M: UserDataMethods<'lua, Self>>(methods: &mut M) { + methods.add_meta_method( + mlua::MetaMethod::Index, + |lua: &Lua, _, key: String| -> mlua::Result> { + match GLOBALS.lock().unwrap().get(key.as_str()) { + Some(value) => Ok(Some( + luahelper::dynamic_to_lua_value(lua, value.clone()) + .map_err(|e| mlua::Error::external(format!("{:#}", e)))?, + )), + None => Ok(None), + } + }, + ); + methods.add_meta_method( + mlua::MetaMethod::NewIndex, + |_, _, (key, value): (String, mlua::Value)| -> mlua::Result<()> { + let value = luahelper::lua_value_to_dynamic(value)?; + GLOBALS.lock().unwrap().insert(key, value); + Ok(()) + }, + ); + } +} + +pub fn register(lua: &Lua) -> anyhow::Result<()> { + let wezterm_mod = get_or_create_module(lua, "wezterm")?; + wezterm_mod.set("GLOBAL", Global {})?; + Ok(()) +}