summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorbosr <bosr@users.noreply.github.com>2021-04-07 12:34:34 +0200
committerGitHub <noreply@github.com>2021-04-07 19:34:34 +0900
commitf0887d3e6178482255f11aa378124aef3699245f (patch)
treece9b0300de08ab7220ab63ed4e857da876367f9f
parent06f57ca9733aab6e6b67015917fdfd4bf1c70c48 (diff)
downloadale-f0887d3e6178482255f11aa378124aef3699245f.zip
apple-swift-format: linter and fixer with config swiftpm support (#3671)
-rw-r--r--ale_linters/swift/appleswiftformat.vim43
-rw-r--r--ale_linters/swift/swiftformat.vim62
-rw-r--r--autoload/ale/fix/registry.vim5
-rw-r--r--autoload/ale/fixers/appleswiftformat.vim16
-rw-r--r--autoload/ale/swift.vim57
-rw-r--r--doc/ale-swift.txt39
-rw-r--r--doc/ale.txt1
-rw-r--r--test/fixers/test_appleswiftformat_fixer_callback.vader47
-rw-r--r--test/handler/test_appleswiftformat_handler.vader (renamed from test/handler/test_swiftformat_handler.vader)10
-rw-r--r--test/linter/test_swift_appleswiftformat.vader42
-rw-r--r--test/linter/test_swift_swiftformat.vader25
-rw-r--r--test/test-files/swift/swift-package-project-with-config/.swift-format10
-rw-r--r--test/test-files/swift/swift-package-project-with-config/Package.swift0
-rw-r--r--test/test-files/swift/swift-package-project-with-config/src/folder/dummy.swift0
14 files changed, 265 insertions, 92 deletions
diff --git a/ale_linters/swift/appleswiftformat.vim b/ale_linters/swift/appleswiftformat.vim
new file mode 100644
index 00000000..4c61764d
--- /dev/null
+++ b/ale_linters/swift/appleswiftformat.vim
@@ -0,0 +1,43 @@
+" Authors: Klaas Pieter Annema <https://github.com/klaaspieter>, bosr <bosr@bosr.cc>
+" Description: Support for swift-format https://github.com/apple/swift-format
+
+function! ale_linters#swift#appleswiftformat#GetLinterCommand(buffer) abort
+ let l:command_args = ale#swift#GetAppleSwiftFormatCommand(a:buffer) . ' lint %t'
+ let l:config_args = ale#swift#GetAppleSwiftFormatConfigArgs(a:buffer)
+
+ if l:config_args isnot# ''
+ let l:command_args = l:command_args . ' ' . l:config_args
+ endif
+
+ return l:command_args
+endfunction
+
+function! ale_linters#swift#appleswiftformat#Handle(buffer, lines) abort
+ " Matches the typical output of swift-format, that is lines of the following pattern:
+ "
+ " Sources/main.swift:4:21: warning: [DoNotUseSemicolons] remove ';' and move the next statement to the new line
+ " Sources/main.swift:3:12: warning: [Spacing] remove 1 space
+ let l:pattern = '\v^.*:(\d+):(\d+): (\S+): \[(\S+)\] (.*)$'
+ let l:output = []
+
+ for l:match in ale#util#GetMatches(a:lines, l:pattern)
+ call add(l:output, {
+ \ 'lnum': l:match[1] + 0,
+ \ 'col': l:match[2] + 0,
+ \ 'type': l:match[3] is# 'error' ? 'E' : 'W',
+ \ 'code': l:match[4],
+ \ 'text': l:match[5],
+ \})
+ endfor
+
+ return l:output
+endfunction
+
+call ale#linter#Define('swift', {
+\ 'name': 'apple-swift-format',
+\ 'executable': function('ale#swift#GetAppleSwiftFormatExecutable'),
+\ 'command': function('ale_linters#swift#appleswiftformat#GetLinterCommand'),
+\ 'output_stream': 'stderr',
+\ 'language': 'swift',
+\ 'callback': 'ale_linters#swift#appleswiftformat#Handle'
+\})
diff --git a/ale_linters/swift/swiftformat.vim b/ale_linters/swift/swiftformat.vim
deleted file mode 100644
index 2504511a..00000000
--- a/ale_linters/swift/swiftformat.vim
+++ /dev/null
@@ -1,62 +0,0 @@
-" Author: Klaas Pieter Annema <https://github.com/klaaspieter>
-" Description: Support for swift-format https://github.com/apple/swift-format
-
-let s:default_executable = 'swift-format'
-call ale#Set('swift_swiftformat_executable', s:default_executable)
-
-function! ale_linters#swift#swiftformat#UseSwift(buffer) abort
- let l:swift_config = ale#path#FindNearestFile(a:buffer, 'Package.swift')
- let l:executable = ale#Var(a:buffer, 'swift_swiftformat_executable')
-
- return !empty(l:swift_config) && l:executable is# s:default_executable
-endfunction
-
-function! ale_linters#swift#swiftformat#GetExecutable(buffer) abort
- if ale_linters#swift#swiftformat#UseSwift(a:buffer)
- return 'swift'
- endif
-
- return ale#Var(a:buffer, 'swift_swiftformat_executable')
-endfunction
-
-function! ale_linters#swift#swiftformat#GetCommand(buffer) abort
- let l:executable = ale_linters#swift#swiftformat#GetExecutable(a:buffer)
- let l:args = '--mode lint %t'
-
- if ale_linters#swift#swiftformat#UseSwift(a:buffer)
- let l:args = 'run swift-format' . ' ' . l:args
- endif
-
- return ale#Escape(l:executable) . ' ' . l:args
-endfunction
-
-function! ale_linters#swift#swiftformat#Handle(buffer, lines) abort
- " Matches lines of the following pattern:
- "
- " Sources/main.swift:4:21: warning: [DoNotUseSemicolons]: remove ';' and move the next statement to the new line
- " Sources/main.swift:3:12: warning: [Spacing]: remove 1 space
- let l:pattern = '\v^.*:(\d+):(\d+): (\S+) \[(\S+)\]: (.*)$'
- let l:output = []
-
- for l:match in ale#util#GetMatches(a:lines, l:pattern)
- call add(l:output, {
- \ 'lnum': l:match[1] + 0,
- \ 'col': l:match[2] + 0,
- \ 'type': l:match[3] is# 'error' ? 'E' : 'W',
- \ 'code': l:match[4],
- \ 'text': l:match[5],
- \})
- endfor
-
- return l:output
-endfunction
-
-
-call ale#linter#Define('swift', {
-\ 'name': 'swift-format',
-\ 'executable': function('ale_linters#swift#swiftformat#GetExecutable'),
-\ 'command': function('ale_linters#swift#swiftformat#GetCommand'),
-\ 'output_stream': 'stderr',
-\ 'language': 'swift',
-\ 'callback': 'ale_linters#swift#swiftformat#Handle'
-\})
diff --git a/autoload/ale/fix/registry.vim b/autoload/ale/fix/registry.vim
index 0cf866dc..c26d4da3 100644
--- a/autoload/ale/fix/registry.vim
+++ b/autoload/ale/fix/registry.vim
@@ -191,6 +191,11 @@ let s:default_registry = {
\ 'suggested_filetypes': ['swift'],
\ 'description': 'Apply SwiftFormat to a file.',
\ },
+\ 'apple-swift-format': {
+\ 'function': 'ale#fixers#appleswiftformat#Fix',
+\ 'suggested_filetypes': ['swift'],
+\ 'description': 'Apply apple/swift-format to a file.',
+\ },
\ 'phpcbf': {
\ 'function': 'ale#fixers#phpcbf#Fix',
\ 'suggested_filetypes': ['php'],
diff --git a/autoload/ale/fixers/appleswiftformat.vim b/autoload/ale/fixers/appleswiftformat.vim
new file mode 100644
index 00000000..ca27e82c
--- /dev/null
+++ b/autoload/ale/fixers/appleswiftformat.vim
@@ -0,0 +1,16 @@
+" Author: (bosr) <bosr@bosr.cc>
+" Description: Integration of apple/swift-format formatter with ALE.
+
+function! ale#fixers#appleswiftformat#Fix(buffer) abort
+ let l:command_args = ale#swift#GetAppleSwiftFormatCommand(a:buffer) . ' format --in-place %t'
+ let l:config_args = ale#swift#GetAppleSwiftFormatConfigArgs(a:buffer)
+
+ if l:config_args isnot# ''
+ let l:command_args = l:command_args . ' ' . l:config_args
+ endif
+
+ return {
+ \ 'read_temporary_file': 1,
+ \ 'command': l:command_args,
+ \}
+endfunction
diff --git a/autoload/ale/swift.vim b/autoload/ale/swift.vim
index b31b8dc5..3232d42a 100644
--- a/autoload/ale/swift.vim
+++ b/autoload/ale/swift.vim
@@ -11,3 +11,60 @@ function! ale#swift#FindProjectRoot(buffer) abort
return ''
endfunction
+
+" Support Apple Swift Format {{{1
+
+call ale#Set('swift_appleswiftformat_executable', 'swift-format')
+call ale#Set('swift_appleswiftformat_use_swiftpm', 0)
+
+" Return the executable depending on whether or not to use Swift Package Manager.
+"
+" If not asked to use Swift Package Manager (use_swiftpm = 0), the returned
+" value is the global executable, else the returned value is 'swift' because
+" the final command line will be `swift run swift-format ...`.
+"
+" Failure is expected if use_swiftpm is `1` but no Package.swift can be located.
+function! ale#swift#GetAppleSwiftFormatExecutable(buffer) abort
+ if !ale#Var(a:buffer, 'swift_appleswiftformat_use_swiftpm')
+ return ale#Var(a:buffer, 'swift_appleswiftformat_executable')
+ endif
+
+ if ale#path#FindNearestFile(a:buffer, 'Package.swift') is# ''
+ " If there is no Package.swift file, we don't use swift-format even if it exists,
+ " so we return '' to indicate failure.
+ return ''
+ endif
+
+ return 'swift'
+endfunction
+
+" Return the command depending on whether or not to use Swift Package Manager.
+"
+" If asked to use Swift Package Manager (use_swiftpm = 1), the command
+" arguments are prefixed with 'swift run'.
+"
+" In either case, the configuration file is located and added to the command.
+function! ale#swift#GetAppleSwiftFormatCommand(buffer) abort
+ let l:executable = ale#swift#GetAppleSwiftFormatExecutable(a:buffer)
+ let l:command_args = ''
+
+ if ale#Var(a:buffer, 'swift_appleswiftformat_use_swiftpm')
+ let l:command_args = ' ' . 'run swift-format'
+ endif
+
+ return ale#Escape(l:executable) . l:command_args
+endfunction
+
+" Locate the nearest '.swift-format' configuration file, and return the
+" arguments, else return an empty string.
+function! ale#swift#GetAppleSwiftFormatConfigArgs(buffer) abort
+ let l:config_filepath = ale#path#FindNearestFile(a:buffer, '.swift-format')
+
+ if l:config_filepath isnot# ''
+ return '--configuration' . ' ' . l:config_filepath
+ endif
+
+ return ''
+endfunction
+
+" }}}
diff --git a/doc/ale-swift.txt b/doc/ale-swift.txt
index 8fa0c06c..6d53ca7c 100644
--- a/doc/ale-swift.txt
+++ b/doc/ale-swift.txt
@@ -3,6 +3,44 @@ ALE Swift Integration *ale-swift-options*
===============================================================================
+apple-swift-format *ale-swift-apple-swift-format*
+
+There are 3 options to enable linting and fixing with Apple's swift-format:
+
+1. Install the local executable in your path, as described here:
+ https://github.com/apple/swift-format
+2. Install the executable via your OS package manager, for instance via
+ Homebrew with `brew install swift-format`
+3. Your Swift project has a dependency on the swift-format package, so it can
+ be run with `swift run swift-format lint ...` In this case, you need to set
+ a variable, see |g:ale_swift_appleswiftformat_use_swiftpm|.
+
+Additionally, ALE tries to locate and use the nearest existing `.swift-format`
+configuration file.
+
+
+g:ale_swift_appleswiftformat_executable *g:ale_swift_appleswiftformat_executable*
+ *b:ale_swift_appleswiftformat_executable*
+ Type: |String|
+ Default: `'swift-format'`
+
+ This variable can be modified to change the executable path for
+ `swift-format`.
+
+
+g:ale_swift_appleswiftformat_use_swiftpm *g:ale_swift_appleswiftformat_use_swiftpm*
+ *b:ale_swift_appleswiftformat_use_swiftpm*
+ Type: |Number|
+ Default: `0`
+
+ When set to `1`, this option will cause ALE to use
+ `swift run swift-format lint ...` instead of the global executable. Use this
+ option if your Swift project has a dependency on the swift-format package.
+
+ See |ale-integrations-local-executables|
+
+
+===============================================================================
sourcekitlsp *ale-swift-sourcekitlsp*
To enable the SourceKit-LSP you need to install and build the executable as
@@ -16,6 +54,7 @@ g:ale_sourcekit_lsp_executable *g:ale_sourcekit_lsp_executable*
See |ale-integrations-local-executables|
+
===============================================================================
vim:tw=78:ts=2:sts=2:sw=2:ft=help:norl:
diff --git a/doc/ale.txt b/doc/ale.txt
index 84d4b096..682db80d 100644
--- a/doc/ale.txt
+++ b/doc/ale.txt
@@ -3021,6 +3021,7 @@ documented in additional help files.
prettier..............................|ale-svelte-prettier|
svelteserver..........................|ale-svelte-svelteserver|
swift...................................|ale-swift-options|
+ apple-swift-format....................|ale-swift-apple-swift-format|
sourcekitlsp..........................|ale-swift-sourcekitlsp|
systemd.................................|ale-systemd-options|
systemd-analyze.......................|ale-systemd-analyze|
diff --git a/test/fixers/test_appleswiftformat_fixer_callback.vader b/test/fixers/test_appleswiftformat_fixer_callback.vader
new file mode 100644
index 00000000..72465f4f
--- /dev/null
+++ b/test/fixers/test_appleswiftformat_fixer_callback.vader
@@ -0,0 +1,47 @@
+Before:
+ call ale#assert#SetUpFixerTest('swift', 'apple-swift-format')
+
+After:
+ call ale#assert#TearDownFixerTest()
+
+Execute(The swiftformat callback should return the correct default values):
+ call ale#test#SetFilename('../test-files/swift/dummy.swift')
+ let g:ale_swift_appleswiftformat_executable = 'xxxinvalid'
+ let g:ale_swift_appleswiftformat_use_swiftpm = 0
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape(g:ale_swift_appleswiftformat_executable)
+ \ . ' format --in-place %t',
+ \ },
+ \ ale#fixers#appleswiftformat#Fix(bufnr(''))
+
+Execute(The swiftformat callback should return the correct default values and located configuration):
+ call ale#test#SetDirectory('/testplugin/test/test-files/swift/swift-package-project-with-config')
+ call ale#test#SetFilename('src/folder/dummy.swift')
+
+ let g:ale_swift_appleswiftformat_executable = 'xxxinvalid'
+ let g:ale_swift_appleswiftformat_use_swiftpm = 0
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape(g:ale_swift_appleswiftformat_executable)
+ \ . ' format --in-place %t --configuration ' . glob(g:dir . '/.swift-format'),
+ \ },
+ \ ale#fixers#appleswiftformat#Fix(bufnr(''))
+
+ call ale#test#RestoreDirectory()
+
+Execute(The swiftformat callback should use swiftpm is use_swiftpm is set to 1):
+ call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
+ let g:ale_swift_appleswiftformat_use_swiftpm = 1
+
+ AssertEqual
+ \ {
+ \ 'read_temporary_file': 1,
+ \ 'command': ale#Escape('swift')
+ \ . ' run swift-format format --in-place %t',
+ \ },
+ \ ale#fixers#appleswiftformat#Fix(bufnr(''))
diff --git a/test/handler/test_swiftformat_handler.vader b/test/handler/test_appleswiftformat_handler.vader
index 3dcc4f1a..818bd9c5 100644
--- a/test/handler/test_swiftformat_handler.vader
+++ b/test/handler/test_appleswiftformat_handler.vader
@@ -1,10 +1,10 @@
Before:
- runtime ale_linters/swift/swiftformat.vim
+ runtime ale_linters/swift/appleswiftformat.vim
After:
call ale#linter#Reset()
-Execute(The swiftformat handler should parse lines correctly):
+Execute(The appleswiftformat handler should parse lines correctly):
AssertEqual
\ [
\ {
@@ -22,7 +22,7 @@ Execute(The swiftformat handler should parse lines correctly):
\ 'text': 'remove 1 space'
\ },
\ ],
- \ ale_linters#swift#swiftformat#Handle(bufnr(''), [
- \ 'Sources/main.swift:4:21: warning: [DoNotUseSemicolons]: remove '';'' and move the next statement to the new line',
- \ 'Sources/main.swift:3:12: warning: [Spacing]: remove 1 space',
+ \ ale_linters#swift#appleswiftformat#Handle(bufnr(''), [
+ \ 'Sources/main.swift:4:21: warning: [DoNotUseSemicolons] remove '';'' and move the next statement to the new line',
+ \ 'Sources/main.swift:3:12: warning: [Spacing] remove 1 space',
\ ])
diff --git a/test/linter/test_swift_appleswiftformat.vader b/test/linter/test_swift_appleswiftformat.vader
new file mode 100644
index 00000000..3dbae8ff
--- /dev/null
+++ b/test/linter/test_swift_appleswiftformat.vader
@@ -0,0 +1,42 @@
+Before:
+ call ale#assert#SetUpLinterTest('swift', 'appleswiftformat')
+
+After:
+ call ale#assert#TearDownLinterTest()
+
+Execute(Should use default command when use_swiftpm is not set):
+ call ale#test#SetFilename('../test-files/swift/non-swift-package-project/src/folder/dummy.swift')
+
+ let g:ale_swift_appleswiftformat_executable = 'swift-format'
+ let g:ale_swift_appleswiftformat_use_swiftpm = 0
+
+ AssertLinter 'swift-format', ale#Escape('swift-format') . ' lint %t'
+
+Execute(Should use default command and available configuration when use_swiftpm is not set):
+ call ale#test#SetDirectory('/testplugin/test/test-files/swift/swift-package-project-with-config')
+ call ale#test#SetFilename('src/folder/dummy.swift')
+
+ let g:ale_swift_appleswiftformat_executable = 'swift-format'
+ let g:ale_swift_appleswiftformat_use_swiftpm = 0
+
+ AssertLinter 'swift-format',
+ \ ale#Escape('swift-format') . ' lint %t ' . '--configuration '
+ \ . glob(g:dir . '/.swift-format')
+
+ call ale#test#RestoreDirectory()
+
+Execute(Should use swift run when use_swiftpm is set to 1):
+ call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
+
+ let g:ale_swift_appleswiftformat_use_swiftpm = 1
+
+ AssertLinter 'swift', ale#Escape('swift') . ' run swift-format lint %t'
+
+Execute(Should use the provided global executable):
+ call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
+
+ let g:ale_swift_appleswiftformat_executable = '/path/to/custom/swift-format'
+ let g:ale_swift_appleswiftformat_use_swiftpm = 0
+
+ AssertLinter '/path/to/custom/swift-format',
+ \ ale#Escape('/path/to/custom/swift-format') . ' lint %t'
diff --git a/test/linter/test_swift_swiftformat.vader b/test/linter/test_swift_swiftformat.vader
deleted file mode 100644
index 9f6ee62e..00000000
--- a/test/linter/test_swift_swiftformat.vader
+++ /dev/null
@@ -1,25 +0,0 @@
-Before:
- call ale#assert#SetUpLinterTest('swift', 'swiftformat')
-
-After:
- call ale#assert#TearDownLinterTest()
-
-Execute(Should use default command when not in a swift package):
- call ale#test#SetFilename('../test-files/swift/non-swift-package-project/src/folder/dummy.swift')
-
- AssertLinter 'swift-format',
- \ ale#Escape('swift-format') . ' --mode lint %t'
-
-Execute(Should use swift run when in a swift package):
- call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
-
- AssertLinter 'swift',
- \ ale#Escape('swift') . ' run swift-format --mode lint %t'
-
-Execute(Should let users configure a global executable and override local paths):
- call ale#test#SetFilename('../test-files/swift/swift-package-project/src/folder/dummy.swift')
-
- let g:ale_swift_swiftformat_executable = '/path/to/custom/swift-format'
-
- AssertLinter '/path/to/custom/swift-format',
- \ ale#Escape('/path/to/custom/swift-format') . ' --mode lint %t'
diff --git a/test/test-files/swift/swift-package-project-with-config/.swift-format b/test/test-files/swift/swift-package-project-with-config/.swift-format
new file mode 100644
index 00000000..19fb8b96
--- /dev/null
+++ b/test/test-files/swift/swift-package-project-with-config/.swift-format
@@ -0,0 +1,10 @@
+{
+ "version": 1,
+ "lineLength": 100,
+ "indentation": {
+ "spaces": 4
+ },
+ "respectsExistingLineBreaks": true,
+ "lineBreakBeforeControlFlowKeywords": true,
+ "lineBreakBeforeEachArgument": true
+}
diff --git a/test/test-files/swift/swift-package-project-with-config/Package.swift b/test/test-files/swift/swift-package-project-with-config/Package.swift
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/swift/swift-package-project-with-config/Package.swift
diff --git a/test/test-files/swift/swift-package-project-with-config/src/folder/dummy.swift b/test/test-files/swift/swift-package-project-with-config/src/folder/dummy.swift
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/test/test-files/swift/swift-package-project-with-config/src/folder/dummy.swift