From 4d5520066bc006afceece6703b9d85be6f907f5c Mon Sep 17 00:00:00 2001 From: Andrew Veritas Date: Sat, 27 May 2023 09:30:33 -0700 Subject: [PATCH 1/6] Add ruby formatting support using Rubocop. This change is based on an abandoned change by zinovyev: https://github.com/zinovyev/vim-codefmt/tree/add-support-for-ruby and matching pull request: https://github.com/google/vim-codefmt/pull/132 --- README.md | 1 + autoload/codefmt/rubocop.vim | 70 ++++++++++++++++++++++++++++++++++++ instant/flags.vim | 4 +++ plugin/register.vim | 2 ++ vroom/rubocop.vroom | 59 ++++++++++++++++++++++++++++++ 5 files changed, 136 insertions(+) create mode 100644 autoload/codefmt/rubocop.vim create mode 100644 vroom/rubocop.vroom diff --git a/README.md b/README.md index 237d7f7..6e9a9ed 100644 --- a/README.md +++ b/README.md @@ -28,6 +28,7 @@ helpfiles in the `doc/` directory. The helpfiles are also available via * OCaml ([ocamlformat](https://github.com/ocaml-ppx/ocamlformat)) * Proto (clang-format) * Python (Autopep8, Black, or YAPF) +* Ruby ([rubocop](https://rubocop.org)) * Rust ([rustfmt](https://github.com/rust-lang/rustfmt)) * TypeScript (clang-format) * Shell (shfmt) diff --git a/autoload/codefmt/rubocop.vim b/autoload/codefmt/rubocop.vim new file mode 100644 index 0000000..e55ac34 --- /dev/null +++ b/autoload/codefmt/rubocop.vim @@ -0,0 +1,70 @@ +" Copyright 2023 Google Inc. All rights reserved. +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +let s:plugin = maktaba#plugin#Get('codefmt') + + +"" +" @private +" Formatter: rubocop +function! codefmt#rubocop#GetFormatter() abort + let l:formatter = { + \ 'name': 'rubocop', + \ 'setup_instructions': 'Install rubocop ' . + \ '(https://rubygems.org/gems/rubocop).'} + + function l:formatter.IsAvailable() abort + return executable(s:plugin.Flag('rubocop_executable')) + endfunction + + function l:formatter.AppliesToBuffer() abort + return &filetype is# 'eruby' || &filetype is# 'ruby' + endfunction + + "" + " Reformat the current buffer with rubocop or the binary named in + " @flag(rubocop_executable), only targeting the range between {startline} and + " {endline}. + " @throws ShellError + function l:formatter.FormatRange(startline, endline) abort + " See flag explanations at: + " https://docs.rubocop.org/rubocop/1.51/usage/basic_usage.html + let l:cmd = [s:plugin.Flag('rubocop_executable'), '--stdin', @%, '-a', '--no-color', '-fq', '-o', '/dev/null'] + + call maktaba#ensure#IsNumber(a:startline) + call maktaba#ensure#IsNumber(a:endline) + + let l:lines = getline(1, line('$')) + let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n") + + " Rubocop exits with an error condition if there are lint errors, even + " after successfully formatting. This is annoying for our purpuoses, + " because we have no way to distinguish lint errors from a 'real' falure. + " Use Call(0) to suppress maktaba's error handling. + let l:result = maktaba#syscall#Create(l:cmd).WithStdin(l:input).Call(0) + let l:formatted = split(l:result.stdout, "\n") + + let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : [] + " Note: l:formatted[1:] trims the first line from the output. Rubocop is + " primarily a linter, and by default it outputs lint errors first, followed + " by a dividing line, and then the formatted result. '-o /dev/null' in the + " command line suppresses any lint errors, but the divider is always + " printed. + let l:full_formatted = l:before + l:formatted[1:] + l:lines[a:endline :] + + call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted) + endfunction + + return l:formatter +endfunction diff --git a/instant/flags.vim b/instant/flags.vim index 3e10fa6..4900c5b 100644 --- a/instant/flags.vim +++ b/instant/flags.vim @@ -174,6 +174,10 @@ call s:plugin.Flag('prettier_options', []) " The path to the swift-format executable. call s:plugin.Flag('swift_format_executable', 'swift-format') +"" +" The path to the Rubocop executable. +call s:plugin.Flag('rubocop_executable', 'rubocop') + "" " @private function s:LookupPrettierExecutable() abort diff --git a/plugin/register.vim b/plugin/register.vim index c1804f5..36f9d6c 100644 --- a/plugin/register.vim +++ b/plugin/register.vim @@ -44,6 +44,7 @@ " * nix: nixpkgs-fmt " * ocaml: ocamlformat " * python: autopep8, black, yapf +" * ruby: rubocop " * rust: rustfmt " * sh: shfmt " * swift: swift-format @@ -80,6 +81,7 @@ call s:registry.AddExtension(codefmt#autopep8#GetFormatter()) call s:registry.AddExtension(codefmt#isort#GetFormatter()) call s:registry.AddExtension(codefmt#black#GetFormatter()) call s:registry.AddExtension(codefmt#yapf#GetFormatter()) +call s:registry.AddExtension(codefmt#rubocop#GetFormatter()) call s:registry.AddExtension(codefmt#rustfmt#GetFormatter()) call s:registry.AddExtension(codefmt#shfmt#GetFormatter()) call s:registry.AddExtension(codefmt#swiftformat#GetFormatter()) diff --git a/vroom/rubocop.vroom b/vroom/rubocop.vroom new file mode 100644 index 0000000..b0dab20 --- /dev/null +++ b/vroom/rubocop.vroom @@ -0,0 +1,59 @@ +Rubocop is a linter and formatter for ruby. +If you aren't familiar with basic codefmt usage yet, see main.vroom first. + +First, set up the vroom environment. + + :source $VROOMDIR/setupvroom.vim + + :let g:repeat_calls = [] + :function FakeRepeat(...) + | call add(g:repeat_calls, a:000) + :endfunction + :call maktaba#test#Override('repeat#set', 'FakeRepeat') + + :call codefmt#SetWhetherToPerformIsAvailableChecksForTesting(0) + +By default, the rubocop executable is called. To use this plugin, rubocop +must be installed on your system. + :FormatCode rubocop + ! rubocop .* + + + +The name and path of the Rubocop executable can be configured with a flag: + :Glaive codefmt rubocop_executable=some_other_program + :FormatCode rubocop + ! some_other_program .*-fq.* + :Glaive codefmt rubocop_executable=rubocop + + + +Rubocop does basic whitespace management. Though because it's primarily a +linter, it outputs lint errors first, then a separator. Even with the lint +errors disabled (-fq), you still get the separator. + + % def SomeClass end + :FormatCode rubocop + ! rubocop .*-fq.* + $ ========= + $ def SomeClass + $ end + def SomeClass + end + + + +Being a linter, Rubocop cares about style as well as formatting. +When a buffer is stylistically fine, it returns 0, and everything is OK. +But sometimes it will return 1 even though things have gone well; +we should still use the output when that happens. + + % def SomeClass end + :FormatCode rubocop + ! rubocop .* + $ ========= + $ def SomeClass + $ end + $ 1 (status) + def SomeClass + end From 4a4ddcdd8e04403ca6a1e4f5ab58e77dbd1ec00a Mon Sep 17 00:00:00 2001 From: Andrew Veritas Date: Sat, 27 May 2023 12:24:57 -0700 Subject: [PATCH 2/6] Add parameters to AttemptFakeRangeFormatting to allow code reuse --- autoload/codefmt/autopep8.vim | 4 +++- autoload/codefmt/dartfmt.vim | 2 +- autoload/codefmt/fish_indent.vim | 2 +- autoload/codefmt/formatterhelpers.vim | 9 ++++++--- autoload/codefmt/gofmt.vim | 2 +- autoload/codefmt/jsbeautify.vim | 2 +- autoload/codefmt/ktfmt.vim | 2 +- autoload/codefmt/mixformat.vim | 2 +- autoload/codefmt/rubocop.vim | 28 +++++++++++---------------- autoload/codefmt/shfmt.vim | 4 +++- autoload/codefmt/zprint.vim | 4 +++- doc/codefmt.txt | 2 +- vroom/rubocop.vroom | 3 ++- 13 files changed, 35 insertions(+), 31 deletions(-) diff --git a/autoload/codefmt/autopep8.vim b/autoload/codefmt/autopep8.vim index f9ba8a5..5639a4d 100644 --- a/autoload/codefmt/autopep8.vim +++ b/autoload/codefmt/autopep8.vim @@ -77,7 +77,9 @@ function! codefmt#autopep8#GetFormatter() abort call codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ a:startline, \ a:endline, - \ [l:executable, '-']) + \ [l:executable, '-'], + \ 0, + \ 0) endif endfunction diff --git a/autoload/codefmt/dartfmt.vim b/autoload/codefmt/dartfmt.vim index 6bd98a1..e7f5b53 100644 --- a/autoload/codefmt/dartfmt.vim +++ b/autoload/codefmt/dartfmt.vim @@ -43,7 +43,7 @@ function! codefmt#dartfmt#GetFormatter() abort " dartfmt does not support range formatting yet: " https://github.com/dart-lang/dart_style/issues/92 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd) + \ a:startline, a:endline, l:cmd, 0, 0) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/fish_indent.vim b/autoload/codefmt/fish_indent.vim index 7b0c78d..efbef6e 100644 --- a/autoload/codefmt/fish_indent.vim +++ b/autoload/codefmt/fish_indent.vim @@ -41,7 +41,7 @@ function! codefmt#fish_indent#GetFormatter() abort " fish_indent does not support range formatting yet: " https://github.com/fish-shell/fish-shell/issues/6490 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd) + \ a:startline, a:endline, l:cmd, 0, 0) endfunction return l:formatter diff --git a/autoload/codefmt/formatterhelpers.vim b/autoload/codefmt/formatterhelpers.vim index a1babb8..b474804 100644 --- a/autoload/codefmt/formatterhelpers.vim +++ b/autoload/codefmt/formatterhelpers.vim @@ -90,18 +90,21 @@ endfunction " @throws ShellError if the {cmd} system call fails " @throws WrongType function! codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ startline, endline, cmd) abort + \ startline, endline, cmd, ignoreerrors, skipfirstnlines) abort call maktaba#ensure#IsNumber(a:startline) call maktaba#ensure#IsNumber(a:endline) let l:lines = getline(1, line('$')) let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n") - let l:result = maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call() + let l:result = a:ignoreerrors ? + \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(0) + \ : maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call() let l:formatted = split(l:result.stdout, "\n") " Special case empty slice: neither l:lines[:0] nor l:lines[:-1] is right. let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : [] - let l:full_formatted = l:before + l:formatted + l:lines[a:endline :] + let l:full_formatted = l:before + l:formatted[a:skipfirstnlines :] + \ + l:lines[a:endline :] call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted) endfunction diff --git a/autoload/codefmt/gofmt.vim b/autoload/codefmt/gofmt.vim index 723e594..e65387b 100644 --- a/autoload/codefmt/gofmt.vim +++ b/autoload/codefmt/gofmt.vim @@ -43,7 +43,7 @@ function! codefmt#gofmt#GetFormatter() abort " gofmt does not support range formatting. " TODO: File a feature request with gofmt and link it here. call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd) + \ a:startline, a:endline, l:cmd, 0, 0) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/jsbeautify.vim b/autoload/codefmt/jsbeautify.vim index 3011284..e7ba68e 100644 --- a/autoload/codefmt/jsbeautify.vim +++ b/autoload/codefmt/jsbeautify.vim @@ -62,7 +62,7 @@ function! codefmt#jsbeautify#GetFormatter() abort " js-beautify does not support range formatting yet: " https://github.com/beautify-web/js-beautify/issues/610 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd) + \ a:startline, a:endline, l:cmd, 0, 0) endfunction function l:formatter._GetSupportedFormatName(filetype) dict abort diff --git a/autoload/codefmt/ktfmt.vim b/autoload/codefmt/ktfmt.vim index 0bbe153..d2260c9 100644 --- a/autoload/codefmt/ktfmt.vim +++ b/autoload/codefmt/ktfmt.vim @@ -84,7 +84,7 @@ function! codefmt#ktfmt#GetFormatter() abort " TODO(tstone) Switch to using --lines once that arg is added, see " https://github.com/facebookincubator/ktfmt/issues/218 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd) + \ a:startline, a:endline, l:cmd, 0, 0) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/mixformat.vim b/autoload/codefmt/mixformat.vim index d1b6c4b..99fe9ed 100644 --- a/autoload/codefmt/mixformat.vim +++ b/autoload/codefmt/mixformat.vim @@ -59,7 +59,7 @@ function! codefmt#mixformat#GetFormatter() abort " mix format doesn't have a line-range option, but does a reasonable job " (except for leading indent) when given a full valid expression call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:syscall) + \ a:startline, a:endline, l:syscall, 0, 0) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/rubocop.vim b/autoload/codefmt/rubocop.vim index e55ac34..0687dda 100644 --- a/autoload/codefmt/rubocop.vim +++ b/autoload/codefmt/rubocop.vim @@ -36,34 +36,28 @@ function! codefmt#rubocop#GetFormatter() abort " Reformat the current buffer with rubocop or the binary named in " @flag(rubocop_executable), only targeting the range between {startline} and " {endline}. + " " @throws ShellError function l:formatter.FormatRange(startline, endline) abort " See flag explanations at: " https://docs.rubocop.org/rubocop/1.51/usage/basic_usage.html let l:cmd = [s:plugin.Flag('rubocop_executable'), '--stdin', @%, '-a', '--no-color', '-fq', '-o', '/dev/null'] - call maktaba#ensure#IsNumber(a:startline) - call maktaba#ensure#IsNumber(a:endline) - - let l:lines = getline(1, line('$')) - let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n") - " Rubocop exits with an error condition if there are lint errors, even " after successfully formatting. This is annoying for our purpuoses, " because we have no way to distinguish lint errors from a 'real' falure. " Use Call(0) to suppress maktaba's error handling. - let l:result = maktaba#syscall#Create(l:cmd).WithStdin(l:input).Call(0) - let l:formatted = split(l:result.stdout, "\n") - - let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : [] - " Note: l:formatted[1:] trims the first line from the output. Rubocop is - " primarily a linter, and by default it outputs lint errors first, followed - " by a dividing line, and then the formatted result. '-o /dev/null' in the - " command line suppresses any lint errors, but the divider is always - " printed. - let l:full_formatted = l:before + l:formatted[1:] + l:lines[a:endline :] + let l:ignoreerrors = 1 + " Rubocop is primarily a linter, and by default it outputs lint errors + " first, followed by a dividing line, and then the formatted result. + " '-o /dev/null' in the command line suppresses any lint errors, but the + " divider is always printed. + let l:skipfirstnlines = 1 - call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted) + " Rubocop does not support range formatting; see bug: + " https://github.com/Shopify/ruby-lsp/issues/203 + call codefmt#formatterhelpers#AttemptFakeRangeFormatting( + \ a:startline, a:endline, l:cmd, l:ignoreerrors, l:skipfirstnlines) endfunction return l:formatter diff --git a/autoload/codefmt/shfmt.vim b/autoload/codefmt/shfmt.vim index 114263d..35377a8 100644 --- a/autoload/codefmt/shfmt.vim +++ b/autoload/codefmt/shfmt.vim @@ -62,7 +62,9 @@ function! codefmt#shfmt#GetFormatter() abort call codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ a:startline, \ a:endline, - \ l:cmd) + \ l:cmd, + \ 0, + \ 0) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/zprint.vim b/autoload/codefmt/zprint.vim index f20a500..f9df78d 100644 --- a/autoload/codefmt/zprint.vim +++ b/autoload/codefmt/zprint.vim @@ -72,7 +72,9 @@ function! codefmt#zprint#GetFormatter() abort call codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ a:startline, \ a:endline, - \ l:syscall) + \ l:syscall, + \ 0, + \ 0) endfunction return l:formatter diff --git a/doc/codefmt.txt b/doc/codefmt.txt index db07692..42d3786 100644 --- a/doc/codefmt.txt +++ b/doc/codefmt.txt @@ -383,7 +383,7 @@ codefmt#formatterhelpers#Format({cmd}) *codefmt#formatterhelpers#Format()* Throws ERROR(ShellError) if the {cmd} system call fails codefmt#formatterhelpers#AttemptFakeRangeFormatting({startline}, {endline}, - {cmd}) *codefmt#formatterhelpers#AttemptFakeRangeFormatting()* + {cmd}, {ignoreerrors}, {skipfirstnlines}) *codefmt#formatterhelpers#AttemptFakeRangeFormatting()* Attempt to format a range of lines from {startline} to {endline} in the current buffer via a formatter that doesn't natively support range formatting, which is invoked via {cmd} (a system call represented by either diff --git a/vroom/rubocop.vroom b/vroom/rubocop.vroom index b0dab20..d771f70 100644 --- a/vroom/rubocop.vroom +++ b/vroom/rubocop.vroom @@ -14,7 +14,8 @@ First, set up the vroom environment. :call codefmt#SetWhetherToPerformIsAvailableChecksForTesting(0) By default, the rubocop executable is called. To use this plugin, rubocop -must be installed on your system. +must be installed on your system. (But not for testing; vroom intercepts +system calls.) :FormatCode rubocop ! rubocop .* From f8213de6b4f00c6c18f5529af8af3ce6e59ce2b5 Mon Sep 17 00:00:00 2001 From: Andrew Veritas Date: Sat, 27 May 2023 16:51:54 -0700 Subject: [PATCH 3/6] Use varargs to pass parameters to our helper function --- autoload/codefmt/autopep8.vim | 4 +--- autoload/codefmt/dartfmt.vim | 2 +- autoload/codefmt/fish_indent.vim | 2 +- autoload/codefmt/formatterhelpers.vim | 20 ++++++++++++++------ autoload/codefmt/gofmt.vim | 2 +- autoload/codefmt/jsbeautify.vim | 2 +- autoload/codefmt/ktfmt.vim | 2 +- autoload/codefmt/mixformat.vim | 2 +- autoload/codefmt/shfmt.vim | 4 +--- autoload/codefmt/zprint.vim | 4 +--- 10 files changed, 23 insertions(+), 21 deletions(-) diff --git a/autoload/codefmt/autopep8.vim b/autoload/codefmt/autopep8.vim index 5639a4d..f9ba8a5 100644 --- a/autoload/codefmt/autopep8.vim +++ b/autoload/codefmt/autopep8.vim @@ -77,9 +77,7 @@ function! codefmt#autopep8#GetFormatter() abort call codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ a:startline, \ a:endline, - \ [l:executable, '-'], - \ 0, - \ 0) + \ [l:executable, '-']) endif endfunction diff --git a/autoload/codefmt/dartfmt.vim b/autoload/codefmt/dartfmt.vim index e7f5b53..6bd98a1 100644 --- a/autoload/codefmt/dartfmt.vim +++ b/autoload/codefmt/dartfmt.vim @@ -43,7 +43,7 @@ function! codefmt#dartfmt#GetFormatter() abort " dartfmt does not support range formatting yet: " https://github.com/dart-lang/dart_style/issues/92 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd, 0, 0) + \ a:startline, a:endline, l:cmd) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/fish_indent.vim b/autoload/codefmt/fish_indent.vim index efbef6e..7b0c78d 100644 --- a/autoload/codefmt/fish_indent.vim +++ b/autoload/codefmt/fish_indent.vim @@ -41,7 +41,7 @@ function! codefmt#fish_indent#GetFormatter() abort " fish_indent does not support range formatting yet: " https://github.com/fish-shell/fish-shell/issues/6490 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd, 0, 0) + \ a:startline, a:endline, l:cmd) endfunction return l:formatter diff --git a/autoload/codefmt/formatterhelpers.vim b/autoload/codefmt/formatterhelpers.vim index b474804..c84006e 100644 --- a/autoload/codefmt/formatterhelpers.vim +++ b/autoload/codefmt/formatterhelpers.vim @@ -87,23 +87,31 @@ endfunction " the tool for range formatting and post a URL for that feature request above " code that calls it. " -" @throws ShellError if the {cmd} system call fails +" vararg0: if truthy, the syscall ignores errors. This can be helpful for +" formatters that return nonzero results for reasons unrelated to formatting. +" +" vararg1: If set to a nonzero number N, skip the first N lines of the +" formatter output. This can be used to trim always-present headers. +" +" @throws ShellError if the {cmd} system call fails (and vararg0 is not set) " @throws WrongType function! codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ startline, endline, cmd, ignoreerrors, skipfirstnlines) abort + \ startline, endline, cmd, ...) abort call maktaba#ensure#IsNumber(a:startline) call maktaba#ensure#IsNumber(a:endline) + let l:ignoreerrors = a:0 >= 1 ? a:1 : 0 + let l:skipfirstnlines = a:0 >= 2 ? a:2 : 0 + let l:lines = getline(1, line('$')) let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n") - let l:result = a:ignoreerrors ? - \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(0) - \ : maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call() + let l:result = + \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(!l:ignoreerrors) let l:formatted = split(l:result.stdout, "\n") " Special case empty slice: neither l:lines[:0] nor l:lines[:-1] is right. let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : [] - let l:full_formatted = l:before + l:formatted[a:skipfirstnlines :] + let l:full_formatted = l:before + l:formatted[l:skipfirstnlines :] \ + l:lines[a:endline :] call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted) diff --git a/autoload/codefmt/gofmt.vim b/autoload/codefmt/gofmt.vim index e65387b..723e594 100644 --- a/autoload/codefmt/gofmt.vim +++ b/autoload/codefmt/gofmt.vim @@ -43,7 +43,7 @@ function! codefmt#gofmt#GetFormatter() abort " gofmt does not support range formatting. " TODO: File a feature request with gofmt and link it here. call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd, 0, 0) + \ a:startline, a:endline, l:cmd) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/jsbeautify.vim b/autoload/codefmt/jsbeautify.vim index e7ba68e..3011284 100644 --- a/autoload/codefmt/jsbeautify.vim +++ b/autoload/codefmt/jsbeautify.vim @@ -62,7 +62,7 @@ function! codefmt#jsbeautify#GetFormatter() abort " js-beautify does not support range formatting yet: " https://github.com/beautify-web/js-beautify/issues/610 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd, 0, 0) + \ a:startline, a:endline, l:cmd) endfunction function l:formatter._GetSupportedFormatName(filetype) dict abort diff --git a/autoload/codefmt/ktfmt.vim b/autoload/codefmt/ktfmt.vim index d2260c9..0bbe153 100644 --- a/autoload/codefmt/ktfmt.vim +++ b/autoload/codefmt/ktfmt.vim @@ -84,7 +84,7 @@ function! codefmt#ktfmt#GetFormatter() abort " TODO(tstone) Switch to using --lines once that arg is added, see " https://github.com/facebookincubator/ktfmt/issues/218 call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:cmd, 0, 0) + \ a:startline, a:endline, l:cmd) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/mixformat.vim b/autoload/codefmt/mixformat.vim index 99fe9ed..d1b6c4b 100644 --- a/autoload/codefmt/mixformat.vim +++ b/autoload/codefmt/mixformat.vim @@ -59,7 +59,7 @@ function! codefmt#mixformat#GetFormatter() abort " mix format doesn't have a line-range option, but does a reasonable job " (except for leading indent) when given a full valid expression call codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ a:startline, a:endline, l:syscall, 0, 0) + \ a:startline, a:endline, l:syscall) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/shfmt.vim b/autoload/codefmt/shfmt.vim index 35377a8..114263d 100644 --- a/autoload/codefmt/shfmt.vim +++ b/autoload/codefmt/shfmt.vim @@ -62,9 +62,7 @@ function! codefmt#shfmt#GetFormatter() abort call codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ a:startline, \ a:endline, - \ l:cmd, - \ 0, - \ 0) + \ l:cmd) catch /ERROR(ShellError):/ " Parse all the errors and stick them in the quickfix list. let l:errors = [] diff --git a/autoload/codefmt/zprint.vim b/autoload/codefmt/zprint.vim index f9df78d..f20a500 100644 --- a/autoload/codefmt/zprint.vim +++ b/autoload/codefmt/zprint.vim @@ -72,9 +72,7 @@ function! codefmt#zprint#GetFormatter() abort call codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ a:startline, \ a:endline, - \ l:syscall, - \ 0, - \ 0) + \ l:syscall) endfunction return l:formatter From c887423c8a1ed272b3a80da60dc2a85b83cf19d8 Mon Sep 17 00:00:00 2001 From: Andrew Veritas Date: Mon, 29 May 2023 10:11:53 -0700 Subject: [PATCH 4/6] Use default values instead of varargs for optional arguments --- autoload/codefmt/formatterhelpers.vim | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/autoload/codefmt/formatterhelpers.vim b/autoload/codefmt/formatterhelpers.vim index c84006e..f3aa272 100644 --- a/autoload/codefmt/formatterhelpers.vim +++ b/autoload/codefmt/formatterhelpers.vim @@ -87,31 +87,30 @@ endfunction " the tool for range formatting and post a URL for that feature request above " code that calls it. " -" vararg0: if truthy, the syscall ignores errors. This can be helpful for -" formatters that return nonzero results for reasons unrelated to formatting. -" -" vararg1: If set to a nonzero number N, skip the first N lines of the -" formatter output. This can be used to trim always-present headers. +" If [ignoreerrors] is nonzero, the syscall ignores errors. This can be helpful +" for formatters that return nonzero results for reasons unrelated to +" formatting. If [skipfirstnlines] is set to a nonzero number N, the first +" N lines of the formatter output are trimmed. This can be used to trim +" always-present headers. " " @throws ShellError if the {cmd} system call fails (and vararg0 is not set) " @throws WrongType function! codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ startline, endline, cmd, ...) abort + \ startline, endline, cmd, ignoreerrors = 0, skipfirstnlines = 0) abort call maktaba#ensure#IsNumber(a:startline) call maktaba#ensure#IsNumber(a:endline) - - let l:ignoreerrors = a:0 >= 1 ? a:1 : 0 - let l:skipfirstnlines = a:0 >= 2 ? a:2 : 0 + call maktaba#ensure#IsNumber(a:ignoreerrors) + call maktaba#ensure#IsNumber(a:skipfirstnlines) let l:lines = getline(1, line('$')) let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n") let l:result = - \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(!l:ignoreerrors) + \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(!a:ignoreerrors) let l:formatted = split(l:result.stdout, "\n") " Special case empty slice: neither l:lines[:0] nor l:lines[:-1] is right. let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : [] - let l:full_formatted = l:before + l:formatted[l:skipfirstnlines :] + let l:full_formatted = l:before + l:formatted[a:skipfirstnlines :] \ + l:lines[a:endline :] call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted) From 6e1c9fead621763294eb23b96edf460c253b585c Mon Sep 17 00:00:00 2001 From: Andrew Veritas Date: Mon, 29 May 2023 10:15:01 -0700 Subject: [PATCH 5/6] Fix stale reference to vararg0 --- autoload/codefmt/formatterhelpers.vim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/autoload/codefmt/formatterhelpers.vim b/autoload/codefmt/formatterhelpers.vim index f3aa272..befaa11 100644 --- a/autoload/codefmt/formatterhelpers.vim +++ b/autoload/codefmt/formatterhelpers.vim @@ -93,7 +93,7 @@ endfunction " N lines of the formatter output are trimmed. This can be used to trim " always-present headers. " -" @throws ShellError if the {cmd} system call fails (and vararg0 is not set) +" @throws ShellError if the {cmd} system call fails (and ignoreerrors is 0) " @throws WrongType function! codefmt#formatterhelpers#AttemptFakeRangeFormatting( \ startline, endline, cmd, ignoreerrors = 0, skipfirstnlines = 0) abort From 1fe6fb3fa864c7cb1aa9cfade95437686dbfae7b Mon Sep 17 00:00:00 2001 From: Andrew Veritas Date: Tue, 30 May 2023 07:58:59 -0700 Subject: [PATCH 6/6] Revert to using varargs instead of defaults to ensure compatiblity with older versions of vim --- autoload/codefmt/formatterhelpers.vim | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/autoload/codefmt/formatterhelpers.vim b/autoload/codefmt/formatterhelpers.vim index befaa11..f2ef96f 100644 --- a/autoload/codefmt/formatterhelpers.vim +++ b/autoload/codefmt/formatterhelpers.vim @@ -75,6 +75,7 @@ endfunction "" " @public +" @usage startline endline cmd \[ignoreerrors] \[skipfirstnlines] " Attempt to format a range of lines from {startline} to {endline} in the " current buffer via a formatter that doesn't natively support range " formatting, which is invoked via {cmd} (a system call represented by either @@ -93,24 +94,28 @@ endfunction " N lines of the formatter output are trimmed. This can be used to trim " always-present headers. " -" @throws ShellError if the {cmd} system call fails (and ignoreerrors is 0) +" @throws ShellError if the {cmd} system call fails (and [ignoreerrors] is 0) " @throws WrongType function! codefmt#formatterhelpers#AttemptFakeRangeFormatting( - \ startline, endline, cmd, ignoreerrors = 0, skipfirstnlines = 0) abort + \ startline, endline, cmd, ...) abort call maktaba#ensure#IsNumber(a:startline) call maktaba#ensure#IsNumber(a:endline) - call maktaba#ensure#IsNumber(a:ignoreerrors) - call maktaba#ensure#IsNumber(a:skipfirstnlines) + + let l:ignoreerrors = a:0 >= 1 ? a:1 : 0 + let l:skipfirstnlines = a:0 >= 2 ? a:2 : 0 + + call maktaba#ensure#IsNumber(l:ignoreerrors) + call maktaba#ensure#IsNumber(l:skipfirstnlines) let l:lines = getline(1, line('$')) let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n") let l:result = - \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(!a:ignoreerrors) + \ maktaba#syscall#Create(a:cmd).WithStdin(l:input).Call(!l:ignoreerrors) let l:formatted = split(l:result.stdout, "\n") " Special case empty slice: neither l:lines[:0] nor l:lines[:-1] is right. let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : [] - let l:full_formatted = l:before + l:formatted[a:skipfirstnlines :] + let l:full_formatted = l:before + l:formatted[l:skipfirstnlines :] \ + l:lines[a:endline :] call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted)