# Copyright 2013-2023 The Cobra Authors # Copyright 2023 Erika Rowland # # Licensed under the Apache License, Version 2.0 (the "License"); # you may not use this file except in compliance with the License. # You may obtain a copy of the License at # # http://www.apache.org/licenses/LICENSE-2.0 # # Unless required by applicable law or agreed to in writing, software # distributed under the License is distributed on an "AS IS" BASIS, # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. # See the License for the specific language governing permissions and # limitations under the License. defmodule Mix.Tasks.Complete.Bash do use Mix.Task @shortdoc "Output bash completion source for mix" def run(_) do Mix.Tasks.Complete.run([]) IO.puts(""" __mix_completion_debug() { if [[ -n ${BASH_COMP_DEBUG_FILE-} ]]; then echo "$*" >>"${BASH_COMP_DEBUG_FILE}" fi } __mix_completion_handle_standard_completion_case() { local tab=$'\t' comp local longest=0 local compline # Look for the longest completion so that we can format things nicely while IFS='' read -r compline; do [[ -z $compline ]] && continue # Strip any description before checking the length comp=${compline%%$tab*} # Only consider the completions that match [[ $comp == "$cur"* ]] || continue COMPREPLY+=("$compline") if ((${#comp} > longest)); then longest=${#comp} fi done <<<"$completions" # If there is a single completion left, remove the description text if ((${#COMPREPLY[*]} == 1)); then comp="${COMPREPLY[0]%%$tab*}" COMPREPLY[0]=$comp else # Format the descriptions __mix_completion_format_comp_descriptions $longest fi } __mix_completion_format_comp_descriptions() { local tab=$'\t' local comp desc maxdesclength local longest=$1 local i ci for ci in ${!COMPREPLY[*]}; do comp=${COMPREPLY[ci]} # Properly format the description string which follows a tab character if there is one if [[ "$comp" == *$tab* ]]; then desc=${comp#*$tab} comp=${comp%%$tab*} # $COLUMNS stores the current shell width. # Remove an extra 4 because we add 2 spaces and 2 parentheses. maxdesclength=$((COLUMNS - longest - 4)) # Make sure we can fit a description of at least 8 characters # if we are to align the descriptions. if ((maxdesclength > 8)); then # Add the proper number of spaces to align the descriptions for ((i = ${#comp}; i < longest; i++)); do comp+=" " done else # Don't pad the descriptions so we can fit more text after the completion maxdesclength=$((COLUMNS - ${#comp} - 4)) fi # If there is enough space for any description text, # truncate the descriptions that are too long for the shell width if ((maxdesclength > 0)); then if ((${#desc} > maxdesclength)); then desc=${desc:0:$((maxdesclength - 1))} desc+="…" fi comp+=" ($desc)" fi COMPREPLY[ci]=$comp fi done } _mix_complete_complete() { local options local IFS=$' \t\n' local words=("${COMP_WORDS[@]}") local cword=$COMP_CWORD local prev=$3 local cur="${words[$cword]}" COMPREPLY=() if [[ -f 'mix.exs' && -f '.mix_complete.cache' ]]; then options=$(cat .mix_complete.cache) elif [[ ! -z "$XDG_CACHE_HOME" && -f "$XDG_CACHE_HOME/.mix_complete.cache" ]]; then options=$(cat "$XDG_CACHE_HOME/.mix_complete.cache") elif [[ -f "$HOME/.cache/.mix_complete.cache" ]]; then options=$(cat "$HOME/.cache/.mix_complete.cache") else options="" fi completions="$options" __mix_completion_debug "==$(date)==" __mix_completion_debug "cur $cur" __mix_completion_debug "words $words" if [[ $prev == 'mix' ]]; then __mix_completion_handle_standard_completion_case else COMPREPLY=() compopt -o default fi } _mix_complete_setup() { complete -F _mix_complete_complete mix } _mix_complete_setup """) end end