mirror of
https://github.com/wez/wezterm.git
synced 2024-11-27 02:25:28 +03:00
add wezterm.json_parse and wezterm.json_encode
This commit is contained in:
parent
c8cb99a512
commit
4a4787ff41
11
Cargo.lock
generated
11
Cargo.lock
generated
@ -1096,6 +1096,7 @@ dependencies = [
|
||||
"dirs-next",
|
||||
"env_logger",
|
||||
"filesystem",
|
||||
"json",
|
||||
"lazy_static",
|
||||
"libc",
|
||||
"log",
|
||||
@ -1835,6 +1836,16 @@ dependencies = [
|
||||
"wasm-bindgen",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "json"
|
||||
version = "0.1.0"
|
||||
dependencies = [
|
||||
"anyhow",
|
||||
"config",
|
||||
"luahelper",
|
||||
"serde_json",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "k9"
|
||||
version = "0.11.5"
|
||||
|
@ -23,6 +23,7 @@ As features stabilize some brief notes about them will accumulate here.
|
||||
* You may now use [wezterm.format](config/lua/wezterm/format.md) (or otherwise use strings with escape sequences) in the labels of the [Launcher Menu](config/launch.md#the-launcher-menu).
|
||||
* You may now specify `assume_emoji_presentation = true` (or `false`) in [wezterm.font()](config/lua/wezterm/font.md) and [wezterm.font_with_fallback()](config/lua/wezterm/font_with_fallback.md)
|
||||
* Wayland: `zwp_text_input_v3` is now supported, which enables IME to work in wezterm if your compositor also implements this protocol.
|
||||
* New [wezterm.json_parse()](config/lua/wezterm/json_parse.md) and [wezterm.json_encode()](config/lua/wezterm/json_encode.md) functions for working with JSON.
|
||||
|
||||
#### Fixed
|
||||
* [ActivateKeyTable](config/lua/keyassignment/ActivateKeyTable.md)'s `replace_current` field was not actually optional. Made it optional. [#2179](https://github.com/wez/wezterm/issues/2179)
|
||||
|
10
docs/config/lua/wezterm/json_encode.md
Normal file
10
docs/config/lua/wezterm/json_encode.md
Normal file
@ -0,0 +1,10 @@
|
||||
# `wezterm.json_encode(value)`
|
||||
|
||||
*Since: nightly builds only*
|
||||
|
||||
Encodes the supplied lua value as json:
|
||||
|
||||
```
|
||||
> wezterm.json_encode({foo = "bar"})
|
||||
"{\"foo\":\"bar\"}"
|
||||
```
|
12
docs/config/lua/wezterm/json_parse.md
Normal file
12
docs/config/lua/wezterm/json_parse.md
Normal file
@ -0,0 +1,12 @@
|
||||
# `wezterm.json_parse(string)`
|
||||
|
||||
*Since: nightly builds only*
|
||||
|
||||
Parses the supplied string as json and returns the equivalent lua values:
|
||||
|
||||
```
|
||||
> wezterm.json_parse('{"foo":"bar"}')
|
||||
{
|
||||
"foo": "bar",
|
||||
}
|
||||
```
|
@ -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" }
|
||||
json = { path = "../lua-api-crates/json" }
|
||||
share-data = { path = "../lua-api-crates/share-data" }
|
||||
ssh-funcs = { path = "../lua-api-crates/ssh-funcs" }
|
||||
spawn-funcs = { path = "../lua-api-crates/spawn-funcs" }
|
||||
|
@ -165,6 +165,7 @@ fn register_lua_modules() {
|
||||
logging::register,
|
||||
mux_lua::register,
|
||||
filesystem::register,
|
||||
json::register,
|
||||
ssh_funcs::register,
|
||||
spawn_funcs::register,
|
||||
share_data::register,
|
||||
|
12
lua-api-crates/json/Cargo.toml
Normal file
12
lua-api-crates/json/Cargo.toml
Normal file
@ -0,0 +1,12 @@
|
||||
[package]
|
||||
name = "json"
|
||||
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" }
|
||||
luahelper = { path = "../../luahelper" }
|
||||
serde_json = "1.0.82"
|
166
lua-api-crates/json/src/lib.rs
Normal file
166
lua-api-crates/json/src/lib.rs
Normal file
@ -0,0 +1,166 @@
|
||||
use config::lua::get_or_create_module;
|
||||
use config::lua::mlua::{self, Lua, ToLua, Value as LuaValue};
|
||||
use serde_json::{Map, Value as JValue};
|
||||
use std::collections::HashSet;
|
||||
|
||||
pub fn register(lua: &Lua) -> anyhow::Result<()> {
|
||||
let wezterm_mod = get_or_create_module(lua, "wezterm")?;
|
||||
wezterm_mod.set("json_parse", lua.create_function(json_parse)?)?;
|
||||
wezterm_mod.set("json_encode", lua.create_function(json_encode)?)?;
|
||||
Ok(())
|
||||
}
|
||||
|
||||
fn json_value_to_lua_value<'lua>(lua: &'lua Lua, value: JValue) -> mlua::Result<LuaValue> {
|
||||
Ok(match value {
|
||||
JValue::Null => LuaValue::Nil,
|
||||
JValue::Bool(b) => LuaValue::Boolean(b),
|
||||
JValue::Number(n) => match n.as_i64() {
|
||||
Some(n) => LuaValue::Integer(n),
|
||||
None => match n.as_f64() {
|
||||
Some(n) => LuaValue::Number(n),
|
||||
None => {
|
||||
return Err(mlua::Error::external(format!(
|
||||
"cannot represent {n:#?} as either i64 or f64"
|
||||
)))
|
||||
}
|
||||
},
|
||||
},
|
||||
JValue::String(s) => s.to_lua(lua)?,
|
||||
JValue::Array(arr) => {
|
||||
let tbl = lua.create_table_with_capacity(arr.len() as i32, 0)?;
|
||||
for (idx, value) in arr.into_iter().enumerate() {
|
||||
tbl.set(idx + 1, json_value_to_lua_value(lua, value)?)?;
|
||||
}
|
||||
LuaValue::Table(tbl)
|
||||
}
|
||||
JValue::Object(map) => {
|
||||
let tbl = lua.create_table_with_capacity(0, map.len() as i32)?;
|
||||
for (key, value) in map.into_iter() {
|
||||
let key = key.to_lua(lua)?;
|
||||
let value = json_value_to_lua_value(lua, value)?;
|
||||
tbl.set(key, value)?;
|
||||
}
|
||||
LuaValue::Table(tbl)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn json_parse<'lua>(lua: &'lua Lua, text: String) -> mlua::Result<LuaValue> {
|
||||
let value =
|
||||
serde_json::from_str(&text).map_err(|err| mlua::Error::external(format!("{err:#}")))?;
|
||||
json_value_to_lua_value(lua, value)
|
||||
}
|
||||
|
||||
fn lua_value_to_json_value(value: LuaValue, visited: &mut HashSet<usize>) -> mlua::Result<JValue> {
|
||||
let ptr = value.to_pointer() as usize;
|
||||
if visited.contains(&ptr) {
|
||||
// Skip this one, as we've seen it before.
|
||||
// Treat it as a Null value.
|
||||
return Ok(JValue::Null);
|
||||
}
|
||||
visited.insert(ptr);
|
||||
Ok(match value {
|
||||
LuaValue::Nil => JValue::Null,
|
||||
LuaValue::String(s) => JValue::String(s.to_str()?.to_string()),
|
||||
LuaValue::Boolean(b) => JValue::Bool(b),
|
||||
LuaValue::Integer(i) => JValue::Number(i.into()),
|
||||
LuaValue::Number(i) => {
|
||||
if let Some(n) = serde_json::value::Number::from_f64(i) {
|
||||
JValue::Number(n)
|
||||
} else {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "number",
|
||||
to: "JsonValue",
|
||||
message: Some(format!("unable to represent {i} as json float")),
|
||||
});
|
||||
}
|
||||
}
|
||||
// Handle our special Null userdata case and map it to Null
|
||||
LuaValue::LightUserData(ud) if ud.0.is_null() => JValue::Null,
|
||||
LuaValue::LightUserData(_) | LuaValue::UserData(_) => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "userdata",
|
||||
to: "JsonValue",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
LuaValue::Function(_) => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "function",
|
||||
to: "JsonValue",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
LuaValue::Thread(_) => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: "thread",
|
||||
to: "JsonValue",
|
||||
message: None,
|
||||
})
|
||||
}
|
||||
LuaValue::Error(e) => return Err(e),
|
||||
LuaValue::Table(table) => {
|
||||
if let Ok(true) = table.contains_key(1) {
|
||||
let mut array = vec![];
|
||||
let pairs = table.clone();
|
||||
for value in table.sequence_values() {
|
||||
array.push(lua_value_to_json_value(value?, visited)?);
|
||||
}
|
||||
|
||||
for pair in pairs.pairs::<LuaValue, LuaValue>() {
|
||||
let (key, _value) = pair?;
|
||||
match &key {
|
||||
LuaValue::Integer(n) if *n >= 1 && *n as usize <= array.len() => {
|
||||
// Ok!
|
||||
}
|
||||
_ => {
|
||||
let type_name = key.type_name();
|
||||
let key = luahelper::ValuePrinter(key);
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: type_name,
|
||||
to: "numeric array index",
|
||||
message: Some(format!(
|
||||
"Unexpected key {key:?} for array style table"
|
||||
)),
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
JValue::Array(array.into())
|
||||
} else {
|
||||
let mut obj = Map::default();
|
||||
for pair in table.pairs::<LuaValue, LuaValue>() {
|
||||
let (key, value) = pair?;
|
||||
let key_type = key.type_name();
|
||||
let key = match lua_value_to_json_value(key, visited)? {
|
||||
JValue::String(s) => s,
|
||||
_ => {
|
||||
return Err(mlua::Error::FromLuaConversionError {
|
||||
from: key_type,
|
||||
to: "string",
|
||||
message: Some("json object keys must be strings".to_string()),
|
||||
});
|
||||
}
|
||||
};
|
||||
let lua_type = value.type_name();
|
||||
let value = lua_value_to_json_value(value, visited).map_err(|e| {
|
||||
mlua::Error::FromLuaConversionError {
|
||||
from: lua_type,
|
||||
to: "value",
|
||||
message: Some(format!("while processing {key:?}: {}", e.to_string())),
|
||||
}
|
||||
})?;
|
||||
obj.insert(key, value);
|
||||
}
|
||||
JValue::Object(obj.into())
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
fn json_encode<'lua>(_: &'lua Lua, value: LuaValue) -> mlua::Result<String> {
|
||||
let mut visited = HashSet::new();
|
||||
let json = lua_value_to_json_value(value, &mut visited)?;
|
||||
serde_json::to_string(&json).map_err(|err| mlua::Error::external(format!("{err:#}")))
|
||||
}
|
Loading…
Reference in New Issue
Block a user