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",
|
"dirs-next",
|
||||||
"env_logger",
|
"env_logger",
|
||||||
"filesystem",
|
"filesystem",
|
||||||
|
"json",
|
||||||
"lazy_static",
|
"lazy_static",
|
||||||
"libc",
|
"libc",
|
||||||
"log",
|
"log",
|
||||||
@ -1835,6 +1836,16 @@ dependencies = [
|
|||||||
"wasm-bindgen",
|
"wasm-bindgen",
|
||||||
]
|
]
|
||||||
|
|
||||||
|
[[package]]
|
||||||
|
name = "json"
|
||||||
|
version = "0.1.0"
|
||||||
|
dependencies = [
|
||||||
|
"anyhow",
|
||||||
|
"config",
|
||||||
|
"luahelper",
|
||||||
|
"serde_json",
|
||||||
|
]
|
||||||
|
|
||||||
[[package]]
|
[[package]]
|
||||||
name = "k9"
|
name = "k9"
|
||||||
version = "0.11.5"
|
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 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)
|
* 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.
|
* 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
|
#### 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)
|
* [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" }
|
logging = { path = "../lua-api-crates/logging" }
|
||||||
mux-lua = { path = "../lua-api-crates/mux" }
|
mux-lua = { path = "../lua-api-crates/mux" }
|
||||||
filesystem = { path = "../lua-api-crates/filesystem" }
|
filesystem = { path = "../lua-api-crates/filesystem" }
|
||||||
|
json = { path = "../lua-api-crates/json" }
|
||||||
share-data = { path = "../lua-api-crates/share-data" }
|
share-data = { path = "../lua-api-crates/share-data" }
|
||||||
ssh-funcs = { path = "../lua-api-crates/ssh-funcs" }
|
ssh-funcs = { path = "../lua-api-crates/ssh-funcs" }
|
||||||
spawn-funcs = { path = "../lua-api-crates/spawn-funcs" }
|
spawn-funcs = { path = "../lua-api-crates/spawn-funcs" }
|
||||||
|
@ -165,6 +165,7 @@ fn register_lua_modules() {
|
|||||||
logging::register,
|
logging::register,
|
||||||
mux_lua::register,
|
mux_lua::register,
|
||||||
filesystem::register,
|
filesystem::register,
|
||||||
|
json::register,
|
||||||
ssh_funcs::register,
|
ssh_funcs::register,
|
||||||
spawn_funcs::register,
|
spawn_funcs::register,
|
||||||
share_data::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