blob: b78c1994dd817264272f9dc7728e75adc404ca60 [file] [log] [blame]
Bram Moolenaar7db29e42022-12-11 15:53:04 +00001" Adapted from fatih/vim-go: autoload/go/fmt.vim
2"
3" Copyright 2011 The Go Authors. All rights reserved.
4" Use of this source code is governed by a BSD-style
5" license that can be found in the LICENSE file.
6"
7" Upstream: https://github.com/ziglang/zig.vim
8
9function! zig#fmt#Format() abort
10 " Save cursor position and many other things.
11 let view = winsaveview()
12
13 if !executable('zig')
14 echohl Error | echomsg "no zig binary found in PATH" | echohl None
15 return
16 endif
17
18 let cmdline = 'zig fmt --stdin --ast-check'
19 let current_buf = bufnr('')
20
21 " The formatted code is output on stdout, the errors go on stderr.
22 if exists('*systemlist')
23 silent let out = systemlist(cmdline, current_buf)
24 else
25 silent let out = split(system(cmdline, current_buf))
26 endif
27 if len(out) == 1
28 if out[0] == "error: unrecognized parameter: '--ast-check'"
29 let cmdline = 'zig fmt --stdin'
30 if exists('*systemlist')
31 silent let out = systemlist(cmdline, current_buf)
32 else
33 silent let out = split(system(cmdline, current_buf))
34 endif
35 endif
36 endif
37 let err = v:shell_error
38
39
40 if err == 0
41 " remove undo point caused via BufWritePre.
42 try | silent undojoin | catch | endtry
43
44 " Replace the file content with the formatted version.
45 if exists('*deletebufline')
46 call deletebufline(current_buf, len(out), line('$'))
47 else
48 silent execute ':' . len(out) . ',' . line('$') . ' delete _'
49 endif
50 call setline(1, out)
51
52 " No errors detected, close the loclist.
53 call setloclist(0, [], 'r')
54 lclose
55 elseif get(g:, 'zig_fmt_parse_errors', 1)
56 let errors = s:parse_errors(expand('%'), out)
57
58 call setloclist(0, [], 'r', {
59 \ 'title': 'Errors',
60 \ 'items': errors,
61 \ })
62
63 let max_win_height = get(g:, 'zig_fmt_max_window_height', 5)
64 " Prevent the loclist from becoming too long.
65 let win_height = min([max_win_height, len(errors)])
66 " Open the loclist, but only if there's at least one error to show.
67 execute 'silent! lwindow ' . win_height
68 endif
69
70 call winrestview(view)
71
72 if err != 0
73 echohl Error | echomsg "zig fmt returned error" | echohl None
74 return
75 endif
76
77 " Run the syntax highlighter on the updated content and recompute the folds if
78 " needed.
79 syntax sync fromstart
80endfunction
81
82" parse_errors parses the given errors and returns a list of parsed errors
83function! s:parse_errors(filename, lines) abort
84 " list of errors to be put into location list
85 let errors = []
86 for line in a:lines
87 let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\)\s*\(.*\)')
88 if !empty(tokens)
89 call add(errors,{
90 \"filename": a:filename,
91 \"lnum": tokens[2],
92 \"col": tokens[3],
93 \"text": tokens[4],
94 \ })
95 endif
96 endfor
97
98 return errors
99endfunction
100" vim: sw=2 ts=2 et