manen

Fancy Lua REPL
Log | Files | Refs | README | LICENSE

commit b6817731e46cf374b42642fc1c9c8fe9ea35d05b
parent 3904958712cb67c079a2e1ea8166fe52d31872a0
Author: Sylvia Ivory <git@sivory.net>
Date:   Fri, 20 Jun 2025 21:46:53 -0700

Pretty table printing

Diffstat:
Msrc/editor.rs | 85+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++------
1 file changed, 79 insertions(+), 6 deletions(-)

diff --git a/src/editor.rs b/src/editor.rs @@ -1,10 +1,13 @@ +use std::collections::HashSet; + +use comfy_table::{presets::UTF8_FULL, Table}; use mlua::prelude::*; use reedline::{DefaultPrompt, DefaultPromptSegment, Reedline, Signal}; use crate::highlight::LuaHighlighter; pub enum TableFormat { - Ascii, + Pretty, Lua, Address, } @@ -36,8 +39,8 @@ impl Editor { editor, lua, - table_format: TableFormat::Address, - print_nested_tables: false, + table_format: TableFormat::Pretty, + print_nested_tables: true, }) } @@ -61,11 +64,81 @@ impl Editor { } } + fn addr_tbl(tbl: &LuaTable) -> String { + format!("table@{:?}", tbl.to_pointer()) + } + + fn convert_string(string: &LuaString) -> String { + let bytes = string + .as_bytes() + .iter() + .flat_map(|b| std::ascii::escape_default(*b)) + .collect::<Vec<_>>(); + + String::from_utf8_lossy(&bytes).to_string() + } + + fn lua_to_string(value: &LuaValue) -> LuaResult<String> { + match value { + LuaValue::String(string) => Ok(Self::convert_string(string)), + LuaValue::Table(tbl) => Ok(Self::addr_tbl(tbl)), + value => value.to_string() + } + } + + fn pretty_table(&self, tbl: &LuaTable, visited: &mut HashSet<String>) -> LuaResult<String> { + let addr = Self::addr_tbl(tbl); + + if visited.contains(&addr) { + return Ok(format!("{addr} (self-reference)")) + } else { + visited.insert(addr.clone()); + } + + let mut table = Table::new(); + table.load_preset(UTF8_FULL); + + for (key, value) in tbl.pairs::<LuaValue, LuaValue>().flatten() { + let value_str = if let LuaValue::Table(sub) = value { + if self.print_nested_tables { + self.pretty_table(&sub, visited)? + } else { + addr.clone() + } + } else { + Self::lua_to_string(&value)? + }; + + table.add_row(vec![Self::lua_to_string(&key)?, value_str]); + } + + if table.is_empty() { + Ok(String::from("{}")) + } else { + Ok(table.to_string()) + } + } + + fn handle_table(&self, tbl: &LuaTable) -> LuaResult<()> { + match self.table_format { + TableFormat::Address => println!("table@{:?}", tbl.to_pointer()), + TableFormat::Lua => todo!(), + TableFormat::Pretty => { + let mut visited = HashSet::new(); + println!("{}", self.pretty_table(tbl, &mut visited)?) + } + } + + Ok(()) + } + fn eval(&mut self, line: &str) -> LuaResult<()> { - let res: LuaValue = self.lua.load(line).eval()?; + let value: LuaValue = self.lua.load(line).eval()?; - // TODO; pretty print tables - println!("{}", res.to_string()?); + match value { + LuaValue::Table(tbl) => self.handle_table(&tbl)?, + value => println!("{}", Self::lua_to_string(&value)?), + } Ok(()) }