This commit is contained in:
Joakim
2026-10-12 22:54:45 +02:00
parent 972e941674
commit 4227383e5c
5 changed files with 69 additions and 53 deletions

View File

@@ -1,3 +1,9 @@
## v2 - latest fix
- Fixed `Ctrl+C` exit handling so the Bash wrapper reliably changes to the directory where TUI was closed, including when Bash `set -e` is enabled.
- Action commands are evaluated as complete Bash commands, so `&&` and `||` chains work as they do directly in the terminal.
- Updated the example ZIP action to demonstrate success/failure prompts with `&&` / `||`.
# Changelog
## v2.1

View File

@@ -94,8 +94,7 @@ keys:
actions:
list-zip:
command:
- unzip -l <path>
- read -rp "Tryck Enter för att fortsätta..."
command: 'unzip -l <path> && read -rp "Enter to continue.." || read -rp "FAILED - Enter to continue..."'
move:
command: mv -v <path> <dir>
@@ -165,44 +164,42 @@ not clear the already marked paths.
When an action is triggered, TUI writes the generated commands to a temporary
file and exits with a private handoff status. The `tui()` Bash function then
executes them.
executes them in the parent Bash process.
For example:
When TUI is closed with `Ctrl+C`, the wrapper changes the parent Bash shell to
the directory where TUI was actually closed.
Action commands are handed to Bash as complete commands, so normal shell
operators such as `&&` and `||` work exactly as they do at the terminal. For
example:
```yaml
actions:
list-zip:
command: 'unzip -l <path> && read -rp "Enter to continue.." || read -rp "FAILED - Enter to continue..."'
```
The complete command is evaluated once. If `unzip` succeeds, the success
`read` is executed. If `unzip` fails, the failure `read` is executed.
For actions containing several separate commands, use a YAML list:
```yaml
actions:
example:
command:
- unzip -l <path>
- read -rp "Tryck Enter för att fortsätta..."
- command-one <path>
- command-two <path>
```
The flow is:
TUI is **not redrawn between commands belonging to the same action**. Each
command is inserted into Bash history. If a separate command fails, the
remaining commands in that action are not executed; TUI prints the exit code
and waits before returning to TUI.
```text
TUI
↓
unzip -l archive.zip
↓
read -rp "Tryck Enter..."
↓
TUI
```
TUI is **not redrawn between commands belonging to the same action**.
Every command is also inserted into Bash history. If one command fails, the
remaining commands in that action are not executed. TUI prints the exit code
and waits for:
```text
Tryck Enter för att fortsätta...
```
before returning to TUI, so an error cannot disappear immediately.
The shell wrapper uses `pushd`/`popd` so the command runs in the directory
shown by TUI without permanently changing the user's Bash working directory.
The shell wrapper uses `pushd`/`popd` so action commands run in the directory
shown by TUI without permanently changing the user's Bash directory during
the action.
## Security note

View File

@@ -29,21 +29,19 @@ keys:
- "*": move
y:
file:
- "*": delete-file
- "*": delete
folder:
- "*": delete-folder
- "*": delete
actions:
list-zip:
command: unzip -l <path> && read -rp "Enter to continue.." || read -rp "FAILED - Enter to continue..."
command: 'unzip -l <path> && read -rp "Enter to continue.." || read -rp "FAILED - Enter to continue..."'
copy:
command: cp -v <path> <dir>copy_<name>
move:
command: mv -v <path> <dir>
delete-file:
delete:
command: rm -v <path>
delete-folder:
command: rmdir -v <path> || read -rp "FAILED - Enter to continue..."
edit:
command: joe <path>
view:

View File

@@ -33,16 +33,26 @@ tui() {
: > "$command_file"
: > "$cwd_file"
# Use an if/else wrapper so this remains safe when the caller has
# `set -e` enabled. A Ctrl+C from the child must still return control
# here so we can cd to the TUI's final directory.
if (( show_all )); then
TUI_COMMAND_FILE="$command_file" \
TUI_CWD_FILE="$cwd_file" \
python3 "$tui_python" -a "$tui_dir"
if TUI_COMMAND_FILE="$command_file" \
TUI_CWD_FILE="$cwd_file" \
python3 "$tui_python" -a "$tui_dir"; then
rc=0
else
rc=$?
fi
else
TUI_COMMAND_FILE="$command_file" \
TUI_CWD_FILE="$cwd_file" \
python3 "$tui_python" "$tui_dir"
if TUI_COMMAND_FILE="$command_file" \
TUI_CWD_FILE="$cwd_file" \
python3 "$tui_python" "$tui_dir"; then
rc=0
else
rc=$?
fi
fi
rc=$?
tui_cwd="$(<"$cwd_file")"
@@ -56,16 +66,18 @@ tui() {
return 1
fi
# A normal TUI exit means the user wants to leave TUI. Change the
# parent Bash shell to the directory where TUI was actually closed.
# Any exit other than SHELL_HANDOFF means TUI is finished. Always
# change the parent Bash shell to the directory where TUI was
# actually closed. This includes Ctrl+C (status 130).
if (( rc != 42 )); then
if (( rc == 0 )); then
cd "$tui_cwd" || {
rm -f "$command_file" "$cwd_file"
return 1
}
fi
cd "$tui_cwd" || {
rm -f "$command_file" "$cwd_file"
return 1
}
rm -f "$command_file" "$cwd_file"
if (( rc == 130 )); then
return 0
fi
return "$rc"
fi

View File

@@ -607,7 +607,10 @@ def main():
try:
result = curses.wrapper(run, args.directory, args.all)
except KeyboardInterrupt:
return 0
# Keep a distinct status so the Bash wrapper can reliably distinguish
# Ctrl+C from a normal action handoff. The current directory has
# already been written by run()'s finally block.
return 130
return SHELL_HANDOFF if result == SHELL_HANDOFF else 0