mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
vfmt: add support for VDIFF_TOOL, detect more diffing tools (#5857)
This commit is contained in:
@@ -265,8 +265,9 @@ pub fn exec(cmd string) ?Result {
|
||||
C.ExpandEnvironmentStringsW(cmd.to_wide(), voidptr(&command_line), 32768)
|
||||
create_process_ok := C.CreateProcessW(0, command_line, 0, 0, C.TRUE, 0, 0, 0, voidptr(&start_info), voidptr(&proc_info))
|
||||
if !create_process_ok {
|
||||
error_msg := get_error_msg(int(C.GetLastError()))
|
||||
return error('exec failed (CreateProcess): $error_msg cmd: $cmd')
|
||||
error_num := int(C.GetLastError())
|
||||
error_msg := get_error_msg(error_num)
|
||||
return error('exec failed (CreateProcess) with code $error_num: $error_msg cmd: $cmd')
|
||||
}
|
||||
C.CloseHandle(child_stdin)
|
||||
C.CloseHandle(child_stdout_write)
|
||||
|
||||
82
vlib/v/util/diff.v
Normal file
82
vlib/v/util/diff.v
Normal file
@@ -0,0 +1,82 @@
|
||||
module util
|
||||
|
||||
import os
|
||||
import time
|
||||
|
||||
// iterates through a list of known diff cli commands
|
||||
// and returns it with basic options
|
||||
pub fn find_working_diff_command() ?string {
|
||||
env_difftool := os.getenv('VDIFF_TOOL')
|
||||
env_diffopts := os.getenv('VDIFF_OPTIONS')
|
||||
mut known_diff_tools := []string{}
|
||||
if env_difftool.len > 0 {
|
||||
known_diff_tools << env_difftool
|
||||
}
|
||||
known_diff_tools << [
|
||||
'colordiff', 'gdiff', 'diff', 'colordiff.exe',
|
||||
'diff.exe', 'opendiff', 'code', 'code.cmd'
|
||||
]
|
||||
// NOTE: code.cmd is the Windows variant of the `code` cli tool
|
||||
for diffcmd in known_diff_tools {
|
||||
if diffcmd == 'opendiff' { // opendiff has no `--version` option
|
||||
if opendiff_exists() {
|
||||
return diffcmd
|
||||
}
|
||||
continue
|
||||
}
|
||||
p := os.exec('$diffcmd --version') or {
|
||||
continue
|
||||
}
|
||||
if p.exit_code == 127 && diffcmd == env_difftool {
|
||||
// user setup is wonky, fix it
|
||||
return error('could not find specified VDIFF_TOOL $diffcmd')
|
||||
}
|
||||
if p.exit_code == 0 { // success
|
||||
if diffcmd in ['code', 'code.cmd'] {
|
||||
// there is no guarantee that the env opts exist
|
||||
// or include `-d`, so (harmlessly) add it
|
||||
return '$diffcmd $env_diffopts -d'
|
||||
}
|
||||
return '$diffcmd $env_diffopts'
|
||||
}
|
||||
}
|
||||
return error('No working "diff" command found')
|
||||
}
|
||||
|
||||
// determine if the FileMerge opendiff tool is available
|
||||
fn opendiff_exists() bool {
|
||||
o := os.exec('opendiff') or {
|
||||
return false
|
||||
}
|
||||
if o.exit_code == 1 { // failed (expected), but found (i.e. not 127)
|
||||
if o.output.contains('too few arguments') { // got some exptected output
|
||||
return true
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
pub fn color_compare_files(diff_cmd, file1, file2 string) string {
|
||||
if diff_cmd != '' {
|
||||
full_cmd := '$diff_cmd --minimal --text --unified=2 ' +
|
||||
' --show-function-line="fn " "$file1" "$file2" '
|
||||
x := os.exec(full_cmd) or {
|
||||
return 'comparison command: `$full_cmd` failed'
|
||||
}
|
||||
return x.output.trim_right('\r\n')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn color_compare_strings(diff_cmd, expected, found string) string {
|
||||
cdir := os.cache_dir()
|
||||
ctime := time.sys_mono_now()
|
||||
e_file := os.join_path(cdir, '${ctime}.expected.txt')
|
||||
f_file := os.join_path(cdir, '${ctime}.found.txt')
|
||||
os.write_file(e_file, expected)
|
||||
os.write_file(f_file, found)
|
||||
res := color_compare_files(diff_cmd, e_file, f_file)
|
||||
os.rm(e_file)
|
||||
os.rm(f_file)
|
||||
return res
|
||||
}
|
||||
@@ -6,7 +6,6 @@ module util
|
||||
import os
|
||||
import term
|
||||
import v.token
|
||||
import time
|
||||
|
||||
// The filepath:line:col: format is the default C compiler error output format.
|
||||
// It allows editors and IDE's like emacs to quickly find the errors in the
|
||||
@@ -89,7 +88,7 @@ pub fn formatted_error(kind, omsg, filepath string, pos token.Position) string {
|
||||
}
|
||||
}
|
||||
column := imax(0, pos.pos - p - 1)
|
||||
position := '${path}:${pos.line_nr+1}:${util.imax(1,column+1)}:'
|
||||
position := '$path:${pos.line_nr+1}:${imax(1,column+1)}:'
|
||||
scontext := source_context(kind, source, column, pos).join('\n')
|
||||
final_position := bold(position)
|
||||
final_kind := bold(color(kind, kind))
|
||||
@@ -112,11 +111,8 @@ pub fn source_context(kind, source string, column int, pos token.Position) []str
|
||||
sline := source_lines[iline]
|
||||
start_column := imax(0, imin(column, sline.len))
|
||||
end_column := imax(0, imin(column + imax(0, pos.len), sline.len))
|
||||
cline := if iline == pos.line_nr {
|
||||
sline[..start_column] + color(kind, sline[start_column..end_column]) + sline[end_column..]
|
||||
} else {
|
||||
sline
|
||||
}
|
||||
cline := if iline == pos.line_nr { sline[..start_column] + color(kind, sline[start_column..end_column]) +
|
||||
sline[end_column..] } else { sline }
|
||||
clines << '${iline+1:5d} | ' + cline.replace('\t', tab_spaces)
|
||||
//
|
||||
if iline == pos.line_nr {
|
||||
@@ -126,18 +122,10 @@ pub fn source_context(kind, source string, column int, pos token.Position) []str
|
||||
// use strings.repeat(` `, col) to form it.
|
||||
mut pointerline := ''
|
||||
for bchar in sline[..start_column] {
|
||||
x := if bchar.is_space() {
|
||||
bchar
|
||||
} else {
|
||||
` `
|
||||
}
|
||||
x := if bchar.is_space() { bchar } else { ` ` }
|
||||
pointerline += x.str()
|
||||
}
|
||||
underline := if pos.len > 1 {
|
||||
'~'.repeat(end_column - start_column)
|
||||
} else {
|
||||
'^'
|
||||
}
|
||||
underline := if pos.len > 1 { '~'.repeat(end_column - start_column) } else { '^' }
|
||||
pointerline += bold(color(kind, underline))
|
||||
clines << ' | ' + pointerline.replace('\t', tab_spaces)
|
||||
}
|
||||
@@ -147,44 +135,6 @@ pub fn source_context(kind, source string, column int, pos token.Position) []str
|
||||
|
||||
pub fn verror(kind, s string) {
|
||||
final_kind := bold(color(kind, kind))
|
||||
eprintln('${final_kind}: $s')
|
||||
eprintln('$final_kind: $s')
|
||||
exit(1)
|
||||
}
|
||||
|
||||
pub fn find_working_diff_command() ?string {
|
||||
for diffcmd in ['colordiff', 'gdiff', 'diff', 'colordiff.exe', 'diff.exe'] {
|
||||
p := os.exec('$diffcmd --version') or {
|
||||
continue
|
||||
}
|
||||
if p.exit_code == 0 {
|
||||
return diffcmd
|
||||
}
|
||||
}
|
||||
return error('no working diff command found')
|
||||
}
|
||||
|
||||
pub fn color_compare_files(diff_cmd, file1, file2 string) string {
|
||||
if diff_cmd != '' {
|
||||
mut other_options := os.getenv('VDIFF_OPTIONS')
|
||||
full_cmd := '$diff_cmd --minimal --text --unified=2 ' +
|
||||
' --show-function-line="fn " $other_options "$file1" "$file2" '
|
||||
x := os.exec(full_cmd) or {
|
||||
return 'comparison command: `${full_cmd}` failed'
|
||||
}
|
||||
return x.output.trim_right('\r\n')
|
||||
}
|
||||
return ''
|
||||
}
|
||||
|
||||
pub fn color_compare_strings(diff_cmd string, expected string, found string) string {
|
||||
cdir := os.cache_dir()
|
||||
ctime := time.sys_mono_now()
|
||||
e_file := os.join_path(cdir, '${ctime}.expected.txt')
|
||||
f_file := os.join_path(cdir, '${ctime}.found.txt')
|
||||
os.write_file( e_file, expected)
|
||||
os.write_file( f_file, found)
|
||||
res := util.color_compare_files(diff_cmd, e_file, f_file)
|
||||
os.rm( e_file )
|
||||
os.rm( f_file )
|
||||
return res
|
||||
}
|
||||
|
||||
@@ -12,9 +12,7 @@ pub const (
|
||||
|
||||
// math.bits is needed by strconv.ftoa
|
||||
pub const (
|
||||
builtin_module_parts = ['math.bits', 'strconv', 'strconv.ftoa', 'hash.wyhash', 'strings',
|
||||
'builtin'
|
||||
]
|
||||
builtin_module_parts = ['math.bits', 'strconv', 'strconv.ftoa', 'hash.wyhash', 'strings', 'builtin']
|
||||
)
|
||||
|
||||
pub const (
|
||||
@@ -167,7 +165,7 @@ pub fn launch_tool(is_verbose bool, tool_name string, args []string) {
|
||||
}
|
||||
if tool_compilation.exit_code != 0 {
|
||||
mut err := 'Permission denied'
|
||||
if !tool_compilation.output.contains('Permission denied') {
|
||||
if !tool_compilation.output.contains(err) {
|
||||
err = '\n$tool_compilation.output'
|
||||
}
|
||||
eprintln('cannot compile `$tool_source`: $err')
|
||||
|
||||
Reference in New Issue
Block a user