1module util
2
3import os
4import time
5
6// iterates through a list of known diff cli commands
7// and returns it with basic options
8pub fn find_working_diff_command() ?string {
9	env_difftool := os.getenv('VDIFF_TOOL')
10	env_diffopts := os.getenv('VDIFF_OPTIONS')
11	mut known_diff_tools := []string{}
12	if env_difftool.len > 0 {
13		known_diff_tools << env_difftool
14	}
15	known_diff_tools << [
16		'colordiff', 'gdiff', 'diff', 'colordiff.exe',
17		'diff.exe', 'opendiff', 'code', 'code.cmd'
18	]
19	// NOTE: code.cmd is the Windows variant of the `code` cli tool
20	for diffcmd in known_diff_tools {
21		if diffcmd == 'opendiff' { // opendiff has no `--version` option
22			if opendiff_exists() {
23				return diffcmd
24			}
25			continue
26		}
27		p := os.exec('$diffcmd --version') or {
28			continue
29		}
30		if p.exit_code == 127 && diffcmd == env_difftool {
31			// user setup is wonky, fix it
32			return error('could not find specified VDIFF_TOOL $diffcmd')
33		}
34		if p.exit_code == 0 { // success
35			if diffcmd in ['code', 'code.cmd'] {
36				// there is no guarantee that the env opts exist
37				// or include `-d`, so (harmlessly) add it
38				return '$diffcmd $env_diffopts -d'
39			}
40			return '$diffcmd $env_diffopts'
41		}
42	}
43	return error('No working "diff" command found')
44}
45
46// determine if the FileMerge opendiff tool is available
47fn opendiff_exists() bool {
48	o := os.exec('opendiff') or {
49		return false
50	}
51	if o.exit_code == 1 { // failed (expected), but found (i.e. not 127)
52		if o.output.contains('too few arguments') { // got some exptected output
53			return true
54		}
55	}
56	return false
57}
58
59pub fn color_compare_files(diff_cmd, file1, file2 string) string {
60	if diff_cmd != '' {
61		full_cmd := '$diff_cmd --minimal --text --unified=2 ' +
62			' --show-function-line="fn " "$file1" "$file2" '
63		x := os.exec(full_cmd) or {
64			return 'comparison command: `$full_cmd` failed'
65		}
66		return x.output.trim_right('\r\n')
67	}
68	return ''
69}
70
71pub fn color_compare_strings(diff_cmd, expected, found string) string {
72	cdir := os.cache_dir()
73	ctime := time.sys_mono_now()
74	e_file := os.join_path(cdir, '${ctime}.expected.txt')
75	f_file := os.join_path(cdir, '${ctime}.found.txt')
76	os.write_file(e_file, expected)
77	os.write_file(f_file, found)
78	res := color_compare_files(diff_cmd, e_file, f_file)
79	os.rm(e_file)
80	os.rm(f_file)
81	return res
82}
83