fx — automated, selectable fix sources for f()
fx automates the [LEARN] ... Enter a fix: prompt in f() by gathering
candidate fixes from a directory of small, pluggable scripts and letting
you pick one (or auto-picking) before it's piped into f's stdin.
Zero changes to ../../src/f.sh. f()'s read -r n already doesn't
care whether that line comes from a human or a program — fx just
decides what to type there.
Usage
. ../../src/f.sh
. fx.sh
fx some-command --that --might --fail
Set FX_AUTO=1 to skip the picker and take the top-ranked candidate
automatically. Without it, fx uses fzf if installed, or a plain
numbered prompt otherwise.
Default sources (sources.d/, run in filename order)
| File | What it offers |
|---|---|
10-known.sh |
Fixes already taught for a command that starts the same way, since f()'s own lookup only matches the exact string. |
20-history.sh |
The closest-looking command you've actually run before, read from $HISTFILE. |
30-selfdiag.sh |
Re-runs the command once, and if the tool's own error output suggests a corrected invocation (git's --set-upstream hint, etc.), emits a function that re-derives the suggestion live on every future call — not a frozen snapshot. This distinction matters: an earlier version of this source cached the literal suggested line and it silently broke on the second branch it saw (git ls-remote showed the second branch never got pushed). Re-diagnosing on every call is what makes one taught fix generalize correctly. |
40-pathfuzzy.sh |
If the first word isn't a real command, offers a function (not an alias — aliases don't expand in non-interactive shells without shopt -s expand_aliases) wrapping the closest-spelled real command, using transposition-aware edit distance so gti scores closer to git than to unrelated same-length commands like ftp. |
50-thefuck.sh |
Bridges to thefuck --yes, if installed, as one more opinion. Note --yes executes its own suggestion, so this candidate is often already-applied by the time you see it. |
90-team-shared.sh |
Off by default (no-ops unless FX_TEAM_URL is set) — see below, this one is the extension example. |
Adding a custom source
Drop a new executable file into sources.d/. Nothing else to register.
Contract:
- invoked as
sourcefile "$CMD"where$CMDis the whole failing command line - may read
$FX_OUTPUT— captured stdout+stderr of one real attempt (empty ifFX_NO_PROBEis set) - prints zero or more candidate fix lines to stdout, one per line
- non-zero exit or no output = "no opinion," silently skipped
- filename prefix (
NN-name) sets consideration/display order — lower runs first
90-team-shared.sh is a real, working example of this contract: it pulls
a shared p-format corrections file from $FX_TEAM_URL and offers
exact-key matches. It's a template, not a dependency — treat a URL you
point it at the same way you'd treat an rc file you source: a match
becomes eval'd code the moment you select it.
Known cost
fx runs the command once itself before consulting sources (so
30-selfdiag.sh has real output to read). That's one extra execution
beyond what plain f() does. Set FX_NO_PROBE=1 to skip it for
commands with side effects you don't want repeated — the output-aware
source just has no opinion in that case, and the others still work.