Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve host completion #3454

Merged
merged 5 commits into from
Oct 12, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
35 changes: 27 additions & 8 deletions shell/completion.bash
Original file line number Diff line number Diff line change
Expand Up @@ -407,15 +407,34 @@ _fzf_proc_completion_post() {
command awk '{print $2}'
}

__fzf_list_hosts() {
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | command awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | command tr ',' '\n' | command tr -d '[' | command awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
command awk -v "user=$1" '{if (length($2) > 0) {print user $2}}' | command sort -u
}
# To use custom hostname lists, override __fzf_list_hosts.
# The function is expected to print hostnames, one per line as well as in the
# desired sorting and with any duplicates removed, to standard output.
if ! declare -F __fzf_list_hosts > /dev/null; then
if declare -F _known_hosts_real > /dev/null; then
# if available, use bash-completions’s _known_hosts_real() for getting the list of hosts

__fzf_list_hosts() {
# set the local attribute for any non-local variable that is set by _known_hosts_real()
local COMPREPLY=()

_known_hosts_real ''
printf '%s\n' "${COMPREPLY[@]}" | command sort -u --version-sort
Comment on lines +421 to +422
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is fine for now. But I'll have to reconsider this if they decide to change the way the function works in the future.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they're consolidating their function naming right now, so me might need to adapt that soon to work with the new name and fall back to the old one... but that shouldn't be too hard.

Other than that... I'd rather not expect any deeper changes to what the function does, do you?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think they're consolidating their function naming right now, so me might need to adapt that soon to work with the new name and fall back to the old one... but that shouldn't be too hard.

Oh, that's a deal breaker for me. I don't want to ship a product that might not work because of a sudden change in an implicit dependency.

Copy link
Owner

@junegunn junegunn Oct 12, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I'm not familiar with their code, and I just assumed _known_hosts_real was one of their documented public API that is guaranteed to be backward-compatible. If that's not the case, I'm not going to make fzf depend on it.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Well, bash-completion is not the C standard or so... I think it's reasonable to expect that they have some level of stability in their ABI (since people use it), but nothing is ever set fully in stone… not even POSIX and the likes.

I've also only noticed it a few days ago (when looking into that eval issue we had), that they're renaming their functions... and didn't really think any further that this might also affect _known_hosts_real(), but it does … in scop/bash-completion@d311921 they’ve renamed it to _comp_compgen_known_hosts().

But actually I think this consolidation is quite reasonable for them to do… the many different names and prefixes they've started to use over time were much more messy and likely that people accidentally use such names for something else.

I've already mention that earlier here, I think hat fzf might also benefit from such systematic consolidation (e.g. names like FZF_CTRL_T_COMMAND are pretty vague (an ideally the keybinding should be configurable and not fixed to Ctrl-T).

It may even make sense for fzf to integrate in the naming schema used by bash-completion to some extent... e.g. if we'd always use _comp_fzf_* or so for functions.

Anyway I don't see the big deal breaker here?!

It's not that they'd do this every year or so... and that consolidation they do seems to rather make this stable/official now.

APIs do change, or the code is either dead are - less likely - already perfect.

Especially, it's trivially easy to support both (see #3476).

Also, there's already much more complex to read code, that we have now in order to support different versions. The mawk-version check or the code to support old bash versions.

Even if we would start using more bash-completion functions (e.g. also for the eval thing), I'd guess their total number would be rather limited, so I think this is pretty manageable.

Similarly, even if I could persuade you to e.g. rename FZF_CTRL_T_COMMAND and the likes (which I guess might be a tough job to do ;-) ), it would be easy to fall back to the old names, and e.g. print deprecation warnings for a while.

}
else
# otherwise, get a list of hosts on our own

__fzf_list_hosts() {
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | command awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts 2> /dev/null | command tr ',' '\n' | command tr -d '[' | command awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0') |
command awk '{if (length($2) > 0) {print $2}}' | command sort -u
}
fi
fi

_fzf_host_completion() {
_fzf_complete +m -- "$@" < <(__fzf_list_hosts "")
_fzf_complete +m -- "$@" < <(__fzf_list_hosts)
}

# Values for $1 $2 $3 are described here
Expand All @@ -431,7 +450,7 @@ _fzf_complete_ssh() {
*)
local user=
[[ "$2" =~ '@' ]] && user="${2%%@*}@"
_fzf_complete +m -- "$@" < <(__fzf_list_hosts "$user")
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | command awk -v user="$user" '{print user $0}')
;;
esac
}
Expand Down
23 changes: 14 additions & 9 deletions shell/completion.zsh
Original file line number Diff line number Diff line change
Expand Up @@ -218,16 +218,21 @@ _fzf_complete() {
command rm -f "$fifo"
}

__fzf_list_hosts() {
setopt localoptions nonomatch
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts | command grep -Fv '0.0.0.0') |
awk -v "user=$1" '{if (length($2) > 0) {print user $2}}' | sort -u
}
# To use custom hostname lists, override __fzf_list_hosts.
# The function is expected to print hostnames, one per line as well as in the
# desired sorting and with any duplicates removed, to standard output.
if ! declare -f __fzf_list_hosts > /dev/null; then
__fzf_list_hosts() {
setopt localoptions nonomatch
command cat <(command tail -n +1 ~/.ssh/config ~/.ssh/config.d/* /etc/ssh/ssh_config 2> /dev/null | command grep -i '^\s*host\(name\)\? ' | awk '{for (i = 2; i <= NF; i++) print $1 " " $i}' | command grep -v '[*?%]') \
<(command grep -oE '^[[a-z0-9.,:-]+' ~/.ssh/known_hosts 2> /dev/null | tr ',' '\n' | tr -d '[' | awk '{ print $1 " " $1 }') \
<(command grep -v '^\s*\(#\|$\)' /etc/hosts 2> /dev/null | command grep -Fv '0.0.0.0') |
awk '{if (length($2) > 0) {print $2}}' | sort -u
}
fi

_fzf_complete_telnet() {
_fzf_complete +m -- "$@" < <(__fzf_list_hosts "")
_fzf_complete +m -- "$@" < <(__fzf_list_hosts)
}

# The first and the only argument is the LBUFFER without the current word that contains the trigger.
Expand All @@ -241,7 +246,7 @@ _fzf_complete_ssh() {
*)
local user=
[[ $prefix =~ @ ]] && user="${prefix%%@*}@"
_fzf_complete +m -- "$@" < <(__fzf_list_hosts "$user")
_fzf_complete +m -- "$@" < <(__fzf_list_hosts | awk -v user="$user" '{print user $0}')
;;
esac
}
Expand Down