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 support of make autocompletion for huge Makefiles #63

Closed
wants to merge 1 commit into from
Closed
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
70 changes: 66 additions & 4 deletions completions/make
Original file line number Diff line number Diff line change
Expand Up @@ -153,10 +153,72 @@ _make()
fi

local reset=$( shopt -po posix ); set +o posix # <(...)
COMPREPLY=( $( LC_ALL=C \
$1 -npq __BASH_MAKE_COMPLETION__=1 \
"${makef[@]}" "${makef_dir[@]}" .DEFAULT 2>/dev/null | \
command sed -nf <(_make_target_extract_script $mode "$cur") ) )

# there are two caches:
local cache_file="" # for the output of make
local prefix_cache_file="" # for the output of sed

# caching settings:
local cache_dir="$HOME/.cache_make_bash_completion"
local sed_threshold_in_millis="150" # otherwise, do not cache
local make_threshold_in_millis="50" # otherwise, do not cache

# Note:
# Caching is currently not implemented if "-C" or "-f" is used.
# In principle, there is no reason why it should not work,
# but as I do not use these features, I just skip it, here.
if [[ -z "${makef[@]}" && -z ${make_dir[@]} && -r "Makefile" ]] ; then
local cache_key=$( ( pwd && cat Makefile ) | md5sum | cut -f 1 -d ' ' )

# Currently, there is no cleanup mechanism, and there might
# be a smarter hashing strategy, too.
mkdir -p -- "$cache_dir"
cache_file="$cache_dir/make-bash-completion-${cache_key}.cache"
prefix_cache_file="$cache_dir/make-bash-completion_${cur}_${mode}_${cache_key}.cache"
fi

local prefix_filtered_result
if [[ -n "$prefix_cache_file" && -r "$prefix_cache_file" ]] ; then
prefix_filtered_result=$(cat -- "$prefix_cache_file")
else
local make_output
if [[ -n "$cache_file" && -r "$cache_file" ]] ; then
make_output=$(cat -- "$cache_file")
else
local before_make_nanos="$(date +%s%N)"
make_output="$( LC_ALL=C \
make -npq __BASH_MAKE_COMPLETION__=1 \
"${makef[@]}" "${makef_dir[@]}" .DEFAULT 2>/dev/null )"
local after_make_nanos="$(date +%s%N)"
if [[ -n "$cache_file" ]] && (( (($after_make_nanos - $before_make_nanos) / 1000000) > $make_threshold_in_millis )) ; then
echo "$make_output" > "$cache_file"
fi
fi

local before_sed_nanos="$(date +%s%N)"
prefix_filtered_result=$( echo "$make_output" | \
command sed -nf <(_make_target_extract_script $mode "$cur") )
local after_sed_nanos="$(date +%s%N)"

if [[ -n "$prefix_cache_file" ]] && (( (( ${after_sed_nanos} - ${before_sed_nanos}) / 1000000) > ${sed_threshold_in_millis} )) ; then
echo "$prefix_filtered_result" > "$prefix_cache_file"
fi
fi

# Filter away all non-binaries and the source files, as
# otherwise, it can result in thousands of results,
# which are mostly uninteresting.
#
# Note:
# Filtering here with grep is almost certainly a hack.
# A better approach could be to change the sed expression
# in _make_target_extract_script. Maybe that would simplify
# the work that sed has to do and make it run faster
# (in my system, sed is the bottleneck).
#
COMPREPLY=( $( echo "$prefix_filtered_result" | \
egrep -v '\.(o|obj|h|c|cpp)$') )

$reset

if [[ $mode != -d ]]; then
Expand Down