From d70dc2735d0c40338158ab72e3cd9dd513bffd5f Mon Sep 17 00:00:00 2001 From: Bryant Luk <bryant.luk@bryantluk.com> Date: Fri, 2 Nov 2018 20:06:39 -0500 Subject: [PATCH] Initial version --- .vintrc.yaml | 10 ++ NOTICE | 40 +++++ README.md | 94 ++++++++++- autoload/swift/echo.vim | 68 ++++++++ autoload/swift/job.vim | 261 +++++++++++++++++++++++++++++++ autoload/swift/list.vim | 152 ++++++++++++++++++ autoload/swift/spm.vim | 125 +++++++++++++++ autoload/swift/swiftformat.vim | 168 ++++++++++++++++++++ autoload/swift/swiftlint.vim | 119 ++++++++++++++ compiler/spm.vim | 57 +++++++ compiler/swiftc.vim | 68 ++++++++ doc/swifty-vim.txt | 277 +++++++++++++++++++++++++++++++++ ftdetect/sil.vim | 15 +- ftdetect/swift.vim | 15 +- ftdetect/swiftgyb.vim | 15 +- ftplugin/swift.vim | 45 +++++- ftplugin/swift/commands.vim | 33 ++++ ftplugin/swift/mappings.vim | 27 ++++ plugin/swift.vim | 57 +++++++ syntax/sil.vim | 10 +- syntax/swift.vim | 12 +- syntax/swiftgyb.vim | 10 +- 22 files changed, 1653 insertions(+), 25 deletions(-) create mode 100644 .vintrc.yaml create mode 100644 NOTICE create mode 100644 autoload/swift/echo.vim create mode 100644 autoload/swift/job.vim create mode 100644 autoload/swift/list.vim create mode 100644 autoload/swift/spm.vim create mode 100644 autoload/swift/swiftformat.vim create mode 100644 autoload/swift/swiftlint.vim create mode 100644 compiler/spm.vim create mode 100644 compiler/swiftc.vim create mode 100644 doc/swifty-vim.txt create mode 100644 ftplugin/swift/commands.vim create mode 100644 ftplugin/swift/mappings.vim create mode 100644 plugin/swift.vim diff --git a/.vintrc.yaml b/.vintrc.yaml new file mode 100644 index 0000000..0914f1b --- /dev/null +++ b/.vintrc.yaml @@ -0,0 +1,10 @@ +cmdargs: + # Checking more strictly + severity: style_problem + +policies: + # Disable a violation + ProhibitUnnecessaryDoubleQuote: + enabled: false + ProhibitImplicitScopeVariable: + enabled: false diff --git a/NOTICE b/NOTICE new file mode 100644 index 0000000..082c6f6 --- /dev/null +++ b/NOTICE @@ -0,0 +1,40 @@ +This software includes some portions from Swift.org. + +Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors +Licensed under Apache License v2.0 with Runtime Library Exception + +See https://swift.org/LICENSE.txt for license information +See https://swift.org/CONTRIBUTORS.txt for the list of Swift project +authors + +----- + +This software includes some portions from vim-go. + +Copyright (c) 2015, Fatih Arslan +All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions are met: + +* Redistributions of source code must retain the above copyright notice, this + list of conditions and the following disclaimer. + +* Redistributions in binary form must reproduce the above copyright notice, + this list of conditions and the following disclaimer in the documentation + and/or other materials provided with the distribution. + +* Neither the name of vim-go nor the names of its + contributors may be used to endorse or promote products derived from + this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. diff --git a/README.md b/README.md index f66e383..9b2ab9a 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,85 @@ -# ⌨️ vim-swift +# ⌨️ swifty-vim -A [Swift][swift] plugin for [vim][vim]. +A [Vim][vim] plugin for [Swift][swift] which provides +file detection, syntax highlighting, support for compiling and +running tests, and optional support for formatting and linting tools. + +It is inspired by [vim-go][vim-go] and [rust.vim][rust_vim]. + +## Requirements + +* Vim 8.0.0902 or greater +* [Swift Toolchain][swift_toolchain_install] or Xcode +* (Optional) [SwiftFormat][swiftformat] +* (Optional) [SwiftLint][swiftlint] + +## Installation + +Use one of the following package managers: + +* [Vim 8 packages][vim8pack]: + * `git clone https://github.com/bluk/swifty-vim ~/.vim/pack/plugins/start/swifty-vim` +* [Pathogen][pathogen]: + * `git clone --depth=1 https://github.com/bluk/swifty-vim.git ~/.vim/bundle/swifty-vim` +* [vim-plug][vim-plug]: + * Add `Plug 'bluk/swifty-vim'` to `~/.vimrc` + * `:PlugInstall` or `$ vim +PlugInstall +qall` +* [dein.vim][dein.vim]: + * Add `call dein#add('bluk/swifty-vim')` to `~/.vimrc` + * `:call dein#install()` +* [Vundle][vundle]: + * Add `Plugin 'bluk/swifty-vim'` to `~/.vimrc` + * `:PluginInstall` or `$ vim +PluginInstall +qall` + +## Features + +There are configuration options to customize the behavior of the key mappings +and commands. + +### Swift Package Manager Support + +Key mappings and commands such as: + +* `:SwiftPMBuild` to build the current package source or tests. +* `:SwiftPMTest` to run the package tests. +* `:SwiftPMTestFunctionOnly` to run the current test under the cursor. + +### SwiftFormat Support + +Key mapping and command: + +* `:SwiftFormat` to format the current file. + +### SwiftLint Support + +Key mapping and command: + +* `:SwiftLint` to lint the current file. + +## Sample vimrc Configuration + +Add the following to your `vimrc`: + +```vim +" Build the current Swift package. If in a 'Tests' directory, also build the tests. +autocmd FileType swift nmap <leader>b <Plug>(swift-spm-build) +" Run the current Swift package tests. +autocmd FileType swift nmap <leader>t <Plug>(swift-spm-test) +" Run the test under the current cursor. +autocmd FileType swift nmap <leader>ft <Plug>(swift-spm-test-function-only) + +" Run SwiftFormat on save. +let g:swift_swiftformat_autosave = 1 +" Run SwiftLint on save. +let g:swift_swiftlint_autosave = 1 +``` + +## Documentation / Help + +Help can be found in the included [documentation][doc_dir]. + +Run `:help swifty-vim` in Vim. Helptags (`:Helptags`) may need to be generated for navigation. See your +plugin manager or the helptags documentation (`:help helptags`) for more information. ## License @@ -9,3 +88,14 @@ A [Swift][swift] plugin for [vim][vim]. [license]: LICENSE [swift]: https://swift.org [vim]: https://www.vim.org +[vim-go]: https://github.com/fatih/vim-go +[rust_vim]: https://github.com/rust-lang/rust.vim/ +[swift_toolchain_install]: https://swift.org/getting-started/ +[swiftformat]: https://github.com/nicklockwood/SwiftFormat +[swiftlint]: https://github.com/realm/SwiftLint +[vim8pack]: http://vimhelp.appspot.com/repeat.txt.html#packages +[pathogen]: https://github.com/tpope/vim-pathogen +[vim-plug]: https://github.com/junegunn/vim-plug +[dein.vim]: https://github.com/Shougo/dein.vim +[vundle]: https://github.com/gmarik/vundle +[doc_dir]: doc/ diff --git a/autoload/swift/echo.vim b/autoload/swift/echo.vim new file mode 100644 index 0000000..a9942be --- /dev/null +++ b/autoload/swift/echo.vim @@ -0,0 +1,68 @@ +" Vim autoload file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Utility functions to echo messages. + +" Source code modified from original file: +" https://github.com/fatih/vim-go/blob/8b21b2dc67ea7c666fa3a8052c6062ae217ec0d9/autoload/go/util.vim +" +" Copyright (c) 2015, Fatih Arslan +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" * Redistributions of source code must retain the above copyright notice, this +" list of conditions and the following disclaimer. +" +" * Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" * Neither the name of vim-go nor the names of its +" contributors may be used to endorse or promote products derived from +" this software without specific prior written permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +" +" Echo a message to the screen and highlight it with the group in a:hi. +" +" The message can be a list or string; every line with be :echomsg'd separately. +function! s:echo(msg, hi) abort + let l:msg = [] + if type(a:msg) != type([]) + let l:msg = split(a:msg, "\n") + else + let l:msg = a:msg + endif + + " Tabs display as ^I or <09>, so manually expand them. + let l:msg = map(l:msg, 'substitute(v:val, "\t", " ", "")') + + exe 'echohl ' . a:hi + for line in l:msg + echom "swifty-vim: " . line + endfor + echohl None +endfunction + +function! swift#echo#EchoSuccess(msg) abort + call s:echo(a:msg, 'None') +endfunction +function! swift#echo#EchoError(msg) abort + call s:echo(a:msg, 'ErrorMsg') +endfunction +function! swift#echo#EchoWarning(msg) abort + call s:echo(a:msg, 'WarningMsg') +endfunction + +" vim: sw=2 ts=2 et diff --git a/autoload/swift/job.vim b/autoload/swift/job.vim new file mode 100644 index 0000000..ac71483 --- /dev/null +++ b/autoload/swift/job.vim @@ -0,0 +1,261 @@ +" Vim autoload file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Functions to manage asynchronous jobs. + +" Source code modified from original file: +" https://github.com/fatih/vim-go/blob/bc6f1df41ffc1e6beb7309aa92318e4100cc83b7/autoload/go/job.vim +" +" Copyright (c) 2015, Fatih Arslan +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" * Redistributions of source code must retain the above copyright notice, this +" list of conditions and the following disclaimer. +" +" * Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" * Neither the name of vim-go nor the names of its +" contributors may be used to endorse or promote products derived from +" this software without specific prior written permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +function! swift#job#Spawn(args) abort + " autowrite is not enabled for jobs + call s:autowrite() + + let l:options = s:job_options(a:args) + + if !empty(a:args.status_type) + let prefix = '[' . a:args.status_type . ']' + call swift#echo#EchoSuccess(prefix . " dispatched.") + endif + + return s:start_job(a:args.cmd, l:options) +endfunction + +" Options returns callbacks to be used with job_start. It is abstracted to be +" used with various swift commands, such as build, test, etc.. This +" allows us to avoid writing the same callback over and over for some +" commands. It's fully customizable so each command can change it to its own +" logic. +" +" args is a dictionary with the these keys: +" 'jump_to_error': +" Set to 1 to jump to the first error in the error list. +" Defaults to 0. +" 'status_type': +" The status type to use when updating the status. +" 'list_type': +" The list type to use to present errors. Errors will not be handled +" when the value is '_'. Defaults to '_job'. +" 'list_title': +" The title to set the error list with. +" 'errorformat': +" The errorformat string to use when parsing errors. Defaults to +" &errorformat. See :help 'errorformat'. +" 'job_dir': +" The directory that the job should be run in. +" Defaults to the directory where the buffer is located in. +" +" The return value is a dictionary with these keys: +" 'callback': +" A function suitable to be passed as a job callback handler. See +" job-callback. +" 'exit_cb': +" A function suitable to be passed as a job exit_cb handler. See +" job-exit_cb. +" 'close_cb': +" A function suitable to be passed as a job close_cb handler. See +" job-close_cb. +" 'cwd': +" The path to the directory which contains the current buffer. The +" callbacks are configured to expect this directory is the working +" directory for the job; it should not be modified by callers. +function! s:job_options(args) abort + let callbacks = {} + let state = { + \ 'winid': win_getid(winnr()), + \ 'dir': getcwd(), + \ 'job_dir': fnameescape(expand("%:p:h")), + \ 'messages': [], + \ 'jump_to_error': 0, + \ 'list_title': "", + \ 'list_type': "_job", + \ 'exited': 0, + \ 'exit_status': 0, + \ 'closed': 0, + \ 'errorformat': &errorformat, + \ 'status_type' : '' + \ } + + if has_key(a:args, 'jump_to_error') + let state.jump_to_error = a:args.jump_to_error + endif + + if has_key(a:args, 'list_title') + let state.list_title = a:args.list_title + endif + + if has_key(a:args, 'list_type') + let state.list_type = a:args.list_type + endif + + if has_key(a:args, 'status_type') + let state.status_type = a:args.status_type + endif + + if has_key(a:args, 'errorformat') + let state.errorformat = a:args.errorformat + endif + + if has_key(a:args, 'job_dir') + let state.job_dir = a:args.job_dir + endif + + " vint: -ProhibitNoAbortFunction + function state.complete(job, exit_status, data) abort + call self.show_errors(a:job, a:exit_status, a:data) + endfunction + " vint: +ProhibitNoAbortFunction + + " vint: -ProhibitNoAbortFunction + function state.show_status(job, exit_status) dict abort + if empty(self.status_type) + return + endif + + let prefix = '[' . self.status_type . '] ' + if a:exit_status == 0 + call swift#echo#EchoSuccess(prefix . "SUCCESS") + else + call swift#echo#EchoError(prefix . "FAIL") + endif + endfunction + " vint: +ProhibitNoAbortFunction + + " vint: -ProhibitNoAbortFunction + function state.show_errors(job, exit_status, data) abort + if self.list_type ==# '_' + return + endif + + let l:winid = win_getid(winnr()) + call win_gotoid(self.winid) + + if a:exit_status == 0 && len(a:data) == 0 + call swift#list#Clean(self.list_type) + call win_gotoid(l:winid) + return + endif + + let out = join(self.messages, "\n") + + let l:cd = exists('*haslocaldir') && haslocaldir() ? 'lcd' : 'cd' + try + execute l:cd self.job_dir + call swift#list#ParseFormat(self.list_type, self.errorformat, out, self.list_title) + let errors = swift#list#Get(self.list_type) + finally + execute l:cd fnameescape(self.dir) + endtry + + if empty(errors) + if a:exit_status == 0 + call swift#list#Clean(self.list_type) + else + call swift#echo#EchoError([self.dir] + self.messages) + endif + call win_gotoid(l:winid) + return + endif + + if self.winid == l:winid + call swift#list#Window(self.list_type, len(errors)) + if self.jump_to_error + call swift#list#JumpToFirst(self.list_type) + else + call win_gotoid(l:winid) + endif + endif + endfunction + " vint: +ProhibitNoAbortFunction + + let callbacks.cwd = state.job_dir + + function! s:callback(chan, msg) dict abort + call add(self.messages, a:msg) + endfunction + let callbacks.callback = function('s:callback', [], state) + + function! s:exit_cb(job, exit_status) dict abort + let self.exit_status = a:exit_status + let self.exited = 1 + + call self.show_status(a:job, a:exit_status) + + if self.closed + call self.complete(a:job, self.exit_status, self.messages) + endif + endfunction + let callbacks.exit_cb = function('s:exit_cb', [], state) + + function! s:close_cb(ch) dict abort + let self.closed = 1 + + if self.exited + let l:job = ch_getjob(a:ch) + call self.complete(l:job, self.exit_status, self.messages) + endif + endfunction + let callbacks.close_cb = function('s:close_cb', [], state) + + return callbacks +endfunction + +function! s:start_job(cmd, options) abort + let l:options = copy(a:options) + + " Verify that the working directory for the job actually exists. Return + " early if the directory does not exist. This helps avoid errors when + " working with plugins that use virtual files that don't actually exist on + " the file system. + if !isdirectory(l:options.cwd) + return + endif + + return job_start(a:cmd, l:options) +endfunction + +function! s:autowrite() abort + if &autowrite == 1 || &autowriteall == 1 + silent! wall + else + for l:nr in range(0, bufnr('$')) + if buflisted(l:nr) && getbufvar(l:nr, '&modified') + " Sleep one second to make sure people see the message. Otherwise it is + " often immediacy overwritten by the async messages (which also don't + " invoke the "hit ENTER" prompt). + call swift#echo#EchoWarning('[No write since last change]') + sleep 1 + return + endif + endfor + endif +endfunction + +" vim: sw=2 ts=2 et diff --git a/autoload/swift/list.vim b/autoload/swift/list.vim new file mode 100644 index 0000000..e8e1441 --- /dev/null +++ b/autoload/swift/list.vim @@ -0,0 +1,152 @@ +" Vim autoload file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Functions to interact with locationlist and quickfix list. + +" Source code modified from original file: +" https://github.com/fatih/vim-go/blob/dee5fe4f65ea8d7bdd2ff87a1675743f91bdd297/autoload/go/list.vim +" +" Copyright (c) 2015, Fatih Arslan +" All rights reserved. +" +" Redistribution and use in source and binary forms, with or without +" modification, are permitted provided that the following conditions are met: +" +" * Redistributions of source code must retain the above copyright notice, this +" list of conditions and the following disclaimer. +" +" * Redistributions in binary form must reproduce the above copyright notice, +" this list of conditions and the following disclaimer in the documentation +" and/or other materials provided with the distribution. +" +" * Neither the name of vim-go nor the names of its +" contributors may be used to endorse or promote products derived from +" this software without specific prior written permission. +" +" THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" +" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +" IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +" DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE +" FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL +" DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR +" SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER +" CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, +" OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +" OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +if !exists("g:swift_list_autoclose") + let g:swift_list_autoclose = 1 +endif + +if !exists("g:swift_list_height") + let g:swift_list_height = 0 +endif + +if !exists("g:swift_list_type_commands") + let g:swift_list_type_commands = {} +endif + +if !exists("g:swift_list_type") + let g:swift_list_type = "" +endif + +function! swift#list#Window(list_type, list_height, ...) abort + if a:list_height == 0 + call s:close_list(a:list_type) + return + endif + + let l:height = g:swift_list_height + if l:height == 0 + if a:list_height > 10 + let l:height = 10 + else + let l:height = a:list_height + endif + endif + + if a:list_type ==# "locationlist" + exe 'lopen ' . height + else + exe 'copen ' . height + endif +endfunction + +function! swift#list#Get(list_type) abort + if a:list_type ==# "locationlist" + return getloclist(0) + else + return getqflist() + endif +endfunction + +function! swift#list#ParseFormat(list_type, format, items, title) abort + let old_errorformat = &errorformat + let &errorformat = a:format + + try + if a:list_type ==# "locationlist" + lgetexpr a:items + call setloclist(0, [], 'a', { 'title': a:title }) + else + cgetexpr a:items + call setqflist([], 'a', { 'title': a:title }) + endif + finally + let &errorformat = old_errorformat + endtry +endfunction + +function! swift#list#JumpToFirst(list_type) abort + if a:list_type ==# "locationlist" + ll 1 + else + cc 1 + endif +endfunction + +" Clean cleans and closes the location list +function! swift#list#Clean(list_type) abort + if a:list_type ==# "locationlist" + lex [] + else + cex [] + endif + + call s:close_list(a:list_type) +endfunction + +function! s:close_list(list_type) abort + if !g:swift_list_autoclose + return + endif + + if a:list_type ==# "locationlist" + lclose + else + cclose + endif +endfunction + +let s:default_list_type_commands = { + \ "SwiftBuild": "quickfix", + \ "SwiftFormat": "locationlist", + \ "SwiftLint": "quickfix", + \ "SwiftLintAutoSave": "locationlist", + \ "SwiftTest": "quickfix", + \ "_job": "locationlist", + \ } + +function! swift#list#Type(for) abort + if !empty(g:swift_list_type) + return g:swift_list_type + endif + + let l:list_type = get(g:swift_list_type_commands, a:for) + if l:list_type ==# "0" + return get(s:default_list_type_commands, a:for, "quickfix") + endif + return l:list_type +endfunction + +" vim: sw=2 ts=2 et diff --git a/autoload/swift/spm.vim b/autoload/swift/spm.vim new file mode 100644 index 0000000..70777c9 --- /dev/null +++ b/autoload/swift/spm.vim @@ -0,0 +1,125 @@ +" Vim autoload file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Functions related to running Swift Package Manager. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if !exists("g:swift_compiler_spm_path") + let g:swift_compiler_spm_path = "swift" +endif + +function! swift#spm#Build(...) abort + let l:opts = (a:0 > 0) ? copy(a:1) : {} + + let l:filename = expand('%') + if expand('%:p') =~# '.*Tests.*' + if !has_key(l:opts, 'only_compile') + let l:opts.only_compile = 1 + endif + + let l:args = [l:opts] + call extend(l:args, a:000[1:]) + + call call('swift#spm#Test', l:args) + elseif l:filename =~# '^\f\+\.swift$' + let l:args = [l:opts] + call extend(l:args, a:000[1:]) + + call call('swift#spm#SourceBuild', l:args) + endif +endfunction + +function! swift#spm#SourceBuild(...) abort + let l:opts = (a:0 > 0) ? copy(a:1) : {} + let l:jump_to_error = has_key(l:opts, 'jump_to_error') ? l:opts.jump_to_error + \ : g:swift_jump_to_error + + let l:args = ['build'] + map(copy(a:000[1:]), "expand(v:val)") + + let l:list_title = "SwiftBuild" + let l:list_type = swift#list#Type(l:list_title) + call swift#job#Spawn({ + \ 'cmd': [g:swift_compiler_spm_path] + l:args, + \ 'jump_to_error': l:jump_to_error, + \ 'list_title': l:list_title, + \ 'list_type': l:list_type, + \ 'status_type': 'build', + \ 'job_dir': swift#spm#FindPackageSwiftDir(), + \}) +endfunction + +function! swift#spm#Test(...) abort + let l:opts = (a:0 > 0) ? copy(a:1) : {} + let l:jump_to_error = has_key(l:opts, 'jump_to_error') ? l:opts.jump_to_error + \ : g:swift_jump_to_error + let l:only_compile = has_key(l:opts, 'only_compile') ? l:opts.only_compile : 0 + + if l:only_compile == 1 + let l:args = ["build", "--build-tests"] + else + let l:args = ["test"] + endif + + call extend(l:args, map(copy(a:000[1:]), "expand(v:val)")) + + let l:format=",%E%f:%l:%c: error: %m" + let l:format.=",%W%f:%l:%c: warning: %m" + let l:format.=",%E%f:%l: error: %.%# : %m" + let l:format.=",%W%f:%l: warning: %.%# : %m" + let l:format.=",%-G%.%#" + + let l:list_title = "SwiftTest" + let l:list_type = swift#list#Type(l:list_title) + call swift#job#Spawn({ + \ 'cmd': [g:swift_compiler_spm_path] + l:args, + \ 'jump_to_error': l:jump_to_error, + \ 'list_title': l:list_title, + \ 'list_type': l:list_type, + \ 'status_type': l:only_compile ? 'compile test' : 'test', + \ 'errorformat': l:format, + \ 'job_dir': swift#spm#FindPackageSwiftDir(), + \ }) +endfunction + +function! swift#spm#TestFunctionOnly(opts, ...) abort + let l:opts = (a:0 > 0) ? copy(a:1) : {} + + let l:line_number = search('func\s\+\(test\)', "bcnW") + + if l:line_number == 0 + call swift#echo#EchoWarning('[test] No test found immediately before cursor.') + return + endif + + let l:line_contents = getline(l:line_number) + let l:test_name = split(split(l:line_contents, " ")[1], "(")[0] + + let l:args = [l:opts, "--filter", l:test_name] + + call extend(l:args, a:000[1:]) + + call call('swift#spm#Test', l:args) +endfunction + +function! swift#spm#FindPackageSwiftDir() abort + let l:package_swift = findfile("Package.swift", expand('%:p:h') . ";") + if empty(l:package_swift) + return "" + endif + return fnamemodify(l:package_swift, ':p:h') +endfunction + +" vim: sw=2 ts=2 et diff --git a/autoload/swift/swiftformat.vim b/autoload/swift/swiftformat.vim new file mode 100644 index 0000000..6c43426 --- /dev/null +++ b/autoload/swift/swiftformat.vim @@ -0,0 +1,168 @@ +" Vim autoload file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Functions related to running SwiftFormat. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if !exists("g:swift_swiftformat_path") + let g:swift_swiftformat_path = "swiftformat" +endif + +if !exists("g:swift_swiftformat_autosave") + let g:swift_swiftformat_autosave = 0 +endif + +if !exists("g:swift_swiftformat_config_file_path") + let g:swift_swiftformat_config_file_path = "" +endif + +if !exists("g:swift_swiftformat_config_file_name") + let g:swift_swiftformat_config_file_name = ".swiftformat" +endif + +if !exists("g:swift_swiftformat_config_file_search_parent_dir") + let g:swift_swiftformat_config_file_search_parent_dir = 1 +endif + +if !exists("g:swift_swiftformat_fail_silently") + let g:swift_swiftformat_fail_silently = 0 +endif + +if !exists("g:swift_swiftformat_options") + let g:swift_swiftformat_options = [] +endif + +function! swift#swiftformat#Format(...) abort + let l:opts = (a:0 > 0) ? copy(a:1) : {} + let l:jump_to_error = has_key(l:opts, 'jump_to_error') ? l:opts.jump_to_error + \ : g:swift_jump_to_error + + mkview! + + let current_col = col('.') + let diff_offset = 0 + + let l:winid = win_getid(winnr()) + + let l:output_tmpname = tempname() + let l:stderr_tmpname = tempname() + + let l:command = s:format_cmd(g:swift_swiftformat_path, l:output_tmpname) + call extend(l:command, map(copy(a:000[1:]), "expand(v:val)")) + call extend(l:command, [' 2> ', l:stderr_tmpname]) + + let l:buffer = getline(1, '$') + silent let out = systemlist(join(l:command, " "), l:buffer) + + let l:stderr = readfile(l:stderr_tmpname) + call delete(l:stderr_tmpname) + + let l:list_type = swift#list#Type("SwiftFormat") + + if v:shell_error == 0 + try | silent undojoin | catch | endtry + + let l:content = readfile(l:output_tmpname) + let diff_offset = len(l:content) - line('$') + + silent! execute '%!cat ' . l:output_tmpname + + if l:list_type ==# "quickfix" + let l:list_title = getqflist({'title': 1}) + else + let l:list_title = getloclist(0, {'title': 1}) + endif + if has_key(l:list_title, "title") && l:list_title['title'] ==# "Format" + call swift#list#Clean(l:list_type) + endif + + silent! loadview + + call cursor(line('.') + diff_offset, current_col) + elseif !g:swift_swiftformat_fail_silently + " Add 1 to the column value of the SwiftFormat error output. + let l:stderr = map(copy(l:stderr), 'substitute(v:val, "\\(.* at \\d\\+:\\)\\(\\d\\+\\)", "\\=(submatch(1)) . (submatch(2) + 1)", "g")') + " Hack in the filename to the beginning of the error output. + let l:stderr = map(copy(l:stderr), "'" . expand('%') . ":'" . ' . v:val') + + let l:format="%E%f:error: %m at %l:%c" + let l:format.=",%W%f:warning: %m at %l:%c" + let l:format.=",%E%f:error: %m" + let l:format.=",%W%f:warning: %m" + let l:format.=",%-G%.%#" + + call swift#list#ParseFormat(l:list_type, l:format, l:stderr, 'Format') + let errors = swift#list#Get(l:list_type) + if empty(errors) + call swift#echo#EchoError(l:stderr) + silent! loadview + else + call swift#list#Window(l:list_type, len(errors)) + call win_gotoid(l:winid) + silent! loadview + if l:jump_to_error + call swift#list#JumpToFirst(l:list_type) + else + call win_gotoid(l:winid) + endif + endif + else + silent! loadview + endif + + call delete(l:output_tmpname) +endfunction + +function! swift#swiftformat#PreWrite() abort + if get(g:, "swift_swiftformat_autosave", 0) + call swift#swiftformat#Format({}) + endif +endfunction + +function! s:format_cmd(bin_name, target) abort + let l:cmd = [a:bin_name] + + let l:config_file = s:find_config() + if !empty(l:config_file) + call extend(l:cmd, ["--config", l:config_file]) + endif + + call extend(l:cmd, g:swift_swiftformat_options) + + if !empty(a:target) + call extend(l:cmd, ["--output", a:target]) + endif + + return l:cmd +endfunction + +function! s:find_config() abort + if !empty(g:swift_swiftformat_config_file_path) + return g:swift_swiftformat_config_file_path + endif + + if !g:swift_swiftformat_config_file_search_parent_dir + return "" + endif + + let l:format_config = findfile(g:swift_swiftformat_config_file_name, expand('%:p:h') . ";") + if empty(l:format_config) + return "" + endif + return fnamemodify(l:format_config, ':p') +endfunction + +" vim: sw=2 ts=2 et diff --git a/autoload/swift/swiftlint.vim b/autoload/swift/swiftlint.vim new file mode 100644 index 0000000..5b7f9c6 --- /dev/null +++ b/autoload/swift/swiftlint.vim @@ -0,0 +1,119 @@ +" Vim autoload file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Functions related to running SwiftLint. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if !exists("g:swift_swiftlint_path") + let g:swift_swiftlint_path = "swiftlint" +endif + +if !exists("g:swift_swiftlint_autosave") + let g:swift_swiftlint_autosave = 0 +endif + +if !exists("g:swift_swiftlint_config_file_path") + let g:swift_swiftlint_config_file_path = "" +endif + +if !exists("g:swift_swiftlint_config_file_name") + let g:swift_swiftlint_config_file_name = ".swiftlint.yml" +endif + +if !exists("g:swift_swiftlint_config_file_search_parent_dir") + let g:swift_swiftlint_config_file_search_parent_dir = 1 +endif + +if !exists("g:swift_swiftlint_options") + let g:swift_swiftlint_options = [] +endif + +if !exists("g:swift_swiftlint_from_package") + let g:swift_swiftlint_from_package = 0 +endif + +function! swift#swiftlint#Lint(...) abort + let l:opts = (a:0 > 0) ? copy(a:1) : {} + let l:jump_to_error = has_key(l:opts, 'jump_to_error') ? l:opts.jump_to_error + \ : g:swift_jump_to_error + let l:autosave = has_key(l:opts, 'autosave') ? l:opts.autosave : 0 + + let l:args = [] + + if g:swift_swiftlint_from_package + let l:job_dir = swift#spm#FindPackageSwiftDir() + else + let l:config_file = s:find_config() + let l:job_dir = fnamemodify(l:config_file, ':h') + if !empty(l:config_file) + call extend(l:args, ["--config", l:config_file]) + endif + endif + + call extend(l:args, g:swift_swiftlint_options) + + if !g:swift_swiftlint_from_package + call extend(l:args, ["--path", expand('%:p')]) + endif + + call extend(l:args, map(copy(a:000[1:]), "expand(v:val)")) + + if l:autosave + redraw + endif + + let l:format=",%E%f:%l:%c: error: %m" + let l:format.=",%W%f:%l:%c: warning: %m" + let l:format.=",%E%f:%l: error: %m" + let l:format.=",%W%f:%l: warning: %m" + let l:format.=",%-G%.%#" + + let l:list_title = l:autosave ? "SwiftLintAutoSave" : "SwiftLint" + let l:list_type = swift#list#Type(l:list_title) + call swift#job#Spawn({ + \ 'cmd' : [g:swift_swiftlint_path] + l:args, + \ 'jump_to_error': l:jump_to_error, + \ 'list_title': l:list_title, + \ 'list_type': l:list_type, + \ 'status_type': "swiftlint", + \ 'errorformat': l:format, + \ 'job_dir': l:job_dir, + \ }) +endfunction + +function! swift#swiftlint#PostWrite() abort + if get(g:, "swift_swiftlint_autosave", 0) + call swift#swiftlint#Lint({ "autosave": 1 }) + endif +endfunction + +function! s:find_config() abort + if !empty(g:swift_swiftlint_config_file_path) + return g:swift_swiftlint_config_file_path + endif + + if !g:swift_swiftlint_config_file_search_parent_dir + return "" + endif + + let l:lint_config = findfile(g:swift_swiftlint_config_file_name, expand('%:p:h') . ";") + if empty(l:lint_config) + return "" + endif + return fnamemodify(l:lint_config, ':p') +endfunction + +" vim: sw=2 ts=2 et diff --git a/compiler/spm.vim b/compiler/spm.vim new file mode 100644 index 0000000..cec7c95 --- /dev/null +++ b/compiler/spm.vim @@ -0,0 +1,57 @@ +" Vim compiler file +" Language: Swift +" Compiler: Swift Package Manager package compiler. +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Swift Package Manager package compiler options and errorformat. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if exists("current_compiler") + finish +endif +let current_compiler = "spm" + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal <args> +endif + +if !exists("g:swift_compiler_spm_path") + let g:swift_compiler_spm_path = "swift" +endif + +if !exists("g:swift_compiler_spm_options") + let g:swift_compiler_spm_options = "build" +endif + +let s:save_cpoptions = &cpoptions +set cpoptions-=C + +execute 'CompilerSet makeprg=' + \ . escape(g:swift_compiler_spm_path, ' ') + \ . '\ ' + \ . escape(g:swift_compiler_spm_options, ' \|"') + \ . '\ $*' + +CompilerSet errorformat= + \%E%f:%l:%c:\ error:\ %m, + \%W%f:%l:%c:\ warning:\ %m, + \%E%f:%l:\ error:\ %m, + \%W%f:%l:\ warning:\ %m, + \%-G%.%# + +let &cpoptions = s:save_cpoptions +unlet s:save_cpoptions + +" vim: sw=2 ts=2 et diff --git a/compiler/swiftc.vim b/compiler/swiftc.vim new file mode 100644 index 0000000..d1b0f02 --- /dev/null +++ b/compiler/swiftc.vim @@ -0,0 +1,68 @@ +" Vim compiler file +" Language: Swift +" Compiler: Swiftc Compiler +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Swiftc compiler options and errorformat. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if exists("current_compiler") + finish +endif +let current_compiler = "swiftc" + +if exists(":CompilerSet") != 2 + command -nargs=* CompilerSet setlocal <args> +endif + +if !exists("g:swift_compiler_swiftc_path") + let g:swift_compiler_swiftc_path = "swiftc" +endif + +if !exists("g:swift_compiler_swiftc_options") + let g:swift_compiler_swiftc_options = "" +endif + +if !exists("g:swift_compiler_swiftc_makeprg_no_percent") + let g:swift_compiler_swiftc_makeprg_no_percent = 0 +endif + +let s:save_cpoptions = &cpoptions +set cpoptions-=C + +if g:swift_compiler_swiftc_makeprg_no_percent + execute 'CompilerSet makeprg=' + \ . escape(g:swift_compiler_swiftc_path, ' ') + \ . '\ ' + \ . escape(g:swift_compiler_swiftc_options, ' ') +else + execute 'CompilerSet makeprg=' + \ . escape(g:swift_compiler_swiftc_path, ' ') + \ . '\ ' + \ . escape(g:swift_compiler_swiftc_options, ' ') + \ . '\ $*\ %' +endif + +CompilerSet errorformat= + \%E%f:%l:%c:\ error:\ %m, + \%W%f:%l:%c:\ warning:\ %m, + \%E%f:%l:\ error:\ %m, + \%W%f:%l:\ warning:\ %m, + \%-G%.%# + +let &cpoptions = s:save_cpoptions +unlet s:save_cpoptions + +" vim: sw=2 ts=2 et diff --git a/doc/swifty-vim.txt b/doc/swifty-vim.txt new file mode 100644 index 0000000..73562f7 --- /dev/null +++ b/doc/swifty-vim.txt @@ -0,0 +1,277 @@ +*swifty-vim.txt* Swift development plugin +*swifty-vim* + +============================================================================== +CONTENTS *swift-contents* + +1. Introduction |swift-intro| +2. Settings |swift-settings| +3. Commands |swift-commands| +4. Mappings |swift-mappings| + +============================================================================== +INTRODUCTION *swift-intro* + +A Vim plugin for the Swift programming language. It provides file detection, +syntax highlighting, support for compiling and running tests, and optional +support for formatting and linting tools. + +============================================================================== +SETTINGS *swift-settings* + +You can change the settings in your vimrc. + *g:swift_compiler_spm_path* +g:swift_compiler_spm_path~ + Set this option to the path to swift. If unset, "swift" will be located + in the $PATH: > + + let g:swiftc_compiler_spm_path = "/usr/bin/swift" +< + *g:swift_compiler_spm_options* +g:swift_compiler_spm_options~ + Set this option to any swift compiler options. If unset, no extra options + will be passed to swift. Defaults to "build". > + + let g:swiftc_compiler_spm_options = "build" +< + *g:swift_compiler_swiftc_path* +g:swift_compiler_swiftc_path~ + Set this option to the path to swiftc. If unset, "swiftc" will be located + in the $PATH: > + + let g:swiftc_compiler_swiftc_path = "/usr/bin/swiftc" +< + *g:swift_compiler_swiftc_options* +g:swift_compiler_swiftc_options~ + Set this option to any swiftc compiler options. If unset, no extra options + will be passed to swiftc. > + + let g:swiftc_compiler_swiftc_options = "-D DEBUG" +< + *g:swift_compiler_swiftc_makeprog_no_percent* +g:swift_compiler_swiftc_makeprog_no_percent~ + Set this option to 1 to not include the file name when calling "swiftc". > + + let g:swift_compiler_swiftc_makeprog_no_percent = 1 +< + + *g:swift_jump_to_error* +g:swift_jump_to_error~ + Set this option to 0 to not immediately jump to the first error in a list. > + + let g:swift_jump_to_error = 0 +< + + *g:swift_list_autoclose* +g:swift_list_autoclose~ + Set this option to 0 to not automatically close a list if there are no + errors. > + + let g:swift_list_autoclose = 0 +< + + *g:swift_list_height* +g:swift_list_height~ + Set this option to the exact height which lists should be opened with. + Unset or set to 0 to allow lists to be automatically sized. > + + let g:swift_list_height = 5 +< + *g:swift_list_type* +g:swift_list_type~ + Set this option to always use a specific list type when parsing messages. > + + let g:swift_list_type = "locationlist" +< + *g:swift_list_type_commands* +g:swift_list_type_commands~ + Set this option to a dictionary where the key is the list type and the + value is the type of list to use. > + + let g:swift_list_type_commands = { "SwiftBuild": "locationlist" } +< + *g:swift_version_check* +g:swift_version_check~ + Set this option to 0 to not check for the version of Vim being used. > + + let g:swift_version_check = 0 +< + +Integration with SwiftFormat *swift-swiftformat* +---------------------------- + +This plugin can use SwiftFormat to format code. SwiftFormat must be installed +separately. + + *g:swift_swiftformat_autosave* +g:swift_swiftformat_autosave~ + Set this option to 1 to automatically invoke SwiftFormat when saving. > + + let g:swift_swiftformat_autosave = 0 +< + *g:swift_swiftformat_config_file_path* +g:swift_swiftformat_config_file_path~ + Set this option to a global SwiftFormat file path which will always + be used. > + + let g:swift_swiftformat_config_file_path = + \ $HOME . "/.swiftformat" +< + *g:swift_swiftformat_config_file_name* +g:swift_swiftformat_config_file_name~ + Set this option to the name of the SwiftFormat config to search for. + Defaults to ".swiftformat". > + + let g:swift_swiftformat_config_file_name = ".swiftformat" +< + + *g:swift_swiftformat_config_file_search_parent_dir* +g:swift_swiftformat_config_file_search_parent_dir~ + Set this option to 1 to find the |g:swift_swiftformat_config_file_name| in + the current or parent directories. Defaults to 1. > + + let g:swift_swiftformat_config_file_search_parent_dir = 0 +< + *g:swift_swiftformat_fail_silently* +g:swift_swiftformat_fail_silently~ + Set this option to 1 to let SwiftFormat fail silently. > + + let g:swift_swiftformat_fail_silently = 1 +< + *g:swift_swiftformat_options* +g:swift_swiftformat_options~ + Set this option to a list of any SwiftFormat options to use. > + + let g:swift_swiftformat_options = ["--enable", "trailingCommas"] +< + *g:swift_swiftformat_path* +g:swift_swiftformat_path~ + Set this option to the specific SwiftFormat path to use. > + + let g:swift_swiftformat_path = "/usr/local/bin/swiftformat" +< + +Integration with SwiftLint *swift-swiftlint* +---------------------------- + +This plugin can use SwiftLint to lint code. SwiftLint must be installed +separately. + + *g:swift_swiftlint_autosave* +g:swift_swiftlint_autosave~ + Set this option to 1 to automatically invoke SwiftLint when saving. > + + let g:swift_swiftlint_autosave = 1 +< + *g:swift_swiftlint_config_file_path* +g:swift_swiftlint_config_file_path~ + Set this option to a global SwiftLint file path which will always + be used. > + + let g:swift_swiftlint_config_file_path = $HOME . "/swiftlint.yml" +< + *g:swift_swiftlint_config_file_name* +g:swift_swiftlint_config_file_name~ + Set this option to the name of the SwiftLint config to search for. + Defaults to ".swiftlint.yml". > + + let g:swift_swiftlint_config_file_name = ".swiftlint.yml" +< + *g:swift_swiftlint_config_file_search_parent_dir* +g:swift_swiftlint_config_file_search_parent_dir~ + Set this option to 1 to find the |g:swift_swiftlint_config_file_name| in + the current or parent directories. Defaults to 1. > + + let g:swift_swiftlint_config_file_search_parent_dir = 0 +< + *g:swift_swiftlint_from_package* +g:swift_swiftlint_from_package~ + Set this option to 1 to run against the entire Swift Package instead of a + single file. > + + let g:swift_swiftlint_from_package = 1 +< + *g:swift_swiftlint_options* +g:swift_swiftlint_options~ + Set this option to a list of any SwiftLint options to use. > + + let g:swift_swiftlint_options = ["--enable", "trailingCommas"] +< + *g:swift_swiftlint_path* +g:swift_swiftlint_path~ + Set this option to the specific SwiftLint path to use. > + + let g:swift_swiftlint_path = "/usr/local/bin/swiftlint" +< + +============================================================================== +COMMANDS *swift-commands* + +Swift Package Manager +--------------------- + +Convenience commands for working with Swift Package Manager packages. + +:SwiftPMBuild <args> *:SwiftPMBuild* + Runs 'swift build' or 'swift build --build-tests' (depending + on the file) with the provided arguments. + +:SwiftPMSourceBuild <args> *:SwiftPMSourceBuild* + Runs 'swift build' with the provided arguments. + +:SwiftPMTest <args> *:SwiftPMTest* + Runs 'swift test' with the provided arguments. + +:SwiftPMTestBuild <args> *:SwiftPMTestBuild* + Runs 'swift build --build-tests' with the provided arguments. + +:SwiftPMTestFunctionOnly <args> *:SwiftPMTestFunctionOnly* + Runs 'swift test --filter <current test func>' with the + provided arguments. + +Formatting +---------- + +:SwiftFormat *:SwiftFormat* + Runs |g:swift_swiftformat_path| on the current buffer. If + |g:swift_swiftformat_options| is set, then the options will + be used. + + If |g:swift_swiftformat_fail_silently| is 0 (the default), + then a list will be populated with any errors. + If |g:swift_swiftformat_fail_silently| is set to 1, + then it will not populate any list with any errors. + + +Linting +------------------- + +:SwiftLint *:SwiftLint* + Runs |g:swift_swiftlint_path| on the current buffer. + +============================================================================== +MAPPINGS *swift-mappings* + +There are <Plug> keys defined which can be mapped to with custom key bindings. +You can map to a <Plug> key by doing the following: + + autocmd FileType swift nmap <leader>t <Plug>(swift-spm-test) + + + *(swift-spm-build)* +Builds the current Swift Package with `swift build`. + + *(swift-spm-test)* +Tests the current Swift Package with `swift test`. + + *(swift-spm-test-function-only)* +Tests the current test function with `swift test`. + + *(swift-swiftformat)* +Runs `swiftformat` on the current buffer. + + *(swift-swiftlint)* +Runs `swiftlint` on the current buffer. + +============================================================================== + vim:tw=78:sw=4:noet:ts=8:ft=help:norl: diff --git a/ftdetect/sil.vim b/ftdetect/sil.vim index 0515f35..05a20d6 100644 --- a/ftdetect/sil.vim +++ b/ftdetect/sil.vim @@ -1,3 +1,11 @@ +" Vim ftdetect file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Detects sil files. + +" Source code modified from original file: +" https://github.com/apple/swift/blob/d128dad3ff1ca24f7a7ca4f0c6c8203b3b87982c/utils/vim/ftdetect/sil.vim +" " This source file was originally part of the Swift.org open source project " " Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors @@ -6,7 +14,8 @@ " See https://swift.org/LICENSE.txt for license information " See https://swift.org/CONTRIBUTORS.txt for the list of Swift project " authors -" -" Original file: -" https://github.com/apple/swift/blob/d128dad3ff1ca24f7a7ca4f0c6c8203b3b87982c/utils/vim/ftdetect/sil.vim + +" vint: -ProhibitAutocmdWithNoGroup autocmd BufNewFile,BufRead *.sil set filetype=sil + +" vim: sw=2 ts=2 et diff --git a/ftdetect/swift.vim b/ftdetect/swift.vim index 06b123f..e719998 100644 --- a/ftdetect/swift.vim +++ b/ftdetect/swift.vim @@ -1,3 +1,11 @@ +" Vim ftdetect file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Detects Swift files. + +" Source code modified from original file: +" https://github.com/apple/swift/blob/11874988289e2afb443a156dae45aedb3f5fd1b7/utils/vim/ftdetect/swift.vim +" " This source file was originally part of the Swift.org open source project " " Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors @@ -6,7 +14,8 @@ " See https://swift.org/LICENSE.txt for license information " See https://swift.org/CONTRIBUTORS.txt for the list of Swift project " authors -" -" Original file: -" https://github.com/apple/swift/blob/11874988289e2afb443a156dae45aedb3f5fd1b7/utils/vim/ftdetect/swift.vim + +" vint: -ProhibitAutocmdWithNoGroup autocmd BufNewFile,BufRead *.swift set filetype=swift + +" vim: sw=2 ts=2 et diff --git a/ftdetect/swiftgyb.vim b/ftdetect/swiftgyb.vim index 4b5de31..3fd4fc7 100644 --- a/ftdetect/swiftgyb.vim +++ b/ftdetect/swiftgyb.vim @@ -1,3 +1,11 @@ +" Vim ftdetect file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Detects gyb on Swift files. + +" Source code modified from original file: +" https://github.com/apple/swift/blob/6044c97318f768a3971198545e8b6e7e6dd80d0c/utils/vim/ftdetect/swiftgyb.vim +" " This source file was originally part of the Swift.org open source project " " Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors @@ -6,7 +14,8 @@ " See https://swift.org/LICENSE.txt for license information " See https://swift.org/CONTRIBUTORS.txt for the list of Swift project " authors -" -" Original file: -" https://github.com/apple/swift/blob/6044c97318f768a3971198545e8b6e7e6dd80d0c/utils/vim/ftdetect/swiftgyb.vim + +" vint: -ProhibitAutocmdWithNoGroup autocmd BufNewFile,BufRead *.swift.gyb set filetype=swiftgyb + +" vim: sw=2 ts=2 et diff --git a/ftplugin/swift.vim b/ftplugin/swift.vim index 755d364..380006e 100644 --- a/ftplugin/swift.vim +++ b/ftplugin/swift.vim @@ -1,5 +1,42 @@ +" Vim ftplugin file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Filetype plugin settings for Swift. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if exists("b:did_ftplugin") + finish +endif +let b:did_ftplugin = 1 + +if !exists("g:swift_jump_to_error") + let g:swift_jump_to_error = 1 +endif + setlocal comments=s1:/*,mb:*,ex:*/,:///,:// -setlocal smartindent -setlocal expandtab -setlocal ts=4 -setlocal sw=4 +setlocal commentstring=//\ %s + +augroup swiftyvim + autocmd! + + if strlen(findfile("Package.swift", expand('%:p:h') . ";")) > 0 + compiler spm + else + compiler swiftc + endif +augroup end + +" vim: sw=2 ts=2 et diff --git a/ftplugin/swift/commands.vim b/ftplugin/swift/commands.vim new file mode 100644 index 0000000..d5cd3c2 --- /dev/null +++ b/ftplugin/swift/commands.vim @@ -0,0 +1,33 @@ +" Vim ftplugin file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Filetype plugin settings for swifty-vim commands. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +" -- swift package manager +command! -nargs=* SwiftPMBuild call swift#spm#Build({}, <f-args>) +command! -nargs=* SwiftPMSourceBuild call swift#spm#SourceBuild({}, <f-args>) +command! -nargs=* SwiftPMTest call swift#spm#Test({}, <f-args>) +command! -nargs=* SwiftPMTestBuild call swift#spm#Test({ "only_compile": 1 }, <f-args>) +command! -nargs=* SwiftPMTestFunctionOnly call swift#spm#TestFunctionOnly({}, <f-args>) + +" -- swiftformat +command! -nargs=* SwiftFormat call swift#swiftformat#Format({}, <f-args>) + +" -- swiftlint +command! -nargs=* SwiftLint call swift#swiftlint#Lint({}, <f-args>) + +" vim: sw=2 ts=2 et diff --git a/ftplugin/swift/mappings.vim b/ftplugin/swift/mappings.vim new file mode 100644 index 0000000..dd441e2 --- /dev/null +++ b/ftplugin/swift/mappings.vim @@ -0,0 +1,27 @@ +" Vim ftplugin file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Filetype plugin settings for swifty-vim mappings. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +nnoremap <silent> <Plug>(swift-spm-build) :<C-u>call swift#spm#Build({})<CR> +nnoremap <silent> <Plug>(swift-spm-test) :<C-u>call swift#spm#Test({})<CR> +nnoremap <silent> <Plug>(swift-spm-test-function-only) :<C-u>call swift#spm#TestFunctionOnly({})<CR> + +nnoremap <silent> <Plug>(swift-swiftformat) :<C-u>call swift#swiftformat#Format({})<CR> +nnoremap <silent> <Plug>(swift-swiftlint) :<C-u>call swift#swiftlint#Lint({})<CR> + +" vim: sw=2 ts=2 et diff --git a/plugin/swift.vim b/plugin/swift.vim new file mode 100644 index 0000000..a8a63f2 --- /dev/null +++ b/plugin/swift.vim @@ -0,0 +1,57 @@ +" Vim plugin file +" Language: Swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Plugin settings for swifty-vim. + +" Copyright 2018 Bryant Luk +" +" Licensed under the Apache License, Version 2.0 (the "License"); +" you may not use this file except in compliance with the License. +" You may obtain a copy of the License at +" +" http://www.apache.org/licenses/LICENSE-2.0 +" +" Unless required by applicable law or agreed to in writing, software +" distributed under the License is distributed on an "AS IS" BASIS, +" WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +" See the License for the specific language governing permissions and +" limitations under the License. + +if exists("g:swift_loaded") + finish +endif +let g:swift_loaded = 1 + +if !exists("g:swift_version_check") + let g:swift_version_check = 1 +endif + +function s:check_version() abort + if g:swift_version_check == 0 + return + endif + + let l:is_unsupported = (v:version < 800 || (v:version == 800 && !has("patch0902"))) + if l:is_unsupported == 1 + echohl Error + echom "swifty-vim requires Vim 8.0.0902, but it seems you are using an older version." + echom "Please upgrade Vim to use all of the features." + echom "" + echom "You can disable this message by setting:" + echom " let g:swift_version_check = 0" + echohl None + + sleep 2 + endif +endfunction + +call s:check_version() + +augroup swiftyvim.events + autocmd! + + autocmd BufWritePre *.swift call swift#swiftformat#PreWrite() + autocmd BufWritePost *.swift call swift#swiftlint#PostWrite() +augroup end + +" vim: sw=2 ts=2 et diff --git a/syntax/sil.vim b/syntax/sil.vim index 53b043a..79ceb3a 100644 --- a/syntax/sil.vim +++ b/syntax/sil.vim @@ -1,5 +1,10 @@ " Vim syntax file " Language: sil +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Syntax file for sil. + +" Source code modified from original file: +" https://github.com/apple/swift/blob/73df12c09f052f34985b62834f8f0fd2de4c8f10/utils/vim/syntax/sil.vim " " This source file was originally part of the Swift.org open source project " @@ -9,9 +14,6 @@ " See https://swift.org/LICENSE.txt for license information " See https://swift.org/CONTRIBUTORS.txt for the list of Swift project " authors -" -" Original file: -" https://github.com/apple/swift/blob/73df12c09f052f34985b62834f8f0fd2de4c8f10/utils/vim/syntax/sil.vim if exists("b:current_syntax") finish @@ -170,3 +172,5 @@ hi def link silMetatypeType Special hi def link silAttribute PreProc let b:current_syntax = "sil" + +" vim: sw=2 ts=2 et diff --git a/syntax/swift.vim b/syntax/swift.vim index 99a7a82..32df060 100644 --- a/syntax/swift.vim +++ b/syntax/swift.vim @@ -1,6 +1,11 @@ " Vim syntax file " Language: swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Syntax file for Swift. +" Source code modified from original file: +" https://github.com/apple/swift/blob/ea2c860ddb4817dc83c7152035aa05569f3a2770/utils/vim/syntax/swift.vim +" " This source file was originally part of the Swift.org open source project " " Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors @@ -9,9 +14,6 @@ " See https://swift.org/LICENSE.txt for license information " See https://swift.org/CONTRIBUTORS.txt for the list of Swift project " authors -" -" Original file: -" https://github.com/apple/swift/blob/ea2c860ddb4817dc83c7152035aa05569f3a2770/utils/vim/syntax/swift.vim if exists("b:current_syntax") finish @@ -168,7 +170,7 @@ syn match swiftHex /[+\-]\?\<0x[0-9A-Fa-f][0-9A-Fa-f_]*\(\([.][0-9A-Fa-f_]*\)\?[ syn match swiftOct /[+\-]\?\<0o[0-7][0-7_]*\>/ syn match swiftBin /[+\-]\?\<0b[01][01_]*\>/ -syn match swiftOperator +\.\@<!\.\.\.\@!\|[/=\-+*%<>!&|^~]\@<!\(/[/*]\@![/=\-+*%<>!&|^~]*\|*/\@![/=\-+*%<>!&|^~]*\|->\@![/=\-+*%<>!&|^~]*\|[=+%<>!&|^~][/=\-+*%<>!&|^~]*\)+ skipwhite skipempty nextgroup=swiftTypeParameters +syn match swiftOperator "+\.\@<!\.\.\.\@!\|[/=\-+*%<>!&|^~]\@<!\(/[/*]\@![/=\-+*%<>!&|^~]*\|*/\@![/=\-+*%<>!&|^~]*\|->\@![/=\-+*%<>!&|^~]*\|[=+%<>!&|^~][/=\-+*%<>!&|^~]*\)+" skipwhite skipempty nextgroup=swiftTypeParameters syn match swiftOperator "\.\.[<.]" skipwhite skipempty nextgroup=swiftTypeParameters syn match swiftChar /'\([^'\\]\|\\\(["'tnr0\\]\|x[0-9a-fA-F]\{2}\|u[0-9a-fA-F]\{4}\|U[0-9a-fA-F]\{8}\)\)'/ @@ -239,3 +241,5 @@ hi def link swiftNilOps Operator hi def link swiftScope PreProc let b:current_syntax = "swift" + +" vim: sw=2 ts=2 et diff --git a/syntax/swiftgyb.vim b/syntax/swiftgyb.vim index 6ef9618..a9d368f 100644 --- a/syntax/swiftgyb.vim +++ b/syntax/swiftgyb.vim @@ -1,6 +1,11 @@ " Vim syntax file " Language: gyb on swift +" Maintainer: Bryant Luk <code@bryantluk.com> +" Description: Syntax file for gyb on Swift. +" Source code modified from original file: +" https://github.com/apple/swift/blob/6044c97318f768a3971198545e8b6e7e6dd80d0c/utils/vim/syntax/swiftgyb.vim +" " This source file was originally part of the Swift.org open source project " " Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors @@ -9,9 +14,6 @@ " See https://swift.org/LICENSE.txt for license information " See https://swift.org/CONTRIBUTORS.txt for the list of Swift project " authors -" -" Original file: -" https://github.com/apple/swift/blob/6044c97318f768a3971198545e8b6e7e6dd80d0c/utils/vim/syntax/swiftgyb.vim runtime! syntax/swift.vim unlet b:current_syntax @@ -23,3 +25,5 @@ syn match gybPythonCode /\${[^}]*}/ hi def link gybPythonCode CursorLineNr let b:current_syntax = "swiftgyb" + +" vim: sw=2 ts=2 et