Skip to content

Commit 0609431

Browse files
authored
refactor: add codefmt#formatterhelpers#ResolveFlagToArray (#138)
Refactor some common boilerplate so that it's easier to apply this logic to executables and options across all plugins. Implemented in prettier and zprint for starters, with no functional changes to either plugin.
1 parent af796cf commit 0609431

File tree

3 files changed

+63
-31
lines changed

3 files changed

+63
-31
lines changed

autoload/codefmt/formatterhelpers.vim

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313
" limitations under the License.
1414

1515

16+
let s:plugin = maktaba#plugin#Get('codefmt')
17+
18+
1619
""
1720
" @public
1821
" Format lines in the current buffer via a formatter invoked by {cmd}, which
@@ -31,6 +34,7 @@ function! codefmt#formatterhelpers#Format(cmd) abort
3134
call maktaba#buffer#Overwrite(1, line('$'), l:formatted)
3235
endfunction
3336

37+
3438
""
3539
" @public
3640
" Attempt to format a range of lines from {startline} to {endline} in the
@@ -62,3 +66,44 @@ function! codefmt#formatterhelpers#AttemptFakeRangeFormatting(
6266

6367
call maktaba#buffer#Overwrite(1, line('$'), l:full_formatted)
6468
endfunction
69+
70+
71+
""
72+
" @public
73+
" Resolve a flag (function, string or array) to a normalized array, with special
74+
" handling to convert a spaceless string to a single-element array. This is the
75+
" common case for executables, and more importantly, is backward-compatible for
76+
" existing user settings.
77+
"
78+
" @throws WrongType if the flag doesn't resolve to a string or array
79+
function! codefmt#formatterhelpers#ResolveFlagToArray(flag_name) abort
80+
let l:FlagFn = s:plugin.Flag(a:flag_name)
81+
if maktaba#value#IsFuncref(l:FlagFn)
82+
let l:value = maktaba#function#Call(l:FlagFn)
83+
else
84+
let l:value = l:FlagFn
85+
endif
86+
87+
" After (conditionally) calling the function, the resulting value should be
88+
" either a list that we can use directly, or a string that we can treat as
89+
" a single-element list, mainly for backward compatibility.
90+
if maktaba#value#IsString(l:value)
91+
if l:value =~ '\s'
92+
" Uh oh, there are spaces in the string. Rather than guessing user intent
93+
" with shell quoting and word splitting, handle this (hopefully unusual)
94+
" case by telling them to update their configuration.
95+
throw maktaba#error#WrongType(
96+
\ '%s flag is a string with spaces, please make it a list. ' .
97+
\ 'Resolved value was: %s',
98+
\ a:flag_name, l:value)
99+
endif
100+
" Convert spaceless string to single-element list.
101+
let l:value = [l:value]
102+
elseif !maktaba#value#IsList(l:value)
103+
throw maktaba#error#WrongType(
104+
\ '%s flag should be a list after calling. Found %s',
105+
\ a:flag_name, maktaba#value#TypeName(l:value))
106+
endif
107+
108+
return l:value
109+
endfunction

autoload/codefmt/prettier.vim

Lines changed: 9 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,7 @@
1616
let s:plugin = maktaba#plugin#Get('codefmt')
1717

1818
" See https://prettier.io for a list of supported file types.
19-
let s:supported_filetypes = ['javascript', 'markdown', 'html', 'css', 'yaml',
19+
let s:supported_filetypes = ['javascript', 'markdown', 'html', 'css', 'yaml',
2020
\ 'jsx', 'less', 'scss', 'mdx', 'vue']
2121

2222

@@ -30,7 +30,9 @@ function! codefmt#prettier#GetFormatter() abort
3030
\ 'and configure the prettier_executable flag'}
3131

3232
function l:formatter.IsAvailable() abort
33-
return executable(s:plugin.Flag('prettier_executable'))
33+
let l:cmd = codefmt#formatterhelpers#ResolveFlagToArray(
34+
\ 'prettier_executable')
35+
return !empty(l:cmd) && executable(l:cmd[0])
3436
endfunction
3537

3638
function l:formatter.AppliesToBuffer() abort
@@ -42,17 +44,8 @@ function! codefmt#prettier#GetFormatter() abort
4244
" @flag(prettier_executable), only targeting the range between {startline} and
4345
" {endline}.
4446
function l:formatter.FormatRange(startline, endline) abort
45-
let l:Prettier_options = s:plugin.Flag('prettier_options')
46-
if type(l:Prettier_options) is# type([])
47-
let l:prettier_options = l:Prettier_options
48-
elseif maktaba#value#IsCallable(l:Prettier_options)
49-
let l:prettier_options = maktaba#function#Call(l:Prettier_options)
50-
else
51-
throw maktaba#error#WrongType(
52-
\ 'prettier_options flag must be list or callable. Found %s',
53-
\ string(l:Prettier_options))
54-
endif
55-
let l:cmd = [s:plugin.Flag('prettier_executable'), '--stdin', '--no-color']
47+
let l:cmd = codefmt#formatterhelpers#ResolveFlagToArray(
48+
\ 'prettier_executable') + ['--stdin', '--no-color']
5649

5750
" prettier is able to automatically choose the best parser if the filepath
5851
" is provided. Otherwise, fall back to the previous default: babylon.
@@ -74,7 +67,9 @@ function! codefmt#prettier#GetFormatter() abort
7467
let l:lines_end = join(l:lines[0 : a:endline - 1], "\n")
7568
call extend(l:cmd, ['--range-end', string(strchars(l:lines_end))])
7669

77-
call extend(l:cmd, l:prettier_options)
70+
call extend(l:cmd, codefmt#formatterhelpers#ResolveFlagToArray(
71+
\ 'prettier_options'))
72+
7873
try
7974
let l:result = maktaba#syscall#Create(l:cmd).WithStdin(l:input).Call()
8075
let l:formatted = split(l:result.stdout, "\n")

autoload/codefmt/zprint.vim

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ function! codefmt#zprint#GetFormatter() abort
3838
\ 'and configure the zprint_executable flag'}
3939

4040
function l:formatter.IsAvailable() abort
41-
return executable(s:plugin.Flag('zprint_executable'))
41+
let l:cmd = codefmt#formatterhelpers#ResolveFlagToArray(
42+
\ 'zprint_executable')
43+
return !empty(l:cmd) && executable(l:cmd[0])
4244
endfunction
4345

4446
function l:formatter.AppliesToBuffer() abort
@@ -50,25 +52,15 @@ function! codefmt#zprint#GetFormatter() abort
5052
" @flag(zprint_executable), only targeting the range between {startline} and
5153
" {endline}.
5254
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_args = [s:plugin.Flag('zprint_executable')]
67-
call extend(l:cmd_args, l:zprint_options)
55+
let l:exe = codefmt#formatterhelpers#ResolveFlagToArray(
56+
\ 'zprint_executable')
57+
let l:opts = codefmt#formatterhelpers#ResolveFlagToArray(
58+
\ 'zprint_options')
6859

6960
" Prepare the syscall, changing to the containing directory in case the user
7061
" has configured {:search-config? true} in ~/.zprintrc
71-
let l:cmd = maktaba#syscall#Create(l:cmd_args).WithCwd(expand('%:p:h'))
62+
let l:cmd = maktaba#syscall#Create(l:exe + l:opts).WithCwd(expand('%:p:h'))
63+
7264
" zprint does not support range formatting yet:
7365
" https://github.com/kkinnear/zprint/issues/122
7466
" This fake range formatting works well for top-level forms, although it's

0 commit comments

Comments
 (0)