# Neovim IDE Setup Guide A comprehensive guide to setting up Neovim as a full-featured IDE for Python, Shell scripts, and more using Lua configuration. ## Table of Contents 1. [Prerequisites](#prerequisites) 2. [Directory Structure](#directory-structure) 3. [Configuration Files](#configuration-files) - [init.lua](#initlua) - [lua/plugins/init.lua](#luapluginsinitlua) - [lua/plugins/lsp.lua](#luapluginslsplua) - [lua/plugins/dap.lua](#luapluginsdaplua) - [lua/plugins/treesitter.lua](#luapluginstreesitterlua) - [lua/plugins/telescope.lua](#luapluginstelescopelua) - [lua/plugins/nvimtree.lua](#luapluginsnvimtreelua) - [lua/plugins/cmp.lua](#luapluginscmplua) - [lua/plugins/toggleterm.lua](#luapluginstoggletermlua) - [lua/plugins/formatter.lua](#luapluginsformatterlua) 4. [Installing Language Servers](#installing-language-servers) 5. [Keybindings Reference](#keybindings-reference) 6. [First Launch](#first-launch) --- ## Prerequisites ### Install Neovim (v0.9+) **Ubuntu/Debian:** ```bash sudo add-apt-repository ppa:neovim-ppa/unstable sudo apt update sudo apt install neovim ``` **Fedora:** ```bash sudo dnf install neovim ``` **Arch Linux:** ```bash sudo pacman -S neovim ``` **macOS:** ```bash brew install neovim ``` ### Install Required Tools ```bash # Node.js (for LSP servers via Mason) curl -fsSL https://fnm.vercel.app/install | bash source ~/.bashrc fnm install --latest # Python (for Python LSP and debugging) pip install python-lsp-server debugpy # ripgrep (for telescope live grep) sudo apt install ripgrep # Ubuntu sudo dnf install ripgrep # Fedora sudo pacman -S ripgrep # Arch brew install ripgrep # macOS # git (for plugin installation) sudo apt install git ``` --- ## Directory Structure Create the following directory structure: ```bash mkdir -p ~/.config/nvim/lua/plugins ``` Your final structure should look like: ``` ~/.config/nvim/ ├── init.lua └── lua/ └── plugins/ ├── init.lua ├── lsp.lua ├── dap.lua ├── treesitter.lua ├── telescope.lua ├── nvimtree.lua ├── cmp.lua ├── toggleterm.lua └── formatter.lua ``` --- ## Configuration Files ### ~/.config/nvim/init.lua Main entry point for Neovim configuration. ```lua -- Leader key vim.g.mapleader = " " vim.g.maplocalleader = " " -- General settings vim.opt.number = true vim.opt.relativenumber = true vim.opt.tabstop = 4 vim.opt.shiftwidth = 4 vim.opt.expandtab = true vim.opt.smartindent = true vim.opt.wrap = false vim.opt.scrolloff = 8 vim.opt.signcolumn = "yes" vim.opt.termguicolors = true vim.opt.cursorline = true -- Enable clipboard vim.opt.clipboard = "unnamedplus" -- Search settings vim.opt.ignorecase = true vim.opt.smartcase = true vim.opt.hlsearch = true -- Split settings vim.opt.splitright = true vim.opt.splitbelow = true -- Performance vim.opt.updatetime = 50 vim.opt.timeoutlen = 300 -- Set colorscheme vim.cmd.colorscheme "tokyonight" -- Load plugins require("plugins") -- Keybindings local keymap = vim.keymap.set -- Better window navigation keymap("n", "", "h", { desc = "Navigate left" }) keymap("n", "", "j", { desc = "Navigate down" }) keymap("n", "", "k", { desc = "Navigate up" }) keymap("n", "", "l", { desc = "Navigate right" }) -- Resize windows keymap("n", "", ":resize -2", { desc = "Resize window up" }) keymap("n", "", ":resize +2", { desc = "Resize window down" }) keymap("n", "", ":vertical resize -2", { desc = "Resize window left" }) keymap("n", "", ":vertical resize +2", { desc = "Resize window right" }) -- Move text up/down keymap("n", "", ":m .+1==", { desc = "Move line down" }) keymap("n", "", ":m .-2==", { desc = "Move line up" }) keymap("v", "", ":m '>+1gv=gv", { desc = "Move selection down" }) keymap("v", "", ":m '<-2gv=gv", { desc = "Move selection up" }) -- Stay in indent mode keymap("v", "<", "", ">gv", { desc = "Indent right" }) -- Better paste keymap("v", "p", '"_dP', { desc = "Paste without yanking" }) -- Clear highlights keymap("n", "h", ":nohlsearch", { desc = "Clear search highlights" }) -- Save and quit keymap("n", "w", ":w", { desc = "Save file" }) keymap("n", "q", ":q", { desc = "Quit" }) keymap("n", "Q", ":qa!", { desc = "Force quit all" }) -- Toggle options keymap("n", "tn", ":set nu!", { desc = "Toggle line numbers" }) keymap("n", "tr", ":set rnu!", { desc = "Toggle relative numbers" }) ``` --- ### ~/.config/nvim/lua/plugins/init.lua Plugin manager setup using lazy.nvim. ```lua -- Bootstrap lazy.nvim local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" if not vim.loop.fs_stat(lazypath) then vim.fn.system({ "git", "clone", "--filter=blob:none", "https://github.com/folke/lazy.nvim.git", "--branch=stable", lazypath, }) end vim.opt.rtp:prepend(lazypath) -- Plugin specifications require("lazy").setup({ -- Theme { "folke/tokyonight.nvim", lazy = false }, -- Plugin manager { "folke/lazy.nvim", version = "*" }, -- LSP { "neovim/nvim-lspconfig" }, { "williamboman/mason.nvim" }, { "williamboman/mason-lspconfig.nvim" }, -- Autocomplete { "hrsh7th/nvim-cmp" }, { "hrsh7th/cmp-nvim-lsp" }, { "hrsh7th/cmp-buffer" }, { "hrsh7th/cmp-path" }, { "hrsh7th/cmp-cmdline" }, { "L3MON4D3/LuaSnip" }, { "saadparwaiz1/cmp_luasnip" }, -- Treesitter (syntax) { "nvim-treesitter/nvim-treesitter", build = ":TSUpdate" }, { "nvim-treesitter/nvim-treesitter-textobjects" }, -- Fuzzy finder { "nvim-telescope/telescope.nvim", dependencies = { "nvim-lua/plenary.nvim" } }, -- File tree { "nvim-tree/nvim-tree.lua" }, { "nvim-tree/nvim-web-devicons" }, -- Terminal { "akinsho/toggleterm.nvim" }, -- Debugging { "mfussenegger/nvim-dap" }, { "rcarriga/nvim-dap-ui" }, { "theHamsta/nvim-dap-virtual-text" }, -- Formatters/Linters { "nvimtools/none-ls.nvim" }, { "nvim-lua/plenary.nvim" }, -- Utility { "windwp/nvim-autopairs" }, { "numToStr/Comment.nvim" }, }) ``` --- ### ~/.config/nvim/lua/plugins/lsp.lua LSP configuration for Python and Shell scripts. ```lua -- Setup Mason (LSP installer) require("mason").setup({ ui = { border = "rounded", icons = { package_installed = "✓", package_pending = "➜", package_uninstalled = "✗", }, }, log_level = vim.log.levels.INFO, max_concurrent_installers = 4, }) -- LSP config local lspconfig = require("lspconfig") local cmp_nvim_lsp = require("cmp_nvim_lsp") -- Capabilities for autocomplete local capabilities = cmp_nvim_lsp.default_capabilities() -- Diagnostic settings vim.diagnostic.config({ virtual_text = true, signs = true, underline = true, update_in_insert = false, severity_sort = true, float = { border = "rounded", source = true, }, }) -- Signs for diagnostics 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 -- LSP handlers vim.lsp.handlers["textDocument/hover"] = vim.lsp.with(vim.lsp.handlers.hover, { border = "rounded", }) vim.lsp.handlers["textDocument/signatureHelp"] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = "rounded", }) -- LSP Keybindings local function lsp_keymaps(bufnr) local opts = { buffer = bufnr, silent = true } vim.keymap.set("n", "gd", vim.lsp.buf.definition, opts) vim.keymap.set("n", "gD", vim.lsp.buf.declaration, opts) vim.keymap.set("n", "gi", vim.lsp.buf.implementation, opts) vim.keymap.set("n", "gr", vim.lsp.buf.references, opts) vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) vim.keymap.set("n", "rn", vim.lsp.buf.rename, opts) vim.keymap.set("n", "ca", vim.lsp.buf.code_action, opts) vim.keymap.set("n", "e", vim.diagnostic.open_float, opts) vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts) end -- Python LSP lspconfig.pyright.setup({ capabilities = capabilities, on_attach = function(client, bufnr) lsp_keymaps(bufnr) -- Disable virtual text for python if needed -- client.server_capabilities.semanticTokensProvider = nil end, settings = { python = { analysis = { typeCheckingMode = "basic", autoSearchPaths = true, useLibraryCodeForTypes = true, }, }, }, }) -- Bash LSP lspconfig.bashls.setup({ capabilities = capabilities, on_attach = function(client, bufnr) lsp_keymaps(bufnr) end, }) -- HTML, CSS, JSON (optional) lspconfig.html.setup({ capabilities = capabilities, on_attach = lsp_keymaps, }) lspconfig.jsonls.setup({ capabilities = capabilities, on_attach = lsp_keymaps, }) -- Lua LSP (for neovim config editing) lspconfig.lua_ls.setup({ capabilities = capabilities, on_attach = function(client, bufnr) lsp_keymaps(bufnr) end, settings = { Lua = { runtime = { version = "LuaJIT", }, diagnostics = { globals = { "vim" }, }, workspace = { library = vim.api.nvim_get_runtime_file("", true), checkThirdParty = false, }, telemetry = { enable = false, }, }, }, }) -- Setup Mason LSP config require("mason-lspconfig").setup({ ensure_installed = { "pyright", "bashls", "html", "jsonls", "lua_ls", }, handlers = { function(server_name) require("lspconfig")[server_name].setup({ capabilities = capabilities, }) end, }, }) ``` --- ### ~/.config/nvim/lua/plugins/dap.lua Debug Adapter Protocol configuration for debugging Python. ```lua local dap = require("dap") local dapui = require("dapui") -- Setup DAP UI dapui.setup({ icons = { expanded = "▾", collapsed = "▸", current_frame = "▸" }, mappings = { expand = { "", "<2-LeftMouse>" }, open = "o", remove = "d", edit = "e", repl = "r", toggle = "t", }, expand_lines = vim.fn.has("nvim-0.7") == 1, layouts = { { elements = { { id = "scopes", size = 0.25 }, { id = "breakpoints", size = 0.25 }, { id = "stacks", size = 0.25 }, { id = "watches", size = 0.25 }, }, size = 0.25, position = "right", }, { elements = { { id = "repl", size = 0.5 }, { id = "console", size = 0.5 }, }, position = "bottom", size = 0.25, }, }, floating = { max_height = nil, max_width = nil, border = "rounded", mappings = { close = { "q", "" }, }, }, windows = { indent = 1 }, }) -- Open DAP UI automatically 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 -- Python debug adapter configuration dap.configurations.python = { { type = "python", request = "launch", name = "Launch file", program = "${file}", pythonPath = function() return vim.fn.exepath("python3") or "python" end, }, { type = "python", request = "launch", name = "Debug current file (integrated terminal)", program = "${file}", console = "integratedTerminal", pythonPath = function() return vim.fn.exepath("python3") or "python" end, }, { type = "python", request = "launch", name = "Debug with arguments", program = "${file}", args = function() local args = vim.fn.input("Args: ", ""):split(" ") return args end, console = "integratedTerminal", pythonPath = function() return vim.fn.exepath("python3") or "python" end, }, } -- DAP keybindings vim.keymap.set("n", "db", dap.toggle_breakpoint, { desc = "Toggle breakpoint" }) vim.keymap.set("n", "dc", dap.continue, { desc = "Continue" }) vim.keymap.set("n", "ds", dap.step_over, { desc = "Step over" }) vim.keymap.set("n", "di", dap.step_into, { desc = "Step into" }) vim.keymap.set("n", "do", dap.step_out, { desc = "Step out" }) vim.keymap.set("n", "dr", dap.repl.open, { desc = "Open REPL" }) vim.keymap.set("n", "dl", dap.run_last, { desc = "Run last debug config" }) vim.keymap.set("n", "du", dapui.toggle, { desc = "Toggle DAP UI" }) ``` --- ### ~/.config/nvim/lua/plugins/treesitter.lua Treesitter configuration for syntax highlighting. ```lua require("nvim-treesitter.configs").setup({ ensure_installed = { "python", "bash", "lua", "html", "css", "javascript", "typescript", "json", "yaml", "markdown", "markdown_inline", "go", "rust", "c", "cpp", }, sync_install = false, auto_install = true, highlight = { enable = true, additional_vim_regex_highlighting = false, }, indent = { enable = true, }, textobjects = { select = { enable = true, lookahead = true, keymaps = { ["af"] = "@function.outer", ["if"] = "@function.inner", ["ac"] = "@class.outer", ["ic"] = "@class.inner", ["aa"] = "@parameter.outer", ["ia"] = "@parameter.inner", }, }, move = { enable = true, set_jumps = true, goto_next_start = { ["]f"] = "@function.outer", ["]c"] = "@class.outer", }, goto_next_end = { ["]F"] = "@function.outer", ["]C"] = "@class.outer", }, goto_previous_start = { ["[f"] = "@function.outer", ["[c"] = "@class.outer", }, goto_previous_end = { ["[F"] = "@function.outer", ["[C"] = "@class.outer", }, }, swap = { enable = true, swap_next = { ["sp"] = "@parameter.inner", }, swap_previous = { ["sP"] = "@parameter.inner", }, }, }, }) ``` --- ### ~/.config/nvim/lua/plugins/telescope.lua Telescope fuzzy finder configuration. ```lua local telescope = require("telescope") local actions = require("telescope.actions") telescope.setup({ defaults = { prompt_prefix = " ", selection_caret = " ", path_display = { "truncate" }, sorting_strategy = "ascending", layout_strategy = "horizontal", layout_config = { horizontal = { prompt_position = "top", preview_width = 0.55, results_width = 0.8, }, vertical = { mirror = false, }, width = 0.87, height = 0.80, preview_cutoff = 120, }, mappings = { i = { [""] = actions.cycle_history_next, [""] = actions.cycle_history_prev, [""] = actions.move_selection_next, [""] = actions.move_selection_previous, [""] = actions.close, [""] = actions.move_selection_next, [""] = actions.move_selection_previous, [""] = actions.select_default, [""] = actions.select_horizontal, [""] = actions.select_vertical, [""] = actions.select_tab, [""] = actions.preview_scrolling_up, [""] = actions.preview_scrolling_down, }, n = { [""] = actions.close, [""] = actions.select_default, [""] = actions.select_horizontal, [""] = actions.select_vertical, [""] = actions.select_tab, ["j"] = actions.move_selection_next, ["k"] = actions.move_selection_previous, ["H"] = actions.move_to_top, ["M"] = actions.move_to_middle, ["L"] = actions.move_to_bottom, ["gg"] = actions.move_to_top, ["G"] = actions.move_to_bottom, [""] = actions.preview_scrolling_up, [""] = actions.preview_scrolling_down, }, }, }, pickers = { find_files = { theme = "dropdown", previewer = false, }, live_grep = { theme = "ivy", }, buffers = { theme = "dropdown", previewer = false, }, }, }) -- Load telescope extensions pcall(telescope.load_extension, "fzf") -- Telescope keybindings local builtin = require("telescope.builtin") vim.keymap.set("n", "ff", builtin.find_files, { desc = "Find files" }) vim.keymap.set("n", "fg", builtin.live_grep, { desc = "Live grep" }) vim.keymap.set("n", "fb", builtin.buffers, { desc = "Find buffers" }) vim.keymap.set("n", "fh", builtin.help_tags, { desc = "Help tags" }) vim.keymap.set("n", "fr", builtin.oldfiles, { desc = "Recent files" }) vim.keymap.set("n", "fc", builtin.grep_string, { desc = "Grep string under cursor" }) vim.keymap.set("n", "fd", builtin.diagnostics, { desc = "Find diagnostics" }) ``` --- ### ~/.config/nvim/lua/plugins/nvimtree.lua File tree configuration. ```lua require("nvim-tree").setup({ on_attach = function(bufnr) local api = require("nvim-tree.api") local function opts(desc) return { desc = "nvim-tree: " .. desc, buffer = bufnr, noremap = true, silent = true, nowait = true } end vim.keymap.set("n", "", api.node.open.edit, opts("Open")) vim.keymap.set("n", "", api.node.open.preview, opts("Open Preview")) vim.keymap.set("n", ">", api.node.navigate.sibling.next, opts("Next Sibling")) vim.keymap.set("n", "<", api.node.navigate.sibling.prev, opts("Previous Sibling")) vim.keymap.set("n", ".", api.node.run.cmd, opts("Run Command")) vim.keymap.set("n", "-", api.tree.change_root_to_parent, opts("Up")) vim.keymap.set("n", "a", api.fs.create, opts("Create File")) vim.keymap.set("n", "bd", api.node.mbx.trash, opts("Trash")) vim.keymap.set("n", "bn", api.fs.rename, opts("Rename")) vim.keymap.set("n", "bmv", api.fs.rename_basename, opts("Rename: Basename")) vim.keymap.set("n", "bt", api.fs.copy.node_to_clipboard, opts("Copy To Clipboard")) vim.keymap.set("n", "bp", api.fs.paste_from_clipboard, opts("Paste From Clipboard")) vim.keymap.set("n", "q", api.tree.close, opts("Close")) vim.keymap.set("n", "R", api.tree.reload, opts("Refresh")) vim.keymap.set("n", "f", api.live_filter.start, opts("Filter")) vim.keymap.set("n", "F", api.live_filter.clear, opts("Clean Filter")) vim.keymap.set("n", "g?", api.tree.toggle_help, opts("Help")) vim.keymap.set("n", "W", api.tree.collapse_all, opts("Collapse")) vim.keymap.set("n", "E", api.tree.expand_all, opts("Expand All")) vim.keymap.set("n", "S", api.node.search.manual, opts("Search")) vim.keymap.set("n", "U", api.tree.toggle_custom_filter, opts("Toggle Filter")) vim.keymap.set("n", "]", api.node.navigate.diagnostics.next, opts("Next Diagnostic")) vim.keymap.set("n", "[", api.node.navigate.diagnostics.prev, opts("Prev Diagnostic")) end, sort_by = "case_sensitive", view = { width = 30, hide_root_folder = false, side = "left", number = false, relativenumber = false, signcolumn = "yes", }, renderer = { group_empty = true, indent_width = 1, indent_markers = { enable = true, inline_arrows = true, icons = { corner = "└", edge = "│", item = "│", bottom = "─", none = " ", }, }, icons = { webdev_colors = true, git_placement = "after", padding = " ", symlink_arrow = " ➛ ", show = { file = true, folder = true, folder_arrow = true, git = true, }, glyphs = { default = " ", symlink = "S", bookmark = "B", folder = { arrow_closed = "▸", arrow_open = "▾", default = "D", open = "D", empty = "E", empty_open = "E", symlink = "S", symlink_open = "S", }, git = { unstaged = "✗", staged = "✓", unmerged = "✦", renamed = "➜", untracked = "★", ignored = "◌", }, }, }, }, filters = { dotfiles = false, git_clean = false, no_buffer = false, custom = { "node_modules", ".cache", "__pycache__" }, exclude = {}, }, actions = { use_system_clipboard = true, change_dir = { enable = true, global = false, restrict_above_cwd = false, }, file_popup = { open_win_config = { col = 1, row = 1, relative = "cursor", border = "shadow", style = "minimal", }, }, open_file = { quit_on_open = false, resize_window = true, window_picker = { enable = true, chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890", exclude = { filetype = { "notify", "packer", "qf", "diff", "fugitive", "Outline" }, buftype = { "terminal", "help" }, }, }, }, remove_file = { close_buffer = true, }, }, trash = { cmd = "trash", }, }) -- Nvim-tree keybindings vim.keymap.set("n", "e", ":NvimTreeToggle", { desc = "Toggle file tree" }) vim.keymap.set("n", "o", ":NvimTreeFocus", { desc = "Focus file tree" }) ``` --- ### ~/.config/nvim/lua/plugins/cmp.lua Autocomplete configuration. ```lua local cmp = require("cmp") local luasnip = require("luasnip") require("luasnip.loaders.from_vscode").lazy_load() local has_words_before = function() local line, col = unpack(vim.api.nvim_win_get_cursor(0)) return col ~= 0 and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil end cmp.setup({ snippet = { expand = function(args) luasnip.lsp_expand(args.body) end, }, mapping = cmp.mapping.preset.insert({ [""] = cmp.mapping.scroll_docs(-4), [""] = cmp.mapping.scroll_docs(4), [""] = cmp.mapping.complete(), [""] = cmp.mapping.abort(), [""] = cmp.mapping.confirm({ select = true }), [""] = cmp.mapping(function(fallback) if cmp.visible() then cmp.select_next_item() elseif luasnip.expand_or_jumpable() then luasnip.expand_or_jump() elseif has_words_before() then cmp.complete() else fallback() end end, { "i", "s" }), [""] = 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" }, { name = "luasnip" }, { name = "path" }, }, { { name = "buffer", keyword_length = 3 }, }), formatting = { fields = { "kind", "abbr", "menu" }, format = function(entry, vim_item) local kind_icons = { Text = "󰉿", Method = "󰆧", Function = "󰊕", Constructor = "", Field = "󰇽", Variable = "󰀡", Class = "󰠱", Interface = "", Module = "", Property = "󰜢", Unit = "󰑭", Value = "󰎠", Enum = "", Keyword = "󰌋", Snippet = "", Color = "󰏘", File = "󰈙", Reference = "󰈇", Folder = "󰉋", EnumMember = "", Constant = "󰏿", Struct = "󰙅", Event = "", Operator = "󰆕", TypeParameter = "", } vim_item.kind = string.format("%s %s", kind_icons[vim_item.kind], vim_item.kind) vim_item.menu = ({ nvim_lsp = "[LSP]", luasnip = "[Snip]", buffer = "[Buf]", path = "[Path]", })[entry.source.name] return vim_item end, }, window = { completion = cmp.config.window.bordered(), documentation = cmp.config.window.bordered(), }, }) -- Command line 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" }, }, }) ``` --- ### ~/.config/nvim/lua/plugins/toggleterm.lua Integrated terminal configuration. ```lua require("toggleterm").setup({ size = function(term) if term.direction == "horizontal" then return 15 elseif term.direction == "vertical" then return vim.o.columns * 0.4 end end, open_mapping = [[]], hide_numbers = true, shade_filetypes = {}, shade_terminals = true, shading_factor = 2, start_in_insert = true, insert_mappings = true, terminal_mappings = true, persist_size = true, direction = "float", close_on_exit = true, shell = vim.o.shell, float_opts = { border = "curved", winblend = 0, highlights = { border = "Normal", background = "Normal", }, }, }) -- Terminal keybindings local Terminal = require("toggleterm.terminal").Terminal local lazygit = Terminal:new({ cmd = "lazygit", hidden = true, direction = "float", float_opts = { border = "curved", }, }) function _lazygit_toggle() lazygit:toggle() end vim.keymap.set("n", "gg", "lua _lazygit_toggle()", { desc = "Toggle lazygit" }) vim.keymap.set("n", "tf", "ToggleTerm direction=float", { desc = "Toggle float terminal" }) vim.keymap.set("n", "th", "ToggleTerm direction=horizontal", { desc = "Toggle horizontal terminal" }) vim.keymap.set("n", "tv", "ToggleTerm direction=vertical", { desc = "Toggle vertical terminal" }) ``` --- ### ~/.config/nvim/lua/plugins/formatter.lua Formatter and linter configuration using none-ls. ```lua local null_ls = require("null-ls") local formatting = null_ls.builtins.formatting local diagnostics = null_ls.builtins.diagnostics null_ls.setup({ debug = false, sources = { -- Python formatting.black, formatting.isort, diagnostics.pylint, diagnostics.mypy, -- Shell formatting.shfmt, diagnostics.shellcheck, -- Lua formatting.stylua, -- JavaScript/TypeScript formatting.prettier, formatting.eslint_d, -- JSON/YAML formatting.jsonlint, formatting.yamllint, }, on_attach = function(client, bufnr) if client.supports_method("textDocument/formatting") then vim.keymap.set("n", "f", function() vim.lsp.buf.format({ async = false }) end, { buffer = bufnr, desc = "Format buffer" }) end end, }) -- Formatter keybindings vim.keymap.set("n", "f", vim.lsp.buf.format, { desc = "Format buffer" }) ``` --- ## Installing Language Servers After launching Neovim for the first time with this configuration: 1. Open Neovim: `nvim` 2. Wait for lazy.nvim to install all plugins (this may take a few minutes) 3. After plugins are installed, install language servers: - Press `ms` to open Mason (or run `:Mason`) - Install the following: - `pyright` (Python) - `bash-language-server` (Shell/Bash) - `lua-language-server` (Lua) - `html-lsp` (HTML) - `json-lsp` (JSON) - `prettier` (Formatting) - `shellcheck` (Shell linting) - `shfmt` (Shell formatting) - `black` (Python formatting) - `mypy` (Python type checking) --- ## Keybindings Reference ### General | Keybinding | Action | |------------|--------| | `` | Leader key | | `h` | Clear search highlights | | `w` | Save file | | `q` | Quit | | `tn` | Toggle line numbers | | `tr` | Toggle relative numbers | ### Window Navigation | Keybinding | Action | |------------|--------| | `` | Navigate left | | `` | Navigate down | | `` | Navigate up | | `` | Navigate right | | `` | Resize window up | | `` | Resize window down | | `` | Resize window left | | `` | Resize window right | ### Telescope (Fuzzy Finder) | Keybinding | Action | |------------|--------| | `ff` | Find files | | `fg` | Live grep | | `fb` | Find buffers | | `fh` | Help tags | | `fr` | Recent files | | `fc` | Grep string under cursor | | `fd` | Find diagnostics | ### NvimTree (File Tree) | Keybinding | Action | |------------|--------| | `e` | Toggle file tree | | `o` | Focus file tree | ### LSP | Keybinding | Action | |------------|--------| | `gd` | Go to definition | | `gD` | Go to declaration | | `gi` | Go to implementation | | `gr` | Go to references | | `K` | Hover | | `rn` | Rename | | `ca` | Code actions | | `e` | Show diagnostics | | `[d` | Previous diagnostic | | `]d` | Next diagnostic | ### Debugging (DAP) | Keybinding | Action | |------------|--------| | `db` | Toggle breakpoint | | `dc` | Continue | | `ds` | Step over | | `di` | Step into | | `do` | Step out | | `dr` | Open REPL | | `dl` | Run last debug config | | `du` | Toggle DAP UI | ### Terminal | Keybinding | Action | |------------|--------| | `` | Toggle terminal | | `tf` | Toggle float terminal | | `th` | Toggle horizontal terminal | | `tv` | Toggle vertical terminal | | `gg` | Toggle lazygit | ### Treesitter (Textobjects) | Keybinding | Action | |------------|--------| | `af` | Select function (outer) | | `if` | Select function (inner) | | `ac` | Select class (outer) | | `ic` | Select class (inner) | | `aa` | Select parameter (outer) | | `ia` | Select parameter (inner) | --- ## First Launch 1. **Launch Neovim:** ```bash nvim ``` 2. **Wait for plugin installation:** - Lazy.nvim will automatically install all plugins - You'll see progress in the statusline 3. **Install language servers:** - Run `:Mason` or press `ms` - Install the servers listed above 4. **Verify installation:** - For Python: Open a `.py` file and run `:LspInfo` - Run `:checkhealth` to see overall status 5. **Optional: Install additional tools:** ```bash # For Python debugging pip install debugpy # For shell linting pip install shellcheck-py # For lazygit (optional but recommended) brew install lazygit # macOS sudo apt install lazygit # Ubuntu ``` --- ## Troubleshooting ### LSP not starting - Run `:LspInfo` to check LSP status - Make sure language servers are installed via Mason ### Treesitter highlighting not working - Run `:TSUpdate` to update/install parsers - Check `:TSInstallInfo` for available parsers ### Telescope not working - Ensure `ripgrep` is installed - Check telescope log with `:Telescope log` ### DAP not connecting - Ensure `debugpy` is installed: `pip install debugpy` - Check `: DapLog` for debug logs ### Performance issues - Check startup time with `:StartupTime` - Disable unused plugins in `lua/plugins/init.lua` --- This guide provides a complete Neovim IDE setup. Modify the configuration files to suit your preferences!