rustfmt.vim 2.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108
  1. " Author: Stephen Sugden <stephen@stephensugden.com>
  2. "
  3. " Adapted from https://github.com/fatih/vim-go
  4. " For bugs, patches and license go to https://github.com/rust-lang/rust.vim
  5. if !exists("g:rustfmt_autosave")
  6. let g:rustfmt_autosave = 0
  7. endif
  8. if !exists("g:rustfmt_command")
  9. let g:rustfmt_command = "rustfmt"
  10. endif
  11. if !exists("g:rustfmt_options")
  12. let g:rustfmt_options = ""
  13. endif
  14. if !exists("g:rustfmt_fail_silently")
  15. let g:rustfmt_fail_silently = 0
  16. endif
  17. let s:got_fmt_error = 0
  18. function! s:RustfmtCommandRange(filename, line1, line2)
  19. let l:arg = {"file": shellescape(a:filename), "range": [a:line1, a:line2]}
  20. return printf("%s %s --write-mode=overwrite --file-lines '[%s]'", g:rustfmt_command, g:rustfmt_options, json_encode(l:arg))
  21. endfunction
  22. function! s:RustfmtCommand(filename)
  23. return g:rustfmt_command . " --write-mode=overwrite " . g:rustfmt_options . " " . shellescape(a:filename)
  24. endfunction
  25. function! s:RunRustfmt(command, curw, tmpname)
  26. if exists("*systemlist")
  27. let out = systemlist(a:command)
  28. else
  29. let out = split(system(a:command), '\r\?\n')
  30. endif
  31. if v:shell_error == 0 || v:shell_error == 3
  32. " remove undo point caused via BufWritePre
  33. try | silent undojoin | catch | endtry
  34. " Replace current file with temp file, then reload buffer
  35. call rename(a:tmpname, expand('%'))
  36. silent edit!
  37. let &syntax = &syntax
  38. " only clear location list if it was previously filled to prevent
  39. " clobbering other additions
  40. if s:got_fmt_error
  41. let s:got_fmt_error = 0
  42. call setloclist(0, [])
  43. lwindow
  44. endif
  45. elseif g:rustfmt_fail_silently == 0
  46. " otherwise get the errors and put them in the location list
  47. let errors = []
  48. for line in out
  49. " src/lib.rs:13:5: 13:10 error: expected `,`, or `}`, found `value`
  50. let tokens = matchlist(line, '^\(.\{-}\):\(\d\+\):\(\d\+\):\s*\(\d\+:\d\+\s*\)\?\s*error: \(.*\)')
  51. if !empty(tokens)
  52. call add(errors, {"filename": @%,
  53. \"lnum": tokens[2],
  54. \"col": tokens[3],
  55. \"text": tokens[5]})
  56. endif
  57. endfor
  58. if empty(errors)
  59. % | " Couldn't detect rustfmt error format, output errors
  60. endif
  61. if !empty(errors)
  62. call setloclist(0, errors, 'r')
  63. echohl Error | echomsg "rustfmt returned error" | echohl None
  64. endif
  65. let s:got_fmt_error = 1
  66. lwindow
  67. " We didn't use the temp file, so clean up
  68. call delete(a:tmpname)
  69. endif
  70. call winrestview(a:curw)
  71. endfunction
  72. function! rustfmt#FormatRange(line1, line2)
  73. let l:curw = winsaveview()
  74. let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt"
  75. call writefile(getline(1, '$'), l:tmpname)
  76. let command = s:RustfmtCommandRange(l:tmpname, a:line1, a:line2)
  77. call s:RunRustfmt(command, l:curw, l:tmpname)
  78. endfunction
  79. function! rustfmt#Format()
  80. let l:curw = winsaveview()
  81. let l:tmpname = expand("%:p:h") . "/." . expand("%:p:t") . ".rustfmt"
  82. call writefile(getline(1, '$'), l:tmpname)
  83. let command = s:RustfmtCommand(l:tmpname)
  84. call s:RunRustfmt(command, l:curw, l:tmpname)
  85. endfunction