Finish porting config.yml to init.lua

pull/173/head
Arijit Basu 3 years ago committed by Arijit Basu
parent da1d7742f7
commit 25a9d03237

2
Cargo.lock generated

@ -1099,7 +1099,7 @@ checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
[[package]]
name = "xplr"
version = "0.10.0-beta.3"
version = "0.10.0-beta.4"
dependencies = [
"anyhow",
"chrono",

@ -1,6 +1,6 @@
[package]
name = "xplr"
version = "0.10.0-beta.3" # Update config.yml, config.rs
version = "0.10.0-beta.4" # Update lua.rs
authors = ["Arijit Basu <sayanarijit@gmail.com>"]
edition = "2018"
description = "A hackable, minimal, fast TUI file explorer"

@ -1,6 +1,5 @@
use crate::config::Config;
use crate::config::Mode;
use crate::default_config::DEFAULT_LUA_SCRIPT;
use crate::explorer;
use crate::input::Key;
use crate::lua;
@ -15,12 +14,11 @@ use std::collections::HashMap;
use std::collections::VecDeque;
use std::env;
use std::fs;
use std::io;
use std::path::PathBuf;
pub const VERSION: &str = env!("CARGO_PKG_VERSION");
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)
@ -1459,59 +1457,20 @@ pub struct App {
impl App {
pub fn create(pwd: PathBuf, lua: &mlua::Lua) -> Result<Self> {
let config = lua::init(lua)?;
let config_dir = dirs::config_dir()
.unwrap_or_else(|| PathBuf::from("."))
.join("xplr");
let yaml_config_file = config_dir.join("config.yml");
let lua_script_file = config_dir.join("init.lua");
let default_config = Config::default();
let default_config_version = default_config.version().clone();
// TODO deprecate this ---------------------------------
let config: Config = if yaml_config_file.exists() {
let c: Config =
serde_yaml::from_reader(io::BufReader::new(&fs::File::open(&yaml_config_file)?))?;
c.extended()
} else {
default_config
};
if !config.is_compatible()? {
bail!(
"incompatible configuration version in {}
You config version is : {}
Required version is : {}
Visit {}",
yaml_config_file.to_string_lossy().to_string(),
config.version(),
default_config_version,
UPGRADE_GUIDE_LINK,
)
};
// -------------------------------------------------------
let config = lua::init(lua, DEFAULT_LUA_SCRIPT, config)?;
let lua_script_file = config_dir.join("init.lua");
let config = if lua_script_file.exists() {
lua::extend(lua, &fs::read_to_string(&lua_script_file)?)?
lua::extend(lua, &lua_script_file.to_string_lossy().to_string())?
} else {
config
};
if !config.is_compatible()? {
bail!(
"incompatible configuration version in {}
You config version is : {}
Required version is : {}
Visit {}",
lua_script_file.to_string_lossy().to_string(),
config.version(),
default_config_version,
UPGRADE_GUIDE_LINK,
)
};
let mode = match config.modes().get(
&config
.general()
@ -1563,9 +1522,9 @@ impl App {
let pwd = pwd.to_string_lossy().to_string();
let mut app = Self {
version: Config::default().version().clone(),
config: config.clone(),
let app = Self {
version: VERSION.to_string(),
config,
pwd,
directory_buffers: Default::default(),
selection: Default::default(),
@ -1583,31 +1542,6 @@ impl App {
last_modes: Default::default(),
};
if let Some(notif) = config.upgrade_notification()? {
let notif = format!(
"{}. To stop seeing this log, update your config version from {} to {}",
&notif,
config.version(),
app.version()
);
app = app.enqueue(Task::new(
MsgIn::External(ExternalMsg::LogInfo(notif)),
None,
));
}
// if yaml_config_file.exists() && !lua_script_file.exists() {
// let notif = format!(
// "`config.yml` will be deprecated in favor of `init.lua`. To stop this warning, create empty file {}",
// lua_script_file.to_string_lossy().to_string()
// );
// app = app.enqueue(Task::new(
// MsgIn::External(ExternalMsg::LogWarning(notif)),
// None,
// ));
// }
Ok(app)
}

@ -3,12 +3,10 @@ use crate::app::HelpMenuLine;
use crate::app::NodeFilter;
use crate::app::NodeSorter;
use crate::app::NodeSorterApplicable;
use crate::default_config;
use crate::ui::Border;
use crate::ui::Constraint;
use crate::ui::Layout;
use crate::ui::Style;
use anyhow::Result;
use indexmap::IndexMap;
use indexmap::IndexSet;
use serde::{Deserialize, Serialize};
@ -1219,11 +1217,9 @@ impl LayoutsConfig {
}
}
#[derive(Debug, Clone, Serialize, Deserialize)]
#[derive(Debug, Default, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub struct Config {
version: String,
#[serde(default)]
layouts: LayoutsConfig,
@ -1237,18 +1233,6 @@ pub struct Config {
modes: ModesConfig,
}
impl Default for Config {
fn default() -> Self {
Self {
version: default_config::version(),
layouts: default_config::layouts(),
general: default_config::general(),
node_types: default_config::node_types(),
modes: default_config::modes(),
}
}
}
impl Config {
pub fn extended(mut self) -> Self {
let default = Self::default();
@ -1259,51 +1243,6 @@ impl Config {
self
}
fn parsed_version(&self) -> Result<(u16, u16, u16, Option<u16>)> {
let mut configv = self
.version
.strip_prefix('v')
.unwrap_or_default()
.split('.');
let major = configv.next().unwrap_or_default().parse::<u16>()?;
let minor = configv.next().unwrap_or_default().parse::<u16>()?;
let bugfix = configv
.next()
.and_then(|s| s.split('-').next())
.unwrap_or_default()
.parse::<u16>()?;
let beta = configv.next().unwrap_or_default().parse::<u16>().ok();
Ok((major, minor, bugfix, beta))
}
pub fn is_compatible(&self) -> Result<bool> {
let result = match self.parsed_version()? {
(0, 10, 0, Some(3)) => true,
(0, 10, 0, Some(2)) => true,
(0, 10, 0, Some(1)) => true,
(_, _, _, _) => false,
};
Ok(result)
}
pub fn upgrade_notification(&self) -> Result<Option<&str>> {
let result = None;
// let result = match self.parsed_version()? {
// (_, _, _, _) => None,
// };
Ok(result)
}
/// Get a reference to the config's version.
pub fn version(&self) -> &String {
&self.version
}
/// Get a reference to the config's layouts.
pub fn layouts(&self) -> &LayoutsConfig {
&self.layouts
@ -1323,42 +1262,4 @@ impl Config {
pub fn modes(&self) -> &ModesConfig {
&self.modes
}
/// Set the config's version.
pub fn with_version(mut self, version: String) -> Self {
self.version = version;
self
}
}
#[cfg(test)]
mod test {
use super::*;
use std::collections::HashMap;
#[test]
fn test_compatibility() {
let config = Config::default();
assert!(config.is_compatible().unwrap());
assert_eq!(config.upgrade_notification().unwrap(), None);
}
#[test]
fn test_extend_hashmap() {
let mut a = HashMap::new();
let mut b = HashMap::new();
a.insert("a", "a");
a.insert("b", "a");
b.insert("b", "b");
b.insert("c", "b");
a.extend(b);
assert_eq!(a.get("a"), Some(&"a"));
assert_eq!(a.get("b"), Some(&"b"));
assert_eq!(a.get("c"), Some(&"b"));
}
}

@ -1,81 +0,0 @@
version: v0.10.0-beta.3
layouts:
custom: {}
builtin:
default:
Horizontal:
config:
horizontal_margin: 0
vertical_margin: 0
constraints:
- Percentage: 70
- Percentage: 30
splits:
- Vertical:
config:
margin: 0
constraints:
- Length: 3
- Min: 1
- Length: 3
splits:
- SortAndFilter: ~
- Table: ~
- InputAndLogs: ~
- Vertical:
config:
constraints:
- Percentage: 50
- Percentage: 50
splits:
- Selection: ~
- HelpMenu: ~
no_help:
Horizontal:
config:
constraints:
- Percentage: 70
- Percentage: 30
splits:
- Vertical:
config:
constraints:
- Length: 3
- Min: 1
- Length: 3
splits:
- SortAndFilter: ~
- Table: ~
- InputAndLogs: ~
- Selection: ~
no_selection:
Horizontal:
config:
constraints:
- Percentage: 70
- Percentage: 30
splits:
- Vertical:
config:
constraints:
- Length: 3
- Min: 1
- Length: 3
splits:
- SortAndFilter: ~
- Table: ~
- InputAndLogs: ~
- HelpMenu: ~
no_help_no_selection:
Vertical:
config:
constraints:
- Length: 3
- Min: 1
- Length: 3
splits:
- SortAndFilter: ~
- Table: ~
- InputAndLogs: ~

@ -1,29 +0,0 @@
const DEFAULT_CONFIG_YAML: &str = include_str!("config.yml");
pub const DEFAULT_LUA_SCRIPT: &str = include_str!("init.lua");
use crate::config::{self, Config};
use lazy_static::lazy_static;
lazy_static! {
static ref DEFAULT_CONFIG: Config = serde_yaml::from_str(DEFAULT_CONFIG_YAML).unwrap();
}
pub fn version() -> String {
DEFAULT_CONFIG.version().clone()
}
pub fn layouts() -> config::LayoutsConfig {
DEFAULT_CONFIG.layouts().clone()
}
pub fn general() -> config::GeneralConfig {
DEFAULT_CONFIG.general().clone()
}
pub fn node_types() -> config::NodeTypesConfig {
DEFAULT_CONFIG.node_types().clone()
}
pub fn modes() -> config::ModesConfig {
DEFAULT_CONFIG.modes().clone()
}

File diff suppressed because it is too large Load Diff

@ -5,7 +5,6 @@
pub mod app;
pub mod auto_refresher;
pub mod config;
pub mod default_config;
pub mod event_reader;
pub mod explorer;
pub mod input;

@ -1,8 +1,51 @@
use crate::app::VERSION;
use crate::config::Config;
use anyhow::bail;
use anyhow::Result;
use mlua::Lua;
use mlua::LuaSerdeExt;
use std::fs;
const DEFAULT_LUA_SCRIPT: &str = include_str!("init.lua");
const UPGRADE_GUIDE_LINK: &str = "https://github.com/sayanarijit/xplr/wiki/Upgrade-Guide";
fn parse_version(version: &str) -> Result<(u16, u16, u16, Option<u16>)> {
let mut configv = version.split('.');
let major = configv.next().unwrap_or_default().parse::<u16>()?;
let minor = configv.next().unwrap_or_default().parse::<u16>()?;
let bugfix = configv
.next()
.and_then(|s| s.split('-').next())
.unwrap_or_default()
.parse::<u16>()?;
let beta = configv.next().unwrap_or_default().parse::<u16>().ok();
Ok((major, minor, bugfix, beta))
}
/// Check the config version and notify users.
pub fn check_version(version: &str, path: &str) -> Result<()> {
// Until we're v1, let's ignore major versions
let (rmajor, rminor, rbugfix, rbeta) = parse_version(VERSION)?;
let (smajor, sminor, sbugfix, sbeta) = parse_version(version)?;
if rmajor == smajor && rminor == sminor && rbugfix <= sbugfix && rbeta == sbeta {
Ok(())
} else {
bail!(
"incompatible script version in {}
The script version is : {}
Required version is : {}
Visit {}",
path,
version,
VERSION.to_string(),
UPGRADE_GUIDE_LINK,
)
}
}
fn resolve_fn_recursive<'lua, 'a>(
table: &mlua::Table<'lua>,
@ -20,17 +63,14 @@ fn resolve_fn_recursive<'lua, 'a>(
}
/// This function resolves paths like `builtin.func_foo`, `custom.func_bar` into lua functions.
pub fn resolve_fn<'lua>(
globals: &mlua::Table<'lua>,
path: &str,
) -> Result<mlua::Function<'lua>> {
pub fn resolve_fn<'lua>(globals: &mlua::Table<'lua>, path: &str) -> Result<mlua::Function<'lua>> {
let path = format!("xplr.fn.{}", path);
resolve_fn_recursive(&globals, path.split('.'))
}
// TODO: Remove config input when config.yml is deprecated
/// Used to initialize Lua globals
pub fn init(lua: &Lua, lua_script: &str, config: Config) -> Result<Config> {
pub fn init(lua: &Lua) -> Result<Config> {
let config = Config::default();
let globals = lua.globals();
let lua_xplr = lua.create_table()?;
@ -45,31 +85,48 @@ pub fn init(lua: &Lua, lua_script: &str, config: Config) -> Result<Config> {
lua_xplr.set("fn", lua_xplr_fn)?;
globals.set("xplr", lua_xplr)?;
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,
Err(_) => bail!("'version' must be defined globally in init.lua"),
};
lua.load(DEFAULT_LUA_SCRIPT).set_name("init")?.exec()?;
let lua_xplr: mlua::Table = globals.get("xplr")?;
let config: Config = lua.from_value(lua_xplr.get("config")?)?;
Ok(config.with_version(version))
Ok(config)
}
/// Used to extend Lua globals
pub fn extend(lua: &Lua, lua_script: &str) -> Result<Config> {
lua.load(&lua_script).set_name("init")?.exec()?;
pub fn extend(lua: &Lua, path: &str) -> Result<Config> {
let globals = lua.globals();
let script = fs::read_to_string(path)?;
lua.load(&script).set_name("init")?.exec()?;
let version: String = match globals.get("version").and_then(|v| lua.from_value(v)) {
Ok(v) => v,
Err(_) => bail!("'version' must be defined globally in init.lua"),
Err(_) => bail!("'version' must be defined globally in {}", path),
};
check_version(&version, path)?;
let lua_xplr: mlua::Table = globals.get("xplr")?;
let config: Config = lua.from_value(lua_xplr.get("config")?)?;
Ok(config.with_version(version))
Ok(config)
}
#[cfg(test)]
mod test {
use super::*;
#[test]
fn test_compatibility() {
assert!(check_version(VERSION, "foo path").is_ok());
assert!(check_version("0.10.0-beta.4", "foo path").is_ok());
assert!(check_version("0.9.0", "foo path").is_err());
assert!(check_version("0.10.0", "foo path").is_err());
assert!(check_version("0.10.0-beta.3", "foo path").is_err());
assert!(check_version("0.10.0-beta.5", "foo path").is_err());
assert!(check_version("1.10.0-beta.4", "foo path").is_ok());
}
}

@ -35,7 +35,6 @@ fn call(app: &app::App, cmd: app::Command, silent: bool) -> io::Result<ExitStatu
Command::new(cmd.command().clone())
.env("XPLR_APP_VERSION", app.version())
.env("XPLR_CONFIG_VERSION", app.config().version())
.env("XPLR_PID", &app.pid().to_string())
.env("XPLR_INPUT_BUFFER", app.input_buffer().unwrap_or_default())
.env("XPLR_FOCUS_PATH", app.focused_node_str())

@ -70,12 +70,12 @@ impl LayoutOptions {
#[derive(Debug, Clone, Serialize, Deserialize)]
#[serde(deny_unknown_fields)]
pub enum Layout {
Nothing(Option<PanelUiConfig>),
Table(Option<PanelUiConfig>),
InputAndLogs(Option<PanelUiConfig>),
Selection(Option<PanelUiConfig>),
HelpMenu(Option<PanelUiConfig>),
SortAndFilter(Option<PanelUiConfig>),
Nothing,
Table,
InputAndLogs,
Selection,
HelpMenu,
SortAndFilter,
Horizontal {
config: LayoutOptions,
splits: Vec<Layout>,
@ -88,19 +88,14 @@ pub enum Layout {
impl Default for Layout {
fn default() -> Self {
Self::Nothing(Default::default())
Self::Nothing
}
}
impl Layout {
pub fn extend(self, other: Self) -> Self {
match (self, other) {
(s, Self::Nothing(_)) => s,
(Self::Table(s), Self::Table(o)) => Self::Table(o.or(s)),
(Self::InputAndLogs(s), Self::InputAndLogs(o)) => Self::InputAndLogs(o.or(s)),
(Self::Selection(s), Self::Selection(o)) => Self::Selection(o.or(s)),
(Self::HelpMenu(s), Self::HelpMenu(o)) => Self::HelpMenu(o.or(s)),
(Self::SortAndFilter(s), Self::SortAndFilter(o)) => Self::SortAndFilter(o.or(s)),
(s, Self::Nothing) => s,
(
Self::Horizontal {
config: sconfig,
@ -416,7 +411,6 @@ fn block<'a>(config: PanelUiConfig, default_title: String) -> Block<'a> {
}
fn draw_table<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
screen_size: Rect,
layout_size: Rect,
@ -424,13 +418,10 @@ fn draw_table<B: Backend>(
lua: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config
let config = panel_config
.default()
.clone()
.extend(panel_config.table().clone());
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let app_config = app.config().to_owned();
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();
@ -619,7 +610,6 @@ fn draw_table<B: Backend>(
}
fn draw_selection<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
_screen_size: Rect,
layout_size: Rect,
@ -627,13 +617,10 @@ fn draw_selection<B: Backend>(
_: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config
let config = panel_config
.default()
.clone()
.extend(panel_config.selection().clone());
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let selection: Vec<ListItem> = app
.selection()
.iter()
@ -654,7 +641,6 @@ fn draw_selection<B: Backend>(
}
fn draw_help_menu<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
_screen_size: Rect,
layout_size: Rect,
@ -662,13 +648,10 @@ fn draw_help_menu<B: Backend>(
_: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config
let config = panel_config
.default()
.clone()
.extend(panel_config.help_menu().clone());
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let help_menu_rows = app
.mode()
.help_menu()
@ -710,7 +693,6 @@ fn draw_help_menu<B: Backend>(
}
fn draw_input_buffer<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
_screen_size: Rect,
layout_size: Rect,
@ -718,13 +700,10 @@ fn draw_input_buffer<B: Backend>(
_: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config
let config = panel_config
.default()
.clone()
.extend(panel_config.input_and_logs().clone());
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let input_buf = Paragraph::new(Spans::from(vec![
Span::styled(
app.config()
@ -751,7 +730,6 @@ fn draw_input_buffer<B: Backend>(
}
fn draw_sort_n_filter<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
_screen_size: Rect,
layout_size: Rect,
@ -759,13 +737,10 @@ fn draw_sort_n_filter<B: Backend>(
_: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config
let config = panel_config
.default()
.clone()
.extend(panel_config.sort_and_filter().clone());
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let ui = app.config().general().sort_and_filter_ui().clone();
let filter_by = app.explorer_config().filters();
let sort_by = app.explorer_config().sorters();
@ -832,7 +807,6 @@ fn draw_sort_n_filter<B: Backend>(
}
fn draw_logs<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
_screen_size: Rect,
layout_size: Rect,
@ -840,13 +814,10 @@ fn draw_logs<B: Backend>(
_: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config
let config = panel_config
.default()
.clone()
.extend(panel_config.input_and_logs().clone());
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let logs_config = app.config().general().logs().clone();
let logs = if app.logs_hidden() {
vec![]
@ -909,7 +880,6 @@ fn draw_logs<B: Backend>(
}
pub fn draw_nothing<B: Backend>(
config: Option<PanelUiConfig>,
f: &mut Frame<B>,
_screen_size: Rect,
layout_size: Rect,
@ -917,10 +887,7 @@ pub fn draw_nothing<B: Backend>(
_lua: &Lua,
) {
let panel_config = app.config().general().panel_ui();
let default_panel_config = panel_config.default().clone();
let config = config
.map(|c| default_panel_config.clone().extend(c))
.unwrap_or(default_panel_config);
let config = panel_config.default().clone();
let nothing = Paragraph::new("").block(block(config, "".into()));
f.render_widget(nothing, layout_size);
}
@ -934,18 +901,16 @@ pub fn draw_layout<B: Backend>(
lua: &Lua,
) {
match layout {
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, lua)
}
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) => {
Layout::Nothing => draw_nothing(f, screen_size, layout_size, app, lua),
Layout::Table => draw_table(f, screen_size, layout_size, app, lua),
Layout::SortAndFilter => draw_sort_n_filter(f, screen_size, layout_size, app, lua),
Layout::HelpMenu => draw_help_menu(f, screen_size, layout_size, app, lua),
Layout::Selection => draw_selection(f, screen_size, layout_size, app, lua),
Layout::InputAndLogs => {
if app.input_buffer().is_some() {
draw_input_buffer(config, f, screen_size, layout_size, app, lua);
draw_input_buffer(f, screen_size, layout_size, app, lua);
} else {
draw_logs(config, f, screen_size, layout_size, app, lua);
draw_logs(f, screen_size, layout_size, app, lua);
};
}
Layout::Horizontal { config, splits } => {

Loading…
Cancel
Save