------------ Neovim config -------- ------------ Options ------------ -- Leader key as space vim.g.mapleader = " " -- Line numbers vim.o.number = true vim.o.relativenumber = true -- Line wrapping vim.o.wrap = false vim.o.sidescroll = 5 -- Scroll with 8 lines of buffer vim.o.scrolloff = 8 -- Folds vim.o.foldtext = "" vim.o.foldlevelstart = 1 -- Tabs vim.o.tabstop = 4 vim.o.softtabstop = 4 vim.o.shiftwidth = 0 vim.o.expandtab = true -- Indenting vim.o.autoindent = true vim.o.smartindent = true vim.o.breakindent = true -- Borders vim.o.winborder = "rounded" -- Search options for case vim.o.ignorecase = true vim.o.smartcase = true -- Swaps, backups, and undos vim.o.swapfile = false vim.o.backup = false vim.o.undodir = vim.fn.expand("~/.vim/undodir") vim.o.undofile = true ------------ Keybindings ------------ -- Custom map function local function map(mode, left, right, opts) local default_opts = { noremap = true, silent = true, } opts = opts or {} -- "keep" mode preserves the values from the leftmost table, -- so prioritize any options provided over the defaults local full_opts = vim.tbl_extend("keep", opts, default_opts) vim.keymap.set(mode, left, right, full_opts) end -- Clear any highlighted searches when pressing Esc -- This lets me leave hlsearch on by default while having an easy way to clear -- it again. map({ "i", "n" }, "", "noh", { desc = "Escape and clear hlsearch" }) -- Move lines while in visual mode with J and K map("v", "J", ":m '>+1gv=gv") map("v", "K", ":m '<-2gv=gv") -- Keep cursor in the same place when using J to join lines map("n", "J", "mzJ`z") -- Center the screen when jumping around with C-d and C-u map("n", "", "zz") map("n", "", "zz") -- Center the screen when jumping to next / previous search terms map("n", "n", "nzzzv") map("n", "N", "Nzzzv") -- Easier quickfix naviagion map("n", "", "cprev", { desc = "Quickfix previous item" }) map("n", "", "cnext", { desc = "Quickfix next item" }) -- Quick maps to paste/delete without overwriting the current buffer map("x", "p", '"_dP') map({ "n", "v" }, "d", '"_dP') -- System clipboard map({ "n", "v" }, "cd", '"+d', { desc = "Clipboard delete" }) map({ "n", "v" }, "cp", '"+p', { desc = "Clipboard paste" }) map({ "n", "v" }, "cy", '"+y', { desc = "Clipboard yank" }) -- Create a GitHub URL for the current file and line number, and copy it -- to the clipboard. map("n", "yfg", function() local remote_url = vim.fn.system("git config --get remote.origin.url") if not remote_url:find("github.com") then vim.notify("This is not a GitHub repository") return end local trimmed_remote_url = remote_url:gsub("%.git", ""):gsub("%s+", ""):gsub("\n", "") local branch_name = vim.fn.system("git rev-parse --abbrev-ref HEAD"):gsub("\n", "") -- Now construct the link in this format: -- /blob//#l local filepath = vim.fn.expand("%:."):gsub("\\", "/") local line = vim.fn.line(".") local result = trimmed_remote_url .. "/blob/" .. branch_name .. "/" .. filepath .. "#L" .. line vim.fn.setreg("+", result) vim.notify("Copied GitHub URL to clipboard: " .. result) end, { desc = "Yank GitHub URL to clipboard", expr = true }) ------------ Plugins ------------ vim.pack.add({ { src = "https://github.com/rose-pine/neovim" }, { src = "https://github.com/stevearc/oil.nvim" }, { src = "https://github.com/echasnovski/mini.pick" }, { src = "https://github.com/nvim-treesitter/nvim-treesitter" }, { src = "https://github.com/mason-org/mason.nvim" }, }) -- LSP vim.lsp.enable({ "lua_ls", "ruff", "basedpyright", "rust_analyzer" }) -- LSP specific keybindings vim.api.nvim_create_autocmd("LspAttach", { group = vim.api.nvim_create_augroup("IbrahimLspConfig", {}), callback = function(evt) local function lsp_map(mode, lhs, rhs, desc) local opts = { buffer = evt.buf, desc = "LSP: " .. (desc or "") } map(mode, lhs, rhs, opts) end local has_telescope, _ = pcall(require, "telescope") local function lsp_telescope_map(mode, lhs, with_telescope_rhs, no_telescope_rhs, desc) if has_telescope then desc = desc .. " (Telescope)" lsp_map(mode, lhs, with_telescope_rhs, desc) else lsp_map(mode, lhs, no_telescope_rhs, desc) end end local function tele_builtin(name, opts) return function() require("telescope.builtin")[name](opts) end end -- Navigation lsp_map("n", "gd", vim.lsp.buf.definition, "[G]oto [D]efinition") lsp_map("n", "gt", vim.lsp.buf.type_definition, "[G]oto [t]ype Definition") lsp_map("n", "gD", vim.lsp.buf.declaration, "[G]oto [D]eclaration") lsp_map("n", "gr", vim.lsp.buf.references, "[G]oto [R]eferences") lsp_map("n", "gI", vim.lsp.buf.implementation, "[G]oto [I]mplementation") lsp_telescope_map("n", "gr", tele_builtin("lsp_references"), vim.lsp.buf.references, "Go to references") lsp_telescope_map( "n", "sn", tele_builtin("lsp_document_symbols"), vim.lsp.buf.document_symbol, "Search document symbols" ) lsp_telescope_map( "n", "sN", tele_builtin("lsp_dynamic_workspace_symbols"), vim.lsp.buf.workspace_symbol, "Search workspace symbols" ) -- Code changes lsp_map("n", "cr", vim.lsp.buf.rename, "Rename") lsp_map("n", "ca", vim.lsp.buf.code_action, "Code actions") lsp_map("n", "rf", vim.lsp.buf.format, "Format") -- Diagnostics lsp_map("n", "ds", vim.diagnostic.open_float, "[s]how [d]iagnostic window") lsp_map("n", "dn", function() vim.diagnostic.jump({ count = 1, float = true }) end, "Go to [n]ext [d]iagnostic") lsp_map("n", "dp", function() vim.diagnostic.jump({ count = -1, float = true }) end, "Go to [p]revious [d]iagnostic") -- See `:help K` for why this keymap lsp_map("n", "K", function() vim.lsp.buf.hover { border = "single", max_height = 25, max_width = 120 } end, "Hover Documentation") lsp_map("n", "", vim.lsp.buf.signature_help, "Signature Documentation") -- Workspace lsp_map("n", "wa", vim.lsp.buf.add_workspace_folder, "[W]orkspace [A]dd Folder") lsp_map("n", "wr", vim.lsp.buf.remove_workspace_folder, "[W]orkspace [R]emove Folder") lsp_map("n", "wl", function() print(vim.inspect(vim.lsp.buf.list_workspace_folders())) end, "[W]orkspace [L]ist Folders") end, }) require("mason").setup() -- Treesitter require "nvim-treesitter.configs".setup({ ensure_installed = { "lua", "python", "rust" }, highlight = { enable = true } }) -- Completion vim.api.nvim_create_autocmd('LspAttach', { callback = function(ev) local client = vim.lsp.get_client_by_id(ev.data.client_id) if client:supports_method('textDocument/completion') then vim.lsp.completion.enable(true, client.id, ev.buf, { autotrigger = true }) end end, }) vim.cmd("set completeopt+=noselect") -- Mini.pick require "mini.pick".setup() map("n", "f", "Pick files") map("n", "vh", "Pick help") -- Oil require "oil".setup() vim.keymap.set("n", "g-", "Oil") -- -- Harpoon -- local harpoon = require("harpoon") -- harpoon:setup() -- -- map("n", "a", function() -- harpoon:list():add() -- end, { desc = "mark file with harpoon" }) -- -- map("n", "", function() -- harpoon.ui:toggle_quick_menu(harpoon:list()) -- end, { desc = "open harpoon menu" }) -- -- map("n", "j", function() -- harpoon:list():select(1) -- end, { desc = "open harpoon file 1" }) -- map("n", "k", function() -- harpoon:list():select(2) -- end, { desc = "open harpoon file 2" }) -- map("n", "l", function() -- harpoon:list():select(3) -- end, { desc = "open harpoon file 3" }) -- map("n", ";", function() -- harpoon:list():select(4) -- end, { desc = "Open Harpoon file 4" }) -- -- -- Neotest -- require "neotest".setup({ -- adapters = { -- require("neotest-python")({ -- python = "python", -- runner = "pytest", -- is_test_file = function(file_path) ---@param file_path string -- local normalized_path = vim.fs.normalize(file_path) -- return normalized_path.match("test/.*%/test_.%.py$") ~= nil -- end, -- }), -- } -- }) -- -- map("n", "tr", require("neotest").run.run, { desc = "Neotest: run test at cursor" }) -- map("n", "tf", function() -- require("netotest").run.run(vim.fn.expand("%")) -- end, { desc = "Neotest: run all tests in current file" }) -- map("n", "ts", require("neotest").summary.toggle, { desc = "Neotest: toggle summary panel" }) -- -- Undotree -- require("undotree").setup() -- map("n", "u", require("undotree").toggle, { desc = "Toggle Undotree" }) -- Colorscheme vim.o.background = "dark" vim.cmd("colorscheme rose-pine")