109 __%[1]s_debug "No file completion directive not supported in this version of bash" |
109 __%[1]s_debug "No file completion directive not supported in this version of bash" |
110 fi |
110 fi |
111 fi |
111 fi |
112 fi |
112 fi |
113 |
113 |
|
114 # Separate activeHelp from normal completions |
|
115 local completions=() |
|
116 local activeHelp=() |
|
117 __%[1]s_extract_activeHelp |
|
118 |
114 if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then |
119 if [ $((directive & shellCompDirectiveFilterFileExt)) -ne 0 ]; then |
115 # File extension filtering |
120 # File extension filtering |
116 local fullFilter filter filteringCmd |
121 local fullFilter filter filteringCmd |
117 |
122 |
118 # Do not use quotes around the $out variable or else newline |
123 # Do not use quotes around the $completions variable or else newline |
119 # characters will be kept. |
124 # characters will be kept. |
120 for filter in ${out[*]}; do |
125 for filter in ${completions[*]}; do |
121 fullFilter+="$filter|" |
126 fullFilter+="$filter|" |
122 done |
127 done |
123 |
128 |
124 filteringCmd="_filedir $fullFilter" |
129 filteringCmd="_filedir $fullFilter" |
125 __%[1]s_debug "File filtering command: $filteringCmd" |
130 __%[1]s_debug "File filtering command: $filteringCmd" |
127 elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then |
132 elif [ $((directive & shellCompDirectiveFilterDirs)) -ne 0 ]; then |
128 # File completion for directories only |
133 # File completion for directories only |
129 |
134 |
130 # Use printf to strip any trailing newline |
135 # Use printf to strip any trailing newline |
131 local subdir |
136 local subdir |
132 subdir=$(printf "%%s" "${out[0]}") |
137 subdir=$(printf "%%s" "${completions[0]}") |
133 if [ -n "$subdir" ]; then |
138 if [ -n "$subdir" ]; then |
134 __%[1]s_debug "Listing directories in $subdir" |
139 __%[1]s_debug "Listing directories in $subdir" |
135 pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return |
140 pushd "$subdir" >/dev/null 2>&1 && _filedir -d && popd >/dev/null 2>&1 || return |
136 else |
141 else |
137 __%[1]s_debug "Listing directories in ." |
142 __%[1]s_debug "Listing directories in ." |
138 _filedir -d |
143 _filedir -d |
139 fi |
144 fi |
140 else |
145 else |
141 __%[1]s_handle_standard_completion_case |
146 __%[1]s_handle_completion_types |
142 fi |
147 fi |
143 |
148 |
144 __%[1]s_handle_special_char "$cur" : |
149 __%[1]s_handle_special_char "$cur" : |
145 __%[1]s_handle_special_char "$cur" = |
150 __%[1]s_handle_special_char "$cur" = |
|
151 |
|
152 # Print the activeHelp statements before we finish |
|
153 if [ ${#activeHelp} -ne 0 ]; then |
|
154 printf "\n"; |
|
155 printf "%%s\n" "${activeHelp[@]}" |
|
156 printf "\n" |
|
157 |
|
158 # The prompt format is only available from bash 4.4. |
|
159 # We test if it is available before using it. |
|
160 if (x=${PS1@P}) 2> /dev/null; then |
|
161 printf "%%s" "${PS1@P}${COMP_LINE[@]}" |
|
162 else |
|
163 # Can't print the prompt. Just print the |
|
164 # text the user had typed, it is workable enough. |
|
165 printf "%%s" "${COMP_LINE[@]}" |
|
166 fi |
|
167 fi |
|
168 } |
|
169 |
|
170 # Separate activeHelp lines from real completions. |
|
171 # Fills the $activeHelp and $completions arrays. |
|
172 __%[1]s_extract_activeHelp() { |
|
173 local activeHelpMarker="%[8]s" |
|
174 local endIndex=${#activeHelpMarker} |
|
175 |
|
176 while IFS='' read -r comp; do |
|
177 if [ "${comp:0:endIndex}" = "$activeHelpMarker" ]; then |
|
178 comp=${comp:endIndex} |
|
179 __%[1]s_debug "ActiveHelp found: $comp" |
|
180 if [ -n "$comp" ]; then |
|
181 activeHelp+=("$comp") |
|
182 fi |
|
183 else |
|
184 # Not an activeHelp line but a normal completion |
|
185 completions+=("$comp") |
|
186 fi |
|
187 done < <(printf "%%s\n" "${out}") |
|
188 } |
|
189 |
|
190 __%[1]s_handle_completion_types() { |
|
191 __%[1]s_debug "__%[1]s_handle_completion_types: COMP_TYPE is $COMP_TYPE" |
|
192 |
|
193 case $COMP_TYPE in |
|
194 37|42) |
|
195 # Type: menu-complete/menu-complete-backward and insert-completions |
|
196 # If the user requested inserting one completion at a time, or all |
|
197 # completions at once on the command-line we must remove the descriptions. |
|
198 # https://github.com/spf13/cobra/issues/1508 |
|
199 local tab=$'\t' comp |
|
200 while IFS='' read -r comp; do |
|
201 [[ -z $comp ]] && continue |
|
202 # Strip any description |
|
203 comp=${comp%%%%$tab*} |
|
204 # Only consider the completions that match |
|
205 if [[ $comp == "$cur"* ]]; then |
|
206 COMPREPLY+=("$comp") |
|
207 fi |
|
208 done < <(printf "%%s\n" "${completions[@]}") |
|
209 ;; |
|
210 |
|
211 *) |
|
212 # Type: complete (normal completion) |
|
213 __%[1]s_handle_standard_completion_case |
|
214 ;; |
|
215 esac |
146 } |
216 } |
147 |
217 |
148 __%[1]s_handle_standard_completion_case() { |
218 __%[1]s_handle_standard_completion_case() { |
149 local tab comp |
219 local tab=$'\t' comp |
150 tab=$(printf '\t') |
220 |
|
221 # Short circuit to optimize if we don't have descriptions |
|
222 if [[ "${completions[*]}" != *$tab* ]]; then |
|
223 IFS=$'\n' read -ra COMPREPLY -d '' < <(compgen -W "${completions[*]}" -- "$cur") |
|
224 return 0 |
|
225 fi |
151 |
226 |
152 local longest=0 |
227 local longest=0 |
|
228 local compline |
153 # Look for the longest completion so that we can format things nicely |
229 # Look for the longest completion so that we can format things nicely |
154 while IFS='' read -r comp; do |
230 while IFS='' read -r compline; do |
|
231 [[ -z $compline ]] && continue |
155 # Strip any description before checking the length |
232 # Strip any description before checking the length |
156 comp=${comp%%%%$tab*} |
233 comp=${compline%%%%$tab*} |
157 # Only consider the completions that match |
234 # Only consider the completions that match |
158 comp=$(compgen -W "$comp" -- "$cur") |
235 [[ $comp == "$cur"* ]] || continue |
|
236 COMPREPLY+=("$compline") |
159 if ((${#comp}>longest)); then |
237 if ((${#comp}>longest)); then |
160 longest=${#comp} |
238 longest=${#comp} |
161 fi |
239 fi |
162 done < <(printf "%%s\n" "${out[@]}") |
240 done < <(printf "%%s\n" "${completions[@]}") |
163 |
|
164 local completions=() |
|
165 while IFS='' read -r comp; do |
|
166 if [ -z "$comp" ]; then |
|
167 continue |
|
168 fi |
|
169 |
|
170 __%[1]s_debug "Original comp: $comp" |
|
171 comp="$(__%[1]s_format_comp_descriptions "$comp" "$longest")" |
|
172 __%[1]s_debug "Final comp: $comp" |
|
173 completions+=("$comp") |
|
174 done < <(printf "%%s\n" "${out[@]}") |
|
175 |
|
176 while IFS='' read -r comp; do |
|
177 COMPREPLY+=("$comp") |
|
178 done < <(compgen -W "${completions[*]}" -- "$cur") |
|
179 |
241 |
180 # If there is a single completion left, remove the description text |
242 # If there is a single completion left, remove the description text |
181 if [ ${#COMPREPLY[*]} -eq 1 ]; then |
243 if [ ${#COMPREPLY[*]} -eq 1 ]; then |
182 __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" |
244 __%[1]s_debug "COMPREPLY[0]: ${COMPREPLY[0]}" |
183 comp="${COMPREPLY[0]%%%% *}" |
245 comp="${COMPREPLY[0]%%%%$tab*}" |
184 __%[1]s_debug "Removed description from single completion, which is now: ${comp}" |
246 __%[1]s_debug "Removed description from single completion, which is now: ${comp}" |
185 COMPREPLY=() |
247 COMPREPLY[0]=$comp |
186 COMPREPLY+=("$comp") |
248 else # Format the descriptions |
|
249 __%[1]s_format_comp_descriptions $longest |
187 fi |
250 fi |
188 } |
251 } |
189 |
252 |
190 __%[1]s_handle_special_char() |
253 __%[1]s_handle_special_char() |
191 { |
254 { |
200 fi |
263 fi |
201 } |
264 } |
202 |
265 |
203 __%[1]s_format_comp_descriptions() |
266 __%[1]s_format_comp_descriptions() |
204 { |
267 { |
205 local tab |
268 local tab=$'\t' |
206 tab=$(printf '\t') |
269 local comp desc maxdesclength |
207 local comp="$1" |
270 local longest=$1 |
208 local longest=$2 |
271 |
209 |
272 local i ci |
210 # Properly format the description string which follows a tab character if there is one |
273 for ci in ${!COMPREPLY[*]}; do |
211 if [[ "$comp" == *$tab* ]]; then |
274 comp=${COMPREPLY[ci]} |
212 desc=${comp#*$tab} |
275 # Properly format the description string which follows a tab character if there is one |
213 comp=${comp%%%%$tab*} |
276 if [[ "$comp" == *$tab* ]]; then |
214 |
277 __%[1]s_debug "Original comp: $comp" |
215 # $COLUMNS stores the current shell width. |
278 desc=${comp#*$tab} |
216 # Remove an extra 4 because we add 2 spaces and 2 parentheses. |
279 comp=${comp%%%%$tab*} |
217 maxdesclength=$(( COLUMNS - longest - 4 )) |
280 |
218 |
281 # $COLUMNS stores the current shell width. |
219 # Make sure we can fit a description of at least 8 characters |
282 # Remove an extra 4 because we add 2 spaces and 2 parentheses. |
220 # if we are to align the descriptions. |
283 maxdesclength=$(( COLUMNS - longest - 4 )) |
221 if [[ $maxdesclength -gt 8 ]]; then |
284 |
222 # Add the proper number of spaces to align the descriptions |
285 # Make sure we can fit a description of at least 8 characters |
223 for ((i = ${#comp} ; i < longest ; i++)); do |
286 # if we are to align the descriptions. |
224 comp+=" " |
287 if [[ $maxdesclength -gt 8 ]]; then |
225 done |
288 # Add the proper number of spaces to align the descriptions |
226 else |
289 for ((i = ${#comp} ; i < longest ; i++)); do |
227 # Don't pad the descriptions so we can fit more text after the completion |
290 comp+=" " |
228 maxdesclength=$(( COLUMNS - ${#comp} - 4 )) |
291 done |
229 fi |
292 else |
230 |
293 # Don't pad the descriptions so we can fit more text after the completion |
231 # If there is enough space for any description text, |
294 maxdesclength=$(( COLUMNS - ${#comp} - 4 )) |
232 # truncate the descriptions that are too long for the shell width |
295 fi |
233 if [ $maxdesclength -gt 0 ]; then |
296 |
234 if [ ${#desc} -gt $maxdesclength ]; then |
297 # If there is enough space for any description text, |
235 desc=${desc:0:$(( maxdesclength - 1 ))} |
298 # truncate the descriptions that are too long for the shell width |
236 desc+="…" |
299 if [ $maxdesclength -gt 0 ]; then |
237 fi |
300 if [ ${#desc} -gt $maxdesclength ]; then |
238 comp+=" ($desc)" |
301 desc=${desc:0:$(( maxdesclength - 1 ))} |
239 fi |
302 desc+="…" |
240 fi |
303 fi |
241 |
304 comp+=" ($desc)" |
242 # Must use printf to escape all special characters |
305 fi |
243 printf "%%q" "${comp}" |
306 COMPREPLY[ci]=$comp |
|
307 __%[1]s_debug "Final comp: $comp" |
|
308 fi |
|
309 done |
244 } |
310 } |
245 |
311 |
246 __start_%[1]s() |
312 __start_%[1]s() |
247 { |
313 { |
248 local cur prev words cword split |
314 local cur prev words cword split |