manen

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

commit aa3a7f0297a6dfb679f1c7a163267e810702a10e
parent 2d4e6a46cc8afd76c79d32e748e0851f668d116f
Author: Sylvia Ivory <git@sivory.net>
Date:   Mon, 23 Jun 2025 03:27:50 -0700

Allow running Lua files

Diffstat:
Msrc/editor.rs | 1-
Msrc/format.rs | 16+++++++++-------
Msrc/inspect.rs | 30++++++++++++++++++++----------
Msrc/main.rs | 44+++++++++++++++++++++++++++++++++++++++++---
4 files changed, 70 insertions(+), 21 deletions(-)

diff --git a/src/editor.rs b/src/editor.rs @@ -119,7 +119,6 @@ impl Editor { value => display_basic(&value, true), }; - // TODO; colorize println!("{stringify}"); Ok(()) diff --git a/src/format.rs b/src/format.rs @@ -12,7 +12,7 @@ pub enum TableFormat { Address, } -fn comfy_table( +fn comfy_table_inner( tbl: &LuaTable, recursive: bool, visited: &mut HashMap<usize, usize>, @@ -29,7 +29,7 @@ fn comfy_table( let printable = is_short_printable(tbl); if printable { - return Ok(print_array(tbl)); + return Ok(print_array(tbl, false)); } let mut table = Table::new(); @@ -41,7 +41,7 @@ fn comfy_table( if recursive { ( display_basic(&key, false), - comfy_table(&sub, recursive, visited)?, + comfy_table_inner(&sub, recursive, visited)?, ) } else { ( @@ -63,6 +63,11 @@ fn comfy_table( } } +pub fn comfy_table(tbl: &LuaTable, recursive: bool) -> LuaResult<String> { + let mut visited = HashMap::new(); + comfy_table_inner(tbl, recursive, &mut visited) +} + impl TableFormat { pub fn format(&self, tbl: &LuaTable, colorize: bool) -> LuaResult<String> { match self { @@ -81,10 +86,7 @@ impl TableFormat { TableFormat::Inspect => { display_table(tbl, colorize).map_err(|e| LuaError::ExternalError(Arc::new(e))) } - TableFormat::ComfyTable(recursive) => { - let mut visited = HashMap::new(); - comfy_table(tbl, *recursive, &mut visited) - } + TableFormat::ComfyTable(recursive) => comfy_table(tbl, *recursive), } } } diff --git a/src/inspect.rs b/src/inspect.rs @@ -1,6 +1,7 @@ use std::{ collections::{HashMap, HashSet}, fmt::{self, Write}, + sync::Arc, }; use aho_corasick::AhoCorasick; @@ -144,8 +145,8 @@ fn format_string(lua_str: &LuaString, colorize: bool) -> String { } } -fn addr_color(val: &LuaValue) -> Option<(String, Color)> { - match val { +fn addr_color(value: &LuaValue) -> Option<(String, Color)> { + match value { LuaValue::LightUserData(l) => Some((format!("{:?}", l.0), Color::Cyan)), LuaValue::Table(t) => Some((format!("{:?}", t.to_pointer()), Color::LightBlue)), LuaValue::Function(f) => Some((format!("{:?}", f.to_pointer()), Color::Purple)), @@ -163,11 +164,11 @@ fn handle_strings<'a>(colorize: bool, strings: AnsiStrings<'a>) -> String { } } -pub fn display_basic(val: &LuaValue, colorize: bool) -> String { - match addr_color(val) { +pub fn display_basic(value: &LuaValue, colorize: bool) -> String { + match addr_color(value) { Some((addr, color)) => { let strings: &[AnsiString<'static>] = &[ - color.paint(val.type_name()), + color.paint(value.type_name()), Color::Default.paint("@"), Color::LightYellow.paint(addr), ]; @@ -175,7 +176,7 @@ pub fn display_basic(val: &LuaValue, colorize: bool) -> String { handle_strings(colorize, AnsiStrings(strings)) } None => { - let strings = &[match val { + let strings = &[match value { LuaValue::Nil => Color::LightRed.paint("nil"), LuaValue::Boolean(b) => Color::LightYellow.paint(b.to_string()), LuaValue::Integer(i) => Color::LightYellow.paint(i.to_string()), @@ -239,7 +240,7 @@ pub fn is_short_printable(tbl: &LuaTable) -> bool { is_short_printable_inner(tbl, &mut seen) } -pub fn print_array(tbl: &LuaTable) -> String { +pub fn print_array(tbl: &LuaTable, colorize: bool) -> String { let mut buff = Vec::new(); if tbl.is_empty() { @@ -248,9 +249,9 @@ pub fn print_array(tbl: &LuaTable) -> String { for (_, value) in tbl.pairs::<LuaValue, LuaValue>().flatten() { if let LuaValue::Table(inner) = value { - buff.push(print_array(&inner)); + buff.push(print_array(&inner, colorize)); } else { - buff.push(display_basic(&value, true)); + buff.push(display_basic(&value, colorize)); } } @@ -307,7 +308,7 @@ fn display_table_inner( let printable = is_short_printable(tbl); if printable { - return Ok(print_array(tbl)); + return Ok(print_array(tbl, colorize)); } let mut buffer = String::new(); @@ -351,3 +352,12 @@ pub fn display_table(tbl: &LuaTable, colorize: bool) -> Result<String, fmt::Erro display_table_inner(tbl, colorize, &mut seen, 0) } + +pub fn inspect(value: &LuaValue, colorize: bool) -> LuaResult<String> { + match value { + LuaValue::Table(tbl) => { + display_table(tbl, colorize).map_err(|e| LuaError::ExternalError(Arc::new(e))) + } + value => Ok(display_basic(value, colorize)), + } +} diff --git a/src/main.rs b/src/main.rs @@ -1,14 +1,17 @@ use std::{ fs, io::{self, Read}, - path::PathBuf, + path::{Path, PathBuf}, }; use clap::{Parser, Subcommand}; use editor::Editor; use highlight::LuaHighlighter; +use mlua::prelude::*; use reedline::Highlighter; +use crate::{format::comfy_table, inspect::inspect}; + mod editor; mod format; mod highlight; @@ -25,15 +28,50 @@ struct Cli { #[derive(Subcommand)] enum Command { - Repl, + Repl { path: Option<PathBuf> }, Highlight { path: Option<PathBuf> }, } +fn eval_lua(file: String, path: &Path) -> LuaResult<()> { + let lua = Lua::new(); + let globals = lua.globals(); + + globals.raw_set( + "inspect", + lua.create_function(|_, (value, colorize): (LuaValue, Option<bool>)| { + println!("{}", inspect(&value, colorize.unwrap_or(true))?); + Ok(()) + })?, + )?; + + globals.raw_set( + "comfytable", + lua.create_function(|_, (table, recursive): (LuaTable, Option<bool>)| { + println!("{}", comfy_table(&table, recursive.unwrap_or(true))?); + + Ok(()) + })?, + )?; + + lua.load(file) + .set_name(format!("@{}", path.to_string_lossy())) + .eval() +} + fn main() -> color_eyre::Result<()> { + color_eyre::install()?; + let cli = Cli::parse(); match &cli.command { - None | Some(Command::Repl) => Editor::new()?.run(), + None => Editor::new()?.run(), + Some(Command::Repl { path }) => { + if let Some(path) = path { + eval_lua(fs::read_to_string(path)?, path)?; + } else { + Editor::new()?.run() + } + } Some(Command::Highlight { path }) => { let file = if let Some(path) = path { fs::read_to_string(path)?