Skip to content

Commit 037707f

Browse files
agriffisdbarnett
authored andcommitted
feat: add zprint formatter for clojure (#130)
zprint unfortunately lacks the ability to format a range, so we implement `:FormatLines` by sending only the lines to be formatted. See kkinnear/zprint#122
1 parent ff5212a commit 037707f

File tree

7 files changed

+238
-5
lines changed

7 files changed

+238
-5
lines changed

README.md

+1-1
Original file line numberDiff line numberDiff line change
@@ -12,8 +12,8 @@ helpfiles in the `doc/` directory. The helpfiles are also available via
1212

1313
* [Bazel](https://www.github.com/bazelbuild/bazel) BUILD files (buildifier)
1414
* C, C++ (clang-format)
15+
* [Clojure](https://clojure.org/) ([zprint](https://github.com/kkinnear/zprint))
1516
* CSS, Sass, SCSS, Less (js-beautify)
16-
* Chrome GN files (gn)
1717
* Dart (dartfmt)
1818
* Go (gofmt)
1919
* [GN](https://www.chromium.org/developers/gn-build-configuration) (gn)

autoload/codefmt.vim

+3-2
Original file line numberDiff line numberDiff line change
@@ -28,10 +28,11 @@
2828
" The current list of defaults by filetype is:
2929
" * bzl (Bazel): buildifier
3030
" * c, cpp, proto, javascript, typescript: clang-format
31+
" * clojure: zprint
32+
" * dart: dartfmt
33+
" * gn: gn
3134
" * go: gofmt
3235
" * python: autopep8, yapf
33-
" * gn: gn
34-
" * dart: dartfmt
3536

3637

3738
let s:plugin = maktaba#plugin#Get('codefmt')

autoload/codefmt/zprint.vim

+91
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,91 @@
1+
" Copyright 2019 Google Inc. All rights reserved.
2+
"
3+
" Licensed under the Apache License, Version 2.0 (the "License");
4+
" you may not use this file except in compliance with the License.
5+
" You may obtain a copy of the License at
6+
"
7+
" http://www.apache.org/licenses/LICENSE-2.0
8+
"
9+
" Unless required by applicable law or agreed to in writing, software
10+
" distributed under the License is distributed on an "AS IS" BASIS,
11+
" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12+
" See the License for the specific language governing permissions and
13+
" limitations under the License.
14+
15+
""
16+
" @section Recommended zprint mappings, mappings-zprint
17+
" @parentsection mappings
18+
"
19+
" Since zprint only works on top-level Clojure forms, it doesn't make sense to
20+
" format line ranges that aren't complete forms. If you're using vim-sexp
21+
" (https://github.com/guns/vim-sexp), the following mapping replaces the default
22+
" "format the current line" with "format the current top-level form." >
23+
" autocmd FileType clojure nmap <buffer> <silent> <leader>== <leader>=iF
24+
" <
25+
26+
27+
let s:plugin = maktaba#plugin#Get('codefmt')
28+
29+
30+
""
31+
" @private
32+
" Formatter: zprint
33+
function! codefmt#zprint#GetFormatter() abort
34+
let l:formatter = {
35+
\ 'name': 'zprint',
36+
\ 'setup_instructions':
37+
\ 'Install zprint filter (https://github.com/kkinnear/zprint) ' .
38+
\ 'and configure the zprint_executable flag'}
39+
40+
function l:formatter.IsAvailable() abort
41+
return executable(s:plugin.Flag('zprint_executable'))
42+
endfunction
43+
44+
function l:formatter.AppliesToBuffer() abort
45+
return &filetype is# 'clojure'
46+
endfunction
47+
48+
""
49+
" Reformat the current buffer with zprint or the binary named in
50+
" @flag(zprint_executable), only targeting the range between {startline} and
51+
" {endline}.
52+
function l:formatter.FormatRange(startline, endline) abort
53+
" Must be upper-cased to call as a function
54+
let l:ZprintOptions = s:plugin.Flag('zprint_options')
55+
if type(l:ZprintOptions) is# type([])
56+
" Assign upper-case to lower-case
57+
let l:zprint_options = l:ZprintOptions
58+
elseif maktaba#value#IsCallable(l:ZprintOptions)
59+
" Call upper-case to assign lower-case
60+
let l:zprint_options = maktaba#function#Call(l:ZprintOptions)
61+
else
62+
throw maktaba#error#WrongType(
63+
\ 'zprint_options flag must be list or callable. Found %s',
64+
\ string(l:ZprintOptions))
65+
endif
66+
let l:cmd = [s:plugin.Flag('zprint_executable')]
67+
call extend(l:cmd, l:zprint_options)
68+
69+
call maktaba#ensure#IsNumber(a:startline)
70+
call maktaba#ensure#IsNumber(a:endline)
71+
let l:lines = getline(1, line('$'))
72+
73+
" zprint doesn't support formatting a range of lines, so format the range
74+
" individually, ignoring context. This works well for top-level forms, although it's
75+
" not ideal for inner forms because it loses the indentation.
76+
let l:input = join(l:lines[a:startline - 1 : a:endline - 1], "\n")
77+
78+
" Prepare the syscall, changing to the containing directory in case the user
79+
" has configured {:search-config? true} in ~/.zprintrc
80+
let l:result = maktaba#syscall#Create(l:cmd).WithCwd(expand('%:p:h')).WithStdin(l:input).Call()
81+
let l:formatted = split(l:result.stdout, "\n")
82+
83+
" Special case empty slice: neither l:lines[:0] nor l:lines[:-1] is right.
84+
let l:before = a:startline > 1 ? l:lines[ : a:startline - 2] : []
85+
let l:full_formatted = l:before + l:formatted + l:lines[a:endline :]
86+
87+
call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted)
88+
endfunction
89+
90+
return l:formatter
91+
endfunction

doc/codefmt.txt

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ CONTENTS *codefmt-contents*
1111
6. Autocommands...........................................|codefmt-autocmds|
1212
7. Functions.............................................|codefmt-functions|
1313
8. Mappings...............................................|codefmt-mappings|
14+
1. Recommended zprint mappings.................|codefmt-mappings-zprint|
1415

1516
==============================================================================
1617
INTRODUCTION *codefmt-intro*
@@ -98,6 +99,18 @@ Default: [] `
9899
The path to the rustfmt executable.
99100
Default: 'rustfmt' `
100101

102+
*codefmt:zprint_options*
103+
Command line arguments to feed zprint. Either a list or callable that takes no
104+
args and returns a list with command line arguments. The default configures
105+
zprint with Vim's textwidth.
106+
Default: function('s:ZprintOptions') `
107+
108+
*codefmt:zprint_executable*
109+
The path to the zprint executable. Typically this is one of the native images
110+
(zprintl or zprintm) from https://github.com/kkinnear/zprint/releases
111+
installed as zprint.
112+
Default: 'zprint' `
113+
101114
*codefmt:plugin[autocmds]*
102115
Configures whether plugin/autocmds.vim should be loaded.
103116
Default: 1 `
@@ -139,10 +152,11 @@ plugins are enabled or what other software is installed on your system.
139152
The current list of defaults by filetype is:
140153
* bzl (Bazel): buildifier
141154
* c, cpp, proto, javascript, typescript: clang-format
155+
* clojure: zprint
156+
* dart: dartfmt
157+
* gn: gn
142158
* go: gofmt
143159
* python: autopep8, yapf
144-
* gn: gn
145-
* dart: dartfmt
146160

147161
==============================================================================
148162
DICTIONARIES *codefmt-dicts*
@@ -230,5 +244,17 @@ formatting ranges that mimic vim's built-in |operator|s:
230244
enclosing curly braces.
231245
* In visual mode, <PREFIX> will format the visual selection.
232246

247+
==============================================================================
248+
RECOMMENDED ZPRINT MAPPINGS *codefmt-mappings-zprint*
249+
250+
251+
Since zprint only works on top-level Clojure forms, it doesn't make sense to
252+
format line ranges that aren't complete forms. If you're using vim-sexp
253+
(https://github.com/guns/vim-sexp), the following mapping replaces the default
254+
"format the current line" with "format the current top-level form."
255+
>
256+
autocmd FileType clojure nmap <buffer> <silent> <leader>== <leader>=iF
257+
<
258+
233259

234260
vim:tw=78:ts=8:ft=help:norl:

instant/flags.vim

+21
Original file line numberDiff line numberDiff line change
@@ -127,3 +127,24 @@ call s:plugin.Flag('rustfmt_options', [])
127127
""
128128
" The path to the rustfmt executable.
129129
call s:plugin.Flag('rustfmt_executable', 'rustfmt')
130+
131+
132+
""
133+
" @private
134+
" This is declared above zprint_options to avoid interfering with vimdoc parsing
135+
" the maktaba flag.
136+
function s:ZprintOptions() abort
137+
return &textwidth ? ['{:width ' . &textwidth . '}'] : []
138+
endfunction
139+
140+
""
141+
" Command line arguments to feed zprint. Either a list or callable that takes no
142+
" args and returns a list with command line arguments. The default configures
143+
" zprint with Vim's textwidth.
144+
call s:plugin.Flag('zprint_options', function('s:ZprintOptions'))
145+
146+
""
147+
" The path to the zprint executable. Typically this is one of the native
148+
" images (zprintl or zprintm) from https://github.com/kkinnear/zprint/releases
149+
" installed as zprint.
150+
call s:plugin.Flag('zprint_executable', 'zprint')

plugin/register.vim

+1
Original file line numberDiff line numberDiff line change
@@ -35,3 +35,4 @@ call s:registry.AddExtension(codefmt#gn#GetFormatter())
3535
call s:registry.AddExtension(codefmt#buildifier#GetFormatter())
3636
call s:registry.AddExtension(codefmt#googlejava#GetFormatter())
3737
call s:registry.AddExtension(codefmt#shfmt#GetFormatter())
38+
call s:registry.AddExtension(codefmt#zprint#GetFormatter())

vroom/zprint.vroom

+93
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,93 @@
1+
The zprint formatter knows how to format Clojure.
2+
If you aren't familiar with basic codefmt usage yet, see main.vroom first.
3+
4+
We'll set up codefmt and configure the vroom environment, then jump into some
5+
examples.
6+
7+
:source $VROOMDIR/setupvroom.vim
8+
9+
:let g:repeat_calls = []
10+
:function FakeRepeat(...)<CR>
11+
| call add(g:repeat_calls, a:000)<CR>
12+
:endfunction
13+
:call maktaba#test#Override('repeat#set', 'FakeRepeat')
14+
15+
:call codefmt#SetWhetherToPerformIsAvailableChecksForTesting(0)
16+
17+
The zprint formatter expects the zprint executable to be installed on your system.
18+
19+
:FormatCode zprint
20+
! cd .* zprint .*
21+
22+
The name or path of the zprint executable can be configured via the
23+
zprint_executable flag if the default of "zprint" doesn't work.
24+
25+
:Glaive codefmt zprint_executable='/usr/local/bin/zprint'
26+
:FormatCode zprint
27+
! cd .* /usr/local/bin/zprint .*
28+
:Glaive codefmt zprint_executable='zprint'
29+
30+
You can format an entire buffer with :FormatCode.
31+
32+
@clear
33+
% (defn x [] (cond nil 1 :else 2))<CR>
34+
|(defn y [] (cond nil 3 :else 4))
35+
36+
:FormatCode zprint
37+
! cd .* zprint .*
38+
$ (defn x
39+
$ []
40+
$ (cond nil 1
41+
$ :else 2))
42+
$ (defn y
43+
$ []
44+
$ (cond nil 3
45+
$ :else 4))
46+
(defn x
47+
[]
48+
(cond nil 1
49+
:else 2))
50+
(defn y
51+
[]
52+
(cond nil 3
53+
:else 4))
54+
@end
55+
56+
You can format specific line ranges using :FormatLines. (Since zprint works on
57+
top-level forms, the range of lines should be one or more complete forms,
58+
otherwise zprint will generate an error or incorrectly-formatted code.)
59+
60+
@clear
61+
% (defn x [] (cond nil 1 :else 2))<CR>
62+
|(defn y [] (cond nil 3 :else 4))<CR>
63+
|(defn z [] (cond nil 5 :else 6))
64+
65+
:2,2FormatLines zprint
66+
! cd .* zprint .*
67+
$ (defn y
68+
$ []
69+
$ (cond nil 3
70+
$ :else 4))
71+
(defn x [] (cond nil 1 :else 2))
72+
(defn y
73+
[]
74+
(cond nil 3
75+
:else 4))
76+
(defn z [] (cond nil 5 :else 6))
77+
@end
78+
79+
Zprint is the default formatter for the clojure file type, so calling
80+
:FormatCode or :FormatLines will use it automatically.
81+
82+
:set filetype=clojure
83+
:FormatCode
84+
! cd .* zprint .*
85+
:set filetype&
86+
87+
The default setting of zprint_options propagates Vim's textwidth setting to
88+
zprint's command-line.
89+
90+
:set textwidth=123
91+
:FormatCode zprint
92+
! cd .* zprint .*:width 123.*
93+
:set textwidth&

0 commit comments

Comments
 (0)