From 074e0d1250ccb3be4b16c05c398d681f9c9f5874 Mon Sep 17 00:00:00 2001 From: Arijit Basu Date: Fri, 21 May 2021 12:47:28 +0530 Subject: [PATCH] Replace handlebars with Lua Replace handlebars with Lua functions by introduction Lua function API. --- Cargo.lock | 157 +------------------------------------------ Cargo.toml | 3 +- benches/criterion.rs | 31 ++------- src/app.rs | 62 +++++++++++------ src/config.rs | 2 +- src/config.yml | 12 ++-- src/init.lua | 69 +++++++++++++++++++ src/lib.rs | 1 + src/lua.rs | 17 +++++ src/main.rs | 6 +- src/runner.rs | 29 ++------ src/ui.rs | 78 +++++++++++++-------- 12 files changed, 202 insertions(+), 265 deletions(-) create mode 100644 src/init.lua create mode 100644 src/lua.rs diff --git a/Cargo.lock b/Cargo.lock index b96910e..0312ab2 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -60,27 +60,6 @@ dependencies = [ "constant_time_eq", ] -[[package]] -name = "block-buffer" -version = "0.7.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0940dc441f31689269e10ac70eb1002a3a1d3ad1390e030043662eb7fe4688b" -dependencies = [ - "block-padding", - "byte-tools", - "byteorder", - "generic-array", -] - -[[package]] -name = "block-padding" -version = "0.1.5" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "fa79dedbb091f449f1f39e53edf88d5dbe95f895dae6135a8d7b881fb5af73f5" -dependencies = [ - "byte-tools", -] - [[package]] name = "bstr" version = "0.2.15" @@ -99,12 +78,6 @@ version = "3.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "63396b8a4b9de3f4fdfb320ab6080762242f66a8ef174c49d8e19b674db4cdbe" -[[package]] -name = "byte-tools" -version = "0.3.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e3b5ca7a04898ad4bcd41c90c5285445ff5b791899bb1b0abdd2a2aa791211d7" - [[package]] name = "byteorder" version = "1.4.3" @@ -297,15 +270,6 @@ dependencies = [ "memchr", ] -[[package]] -name = "digest" -version = "0.8.1" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f3d0c8c8752312f9713efd397ff63acb9f85585afbf179282e720e7704954dd5" -dependencies = [ - "generic-array", -] - [[package]] name = "dirs" version = "3.0.1" @@ -347,21 +311,6 @@ dependencies = [ "serde", ] -[[package]] -name = "fake-simd" -version = "0.1.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e88a8acf291dafb59c2d96e8f59828f3838bb1a70398823ade51a84de6a6deed" - -[[package]] -name = "generic-array" -version = "0.12.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "ffdf9f34f1447443d37393cc6c2b8313aebddcd96906caf34e54c68d8e57d7bd" -dependencies = [ - "typenum", -] - [[package]] name = "getrandom" version = "0.1.16" @@ -379,20 +328,6 @@ version = "1.7.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "62aca2aba2d62b4a7f5b33f3712cb1b0692779a56fb510499d5c0aa594daeaf3" -[[package]] -name = "handlebars" -version = "3.5.4" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "580b6f551b29a3a02436318aed09ba1c58eea177dc49e39beac627ad356730a5" -dependencies = [ - "log", - "pest", - "pest_derive", - "quick-error", - "serde", - "serde_json", -] - [[package]] name = "hashbrown" version = "0.9.1" @@ -410,9 +345,9 @@ dependencies = [ [[package]] name = "humansize" -version = "1.1.0" +version = "1.1.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b6cab2627acfc432780848602f3f558f7e9dd427352224b0d9324025796d2a5e" +checksum = "02296996cb8796d7c6e3bc2d9211b7802812d36999a51bb754123ead7d37d026" [[package]] name = "indexmap" @@ -521,12 +456,6 @@ dependencies = [ "cc", ] -[[package]] -name = "maplit" -version = "1.0.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3e2e65a1a2e43cfcb47a895c4c8b10d1f4a61097f9f254f183aee60cad9c651d" - [[package]] name = "memchr" version = "2.3.4" @@ -653,12 +582,6 @@ version = "11.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "0ab1bc2a289d34bd04a330323ac98a1b4bc82c9d9fcb1e66b63caa84da26b575" -[[package]] -name = "opaque-debug" -version = "0.2.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2839e79665f131bdb5782e51f2c6c9599c133c6098982a54c794358bf432529c" - [[package]] name = "parking_lot" version = "0.11.1" @@ -684,49 +607,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "pest" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "10f4872ae94d7b90ae48754df22fd42ad52ce740b8f370b03da4835417403e53" -dependencies = [ - "ucd-trie", -] - -[[package]] -name = "pest_derive" -version = "2.1.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "833d1ae558dc601e9a60366421196a8d94bc0ac980476d0b67e1d0988d72b2d0" -dependencies = [ - "pest", - "pest_generator", -] - -[[package]] -name = "pest_generator" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "99b8db626e31e5b81787b9783425769681b347011cc59471e33ea46d2ea0cf55" -dependencies = [ - "pest", - "pest_meta", - "proc-macro2", - "quote", - "syn", -] - -[[package]] -name = "pest_meta" -version = "2.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "54be6e404f5317079812fc8f9f5279de376d8856929e21c184ecf6bbd692a11d" -dependencies = [ - "maplit", - "pest", - "sha-1", -] - [[package]] name = "pkg-config" version = "0.3.19" @@ -770,12 +650,6 @@ dependencies = [ "unicode-xid", ] -[[package]] -name = "quick-error" -version = "2.0.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "3ac73b1112776fc109b2e61909bc46c7e1bf0d7f690ffb1676553acce16d5cda" - [[package]] name = "quote" version = "1.0.9" @@ -979,18 +853,6 @@ dependencies = [ "yaml-rust", ] -[[package]] -name = "sha-1" -version = "0.8.2" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f7d94d0bede923b3cea61f3f1ff57ff8cdfd77b400fb8f9998949e0cf04163df" -dependencies = [ - "block-buffer", - "digest", - "fake-simd", - "opaque-debug", -] - [[package]] name = "signal-hook" version = "0.1.17" @@ -1084,18 +946,6 @@ dependencies = [ "unicode-width", ] -[[package]] -name = "typenum" -version = "1.13.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "879f6906492a7cd215bfa4cf595b600146ccfac0c79bcbd1f3000162af5e8b06" - -[[package]] -name = "ucd-trie" -version = "0.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" - [[package]] name = "unicase" version = "2.6.0" @@ -1249,14 +1099,13 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f" [[package]] name = "xplr" -version = "0.10.0-beta.0" +version = "0.10.0-beta.1" dependencies = [ "anyhow", "chrono", "criterion", "crossterm", "dirs", - "handlebars", "humansize", "indexmap", "lazy_static", diff --git a/Cargo.toml b/Cargo.toml index e0b47bf..b2b1689 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "xplr" -version = "0.10.0-beta.0" # Update config.yml, config.rs +version = "0.10.0-beta.1" # Update config.yml, config.rs authors = ["Arijit Basu "] edition = "2018" description = "A hackable, minimal, fast TUI file explorer" @@ -21,7 +21,6 @@ crossterm = "0.18" dirs = "3.0.1" serde = { version = "1.0", features = ["derive"] } serde_yaml = "0.8" -handlebars = "3.5" mime_guess = "2.0.3" anyhow = "1.0" chrono = { version = "0.4", features = ["serde"] } diff --git a/benches/criterion.rs b/benches/criterion.rs index 2c09144..7a33b02 100644 --- a/benches/criterion.rs +++ b/benches/criterion.rs @@ -1,11 +1,8 @@ use crate::app; use crate::ui; -use anyhow::Result; use criterion::{criterion_group, criterion_main, Criterion}; use crossterm::execute; use crossterm::terminal as term; -use handlebars::{handlebars_helper, Handlebars}; -use humansize::{file_size_opts as options, FileSize}; use std::fs; use std::io::prelude::*; use termion::get_tty; @@ -15,15 +12,14 @@ use xplr::*; const PWD: &str = "/tmp/xplr_bench"; -handlebars_helper!(to_humansize: |size: i64| size.file_size(options::CONVENTIONAL).unwrap_or_default()); - fn navigation_benchmark(c: &mut Criterion) { fs::create_dir_all(PWD).unwrap(); (1..10000).for_each(|i| { fs::File::create(std::path::Path::new(PWD).join(i.to_string())).unwrap(); }); - let mut app = app::App::create(PWD.into()).expect("failed to create app"); + let lua = mlua::Lua::new(); + let mut app = app::App::create(PWD.into(), &lua).expect("failed to create app"); app = app .clone() @@ -100,7 +96,8 @@ fn draw_benchmark(c: &mut Criterion) { fs::File::create(std::path::Path::new(PWD).join(i.to_string())).unwrap(); }); - let mut app = app::App::create(PWD.into()).expect("failed to create app"); + let lua = mlua::Lua::new(); + let mut app = app::App::create(PWD.into(), &lua).expect("failed to create app"); app = app .clone() @@ -110,24 +107,6 @@ fn draw_benchmark(c: &mut Criterion) { )) .unwrap(); - let mut hb = Handlebars::new(); - hb.register_helper("humansize", Box::new(to_humansize)); - hb.register_template_string( - app::TEMPLATE_TABLE_ROW, - &app.config() - .general() - .table() - .row() - .cols() - .clone() - .unwrap_or_default() - .iter() - .map(|c| c.format().clone().unwrap_or_default()) - .collect::>() - .join("\t"), - ) - .unwrap(); - term::enable_raw_mode().unwrap(); let mut stdout = get_tty().unwrap(); // let mut stdout = stdout.lock(); @@ -139,7 +118,7 @@ fn draw_benchmark(c: &mut Criterion) { c.bench_function("draw on terminal", |b| { b.iter(|| { - terminal.draw(|f| ui::draw(f, &app, &hb)).unwrap(); + terminal.draw(|f| ui::draw(f, &app, &lua)).unwrap(); }) }); diff --git a/src/app.rs b/src/app.rs index 75bbf50..7bbf852 100644 --- a/src/app.rs +++ b/src/app.rs @@ -4,6 +4,7 @@ use crate::input::Key; use crate::ui::Layout; use anyhow::{bail, Result}; use chrono::{DateTime, Local}; +use humansize::{file_size_opts as options, FileSize}; use indexmap::set::IndexSet; use mlua::LuaSerdeExt; use serde::{Deserialize, Serialize}; @@ -19,6 +20,11 @@ pub const TEMPLATE_TABLE_ROW: &str = "TEMPLATE_TABLE_ROW"; pub const UNSUPPORTED_STR: &str = "???"; pub const UPGRADE_GUIDE_LINK: &str = "https://github.com/sayanarijit/xplr/wiki/Upgrade-Guide"; +fn to_humansize(size: u64) -> String { + size.file_size(options::CONVENTIONAL) + .unwrap_or_else(|_| format!("{} B", size)) +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Pipe { msg_in: String, @@ -125,6 +131,7 @@ pub struct ResolvedNode { is_readonly: bool, mime_essence: String, size: u64, + human_size: String, } impl ResolvedNode { @@ -144,6 +151,8 @@ impl ResolvedNode { .map(|m| m.essence_str().to_string()) .unwrap_or_default(); + let human_size = to_humansize(size); + Self { absolute_path: path.to_string_lossy().to_string(), extension, @@ -152,6 +161,7 @@ impl ResolvedNode { is_readonly, mime_essence, size, + human_size, } } @@ -189,6 +199,11 @@ impl ResolvedNode { pub fn size(&self) -> u64 { self.size } + + /// Get a reference to the resolved node's human size. + pub fn human_size(&self) -> &String { + &self.human_size + } } #[derive(Debug, Clone, Eq, Hash, PartialEq, Serialize, Deserialize)] @@ -204,6 +219,7 @@ pub struct Node { is_readonly: bool, mime_essence: String, size: u64, + human_size: String, canonical: Option, symlink: Option, } @@ -245,6 +261,8 @@ impl Node { .map(|m| m.essence_str().to_string()) .unwrap_or_default(); + let human_size = to_humansize(size); + Self { parent, relative_path, @@ -257,6 +275,7 @@ impl Node { is_readonly, mime_essence, size, + human_size, canonical: maybe_canonical_meta.clone(), symlink: if is_symlink { maybe_canonical_meta @@ -330,6 +349,11 @@ impl Node { pub fn absolute_path(&self) -> &String { &self.absolute_path } + + /// Get a reference to the node's human size. + pub fn human_size(&self) -> &String { + &self.human_size + } } impl Ord for Node { @@ -1417,18 +1441,6 @@ impl History { } } -#[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(deny_unknown_fields)] -pub struct LuaData { - config: Config, -} - -impl LuaData { - pub fn new(config: Config) -> Self { - Self { config } - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub struct App { version: String, @@ -1451,7 +1463,7 @@ pub struct App { } impl App { - pub fn create(pwd: PathBuf) -> Result { + pub fn create(pwd: PathBuf, lua: &mlua::Lua) -> Result { let config_dir = dirs::config_dir() .unwrap_or_else(|| PathBuf::from(".")) .join("xplr"); @@ -1485,17 +1497,22 @@ impl App { // ------------------------------------------------------- let config: Config = if lua_script_file.exists() { - let lua = mlua::Lua::new(); let globals = lua.globals(); let lua_script = fs::read_to_string(&lua_script_file)?; - let luadata = LuaData::new(config); - lua.to_value(&luadata) - .and_then(|v| globals.set("xplr", v))?; + let lua_xplr = lua.create_table()?; + lua_xplr.set("config", lua.to_value(&config)?)?; + + let lua_xplr_fn = lua.create_table()?; + let lua_xplr_fn_builtin = lua.create_table()?; + let lua_xplr_fn_custom = lua.create_table()?; + + lua_xplr_fn.set("builtin", lua_xplr_fn_builtin)?; + lua_xplr_fn.set("custom", lua_xplr_fn_custom)?; + lua_xplr.set("fn", lua_xplr_fn)?; + globals.set("xplr", lua_xplr)?; - lua.load(&lua_script) - .set_name("init") - .and_then(|l| l.exec())?; + lua.load(&lua_script).set_name("init")?.exec()?; let version: String = match globals.get("version").and_then(|v| lua.from_value(v)) { Ok(v) => v, @@ -1505,9 +1522,10 @@ impl App { )), }; - let luadata: LuaData = globals.get("xplr").and_then(|v| lua.from_value(v))?; + let lua_xplr: mlua::Table = globals.get("xplr")?; - luadata.config.with_version(version) + let config: Config = lua.from_value(lua_xplr.get("config")?)?; + config.with_version(version) } else { config }; diff --git a/src/config.rs b/src/config.rs index 92990a3..6036a2e 100644 --- a/src/config.rs +++ b/src/config.rs @@ -1281,7 +1281,7 @@ impl Config { pub fn is_compatible(&self) -> Result { let result = match self.parsed_version()? { - (0, 10, 0, Some(0)) => true, + (0, 10, 0, Some(1)) => true, (_, _, _, _) => false, }; diff --git a/src/config.yml b/src/config.yml index eeccf68..08724ca 100644 --- a/src/config.yml +++ b/src/config.yml @@ -1,4 +1,4 @@ -version: v0.10.0-beta.0 +version: v0.10.0-beta.1 layouts: custom: {} builtin: @@ -128,12 +128,10 @@ general: height: 1 row: cols: - - format: '{{#if isBeforeFocus}}-{{else}} {{/if}}{{{relativeIndex}}}│{{{index}}}' - - format: > - {{{tree}}}{{{prefix}}}{{{meta.icon}}}{{#if (ne meta.icon "")}} {{/if}}{{{relativePath}}}{{#if isDir}}/{{/if}}{{{suffix}}} - {{#if isSymlink}}-> {{#if isBroken}}×{{else}}{{{symlink.absolutePath}}}{{/if}}{{#if symlink.isDir}}/{{/if}}{{/if}} - - format: '{{#unless isDir}}{{humansize size}}{{/unless}}' - - format: '{{#if isSymlink}}{{{symlink.mimeEssence}}}{{else}}{{{mimeEssence}}}{{/if}}' + - format: xplr.fn.builtin.fmt_general_table_row_cols_0 + - format: xplr.fn.builtin.fmt_general_table_row_cols_1 + - format: xplr.fn.builtin.fmt_general_table_row_cols_2 + - format: xplr.fn.builtin.fmt_general_table_row_cols_3 height: 0 tree: - format: ├─ diff --git a/src/init.lua b/src/init.lua new file mode 100644 index 0000000..c78d884 --- /dev/null +++ b/src/init.lua @@ -0,0 +1,69 @@ +version = 'v0.10.0-beta.1' + +config = xplr.config +fn = xplr.fn + +fn.builtin.fmt_general_table_row_cols_0 = function(m) + local r = "" + if m.is_before_focus then + r = r .. " -" + else + r = r .. " " + end + + r = r .. m.relative_index .. "│" .. m.index + + return r +end + +fn.builtin.fmt_general_table_row_cols_1 = function(m) + local r = m.tree .. m.prefix + + if m.meta.icon == nil then + r = " " .. r + end + + r = r .. m.relative_path + + if m.is_dir then + r = r .. "/" + end + + r = r .. m.suffix .. " " + + if m.is_symlink then + r = r .. "-> " + + if m.is_broken then + r = r .. "×" + else + r = r .. m.absolute_path + end + + if m.symlink.is_dir then + r = r .. "/" + end + end + + return r +end + +fn.builtin.fmt_general_table_row_cols_2 = function(m) + if not m.is_dir then + return m.human_size + else + return "" + end +end + +fn.builtin.fmt_general_table_row_cols_3 = function(m) + if m.is_symlink then + return m.symlink.mime_essence + else + return m.mime_essence + end +end + +fn.custom.foo = function(a, b) + return a + b +end diff --git a/src/lib.rs b/src/lib.rs index dadddcc..ed56a85 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -9,6 +9,7 @@ pub mod default_config; pub mod event_reader; pub mod explorer; pub mod input; +pub mod lua; pub mod pipe_reader; pub mod pwd_watcher; pub mod runner; diff --git a/src/lua.rs b/src/lua.rs new file mode 100644 index 0000000..62d520f --- /dev/null +++ b/src/lua.rs @@ -0,0 +1,17 @@ +use anyhow::bail; +use anyhow::Result; + +pub fn resolve_fn<'lua, 'a>( + table: &mlua::Table<'lua>, + mut path: impl Iterator, +) -> Result> { + if let Some(nxt) = path.next() { + match table.get(nxt)? { + mlua::Value::Table(t) => resolve_fn(&t, path), + mlua::Value::Function(f) => Ok(f), + t => bail!("{:?} is not a function", t), + } + } else { + bail!("Invalid path") + } +} diff --git a/src/main.rs b/src/main.rs index 6f5e04e..07fef2e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -21,12 +21,14 @@ fn main() { pwd = pwd.parent().map(|p| p.into()).unwrap_or_default(); } - let app = app::App::create(pwd).unwrap_or_else(|e| { + let lua = mlua::Lua::new(); + + let app = app::App::create(pwd, &lua).unwrap_or_else(|e| { eprintln!("error: {}", e); std::process::exit(1); }); - match runner::run(app, focused_path) { + match runner::run(app, focused_path, lua) { Ok(Some(out)) => print!("{}", out), Ok(None) => {} Err(err) => { diff --git a/src/runner.rs b/src/runner.rs index 33a832c..2f83669 100644 --- a/src/runner.rs +++ b/src/runner.rs @@ -10,8 +10,6 @@ use crate::ui; use anyhow::Result; use crossterm::execute; use crossterm::terminal as term; -use handlebars::{handlebars_helper, Handlebars}; -use humansize::{file_size_opts as options, FileSize}; use std::fs; use std::io; use std::io::prelude::*; @@ -21,8 +19,6 @@ use termion::get_tty; use tui::backend::CrosstermBackend; use tui::Terminal; -handlebars_helper!(to_humansize: |size: i64| size.file_size(options::CONVENTIONAL).unwrap_or_default()); - fn call(app: &app::App, cmd: app::Command, silent: bool) -> io::Result { let focus_index = app .directory_buffer() @@ -65,7 +61,11 @@ fn call(app: &app::App, cmd: app::Command, silent: bool) -> io::Result) -> Result> { +pub fn run( + mut app: app::App, + focused_path: Option, + lua: mlua::Lua, +) -> Result> { let (tx_msg_in, rx_msg_in) = mpsc::channel(); let (tx_event_reader, rx_event_reader) = mpsc::channel(); let (tx_pwd_watcher, rx_pwd_watcher) = mpsc::channel(); @@ -78,23 +78,6 @@ pub fn run(mut app: app::App, focused_path: Option) -> Result>() - .join("\t"), - )?; - let mut result = Ok(None); let session_path = app.session_path().to_owned(); @@ -190,7 +173,7 @@ pub fn run(mut app: app::App, focused_path: Option) -> Result { diff --git a/src/ui.rs b/src/ui.rs index 831fa22..663dee9 100644 --- a/src/ui.rs +++ b/src/ui.rs @@ -2,9 +2,11 @@ use crate::app; use crate::app::HelpMenuLine; use crate::app::{Node, ResolvedNode}; use crate::config::PanelUiConfig; -use handlebars::Handlebars; +use crate::lua::resolve_fn; use indexmap::IndexSet; use lazy_static::lazy_static; +use mlua::Lua; +use mlua::LuaSerdeExt; use serde::{Deserialize, Serialize}; use std::cmp::Ordering; use std::collections::HashMap; @@ -292,7 +294,6 @@ impl Constraint { } #[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] pub struct ResolvedNodeUiMetadata { absolute_path: String, extension: String, @@ -301,6 +302,7 @@ pub struct ResolvedNodeUiMetadata { is_readonly: bool, mime_essence: String, size: u64, + human_size: String, } impl From for ResolvedNodeUiMetadata { @@ -313,12 +315,12 @@ impl From for ResolvedNodeUiMetadata { is_readonly: node.is_readonly(), mime_essence: node.mime_essence().clone(), size: node.size(), + human_size: node.human_size().clone(), } } } #[derive(Debug, Clone, Serialize, Deserialize)] -#[serde(rename_all = "camelCase")] struct NodeUiMetadata { // From Node parent: String, @@ -332,6 +334,7 @@ struct NodeUiMetadata { is_readonly: bool, mime_essence: String, size: u64, + human_size: String, canonical: Option, symlink: Option, @@ -376,6 +379,7 @@ impl NodeUiMetadata { is_readonly: node.is_readonly(), mime_essence: node.mime_essence().clone(), size: node.size(), + human_size: node.human_size().clone(), canonical: node.canonical().to_owned().map(|s| s.into()), symlink: node.symlink().to_owned().map(|s| s.into()), index, @@ -417,7 +421,7 @@ fn draw_table( screen_size: Rect, layout_size: Rect, app: &app::App, - hb: &Handlebars, + lua: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config @@ -431,6 +435,8 @@ fn draw_table( let header_height = app_config.general().table().header().height().unwrap_or(1); let height: usize = (layout_size.height.max(header_height + 2) - (header_height + 2)).into(); + let globals = lua.globals(); + let rows = app .directory_buffer() .map(|dir| { @@ -530,12 +536,28 @@ fn draw_table( node_type.meta().clone(), ); - let cols = hb - .render(app::TEMPLATE_TABLE_ROW, &meta) - .ok() - .unwrap_or_else(|| app::UNSUPPORTED_STR.into()) - .split('\t') - .map(|x| Cell::from(x.to_string())) + let cols = lua + .to_value::(&meta) + .map(|v| { + app_config + .general() + .table() + .row() + .cols() + .clone() + .unwrap_or_default() + .iter() + .filter_map(|c| { + c.format() + .to_owned() + .and_then(|f| resolve_fn(&globals, f.split('.')).ok()) + }) + .map(|f| f.call((v.clone(),)).unwrap_or_else(|e| e.to_string())) + .collect::>() + }) + .unwrap_or_default() + .iter() + .map(|x| Cell::from(x.to_owned())) .collect::>(); Row::new(cols).style(style.into()) @@ -602,7 +624,7 @@ fn draw_selection( _screen_size: Rect, layout_size: Rect, app: &app::App, - _: &Handlebars, + _: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config @@ -637,7 +659,7 @@ fn draw_help_menu( _screen_size: Rect, layout_size: Rect, app: &app::App, - _: &Handlebars, + _: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config @@ -693,7 +715,7 @@ fn draw_input_buffer( _screen_size: Rect, layout_size: Rect, app: &app::App, - _: &Handlebars, + _: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config @@ -734,7 +756,7 @@ fn draw_sort_n_filter( _screen_size: Rect, layout_size: Rect, app: &app::App, - _: &Handlebars, + _: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config @@ -815,7 +837,7 @@ fn draw_logs( _screen_size: Rect, layout_size: Rect, app: &app::App, - _: &Handlebars, + _: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config @@ -892,7 +914,7 @@ pub fn draw_nothing( _screen_size: Rect, layout_size: Rect, app: &app::App, - _hb: &Handlebars, + _lua: &Lua, ) { let panel_config = app.config().general().panel_ui(); let default_panel_config = panel_config.default().clone(); @@ -909,21 +931,21 @@ pub fn draw_layout( screen_size: Rect, layout_size: Rect, app: &app::App, - hb: &Handlebars, + lua: &Lua, ) { match layout { - Layout::Nothing(config) => draw_nothing(config, f, screen_size, layout_size, app, hb), - Layout::Table(config) => draw_table(config, f, screen_size, layout_size, app, hb), + Layout::Nothing(config) => draw_nothing(config, f, screen_size, layout_size, app, lua), + Layout::Table(config) => draw_table(config, f, screen_size, layout_size, app, lua), Layout::SortAndFilter(config) => { - draw_sort_n_filter(config, f, screen_size, layout_size, app, hb) + draw_sort_n_filter(config, f, screen_size, layout_size, app, lua) } - Layout::HelpMenu(config) => draw_help_menu(config, f, screen_size, layout_size, app, hb), - Layout::Selection(config) => draw_selection(config, f, screen_size, layout_size, app, hb), + Layout::HelpMenu(config) => draw_help_menu(config, f, screen_size, layout_size, app, lua), + Layout::Selection(config) => draw_selection(config, f, screen_size, layout_size, app, lua), Layout::InputAndLogs(config) => { if app.input_buffer().is_some() { - draw_input_buffer(config, f, screen_size, layout_size, app, hb); + draw_input_buffer(config, f, screen_size, layout_size, app, lua); } else { - draw_logs(config, f, screen_size, layout_size, app, hb); + draw_logs(config, f, screen_size, layout_size, app, lua); }; } Layout::Horizontal { config, splits } => { @@ -955,7 +977,7 @@ pub fn draw_layout( splits .into_iter() .zip(chunks.into_iter()) - .for_each(|(split, chunk)| draw_layout(split, f, screen_size, chunk, app, hb)); + .for_each(|(split, chunk)| draw_layout(split, f, screen_size, chunk, app, lua)); } Layout::Vertical { config, splits } => { @@ -987,16 +1009,16 @@ pub fn draw_layout( splits .into_iter() .zip(chunks.into_iter()) - .for_each(|(split, chunk)| draw_layout(split, f, screen_size, chunk, app, hb)); + .for_each(|(split, chunk)| draw_layout(split, f, screen_size, chunk, app, lua)); } } } -pub fn draw(f: &mut Frame, app: &app::App, hb: &Handlebars) { +pub fn draw(f: &mut Frame, app: &app::App, lua: &Lua) { let screen_size = f.size(); let layout = app.layout().clone(); - draw_layout(layout, f, screen_size, screen_size, app, hb); + draw_layout(layout, f, screen_size, screen_size, app, lua); } #[cfg(test)]