How To Write Swift with Nvim
As you may know, I use Nvim for a large part of my work on a daily basis. Recently, I have been involved in the
development of several iOS applications, and found myself stuck with Xcode. However, Nvim can be a relatively acceptable
alternative to work with. It’s lightweight, highly customizable, and works on multiple platforms.
By integrating the SourceKit-LSP
, you can unlock a lot of features like auto-completion, definitions, and diagnostics.
I’ll try to give you a heads-up on how to set up Nvim to write Swift.
Note: Be aware that Xcode is still required for some tasks. Apple has recently open-sourced the Swift build utilities used in Xcode, but it’s still not enough to remove Xcode from the equation entirely.
Prerequisites
Before diving into the configuration, ensure that you have everything installed:
- Nvim (preferably 0.9+)
- Swift Toolchain
- SourceKit-LSP
- A plugin manager for Nvim (e.g.
lazy.nvim
)
To verify that the Swift toolchain is installed and find its location, you can run this command: xcrun --find sourcekit-lsp``. If it’s not found, you can install it either with
brew install swift` or through
the swift.org website.
Configuring Nvim
I am assuming that you know how to install a plugin in Nvim, and write a configuration file. If not, feel free to watch this series of videos on YouTube.
To enable sourcekit-lsp
in Nvim, we’ll use nvim-lspconfig
. We’ll start by adding { "neovim/nvim-lspconfig" }
as a
plugin.
Once installed, we’ll add the following to the LSP configuration:
local lspconfig = require("lspconfig")
lspconfig.sourcekit.setup {
capabilities = {
workspace = {
didChangeWatchedFile = {
dynamicRegistration = true,
},
},
},
cmd = { "xcrun", "sourcekit-lsp" },
filetypes = { "swift", "objective-c", "objective-cpp" },
root_dir = function(filename, _)
local util = require "lspconfig.util"
or util.root_pattern("buildServer.json")(filename)
or util.root_pattern("*.xcodeproj", "*.xcworkspace")(filename)
or util.find_git_ancestor(filename)
or util.root_pattern("Package.swift)(filename)
end,
}
By restarting Nvim, you should now able to use LSP features for Swift.
If you have nvim-cmp
configured with nvim_lsp
as a source, you’ll also have auto-completion suggestions out of the
box.
In some cases, using xcrun sourcekit-lsp
as the command might be an issue. You’ll have to use the default toolchain
path from the Xcode.app
package instead.
cmd = {
"/Applications/Xcode.app/Contents/Developer/Toolchains/XcodeDefault.xctoolchain/usr/bin/sourcekit-lsp"
}
You can get this path directly from the xcrun --find sourcekit-lsp
command.
Binding Xcode
By default, SourceKit-LSP doesn’t understand Xcode projects, but the build system can be extended. To access some Xcode
features from the LSP, we’ll have to bind them. To achieve this, I’ll be using xcode-build-server
. You can dowload it
with brew install xcode-build-server
.
To use this LSP with SwiftUI for example, you’ll need to add a file buildServer.json
to your project. This file can be
generated with either one of the following commands:
xcode-build-server config -workspace *.xcworkspace -scheme <XXX>
xcode-build-server config -project *.xcodeproj -scheme <XXX>
You’ll have to identify the correct Scheme for your project, and use it. This command generates the buildServer.json
file that will allow SourceKit-LSP
to use more than just Swift.
Enhancing the Development Experience
Syntax Highlighting & Formatting
I am assuming that you already have nvim-treesitter
installed and configured. If so, you’ll just need to add Swift to
the list ensure_installed
and enabled highlighting.
To format Swift code automatically, you’ll need to install swiftformat
with brew install swiftformat
.
Then create an auto-command in Nvim:
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*.swift",
callback = function()
vim.cmd("%!swiftformat --stdin")
end,
})
Debugging and Additional Features
Enabling debugging capabilities can be trickier. You can use lldb
manually, or integrate dap.nvim
for a full
debugging experience.
To gain more features from Xcode, like previews and tests, you can also add another plugin called
wojciech-kulik/xcodebuild.nvim
.
I use the following configuration:
{
"wojciech-kulik/xcodebuild.nvim",
dependencies = {},
config = function()
local xcodebuild = require "xcodebuild"
xcodebuild.setup {
auto_open = false,
auto_close = false,
auto_preview = false,
auto_jump = false,
mode = "quickfix",
cycle_results = false,
}
end,
}
There are a lot of other tools that you can use to improve your experience when working with either Xcode or Swift on
Nvim. You could also add xcbeautify
to make Xcode outputs more readable. Feel free to explore.
Conclusion
With this setup, you’ll be able to use Nvim to write some Swift code. However, a lot of features are still missing and you will still need Xcode to do things like advanced debugging of your application.
I will probably write a post on a full Nvim configuration, and update this post to make sure that everything stays up-to-date in the future.