Add support for loading extra config files

Use `-C` / `--extra-config` to load Lua files to overwrite the default
or user defined config.

This helps with integration, where integrating xplr with another tool
requires xplr to overwrite some config, without requiring the users to
install an xplr plugin or update the xplr config.

Example:

```bash
    xplr -C one.lua two.lua

    # Or

    xplr -C one.lua -C two.lua
```

> **WARNING:**
>
> Extra config doesn't require specifying the `version`, hence, it's the
> integration author or the user's responsibility to assert
> compatibility using the globally exposed `version` in the extra config
> files, similar to xplr plugins.

Ref: https://github.com/sayanarijit/xplr/issues/316
remotes/origin/update/version
Arijit Basu 3 years ago committed by Arijit Basu
parent d6766919de
commit 61657a70c7

80
Cargo.lock generated

@ -2,24 +2,24 @@
# It is not intended for manual editing. # It is not intended for manual editing.
[[package]] [[package]]
name = "ansi-to-tui" name = "ansi-to-tui"
version = "0.3.0" version = "0.4.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "78688ae13e204ce559701516a0198d5fb54530b73eb1b3ecf404b4b79ed48dbf" checksum = "27ee8aff7256290439849cfde35078b996c3ce0a3cd5e0703f6c08384f0bc4a6"
dependencies = [ dependencies = [
"tui", "tui",
] ]
[[package]] [[package]]
name = "anyhow" name = "anyhow"
version = "1.0.42" version = "1.0.43"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "595d3cfa7a60d4555cb5067b99f07142a08ea778de5cf993f7b75c7d8fabc486" checksum = "28ae2b3dec75a406790005a200b1bd89785afc02517a00ca99ecfe093ee9e6cf"
[[package]] [[package]]
name = "assert_cmd" name = "assert_cmd"
version = "1.0.7" version = "2.0.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "3d20831bd004dda4c7c372c19cdabff369f794a95e955b3f13fe460e3e1ae95f" checksum = "54f002ce7d0c5e809ebb02be78fd503aeed4a511fd0fcaff6e6914cbdabbfa33"
dependencies = [ dependencies = [
"bstr", "bstr",
"doc-comment", "doc-comment",
@ -202,22 +202,6 @@ dependencies = [
"lazy_static", "lazy_static",
] ]
[[package]]
name = "crossterm"
version = "0.19.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7c36c10130df424b2f3552fcc2ddcd9b28a27b1e54b358b45874f88d1ca6888c"
dependencies = [
"bitflags",
"crossterm_winapi 0.7.0",
"lazy_static",
"libc",
"mio",
"parking_lot",
"signal-hook 0.1.17",
"winapi",
]
[[package]] [[package]]
name = "crossterm" name = "crossterm"
version = "0.20.0" version = "0.20.0"
@ -225,24 +209,15 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d" checksum = "c0ebde6a9dd5e331cd6c6f48253254d117642c31653baa475e394657c59c1f7d"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"crossterm_winapi 0.8.0", "crossterm_winapi",
"libc", "libc",
"mio", "mio",
"parking_lot", "parking_lot",
"signal-hook 0.3.9", "signal-hook",
"signal-hook-mio", "signal-hook-mio",
"winapi", "winapi",
] ]
[[package]]
name = "crossterm_winapi"
version = "0.7.0"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "0da8964ace4d3e4a044fd027919b2237000b24315a37c916f61809f1ff2140b9"
dependencies = [
"winapi",
]
[[package]] [[package]]
name = "crossterm_winapi" name = "crossterm_winapi"
version = "0.8.0" version = "0.8.0"
@ -417,9 +392,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
[[package]] [[package]]
name = "libc" name = "libc"
version = "0.2.98" version = "0.2.100"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "320cfe77175da3a483efed4bc0adc1968ca050b098ce4f2f1c13a56626128790" checksum = "a1fa8cddc8fbbee11227ef194b5317ed014b8acbf15139bd716a18ad3fe99ec5"
[[package]] [[package]]
name = "linked-hash-map" name = "linked-hash-map"
@ -796,9 +771,9 @@ checksum = "5f3aac57ee7f3272d8395c6e4f502f434f0e289fcd62876f70daa008c20dcabe"
[[package]] [[package]]
name = "serde" name = "serde"
version = "1.0.126" version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "ec7505abeacaec74ae4778d9d9328fe5a5d04253220a85c4ee022239fc996d03" checksum = "1056a0db1978e9dbf0f6e4fca677f6f9143dc1c19de346f22cac23e422196834"
dependencies = [ dependencies = [
"serde_derive", "serde_derive",
] ]
@ -815,9 +790,9 @@ dependencies = [
[[package]] [[package]]
name = "serde_derive" name = "serde_derive"
version = "1.0.126" version = "1.0.128"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "963a7dbc9895aeac7ac90e74f34a5d5261828f79df35cbed41e10189d3804d43" checksum = "13af2fbb8b60a8950d6c72a56d2095c28870367cc8e10c55e9745bac4995a2c4"
dependencies = [ dependencies = [
"proc-macro2", "proc-macro2",
"quote", "quote",
@ -837,27 +812,16 @@ dependencies = [
[[package]] [[package]]
name = "serde_yaml" name = "serde_yaml"
version = "0.8.17" version = "0.8.19"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "15654ed4ab61726bf918a39cb8d98a2e2995b002387807fa6ba58fdf7f59bb23" checksum = "6375dbd828ed6964c3748e4ef6d18e7a175d408ffe184bca01698d0c73f915a9"
dependencies = [ dependencies = [
"dtoa", "dtoa",
"linked-hash-map", "indexmap",
"serde", "serde",
"yaml-rust", "yaml-rust",
] ]
[[package]]
name = "signal-hook"
version = "0.1.17"
source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "7e31d442c16f047a671b5a71e2161d6e68814012b7f5379d269ebd915fac2729"
dependencies = [
"libc",
"mio",
"signal-hook-registry",
]
[[package]] [[package]]
name = "signal-hook" name = "signal-hook"
version = "0.3.9" version = "0.3.9"
@ -876,7 +840,7 @@ checksum = "29fd5867f1c4f2c5be079aee7a2adf1152ebb04a4bc4d341f504b7dece607ed4"
dependencies = [ dependencies = [
"libc", "libc",
"mio", "mio",
"signal-hook 0.3.9", "signal-hook",
] ]
[[package]] [[package]]
@ -943,13 +907,13 @@ checksum = "a7f741b240f1a48843f9b8e0444fb55fb2a4ff67293b50a9179dfd5ea67f8d41"
[[package]] [[package]]
name = "tui" name = "tui"
version = "0.15.0" version = "0.16.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "861d8f3ad314ede6219bcb2ab844054b1de279ee37a9bc38e3d606f9d3fb2a71" checksum = "39c8ce4e27049eed97cfa363a5048b09d995e209994634a0efc26a14ab6c0c23"
dependencies = [ dependencies = [
"bitflags", "bitflags",
"cassowary", "cassowary",
"crossterm 0.19.0", "crossterm",
"serde", "serde",
"unicode-segmentation", "unicode-segmentation",
"unicode-width", "unicode-width",
@ -1118,7 +1082,7 @@ dependencies = [
"assert_cmd", "assert_cmd",
"chrono", "chrono",
"criterion", "criterion",
"crossterm 0.20.0", "crossterm",
"dirs", "dirs",
"humansize", "humansize",
"indexmap", "indexmap",

@ -18,25 +18,25 @@ categories = ["command-line-interface", "command-line-utilities"]
name = "xplr" name = "xplr"
[dependencies] [dependencies]
tui = { version = "0.15.0", default-features = false, features = ['crossterm', 'serde'] } tui = { version = "0.16.0", default-features = false, features = ['crossterm', 'serde'] }
crossterm = "0.20.0" crossterm = "0.20.0"
dirs = "3.0.2" dirs = "3.0.2"
serde = { version = "1.0.126", features = ["derive"] } serde = { version = "1.0.128", features = ["derive"] }
serde_yaml = "0.8.17" serde_yaml = "0.8.19"
mime_guess = "2.0.3" mime_guess = "2.0.3"
anyhow = "1.0.42" anyhow = "1.0.43"
chrono = { version = "0.4.19", features = ["serde"] } chrono = { version = "0.4.19", features = ["serde"] }
lazy_static = "1.4.0" lazy_static = "1.4.0"
indexmap = { version = "1.7.0", features = ["serde"] } indexmap = { version = "1.7.0", features = ["serde"] }
natord = "1.0.9" natord = "1.0.9"
humansize = "1.1.1" humansize = "1.1.1"
mlua = { version = "0.6.2", features = ["luajit", "vendored", "serialize", "send"] } mlua = { version = "0.6.2", features = ["luajit", "vendored", "serialize", "send"] }
ansi-to-tui = "0.3.0" ansi-to-tui = "0.4.0"
libc = "0.2.98" libc = "0.2.100"
[dev-dependencies] [dev-dependencies]
criterion = "0.3.5" criterion = "0.3.5"
assert_cmd = "1.0.7" assert_cmd = "2.0.0"
[[bench]] [[bench]]
name = "criterion" name = "criterion"

@ -18,7 +18,8 @@ fn navigation_benchmark(c: &mut Criterion) {
}); });
let lua = mlua::Lua::new(); let lua = mlua::Lua::new();
let mut app = app::App::create(PWD.into(), &lua, None).expect("failed to create app"); let mut app =
app::App::create(PWD.into(), &lua, None, [].into()).expect("failed to create app");
app = app app = app
.clone() .clone()
@ -96,7 +97,8 @@ fn draw_benchmark(c: &mut Criterion) {
}); });
let lua = mlua::Lua::new(); let lua = mlua::Lua::new();
let mut app = app::App::create(PWD.into(), &lua, None).expect("failed to create app"); let mut app =
app::App::create(PWD.into(), &lua, None, [].into()).expect("failed to create app");
app = app app = app
.clone() .clone()

@ -1536,8 +1536,13 @@ pub struct App {
} }
impl App { impl App {
pub fn create(pwd: PathBuf, lua: &mlua::Lua, config_file: Option<PathBuf>) -> Result<Self> { pub fn create(
let config = lua::init(lua)?; pwd: PathBuf,
lua: &mlua::Lua,
config_file: Option<PathBuf>,
extra_config_files: Vec<PathBuf>,
) -> Result<Self> {
let mut config = lua::init(lua)?;
let config_file = if let Some(path) = config_file { let config_file = if let Some(path) = config_file {
path path
@ -1547,14 +1552,19 @@ impl App {
PathBuf::from("/").join("etc").join("xplr").join("init.lua") PathBuf::from("/").join("etc").join("xplr").join("init.lua")
}; };
let (config, load_err) = if config_file.exists() { let config_files = std::iter::once(config_file).chain(extra_config_files.into_iter());
let mut load_errs = vec![];
for config_file in config_files {
match lua::extend(lua, &config_file.to_string_lossy().to_string()) { match lua::extend(lua, &config_file.to_string_lossy().to_string()) {
Ok(c) => (c, None), Ok(c) => {
Err(e) => (config, Some(e.to_string())), config = c;
}
Err(e) => {
load_errs.push(e.to_string());
}
} }
} else { }
(config, None)
};
let mode = match config.modes().get( let mode = match config.modes().get(
&config &config
@ -1606,7 +1616,7 @@ impl App {
env::set_current_dir(&pwd)?; env::set_current_dir(&pwd)?;
let pwd = pwd.to_string_lossy().to_string(); let pwd = pwd.to_string_lossy().to_string();
let app = Self { let mut app = Self {
version: VERSION.to_string(), version: VERSION.to_string(),
config, config,
pwd, pwd,
@ -1629,11 +1639,11 @@ impl App {
fs::create_dir_all(app.session_path())?; fs::create_dir_all(app.session_path())?;
if let Some(err) = load_err { for err in load_errs {
app.log_error(err) app = app.log_error(err)?
} else {
Ok(app)
} }
Ok(app)
} }
pub fn focused_node(&self) -> Option<&Node> { pub fn focused_node(&self) -> Option<&Node> {

@ -14,6 +14,7 @@ struct Cli {
read_only: bool, read_only: bool,
path: Option<PathBuf>, path: Option<PathBuf>,
config: Option<PathBuf>, config: Option<PathBuf>,
extra_config: Vec<PathBuf>,
on_load: Vec<app::ExternalMsg>, on_load: Vec<app::ExternalMsg>,
} }
@ -51,6 +52,17 @@ impl Cli {
// Options // Options
"-c" | "--config" => cli.config = args.pop_front().map(PathBuf::from), "-c" | "--config" => cli.config = args.pop_front().map(PathBuf::from),
"-C" | "--extra-config" => {
while let Some(path) = args.pop_front() {
if path.starts_with('-') {
args.push_front(path);
break;
} else {
cli.extra_config.push(PathBuf::from(path));
}
}
}
"--read-only" => cli.read_only = true, "--read-only" => cli.read_only = true,
"--on-load" => { "--on-load" => {
@ -94,9 +106,10 @@ fn main() {
-V, --version Prints version information"###; -V, --version Prints version information"###;
let options = r###" let options = r###"
-c, --config <PATH> Specifies a custom config file (default is -c, --config <PATH> Specifies a custom config file (default is
"$HOME/.config/xplr/init.lua") "$HOME/.config/xplr/init.lua")
--on-load <MESSAGE>... Sends messages when xplr loads"###; -C, --extra-config <PATH>... Specifies extra config files to load
--on-load <MESSAGE>... Sends messages when xplr loads"###;
let args = r###" let args = r###"
<PATH> Path to focus on, or enter if directory"###; <PATH> Path to focus on, or enter if directory"###;
@ -120,6 +133,7 @@ fn main() {
match app::runner(cli.path.clone()) match app::runner(cli.path.clone())
.map(|a| a.with_on_load(cli.on_load.clone())) .map(|a| a.with_on_load(cli.on_load.clone()))
.map(|a| a.with_config(cli.config.clone())) .map(|a| a.with_config(cli.config.clone()))
.map(|a| a.with_extra_config(cli.extra_config.clone()))
.map(|a| a.with_read_only(cli.read_only)) .map(|a| a.with_read_only(cli.read_only))
.and_then(|a| a.run()) .and_then(|a| a.run())
{ {

@ -2403,9 +2403,9 @@ xplr.fn.builtin.fmt_general_table_row_cols_2 = function(m)
elseif p.other_execute == true and p.setuid == false then elseif p.other_execute == true and p.setuid == false then
r = r .. bit("x", red, p.other_execute) r = r .. bit("x", red, p.other_execute)
elseif p.other_execute == false and p.setuid == true then elseif p.other_execute == false and p.setuid == true then
r = r .. bit("S", red, p.other_execute) r = r .. bit("T", red, p.other_execute)
else else
r = r .. bit("s", red, p.other_execute) r = r .. bit("t", red, p.other_execute)
end end
return r return r

@ -99,7 +99,8 @@ fn start_fifo(path: &str, focus_path: &str) -> Result<fs::File> {
pub struct Runner { pub struct Runner {
pwd: PathBuf, pwd: PathBuf,
focused_path: Option<PathBuf>, focused_path: Option<PathBuf>,
config: Option<PathBuf>, config_file: Option<PathBuf>,
extra_config_files: Vec<PathBuf>,
on_load: Vec<app::ExternalMsg>, on_load: Vec<app::ExternalMsg>,
read_only: bool, read_only: bool,
} }
@ -120,7 +121,8 @@ impl Runner {
Ok(Self { Ok(Self {
pwd, pwd,
focused_path, focused_path,
config: None, config_file: Default::default(),
extra_config_files: Default::default(),
on_load: Default::default(), on_load: Default::default(),
read_only: Default::default(), read_only: Default::default(),
}) })
@ -131,8 +133,13 @@ impl Runner {
self self
} }
pub fn with_config(mut self, config: Option<PathBuf>) -> Self { pub fn with_config(mut self, config_file: Option<PathBuf>) -> Self {
self.config = config; self.config_file = config_file;
self
}
pub fn with_extra_config(mut self, config_files: Vec<PathBuf>) -> Self {
self.extra_config_files = config_files;
self self
} }
@ -144,7 +151,7 @@ impl Runner {
pub fn run(self) -> Result<Option<String>> { pub fn run(self) -> Result<Option<String>> {
// Why unsafe? See https://github.com/sayanarijit/xplr/issues/309 // Why unsafe? See https://github.com/sayanarijit/xplr/issues/309
let lua = unsafe { mlua::Lua::unsafe_new() }; let lua = unsafe { mlua::Lua::unsafe_new() };
let mut app = app::App::create(self.pwd, &lua, self.config)?; let mut app = app::App::create(self.pwd, &lua, self.config_file, self.extra_config_files)?;
app.config.general.set_read_only(self.read_only); app.config.general.set_read_only(self.read_only);
fs::create_dir_all(app.session_path())?; fs::create_dir_all(app.session_path())?;

Loading…
Cancel
Save