mergetool--lib: add functions for finding available tools

Refactor show_tool_help() so that the tool-finding logic is broken out
into a separate show_tool_names() function.

Signed-off-by: David Aguilar <davvid@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
diff --git a/git-mergetool--lib.sh b/git-mergetool--lib.sh
index 7edc27f..293b8e8 100644
--- a/git-mergetool--lib.sh
+++ b/git-mergetool--lib.sh
@@ -2,6 +2,53 @@
 # git-mergetool--lib is a library for common merge tool functions
 MERGE_TOOLS_DIR=$(git --exec-path)/mergetools
 
+mode_ok () {
+	if diff_mode
+	then
+		can_diff
+	elif merge_mode
+	then
+		can_merge
+	else
+		false
+	fi
+}
+
+is_available () {
+	merge_tool_path=$(translate_merge_tool_path "$1") &&
+	type "$merge_tool_path" >/dev/null 2>&1
+}
+
+show_tool_names () {
+	condition=${1:-true} per_line_prefix=${2:-} preamble=${3:-}
+	not_found_msg=${4:-}
+
+	shown_any=
+	( cd "$MERGE_TOOLS_DIR" && ls ) | {
+		while read toolname
+		do
+			if setup_tool "$toolname" 2>/dev/null &&
+				(eval "$condition" "$toolname")
+			then
+				if test -n "$preamble"
+				then
+					printf "%s\n" "$preamble"
+					preamble=
+				fi
+				shown_any=yes
+				printf "%s%s\n" "$per_line_prefix" "$toolname"
+			fi
+		done
+
+		if test -n "$preamble" && test -n "$not_found_msg"
+		then
+			printf "%s\n" "$not_found_msg"
+		fi
+
+		test -n "$shown_any"
+	}
+}
+
 diff_mode() {
 	test "$TOOL_MODE" = diff
 }
@@ -199,37 +246,24 @@
 }
 
 show_tool_help () {
-	unavailable= available= LF='
-'
-	for i in "$MERGE_TOOLS_DIR"/*
-	do
-		tool=$(basename "$i")
-		setup_tool "$tool" 2>/dev/null || continue
+	tool_opt="'git ${TOOL_MODE}tool --tool-<tool>'"
 
-		merge_tool_path=$(translate_merge_tool_path "$tool")
-		if type "$merge_tool_path" >/dev/null 2>&1
-		then
-			available="$available$tool$LF"
-		else
-			unavailable="$unavailable$tool$LF"
-		fi
-	done
+	tab='	'
+	LF='
+'
+	any_shown=no
 
 	cmd_name=${TOOL_MODE}tool
-	if test -n "$available"
-	then
-		echo "'git $cmd_name --tool=<tool>' may be set to one of the following:"
-		echo "$available" | sort | sed -e 's/^/	/'
-	else
-		echo "No suitable tool for 'git $cmd_name --tool=<tool>' found."
-	fi
-	if test -n "$unavailable"
-	then
-		echo
-		echo 'The following tools are valid, but not currently available:'
-		echo "$unavailable" | sort | sed -e 's/^/	/'
-	fi
-	if test -n "$unavailable$available"
+	show_tool_names 'mode_ok && is_available' "$tab$tab" \
+		"$tool_opt may be set to one of the following:" \
+		"No suitable tool for 'git $cmd_name --tool=<tool>' found." &&
+		any_shown=yes
+
+	show_tool_names 'mode_ok && ! is_available' "$tab$tab" \
+		"${LF}The following tools are valid, but not currently available:" &&
+		any_shown=yes
+
+	if test "$any_shown" = yes
 	then
 		echo
 		echo "Some of the tools listed above only work in a windowed"
@@ -249,17 +283,12 @@
 	EOF
 
 	# Loop over each candidate and stop when a valid merge tool is found.
-	for i in $tools
+	for tool in $tools
 	do
-		merge_tool_path=$(translate_merge_tool_path "$i")
-		if type "$merge_tool_path" >/dev/null 2>&1
-		then
-			echo "$i"
-			return 0
-		fi
+		is_available "$tool" && echo "$tool" && return 0
 	done
 
-	echo >&2 "No known merge resolution program available."
+	echo >&2 "No known ${TOOL_MODE} tool is available."
 	return 1
 }