50 lines
2.0 KiB
Bash
Executable File
50 lines
2.0 KiB
Bash
Executable File
#!/bin/bash
|
|
# PATH-fuzzy source: if the first word isn't a known command, alias, or
|
|
# function, offer a function wrapping the closest-spelled real command
|
|
# as a candidate -- as a fix you approve through the normal f() flow,
|
|
# not a silently auto-installed hook. A function, not an alias: aliases
|
|
# only expand in interactive shells (need `shopt -s expand_aliases`
|
|
# otherwise), so an alias-based fix silently does nothing when f/fx run
|
|
# inside a script.
|
|
#
|
|
# Uses Damerau-Levenshtein-lite (edit distance + adjacent transposition)
|
|
# so the canonical "gti" -> "git" typo scores 1, not 2 -- plain Hamming
|
|
# or substitution-only distance ties it with unrelated 3-letter commands
|
|
# like "ftp" and can pick the wrong one.
|
|
cmd="$1"
|
|
first_word=$(printf '%s' "$cmd" | awk '{print $1}')
|
|
[ -n "$first_word" ] || exit 0
|
|
command -v "$first_word" >/dev/null 2>&1 && exit 0
|
|
type "$first_word" >/dev/null 2>&1 && exit 0
|
|
|
|
compgen -c 2>/dev/null | sort -u | awk -v target="$first_word" '
|
|
function min3(a, b, c) { return (a < b ? (a < c ? a : c) : (b < c ? b : c)) }
|
|
function distance(a, b, n, m, i, j, ca, cb, cost, tmp) {
|
|
n = length(a); m = length(b)
|
|
if (n == 0) return m
|
|
if (m == 0) return n
|
|
for (j = 0; j <= m; j++) d[0, j] = j
|
|
for (i = 1; i <= n; i++) {
|
|
d[i, 0] = i
|
|
ca = substr(a, i, 1)
|
|
for (j = 1; j <= m; j++) {
|
|
cb = substr(b, j, 1)
|
|
cost = (ca == cb) ? 0 : 1
|
|
tmp = min3(d[i-1, j] + 1, d[i, j-1] + 1, d[i-1, j-1] + cost)
|
|
if (i > 1 && j > 1 && ca == substr(b, j-1, 1) && substr(a, i-1, 1) == cb) {
|
|
tmp = (tmp < d[i-2, j-2] + 1) ? tmp : d[i-2, j-2] + 1
|
|
}
|
|
d[i, j] = tmp
|
|
}
|
|
}
|
|
return d[n, m]
|
|
}
|
|
{
|
|
lendiff = length($0) - length(target)
|
|
if (lendiff > 2 || lendiff < -2) next
|
|
dd = distance(target, $0)
|
|
if (dd <= 2 && dd > 0 && (best == "" || dd < bestd)) { best = $0; bestd = dd }
|
|
}
|
|
END { if (best != "") print target "(){ command " best " \"$@\"; }" }
|
|
'
|