The External Programs feature allows you to execute custom external programs directly from XeFM with access to the current file manager state through environment variables. This extends XeFM’s functionality by integrating with external tools and scripts.
The programs menu and the sub-shell are two different tools: X runs one of
your configured PROGRAMS and returns to XeFM, while Shift-X drops you into
an interactive shell in the current pane’s directory.
External programs are configured in the PROGRAMS list in your config.py file. Each program entry needs:
name: Display name for the programcommand: List of command argumentsoptions (optional):
terminal: True — hand the terminal over to the program and wait for it
to exit, for full-screen / interactive programs (vim, less, a REPL).
Terminal mode only; in desktop mode there is no terminal to hand over, so
the launch is refused with an error in the log pane.auto_return — deprecated and ignored; launches never block XeFM. A
config warning names the entries still carrying it.PROGRAMS = [
{'name': 'Git Status', 'command': ['git', 'status']},
{'name': 'Git Log', 'command': ['git', 'log', '--oneline', '-10']},
{'name': 'Disk Usage', 'command': ['du', '-sh', '.']},
]
When you run external programs, XeFM provides information about your current state through environment variables:
XEFM_THIS_DIR / XEFM_OTHER_DIR: Current / other pane directoryXEFM_LEFT_DIR / XEFM_RIGHT_DIR: Left / right pane directoryXEFM_THIS_SELECTED / XEFM_OTHER_SELECTED / XEFM_LEFT_SELECTED /
XEFM_RIGHT_SELECTED: Selected files in the respective pane
(space-separated, double-quoted; the focused file when nothing is selected)XEFM_ACTIVE: Set to 1 while running under XeFMYour scripts can use these variables to work with your current selection and location.
The program runs in the background with the current pane as its working directory; the selected filenames (or the focused one) are also appended as command-line arguments. Its output — stdout and stderr — streams into the log pane, in both terminal and desktop mode, and a nonzero exit code is reported there too. XeFM stays fully responsive throughout.
By default the program’s input is closed at launch, so interactive terminal
programs can’t run this way. Give such an entry 'options': {'terminal': True}
instead: in terminal mode XeFM suspends its own display and hands the program
the terminal — with the same working directory, arguments, and XEFM_*
environment — then repaints when it exits, so vim, less, or a REPL work as
expected:
{'name': 'View with less', 'command': ['less'], 'options': {'terminal': True}},
If the program exits with a nonzero code, XeFM waits for Enter before repainting, so whatever error output it left on the terminal stays readable.
In desktop mode there is no terminal to hand over, so a terminal: True
entry is refused with an error in the log pane — as is sub-shell mode
(Shift-X), which in terminal mode remains the tool for extended
interactive command-line work.
On first launch XeFM creates a personal tools directory, ~/.xefm/tools/, and
places an example in it: example_tool.py, which prints every XEFM_*
variable and resolves the current selection to absolute paths. It is wired
into the default PROGRAMS as Example Tool (show XeFM environment), so
pressing X and running it shows exactly what your own scripts receive.
(The directory is seeded once — if you delete the example, it stays deleted.)
To add a tool of your own:
~/.xefm/tools/ — copying example_tool.py is a good
starting point.PROGRAMS in ~/.xefm/config.py:{'name': 'My Tool', 'command': [xefm_python, xefm_tool('my_tool.py')]},
Tools are not limited to Python. The command field is an argument list
passed straight to the operating system, so shell scripts and plain commands
work the same way:
#!/bin/bash
# Simple script that processes selected files
echo "Working in: $XEFM_THIS_DIR"
echo "Selected files: $XEFM_THIS_SELECTED"
{'name': 'My Shell Script', 'command': ['bash', xefm_tool('my_script.sh')]},
XeFM ships with a few ready-made PROGRAMS entries that show how to wire a real
external tool into the menu. Each is a single recipe pointing at a small helper
script that reads the XEFM_* environment variables above. The helpers live in
XeFM’s bundled tools directory (xefm/tools/) and are located at run time by
xefm_tool('name'), which searches ~/.xefm/tools/ first and then that bundled
directory. xefm_python is the interpreter XeFM is running under.
Earlier releases bundled Beyond Compare helper scripts (bcompare_files.py,
bcompare_dirs.py) and menu entries driving them. Both are gone: XeFM’s
built-in diff viewer compares the two selected files (=) and the two pane
directories (Shift+=) — see
Diff Viewer Feature. A config still referencing the
old scripts will log a launch failure; remove those PROGRAMS entries, or —
if you prefer Beyond Compare — write a
small tool in ~/.xefm/tools/ that runs bcompare on XEFM_LEFT_DIR /
XEFM_RIGHT_DIR (start from example_tool.py).
One entry opens the current directory (and any selected files) in VS Code:
{'name': 'Open in VSCode',
'command': [xefm_python, xefm_tool('vscode.py')]}
vscode.py reads XEFM_THIS_DIR and XEFM_THIS_SELECTED. If the current
directory is inside a git repository it walks up to the repository root and
opens that instead of the subdirectory, then adds any selected regular files
(directories are skipped; filenames with spaces are handled). Requires the
code command on your PATH — in VS Code, run Shell Command: Install ‘code’
command in PATH from the command palette.