Bram Moolenaar | 7db29e4 | 2022-12-11 15:53:04 +0000 | [diff] [blame] | 1 | " 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 | |
| 9 | function! 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 |
| 80 | endfunction |
| 81 | |
| 82 | " parse_errors parses the given errors and returns a list of parsed errors |
| 83 | function! 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 |
| 99 | endfunction |
| 100 | " vim: sw=2 ts=2 et |