mirror of
https://github.com/wez/wezterm.git
synced 2024-12-23 05:12:40 +03:00
restore pretty printing lua values in repl
This time with more correctly working cycle detection
This commit is contained in:
parent
55e7d845e9
commit
92eea8e064
2
Cargo.lock
generated
2
Cargo.lock
generated
@ -2229,7 +2229,7 @@ dependencies = [
|
|||||||
[[package]]
|
[[package]]
|
||||||
name = "mlua"
|
name = "mlua"
|
||||||
version = "0.8.0-beta.4"
|
version = "0.8.0-beta.4"
|
||||||
source = "git+https://github.com/wez/mlua?branch=table_to_pointer#7884481691169044c18a77ec495886db0d02bee9"
|
source = "git+https://github.com/khvzak/mlua?branch=master#bcf2cbea3798504471d88345327671bf2da7e8e1"
|
||||||
dependencies = [
|
dependencies = [
|
||||||
"bstr 0.2.17",
|
"bstr 0.2.17",
|
||||||
"cc",
|
"cc",
|
||||||
|
@ -24,4 +24,4 @@ split-debuginfo = "unpacked"
|
|||||||
|
|
||||||
[patch.crates-io]
|
[patch.crates-io]
|
||||||
xcb = {version="1.1", git="https://github.com/wez/rust-xcb", branch="ffi"}
|
xcb = {version="1.1", git="https://github.com/wez/rust-xcb", branch="ffi"}
|
||||||
mlua = {version="0.8.0-beta.4", git="https://github.com/wez/mlua", branch="table_to_pointer"}
|
mlua = {version="0.8.0-beta.4", git="https://github.com/khvzak/mlua", branch="master"}
|
||||||
|
@ -133,7 +133,7 @@ pub fn make_lua_context(config_file: &Path) -> anyhow::Result<Lua> {
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
item @ _ => {
|
item @ _ => {
|
||||||
let item = format!("{:?}", item);
|
let item = format!("{:#?}", ValuePrinter(item));
|
||||||
output.push_str(&item);
|
output.push_str(&item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
pub use mlua;
|
pub use mlua;
|
||||||
use mlua::{ToLua, Value as LuaValue};
|
use mlua::{ToLua, Value as LuaValue};
|
||||||
|
use std::cell::RefCell;
|
||||||
use std::collections::{BTreeMap, HashSet};
|
use std::collections::{BTreeMap, HashSet};
|
||||||
|
use std::rc::Rc;
|
||||||
use wezterm_dynamic::{FromDynamic, ToDynamic, Value as DynValue};
|
use wezterm_dynamic::{FromDynamic, ToDynamic, Value as DynValue};
|
||||||
|
|
||||||
/// Implement lua conversion traits for a type.
|
/// Implement lua conversion traits for a type.
|
||||||
@ -85,6 +87,13 @@ fn lua_value_to_dynamic_impl(
|
|||||||
value: LuaValue,
|
value: LuaValue,
|
||||||
visited: &mut HashSet<usize>,
|
visited: &mut HashSet<usize>,
|
||||||
) -> mlua::Result<DynValue> {
|
) -> mlua::Result<DynValue> {
|
||||||
|
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(DynValue::Null);
|
||||||
|
}
|
||||||
|
visited.insert(ptr);
|
||||||
Ok(match value {
|
Ok(match value {
|
||||||
LuaValue::Nil => DynValue::Null,
|
LuaValue::Nil => DynValue::Null,
|
||||||
LuaValue::String(s) => DynValue::String(s.to_str()?.to_string()),
|
LuaValue::String(s) => DynValue::String(s.to_str()?.to_string()),
|
||||||
@ -114,14 +123,6 @@ fn lua_value_to_dynamic_impl(
|
|||||||
}
|
}
|
||||||
LuaValue::Error(e) => return Err(e),
|
LuaValue::Error(e) => return Err(e),
|
||||||
LuaValue::Table(table) => {
|
LuaValue::Table(table) => {
|
||||||
let ptr = table.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(DynValue::Null);
|
|
||||||
}
|
|
||||||
visited.insert(ptr);
|
|
||||||
|
|
||||||
if let Ok(true) = table.contains_key(1) {
|
if let Ok(true) = table.contains_key(1) {
|
||||||
let mut array = vec![];
|
let mut array = vec![];
|
||||||
for value in table.sequence_values() {
|
for value in table.sequence_values() {
|
||||||
@ -155,3 +156,136 @@ pub struct ValueLua {
|
|||||||
pub value: wezterm_dynamic::Value,
|
pub value: wezterm_dynamic::Value,
|
||||||
}
|
}
|
||||||
impl_lua_conversion_dynamic!(ValueLua);
|
impl_lua_conversion_dynamic!(ValueLua);
|
||||||
|
|
||||||
|
pub struct ValuePrinter<'lua>(pub LuaValue<'lua>);
|
||||||
|
|
||||||
|
impl<'lua> std::fmt::Debug for ValuePrinter<'lua> {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
||||||
|
let visited = Rc::new(RefCell::new(HashSet::new()));
|
||||||
|
ValuePrinterHelper {
|
||||||
|
visited,
|
||||||
|
value: self.0.clone(),
|
||||||
|
}
|
||||||
|
.fmt(fmt)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
struct ValuePrinterHelper<'lua> {
|
||||||
|
visited: Rc<RefCell<HashSet<usize>>>,
|
||||||
|
value: LuaValue<'lua>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> PartialEq for ValuePrinterHelper<'lua> {
|
||||||
|
fn eq(&self, rhs: &Self) -> bool {
|
||||||
|
self.value.eq(&rhs.value)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> Eq for ValuePrinterHelper<'lua> {}
|
||||||
|
|
||||||
|
impl<'lua> PartialOrd for ValuePrinterHelper<'lua> {
|
||||||
|
fn partial_cmp(&self, rhs: &Self) -> Option<std::cmp::Ordering> {
|
||||||
|
let lhs = lua_value_to_dynamic(self.value.clone()).unwrap_or(DynValue::Null);
|
||||||
|
let rhs = lua_value_to_dynamic(rhs.value.clone()).unwrap_or(DynValue::Null);
|
||||||
|
lhs.partial_cmp(&rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> Ord for ValuePrinterHelper<'lua> {
|
||||||
|
fn cmp(&self, rhs: &Self) -> std::cmp::Ordering {
|
||||||
|
let lhs = lua_value_to_dynamic(self.value.clone()).unwrap_or(DynValue::Null);
|
||||||
|
let rhs = lua_value_to_dynamic(rhs.value.clone()).unwrap_or(DynValue::Null);
|
||||||
|
lhs.cmp(&rhs)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> ValuePrinterHelper<'lua> {
|
||||||
|
fn has_cycle(&self, value: &mlua::Value) -> bool {
|
||||||
|
self.visited
|
||||||
|
.borrow()
|
||||||
|
.contains(&(value.to_pointer() as usize))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<'lua> std::fmt::Debug for ValuePrinterHelper<'lua> {
|
||||||
|
fn fmt(&self, fmt: &mut std::fmt::Formatter) -> std::result::Result<(), std::fmt::Error> {
|
||||||
|
match &self.value {
|
||||||
|
LuaValue::Nil => fmt.write_str("nil"),
|
||||||
|
LuaValue::Boolean(b) => fmt.write_str(if *b { "true" } else { "false" }),
|
||||||
|
LuaValue::Integer(i) => fmt.write_fmt(format_args!("{}", i)),
|
||||||
|
LuaValue::Number(i) => fmt.write_fmt(format_args!("{}", i)),
|
||||||
|
LuaValue::String(s) => match s.to_str() {
|
||||||
|
Ok(s) => fmt.write_fmt(format_args!("{:?}", s)),
|
||||||
|
Err(_) => fmt.write_fmt(format_args!("{:?}", s.as_bytes())),
|
||||||
|
},
|
||||||
|
LuaValue::Table(t) => {
|
||||||
|
self.visited
|
||||||
|
.borrow_mut()
|
||||||
|
.insert(self.value.to_pointer() as usize);
|
||||||
|
if let Ok(true) = t.contains_key(1) {
|
||||||
|
// Treat as list
|
||||||
|
let mut list = fmt.debug_list();
|
||||||
|
for (idx, value) in t.clone().sequence_values().enumerate() {
|
||||||
|
match value {
|
||||||
|
Ok(value) => {
|
||||||
|
if !self.has_cycle(&value) {
|
||||||
|
list.entry(&Self {
|
||||||
|
visited: Rc::clone(&self.visited),
|
||||||
|
value,
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
log::warn!("Ignoring value at ordinal position {} which has cyclical reference", idx);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
list.entry(&err);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
list.finish()?;
|
||||||
|
drop(list);
|
||||||
|
Ok(())
|
||||||
|
} else {
|
||||||
|
// Treat as map; put it into a BTreeMap so that we have a stable
|
||||||
|
// order for our tests.
|
||||||
|
let mut map = BTreeMap::new();
|
||||||
|
for pair in t.clone().pairs::<LuaValue, LuaValue>() {
|
||||||
|
match pair {
|
||||||
|
Ok(pair) => {
|
||||||
|
if !self.has_cycle(&pair.1) {
|
||||||
|
map.insert(
|
||||||
|
Self {
|
||||||
|
visited: Rc::clone(&self.visited),
|
||||||
|
value: pair.0,
|
||||||
|
},
|
||||||
|
Self {
|
||||||
|
visited: Rc::clone(&self.visited),
|
||||||
|
value: pair.1,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
} else {
|
||||||
|
log::warn!(
|
||||||
|
"Ignoring field {:?} which has cyclical reference",
|
||||||
|
Self {
|
||||||
|
visited: Rc::clone(&self.visited),
|
||||||
|
value: pair.0
|
||||||
|
}
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Err(err) => {
|
||||||
|
log::error!("error while retrieving map entry: {}", err);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.debug_map().entries(&map).finish()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
LuaValue::UserData(_) | LuaValue::LightUserData(_) => fmt.write_str("userdata"),
|
||||||
|
LuaValue::Thread(_) => fmt.write_str("thread"),
|
||||||
|
LuaValue::Function(_) => fmt.write_str("function"),
|
||||||
|
LuaValue::Error(e) => fmt.write_fmt(format_args!("error {}", e)),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
use crate::scripting::guiwin::GuiWin;
|
use crate::scripting::guiwin::GuiWin;
|
||||||
use chrono::prelude::*;
|
use chrono::prelude::*;
|
||||||
use log::Level;
|
use log::Level;
|
||||||
|
use luahelper::ValuePrinter;
|
||||||
use mlua::Value;
|
use mlua::Value;
|
||||||
use mux::termwiztermtab::TermWizTerminal;
|
use mux::termwiztermtab::TermWizTerminal;
|
||||||
use termwiz::cell::{AttributeChange, CellAttributes, Intensity};
|
use termwiz::cell::{AttributeChange, CellAttributes, Intensity};
|
||||||
@ -133,7 +134,7 @@ pub fn show_debug_overlay(mut term: TermWizTerminal, gui_win: GuiWin) -> anyhow:
|
|||||||
let chunk = host.lua.load(&expr);
|
let chunk = host.lua.load(&expr);
|
||||||
match smol::block_on(chunk.eval_async::<Value>()) {
|
match smol::block_on(chunk.eval_async::<Value>()) {
|
||||||
Ok(result) => {
|
Ok(result) => {
|
||||||
let value = luahelper::lua_value_to_dynamic(result);
|
let value = ValuePrinter(result);
|
||||||
let text = format!("{:#?}", value);
|
let text = format!("{:#?}", value);
|
||||||
term.render(&[Change::Text(format!("{}\r\n", text.replace("\n", "\r\n")))])?;
|
term.render(&[Change::Text(format!("{}\r\n", text.replace("\n", "\r\n")))])?;
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user