Closed tiehuis closed 6 years ago
Nice! This is exciting. I'll want to get zig fmt to a higher level of quality before turning this on by default, but once we're at that point I think this makes sense to add to zig.vim.
I think zig fmt
is to a level of quality where I would feel comfortable running it on every save.
Do you think that we should do these things first?
I don't think caching is really necessary here since the action is pretty quick.
The way the Go plugin originally worked was by running go fmt
and outputting the formatted code to a temporary file and then performing a rename to the current. zig fmt
does this itself, but if there was an option to write the output to a new file -o
or --output
argument then it should be as straight-forward as switching the command. There are a few things the plugin does in order to retain its buffer position and undo history and I'd need to investigate how an in-place write may affect this otherwise.
Ahh, I see what you are meaning with regards to caching. If writing the file in place then I think that behaviour would be nice. Doesn't matter to this plugin, though.
To be clear, the point of this would not be to save time - it's not caching anything. The point would be to avoid modifying the file system timestamps and causing a file system event to trigger when zig fmt did not actually change anything. For example if the editor responded to the file on disk updating by popping up a GUI dialog box, this would prevent that from happening if zig fmt did not change anything. It would also enable zig fmt to print to stdout only the files that changed, which might be useful in a git hook script.
I'm still suggesting an atomic rename - just that we would notice when renaming would be pointless and so then delete the temporary file and call it a day.
I did this in https://github.com/ziglang/zig/commit/2c96f19fd3ed312e5cb0ac8006b73e73abf4a98d. I didn't end up needing shasum, I just compared bytes directly.
I'm having trouble using this branch, do you know how to use it without Plug?
If using Vim 8, you should be able to just clone into the appropriate directory. https://gist.github.com/manasthakur/ab4cf8d32a28ea38271ac0d07373bb53#managing-plugins-natively-using-vim-8-packages
I was able to get the package loaded with vim 8, but I wasn't able to get zig fmt integration working. I didn't see any error messages or anything when I saved, even though the "fail silently" option was off
Check that you have enabled auto format by default in your vimrc, that you specify a binary path (irrelevant we don't actually check this and you specify the format command with whatever your binary name happens to mine).
let g:zig_fmt_autosave = 0
let g:zig_bin_path = '/home/me/local/bin'
let g:zig_fmt_command = ['zig2', 'fmt']
The Go plugin formats to a temporary file first before renaming in the plugin itself which is different from the default zig behavior. You'll need something more like the following with some more tweaks still. Didn't get a chance to look into this tonight. I need to figure out the best way reload the buffer in place and update the cursor and all that correctly. Side-note: %:p
just uses the full filename path and was to work around the dirname issue so isn't needed.
If you need to check the executed commands, add an echo(l:cmd)
to zig#fmt#run
.
diff --git a/autoload/zig/fmt.vim b/autoload/zig/fmt.vim
index 510568a..5d8ba7d 100644
--- a/autoload/zig/fmt.vim
+++ b/autoload/zig/fmt.vim
@@ -45,13 +45,13 @@ function! zig#fmt#Format() abort
let bin_name = zig#config#FmtCommand()
let current_col = col('.')
- let [l:out, l:err] = zig#fmt#run(bin_name, l:tmpname, expand('%'))
+ let [l:out, l:err] = zig#fmt#run(bin_name, expand('%:p'))
let diff_offset = len(readfile(l:tmpname)) - line('$')
if l:err == 0
- call zig#fmt#update_file(l:tmpname, expand('%'))
+ call zig#fmt#update_file(expand('%:p'))
elseif !zig#config#FmtFailSilently()
- let errors = s:parse_errors(expand('%'), out)
+ let errors = s:parse_errors(expand('%:p'), out)
call s:show_errors(errors)
endif
@@ -81,8 +81,9 @@ function! zig#fmt#Format() abort
syntax sync fromstart
endfunction
-" update_file updates the target file with the given formatted source
-function! zig#fmt#update_file(source, target)
+" update_file updates reloads the buffer to reflect the new formatted code
+" TODO: This doesn't work as we want and simply restores the old content.
+function! zig#fmt#update_file(target)
" remove undo point caused via BufWritePre
try | silent undojoin | catch | endtry
@@ -92,8 +93,6 @@ function! zig#fmt#update_file(source, target)
let original_fperm = getfperm(a:target)
endif
- call rename(a:source, a:target)
-
" restore file permissions
if exists("*setfperm") && original_fperm != ''
call setfperm(a:target , original_fperm)
@@ -126,12 +125,12 @@ function! zig#fmt#update_file(source, target)
endif
endfunction
-" run runs the gofmt/goimport command for the given source file and returns
-" the output of the executed command. Target is the real file to be formatted.
-function! zig#fmt#run(bin_name, source, target)
+" run runs the zig fmt command for the given source and returns the output.
+" Target is the real file to be formatted.
+function! zig#fmt#run(bin_name, target)
let l:cmd = []
call extend(cmd, a:bin_name)
- call extend(cmd, [a:source, a:target])
+ call extend(cmd, [a:target])
return zig#util#Exec(l:cmd)
endfunction
Alright, I've fixed the problems I think you were encountering. In particular, zig fmt
was not returning an error code on failure which was likely why you weren't seeing any errors. Also fixed the buffer not being saved prior to formatting so you'd never see any changes beyond the first save.
Auto-format is disabled by default. Here is the config I use for reference (zig2
is the self-hosted binary):
let g:zig_fmt_command = ['zig2', 'fmt', '--color', 'off']
let g:zig_fmt_autosave = 1
Let me know if there are any pending issues once you try it.
Got it working! thanks! This is really fun
This is largely taken from the great fatih/go-vim vim plugin. This is a quick go at isolating the required functionality for
zig fmt
to work in place ofgofmt
.You will need to specify the binary path of the zig compiler for this to work in your zig config. e.g.
let g:zig_bin_path = '/usr/bin'
.Since this requires the stage 2 compiler, I build it and copy it into the same directory as the C++ compiler, renaming it to
zig2
. Then, I set the following vim configlet g:zig_fmt_command = ['zig2', 'fmt']
.There are a few things to fix up, namely error message reporting is not really working at all as we need to specify the message format. But have a play around and see how you find this.