Skip to content

Instantly share code, notes, and snippets.

@abdulkareem-siddiq
Last active September 2, 2026 18:39
Show Gist options
  • Select an option

  • Save abdulkareem-siddiq/2ff4f8dd64fac65d03dbdec9e4456fa8 to your computer and use it in GitHub Desktop.

Select an option

Save abdulkareem-siddiq/2ff4f8dd64fac65d03dbdec9e4456fa8 to your computer and use it in GitHub Desktop.
Cross-Platform macOS & Linux Neovim VSCode Setup Script for C++, Swift, Go & CMake
#!/usr/bin/env bash
# ==============================================================================
# Cross-Platform macOS & Linux Neovim VSCode Setup Script for C++, Swift & Go
# (Visual Studio for Mac Keyboard Compatible)
# ==============================================================================
#
# Gist URL: https://gist.github.com/abdulkareem-siddiq/2ff4f8dd64fac65d03dbdec9e4456fa8
# Raw URL: https://gist.githubusercontent.com/abdulkareem-siddiq/2ff4f8dd64fac65d03dbdec9e4456fa8/raw/setup_neovim_vscode.sh
#
# Features (Idempotent & Re-run Safe):
# 1. Automatic OS & Package Manager detection (Homebrew, DNF, YUM, APT, Pacman)
# 2. Installs required system dependencies (Neovim, Git, Ripgrep, Fd, Clang, Go, Swift)
# 3. Backs up existing Neovim configuration if present
# 4. Modular Lua configuration using Lazy.nvim plugin manager
# 5. VSCode Dark+ Theme (Mofiqul/vscode.nvim) with custom syntax token styling
# 6. Full Visual Studio on Mac Keyboard Compatibility (Cmd+S, Cmd+P, Cmd+B, Cmd+W, Cmd+J, Cmd+F, F12, F2, F5, etc.)
# 7. Polyglot LSP Setup:
# - C / C++: clangd (background indexing, clang-tidy, inlay hints)
# - Swift: sourcekit-lsp (dynamic macOS/Linux toolchain resolution)
# - Go: gopls (staticcheck, gofumpt, nilness analysis, inlay hints)
# - CMake: cmake-language-server
# - Lua: lua-language-server
# 8. Visual Studio F-Key Debugging (DAP):
# - C / C++ / Swift: codelldb
# - Go: delve (dlv)
# 9. Automatic Code Formatting on Save (conform.nvim):
# - clang-format, goimports, gofumpt, swiftformat, stylua
# 10. Tree-sitter semantic syntax highlighting across all languages
#
# Quick Run:
# chmod +x setup_neovim_vscode.sh
# ./setup_neovim_vscode.sh
# ==============================================================================
set -euo pipefail
# --- Color formatting helpers ---
BOLD="$(tput bold 2>/dev/null || echo '')"
GREEN="$(tput setaf 2 2>/dev/null || echo '')"
YELLOW="$(tput setaf 3 2>/dev/null || echo '')"
BLUE="$(tput setaf 4 2>/dev/null || echo '')"
CYAN="$(tput setaf 6 2>/dev/null || echo '')"
RED="$(tput setaf 1 2>/dev/null || echo '')"
NC="$(tput sgr0 2>/dev/null || echo '')"
info() { echo -e "${CYAN}${BOLD}[INFO]${NC} $*"; }
success() { echo -e "${GREEN}${BOLD}[SUCCESS]${NC} $*"; }
warn() { echo -e "${YELLOW}${BOLD}[WARN]${NC} $*"; }
error() { echo -e "${RED}${BOLD}[ERROR]${NC} $*" >&2; }
NVIM_CONFIG_DIR="${HOME}/.config/nvim"
detect_os() {
if [[ "$(uname)" == "Darwin" ]]; then
echo "macos"
elif [[ -f /etc/redhat-release ]] || [[ -f /etc/fedora-release ]]; then
echo "redhat"
elif [[ -f /etc/debian_version ]]; then
echo "debian"
elif [[ -f /etc/arch-release ]]; then
echo "arch"
else
echo "linux"
fi
}
install_dependencies() {
local os="$1"
info "Detecting system dependencies for platform: ${BOLD}${os}${NC}..."
case "$os" in
macos)
if ! command -v brew >/dev/null 2>&1; then
warn "Homebrew is not installed. Please install Homebrew from https://brew.sh/"
else
info "Ensuring core packages via Homebrew..."
brew install neovim git ripgrep fd cmake llvm go swift-format tree-sitter-cli node 2>/dev/null || true
fi
;;
redhat)
local pkg_mgr="dnf"
command -v dnf >/dev/null 2>&1 || pkg_mgr="yum"
info "Ensuring core packages via RedHat/Fedora ${pkg_mgr}..."
sudo "${pkg_mgr}" install -y epel-release 2>/dev/null || true
sudo "${pkg_mgr}" install -y neovim git ripgrep fd-find cmake make gcc gcc-c++ clang llvm golang 2>/dev/null || true
;;
debian)
info "Ensuring core packages via apt..."
sudo apt-get update -y
sudo apt-get install -y neovim git ripgrep fd-find cmake make gcc g++ clang llvm golang-go 2>/dev/null || true
;;
arch)
info "Ensuring core packages via pacman..."
sudo pacman -S --needed --noconfirm neovim git ripgrep fd cmake make gcc clang llvm go 2>/dev/null || true
;;
esac
}
backup_existing_config() {
if [[ -d "${NVIM_CONFIG_DIR}" ]]; then
if [[ -f "${NVIM_CONFIG_DIR}/init.vim" && ! -f "${NVIM_CONFIG_DIR}/init.lua" ]]; then
local backup_path="${NVIM_CONFIG_DIR}.bak.$(date +%Y%m%d%H%M%S)"
warn "Existing legacy init.vim config detected. Backing up to ${backup_path}"
mv "${NVIM_CONFIG_DIR}" "${backup_path}"
fi
fi
mkdir -p "${NVIM_CONFIG_DIR}/lua/config"
mkdir -p "${NVIM_CONFIG_DIR}/lua/plugins"
mkdir -p "${NVIM_CONFIG_DIR}/queries/swift"
}
write_config_files() {
info "Writing modular Lua configuration files to ${NVIM_CONFIG_DIR}..."
cat << 'EOF_INIT_LUA' > "${NVIM_CONFIG_DIR}/init.lua"
-- ==============================================================================
-- Neovim Configuration (VSCode Aesthetic & Complete C++ IDE Setup)
-- ==============================================================================
-- Set leader key before loading plugins
vim.g.mapleader = " "
vim.g.maplocalleader = " "
-- Load core configurations
require("config.options")
require("config.keymaps")
require("config.autocmds")
require("config.lazy")
EOF_INIT_LUA
cat << 'EOF_LUA_CONFIG_OPTIONS_LUA' > "${NVIM_CONFIG_DIR}/lua/config/options.lua"
-- ==============================================================================
-- Editor Options (VSCode Look & Feel, Idempotent & Portable)
-- ==============================================================================
local opt = vim.opt
-- Appearance & Theme
opt.termguicolors = true
opt.cursorline = true
opt.number = true
opt.relativenumber = false -- VSCode uses absolute line numbers by default
opt.signcolumn = "yes" -- Always draw signcolumn to prevent layout shifting
opt.fillchars = { eob = " " } -- Hide ugly '~' on empty lines at the end of buffer
opt.showmode = false -- Hide default mode (-- INSERT --) since statusline displays it
opt.pumheight = 10 -- Max items in popup completion menu
opt.pumblend = 0 -- Popup menu transparency
opt.winblend = 0 -- Floating window transparency
opt.conceallevel = 0 -- Make markdown and json symbols visible
-- Indentation & Tabs (Standard: 4 spaces)
opt.tabstop = 4
opt.shiftwidth = 4
opt.softtabstop = 4
opt.expandtab = true
opt.autoindent = true
opt.smartindent = true
-- Behavior & Usability
opt.mouse = "a" -- Full mouse support (scroll, click, resize splits)
opt.wrap = false -- No line wrapping by default
opt.scrolloff = 8 -- Keep 8 lines above/below cursor when scrolling
opt.sidescrolloff = 8 -- Keep 8 columns to the left/right
opt.splitbelow = true -- Horizontal split opens below
opt.splitright = true -- Vertical split opens to the right
opt.updatetime = 200 -- Faster completion / hover response (default 4000ms)
opt.timeoutlen = 400 -- Faster keybinding sequence timeout
opt.undofile = true -- Persistent undo history across restarts
opt.swapfile = false -- Disable swap files
opt.backup = false -- Disable backup files
-- Search Options
opt.ignorecase = true -- Case insensitive search by default
opt.smartcase = true -- Case sensitive if uppercase letters are typed
opt.hlsearch = true -- Highlight all matches
opt.incsearch = true -- Show matches as you type
-- Fold settings (Treesitter folding)
opt.foldmethod = "expr"
opt.foldexpr = "v:lua.vim.treesitter.foldexpr()"
opt.foldlevel = 99 -- Files open unfolded
opt.foldlevelstart = 99
opt.foldenable = true
-- Portable Clipboard (macOS pbcopy/pbpaste, RedHat/Linux xclip/wl-copy, and OSC52 fallback)
opt.clipboard = "unnamedplus"
EOF_LUA_CONFIG_OPTIONS_LUA
cat << 'EOF_LUA_CONFIG_KEYMAPS_LUA' > "${NVIM_CONFIG_DIR}/lua/config/keymaps.lua"
-- ==============================================================================
-- Keymaps: Visual Studio / VSCode for Mac Compatible + Cross-Platform Ergonomics
-- C++, Swift, Go, CMake, Lua
-- ==============================================================================
local map = vim.keymap.set
-- Clear search highlights
map("n", "<leader>h", "<cmd>nohlsearch<CR>", { desc = "Clear search highlight" })
map("n", "<Esc>", "<cmd>nohlsearch<CR>", { desc = "Clear search highlight" })
-- ==============================================================================
-- 1. Visual Studio on Mac: File & Editor Tab Management
-- ==============================================================================
-- Save File (Cmd+S on Mac / Ctrl+S across Normal, Insert, Visual)
map({ "n", "i", "v" }, "<D-s>", "<cmd>w<CR>", { desc = "Save File (Cmd+S)" })
map({ "n", "i", "v" }, "<C-s>", "<cmd>w<CR>", { desc = "Save File (Ctrl+S)" })
-- Toggle Sidebar Explorer (Cmd+B on Mac / Ctrl+B / <leader>e)
map("n", "<D-b>", "<cmd>NvimTreeToggle<CR>", { desc = "Toggle File Explorer (Cmd+B)" })
map("n", "<C-b>", "<cmd>NvimTreeToggle<CR>", { desc = "Toggle File Explorer (Ctrl+B)" })
map("n", "<leader>e", "<cmd>NvimTreeFocus<CR>", { desc = "Focus File Explorer" })
-- Close Current Tab / Editor (Cmd+W on Mac / <leader>w / <leader>x)
local function close_tab()
local ok, bufdelete = pcall(require, "bufdelete")
if ok then
bufdelete.bufdelete(0, false)
else
vim.cmd("bdelete")
end
end
map("n", "<D-w>", close_tab, { desc = "Close Tab (Cmd+W)" })
map("n", "<leader>w", close_tab, { desc = "Close Tab (<leader>w)" })
map("n", "<leader>x", close_tab, { desc = "Close Tab (<leader>x)" })
-- Tab Navigation (Cmd+Option+Left/Right on Mac, Tab / Shift-Tab, Ctrl+Tab)
map("n", "<D-A-Right>", "<cmd>BufferLineCycleNext<CR>", { desc = "Next Tab (Cmd+Opt+Right)" })
map("n", "<D-A-Left>", "<cmd>BufferLineCyclePrev<CR>", { desc = "Previous Tab (Cmd+Opt+Left)" })
map("n", "<Tab>", "<cmd>BufferLineCycleNext<CR>", { desc = "Next Tab" })
map("n", "<S-Tab>", "<cmd>BufferLineCyclePrev<CR>", { desc = "Previous Tab" })
map("n", "<C-Tab>", "<cmd>BufferLineCycleNext<CR>", { desc = "Next Tab" })
map("n", "<C-S-Tab>", "<cmd>BufferLineCyclePrev<CR>", { desc = "Previous Tab" })
map("n", "]b", "<cmd>BufferLineCycleNext<CR>", { desc = "Next Tab" })
map("n", "[b", "<cmd>BufferLineCyclePrev<CR>", { desc = "Previous Tab" })
map("n", "<leader>bp", "<cmd>BufferLinePick<CR>", { desc = "Pick Tab" })
map("n", "<leader>bc", "<cmd>BufferLineCloseOthers<CR>", { desc = "Close Other Tabs" })
-- Window Splits (Cmd+\ on Mac / <leader>sv / <leader>sh)
map("n", "<D-\\>", "<cmd>vsplit<CR>", { desc = "Split Editor Vertically (Cmd+\\)" })
map("n", "<C-\\>", "<cmd>vsplit<CR>", { desc = "Split Editor Vertically" })
map("n", "<leader>sv", "<cmd>vsplit<CR>", { desc = "Split Vertically" })
map("n", "<leader>sh", "<cmd>split<CR>", { desc = "Split Horizontally" })
map("n", "<leader>sc", "<cmd>close<CR>", { desc = "Close Split" })
-- Window Navigation
map("n", "<C-h>", "<C-w>h", { desc = "Move to left window" })
map("n", "<C-j>", "<C-w>j", { desc = "Move to lower window" })
map("n", "<C-k>", "<C-w>k", { desc = "Move to upper window" })
map("n", "<C-l>", "<C-w>l", { desc = "Move to right window" })
-- Resize window with arrows
map("n", "<C-Up>", "<cmd>resize +2<CR>", { desc = "Increase window height" })
map("n", "<C-Down>", "<cmd>resize -2<CR>", { desc = "Decrease window height" })
map("n", "<C-Left>", "<cmd>vertical resize -2<CR>", { desc = "Decrease window width" })
map("n", "<C-Right>", "<cmd>vertical resize +2<CR>", { desc = "Increase window width" })
-- ==============================================================================
-- 2. Visual Studio on Mac: Line & Block Editing
-- ==============================================================================
-- Move lines up/down (Option+Up / Option+Down on Mac)
map("n", "<A-Down>", "<cmd>m .+1<CR>==", { desc = "Move line down (Opt+Down)" })
map("n", "<A-Up>", "<cmd>m .-2<CR>==", { desc = "Move line up (Opt+Up)" })
map("n", "<A-j>", "<cmd>m .+1<CR>==", { desc = "Move line down" })
map("n", "<A-k>", "<cmd>m .-2<CR>==", { desc = "Move line up" })
map("i", "<A-Down>", "<Esc><cmd>m .+1<CR>==gi", { desc = "Move line down (Opt+Down)" })
map("i", "<A-Up>", "<Esc><cmd>m .-2<CR>==gi", { desc = "Move line up (Opt+Up)" })
map("v", "<A-Down>", ":m '>+1<CR>gv=gv", { desc = "Move block down (Opt+Down)" })
map("v", "<A-Up>", ":m '<-2<CR>gv=gv", { desc = "Move block up (Opt+Up)" })
map("v", "<A-j>", ":m '>+1<CR>gv=gv", { desc = "Move block down" })
map("v", "<A-k>", ":m '<-2<CR>gv=gv", { desc = "Move block up" })
-- Duplicate lines (Shift+Option+Down / Shift+Option+Up on Mac)
map("n", "<A-S-Down>", "<cmd>t.<CR>", { desc = "Duplicate line down (Shift+Opt+Down)" })
map("n", "<A-S-Up>", "<cmd>t.-1<CR>", { desc = "Duplicate line up (Shift+Opt+Up)" })
map("n", "<S-A-Down>", "<cmd>t.<CR>", { desc = "Duplicate line down" })
map("n", "<S-A-Up>", "<cmd>t.-1<CR>", { desc = "Duplicate line up" })
map("i", "<A-S-Down>", "<Esc><cmd>t.<CR>gi", { desc = "Duplicate line down (Shift+Opt+Down)" })
map("i", "<A-S-Up>", "<Esc><cmd>t.-1<CR>gi", { desc = "Duplicate line up (Shift+Opt+Up)" })
map("v", "<A-S-Down>", ":'<,'>t'> <CR>gv", { desc = "Duplicate selection down" })
map("v", "<A-S-Up>", ":'<,'>t'<-1 <CR>gv", { desc = "Duplicate selection up" })
-- Delete Line (Cmd+Shift+K on Mac)
map({ "n", "i", "v" }, "<D-S-k>", "<cmd>d<CR>", { desc = "Delete Line (Cmd+Shift+K)" })
map({ "n", "i", "v" }, "<D-K>", "<cmd>d<CR>", { desc = "Delete Line (Cmd+Shift+K)" })
-- Toggle Line Comment (Cmd+/ on Mac / Ctrl+/)
map("n", "<D-/>", function() require("Comment.api").toggle.linewise.current() end, { desc = "Toggle Comment (Cmd+/)" })
map("v", "<D-/>", "<ESC><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<CR>", { desc = "Toggle Comment (Cmd+/)" })
map("n", "<C-/>", function() require("Comment.api").toggle.linewise.current() end, { desc = "Toggle Comment (Ctrl+/)" })
map("v", "<C-/>", "<ESC><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<CR>", { desc = "Toggle Comment (Ctrl+/)" })
map("n", "<C-_>", function() require("Comment.api").toggle.linewise.current() end, { desc = "Toggle Comment" })
map("v", "<C-_>", "<ESC><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<CR>", { desc = "Toggle Comment" })
-- Toggle Word Wrap (Option+Z on Mac)
map("n", "<A-z>", "<cmd>set wrap!<CR>", { desc = "Toggle Word Wrap (Opt+Z)" })
-- Indent keeping visual selection
map("v", "<", "<gv", { desc = "Indent left and keep selection" })
map("v", ">", ">gv", { desc = "Indent right and keep selection" })
-- ==============================================================================
-- 3. Visual Studio on Mac: Search, Palette & Symbols
-- ==============================================================================
-- Quick Open File (Cmd+P on Mac / Ctrl+P)
map("n", "<D-p>", "<cmd>Telescope find_files<CR>", { desc = "Quick Open File (Cmd+P)" })
map("n", "<C-p>", "<cmd>Telescope find_files<CR>", { desc = "Quick Open File (Ctrl+P)" })
map("n", "<leader>ff", "<cmd>Telescope find_files<CR>", { desc = "Find Files" })
map("n", "<leader>fr", "<cmd>Telescope oldfiles<CR>", { desc = "Recent Files" })
-- Command Palette (Cmd+Shift+P / F1 on Mac / <leader>cp)
map("n", "<D-S-p>", "<cmd>Telescope commands<CR>", { desc = "Command Palette (Cmd+Shift+P)" })
map("n", "<D-P>", "<cmd>Telescope commands<CR>", { desc = "Command Palette (Cmd+Shift+P)" })
map("n", "<F1>", "<cmd>Telescope commands<CR>", { desc = "Command Palette (F1)" })
map("n", "<leader>cp", "<cmd>Telescope commands<CR>", { desc = "Command Palette" })
map("n", "<leader>fk", "<cmd>Telescope keymaps<CR>", { desc = "List Keymaps" })
-- Find in Buffer (Cmd+F on Mac / Ctrl+F)
map("n", "<D-f>", "<cmd>Telescope current_buffer_fuzzy_find<CR>", { desc = "Find in Buffer (Cmd+F)" })
map("n", "<C-f>", "<cmd>Telescope current_buffer_fuzzy_find<CR>", { desc = "Find in Buffer (Ctrl+F)" })
-- Find in Files / Live Grep (Cmd+Shift+F on Mac / <leader>fg)
map("n", "<D-S-f>", "<cmd>Telescope live_grep<CR>", { desc = "Find in Files (Cmd+Shift+F)" })
map("n", "<D-F>", "<cmd>Telescope live_grep<CR>", { desc = "Find in Files (Cmd+Shift+F)" })
map("n", "<leader>fg", "<cmd>Telescope live_grep<CR>", { desc = "Find in Files (Grep)" })
-- Go to Symbol in File (Cmd+Shift+O on Mac / <leader>ss)
map("n", "<D-S-o>", "<cmd>Telescope lsp_document_symbols<CR>", { desc = "Go to Symbol (Cmd+Shift+O)" })
map("n", "<D-O>", "<cmd>Telescope lsp_document_symbols<CR>", { desc = "Go to Symbol (Cmd+Shift+O)" })
map("n", "<leader>ss", "<cmd>Telescope lsp_document_symbols<CR>", { desc = "Document Symbols" })
-- Go to Symbol in Workspace (Cmd+T on Mac / <leader>sS)
map("n", "<D-t>", "<cmd>Telescope lsp_workspace_symbols<CR>", { desc = "Workspace Symbols (Cmd+T)" })
map("n", "<leader>sS", "<cmd>Telescope lsp_workspace_symbols<CR>", { desc = "Workspace Symbols" })
-- ==============================================================================
-- 4. Visual Studio on Mac: Integrated Terminal Drawer
-- ==============================================================================
-- Toggle Terminal (Cmd+J on Mac / Ctrl+` / <leader>t)
map({ "n", "t" }, "<D-j>", "<cmd>ToggleTerm<CR>", { desc = "Toggle Terminal Panel (Cmd+J)" })
map({ "n", "t" }, "<C-`>", "<cmd>ToggleTerm<CR>", { desc = "Toggle Terminal Panel (Ctrl+`)" })
map({ "n", "t" }, "<D-`>", "<cmd>ToggleTerm<CR>", { desc = "Toggle Terminal Panel (Cmd+`)" })
map("n", "<leader>t", "<cmd>ToggleTerm<CR>", { desc = "Toggle Terminal Panel" })
map("t", "<Esc><Esc>", [[<C-\><C-n>]], { desc = "Exit terminal mode" })
-- ==============================================================================
-- 5. Visual Studio on Mac: Code Intelligence & LSP (C++, Swift, Go)
-- ==============================================================================
-- Go to Definition (F12 on Mac / gd)
map("n", "<F12>", "<cmd>lua vim.lsp.buf.definition()<CR>", { desc = "Go to Definition (F12)" })
map("n", "gd", "<cmd>lua vim.lsp.buf.definition()<CR>", { desc = "Go to Definition (gd)" })
map("n", "gD", "<cmd>lua vim.lsp.buf.declaration()<CR>", { desc = "Go to Declaration" })
-- Peek / Float Definition (Option+F12 on Mac)
map("n", "<A-F12>", "<cmd>lua vim.lsp.buf.definition()<CR>", { desc = "Peek Definition (Opt+F12)" })
-- Find All References (Shift+F12 on Mac / gr)
map("n", "<S-F12>", "<cmd>Telescope lsp_references<CR>", { desc = "Find References (Shift+F12)" })
map("n", "gr", "<cmd>Telescope lsp_references<CR>", { desc = "Find References (gr)" })
-- Go to Implementation (Cmd+F12 on Mac / gi)
map("n", "<D-F12>", "<cmd>lua vim.lsp.buf.implementation()<CR>", { desc = "Go to Implementation (Cmd+F12)" })
map("n", "gi", "<cmd>lua vim.lsp.buf.implementation()<CR>", { desc = "Go to Implementation" })
map("n", "gt", "<cmd>lua vim.lsp.buf.type_definition()<CR>", { desc = "Type Definition" })
-- Hover Documentation & Signature (K / Ctrl+Shift+Space on Mac)
map("n", "K", "<cmd>lua vim.lsp.buf.hover()<CR>", { desc = "Hover Documentation (K)" })
map("n", "<C-k>", "<cmd>lua vim.lsp.buf.signature_help()<CR>", { desc = "Signature Help" })
map("n", "<C-S-Space>", "<cmd>lua vim.lsp.buf.signature_help()<CR>", { desc = "Parameter Info" })
-- Rename Symbol (F2 on Mac / <leader>rn)
map("n", "<F2>", "<cmd>lua vim.lsp.buf.rename()<CR>", { desc = "Rename Symbol (F2)" })
map("n", "<leader>rn", "<cmd>lua vim.lsp.buf.rename()<CR>", { desc = "Rename Symbol" })
-- Quick Fix / Code Action (Cmd+. on Mac / Alt+Enter / <leader>ca)
map({ "n", "v" }, "<D-.>", "<cmd>lua vim.lsp.buf.code_action()<CR>", { desc = "Code Action (Cmd+.)" })
map({ "n", "v" }, "<A-CR>", "<cmd>lua vim.lsp.buf.code_action()<CR>", { desc = "Code Action (Alt+Enter)" })
map({ "n", "v" }, "<leader>ca", "<cmd>lua vim.lsp.buf.code_action()<CR>", { desc = "Code Actions" })
-- Format Document (Shift+Option+F on Mac / F7 / <leader>cf)
map({ "n", "v" }, "<A-S-f>", "<cmd>lua require('conform').format({ async = true, lsp_fallback = true })<CR>", { desc = "Format Document (Shift+Opt+F)" })
map({ "n", "v" }, "<F7>", "<cmd>lua require('conform').format({ async = true, lsp_fallback = true })<CR>", { desc = "Format Document (F7)" })
map({ "n", "v" }, "<leader>cf", "<cmd>lua require('conform').format({ async = true, lsp_fallback = true })<CR>", { desc = "Format Document" })
-- Switch Header / Source (Cmd+Option+O on Mac / Alt+O / <leader>ch)
map("n", "<D-A-o>", "<cmd>ClangdSwitchSourceHeader<CR>", { desc = "Switch Header/Source (Cmd+Opt+O)" })
map("n", "<A-o>", "<cmd>ClangdSwitchSourceHeader<CR>", { desc = "Switch Header/Source (Opt+O)" })
map("n", "<leader>ch", "<cmd>ClangdSwitchSourceHeader<CR>", { desc = "Switch Header/Source" })
-- Diagnostics navigation
map("n", "[d", "<cmd>lua vim.diagnostic.goto_prev()<CR>", { desc = "Previous Diagnostic" })
map("n", "]d", "<cmd>lua vim.diagnostic.goto_next()<CR>", { desc = "Next Diagnostic" })
map("n", "<leader>d", "<cmd>lua vim.diagnostic.open_float()<CR>", { desc = "Line Diagnostics" })
map("n", "<leader>dl", "<cmd>Telescope diagnostics<CR>", { desc = "Workspace Diagnostics" })
-- Toggle Inlay Hints
map("n", "<leader>th", function()
local is_enabled = vim.lsp.inlay_hint.is_enabled()
vim.lsp.inlay_hint.enable(not is_enabled)
vim.notify("Inlay hints " .. (is_enabled and "disabled" or "enabled"), vim.log.levels.INFO)
end, { desc = "Toggle Inlay Hints" })
-- ==============================================================================
-- 6. Visual Studio on Mac: Debugging (DAP F-Keys)
-- ==============================================================================
-- Start / Continue Debugging (F5 on Mac)
map("n", "<F5>", "<cmd>lua require('dap').continue()<CR>", { desc = "Debug: Start / Continue (F5)" })
-- Toggle Breakpoint (F9 on Mac)
map("n", "<F9>", "<cmd>lua require('dap').toggle_breakpoint()<CR>", { desc = "Debug: Toggle Breakpoint (F9)" })
-- Step Over (F10 on Mac / Cmd+Shift+O)
map("n", "<F10>", "<cmd>lua require('dap').step_over()<CR>", { desc = "Debug: Step Over (F10)" })
-- Step Into (F11 on Mac / Cmd+Shift+I)
map("n", "<F11>", "<cmd>lua require('dap').step_into()<CR>", { desc = "Debug: Step Into (F11)" })
-- Step Out (Shift+F11 on Mac / Cmd+Shift+U)
map("n", "<S-F11>", "<cmd>lua require('dap').step_out()<CR>", { desc = "Debug: Step Out (Shift+F11)" })
-- Stop Debugging (Shift+F5 on Mac)
map("n", "<S-F5>", "<cmd>lua require('dap').terminate()<CR>", { desc = "Debug: Stop (Shift+F5)" })
-- Restart Debugging (Cmd+Shift+F5 on Mac / Ctrl+Shift+F5)
map("n", "<D-S-F5>", "<cmd>lua require('dap').restart()<CR>", { desc = "Debug: Restart (Cmd+Shift+F5)" })
map("n", "<C-S-F5>", "<cmd>lua require('dap').restart()<CR>", { desc = "Debug: Restart (Ctrl+Shift+F5)" })
map("n", "<leader>db", "<cmd>lua require('dap').set_breakpoint(vim.fn.input('Breakpoint condition: '))<CR>", { desc = "Conditional Breakpoint" })
map("n", "<leader>du", "<cmd>lua require('dapui').toggle()<CR>", { desc = "Toggle Debug UI" })
map("n", "<leader>dr", "<cmd>lua require('dap').repl.open()<CR>", { desc = "Open Debug REPL" })
-- ==============================================================================
-- 7. Language Specific Workflows (Go, Swift, CMake)
-- ==============================================================================
-- Go Workflows
map("n", "<leader>gt", "<cmd>TermExec cmd='go test -v ./...'<CR>", { desc = "Go: Run Tests" })
map("n", "<leader>gr", "<cmd>TermExec cmd='go run .'<CR>", { desc = "Go: Run main" })
map("n", "<leader>gb", "<cmd>TermExec cmd='go build -v ./...'<CR>", { desc = "Go: Build" })
-- Swift Workflows
map("n", "<leader>sb", "<cmd>TermExec cmd='swift build'<CR>", { desc = "Swift: Build" })
map("n", "<leader>st", "<cmd>TermExec cmd='swift test'<CR>", { desc = "Swift: Run Tests" })
map("n", "<leader>sr", "<cmd>TermExec cmd='swift run'<CR>", { desc = "Swift: Run" })
-- CMake Workflows
map("n", "<leader>cg", "<cmd>CMakeGenerate<CR>", { desc = "CMake Generate/Configure" })
map("n", "<leader>cb", "<cmd>CMakeBuild<CR>", { desc = "CMake Build" })
map("n", "<leader>cr", "<cmd>CMakeRun<CR>", { desc = "CMake Run Target" })
map("n", "<leader>cd", "<cmd>CMakeDebug<CR>", { desc = "CMake Debug Target" })
map("n", "<leader>ct", "<cmd>CMakeSelectBuildTarget<CR>", { desc = "CMake Select Target" })
map("n", "<leader>cs", "<cmd>CMakeSelectBuildType<CR>", { desc = "CMake Select Build Type" })
map("n", "<leader>cc", "<cmd>CMakeClean<CR>", { desc = "CMake Clean" })
map("n", "<leader>cq", "<cmd>CMakeClose<CR>", { desc = "CMake Close Runner" })
EOF_LUA_CONFIG_KEYMAPS_LUA
cat << 'EOF_LUA_CONFIG_AUTOCMDS_LUA' > "${NVIM_CONFIG_DIR}/lua/config/autocmds.lua"
-- ==============================================================================
-- Autocommands
-- ==============================================================================
local autocmd = vim.api.nvim_create_autocmd
local augroup = vim.api.nvim_create_augroup
-- 1. Highlight on yank (Visual feedback when copying text)
local yank_group = augroup("HighlightYank", { clear = true })
autocmd("TextYankPost", {
group = yank_group,
pattern = "*",
callback = function()
vim.highlight.on_yank({
higroup = "IncSearch",
timeout = 150,
})
end,
})
-- 2. Automatically link compile_commands.json from build dir to root for clangd
local cmake_group = augroup("CMakeClangdLink", { clear = true })
local function link_compile_commands()
local build_dirs = { "build", "build/Debug", "build/Release", "build/RelWithDebInfo", "out", "out/build" }
for _, dir in ipairs(build_dirs) do
local cc_path = dir .. "/compile_commands.json"
if vim.fn.filereadable(cc_path) == 1 then
if vim.fn.filereadable("compile_commands.json") == 0 then
if vim.fn.has("win32") == 1 then
vim.fn.system("cmd /c mklink compile_commands.json " .. cc_path)
else
vim.fn.system("ln -sf " .. cc_path .. " compile_commands.json")
end
vim.notify("Linked " .. cc_path .. " -> compile_commands.json for clangd", vim.log.levels.INFO)
end
break
end
end
end
autocmd({ "User" }, {
group = cmake_group,
pattern = { "CMakeGeneratePost", "CMakeBuildPost" },
callback = link_compile_commands,
})
autocmd({ "VimEnter", "BufEnter" }, {
group = cmake_group,
pattern = { "*.c", "*.cpp", "*.cc", "*.cxx", "*.h", "*.hpp" },
callback = link_compile_commands,
once = true,
})
-- 3. Restore cursor position upon reopening files
local restore_cursor_group = augroup("RestoreCursor", { clear = true })
autocmd("BufReadPost", {
group = restore_cursor_group,
callback = function(args)
local mark = vim.api.nvim_buf_get_mark(args.buf, '"')
local line_count = vim.api.nvim_buf_line_count(args.buf)
if mark[1] > 0 and mark[1] <= line_count then
pcall(vim.api.nvim_win_set_cursor, 0, mark)
end
end,
})
-- 4. Quick close with 'q' for inspection/utility windows
local close_with_q = augroup("CloseWithQ", { clear = true })
autocmd("FileType", {
group = close_with_q,
pattern = {
"help",
"lspinfo",
"man",
"qf",
"checkhealth",
"dap-float",
"notify",
"dropbar_menu",
},
callback = function(event)
vim.bo[event.buf].buflisted = false
vim.keymap.set("n", "q", "<cmd>close<CR>", { buffer = event.buf, silent = true })
end,
})
-- 5. Resize splits when window is resized
local resize_splits = augroup("ResizeSplits", { clear = true })
autocmd("VimResized", {
group = resize_splits,
callback = function()
local current_tab = vim.fn.tabpagenr()
vim.cmd("tabdo wincmd =")
vim.cmd("tabnext " .. current_tab)
end,
})
EOF_LUA_CONFIG_AUTOCMDS_LUA
cat << 'EOF_LUA_CONFIG_LAZY_LUA' > "${NVIM_CONFIG_DIR}/lua/config/lazy.lua"
-- ==============================================================================
-- Lazy.nvim Plugin Manager Bootstrap
-- ==============================================================================
local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim"
if not (vim.uv or vim.loop).fs_stat(lazypath) then
local lazyrepo = "https://github.com/folke/lazy.nvim.git"
local out = vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath })
if vim.v.shell_error ~= 0 then
vim.api.nvim_echo({
{ "Failed to clone lazy.nvim:\n", "ErrorMsg" },
{ out, "WarningMsg" },
{ "\nPress any key to exit..." },
}, true, {})
vim.fn.getchar()
os.exit(1)
end
end
vim.opt.rtp:prepend(lazypath)
require("lazy").setup("plugins", {
defaults = {
lazy = false, -- Load plugins immediately by default for instant IDE readiness
version = false,
},
install = {
colorscheme = { "vscode", "default" },
},
ui = {
border = "rounded",
icons = {
cmd = "⌘",
config = "🛠",
event = "⚡",
ft = "📂",
init = "⚙",
keys = "🗝",
plugin = "🔌",
runtime = "💻",
require = "🌙",
source = "📄",
start = "🚀",
task = "📌",
lazy = "💤 ",
},
},
performance = {
rtp = {
disabled_plugins = {
"gzip",
"tarPlugin",
"tohtml",
"tutor",
"zipPlugin",
},
},
},
})
EOF_LUA_CONFIG_LAZY_LUA
cat << 'EOF_LUA_PLUGINS_THEME_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/theme.lua"
-- ==============================================================================
-- Theme: VSCode Dark+ Theme
-- ==============================================================================
return {
{
"Mofiqul/vscode.nvim",
lazy = false,
priority = 1000,
config = function()
local vscode = require("vscode")
vscode.setup({
transparent = false,
italic_comments = true,
underline_links = true,
cursorline = true,
disable_nvimtree_bg = false,
color_overrides = {
vscBack = "#1E1E1E",
vscLeftDark = "#252526",
vscLeftMid = "#2D2D2D",
vscLineNumber = "#858585",
vscCursorDark = "#222222",
vscCursorDarkDark = "#181818",
vscTabOther = "#2D2D2D",
vscTabCurrent = "#1E1E1E",
},
group_overrides = {
-- VSCode styled floating windows and borders
NormalFloat = { bg = "#252526" },
FloatBorder = { fg = "#454545", bg = "#252526" },
FloatTitle = { fg = "#4FC1FF", bg = "#252526", bold = true },
-- VSCode search & visual selections
Visual = { bg = "#264F78" },
Search = { bg = "#613214" },
IncSearch = { bg = "#515C6A" },
CurSearch = { bg = "#515C6A" },
-- VSCode line numbering and cursor line
CursorLine = { bg = "#282828" },
CursorLineNr = { fg = "#CCCCCC", bold = true },
LineNr = { fg = "#858585" },
-- VSCode Tabline / Bufferline
TabLine = { bg = "#2D2D2D", fg = "#969696" },
TabLineFill = { bg = "#181818" },
TabLineSel = { bg = "#1E1E1E", fg = "#FFFFFF" },
-- VSCode Diagnostics
DiagnosticError = { fg = "#F14C4C" },
DiagnosticWarn = { fg = "#CCA700" },
DiagnosticInfo = { fg = "#3794FF" },
DiagnosticHint = { fg = "#B5CEA8" },
-- Git Gutter (VSCode style)
GitSignsAdd = { fg = "#2EA043" },
GitSignsChange = { fg = "#0078D4" },
GitSignsDelete = { fg = "#DA3633" },
-- Treesitter C++ specifics
["@type.builtin.cpp"] = { fg = "#4EC9B0" },
["@type.cpp"] = { fg = "#4EC9B0" },
["@keyword.cpp"] = { fg = "#569CD6" },
["@keyword.control.cpp"] = { fg = "#C586C0" },
["@function.call.cpp"] = { fg = "#DCDCAA" },
["@function.method.call.cpp"] = { fg = "#DCDCAA" },
["@string.cpp"] = { fg = "#CE9178" },
["@number.cpp"] = { fg = "#B5CEA8" },
["@constant.cpp"] = { fg = "#4FC1FF" },
["@variable.parameter.cpp"] = { fg = "#9CDCFE" },
["@variable.member.cpp"] = { fg = "#9CDCFE" },
["@comment.cpp"] = { fg = "#6A9955", italic = true },
},
})
vscode.load()
end,
},
}
EOF_LUA_PLUGINS_THEME_LUA
cat << 'EOF_LUA_PLUGINS_UI_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/ui.lua"
-- ==============================================================================
-- UI Components: File Explorer, Statusline, Tabline, Breadcrumbs, Git, Indent Guides
-- ==============================================================================
return {
-- 1. Web Devicons (VSCode file & directory icons)
{
"nvim-tree/nvim-web-devicons",
lazy = false,
opts = {
default = true,
strict = true,
},
},
-- 2. VSCode-like File Explorer (NvimTree)
{
"nvim-tree/nvim-tree.lua",
dependencies = { "nvim-tree/nvim-web-devicons" },
lazy = false,
config = function()
-- Disable netrw for nvim-tree
vim.g.loaded_netrw = 1
vim.g.loaded_netrwPlugin = 1
require("nvim-tree").setup({
view = {
width = 32,
side = "left",
signcolumn = "yes",
},
renderer = {
highlight_git = true,
highlight_opened_files = "name",
indent_markers = {
enable = true,
inline_arrows = true,
icons = {
corner = "└",
edge = "│",
item = "│",
bottom = "─",
none = " ",
},
},
icons = {
web_devicons = {
file = { enable = true, color = true },
folder = { enable = false, color = true },
},
show = {
file = true,
folder = true,
folder_arrow = true,
git = true,
diagnostics = true,
},
glyphs = {
default = "📄",
symlink = "🔗",
folder = {
arrow_closed = "▸",
arrow_open = "▾",
default = "📁",
open = "📂",
empty = "📁",
empty_open = "📂",
symlink = "📂",
symlink_open = "📂",
},
git = {
unstaged = "●",
staged = "✓",
unmerged = "",
renamed = "➜",
untracked = "★",
deleted = "✗",
ignored = "◌",
},
},
},
},
diagnostics = {
enable = true,
show_on_dirs = true,
icons = {
hint = "󰌶",
info = "󰋽",
warning = "󰀪",
error = "󰅚",
},
},
filters = {
dotfiles = false,
custom = { "^.git$", "\\.o$", "\\.so$", "\\.a$", "\\.dylib$", "\\.DS_Store$" },
},
actions = {
open_file = {
quit_on_open = false,
resize_window = true,
},
},
git = {
enable = true,
ignore = false,
},
})
end,
},
-- 3. VSCode-like Tab Bar (Bufferline)
{
"akinsho/bufferline.nvim",
version = "*",
dependencies = { "nvim-tree/nvim-web-devicons", "famiu/bufdelete.nvim" },
lazy = false,
config = function()
local bufferline = require("bufferline")
bufferline.setup({
options = {
mode = "buffers",
style_preset = bufferline.style_preset.default,
themable = true,
numbers = "none",
close_command = function(bufnr)
require("bufdelete").bufdelete(bufnr, false)
end,
right_mouse_command = function(bufnr)
require("bufdelete").bufdelete(bufnr, false)
end,
indicator = {
icon = "▎",
style = "icon",
},
buffer_close_icon = "󰅖",
modified_icon = "●",
close_icon = "",
left_trunc_marker = "",
right_trunc_marker = "",
max_name_length = 24,
max_prefix_length = 15,
truncate_names = true,
tab_size = 20,
diagnostics = "nvim_lsp",
diagnostics_update_in_insert = false,
diagnostics_indicator = function(count, level, diagnostics_dict, context)
local icon = level:match("error") and "󰅚 " or (level:match("warning") and "󰀪 " or "")
return " " .. icon .. count
end,
offsets = {
{
filetype = "NvimTree",
text = "EXPLORER",
text_align = "left",
separator = true,
},
},
color_icons = true,
show_buffer_icons = true,
show_buffer_close_icons = true,
show_close_icon = false,
show_tab_indicators = true,
persist_buffer_sort = true,
separator_style = "thin",
always_show_bufferline = true,
hover = {
enabled = true,
delay = 200,
reveal = { "close" },
},
},
})
end,
},
-- 4. VSCode-like Status Bar (Lualine)
{
"nvim-lualine/lualine.nvim",
dependencies = { "nvim-tree/nvim-web-devicons" },
lazy = false,
config = function()
require("lualine").setup({
options = {
theme = "vscode",
component_separators = { left = "│", right = "│" },
section_separators = { left = "", right = "" },
globalstatus = true,
disabled_filetypes = {
statusline = { "dashboard", "alpha", "starter" },
},
},
sections = {
lualine_a = { { "mode", icon = "" } },
lualine_b = {
{ "branch", icon = "" },
{
"diff",
symbols = { added = " ", modified = " ", removed = " " },
diff_color = {
added = { fg = "#2EA043" },
modified = { fg = "#0078D4" },
removed = { fg = "#DA3633" },
},
},
},
lualine_c = {
{
"filename",
file_status = true,
newfile_status = true,
path = 1, -- Relative path
symbols = {
modified = " ●",
readonly = " 🔒",
unnamed = "[No Name]",
newfile = "[New]",
},
},
},
lualine_x = {
{
"diagnostics",
sources = { "nvim_lsp" },
symbols = { error = "󰅚 ", warn = "󰀪 ", info = "󰋽 ", hint = "󰌶 " },
colored = true,
},
{ "filetype", icon_only = false },
{ "encoding" },
{ "fileformat" },
},
lualine_y = { "progress" },
lualine_z = {
{ "location", icon = "Ln" },
},
},
extensions = { "nvim-tree", "toggleterm", "lazy", "quickfix" },
})
end,
},
-- 5. VSCode Breadcrumb Navigation Bar (Dropbar)
{
"Bekaboo/dropbar.nvim",
lazy = false,
opts = {
bar = {
enable = function(buf, win, _)
return vim.api.nvim_buf_is_valid(buf)
and vim.api.nvim_win_is_valid(win)
and vim.bo[buf].buftype == ""
and vim.bo[buf].filetype ~= "NvimTree"
and vim.bo[buf].filetype ~= "toggleterm"
and vim.bo[buf].filetype ~= "dapui_scopes"
and vim.bo[buf].filetype ~= "dapui_breakpoints"
end,
},
},
},
-- 6. VSCode-like Git Diff Gutter Signs (Gitsigns)
{
"lewis6991/gitsigns.nvim",
lazy = false,
opts = {
signs = {
add = { text = "┃" },
change = { text = "┃" },
delete = { text = " " },
topdelete = { text = "▔" },
changedelete = { text = "┇" },
untracked = { text = "┆" },
},
signcolumn = true,
numhl = false,
linehl = false,
word_diff = false,
current_line_blame = true,
current_line_blame_opts = {
virt_text = true,
virt_text_pos = "eol",
delay = 500,
},
current_line_blame_formatter = " <author>, <author_time:%R> • <summary>",
},
},
-- 7. VSCode-like Indentation Guides (Indent Blankline)
{
"lukas-reineke/indent-blankline.nvim",
main = "ibl",
lazy = false,
opts = {
indent = {
char = "│",
tab_char = "│",
},
scope = {
enabled = true,
show_start = false,
show_end = false,
injected_languages = true,
highlight = { "Function", "Label" },
},
exclude = {
filetypes = {
"help",
"alpha",
"dashboard",
"nvim-tree",
"Trouble",
"trouble",
"lazy",
"mason",
"notify",
"toggleterm",
"lazyterm",
},
},
},
},
}
EOF_LUA_PLUGINS_UI_LUA
cat << 'EOF_LUA_PLUGINS_LSP_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/lsp.lua"
-- ==============================================================================
-- Language Server Protocol (LSP) Setup for C++, Swift, Go, CMake & Lua
-- Cross-platform & Idempotent (macOS, RedHat/Linux)
-- ==============================================================================
return {
{
"neovim/nvim-lspconfig",
lazy = false,
dependencies = {
"williamboman/mason.nvim",
"williamboman/mason-lspconfig.nvim",
"hrsh7th/cmp-nvim-lsp",
},
config = function()
-- Setup Mason package manager
require("mason").setup({
ui = {
border = "rounded",
icons = {
package_installed = "✓",
package_pending = "➜",
package_uninstalled = "✗",
},
},
})
-- Setup Mason LSP config (auto-installs across macOS and RedHat/Linux)
require("mason-lspconfig").setup({
ensure_installed = {
"clangd",
"gopls",
"cmake",
"lua_ls",
},
automatic_installation = true,
})
-- Enhance LSP capabilities for nvim-cmp
local capabilities = vim.lsp.protocol.make_client_capabilities()
local cmp_lsp_ok, cmp_nvim_lsp = pcall(require, "cmp_nvim_lsp")
if cmp_lsp_ok then
capabilities = cmp_nvim_lsp.default_capabilities(capabilities)
end
-- Customize diagnostic signs to look like VSCode
local signs = {
Error = "󰅚 ",
Warn = "󰀪 ",
Hint = "󰌶 ",
Info = "󰋽 ",
}
for type, icon in pairs(signs) do
local hl = "DiagnosticSign" .. type
vim.fn.sign_define(hl, { text = icon, texthl = hl, numhl = "" })
end
-- Configure Diagnostic display
vim.diagnostic.config({
virtual_text = {
prefix = "●",
source = "if_many",
},
signs = true,
underline = true,
update_in_insert = false,
severity_sort = true,
float = {
focused = false,
style = "minimal",
border = "rounded",
source = "always",
header = "",
prefix = "",
},
})
-- Configure floating window borders for hover and signature help
vim.lsp.handlers["textDocument/hover"] = function(err, result, ctx, config)
config = config or {}
config.border = "rounded"
return vim.lsp.handlers.hover(err, result, ctx, config)
end
vim.lsp.handlers["textDocument/signatureHelp"] = function(err, result, ctx, config)
config = config or {}
config.border = "rounded"
return vim.lsp.handlers.signature_help(err, result, ctx, config)
end
-- Common on_attach function (enables inlay hints where supported)
local on_attach = function(client, bufnr)
if client.server_capabilities.inlayHintProvider then
pcall(function()
vim.lsp.inlay_hint.enable(true, { bufnr = bufnr })
end)
end
end
-- Helper to resolve sourcekit-lsp path portably across macOS and Linux/RedHat
local function get_sourcekit_cmd()
if vim.fn.executable("sourcekit-lsp") == 1 then
return { "sourcekit-lsp" }
end
if vim.fn.has("mac") == 1 then
local xcrun_path = vim.fn.trim(vim.fn.system("xcrun --find sourcekit-lsp 2>/dev/null"))
if xcrun_path ~= "" and vim.v.shell_error == 0 then
return { xcrun_path }
end
end
local linux_search_paths = {
"/usr/bin/sourcekit-lsp",
"/usr/local/bin/sourcekit-lsp",
"/opt/swift/usr/bin/sourcekit-lsp",
"/usr/lib/swift/bin/sourcekit-lsp",
}
for _, path in ipairs(linux_search_paths) do
if vim.fn.executable(path) == 1 then
return { path }
end
end
return { "sourcekit-lsp" }
end
-- LSP Configurations
local lsp_configs = {
-- 1. C / C++ (Clangd)
clangd = {
cmd = {
"clangd",
"--background-index",
"--clang-tidy",
"--header-insertion=iwyu",
"--completion-style=detailed",
"--function-arg-placeholders",
"--fallback-style=llvm",
},
root_markers = {
".clangd",
".clang-tidy",
".clang-format",
"compile_commands.json",
"compile_flags.txt",
"CMakeLists.txt",
"build",
".git",
},
init_options = {
usePlaceholders = true,
completeUnimported = true,
clangdFileStatus = true,
},
},
-- 2. Go (Gopls)
gopls = {
cmd = { "gopls" },
root_markers = { "go.work", "go.mod", ".git" },
settings = {
gopls = {
analyses = {
unusedparams = true,
shadow = true,
nilness = true,
unusedwrite = true,
useany = true,
},
staticcheck = true,
gofumpt = true,
usePlaceholders = true,
completeUnimported = true,
hints = {
assignVariableTypes = true,
compositeLiteralFields = true,
compositeLiteralTypes = true,
constantValues = true,
functionTypeParameters = true,
parameterNames = true,
rangeVariableTypes = true,
},
},
},
},
-- 3. Swift (SourceKit-LSP)
sourcekit = {
cmd = get_sourcekit_cmd(),
filetypes = { "swift", "objc", "objcpp" },
root_markers = { "Package.swift", ".git", "compile_commands.json" },
},
-- 4. CMake (neocmake / cmake-language-server)
cmake = {
root_markers = { "CMakeLists.txt", "build", ".git" },
},
-- 5. Lua Language Server
lua_ls = {
settings = {
Lua = {
runtime = { version = "LuaJIT" },
diagnostics = { globals = { "vim" } },
workspace = {
library = vim.api.nvim_get_runtime_file("", true),
checkThirdParty = false,
},
telemetry = { enable = false },
},
},
},
}
-- Register servers using modern vim.lsp.config API (Neovim 0.11+) or lspconfig fallback
if vim.lsp.config and type(vim.lsp.config) == "table" and vim.lsp.enable then
for server, cfg in pairs(lsp_configs) do
cfg.capabilities = capabilities
cfg.on_attach = on_attach
vim.lsp.config(server, cfg)
vim.lsp.enable(server)
end
else
local lspconfig = require("lspconfig")
for server, cfg in pairs(lsp_configs) do
cfg.capabilities = capabilities
cfg.on_attach = on_attach
if cfg.root_markers then
cfg.root_dir = lspconfig.util.root_pattern(unpack(cfg.root_markers))
end
if lspconfig[server] then
lspconfig[server].setup(cfg)
end
end
end
end,
},
}
EOF_LUA_PLUGINS_LSP_LUA
cat << 'EOF_LUA_PLUGINS_CMP_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/cmp.lua"
-- ==============================================================================
-- Autocomplete & Snippets: nvim-cmp with VSCode Codicons
-- ==============================================================================
return {
{
"hrsh7th/nvim-cmp",
lazy = false,
dependencies = {
"hrsh7th/cmp-nvim-lsp",
"hrsh7th/cmp-buffer",
"hrsh7th/cmp-path",
"hrsh7th/cmp-cmdline",
"L3MON4D3/LuaSnip",
"saadparwaiz1/cmp_luasnip",
"rafamadriz/friendly-snippets",
"onsails/lspkind.nvim",
},
config = function()
local cmp = require("cmp")
local luasnip = require("luasnip")
local lspkind = require("lspkind")
-- Load VSCode style snippets from friendly-snippets
require("luasnip.loaders.from_vscode").lazy_load()
cmp.setup({
snippet = {
expand = function(args)
luasnip.lsp_expand(args.body)
end,
},
window = {
completion = cmp.config.window.bordered({
border = "rounded",
winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:Visual,Search:None",
}),
documentation = cmp.config.window.bordered({
border = "rounded",
winhighlight = "Normal:NormalFloat,FloatBorder:FloatBorder,CursorLine:Visual,Search:None",
}),
},
mapping = cmp.mapping.preset.insert({
["<C-k>"] = cmp.mapping.select_prev_item(),
["<C-j>"] = cmp.mapping.select_next_item(),
["<C-b>"] = cmp.mapping.scroll_docs(-4),
["<C-f>"] = cmp.mapping.scroll_docs(4),
["<C-Space>"] = cmp.mapping.complete(),
["<C-e>"] = cmp.mapping.abort(),
["<CR>"] = cmp.mapping.confirm({ select = false }),
-- Tab / Shift-Tab support like VSCode
["<Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_next_item()
elseif luasnip.expand_or_jumpable() then
luasnip.expand_or_jump()
else
fallback()
end
end, { "i", "s" }),
["<S-Tab>"] = cmp.mapping(function(fallback)
if cmp.visible() then
cmp.select_prev_item()
elseif luasnip.jumpable(-1) then
luasnip.jump(-1)
else
fallback()
end
end, { "i", "s" }),
}),
sources = cmp.config.sources({
{ name = "nvim_lsp", priority = 1000 },
{ name = "luasnip", priority = 750 },
{ name = "path", priority = 500 },
{ name = "buffer", priority = 250, keyword_length = 3 },
}),
formatting = {
format = lspkind.cmp_format({
mode = "symbol_text",
preset = "codicons",
maxwidth = 50,
ellipsis_char = "...",
show_labelDetails = true,
before = function(entry, vim_item)
-- Source labeling like VSCode
vim_item.menu = ({
nvim_lsp = "[LSP]",
luasnip = "[Snippet]",
buffer = "[Buffer]",
path = "[Path]",
})[entry.source.name]
return vim_item
end,
}),
},
})
-- Setup cmdline completion
cmp.setup.cmdline(":", {
mapping = cmp.mapping.preset.cmdline(),
sources = cmp.config.sources({
{ name = "path" },
}, {
{ name = "cmdline" },
}),
})
cmp.setup.cmdline("/", {
mapping = cmp.mapping.preset.cmdline(),
sources = {
{ name = "buffer" },
},
})
end,
},
}
EOF_LUA_PLUGINS_CMP_LUA
cat << 'EOF_LUA_PLUGINS_TREESITTER_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/treesitter.lua"
-- ==============================================================================
-- Syntax Highlighting: Tree-sitter (C++, Swift, Go, CMake, Lua, etc.)
-- Fully Portable & Idempotent (Precompiled Parser Sources)
-- ==============================================================================
return {
{
"nvim-treesitter/nvim-treesitter",
branch = "master",
build = ":TSUpdate",
lazy = false,
config = function()
local status_ok, configs = pcall(require, "nvim-treesitter.configs")
if not status_ok then
return
end
-- Ensure swift uses pre-generated parser C files for seamless portability
local parser_config = require("nvim-treesitter.parsers").get_parser_configs()
parser_config.swift = {
install_info = {
url = "https://github.com/alex-pinkus/tree-sitter-swift",
files = { "src/parser.c", "src/scanner.c" },
branch = "main",
generate_requires_npm = false,
requires_generate_from_grammar = false,
},
filetype = "swift",
}
configs.setup({
ensure_installed = {
"c",
"cpp",
"swift",
"go",
"gomod",
"gowork",
"gosum",
"cmake",
"make",
"lua",
"vim",
"vimdoc",
"json",
"yaml",
"toml",
"bash",
"markdown",
"markdown_inline",
"python",
},
auto_install = true,
highlight = {
enable = true,
additional_vim_regex_highlighting = false,
},
indent = {
enable = true,
},
incremental_selection = {
enable = true,
keymaps = {
init_selection = "<C-space>",
node_incremental = "<C-space>",
scope_incremental = false,
node_decremental = "<bs>",
},
},
})
end,
},
}
EOF_LUA_PLUGINS_TREESITTER_LUA
cat << 'EOF_LUA_PLUGINS_FORMATTING_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/formatting.lua"
-- ==============================================================================
-- Code Formatting: conform.nvim (clang-format, goimports/gofmt, swiftformat, stylua)
-- ==============================================================================
return {
{
"stevearc/conform.nvim",
lazy = false,
opts = {
formatters_by_ft = {
c = { "clang-format" },
cpp = { "clang-format" },
objc = { "clang-format" },
objcpp = { "clang-format" },
go = { "goimports", "gofumpt", "gofmt" },
swift = { "swiftformat" },
cmake = { "cmake_format" },
lua = { "stylua" },
python = { "isort", "black" },
json = { "prettier" },
yaml = { "prettier" },
markdown = { "prettier" },
},
format_on_save = {
timeout_ms = 1000,
lsp_fallback = true,
},
formatters = {
["clang-format"] = {
prepend_args = { "-style=file", "-fallback-style=llvm" },
},
},
},
},
}
EOF_LUA_PLUGINS_FORMATTING_LUA
cat << 'EOF_LUA_PLUGINS_DAP_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/dap.lua"
-- ==============================================================================
-- Debugging (DAP): C++, Swift, and Go Debuggers with VSCode UI
-- ==============================================================================
return {
{
"mfussenegger/nvim-dap",
lazy = false,
dependencies = {
"rcarriga/nvim-dap-ui",
"nvim-neotest/nvim-nio",
"theHamsta/nvim-dap-virtual-text",
"jay-babu/mason-nvim-dap.nvim",
"williamboman/mason.nvim",
},
config = function()
local dap = require("dap")
local dapui = require("dapui")
-- Setup Mason DAP integration
require("mason-nvim-dap").setup({
ensure_installed = { "codelldb", "delve" },
automatic_installation = true,
handlers = {},
})
-- Setup DAP Virtual Text (shows variable values inline like VSCode)
require("nvim-dap-virtual-text").setup({
enabled = true,
commented = true,
highlight_changed_variables = true,
show_stop_reason = true,
})
-- Setup VSCode-style DAP UI
dapui.setup({
icons = { expanded = "▾", collapsed = "▸", current_frame = "▸" },
mappings = {
expand = { "<CR>", "<2-LeftMouse>" },
open = "o",
remove = "d",
edit = "e",
repl = "r",
toggle = "t",
},
layouts = {
{
elements = {
{ id = "scopes", size = 0.4 },
{ id = "breakpoints", size = 0.2 },
{ id = "stacks", size = 0.2 },
{ id = "watches", size = 0.2 },
},
size = 40,
position = "left", -- VSCode left debug sidebar
},
{
elements = {
{ id = "repl", size = 0.5 },
{ id = "console", size = 0.5 },
},
size = 12,
position = "bottom", -- VSCode bottom debug console
},
},
floating = {
max_height = nil,
max_width = nil,
border = "rounded",
mappings = {
close = { "q", "<Esc>" },
},
},
})
-- VSCode Breakpoint Signs & Highlights
vim.api.nvim_set_hl(0, "DapBreakpoint", { fg = "#E51400" })
vim.api.nvim_set_hl(0, "DapBreakpointCondition", { fg = "#CCA700" })
vim.api.nvim_set_hl(0, "DapLogPoint", { fg = "#3794FF" })
vim.api.nvim_set_hl(0, "DapStopped", { fg = "#FFE700", bg = "#3B3A32", bold = true })
vim.fn.sign_define("DapBreakpoint", { text = "●", texthl = "DapBreakpoint", linehl = "", numhl = "" })
vim.fn.sign_define("DapBreakpointCondition", { text = "◆", texthl = "DapBreakpointCondition", linehl = "", numhl = "" })
vim.fn.sign_define("DapLogPoint", { text = "◈", texthl = "DapLogPoint", linehl = "", numhl = "" })
vim.fn.sign_define("DapStopped", { text = "▶", texthl = "DapStopped", linehl = "DapStopped", numhl = "DapStopped" })
-- Automatically open and close DAP UI
dap.listeners.after.event_initialized["dapui_config"] = function()
dapui.open()
end
dap.listeners.before.event_terminated["dapui_config"] = function()
dapui.close()
end
dap.listeners.before.event_exited["dapui_config"] = function()
dapui.close()
end
-- 1. Configure CodeLLDB Adapter (for C, C++, Swift, and Rust)
local mason_registry = require("mason-registry")
local codelldb_path = "codelldb"
if mason_registry.is_installed("codelldb") then
local codelldb = mason_registry.get_package("codelldb")
local extension_path = codelldb:get_install_path() .. "/extension/"
codelldb_path = extension_path .. "adapter/codelldb"
end
dap.adapters.codelldb = {
type = "server",
port = "${port}",
executable = {
command = codelldb_path,
args = { "--port", "${port}" },
},
}
-- 2. Configure Delve Adapter (for Go)
dap.adapters.delve = function(callback, config)
if config.mode == "remote" and config.port then
callback({
type = "server",
host = config.host or "127.0.0.1",
port = config.port,
})
return
end
callback({
type = "server",
port = "${port}",
executable = {
command = "dlv",
args = { "dap", "-l", "127.0.0.1:${port}" },
},
})
end
-- C & C++ debug configurations
local cpp_config = {
{
name = "Launch C/C++ Executable (codelldb)",
type = "codelldb",
request = "launch",
program = function()
local default_path = vim.fn.getcwd() .. "/build/"
return vim.fn.input("Path to executable: ", default_path, "file")
end,
cwd = "${workspaceFolder}",
stopOnEntry = false,
args = {},
runInTerminal = false,
},
{
name = "Attach to Process (codelldb)",
type = "codelldb",
request = "attach",
pid = require("dap.utils").pick_process,
args = {},
},
}
dap.configurations.cpp = cpp_config
dap.configurations.c = cpp_config
-- Swift debug configuration (using codelldb)
dap.configurations.swift = {
{
name = "Launch Swift Executable (codelldb)",
type = "codelldb",
request = "launch",
program = function()
local build_dir = vim.fn.getcwd() .. "/.build/debug/"
if vim.fn.isdirectory(build_dir) == 1 then
return vim.fn.input("Path to executable: ", build_dir, "file")
end
return vim.fn.input("Path to executable: ", vim.fn.getcwd() .. "/", "file")
end,
cwd = "${workspaceFolder}",
stopOnEntry = false,
args = {},
runInTerminal = false,
},
{
name = "Attach to Swift Process (codelldb)",
type = "codelldb",
request = "attach",
pid = require("dap.utils").pick_process,
args = {},
},
}
-- Go debug configurations (using Delve)
dap.configurations.go = {
{
type = "delve",
name = "Debug Go (Current File)",
request = "launch",
program = "${file}",
},
{
type = "delve",
name = "Debug Go (Package ./...)",
request = "launch",
program = "${workspaceFolder}",
},
{
type = "delve",
name = "Debug Go Test (Current File)",
request = "launch",
mode = "test",
program = "${file}",
},
{
type = "delve",
name = "Debug Go Test (Package)",
request = "launch",
mode = "test",
program = "./${relativeFileDirname}",
},
{
type = "delve",
name = "Attach Go (Process)",
request = "attach",
mode = "local",
processId = require("dap.utils").pick_process,
},
}
end,
},
}
EOF_LUA_PLUGINS_DAP_LUA
cat << 'EOF_LUA_PLUGINS_CMAKE_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/cmake.lua"
-- ==============================================================================
-- CMake Tools Integration: Build, Run, Debug, and Intellisense Bridge
-- ==============================================================================
return {
{
"Civitasv/cmake-tools.nvim",
lazy = false,
dependencies = {
"nvim-lua/plenary.nvim",
"mfussenegger/nvim-dap",
},
opts = {
cmake_command = "cmake",
cmake_build_directory = "build/${variant:buildType}",
cmake_generate_options = { "-DCMAKE_EXPORT_COMPILE_COMMANDS=1" },
cmake_build_options = {},
cmake_console_size = 10,
cmake_show_console = "always",
cmake_dap_configuration = {
name = "cpp",
type = "codelldb",
request = "launch",
stopOnEntry = false,
runInTerminal = true,
console = "integratedTerminal",
},
cmake_variants_message = {
short = { show = true },
long = { show = true, max_length = 40 },
},
cmake_always_use_terminal = false,
cmake_quickfix = {
show = "only_on_error",
position = "belowright",
size = 10,
encoding = "utf-8",
auto_close_when_success = true,
},
cmake_runner = {
name = "terminal",
opts = {},
default_opts = {
terminal = {
name = "Main Terminal",
prefix_name = "[CMake-Tools]: ",
split_direction = "horizontal",
split_size = 11,
single_terminal_per_instance = true,
single_terminal_per_tab = true,
keep_terminal_static_location = true,
auto_scroll = true,
},
},
},
cmake_notifications = {
runner = { enabled = true },
executor = { enabled = true },
spinner = { "⠋", "⠙", "⠹", "⠸", "⠼", "⠴", "⠦", "⠧", "⠇", "⠏" },
refresh_rate_ms = 100,
},
},
},
}
EOF_LUA_PLUGINS_CMAKE_LUA
cat << 'EOF_LUA_PLUGINS_TELESCOPE_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/telescope.lua"
-- ==============================================================================
-- Fuzzy Finder: Telescope (VSCode Quick Open, Live Grep, Symbols)
-- Idempotent & Portable
-- ==============================================================================
return {
{
"nvim-telescope/telescope.nvim",
lazy = false,
dependencies = {
"nvim-lua/plenary.nvim",
{
"nvim-telescope/telescope-fzf-native.nvim",
build = "make",
cond = function()
return vim.fn.executable("make") == 1
end,
},
},
config = function()
local telescope = require("telescope")
local actions = require("telescope.actions")
-- Determine portable find command (fd / fdfind fallback)
local find_cmd = nil
if vim.fn.executable("fd") == 1 then
find_cmd = { "fd", "--type", "f", "--strip-cwd-prefix", "--hidden", "--exclude", ".git" }
elseif vim.fn.executable("fdfind") == 1 then
find_cmd = { "fdfind", "--type", "f", "--strip-cwd-prefix", "--hidden", "--exclude", ".git" }
end
telescope.setup({
defaults = {
prompt_prefix = " 🔍 ",
selection_caret = " ❯ ",
path_display = { "truncate" },
sorting_strategy = "ascending",
layout_config = {
horizontal = {
prompt_position = "top", -- Top search bar like VSCode
preview_width = 0.55,
results_width = 0.8,
},
vertical = {
mirror = false,
},
width = 0.87,
height = 0.80,
preview_cutoff = 120,
},
mappings = {
i = {
["<C-n>"] = actions.cycle_history_next,
["<C-p>"] = actions.cycle_history_prev,
["<C-j>"] = actions.move_selection_next,
["<C-k>"] = actions.move_selection_previous,
["<C-c>"] = actions.close,
["<CR>"] = actions.select_default,
},
n = {
["q"] = actions.close,
["<CR>"] = actions.select_default,
},
},
file_ignore_patterns = {
"%.git/",
"node_modules/",
"build/",
"bin/",
"%.build/",
"%.o$",
"%.a$",
"%.so$",
"%.dylib$",
"%.DS_Store$",
},
},
pickers = {
find_files = {
hidden = true,
find_command = find_cmd,
},
},
})
pcall(telescope.load_extension, "fzf")
end,
},
}
EOF_LUA_PLUGINS_TELESCOPE_LUA
cat << 'EOF_LUA_PLUGINS_TERMINAL_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/terminal.lua"
-- ==============================================================================
-- Integrated Terminal: ToggleTerm (VSCode Bottom Terminal Panel)
-- ==============================================================================
return {
{
"akinsho/toggleterm.nvim",
version = "*",
lazy = false,
opts = {
size = function(term)
if term.direction == "horizontal" then
return 14
elseif term.direction == "vertical" then
return vim.o.columns * 0.4
end
end,
open_mapping = [[<C-`>]],
hide_numbers = true,
shade_terminals = true,
shading_factor = 2,
start_in_insert = true,
insert_mappings = true,
terminal_mappings = true,
persist_size = true,
persist_mode = true,
direction = "horizontal", -- Bottom drawer like VSCode
close_on_exit = true,
shell = vim.o.shell,
auto_scroll = true,
float_opts = {
border = "curved",
winblend = 0,
},
},
},
}
EOF_LUA_PLUGINS_TERMINAL_LUA
cat << 'EOF_LUA_PLUGINS_CODING_LUA' > "${NVIM_CONFIG_DIR}/lua/plugins/coding.lua"
-- ==============================================================================
-- Coding Utilities: Autopairs, Comments, Which-Key, Todo-Comments, BufDelete
-- ==============================================================================
return {
-- 1. Auto-closing pairs
{
"windwp/nvim-autopairs",
event = "InsertEnter",
config = function()
local autopairs = require("nvim-autopairs")
autopairs.setup({
check_ts = true,
ts_config = {
lua = { "string" },
cpp = { "string_literal" },
c = { "string_literal" },
},
disable_filetype = { "TelescopePrompt" },
fast_wrap = {
map = "<M-e>",
chars = { "{", "[", "(", '"', "'" },
pattern = [=[[%'%"%>%]%)%}%,]]=],
end_key = "$",
keys = "qwertyuiopzxcvbnmasdfghjkl",
check_comma = true,
highlight = "Search",
highlight_grey = "Comment",
},
})
-- Integrate autopairs with nvim-cmp
local cmp_autopairs = require("nvim-autopairs.completion.cmp")
local cmp_ok, cmp = pcall(require, "cmp")
if cmp_ok then
cmp.event:on("confirm_done", cmp_autopairs.on_confirm_done())
end
end,
},
-- 2. VSCode-like Commenting (Ctrl+/ or gcc)
{
"numToStr/Comment.nvim",
lazy = false,
config = function()
require("Comment").setup({
padding = true,
sticky = true,
toggler = {
line = "gcc",
block = "gbc",
},
opleader = {
line = "gc",
block = "gb",
},
})
-- VSCode Ctrl+/ commenting keymaps
vim.keymap.set("n", "<C-/>", function()
require("Comment.api").toggle.linewise.current()
end, { desc = "Toggle comment" })
vim.keymap.set("n", "<C-_>", function()
require("Comment.api").toggle.linewise.current()
end, { desc = "Toggle comment" })
vim.keymap.set("v", "<C-/>", "<ESC><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<CR>", { desc = "Toggle comment" })
vim.keymap.set("v", "<C-_>", "<ESC><cmd>lua require('Comment.api').toggle.linewise(vim.fn.visualmode())<CR>", { desc = "Toggle comment" })
end,
},
-- 3. Which-Key popup guide
{
"folke/which-key.nvim",
event = "VeryLazy",
opts = {
preset = "modern",
win = {
border = "rounded",
},
},
},
-- 4. Todo Comments (VSCode Todo Tree style)
{
"folke/todo-comments.nvim",
dependencies = { "nvim-lua/plenary.nvim" },
lazy = false,
opts = {
signs = true,
keywords = {
FIX = { icon = " ", color = "error", alt = { "FIXME", "BUG", "FIXIT", "ISSUE" } },
TODO = { icon = " ", color = "info" },
HACK = { icon = " ", color = "warning" },
WARN = { icon = " ", color = "warning", alt = { "WARNING", "XXX" } },
PERF = { icon = " ", alt = { "OPTIM", "PERFORMANCE", "OPTIMIZE" } },
NOTE = { icon = " ", color = "hint", alt = { "INFO" } },
TEST = { icon = "⏲ ", color = "test", alt = { "TESTING", "PASSED", "FAILED" } },
},
},
},
-- 5. Buffer delete helper (closes tab without closing split layout)
{
"famiu/bufdelete.nvim",
lazy = false,
},
}
EOF_LUA_PLUGINS_CODING_LUA
cat << 'EOF_QUERIES_SWIFT_HIGHLIGHTS_SCM' > "${NVIM_CONFIG_DIR}/queries/swift/highlights.scm"
[
"."
";"
":"
","
] @punctuation.delimiter
[
"("
")"
"["
"]"
"{"
"}"
] @punctuation.bracket
; Identifiers
(type_identifier) @type
[
(self_expression)
(super_expression)
] @variable.builtin
; Declarations
[
"func"
"deinit"
] @keyword.function
[
(visibility_modifier)
(member_modifier)
(function_modifier)
(property_modifier)
(parameter_modifier)
(inheritance_modifier)
(mutation_modifier)
] @keyword.modifier
(simple_identifier) @variable
(function_declaration
(simple_identifier) @function.method)
(protocol_function_declaration
name: (simple_identifier) @function.method)
(init_declaration
"init" @constructor)
(parameter
external_name: (simple_identifier) @variable.parameter)
(parameter
name: (simple_identifier) @variable.parameter)
(type_parameter
(type_identifier) @variable.parameter)
(inheritance_constraint
(identifier
(simple_identifier) @variable.parameter))
(equality_constraint
(identifier
(simple_identifier) @variable.parameter))
[
"protocol"
"extension"
"indirect"
"nonisolated"
"override"
"convenience"
"required"
"some"
"any"
"weak"
"unowned"
"didSet"
"willSet"
"subscript"
"let"
"var"
(throws)
(where_keyword)
(getter_specifier)
(setter_specifier)
(modify_specifier)
(else)
(as_operator)
] @keyword
[
"enum"
"struct"
"class"
"typealias"
] @keyword.type
[
"async"
"await"
] @keyword.coroutine
(shebang_line) @keyword.directive
(class_body
(property_declaration
(pattern
(simple_identifier) @variable.member)))
(protocol_property_declaration
(pattern
(simple_identifier) @variable.member))
(navigation_expression
(navigation_suffix
(simple_identifier) @variable.member))
(value_argument
name: (value_argument_label
(simple_identifier) @variable.member))
(import_declaration
"import" @keyword.import)
(enum_entry
"case" @keyword)
(modifiers
(attribute
"@" @attribute
(user_type
(type_identifier) @attribute)))
; Function calls
(call_expression
(simple_identifier) @function.call) ; foo()
(call_expression
; foo.bar.baz(): highlight the baz()
(navigation_expression
(navigation_suffix
(simple_identifier) @function.call)))
(call_expression
(prefix_expression
(simple_identifier) @function.call)) ; .foo()
((navigation_expression
(simple_identifier) @type) ; SomeType.method(): highlight SomeType as a type
(#lua-match? @type "^[A-Z]"))
(directive) @keyword.directive
; See https://docs.swift.org/swift-book/documentation/the-swift-programming-language/lexicalstructure/#Keywords-and-Punctuation
(diagnostic) @function.macro
; Statements
(for_statement
"for" @keyword.repeat)
(for_statement
"in" @keyword.repeat)
[
"while"
"repeat"
"continue"
"break"
] @keyword.repeat
(guard_statement
"guard" @keyword.conditional)
(if_statement
"if" @keyword.conditional)
(switch_statement
"switch" @keyword.conditional)
(switch_entry
"case" @keyword)
(switch_entry
"fallthrough" @keyword)
(switch_entry
(default_keyword) @keyword)
"return" @keyword.return
(ternary_expression
[
"?"
":"
] @keyword.conditional.ternary)
[
(try_operator)
"do"
(throw_keyword)
(catch_keyword)
] @keyword.exception
(statement_label) @label
; Comments
[
(comment)
(multiline_comment)
] @comment @spell
((comment) @comment.documentation
(#lua-match? @comment.documentation "^///[^/]"))
((comment) @comment.documentation
(#lua-match? @comment.documentation "^///$"))
((multiline_comment) @comment.documentation
(#lua-match? @comment.documentation "^/[*][*][^*].*[*]/$"))
; String literals
(line_str_text) @string
(str_escaped_char) @string.escape
(multi_line_str_text) @string
(raw_str_part) @string
(raw_str_end_part) @string
(line_string_literal
[
"\\("
")"
] @punctuation.special)
(multi_line_string_literal
[
"\\("
")"
] @punctuation.special)
(raw_str_interpolation
[
(raw_str_interpolation_start)
")"
] @punctuation.special)
[
"\""
"\"\"\""
] @string
; Lambda literals
(lambda_literal
"in" @keyword.operator)
; Basic literals
[
(integer_literal)
(hex_literal)
(oct_literal)
(bin_literal)
] @number
(real_literal) @number.float
(boolean_literal) @boolean
(nil_literal) @constant.builtin
(wildcard_pattern) @character.special
; Regex literals
(regex_literal) @string.regexp
; Operators
(custom_operator) @operator
[
"+"
"-"
"*"
"/"
"%"
"="
"+="
"-="
"*="
"/="
"<"
">"
"<<"
">>"
"<="
">="
"++"
"--"
"^"
"&"
"&&"
"|"
"||"
"~"
"%="
"!="
"!=="
"=="
"==="
"?"
"??"
"->"
"..<"
"..."
(bang)
] @operator
(type_arguments
[
"<"
">"
] @punctuation.bracket)
EOF_QUERIES_SWIFT_HIGHLIGHTS_SCM
bootstrap_neovim() {
info "Bootstrapping lazy.nvim plugin manager..."
local lazy_dir="${HOME}/.local/share/nvim/lazy/lazy.nvim"
if [[ ! -d "${lazy_dir}" ]]; then
git clone --filter=blob:none --branch=stable https://github.com/folke/lazy.nvim.git "${lazy_dir}"
fi
info "Syncing Neovim plugins in headless mode..."
nvim --headless "+Lazy! sync" +qa || true
info "Installing language servers, debuggers, and formatters via Mason..."
nvim --headless "+MasonInstall clangd gopls cmake-language-server lua-language-server codelldb delve clang-format stylua goimports gofumpt" +qa || true
info "Compiling Tree-sitter syntax parsers..."
nvim --headless "+TSInstallSync c cpp go gomod gowork gosum cmake make lua vim vimdoc json yaml bash python" +qa || true
}
print_summary() {
echo ""
echo -e "${GREEN}${BOLD}================================================================${NC}"
echo -e "${GREEN}${BOLD} ✓ Neovim VSCode IDE Setup Completed Successfully! ${NC}"
echo -e "${GREEN}${BOLD}================================================================${NC}"
echo ""
echo -e "${BOLD}Language Capabilities Configured:${NC}"
echo -e " • ${CYAN}C / C++${NC} : clangd LSP + clang-format + CodeLLDB Debugger + CMake"
echo -e " • ${CYAN}Swift${NC} : sourcekit-lsp + swiftformat + CodeLLDB Debugger"
echo -e " • ${CYAN}Golang${NC} : gopls LSP + goimports/gofumpt + Delve Debugger"
echo -e " • ${CYAN}CMake${NC} : cmake-language-server + cmake-tools.nvim"
echo -e " • ${CYAN}Lua${NC} : lua-language-server + stylua"
echo ""
echo -e "${BOLD}Visual Studio on Mac Shortcuts:${NC}"
echo -e " • ${YELLOW}Cmd + B / Ctrl + B${NC} : Toggle Sidebar File Explorer"
echo -e " • ${YELLOW}Cmd + P / Ctrl + P${NC} : Quick Open / Find Files"
echo -e " • ${YELLOW}Cmd + Shift + P / F1${NC} : Command Palette"
echo -e " • ${YELLOW}Cmd + J / Ctrl + \`${NC} : Toggle Bottom Terminal Drawer"
echo -e " • ${YELLOW}Cmd + S / Ctrl + S${NC} : Save File"
echo -e " • ${YELLOW}Cmd + W${NC} : Close Tab"
echo -e " • ${YELLOW}Cmd + Option + Left/Right${NC}: Previous / Next Tab"
echo -e " • ${YELLOW}F12 / gd${NC} : Go to Definition"
echo -e " • ${YELLOW}Shift + F12 / gr${NC} : Find References"
echo -e " • ${YELLOW}F2${NC} : Rename Symbol"
echo -e " • ${YELLOW}Cmd + .${NC} : Quick Fix / Code Action"
echo -e " • ${YELLOW}Shift + Option + F${NC} : Format Document"
echo -e " • ${YELLOW}F5 / F9 / F10 / F11${NC} : Debug (Start / Breakpoint / Step Over / Step Into)"
echo ""
echo -e "Launch Neovim now with: ${BOLD}nvim${NC}"
}
main() {
echo -e "${BLUE}${BOLD}================================================================${NC}"
echo -e "${BLUE}${BOLD} Neovim VSCode IDE Automated Setup (C++, Swift, Go, CMake) ${NC}"
echo -e "${BLUE}${BOLD}================================================================${NC}"
local os
os="$(detect_os)"
install_dependencies "$os"
backup_existing_config
write_config_files
bootstrap_neovim
print_summary
}
main "$@"
@abdulkareem-siddiq

Copy link
Copy Markdown
Author

🚀 One-Line Execution

curl -fsSL https://gist.githubusercontent.com/abdulkareem-siddiq/2ff4f8dd64fac65d03dbdec9e4456fa8/raw/setup_neovim_vscode.sh | bash

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment