Random

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.

Vincent

  • Published on 2025-02-22

Tags