Escape newline in selection list

pull/522/head
Arijit Basu 2 years ago committed by Arijit Basu
parent fbe6b2be10
commit bffe1d43ec

@ -1,7 +1,7 @@
# Environment Variables and Pipes
Alternative to `CallLua`, `CallLuaSilently` messages that call Lua functions,
there are `Call`, `CallSilently`, `BashExec`, `BashExecSilently` messages
there are `Call0`, `CallSilently0`, `BashExec0`, `BashExecSilently0` messages
that call shell commands.
However, unlike the Lua functions, these shell commands have to read the useful
@ -16,12 +16,13 @@ To see the environment variables and pipes, invoke the shell by typing `:!` in d
mode and run the following command:
```
env | grep ^XPLR_
env | grep ^XPLR
```
You will see something like:
```
XPLR=xplr
XPLR_FOCUS_INDEX=0
XPLR_MODE=action to
XPLR_PIPE_SELECTION_OUT=/run/user/1000/xplr/session/122278/pipe/selection_out
@ -43,6 +44,7 @@ called ["pipe"s][18].
The other variables are single-line variables containing simple information:
- [XPLR][38]
- [XPLR_APP_VERSION][30]
- [XPLR_FOCUS_INDEX][31]
- [XPLR_FOCUS_PATH][32]
@ -53,13 +55,18 @@ The other variables are single-line variables containing simple information:
### Environment variables
#### XPLR
The binary path of xplr command.
#### XPLR_APP_VERSION
Self-explanatory.
#### XPLR_FOCUS_INDEX
Contains the index of the currently focused item, as seen in [column-renderer/index][10].
Contains the index of the currently focused item, as seen in
[column-renderer/index][10].
#### XPLR_FOCUS_PATH
@ -67,7 +74,8 @@ Contains the full path of the currently focused node.
#### XPLR_INPUT_BUFFER
The line currently in displaying in the xplr input buffer. For e.g. the search input while searching. See [Reading Input][37].
The line currently in displaying in the xplr input buffer. For e.g. the search
input while searching. See [Reading Input][37].
#### XPLR_MODE
@ -79,7 +87,8 @@ Contains the process ID of the current xplr process.
#### XPLR_SESSION_PATH
Contains the current session path, like /tmp/runtime-"$USER"/xplr/session/"$XPLR_PID"/, you can find temporary files here, such as pipes.
Contains the current session path, like /tmp/runtime-"$USER"/xplr/session/"$XPLR_PID"/,
you can find temporary files here, such as pipes.
### Pipes
@ -93,7 +102,10 @@ Currently there is only one input pipe.
`XPLR_PIPE_*_OUT` are the output pipes that contain data which cannot be
exposed directly via environment variables, like multi-line strings.
These pipes can be accessed as plaintext files located in $XPLR_SESSION_PATH.
These pipes can be accessed as plain text files located in $XPLR_SESSION_PATH.
Depending on the message (e.g. `Call` or `Call0`), each line will be separated
by newline or null character (`\n` or `\0`).
- [XPLR_PIPE_SELECTION_OUT][21]
- [XPLR_PIPE_GLOBAL_HELP_MENU_OUT][22]
@ -104,13 +116,21 @@ These pipes can be accessed as plaintext files located in $XPLR_SESSION_PATH.
#### XPLR_PIPE_MSG_IN
Append new-line delimited messages to this pipe in [YAML][27]
(or [JSON][7]) syntax. These messages will be read and
handled by xplr after the command execution.
Append new messages to this pipe in [YAML][27] (or [JSON][7]) syntax. These
messages will be read and handled by xplr after the command execution.
Depending on the message (e.g. `Call` or `Call0`) you need to separate each
message using newline or null character (`\n` or `\0`).
> **_NOTE:_** Since version `v0.20.0`, it's recommended to avoid writing
> directly to this file, as safely escaping YAML strings is a lot of work. Use
> `xplr -m` / `xplr --pipe-msg-in` to pass messages to xplr in a safer way.
>
> Example: `"$XPLR" -m 'ChangeDirectory: %q' "${HOME:?}"`
#### XPLR_PIPE_SELECTION_OUT
New-line delimited list of selected paths.
List of selected paths.
#### XPLR_PIPE_GLOBAL_HELP_MENU_OUT
@ -118,20 +138,19 @@ The full help menu.
#### XPLR_PIPE_LOGS_OUT
New-line delimited list of logs.
List of logs.
#### XPLR_PIPE_RESULT_OUT
New-line delimited result (selected paths if any, else the focused path)
Result (selected paths if any, else the focused path)
#### XPLR_PIPE_HISTORY_OUT
New-line delimited list of last visited paths (similar to jump list in vim).
List of last visited paths (similar to jump list in vim).
#### XPLR_PIPE_DIRECTORY_NODES_OUT
New-line delimited list of paths, filtered and sorted as displayed in the
[files table][28].
List of paths, filtered and sorted as displayed in the [files table][28].
### Example: Using Environment Variables and Pipes
@ -140,14 +159,14 @@ xplr.config.modes.builtin.default.key_bindings.on_key.space = {
help = "ask name and greet",
messages = {
{
BashExec = [===[
echo "What's your name?"
BashExec0 = [===[
echo "What's your name?"
read name
greeting="Hello $name!"
message="$greeting You are inside $PWD"
read name
greeting="Hello $name!"
message="$greeting You are inside $PWD"
echo LogSuccess: '"'$message'"' >> "${XPLR_PIPE_MSG_IN:?}"
"$XPLR" -m 'LogSuccess: %q' "$message"
]===]
}
}
@ -164,8 +183,8 @@ xplr.config.modes.builtin.default.key_bindings.on_key.X = {
help = "open",
messages = {
{
BashExecSilently = [===[
xdg-open "${XPLR_FOCUS_PATH:?}"
BashExecSilently0 = [===[
xdg-open "${XPLR_FOCUS_PATH:?}"
]===],
},
},
@ -194,3 +213,4 @@ xplr.config.modes.builtin.default.key_bindings.on_key.X = {
[35]: #xplr_pid
[36]: #xplr_session_path
[37]: messages.md#reading-input
[38]: #xplr

@ -570,7 +570,7 @@ Example:
Like `CallSilently0`, but it uses `\n` as the delimiter in input/output
pipes, hence it cannot handle files with `\n` in the name.
You may want to use `Call0Silently` instead.
You may want to use `CallSilently0` instead.
#### CallSilently0
@ -606,14 +606,14 @@ Example:
Like `BashExecSilently0`, but it uses `\n` as the delimiter in
input/output pipes, hence it cannot handle files with `\n` in the name.
You may want to use `BashExec0Silently` instead.
You may want to use `BashExecSilently0` instead.
#### BashExecSilently0
Like `BashExec0` but without the flicker. The stdin, stdout
stderr will be piped to null. So it's non-interactive.
Type: { BashExec0Silently = "string" }
Type: { BashExecSilently0 = "string" }
Example:

@ -58,7 +58,8 @@ Finally, after publishing, don't hesitate to
`BashExec` and so on. File names may contain newline characters
(e.g. `foo$'\n'bar`).
- File names may also contain quotes. Use the syntax
`printf 'Call0: "%s"' "${FOO_ESC}"` where `FOO_ESC=${FOO//\"/\\\"}`.
`printf 'Call0: "%s"' "${FOO_ESC}"` where `FOO_ESC=${FOO//\"/\\\"}` and
`FOO_ESC=${FOO_ESC//$'\n'/\\n}`.
- Check for empty variables using the syntax `${FOO:?}` or use a default value
`${FOO:-defaultvalue}`.

@ -1045,9 +1045,9 @@ xplr.config.modes.builtin.default = {
help = "global help menu",
messages = {
{
BashExec0 = [===[
BashExec = [===[
[ -z "$PAGER" ] && PAGER="less -+F"
cat -- "${XPLR_PIPE_GLOBAL_HELP_MENU_OUT}" | tr '\0' '\n' | ${PAGER:?}
cat -- "${XPLR_PIPE_GLOBAL_HELP_MENU_OUT}" | ${PAGER:?}
]===],
},
},
@ -1157,6 +1157,7 @@ xplr.config.modes.builtin.default = {
BashExecSilently0 = [===[
NAME=$(basename "${XPLR_FOCUS_PATH:?}")
NAME_ESC=${NAME//\"/\\\"}
NAME_ESC=${NAME_ESC//$'\n'/\\n}
printf 'SetInputBuffer: "%s"\0' "${NAME_ESC:?}" >> "${XPLR_PIPE_MSG_IN:?}"
]===],
},
@ -1171,6 +1172,7 @@ xplr.config.modes.builtin.default = {
BashExecSilently0 = [===[
NAME=$(basename "${XPLR_FOCUS_PATH:?}")
NAME_ESC=${NAME//\"/\\\"}
NAME_ESC=${NAME_ESC//$'\n'/\\n}
printf 'SetInputBuffer: "%s"\0' "${NAME_ESC:?}" >> "${XPLR_PIPE_MSG_IN:?}"
]===],
},
@ -1208,6 +1210,7 @@ xplr.config.modes.builtin.default = {
{
BashExecSilently0 = [===[
HOME_ESC=${HOME//\"/\\\"}
HOME_ESC=${HOME_ESC//$'\n'/\\n}
printf 'ChangeDirectory: "%s"\0' "${HOME_ESC:?}" >> "${XPLR_PIPE_MSG_IN:?}"
]===],
},
@ -1304,8 +1307,8 @@ xplr.config.modes.builtin.debug_error = {
help = "open logs in editor",
messages = {
{
BashExec0 = [===[
cat "${XPLR_PIPE_LOGS_OUT:?}" | tr '\0' '\n' | ${EDITOR:-vi} -
BashExec = [===[
cat "${XPLR_PIPE_LOGS_OUT:?}" | ${EDITOR:-vi} -
]===],
},
},
@ -1367,7 +1370,8 @@ xplr.config.modes.builtin.go_to_path = {
{
BashExecSilently0 = [===[
PTH=${XPLR_INPUT_BUFFER}
PTH_ESC=${XPLR_INPUT_BUFFER//\"/\\\"}
PTH_ESC=${PTH//\"/\\\"}
PTH_ESC=${PTH_ESC//$'\n'/\\n}
if [ -d "$PTH" ]; then
printf 'ChangeDirectory: "%s"\0' "$PTH_ESC" >> "${XPLR_PIPE_MSG_IN:?}"
elif [ -e "$PTH" ]; then
@ -1409,6 +1413,7 @@ xplr.config.modes.builtin.selection_ops = {
BashExec0 = [===[
(while IFS= read -r -d '' LINE; do
LINE_ESC=${LINE//\"/\\\"}
LINE_ESC=${LINE_ESC//$'\n'/\\n}
if cp -vr -- "${LINE:?}" ./; then
printf 'LogSuccess: "%s"\0' "$LINE_ESC copied to ." >> "${XPLR_PIPE_MSG_IN:?}"
else
@ -1430,6 +1435,7 @@ xplr.config.modes.builtin.selection_ops = {
BashExec0 = [===[
(while IFS= read -r -d '' LINE; do
LINE_ESC=${LINE//\"/\\\"}
LINE_ESC=${LINE_ESC//$'\n'/\\n}
if mv -v -- "${LINE:?}" ./; then
printf 'LogSuccess: "%s"\0' "$LINE_ESC moved to ." >> "${XPLR_PIPE_MSG_IN:?}"
else
@ -1502,6 +1508,7 @@ xplr.config.modes.builtin.create_directory = {
BashExecSilently0 = [===[
PTH="$XPLR_INPUT_BUFFER"
PTH_ESC=${PTH//\"/\\\"}
PTH_ESC=${PTH_ESC//$'\n'/\\n}
if [ "$PTH" ]; then
mkdir -p -- "$PTH" \
&& printf 'SetInputBuffer: ""\0' >> "${XPLR_PIPE_MSG_IN:?}" \
@ -1545,6 +1552,7 @@ xplr.config.modes.builtin.create_file = {
BashExecSilently0 = [===[
PTH="$XPLR_INPUT_BUFFER"
PTH_ESC=${PTH//\"/\\\"}
PTH_ESC=${PTH_ESC//$'\n'/\\n}
if [ "$PTH" ]; then
mkdir -p -- "$(dirname $PTH)" \
&& touch -- "$PTH" \
@ -1693,8 +1701,10 @@ xplr.config.modes.builtin.rename = {
BashExecSilently0 = [===[
SRC="${XPLR_FOCUS_PATH:?}"
SRC_ESC=${SRC//\"/\\\"}
SRC_ESC=${SRC_ESC//$'\n'/\\n}
TARGET="${XPLR_INPUT_BUFFER:?}"
TARGET_ESC=${TARGET//\"/\\\"}
TARGET_ESC=${TARGET_ESC//$'\n'/\\n}
if [ -e "${TARGET:?}" ]; then
printf 'LogError: "%s"\0' "$TARGET_ESC already exists" >> "${XPLR_PIPE_MSG_IN:?}"
else
@ -1737,8 +1747,10 @@ xplr.config.modes.builtin.duplicate_as = {
BashExecSilently0 = [===[
SRC="${XPLR_FOCUS_PATH:?}"
SRC_ESC=${SRC//\"/\\\"}
SRC_ESC=${SRC_ESC//$'\n'/\\n}
TARGET="${XPLR_INPUT_BUFFER:?}"
TARGET_ESC=${TARGET//\"/\\\"}
TARGET_ESC=${TARGET_ESC//$'\n'/\\n}
if [ -e "${TARGET:?}" ]; then
printf 'LogError: "%s"\0' "$TARGET_ESC already exists" >> "${XPLR_PIPE_MSG_IN:?}"
else
@ -1775,6 +1787,7 @@ xplr.config.modes.builtin.delete = {
BashExec0 = [===[
(while IFS= read -r -d '' LINE; do
LINE_ESC=${LINE//\"/\\\"}
LINE_ESC=${LINE_ESC//$'\n'/\\n}
if rm -rfv -- "${LINE:?}"; then
printf 'LogSuccess: "%s"\0' "$LINE_ESC deleted" >> "${XPLR_PIPE_MSG_IN:?}"
else
@ -1795,6 +1808,7 @@ xplr.config.modes.builtin.delete = {
BashExec0 = [===[
(while IFS= read -r -d '' LINE; do
LINE_ESC=${LINE//\"/\\\"}
LINE_ESC=${LINE_ESC//$'\n'/\\n}
if [ -d "$LINE" ] && [ ! -L "$LINE" ]; then
if rmdir -v -- "${LINE:?}"; then
printf 'LogSuccess: "%s"\0' "$LINE_ESC deleted" >> "${XPLR_PIPE_MSG_IN:?}"
@ -1832,7 +1846,7 @@ xplr.config.modes.builtin.action = {
messages = {
{ Call0 = { command = "bash", args = { "-i" } } },
"ExplorePwdAsync",
"PopMode",
"PopModeKeepingInputBuffer",
},
},
["c"] = {
@ -1857,9 +1871,9 @@ xplr.config.modes.builtin.action = {
help = "logs",
messages = {
{
BashExec0 = [===[
BashExec = [===[
[ -z "$PAGER" ] && PAGER="less -+F"
cat -- "${XPLR_PIPE_LOGS_OUT}" | tr '\0' '\n' | ${PAGER:?}
cat -- "${XPLR_PIPE_LOGS_OUT}" | ${PAGER:?}
]===],
},
"PopMode",

@ -503,7 +503,7 @@ pub enum ExternalMsg {
/// Like `CallSilently0`, but it uses `\n` as the delimiter in input/output
/// pipes, hence it cannot handle files with `\n` in the name.
/// You may want to use `Call0Silently` instead.
/// You may want to use `CallSilently0` instead.
CallSilently(Command),
/// Like `Call0` but without the flicker. The stdin, stdout
@ -535,13 +535,13 @@ pub enum ExternalMsg {
/// Like `BashExecSilently0`, but it uses `\n` as the delimiter in
/// input/output pipes, hence it cannot handle files with `\n` in the name.
/// You may want to use `BashExec0Silently` instead.
/// You may want to use `BashExecSilently0` instead.
BashExecSilently(String),
/// Like `BashExec0` but without the flicker. The stdin, stdout
/// stderr will be piped to null. So it's non-interactive.
///
/// Type: { BashExec0Silently = "string" }
/// Type: { BashExecSilently0 = "string" }
///
/// Example:
///

@ -727,7 +727,7 @@ fn draw_selection<B: Backend>(
.rev()
.take((layout_size.height.max(2) - 2).into())
.rev()
.map(|n| n.absolute_path.to_owned())
.map(|n| n.absolute_path.replace('\\', "\\\\").replace('\n', "\\n"))
.map(ListItem::new)
.collect();

Loading…
Cancel
Save