The Subshell System allows users to temporarily suspend the XeFM interface and enter a shell environment with pre-configured environment variables that provide access to the current state of both file panes and selected files. The system includes intelligent remote directory fallback for seamless operation with both local and remote storage.
Shift-X (plain X opens the external-programs picker)XeFMApp.subshell → _run_in_terminal, with the environment built by
build_xefm_env and the prompt marked by prefix_prompt_markers)[XeFM] label for easy identificationWhen entering subshell mode, the following environment variables are automatically set:
XEFM_LEFT_DIR: Absolute path of the left file pane directoryXEFM_RIGHT_DIR: Absolute path of the right file pane directoryXEFM_THIS_DIR: Absolute path of the currently focused pane directoryXEFM_OTHER_DIR: Absolute path of the non-focused pane directoryXEFM_LEFT_SELECTED: Space-separated list of shell-quoted file names in the left paneXEFM_RIGHT_SELECTED: Space-separated list of shell-quoted file names in the right paneXEFM_THIS_SELECTED: Space-separated list of shell-quoted file names in the focused paneXEFM_OTHER_SELECTED: Space-separated list of shell-quoted file names in the non-focused paneXEFM_ACTIVE: Set to "1" when in XeFM sub-shell mode (used for shell prompt customization)The selected files variables (XEFM_*_SELECTED) follow this logic:
Example scenarios:
XEFM_THIS_SELECTED="file1.txt file2.py 'file with spaces.md'"XEFM_THIS_SELECTED="'current file.txt'"XEFM_THIS_SELECTED=""When browsing remote directories (such as S3 buckets), traditional shell operations would fail because:
s3://bucket/folder/) cannot be used as shell working directoriesos.chdir() would fail with remote pathsThe system implements intelligent working directory selection:
# Normal behavior - uses pane directory
XeFM Sub-shell Mode
==================================================
XEFM_THIS_DIR: /home/user/documents
Working Directory: /home/user/documents
==================================================
# Fallback behavior with user notification
XeFM Sub-shell Mode
==================================================
XEFM_THIS_DIR: s3://my-bucket/folder/
Working Directory: /home/user/xefm
==================================================
Note: Current pane is browsing remote directory: s3://my-bucket/folder/
Subshell working directory set to XeFM's directory: /home/user/xefm
# Determine working directory for subshell
if current_pane['path'].is_remote():
working_dir = os.getcwd() # XeFM's working directory
print(f"Note: Current pane is browsing remote directory: {current_pane['path']}")
print(f"Working directory set to XeFM's directory: {working_dir}")
else:
working_dir = str(current_pane['path']) # Use pane directory normally
# Change to the selected working directory
os.chdir(working_dir)
XeFM automatically quotes all filenames using shell-safe quoting (via Python’s shlex.quote()):
'My Document.txt''file$with&special.txt'simple.txt# ✅ Works directly with any filenames, including spaces and special characters
cd "$XEFM_THIS_DIR"
ls -la $XEFM_THIS_SELECTED
cp $XEFM_THIS_SELECTED "$XEFM_OTHER_DIR/"
tar -czf backup.tar.gz $XEFM_THIS_SELECTED
# If you have files: "My Document.txt", "file with spaces.py", "normal.txt"
# XEFM_THIS_SELECTED becomes: 'My Document.txt' 'file with spaces.py' normal.txt
# This now works perfectly:
ls -la $XEFM_THIS_SELECTED
# Expands to: ls -la 'My Document.txt' 'file with spaces.py' normal.txt
# List files in both panes
ls -la "$XEFM_LEFT_DIR" "$XEFM_RIGHT_DIR"
# Compare directory sizes
du -sh "$XEFM_LEFT_DIR" "$XEFM_RIGHT_DIR"
# Find files in both directories
find "$XEFM_LEFT_DIR" "$XEFM_RIGHT_DIR" -name "*.py"
# List selected files directly (works with spaces!)
ls -la $XEFM_THIS_SELECTED
# ✅ List selected files (works with spaces and special characters!)
cd "$XEFM_THIS_DIR"
ls -la $XEFM_THIS_SELECTED
# ✅ Copy selected files to other pane
cd "$XEFM_THIS_DIR"
cp $XEFM_THIS_SELECTED "$XEFM_OTHER_DIR/"
# ✅ Archive selected files
cd "$XEFM_THIS_DIR"
tar -czf selected_files.tar.gz $XEFM_THIS_SELECTED
# ✅ Show file information
cd "$XEFM_THIS_DIR"
file $XEFM_THIS_SELECTED
# ✅ Process files with any command
cd "$XEFM_THIS_DIR"
wc -l $XEFM_THIS_SELECTED # Count lines in selected files
# While browsing s3://my-bucket/logs/ in XeFM
$ aws s3 ls $XEFM_THIS_DIR
$ aws s3 cp $XEFM_THIS_DIR/error.log .
$ aws s3 sync $XEFM_THIS_DIR ./backup/
# While browsing s3://code-bucket/projects/
$ git clone https://github.com/user/repo.git
$ aws s3 cp $XEFM_THIS_DIR/config.json ./repo/
$ cd repo && make build
# While browsing s3://data-bucket/datasets/
$ python analyze.py --input $XEFM_THIS_DIR
$ aws s3 cp results.csv $XEFM_THIS_DIR/processed/
# Sync directories (copy newer files)
rsync -av "$XEFM_THIS_DIR/" "$XEFM_OTHER_DIR/"
# Compare selected files between panes
for file in $XEFM_THIS_SELECTED; do
if [ -f "$XEFM_OTHER_DIR/$file" ]; then
diff "$XEFM_THIS_DIR/$file" "$XEFM_OTHER_DIR/$file"
fi
done
# Batch rename selected files
for file in $XEFM_THIS_SELECTED; do
mv "$XEFM_THIS_DIR/$file" "$XEFM_THIS_DIR/backup_$file"
done
# For more complex per-file operations, you can still use loops
for file in $XEFM_THIS_SELECTED; do
echo "Processing: $file" # $file is already properly quoted
# Use the quoted filename directly
cp "$XEFM_THIS_DIR"/$file "$XEFM_OTHER_DIR"/
done
$SHELL environment variable)/bin/bash if $SHELL is not setShell configuration files (like .zshrc and .bashrc) are loaded after XeFM sets environment variables, which overwrites any prompt modifications XeFM makes. The solution is to modify your shell configuration to check for the XEFM_ACTIVE environment variable.
Add this to your ~/.zshrc file:
# XeFM sub-shell prompt modification
if [[ -n "$XEFM_ACTIVE" ]]; then
PROMPT="[XeFM] $PROMPT"
fi
Add this to your ~/.bashrc file:
# XeFM sub-shell prompt modification
if [[ -n "$XEFM_ACTIVE" ]]; then
PS1="[XeFM] $PS1"
fi
# Advanced XeFM prompt customization for zsh
if [[ -n "$XEFM_ACTIVE" ]]; then
# Add colored [XeFM] label
PROMPT="%F{yellow}[XeFM]%f $PROMPT"
# Or modify the right prompt
RPROMPT="$RPROMPT %F{red}(XeFM)%f"
fi
# Advanced XeFM prompt customization for bash
if [[ -n "$XEFM_ACTIVE" ]]; then
# Add colored [XeFM] label
PS1="\[\033[1;33m\][XeFM]\[\033[0m\] $PS1"
# Or create a completely custom XeFM prompt
PS1="\[\033[1;33m\][XeFM]\[\033[0m\] \[\033[1;32m\]\u@\h\[\033[0m\]:\[\033[1;34m\]\w\[\033[0m\]\$ "
fi
.zshrc or .bashrc)# For zsh
source ~/.zshrc
# For bash
source ~/.bashrc
x to enter sub-shell mode[XeFM] labelexit to return to XeFM| Shell | Config File | Variable | Example |
|---|---|---|---|
| zsh | ~/.zshrc |
PROMPT |
[XeFM] %n@%m:%~%# |
| bash | ~/.bashrc |
PS1 |
[XeFM] \u@\h:\w\$ |
| fish | ~/.config/fish/config.fish |
Custom function | See fish documentation |
To return to XeFM from sub-shell mode:
exit in the shellCtrl+D (EOF) in the shellThe sub-shell feature can be customized through the key bindings configuration:
KEY_BINDINGS = {
'subshell': ['x', 'X'], # Customize the key binding
# ... other bindings
}
curses.endwin()subprocess.run()is_remote() method# Examples of remote path detection
s3_path = Path('s3://my-bucket/folder/')
local_path = Path('/home/user/documents')
s3_path.is_remote() # Returns True
local_path.is_remote() # Returns False
rsync, find, grep, etc.test/test_subshell.py - Core subshell functionalitytest/test_subshell_remote_fallback.py - Remote directory fallbacktest/test_subshell_remote_simple.py - Core remote logic tests# Test environment variables
python3 test/test_subshell.py
# Test remote fallback
python3 test/test_subshell_remote_fallback.py
rsync, find, grepPrompt not showing [XeFM] label:
XEFM_ACTIVE=1 and starting a new shell“Permission denied” errors: Ensure XeFM has write access to its working directory Environment variables not set: Verify external programs are launched through XeFM Remote paths not accessible: Check cloud CLI configuration (AWS CLI, etc.)
Filenames with spaces: XeFM automatically quotes all filenames - use $XEFM_THIS_SELECTED directly
Configuration conflicts: Place XeFM configuration after other prompt modifications in config file
When remote fallback occurs, XeFM provides clear information:
The Subshell System provides a powerful bridge between XeFM’s file management capabilities and the full power of the shell environment. With intelligent remote directory fallback, automatic file quoting, and comprehensive environment variable support, it enables seamless operation across local and remote storage systems while maintaining the flexibility and power that makes XeFM an effective file management tool.