forked from github-mirrors/ale
apple-swift-format: linter and fixer with config swiftpm support (#3671)
This commit is contained in:
parent
06f57ca973
commit
f0887d3e61
|
@ -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'
|
||||
\})
|
|
@ -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'
|
||||
\})
|
|
@ -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'],
|
||||
|
|
|
@ -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
|
|
@ -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
|
||||
|
||||
" }}}
|
||||
|
|
|
@ -2,6 +2,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*
|
||||
|
||||
|
@ -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:
|
||||
|
||||
|
|
|
@ -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|
|
||||
|
|
|
@ -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(''))
|
|
@ -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',
|
||||
\ ])
|
|
@ -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'
|
|
@ -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'
|
|
@ -0,0 +1,10 @@
|
|||
{
|
||||
"version": 1,
|
||||
"lineLength": 100,
|
||||
"indentation": {
|
||||
"spaces": 4
|
||||
},
|
||||
"respectsExistingLineBreaks": true,
|
||||
"lineBreakBeforeControlFlowKeywords": true,
|
||||
"lineBreakBeforeEachArgument": true
|
||||
}
|
Loading…
Reference in New Issue