Implement -M, --print-msg-in

To help with creating safe arguments for --on-load.

e.g.

```
xplr --on-load $(xplr -M 'ChangeDirectory: %q' "${HOME:?}")
```
pull/522/head
Arijit Basu 2 years ago committed by Arijit Basu
parent 7c730557f2
commit 1d829c36e6

@ -87,12 +87,13 @@ xplr.config.modes.builtin.default.key_bindings.on_key.m = {
help = "bookmark",
messages = {
{
BashExecSilently = [===[
BashExecSilently0 = [===[
PTH="${XPLR_FOCUS_PATH:?}"
PTH_ESC=$(printf %q "$PTH")
if echo "${PTH:?}" >> "${XPLR_SESSION_PATH:?}/bookmarks"; then
echo "LogSuccess: ${PTH:?} added to bookmarks" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'LogSuccess: %q' "$PTH_ESC added to bookmarks"
else
echo "LogError: Failed to bookmark ${PTH:?}" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'LogError: %q' "Failed to bookmark $PTH_ESC"
fi
]===],
},
@ -103,10 +104,11 @@ xplr.config.modes.builtin.default.key_bindings.on_key["`"] = {
help = "go to bookmark",
messages = {
{
BashExec = [===[
BashExec0 = [===[
PTH=$(cat "${XPLR_SESSION_PATH:?}/bookmarks" | fzf --no-sort)
PTH_ESC=$(printf %q "$PTH")
if [ "$PTH" ]; then
echo FocusPath: "'"${PTH:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'FocusPath: %q' "$PTH"
fi
]===],
},
@ -138,17 +140,18 @@ xplr.config.modes.custom.bookmark = {
m = {
help = "bookmark dir",
messages = {
{ BashExecSilently = [[
{ BashExecSilently0 = [[
PTH="${XPLR_FOCUS_PATH:?}"
if [ -d "${PTH}" ]; then
PTH="${PTH}"
elif [ -f "${PTH}" ]; then
PTH="$(dirname "${PTH}")"
fi
PTH_ESC=$(printf %q "$PTH")
if echo "${PTH:?}" >> "${XPLR_BOOKMARK_FILE:?}"; then
echo "LogSuccess: ${PTH:?} added to bookmarks" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'LogSuccess: %q' "$PTH_ESC added to bookmarks"
else
echo "LogError: Failed to bookmark ${PTH:?}" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'LogError: %q' "Failed to bookmark $PTH_ESC"
fi
]]
},
@ -158,10 +161,10 @@ xplr.config.modes.custom.bookmark = {
help = "go to bookmark",
messages = {
{
BashExec = [===[
BashExec0 = [===[
PTH=$(cat "${XPLR_BOOKMARK_FILE:?}" | fzf --no-sort)
if [ "$PTH" ]; then
echo FocusPath: "'"${PTH:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'FocusPath: %q' "$PTH"
fi
]===]
},
@ -170,7 +173,7 @@ xplr.config.modes.custom.bookmark = {
d = {
help = "delete bookmark",
messages = {
{ BashExec = [[
{ BashExec0 = [[
PTH=$(cat "${XPLR_BOOKMARK_FILE:?}" | fzf --no-sort)
sd "$PTH\n" "" "${XPLR_BOOKMARK_FILE:?}"
]]
@ -206,7 +209,7 @@ xplr.config.modes.builtin.go_to.key_bindings.on_key.b = {
help = "bookmark jump",
messages = {
"PopMode",
{ BashExec = [===[
{ BashExec0 = [===[
field='\(\S\+\s*\)'
esc=$(printf '\033')
N="${esc}[0m"
@ -223,7 +226,7 @@ xplr.config.modes.builtin.go_to.key_bindings.on_key.b = {
--preview-window="right:50%" \
| sed 's#.*-> ##')
if [ "$PTH" ]; then
echo ChangeDirectory: "'"${PTH:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'ChangeDirectory: %q' "$PTH"
fi
]===]
},
@ -250,10 +253,10 @@ xplr.config.modes.builtin.go_to.key_bindings.on_key.h = {
messages = {
"PopMode",
{
BashExec = [===[
PTH=$(cat "${XPLR_PIPE_HISTORY_OUT:?}" | sort -u | fzf --no-sort)
BashExec0 = [===[
PTH=$(cat "${XPLR_PIPE_HISTORY_OUT:?}" | sort -z -u | fzf --read0)
if [ "$PTH" ]; then
echo ChangeDirectory: "'"${PTH:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'ChangeDirectory: %q' "$PTH"
fi
]===],
},
@ -286,7 +289,7 @@ xplr.config.modes.builtin.default.key_bindings.on_key.R = {
NODES=${SELECTION:-$(cat "${XPLR_PIPE_DIRECTORY_NODES_OUT:?}")}
if [ "$NODES" ]; then
echo -e "$NODES" | renamer
echo ExplorePwdAsync >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m ExplorePwdAsync
fi
]===],
},
@ -312,7 +315,7 @@ xplr.config.modes.builtin.default.key_bindings.on_key.S = {
help = "serve $PWD",
messages = {
{
BashExec = [===[
BashExec0 = [===[
IP=$(ip addr | grep -w inet | cut -d/ -f1 | grep -Eo '[0-9]{1,3}\.[0-9]{ 1,3}\.[0-9]{1,3}\.[0-9]{1,3}' | fzf --prompt 'Select IP > ')
echo "IP: ${IP:?}"
read -p "Port (default 5000): " PORT
@ -344,16 +347,16 @@ xplr.config.modes.builtin.default.key_bindings.on_key.P = {
help = "preview",
messages = {
{
BashExecSilently = [===[
BashExecSilently0 = [===[
FIFO_PATH="/tmp/xplr.fifo"
if [ -e "$FIFO_PATH" ]; then
echo StopFifo >> "$XPLR_PIPE_MSG_IN"
"$XPLR" -m StopFifo
rm -f -- "$FIFO_PATH"
else
mkfifo "$FIFO_PATH"
"$HOME/.local/bin/imv-open.sh" "$FIFO_PATH" "$XPLR_FOCUS_PATH" &
echo "StartFifo: '$FIFO_PATH'" >> "$XPLR_PIPE_MSG_IN"
"$XPLR" -m 'StartFifo: %q' "$FIFO_PATH"
fi
]===],
},
@ -407,27 +410,33 @@ local function stat(node)
return node.mime_essence
end
local function read(path, lines)
local out = ""
local function read(path, height)
local p = io.open(path)
if p == nil then
return stat(path)
return nil
end
local i = 0
local res = ""
for line in p:lines() do
out = out .. line .. "\n"
if i == lines then
if line:match("[^ -~\n\t]") then
p:close()
return
end
res = res .. line .. "\n"
if i == height then
break
end
i = i + 1
end
p:close()
return out
return res
end
xplr.config.layouts.builtin.default = {
Horizontal = {
config = {
@ -485,7 +494,7 @@ Navigate using the [tere][19] file explorer (defaults to type-to-nav system).
xplr.config.modes.builtin.default.key_bindings.on_key.T = {
help = "tere nav",
messages = {
{ BashExec = [[echo ChangeDirectory: "'"$(tere)"'" >> "$XPLR_PIPE_MSG_IN"]] },
{ BashExec0 = [[xplr -m 'ChangeDirectory: %q' "$(tere)"]] },
},
}
```

@ -155,12 +155,12 @@ xplr.config.modes.custom.fzxplr = {
messages = {
{
BashExec = [===[
PTH=$(cat "${XPLR_PIPE_DIRECTORY_NODES_OUT:?}" | awk -F/ '{print $NF}' | fzf)
if [ -d "$PTH" ]; then
echo ChangeDirectory: "'"${PWD:?}/${PTH:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
else
echo FocusPath: "'"${PWD:?}/${PTH:?}"'" >> "${XPLR_PIPE_MSG_IN:?}"
fi
PTH=$(cat "${XPLR_PIPE_DIRECTORY_NODES_OUT:?}" | awk -F/ '{print $NF}' | fzf)
if [ -d "$PTH" ]; then
"$XPLR" -m 'ChangeDirectory: %q' "$PTH"
else
"$XPLR" -m 'FocusPath: %q' "$PTH"
fi
]===]
},
"PopMode",
@ -180,12 +180,10 @@ As you can see, the key `F` in mode `fzxplr` (the name can be anything)
executes a script in `bash`.
`BashExec`, `PopMode`, `SwitchModeBuiltin`, `ChangeDirectory` and `FocusPath`
are [messages][18], `$XPLR_PIPE_MSG_IN`,
`$XPLR_PIPE_DIRECTORY_NODES_OUT` are
[environment variables][22] exported by `xplr`
before executing the command. They contain the path to the
[input][23] and [output][24] pipes that
allows external tools to interact with `xplr`.
are [messages][18], `$XPLR`, `$XPLR_PIPE_DIRECTORY_NODES_OUT` are
[environment variables][22] exported by `xplr` before executing the command.
They contain the path to the [input][23] and [output][24] pipes that allows
external tools to interact with `xplr`.
Now that we have our new mode ready, let's add an entry point to this mode via
the `default` mode.

@ -24,8 +24,7 @@ version of xplr, but they have one common drawback - the user will need to keep
an eye on the releases, and manually upgrade xplr when a new version is
available.
One way to keep an eye on the releases is to
[watch the repository][4].
One way to keep an eye on the releases is to [watch the repository][4].
## Community Maintained Repositories

@ -7,11 +7,9 @@ Once [installed][1], use the following steps to setup and run xplr.
```bash
mkdir -p ~/.config/xplr
version="$(xplr | grep ^version: | cut -d' ' -f 2)"
version="$(xplr --version | awk '{print $2}')"
# When the app loads, press `#`
echo version = '"'${version:?}'"' > ~/.config/xplr/init.lua
echo "version = '${version:?}'" > ~/.config/xplr/init.lua
```
Then

@ -20,8 +20,11 @@ fn main() {
-- Denotes the end of command-line flags and options
--force-focus Focuses on the given <PATH>, even if it is a directory
-h, --help Prints help information
-m, --pipe-msg-in Helps passing messages to the active xplr session
--print-pwd-as-result Prints the present working directory when quitting
-m, --pipe-msg-in Helps safely passing messages to the active xplr
session, use %%, %s and %q as the placeholders
-M, --print-msg-in Like --pipe-msg-in, but prints the message instead of
passing to the active xplr session
--print-pwd-as-result Prints the present working directory when quitting
with `PrintResultAndQuit`
--read-only Enables read-only mode (config.general.read_only)
--read0 Reads paths separated using the null character (\0)
@ -59,6 +62,11 @@ fn main() {
eprintln!("error: {}", err);
std::process::exit(1);
}
} else if !cli.print_msg_in.is_empty() {
if let Err(err) = cli::print_msg_in(cli.print_msg_in) {
eprintln!("error: {}", err);
std::process::exit(1);
}
} else {
match runner::from_cli(cli).and_then(|a| a.run()) {
Ok(Some(out)) => {

@ -22,6 +22,7 @@ pub struct Cli {
pub extra_config: Vec<PathBuf>,
pub on_load: Vec<app::ExternalMsg>,
pub pipe_msg_in: Vec<String>,
pub print_msg_in: Vec<String>,
pub paths: Vec<PathBuf>,
}
@ -120,9 +121,11 @@ impl Cli {
}
"-m" | "--pipe-msg-in" => {
for arg in args.by_ref() {
cli.pipe_msg_in.push(arg);
}
cli.pipe_msg_in.extend(args.by_ref());
}
"-M" | "--print-msg-in" => {
cli.print_msg_in.extend(args.by_ref());
}
// path
@ -137,15 +140,39 @@ impl Cli {
}
pub fn pipe_msg_in(args: Vec<String>) -> Result<()> {
let mut args = args.into_iter();
let mut msg = fmt_msg_in(args)?;
let format = args.next().context("usage: xplr -m FORMAT [ARGUMENT]...")?;
let mut msg = "".to_string();
if let Ok(path) = std::env::var("XPLR_PIPE_MSG_IN") {
let delimiter = fs::read(&path)?
.first()
.cloned()
.context("failed to detect delimmiter")?;
msg.push(delimiter.try_into()?);
File::options()
.append(true)
.open(&path)?
.write_all(msg.as_bytes())?;
} else {
println!("{}", msg);
};
Ok(())
}
pub fn print_msg_in(args: Vec<String>) -> Result<()> {
let msg = fmt_msg_in(args)?;
print!("{}", msg);
Ok(())
}
fn fmt_msg_in(args: Vec<String>) -> Result<String> {
let mut args = args.into_iter();
let format = args.next().context("usage: FORMAT [ARGUMENT]...")?;
let mut msg = "".to_string();
let mut last_char = None;
let chars = format.chars();
for ch in chars {
for ch in format.chars() {
match (ch, last_char) {
('%', Some('%')) => {
msg.push(ch);
@ -183,22 +210,6 @@ pub fn pipe_msg_in(args: Vec<String>) -> Result<()> {
}
// Validate
let mut msg = json::to_string(&ExternalMsg::try_from(msg.as_str())?)?;
if let Ok(path) = std::env::var("XPLR_PIPE_MSG_IN") {
let delimiter = fs::read(&path)?
.first()
.cloned()
.context("failed to detect delimmiter")?;
msg.push(delimiter.try_into()?);
File::options()
.append(true)
.open(&path)?
.write_all(msg.as_bytes())?;
} else {
println!("{}", msg);
}
Ok(())
let msg = json::to_string(&ExternalMsg::try_from(msg.as_str())?)?;
Ok(msg)
}

@ -678,7 +678,7 @@ fn draw_table<B: Backend>(
config,
format!(
" {} ({}) ",
app.pwd,
app.pwd.replace('\\', "\\\\").replace('\n', "\\n"),
app.directory_buffer
.as_ref()
.map(|d| d.total)

Loading…
Cancel
Save