A comprehensive, dependency-free Neovim plugin for Swift development with integrated LLDB debugger, LSP, build tools, formatting, and more.
- Overview
- Key Features
- Requirements
- Quick Start
- Installation
- Configuration
- Features Guide
- Commands Reference
- Keybindings
- Workflows
- Troubleshooting
- FAQ
- Advanced Topics
swift.nvim is a complete Swift development environment for Neovim that requires zero external dependencies for debugging. Unlike other solutions, it integrates directly with LLDB (included with Swift toolchain), eliminating the need for nvim-dap and complex plugin setups.
- ✅ Direct LLDB Integration - No nvim-dap required
- ✅ Zero Debug Dependencies - Just Swift toolchain + Neovim
- ✅ Visual Debugging - Breakpoint indicators (●) and current line markers (➤)
- ✅ Test Support - Debug both executables and .xctest bundles
- ✅ All-in-One - LSP, formatter, linter, build system, and debugger in one plugin
This plugin follows these principles:
- Simplicity - Minimal configuration for maximum functionality
- Integration - Works seamlessly with existing Neovim plugins
- No Overhead - Only loads what you need
- Swift-First - Built specifically for Swift development
- Interactive debugging with breakpoints, stepping, and variable inspection
- No nvim-dap dependency - Direct LLDB integration
- Visual breakpoint indicators and current line highlighting
- Debug executables and test targets (.xctest bundles)
- Configurable debug output window (bottom, right, or floating)
- Custom LLDB command support
- Runs from project root with correct working directory
- Auto-detects Swift Package Manager (SPM) projects
- Auto-detects Xcode projects and workspaces
- Project-aware commands and features
- Automatic sourcekit-lsp configuration
- Works with nvim-lspconfig
- Code completion, go-to-definition, hover, and more
- Integration with nvim-cmp for enhanced completions
- List and select executable and test targets
- Display current target in statusline
- Auto-detect target types (executable, library, test)
- Build, run, and test Swift packages
- Live build output in separate window
- Support for debug and release configurations
- Clean build artifacts
- Support for swift-format (Apple's official formatter)
- Support for swiftformat (community formatter)
- Format entire files or selections
- Auto-format on save (optional)
- SwiftLint integration
- Auto-lint on save
- Quick fix support
- Configurable severity levels
- 50+ built-in Swift snippets
- Works with LuaSnip
- Categories: structures, functions, control flow, SwiftUI, testing
- Build Xcode projects with xcodebuild
- List and select schemes
- Open project in Xcode.app
- Validate Swift toolchain version
- Check .swift-version compatibility
- Validate formatter and tool versions
| Tool | Minimum Version | Purpose | Install |
|---|---|---|---|
| Neovim | >= 0.8.0 | Editor | neovim.io |
| Swift | Any version | Development & LLDB | See below |
| Tool | Purpose | Install |
|---|---|---|
| nvim-lspconfig | LSP auto-configuration | Plugin manager |
| nvim-cmp | Better completions | Plugin manager |
| LuaSnip | Snippets engine | Plugin manager |
| swift-format | Code formatting | brew install swift-format |
| swiftformat | Alternative formatter | brew install swiftformat |
| SwiftLint | Linting | brew install swiftlint |
| lualine.nvim | Statusline integration | Plugin manager |
# Option 1: Xcode (includes everything)
xcode-select --install
# Option 2: Swift toolchain only
# Download from: https://swift.org/download/
# Option 3: swiftly (version manager - recommended)
curl -L https://swift-server.github.io/swiftly/swiftly-install.sh | bash
swiftly install latest# Using swiftly (recommended)
curl -L https://swift-server.github.io/swiftly/swiftly-install.sh | bash
swiftly install latest
# Or download from: https://swift.org/download/swift --version # Swift compiler
lldb --version # Debugger (comes with Swift)
sourcekit-lsp --version # LSP (comes with Swift)Get up and running in 3 steps:
Using lazy.nvim:
-- ~/.config/nvim/lua/plugins/swift.lua
return {
"devswiftzone/swift.nvim",
ft = "swift",
opts = {}, -- Use defaults
}nvim # Plugin will auto-install on first Swift file:checkhealth swiftYou should see:
- ✓ LLDB found
- ✓ Swift debugging is configured
- ✓ Plugin loaded successfully
" 1. Open a Swift file
nvim main.swift
" 2. Set a breakpoint
:10 " Go to line 10
<F9> " Toggle breakpoint (you'll see ●)
" 3. Build and debug
:SwiftBuildAndDebug
" 4. Navigate
<F10> " Step over
<F11> " Step into
<F5> " Continue
:SwiftDebugVariables " Show variablesJust the essentials - everything works with defaults:
-- ~/.config/nvim/lua/plugins/swift.lua
return {
"devswiftzone/swift.nvim",
ft = "swift", -- Load only for Swift files
opts = {}, -- Use all defaults
config = function(_, opts)
require("swift").setup(opts)
-- Essential keybindings
local debugger = require("swift.features.debugger")
-- Debugger (F keys)
vim.keymap.set("n", "<F5>", debugger.continue, { desc = "Debug: Continue" })
vim.keymap.set("n", "<F9>", debugger.toggle_breakpoint, { desc = "Debug: Breakpoint" })
vim.keymap.set("n", "<F10>", debugger.step_over, { desc = "Debug: Step Over" })
vim.keymap.set("n", "<F11>", debugger.step_into, { desc = "Debug: Step Into" })
-- Build
vim.keymap.set("n", "<leader>bb", ":SwiftBuild<CR>", { desc = "Build" })
vim.keymap.set("n", "<leader>br", ":SwiftRun<CR>", { desc = "Run" })
vim.keymap.set("n", "<leader>bt", ":SwiftTest<CR>", { desc = "Test" })
-- Format & Lint
vim.keymap.set("n", "<leader>sf", ":SwiftFormat<CR>", { desc = "Format" })
vim.keymap.set("n", "<leader>sl", ":SwiftLint<CR>", { desc = "Lint" })
end,
}Complete control over all features:
-- ~/.config/nvim/lua/plugins/swift.lua
return {
"devswiftzone/swift.nvim",
ft = "swift",
opts = {
features = {
-- LSP Configuration
lsp = {
enabled = true,
auto_setup = true,
sourcekit_path = nil, -- Auto-detect
on_attach = function(client, bufnr)
-- Custom LSP keybindings
local opts = { buffer = bufnr, noremap = true, silent = true }
vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts)
vim.keymap.set("n", "K", vim.lsp.buf.hover, opts)
vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts)
vim.keymap.set("n", "gr", vim.lsp.buf.references, opts)
vim.keymap.set("n", "<leader>rn", vim.lsp.buf.rename, opts)
vim.keymap.set("n", "<leader>ca", vim.lsp.buf.code_action, opts)
end,
},
-- Formatter Configuration
formatter = {
enabled = true,
auto_format = false, -- Set to true for format on save
tool = "swift-format", -- or "swiftformat"
swift_format = {
path = nil, -- Auto-detect
args = {},
config_file = nil, -- Auto-find .swift-format
},
},
-- Linter Configuration
linter = {
enabled = true,
auto_lint = true, -- Lint on save
swiftlint_path = nil, -- Auto-detect
config_file = nil, -- Auto-find .swiftlint.yml
severity = "warning",
},
-- Build Runner Configuration
build_runner = {
enabled = true,
show_output = true,
output_position = "botright",
output_height = 15,
auto_close_on_success = false,
},
-- Target Manager Configuration
target_manager = {
enabled = true,
auto_select = true, -- Auto-select first executable target
show_type = true, -- Show target type
},
-- Debugger Configuration (No nvim-dap needed!)
debugger = {
enabled = true,
lldb_path = nil, -- Auto-detect LLDB
-- Visual indicators
signs = {
breakpoint = "●", -- Breakpoint symbol
current_line = "➤", -- Current line symbol
},
-- Colors (using Neovim highlight groups)
colors = {
breakpoint = "DiagnosticError", -- Red
current_line = "DiagnosticInfo", -- Blue
},
-- Debug output window
window = {
position = "bottom", -- "bottom", "right", or "float"
size = 15, -- Height for bottom, width for right
},
},
-- Snippets Configuration
snippets = {
enabled = true, -- Requires LuaSnip
},
-- Xcode Integration (macOS only)
xcode = {
enabled = vim.fn.has("mac") == 1,
default_scheme = nil,
default_simulator = nil,
show_output = true,
output_position = "botright",
output_height = 15,
},
-- Project Detection
project_detector = {
enabled = true,
},
-- Version Validation
version_validator = {
enabled = true,
show_warnings = true,
},
},
-- Logging
log_level = "info", -- "debug", "info", "warn", "error"
},
config = function(_, opts)
require("swift").setup(opts)
-- ============================================================================
-- DEBUGGER KEYBINDINGS
-- ============================================================================
local debugger = require("swift.features.debugger")
-- F keys (standard debugger keys)
vim.keymap.set("n", "<F5>", debugger.continue, { desc = "Debug: Continue" })
vim.keymap.set("n", "<F9>", debugger.toggle_breakpoint, { desc = "Debug: Breakpoint" })
vim.keymap.set("n", "<F10>", debugger.step_over, { desc = "Debug: Step Over" })
vim.keymap.set("n", "<F11>", debugger.step_into, { desc = "Debug: Step Into" })
vim.keymap.set("n", "<F12>", debugger.step_out, { desc = "Debug: Step Out" })
-- <leader>d for debug commands
vim.keymap.set("n", "<leader>db", debugger.toggle_breakpoint, { desc = "Debug: Toggle Breakpoint" })
vim.keymap.set("n", "<leader>dB", debugger.clear_breakpoints, { desc = "Debug: Clear All" })
vim.keymap.set("n", "<leader>dc", debugger.continue, { desc = "Debug: Continue" })
vim.keymap.set("n", "<leader>ds", debugger.stop, { desc = "Debug: Stop" })
vim.keymap.set("n", "<leader>dr", debugger.run, { desc = "Debug: Run" })
vim.keymap.set("n", "<leader>dv", debugger.show_variables, { desc = "Debug: Variables" })
vim.keymap.set("n", "<leader>dt", debugger.show_backtrace, { desc = "Debug: Backtrace" })
vim.keymap.set("n", "<leader>du", ":SwiftDebugUI<CR>", { desc = "Debug: Toggle UI" })
-- ============================================================================
-- BUILD KEYBINDINGS
-- ============================================================================
vim.keymap.set("n", "<leader>bb", ":SwiftBuild<CR>", { desc = "Swift: Build" })
vim.keymap.set("n", "<leader>br", ":SwiftRun<CR>", { desc = "Swift: Run" })
vim.keymap.set("n", "<leader>bt", ":SwiftTest<CR>", { desc = "Swift: Test" })
vim.keymap.set("n", "<leader>bc", ":SwiftClean<CR>", { desc = "Swift: Clean" })
-- ============================================================================
-- FORMAT & LINT KEYBINDINGS
-- ============================================================================
vim.keymap.set("n", "<leader>sf", ":SwiftFormat<CR>", { desc = "Swift: Format" })
vim.keymap.set("v", "<leader>sf", ":SwiftFormatSelection<CR>", { desc = "Swift: Format Selection" })
vim.keymap.set("n", "<leader>sl", ":SwiftLint<CR>", { desc = "Swift: Lint" })
vim.keymap.set("n", "<leader>sL", ":SwiftLintFix<CR>", { desc = "Swift: Lint Fix" })
-- ============================================================================
-- TARGET KEYBINDINGS
-- ============================================================================
vim.keymap.set("n", "<leader>st", ":SwiftTarget<CR>", { desc = "Swift: Select Target" })
vim.keymap.set("n", "<leader>sT", ":SwiftTargetList<CR>", { desc = "Swift: List Targets" })
-- ============================================================================
-- SNIPPETS KEYBINDINGS
-- ============================================================================
vim.keymap.set("n", "<leader>ss", ":SwiftSnippets<CR>", { desc = "Swift: Snippets" })
-- ============================================================================
-- XCODE KEYBINDINGS (macOS only)
-- ============================================================================
if vim.fn.has("mac") == 1 then
vim.keymap.set("n", "<leader>xb", ":SwiftXcodeBuild<CR>", { desc = "Xcode: Build" })
vim.keymap.set("n", "<leader>xs", ":SwiftXcodeSchemes<CR>", { desc = "Xcode: Schemes" })
vim.keymap.set("n", "<leader>xo", ":SwiftXcodeOpen<CR>", { desc = "Xcode: Open" })
end
-- ============================================================================
-- INFO & UTILS KEYBINDINGS
-- ============================================================================
vim.keymap.set("n", "<leader>si", ":SwiftInfo<CR>", { desc = "Swift: Info" })
vim.keymap.set("n", "<leader>sv", ":SwiftVersionInfo<CR>", { desc = "Swift: Version" })
vim.keymap.set("n", "<leader>sh", ":checkhealth swift<CR>", { desc = "Swift: Health" })
-- ============================================================================
-- AUTOCOMMANDS (Optional)
-- ============================================================================
local augroup = vim.api.nvim_create_augroup("SwiftNvim", { clear = true })
-- Auto-format on save (uncomment to enable)
-- vim.api.nvim_create_autocmd("BufWritePre", {
-- group = augroup,
-- pattern = "*.swift",
-- callback = function()
-- vim.cmd("SwiftFormat")
-- end,
-- desc = "Auto-format Swift files on save",
-- })
-- ============================================================================
-- STATUSLINE INTEGRATION (lualine example)
-- ============================================================================
-- If you use lualine, add this to show current target:
-- require('lualine').setup({
-- sections = {
-- lualine_x = {
-- function()
-- local ok, target_manager = pcall(require, "swift.features.target_manager")
-- if ok then
-- local target = target_manager.get_current_target()
-- if target then
-- return "🎯 " .. target
-- end
-- end
-- return ""
-- end,
-- },
-- },
-- })
end,
}Each feature can be individually enabled/disabled and configured:
features = {
lsp = {
enabled = true,
auto_setup = true, -- Auto-configure sourcekit-lsp
sourcekit_path = nil, -- nil = auto-detect
capabilities = nil, -- Auto-configured if nvim-cmp is present
on_attach = function(client, bufnr)
-- Your custom LSP keybindings here
end,
},
}features = {
formatter = {
enabled = true,
auto_format = false, -- true = format on save
tool = "swift-format", -- "swift-format" or "swiftformat"
swift_format = {
path = nil, -- nil = auto-detect
args = {}, -- Additional arguments
config_file = nil, -- nil = auto-find .swift-format
},
swiftformat = {
path = nil,
args = {},
config_file = nil, -- nil = auto-find .swiftformat
},
},
}features = {
linter = {
enabled = true,
auto_lint = true, -- Lint on save
swiftlint_path = nil, -- nil = auto-detect
config_file = nil, -- nil = auto-find .swiftlint.yml
severity = "warning", -- "error" or "warning"
},
}features = {
debugger = {
enabled = true,
lldb_path = nil, -- nil = auto-detect
-- Visual indicators
signs = {
breakpoint = "●", -- Breakpoint symbol
current_line = "➤", -- Current line symbol
},
-- Colors (Neovim highlight groups)
colors = {
breakpoint = "DiagnosticError",
current_line = "DiagnosticInfo",
},
-- Debug output window
window = {
position = "bottom", -- "bottom", "right", "float"
size = 15, -- Height/width depending on position
},
},
}features = {
build_runner = {
enabled = true,
show_output = true,
output_position = "botright", -- Window position
output_height = 15, -- Window height
auto_close_on_success = false, -- Auto-close on successful build
},
}features = {
target_manager = {
enabled = true,
auto_select = true, -- Auto-select first executable
show_type = true, -- Show target type
},
}opts = {
log_level = "info", -- "debug", "info", "warn", "error"
-- log_file = vim.fn.stdpath("cache") .. "/swift.nvim.log", -- Custom log file
}The debugger integrates directly with LLDB without requiring nvim-dap or any other plugins.
- ✅ Zero Dependencies - Just LLDB (included with Swift toolchain)
- ✅ Visual Indicators - Breakpoints (●) and current line (➤)
- ✅ Test Support - Debug .xctest bundles
- ✅ Correct Working Directory - LLDB runs from project root
- ✅ Custom Commands - Send any LLDB command
Starting a Debug Session:
" 1. Select target (if multiple)
:SwiftTarget
" 2. Set breakpoints
:10 " Go to line 10
<F9> " Toggle breakpoint (shows ●)
" 3. Build and debug
:SwiftBuildAndDebug
" When stopped at breakpoint:
<F10> " Step over
<F11> " Step into
<F12> " Step out
<F5> " ContinueDebugging Tests:
" 1. Select test target
:SwiftTarget " Select MyAppTests
" 2. Set breakpoints in test file
<F9> " Toggle breakpoint
" 3. Build and debug tests
:SwiftBuildAndDebugTests
" Navigate through test
<F10> " Step through test| Command | Description | Keybinding |
|---|---|---|
:SwiftDebug |
Start debug session | - |
:SwiftBuildAndDebug |
Build and debug executable | - |
:SwiftBuildAndDebugTests |
Build and debug tests | - |
:SwiftDebugStop |
Stop debugging | <leader>ds |
:SwiftDebugContinue |
Continue execution | <F5> |
:SwiftDebugStepOver |
Step over | <F10> |
:SwiftDebugStepInto |
Step into | <F11> |
:SwiftDebugStepOut |
Step out | <F12> |
:SwiftBreakpointToggle |
Toggle breakpoint | <F9> |
:SwiftBreakpointClear |
Clear all breakpoints | <leader>dB |
:SwiftDebugVariables |
Show variables | <leader>dv |
:SwiftDebugBacktrace |
Show call stack | <leader>dt |
:SwiftDebugCommand <cmd> |
Send LLDB command | - |
:SwiftDebugUI |
Toggle debug window | <leader>du |
You can send any LLDB command during a debug session:
" Print variable
:SwiftDebugCommand p myVariable
" Print object description
:SwiftDebugCommand po myObject
" View all local variables
:SwiftDebugCommand frame variable
" Backtrace
:SwiftDebugCommand bt
" Thread list
:SwiftDebugCommand thread list
" Evaluate expression
:SwiftDebugCommand expr myVar = 42- ● (Red) - Active breakpoint
- ➤ (Blue) - Current execution line
- Highlighted line - Current line during debugging
-- Bottom (default)
window = { position = "bottom", size = 15 }
-- Right side
window = { position = "right", size = 50 }
-- Floating window
window = { position = "float", size = 20 }Automatic configuration of sourcekit-lsp with nvim-lspconfig.
- Auto-detect sourcekit-lsp
- Code completion
- Go to definition/implementation/references
- Hover documentation
- Rename symbol
- Code actions
- Integration with nvim-cmp
LSP starts automatically when you open a Swift file. No configuration needed if nvim-lspconfig is installed.
Default LSP Keybindings (if using Full Config):
gd - Go to definition
K - Hover documentation
gi - Go to implementation
gr - Go to references
<leader>rn - Rename symbol
<leader>ca - Code actions
Build, run, test, and clean Swift packages.
| Command | Description | Example |
|---|---|---|
:SwiftBuild |
Build in debug mode | :SwiftBuild |
:SwiftBuild release |
Build in release mode | :SwiftBuild release |
:SwiftRun |
Run executable | :SwiftRun |
:SwiftTest |
Run all tests | :SwiftTest |
:SwiftTest <name> |
Run specific test | :SwiftTest MyTest |
:SwiftClean |
Clean build artifacts | :SwiftClean |
Build output appears in a separate window at the bottom (configurable).
build_runner = {
show_output = true, -- Show output window
output_position = "botright", -- Position
output_height = 15, -- Height
auto_close_on_success = false,-- Auto-close on success
}Support for both swift-format (Apple's official) and swiftformat (community).
| Command | Description |
|---|---|
:SwiftFormat |
Format current file |
:SwiftFormatSelection |
Format visual selection |
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*.swift",
callback = function()
vim.cmd("SwiftFormat")
end,
})formatter = {
tool = "swift-format", -- or "swiftformat"
}SwiftLint integration with auto-fix support.
| Command | Description |
|---|---|
:SwiftLint |
Lint current file |
:SwiftLintFix |
Lint and auto-fix |
linter = {
auto_lint = true, -- Lint on save
severity = "warning", -- Show warnings (or "error")
}List and select executable and test targets.
| Command | Description |
|---|---|
:SwiftTarget |
Interactive target selector |
:SwiftTargetList |
List all targets |
:SwiftTarget
" Opens selector:
" > MyApp (executable)
" MyLibrary (library)
" MyAppTests (test)Show current target in your statusline (lualine example):
require('lualine').setup({
sections = {
lualine_x = {
function()
local ok, tm = pcall(require, "swift.features.target_manager")
if ok then
local target = tm.get_current_target()
return target and ("🎯 " .. target) or ""
end
return ""
end,
},
},
})50+ built-in Swift snippets for common patterns.
- Structures: struct, class, enum, protocol, extension
- Functions: func, init, deinit, async, throws
- Control Flow: if, guard, switch, for, while
- SwiftUI: View, State, Binding, ObservableObject
- Testing: test, testCase, setUp, tearDown
- And more...
Requires LuaSnip installed. Snippets trigger automatically as you type.
:SwiftSnippets " List all available snippetsBuild and manage Xcode projects from Neovim.
| Command | Description |
|---|---|
:SwiftXcodeBuild |
Build with default scheme |
:SwiftXcodeBuild <scheme> |
Build with specific scheme |
:SwiftXcodeSchemes |
List/select schemes |
:SwiftXcodeOpen |
Open in Xcode.app |
Auto-detects project type and root directory.
Supported project types:
- Swift Package Manager (Package.swift)
- Xcode Projects (.xcodeproj)
- Xcode Workspaces (.xcworkspace)
No configuration needed - works automatically.
Validates Swift toolchain and tool versions.
:SwiftVersionInfo " Show Swift version info
:SwiftValidateEnvironment " Validate all tools
:checkhealth swift " Complete health check:SwiftBuild " Build in debug mode
:SwiftBuild release " Build in release mode
:SwiftRun " Run executable
:SwiftTest " Run all tests
:SwiftTest <name> " Run specific test
:SwiftClean " Clean build artifacts:SwiftDebug " Start debug session
:SwiftBuildAndDebug " Build and debug executable
:SwiftBuildAndDebugTests " Build and debug tests
:SwiftDebugStop " Stop debugging
:SwiftDebugContinue " Continue execution
:SwiftDebugStepOver " Step over
:SwiftDebugStepInto " Step into
:SwiftDebugStepOut " Step out
:SwiftBreakpointToggle " Toggle breakpoint at current line
:SwiftBreakpointClear " Clear all breakpoints
:SwiftDebugVariables " Show local variables
:SwiftDebugBacktrace " Show call stack
:SwiftDebugCommand <cmd> " Send custom LLDB command
:SwiftDebugUI " Toggle debug output window:SwiftFormat " Format current file
:SwiftFormatSelection " Format visual selection
:SwiftLint " Lint current file
:SwiftLintFix " Lint and auto-fix:SwiftTarget " Select target interactively
:SwiftTargetList " List all targets:SwiftSnippets " List all available snippets:SwiftXcodeBuild [scheme] " Build Xcode project
:SwiftXcodeSchemes " List/select schemes
:SwiftXcodeOpen " Open in Xcode.app:SwiftInfo " Plugin information
:SwiftVersionInfo " Swift version information
:SwiftValidateEnvironment " Validate environmentF5 → Continue/Run
F9 → Toggle Breakpoint
F10 → Step Over
F11 → Step Into
F12 → Step Out
<leader>db → Toggle Breakpoint
<leader>dB → Clear All Breakpoints
<leader>dc → Continue
<leader>ds → Stop Debugging
<leader>dr → Run
<leader>dv → Show Variables
<leader>dt → Show Backtrace
<leader>du → Toggle Debug UI
<leader>bb → Build
<leader>br → Run
<leader>bt → Test
<leader>bc → Clean
<leader>sf → Format File (or selection in visual mode)
<leader>sl → Lint
<leader>sL → Lint and Fix
<leader>st → Select Target
<leader>sT → List Targets
<leader>ss → List Snippets
<leader>xb → Build with Xcode
<leader>xs → Select Scheme
<leader>xo → Open in Xcode.app
<leader>si → Plugin Info
<leader>sv → Version Info
<leader>sh → Health Check
You can customize all keybindings in your config:
config = function(_, opts)
require("swift").setup(opts)
local debugger = require("swift.features.debugger")
-- Use your preferred keys
vim.keymap.set("n", "<C-b>", debugger.toggle_breakpoint)
vim.keymap.set("n", "<C-n>", debugger.step_over)
-- etc...
end" 1. Build project
:SwiftBuild
" 2. Check for lint issues
:SwiftLint
" 3. Format code
:SwiftFormat
" 4. Run
:SwiftRun" 1. Select target (if multiple)
:SwiftTarget
" 2. Set breakpoints
<F9> " On important lines
" 3. Build and debug
:SwiftBuildAndDebug
" 4. Navigate through code
<F10> " Step over
<F11> " Step into function
<leader>dv " Inspect variables
<F5> " Continue to next breakpoint
" 5. Stop when done
<leader>ds" 1. Open test file
nvim Tests/MyAppTests.swift
" 2. Select test target
:SwiftTarget
" Choose: MyAppTests
" 3. Set breakpoint in test
<F9>
" 4. Build and debug tests
:SwiftBuildAndDebugTests
" 5. Step through test
<F10> " Step over each line" 1. Check current issues
:SwiftLint
" 2. Auto-fix what you can
:SwiftLintFix
" 3. Format code
:SwiftFormat
" 4. Run tests to verify
:SwiftTest
" 5. Build to confirm
:SwiftBuild" 1. Run tests
:SwiftTest
" 2. Check lint
:SwiftLint
" 3. Build release
:SwiftBuild release
" 4. Test release build manually
" (deploy/distribute)Problem: Can't find executable to debug
Solution:
" Build first
:SwiftBuild
" Make sure you selected the right target
:SwiftTargetProblem: LLDB debugger not detected
Solution:
# macOS - Install Xcode Command Line Tools
xcode-select --install
# Linux/macOS - Install Swift toolchain
curl -L https://swift-server.github.io/swiftly/swiftly-install.sh | bash
swiftly install latest
# Verify
lldb --versionProblem: Breakpoints don't stop execution
Possible causes:
- Not built in debug mode
- Code not executed
- LLDB not properly attached
Solution:
" 1. Build in debug mode
:SwiftBuild
" 2. Check breakpoint is set (you should see ●)
<F9>
" 3. Restart debug session
:SwiftDebugStop
:SwiftBuildAndDebugProblem: No code completion or LSP features
Solution:
# 1. Check if sourcekit-lsp is installed
sourcekit-lsp --version
# 2. Check health
:checkhealth swift
# 3. Make sure nvim-lspconfig is installed
:Lazy # Check if nvim-lspconfig is listedProblem: :SwiftFormat doesn't work
Solution:
# Install swift-format
brew install swift-format
# Or install swiftformat
brew install swiftformat
# Verify
swift-format --version
# or
swiftformat --version
# Check health
:checkhealth swiftProblem: :SwiftLint doesn't work
Solution:
# Install SwiftLint
brew install swiftlint
# Verify
swiftlint version
# Check health
:checkhealth swiftEnable debug logging to troubleshoot:
opts = {
log_level = "debug",
}Then check the log:
:SwiftInfo " Shows log file locationAlways run health check first:
:checkhealth swiftThis will tell you:
- ✓ What's working
- ⚠ What needs attention
- ✗ What's broken
Q: Do I need nvim-dap for debugging? A: No! Swift.nvim uses LLDB directly. No nvim-dap needed.
Q: Does it work on Linux? A: Yes! Just install the Swift toolchain.
Q: What's the minimum Neovim version? A: Neovim >= 0.8.0
Q: Do I need plenary.nvim? A: No, it's not required.
Q: Can I use only some features? A: Yes! Disable features you don't want:
opts = {
features = {
debugger = { enabled = true },
linter = { enabled = false }, -- Disable linter
xcode = { enabled = false }, -- Disable Xcode integration
},
}Q: Can I customize keybindings?
A: Absolutely! Just modify the config function in your setup.
Q: How do I change the debug window position? A: In your config:
debugger = {
window = {
position = "float", -- "bottom", "right", or "float"
size = 20,
},
}Q: How do I debug tests? A:
:SwiftTarget " Select test target (e.g., MyAppTests)
<F9> " Set breakpoints
:SwiftBuildAndDebugTests " Build and debugQ: Can I send custom LLDB commands? A: Yes!
:SwiftDebugCommand p myVariable
:SwiftDebugCommand bt
:SwiftDebugCommand thread listQ: How do I see variables? A:
:SwiftDebugVariables
" Or
<leader>dvQ: Debug window doesn't close automatically
A: Press q in the debug window, or use :SwiftDebugUI to toggle it.
Q: How do I build for release?
A: :SwiftBuild release
Q: Can I run specific tests?
A: Yes! :SwiftTest MyTestName
Q: Build output window is too small A: Adjust in config:
build_runner = {
output_height = 25, -- Increase height
}Q: Code completion doesn't work A: Make sure you have:
- nvim-lspconfig installed
- sourcekit-lsp installed (
swift --version) - Run
:checkhealth swift
Q: How do I customize LSP keybindings?
A: Use the on_attach callback:
lsp = {
on_attach = function(client, bufnr)
-- Your custom keybindings
vim.keymap.set("n", "gd", vim.lsp.buf.definition, { buffer = bufnr })
end,
}Q: How do I show current target in statusline? A: See Target Manager section for lualine example.
Q: Auto-format on save? A: Uncomment this in your config:
vim.api.nvim_create_autocmd("BufWritePre", {
pattern = "*.swift",
callback = function()
vim.cmd("SwiftFormat")
end,
})Q: Can I use it with other Swift plugins? A: Yes! swift.nvim is designed to work alongside other plugins.
Create aliases for frequently used LLDB commands:
vim.api.nvim_create_user_command("PrintSelf", function()
vim.cmd("SwiftDebugCommand po self")
end, {})
vim.api.nvim_create_user_command("ListThreads", function()
vim.cmd("SwiftDebugCommand thread list")
end, {})While debugging:
:SwiftDebugCommand breakpoint modify -c 'myVar > 10'During debug session:
:SwiftDebugCommand expr myArray.count
:SwiftDebugCommand expr let newVar = 42Create .swift-format in project root:
{
"version": 1,
"lineLength": 120,
"indentation": {
"spaces": 2
},
"respectsExistingLineBreaks": true
}Create .swiftlint.yml in project root:
disabled_rules:
- line_length
- trailing_whitespace
opt_in_rules:
- empty_count
- force_unwrapping
line_length: 120
excluded:
- Pods
- .buildDifferent configs for different projects:
-- ~/.config/nvim/lua/plugins/swift.lua
return {
"devswiftzone/swift.nvim",
ft = "swift",
opts = function()
-- Check project type
local cwd = vim.fn.getcwd()
if cwd:match("MyiOSApp") then
return {
features = {
xcode = { enabled = true },
debugger = { window = { position = "float" } },
},
}
else
return {
features = {
xcode = { enabled = false },
},
}
end
end,
}-- In your config
vim.notify = require("notify")
-- swift.nvim will automatically use fancy notifications-- Create custom picker for targets
local function pick_swift_target()
local tm = require("swift.features.target_manager")
local targets = tm.get_targets()
require('telescope.pickers').new({}, {
prompt_title = 'Swift Targets',
finder = require('telescope.finders').new_table({
results = targets,
entry_maker = function(target)
return {
value = target,
display = target.name .. " (" .. target.type .. ")",
ordinal = target.name,
}
end,
}),
sorter = require('telescope.config').values.generic_sorter({}),
attach_mappings = function(prompt_bufnr, map)
local actions = require('telescope.actions')
actions.select_default:replace(function()
local selection = require('telescope.actions.state').get_selected_entry()
actions.close(prompt_bufnr)
tm.set_target(selection.value.name)
end)
return true
end,
}):find()
end
vim.keymap.set('n', '<leader>st', pick_swift_target)For large projects:
opts = {
features = {
lsp = {
enabled = true,
-- Limit LSP to current buffer for large projects
flags = {
debounce_text_changes = 150,
},
},
linter = {
auto_lint = false, -- Manual lint only
},
},
}This repository includes several configuration examples:
- MINIMAL_CONFIG.lua - Minimal setup (~30 lines)
- FULL_CONFIG.lua - Complete setup with all options (~450 lines)
- examples/debugger-config.lua - Debugger-specific example
- Swift.org - Official Swift documentation
- sourcekit-lsp - LSP implementation
- SwiftLint - Linter documentation
- swift-format - Formatter documentation
- Report bugs: GitHub Issues
- Feature requests: GitHub Discussions
MIT License - See LICENSE file for details
Built with ❤️ for the Swift and Neovim communities.
Special thanks to:
- The Swift team for sourcekit-lsp and swift-format
- The Neovim team for an amazing editor
- All contributors and users
swift.nvim - Swift development in Neovim without compromises.
Last updated: 2025