mergetool--lib: list user configured tools in '--tool-help'
[git/jnareb-git.git] / git-mergetool--lib.sh
blob330b036ac931198aa1b6e93c3602d2a2cd38291c
1 #!/bin/sh
2 # git-mergetool--lib is a library for common merge tool functions
3 MERGE_TOOLS_DIR=$(git --exec-path)/mergetools
5 mode_ok () {
6 if diff_mode
7 then
8 can_diff
9 elif merge_mode
10 then
11 can_merge
12 else
13 false
17 is_available () {
18 merge_tool_path=$(translate_merge_tool_path "$1") &&
19 type "$merge_tool_path" >/dev/null 2>&1
22 list_config_tools () {
23 section=$1
24 line_prefix=${2:-}
26 git config --get-regexp $section'\..*\.cmd' |
27 while read -r key value
29 toolname=${key#$section.}
30 toolname=${toolname%.cmd}
32 printf "%s%s\n" "$line_prefix" "$toolname"
33 done
36 show_tool_names () {
37 condition=${1:-true} per_line_prefix=${2:-} preamble=${3:-}
38 not_found_msg=${4:-}
39 extra_content=${5:-}
41 shown_any=
42 ( cd "$MERGE_TOOLS_DIR" && ls ) | {
43 while read toolname
45 if setup_tool "$toolname" 2>/dev/null &&
46 (eval "$condition" "$toolname")
47 then
48 if test -n "$preamble"
49 then
50 printf "%s\n" "$preamble"
51 preamble=
53 shown_any=yes
54 printf "%s%s\n" "$per_line_prefix" "$toolname"
56 done
58 if test -n "$extra_content"
59 then
60 if test -n "$preamble"
61 then
62 # Note: no '\n' here since we don't want a
63 # blank line if there is no initial content.
64 printf "%s" "$preamble"
65 preamble=
67 shown_any=yes
68 printf "\n%s\n" "$extra_content"
71 if test -n "$preamble" && test -n "$not_found_msg"
72 then
73 printf "%s\n" "$not_found_msg"
76 test -n "$shown_any"
80 diff_mode() {
81 test "$TOOL_MODE" = diff
84 merge_mode() {
85 test "$TOOL_MODE" = merge
88 translate_merge_tool_path () {
89 echo "$1"
92 check_unchanged () {
93 if test "$MERGED" -nt "$BACKUP"
94 then
95 status=0
96 else
97 while true
99 echo "$MERGED seems unchanged."
100 printf "Was the merge successful? [y/n] "
101 read answer || return 1
102 case "$answer" in
103 y*|Y*) status=0; break ;;
104 n*|N*) status=1; break ;;
105 esac
106 done
110 valid_tool () {
111 setup_tool "$1" && return 0
112 cmd=$(get_merge_tool_cmd "$1")
113 test -n "$cmd"
116 setup_tool () {
117 tool="$1"
119 # Fallback definitions, to be overriden by tools.
120 can_merge () {
121 return 0
124 can_diff () {
125 return 0
128 diff_cmd () {
129 status=1
130 return $status
133 merge_cmd () {
134 status=1
135 return $status
138 translate_merge_tool_path () {
139 echo "$1"
142 if ! test -f "$MERGE_TOOLS_DIR/$tool"
143 then
144 # Use a special return code for this case since we want to
145 # source "defaults" even when an explicit tool path is
146 # configured since the user can use that to override the
147 # default path in the scriptlet.
148 return 2
151 # Load the redefined functions
152 . "$MERGE_TOOLS_DIR/$tool"
154 if merge_mode && ! can_merge
155 then
156 echo "error: '$tool' can not be used to resolve merges" >&2
157 return 1
158 elif diff_mode && ! can_diff
159 then
160 echo "error: '$tool' can only be used to resolve merges" >&2
161 return 1
163 return 0
166 get_merge_tool_cmd () {
167 merge_tool="$1"
168 if diff_mode
169 then
170 git config "difftool.$merge_tool.cmd" ||
171 git config "mergetool.$merge_tool.cmd"
172 else
173 git config "mergetool.$merge_tool.cmd"
177 # Entry point for running tools
178 run_merge_tool () {
179 # If GIT_PREFIX is empty then we cannot use it in tools
180 # that expect to be able to chdir() to its value.
181 GIT_PREFIX=${GIT_PREFIX:-.}
182 export GIT_PREFIX
184 merge_tool_path=$(get_merge_tool_path "$1") || exit
185 base_present="$2"
186 status=0
188 # Bring tool-specific functions into scope
189 setup_tool "$1"
190 exitcode=$?
191 case $exitcode in
196 # The configured tool is not a built-in tool.
197 test -n "$merge_tool_path" || return 1
200 return $exitcode
202 esac
204 if merge_mode
205 then
206 run_merge_cmd "$1"
207 else
208 run_diff_cmd "$1"
210 return $status
213 # Run a either a configured or built-in diff tool
214 run_diff_cmd () {
215 merge_tool_cmd=$(get_merge_tool_cmd "$1")
216 if test -n "$merge_tool_cmd"
217 then
218 ( eval $merge_tool_cmd )
219 status=$?
220 return $status
221 else
222 diff_cmd "$1"
226 # Run a either a configured or built-in merge tool
227 run_merge_cmd () {
228 merge_tool_cmd=$(get_merge_tool_cmd "$1")
229 if test -n "$merge_tool_cmd"
230 then
231 trust_exit_code=$(git config --bool \
232 "mergetool.$1.trustExitCode" || echo false)
233 if test "$trust_exit_code" = "false"
234 then
235 touch "$BACKUP"
236 ( eval $merge_tool_cmd )
237 status=$?
238 check_unchanged
239 else
240 ( eval $merge_tool_cmd )
241 status=$?
243 return $status
244 else
245 merge_cmd "$1"
249 list_merge_tool_candidates () {
250 if merge_mode
251 then
252 tools="tortoisemerge"
253 else
254 tools="kompare"
256 if test -n "$DISPLAY"
257 then
258 if test -n "$GNOME_DESKTOP_SESSION_ID"
259 then
260 tools="meld opendiff kdiff3 tkdiff xxdiff $tools"
261 else
262 tools="opendiff kdiff3 tkdiff xxdiff meld $tools"
264 tools="$tools gvimdiff diffuse ecmerge p4merge araxis bc3 codecompare"
266 case "${VISUAL:-$EDITOR}" in
267 *vim*)
268 tools="$tools vimdiff emerge"
271 tools="$tools emerge vimdiff"
273 esac
276 show_tool_help () {
277 tool_opt="'git ${TOOL_MODE}tool --tool-<tool>'"
279 tab=' '
280 LF='
282 any_shown=no
284 cmd_name=${TOOL_MODE}tool
285 config_tools=$({
286 diff_mode && list_config_tools difftool "$tab$tab"
287 list_config_tools mergetool "$tab$tab"
288 } | sort)
289 extra_content=
290 if test -n "$config_tools"
291 then
292 extra_content="${tab}user-defined:${LF}$config_tools"
295 show_tool_names 'mode_ok && is_available' "$tab$tab" \
296 "$tool_opt may be set to one of the following:" \
297 "No suitable tool for 'git $cmd_name --tool=<tool>' found." \
298 "$extra_content" &&
299 any_shown=yes
301 show_tool_names 'mode_ok && ! is_available' "$tab$tab" \
302 "${LF}The following tools are valid, but not currently available:" &&
303 any_shown=yes
305 if test "$any_shown" = yes
306 then
307 echo
308 echo "Some of the tools listed above only work in a windowed"
309 echo "environment. If run in a terminal-only session, they will fail."
311 exit 0
314 guess_merge_tool () {
315 list_merge_tool_candidates
316 cat >&2 <<-EOF
318 This message is displayed because '$TOOL_MODE.tool' is not configured.
319 See 'git ${TOOL_MODE}tool --tool-help' or 'git help config' for more details.
320 'git ${TOOL_MODE}tool' will now attempt to use one of the following tools:
321 $tools
324 # Loop over each candidate and stop when a valid merge tool is found.
325 for tool in $tools
327 is_available "$tool" && echo "$tool" && return 0
328 done
330 echo >&2 "No known ${TOOL_MODE} tool is available."
331 return 1
334 get_configured_merge_tool () {
335 # Diff mode first tries diff.tool and falls back to merge.tool.
336 # Merge mode only checks merge.tool
337 if diff_mode
338 then
339 merge_tool=$(git config diff.tool || git config merge.tool)
340 else
341 merge_tool=$(git config merge.tool)
343 if test -n "$merge_tool" && ! valid_tool "$merge_tool"
344 then
345 echo >&2 "git config option $TOOL_MODE.tool set to unknown tool: $merge_tool"
346 echo >&2 "Resetting to default..."
347 return 1
349 echo "$merge_tool"
352 get_merge_tool_path () {
353 # A merge tool has been set, so verify that it's valid.
354 merge_tool="$1"
355 if ! valid_tool "$merge_tool"
356 then
357 echo >&2 "Unknown merge tool $merge_tool"
358 exit 1
360 if diff_mode
361 then
362 merge_tool_path=$(git config difftool."$merge_tool".path ||
363 git config mergetool."$merge_tool".path)
364 else
365 merge_tool_path=$(git config mergetool."$merge_tool".path)
367 if test -z "$merge_tool_path"
368 then
369 merge_tool_path=$(translate_merge_tool_path "$merge_tool")
371 if test -z "$(get_merge_tool_cmd "$merge_tool")" &&
372 ! type "$merge_tool_path" >/dev/null 2>&1
373 then
374 echo >&2 "The $TOOL_MODE tool $merge_tool is not available as"\
375 "'$merge_tool_path'"
376 exit 1
378 echo "$merge_tool_path"
381 get_merge_tool () {
382 # Check if a merge tool has been configured
383 merge_tool=$(get_configured_merge_tool)
384 # Try to guess an appropriate merge tool if no tool has been set.
385 if test -z "$merge_tool"
386 then
387 merge_tool=$(guess_merge_tool) || exit
389 echo "$merge_tool"