Skip to content

Commit f0887d3

Browse files
authored
apple-swift-format: linter and fixer with config swiftpm support (#3671)
1 parent 06f57ca commit f0887d3

File tree

14 files changed

+265
-92
lines changed

14 files changed

+265
-92
lines changed
+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
" Authors: Klaas Pieter Annema <https://github.com/klaaspieter>, bosr <[email protected]>
2+
" Description: Support for swift-format https://github.com/apple/swift-format
3+
4+
function! ale_linters#swift#appleswiftformat#GetLinterCommand(buffer) abort
5+
let l:command_args = ale#swift#GetAppleSwiftFormatCommand(a:buffer) . ' lint %t'
6+
let l:config_args = ale#swift#GetAppleSwiftFormatConfigArgs(a:buffer)
7+
8+
if l:config_args isnot# ''
9+
let l:command_args = l:command_args . ' ' . l:config_args
10+
endif
11+
12+
return l:command_args
13+
endfunction
14+
15+
function! ale_linters#swift#appleswiftformat#Handle(buffer, lines) abort
16+
" Matches the typical output of swift-format, that is lines of the following pattern:
17+
"
18+
" Sources/main.swift:4:21: warning: [DoNotUseSemicolons] remove ';' and move the next statement to the new line
19+
" Sources/main.swift:3:12: warning: [Spacing] remove 1 space
20+
let l:pattern = '\v^.*:(\d+):(\d+): (\S+): \[(\S+)\] (.*)$'
21+
let l:output = []
22+
23+
for l:match in ale#util#GetMatches(a:lines, l:pattern)
24+
call add(l:output, {
25+
\ 'lnum': l:match[1] + 0,
26+
\ 'col': l:match[2] + 0,
27+
\ 'type': l:match[3] is# 'error' ? 'E' : 'W',
28+
\ 'code': l:match[4],
29+
\ 'text': l:match[5],
30+
\})
31+
endfor
32+
33+
return l:output
34+
endfunction
35+
36+
call ale#linter#Define('swift', {
37+
\ 'name': 'apple-swift-format',
38+
\ 'executable': function('ale#swift#GetAppleSwiftFormatExecutable'),
39+
\ 'command': function('ale_linters#swift#appleswiftformat#GetLinterCommand'),
40+
\ 'output_stream': 'stderr',
41+
\ 'language': 'swift',
42+
\ 'callback': 'ale_linters#swift#appleswiftformat#Handle'
43+
\})

ale_linters/swift/swiftformat.vim

-62
This file was deleted.

autoload/ale/fix/registry.vim

+5
Original file line numberDiff line numberDiff line change
@@ -191,6 +191,11 @@ let s:default_registry = {
191191
\ 'suggested_filetypes': ['swift'],
192192
\ 'description': 'Apply SwiftFormat to a file.',
193193
\ },
194+
\ 'apple-swift-format': {
195+
\ 'function': 'ale#fixers#appleswiftformat#Fix',
196+
\ 'suggested_filetypes': ['swift'],
197+
\ 'description': 'Apply apple/swift-format to a file.',
198+
\ },
194199
\ 'phpcbf': {
195200
\ 'function': 'ale#fixers#phpcbf#Fix',
196201
\ 'suggested_filetypes': ['php'],
+16
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
" Author: (bosr) <[email protected]>
2+
" Description: Integration of apple/swift-format formatter with ALE.
3+
4+
function! ale#fixers#appleswiftformat#Fix(buffer) abort
5+
let l:command_args = ale#swift#GetAppleSwiftFormatCommand(a:buffer) . ' format --in-place %t'
6+
let l:config_args = ale#swift#GetAppleSwiftFormatConfigArgs(a:buffer)
7+
8+
if l:config_args isnot# ''
9+
let l:command_args = l:command_args . ' ' . l:config_args
10+
endif
11+
12+
return {
13+
\ 'read_temporary_file': 1,
14+
\ 'command': l:command_args,
15+
\}
16+
endfunction

autoload/ale/swift.vim

+57
Original file line numberDiff line numberDiff line change
@@ -11,3 +11,60 @@ function! ale#swift#FindProjectRoot(buffer) abort
1111

1212
return ''
1313
endfunction
14+
15+
" Support Apple Swift Format {{{1
16+
17+
call ale#Set('swift_appleswiftformat_executable', 'swift-format')
18+
call ale#Set('swift_appleswiftformat_use_swiftpm', 0)
19+
20+
" Return the executable depending on whether or not to use Swift Package Manager.
21+
"
22+
" If not asked to use Swift Package Manager (use_swiftpm = 0), the returned
23+
" value is the global executable, else the returned value is 'swift' because
24+
" the final command line will be `swift run swift-format ...`.
25+
"
26+
" Failure is expected if use_swiftpm is `1` but no Package.swift can be located.
27+
function! ale#swift#GetAppleSwiftFormatExecutable(buffer) abort
28+
if !ale#Var(a:buffer, 'swift_appleswiftformat_use_swiftpm')
29+
return ale#Var(a:buffer, 'swift_appleswiftformat_executable')
30+
endif
31+
32+
if ale#path#FindNearestFile(a:buffer, 'Package.swift') is# ''
33+
" If there is no Package.swift file, we don't use swift-format even if it exists,
34+
" so we return '' to indicate failure.
35+
return ''
36+
endif
37+
38+
return 'swift'
39+
endfunction
40+
41+
" Return the command depending on whether or not to use Swift Package Manager.
42+
"
43+
" If asked to use Swift Package Manager (use_swiftpm = 1), the command
44+
" arguments are prefixed with 'swift run'.
45+
"
46+
" In either case, the configuration file is located and added to the command.
47+
function! ale#swift#GetAppleSwiftFormatCommand(buffer) abort
48+
let l:executable = ale#swift#GetAppleSwiftFormatExecutable(a:buffer)
49+
let l:command_args = ''
50+
51+
if ale#Var(a:buffer, 'swift_appleswiftformat_use_swiftpm')
52+
let l:command_args = ' ' . 'run swift-format'
53+
endif
54+
55+
return ale#Escape(l:executable) . l:command_args
56+
endfunction
57+
58+
" Locate the nearest '.swift-format' configuration file, and return the
59+
" arguments, else return an empty string.
60+
function! ale#swift#GetAppleSwiftFormatConfigArgs(buffer) abort
61+
let l:config_filepath = ale#path#FindNearestFile(a:buffer, '.swift-format')
62+
63+
if l:config_filepath isnot# ''
64+
return '--configuration' . ' ' . l:config_filepath
65+
endif
66+
67+
return ''
68+
endfunction
69+
70+
" }}}

doc/ale-swift.txt

+39
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,44 @@
22
ALE Swift Integration *ale-swift-options*
33

44

5+
===============================================================================
6+
apple-swift-format *ale-swift-apple-swift-format*
7+
8+
There are 3 options to enable linting and fixing with Apple's swift-format:
9+
10+
1. Install the local executable in your path, as described here:
11+
https://github.com/apple/swift-format
12+
2. Install the executable via your OS package manager, for instance via
13+
Homebrew with `brew install swift-format`
14+
3. Your Swift project has a dependency on the swift-format package, so it can
15+
be run with `swift run swift-format lint ...` In this case, you need to set
16+
a variable, see |g:ale_swift_appleswiftformat_use_swiftpm|.
17+
18+
Additionally, ALE tries to locate and use the nearest existing `.swift-format`
19+
configuration file.
20+
21+
22+
g:ale_swift_appleswiftformat_executable *g:ale_swift_appleswiftformat_executable*
23+
*b:ale_swift_appleswiftformat_executable*
24+
Type: |String|
25+
Default: `'swift-format'`
26+
27+
This variable can be modified to change the executable path for
28+
`swift-format`.
29+
30+
31+
g:ale_swift_appleswiftformat_use_swiftpm *g:ale_swift_appleswiftformat_use_swiftpm*
32+
*b:ale_swift_appleswiftformat_use_swiftpm*
33+
Type: |Number|
34+
Default: `0`
35+
36+
When set to `1`, this option will cause ALE to use
37+
`swift run swift-format lint ...` instead of the global executable. Use this
38+
option if your Swift project has a dependency on the swift-format package.
39+
40+
See |ale-integrations-local-executables|
41+
42+
543
===============================================================================
644
sourcekitlsp *ale-swift-sourcekitlsp*
745

@@ -16,6 +54,7 @@ g:ale_sourcekit_lsp_executable *g:ale_sourcekit_lsp_executable*
1654

1755
See |ale-integrations-local-executables|
1856

57+
1958
===============================================================================
2059
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
2160

doc/ale.txt

+1
Original file line numberDiff line numberDiff line change
@@ -3021,6 +3021,7 @@ documented in additional help files.
30213021
prettier..............................|ale-svelte-prettier|
30223022
svelteserver..........................|ale-svelte-svelteserver|
30233023
swift...................................|ale-swift-options|
3024+
apple-swift-format....................|ale-swift-apple-swift-format|
30243025
sourcekitlsp..........................|ale-swift-sourcekitlsp|
30253026
systemd.................................|ale-systemd-options|
30263027
systemd-analyze.......................|ale-systemd-analyze|
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
Before:
2+
call ale#assert#SetUpFixerTest('swift', 'apple-swift-format')
3+
4+
After:
5+
call ale#assert#TearDownFixerTest()
6+
7+
Execute(The swiftformat callback should return the correct default values):
8+
call ale#test#SetFilename('../test-files/swift/dummy.swift')
9+
let g:ale_swift_appleswiftformat_executable = 'xxxinvalid'
10+
let g:ale_swift_appleswiftformat_use_swiftpm = 0
11+
12+
AssertEqual
13+
\ {
14+
\ 'read_temporary_file': 1,
15+
\ 'command': ale#Escape(g:ale_swift_appleswiftformat_executable)
16+
\ . ' format --in-place %t',
17+
\ },
18+
\ ale#fixers#appleswiftformat#Fix(bufnr(''))
19+
20+
Execute(The swiftformat callback should return the correct default values and located configuration):
21+
call ale#test#SetDirectory('/testplugin/test/test-files/swift/swift-package-project-with-config')
22+
call ale#test#SetFilename('src/folder/dummy.swift')
23+
24+
let g:ale_swift_appleswiftformat_executable = 'xxxinvalid'
25+
let g:ale_swift_appleswiftformat_use_swiftpm = 0
26+
27+
AssertEqual
28+
\ {
29+
\ 'read_temporary_file': 1,
30+
\ 'command': ale#Escape(g:ale_swift_appleswiftformat_executable)
31+
\ . ' format --in-place %t --configuration ' . glob(g:dir . '/.swift-format'),
32+
\ },
33+
\ ale#fixers#appleswiftformat#Fix(bufnr(''))
34+
35+
call ale#test#RestoreDirectory()
36+
37+
Execute(The swiftformat callback should use swiftpm is use_swiftpm is set to 1):
38+
call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
39+
let g:ale_swift_appleswiftformat_use_swiftpm = 1
40+
41+
AssertEqual
42+
\ {
43+
\ 'read_temporary_file': 1,
44+
\ 'command': ale#Escape('swift')
45+
\ . ' run swift-format format --in-place %t',
46+
\ },
47+
\ ale#fixers#appleswiftformat#Fix(bufnr(''))

test/handler/test_swiftformat_handler.vader renamed to test/handler/test_appleswiftformat_handler.vader

+5-5
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
Before:
2-
runtime ale_linters/swift/swiftformat.vim
2+
runtime ale_linters/swift/appleswiftformat.vim
33

44
After:
55
call ale#linter#Reset()
66

7-
Execute(The swiftformat handler should parse lines correctly):
7+
Execute(The appleswiftformat handler should parse lines correctly):
88
AssertEqual
99
\ [
1010
\ {
@@ -22,7 +22,7 @@ Execute(The swiftformat handler should parse lines correctly):
2222
\ 'text': 'remove 1 space'
2323
\ },
2424
\ ],
25-
\ ale_linters#swift#swiftformat#Handle(bufnr(''), [
26-
\ 'Sources/main.swift:4:21: warning: [DoNotUseSemicolons]: remove '';'' and move the next statement to the new line',
27-
\ 'Sources/main.swift:3:12: warning: [Spacing]: remove 1 space',
25+
\ ale_linters#swift#appleswiftformat#Handle(bufnr(''), [
26+
\ 'Sources/main.swift:4:21: warning: [DoNotUseSemicolons] remove '';'' and move the next statement to the new line',
27+
\ 'Sources/main.swift:3:12: warning: [Spacing] remove 1 space',
2828
\ ])
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
Before:
2+
call ale#assert#SetUpLinterTest('swift', 'appleswiftformat')
3+
4+
After:
5+
call ale#assert#TearDownLinterTest()
6+
7+
Execute(Should use default command when use_swiftpm is not set):
8+
call ale#test#SetFilename('../test-files/swift/non-swift-package-project/src/folder/dummy.swift')
9+
10+
let g:ale_swift_appleswiftformat_executable = 'swift-format'
11+
let g:ale_swift_appleswiftformat_use_swiftpm = 0
12+
13+
AssertLinter 'swift-format', ale#Escape('swift-format') . ' lint %t'
14+
15+
Execute(Should use default command and available configuration when use_swiftpm is not set):
16+
call ale#test#SetDirectory('/testplugin/test/test-files/swift/swift-package-project-with-config')
17+
call ale#test#SetFilename('src/folder/dummy.swift')
18+
19+
let g:ale_swift_appleswiftformat_executable = 'swift-format'
20+
let g:ale_swift_appleswiftformat_use_swiftpm = 0
21+
22+
AssertLinter 'swift-format',
23+
\ ale#Escape('swift-format') . ' lint %t ' . '--configuration '
24+
\ . glob(g:dir . '/.swift-format')
25+
26+
call ale#test#RestoreDirectory()
27+
28+
Execute(Should use swift run when use_swiftpm is set to 1):
29+
call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
30+
31+
let g:ale_swift_appleswiftformat_use_swiftpm = 1
32+
33+
AssertLinter 'swift', ale#Escape('swift') . ' run swift-format lint %t'
34+
35+
Execute(Should use the provided global executable):
36+
call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
37+
38+
let g:ale_swift_appleswiftformat_executable = '/path/to/custom/swift-format'
39+
let g:ale_swift_appleswiftformat_use_swiftpm = 0
40+
41+
AssertLinter '/path/to/custom/swift-format',
42+
\ ale#Escape('/path/to/custom/swift-format') . ' lint %t'

test/linter/test_swift_swiftformat.vader

-25
This file was deleted.

0 commit comments

Comments
 (0)