TUI
A small keyboard-driven terminal UI for browsing directories and executing
ordinary shell commands defined in .tui files.
The important design choice is that TUI does not execute actions inside a
Python subprocess. It hands the generated commands back to the Bash process
that started tui. This keeps the commands visible in Bash history and gives
actions the normal shell environment.
Requirements
- Debian/Linux with Bash
- Python 3
- PyYAML (
python3-yamlon Debian) cursesfrom the normal Python installation
Install the Debian dependency if necessary:
sudo apt install python3-yaml
Installation
Unpack the project and run:
./install.sh
The installer installs TUI under:
~/.local/lib/tui/
and adds the shell integration to:
~/.bashrc
The integration is therefore loaded automatically for interactive Bash sessions, including the normal Debian login/terminal startup path.
After installation, start a new terminal/login session, or run:
source ~/.bashrc
Then:
tui
Use -a to include hidden files and directories:
tui -a
The installer does not overwrite an existing ~/.tui.
-a / --all is a command-line option, so the shell integration preserves it
when the TUI restarts after an action.
.tui configuration
TUI searches for the nearest .tui starting in the current directory and
walking upwards, but never above $HOME.
A configuration contains keys and actions:
keys:
up: up
down: down
left: parent
right:
folder: enter
file:
- "*.zip": list-zip
ctrl-k:
b: mark-begin
k: mark-end
m:
file:
- "*": move
actions:
list-zip:
command:
- unzip -l <path>
- read -rp "Press Enter to continue..."
move:
command: mv -v <path> <dir>
Rules are evaluated from top to bottom; the first matching glob wins.
Substitutions
| Token | Meaning |
|---|---|
<name> |
basename of the target |
<path> |
full path of the target |
<dir> |
directory currently displayed by TUI, with trailing / |
Navigation
The default example configuration uses:
↑/↓— move cursorEnter/→— execute the configured action../— synthetic parent-directory entry at the top of every listing←— move the cursor to../; pressing←again enters the parent directoryEnteron../— enter the parent directory- navigation cannot move above the directory containing the applicable
.tuifile - hidden files and directories are hidden by default;
tui -ashows them - file and directory colors follow the usual GNU
ls --color=yesconventions for common file types Ctrl-K B— set selection startCtrl-K K— set selection endCtrl-K C— copy marked files/foldersCtrl-K M— move marked filesCtrl-K Y— delete marked files/foldersCtrl-C— quit
Marking
Marks are stored as absolute paths and belong to the TUI session, not to the current directory.
For example:
/home/joakim/notes/
A.txt *
B.txt *
work/
Entering work/ does not clear the marks. Returning to the parent directory
shows A.txt and B.txt as marked again.
Marks in different directories can coexist. If A.txt is marked, then TUI
is moved to work/, Ctrl-K M operates on the original absolute path while
using the current directory as the destination:
mv -v /home/joakim/notes/A.txt .
A mark is removed automatically only when its target no longer exists.
Ctrl-K B and Ctrl-K K define a contiguous selection in the directory being
viewed. Changing directory clears the temporary selection endpoints but does
not clear the already marked paths.
Shell integration
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.
For example:
actions:
list-zip:
command:
- unzip -l <path>
- read -rp "Press Enter to continue..."
The flow is:
TUI
↓
unzip -l archive.zip
↓
read -rp "Press 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:
Press Enter to continue...
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.
Security note
Action strings are intentionally ordinary Bash commands and are executed with
eval by the user's Bash shell. .tui files should therefore be treated as
executable configuration and only used from directories/configurations you
trust.
Development
Run a syntax check with:
python3 -m py_compile tui/tui.py
For development without installing:
source tui/tui-shell.bash
tui
The example configuration is in tui/example.tui.
Version
Use tui -v or tui --version to verify the installed TUI version.
v3 menu
Press M to open the action menu. The menu is generated entirely from the current .tui file, so a directory can provide its own context-specific operations.
The example configuration defines ordinary file operations and Git operations that appear when the current directory is inside a Git worktree.
The top-level keys are also configurable in .tui:
keys:
a: toggle-all
q: quit
m: menu
Menu entries support:
menu:
- label: "Git: pull"
key: p
action: git-pull
selection: none
when: git
selection can be auto, current, marked or none.
Available generic when conditions include always, git, not-git, file, folder, marked, multiple, exists:<path>, missing:<path>, glob:<pattern>, plus all, any and not expressions.
Actions that operate on the current directory rather than a file can use:
actions:
git-pull:
target: none
command: git pull
This keeps the Python code generic: menu presentation, labels, shortcuts, conditions and shell commands belong in .tui.
Floating action menu
Press M to open the configured action menu. The menu is rendered as a floating overlay over the browser. It is positioned above or below the current cursor when possible, so the selected file remains visible.
Menu labels, shortcuts, actions, and context conditions are defined in .tui; the Python UI engine does not contain Git-specific menu definitions.
All user-visible TUI text is English.