Last active
September 2, 2026 18:39
-
-
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
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| #!/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 "$@" |
Author
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
🚀 One-Line Execution
curl -fsSL https://gist.githubusercontent.com/abdulkareem-siddiq/2ff4f8dd64fac65d03dbdec9e4456fa8/raw/setup_neovim_vscode.sh | bash