Support passing argument to `LuaEval` and `LuaEvalSilently`

If the argument of `LuaEval` evaluates to a function, xplr will try to
pass Lua Context to it.

Example:

```lua
{ LuaEval = [[function(app) return { { LogInfo = app.pwd } } end]] }
```

Closes: https://github.com/sayanarijit/xplr/issues/394
pull/425/head
Arijit Basu 3 years ago committed by Arijit Basu
parent ea235b6969
commit 7b9e4deff5

@ -469,12 +469,16 @@ stderr will be piped to null. So it's non-interactive.
**YAML:** `LuaEval: string` **YAML:** `LuaEval: string`
Execute Lua code without needing to define a function. However, Execute Lua code without needing to define a function.
[Lua Context][14] won't be available.
If the `string` is a callable, xplr will try to call it with with the
[Lua Context][14] argument.
**YAML Example:** `LuaEval: "return { { LogInfo = io.read() } }"` **YAML Example:** `LuaEval: "return { { LogInfo = io.read() } }"`
**YAML Example:** `LuaEval: "function(app) return { { LogInfo = app.pwd } } end"`
**Lua Example:** `{ LuaEval = [[return { { LogInfo = io.read() } }]] }` **Lua Example:** `{ LuaEval = [[return { { LogInfo = io.read() } }]] }`
**Lua Example:** `{ LuaEval = [[function(app) return { { LogInfo = app.pwd } } end]] }`
### { LuaEvalSilently = "string" } ### { LuaEvalSilently = "string" }

@ -14,6 +14,7 @@ use crossterm::event;
use crossterm::execute; use crossterm::execute;
use crossterm::terminal as term; use crossterm::terminal as term;
use mlua::LuaSerdeExt; use mlua::LuaSerdeExt;
use mlua::Value;
use std::fs; use std::fs;
use std::io::Write; use std::io::Write;
use std::path::PathBuf; use std::path::PathBuf;
@ -555,18 +556,55 @@ impl Runner {
term::disable_raw_mode()?; term::disable_raw_mode()?;
terminal.show_cursor()?; terminal.show_cursor()?;
let res: Result<Option<Vec<ExternalMsg>>> = lua let res: Result<Value> =
.load(&code) lua.load(&code).eval().map_err(Error::from);
.eval()
match res {
Ok(Value::Function(f)) => {
let arg = app.to_lua_ctx_heavy();
let res: Result<
Option<Vec<ExternalMsg>>,
> = lua
.to_value(&arg)
.and_then(|a| f.call(a))
.and_then(|v| lua.from_value(v)) .and_then(|v| lua.from_value(v))
.map_err(Error::from); .map_err(Error::from);
match res { match res {
Ok(Some(msgs)) => { Ok(Some(msgs)) => {
app = app app = app
.handle_batch_external_msgs(msgs)?; .handle_batch_external_msgs(
msgs,
)?;
} }
Ok(None) => {} Ok(None) => {}
Err(err) => {
app = app.log_error(
err.to_string(),
)?;
}
}
}
Ok(v) => {
let res: Result<
Option<Vec<ExternalMsg>>,
> = lua
.from_value(v)
.map_err(Error::from);
match res {
Ok(Some(msgs)) => {
app = app
.handle_batch_external_msgs(
msgs,
)?;
}
Ok(None) => {}
Err(err) => {
app = app.log_error(
err.to_string(),
)?;
}
}
}
Err(err) => { Err(err) => {
app = app.log_error(err.to_string())?; app = app.log_error(err.to_string())?;
} }
@ -594,18 +632,55 @@ impl Runner {
} }
LuaEvalSilently(code) => { LuaEvalSilently(code) => {
let res: Result<Option<Vec<ExternalMsg>>> = lua let res: Result<Value> =
.load(&code) lua.load(&code).eval().map_err(Error::from);
.eval()
match res {
Ok(Value::Function(f)) => {
let arg = app.to_lua_ctx_heavy();
let res: Result<
Option<Vec<ExternalMsg>>,
> = lua
.to_value(&arg)
.and_then(|a| f.call(a))
.and_then(|v| lua.from_value(v)) .and_then(|v| lua.from_value(v))
.map_err(Error::from); .map_err(Error::from);
match res { match res {
Ok(Some(msgs)) => { Ok(Some(msgs)) => {
app = app app = app
.handle_batch_external_msgs(msgs)?; .handle_batch_external_msgs(
msgs,
)?;
} }
Ok(None) => {} Ok(None) => {}
Err(err) => {
app = app.log_error(
err.to_string(),
)?;
}
}
}
Ok(v) => {
let res: Result<
Option<Vec<ExternalMsg>>,
> = lua
.from_value(v)
.map_err(Error::from);
match res {
Ok(Some(msgs)) => {
app = app
.handle_batch_external_msgs(
msgs,
)?;
}
Ok(None) => {}
Err(err) => {
app = app.log_error(
err.to_string(),
)?;
}
}
}
Err(err) => { Err(err) => {
app = app.log_error(err.to_string())?; app = app.log_error(err.to_string())?;
} }

Loading…
Cancel
Save