diff --git a/nvim/init.lua b/nvim/init.lua index 3b861a5..cfb7624 100644 --- a/nvim/init.lua +++ b/nvim/init.lua @@ -1,69 +1,74 @@ -vim.o.number = true -vim.o.wrap = false -vim.o.tabstop = 4 -vim.o.shiftwidth = 4 +-- ============================================================================ +-- === NEOVIM CONFIGURATION =================================================== +-- ============================================================================ + +-- ============================================================================ +-- 1. CORE SETTINGS +-- ============================================================================ +vim.g.mapleader = "," -- Set leader key to comma + +vim.o.number = true -- Show absolute line numbers +vim.o.wrap = false -- Disable line wrapping globally +vim.o.tabstop = 4 -- Width of a raw character +vim.o.shiftwidth = 4 -- Number of spaces used for autoindent vim.o.expandtab = true -- Use spaces instead of tabs -vim.o.smartcase = true -vim.o.ignorecase = true -vim.o.hlsearch = false -vim.o.signcolumn = "yes" -vim.o.clipboard = "unnamedplus" -vim.o.undofile = true -vim.o.undodir = "/home/narl/.cache/nvim-undodir" +vim.o.smartcase = true -- Override ignorecase if search contains uppercase +vim.o.ignorecase = true -- Case-insensitive searching +vim.o.hlsearch = false -- Disable persistent search highlighting +vim.o.signcolumn = "yes" -- Always show the sign column (prevents text shifting) +vim.o.clipboard = "unnamedplus" -- Sync Neovim with the system clipboard +vim.o.undofile = true -- Enable persistent undo history between sessions +vim.o.undodir = vim.fn.expand("~/.cache/nvim-undodir") -- Path to store undo history -vim.g.mapleader = "," - --- Set up 'mini.deps' (customize to your liking) +-- ============================================================================ +-- 2. PLUGIN MANAGER (mini.deps) +-- ============================================================================ require("mini.deps").setup() - local add = MiniDeps.add + +-- UI & Theming +add({ source = "catppuccin/nvim", name = "catppuccin" }) +add({ source = "nvim-lualine/lualine.nvim" }) +add({ source = "lewis6991/gitsigns.nvim" }) +add({ source = "folke/which-key.nvim" }) + +-- Utility & Editing +add({ source = "akinsho/toggleterm.nvim" }) +add({ source = "chomosuke/typst-preview.nvim" }) add({ - source = "lewis6991/gitsigns.nvim", -}) -add({ - source = "chomosuke/typst-preview.nvim", -}) -add({ - source = "williamboman/mason.nvim", + source = "MeanderingProgrammer/render-markdown.nvim", + depends = { "nvim-treesitter/nvim-treesitter", "echasnovski/mini.icons" }, }) +-- LSP, Formatting & Linting +add({ source = "williamboman/mason.nvim" }) +add({ source = "williamboman/mason-lspconfig.nvim" }) +add({ source = "neovim/nvim-lspconfig", depends = { "williamboman/mason.nvim" } }) +add({ source = "stevearc/conform.nvim" }) +add({ source = "mfussenegger/nvim-lint" }) +add({ source = "seblyng/roslyn.nvim" }) +add({ source = "tris203/rzls.nvim" }) +add({ source = "https://git.narl.io/nvrl/mould-rs", checkout = "main" }) + +-- Autocompletion add({ - source = "stevearc/conform.nvim", -}) - -add({ - source = "williamboman/mason-lspconfig.nvim", -}) - -add({ - source = "mfussenegger/nvim-lint", -}) - -add({ - source = "akinsho/toggleterm.nvim", -}) - --- Add to current session (install if absent) -add({ - source = "neovim/nvim-lspconfig", - -- Supply dependencies near target plugin - depends = { "williamboman/mason.nvim" }, -}) - -add({ - source = "seblyng/roslyn.nvim", -}) - -add({ - source = "tris203/rzls.nvim", + source = "Saghen/blink.cmp", + depends = { "rafamadriz/friendly-snippets" }, + hooks = { + post_install = function(ctx) + vim.cmd("!cd " .. ctx.path .. " && cargo build --release") + end, + post_checkout = function(ctx) + vim.cmd("!cd " .. ctx.path .. " && cargo build --release") + end, + }, }) +-- Treesitter add({ source = "nvim-treesitter/nvim-treesitter", - -- Use 'master' while monitoring updates in 'main' checkout = "master", monitor = "main", - -- Perform action after every checkout hooks = { post_checkout = function() vim.cmd("TSUpdate") @@ -71,61 +76,99 @@ add({ }, }) -add({ - source = "https://git.narl.io/nvrl/mould-rs", - checkout = "main", -}) - -add({ source = "catppuccin/nvim", name = "catppuccin" }) -add({ source = "folke/which-key.nvim" }) -add({ - source = 'Saghen/blink.cmp', - depends = { 'rafamadriz/friendly-snippets' }, - -- Compile the Rust binary after downloading - hooks = { - post_install = function(ctx) - vim.cmd('!cd ' .. ctx.path .. ' && cargo build --release') - end, - post_checkout = function(ctx) - vim.cmd('!cd ' .. ctx.path .. ' && cargo build --release') - end - }, -}) - -require("mini.files").setup({ - mappings = { - show_help = "gh", - }, -}) +-- ============================================================================ +-- 3. MINI MODULES SETUP +-- ============================================================================ +require("mini.extra").setup() require("mini.icons").setup({ style = "ascii" }) -require("mini.pick").setup({}) -require("mini.snippets").setup({}) -require("mini.notify").setup({}) -require("mini.statusline").setup({}) -require("mini.tabline").setup({}) -require("mini.git").setup({}) -require("gitsigns").setup() +require("mini.files").setup({ mappings = { show_help = "gh" } }) +require("mini.pick").setup() +require("mini.snippets").setup() +require("mini.notify").setup() +require("mini.tabline").setup() +require("mini.git").setup() require("mini.indentscope").setup() require("mini.pairs").setup() require("mini.surround").setup() + +-- ============================================================================ +-- 4. UI & THEMING +-- ============================================================================ + +-- Catppuccin Theme +require("catppuccin").setup({ + flavour = "auto", + background = { light = "latte", dark = "mocha" }, + transparent_background = false, + show_end_of_buffer = false, + integrations = { + cmp = true, + gitsigns = true, + nvimtree = true, + treesitter = true, + mini = { enabled = true }, + }, +}) +vim.cmd.colorscheme("catppuccin") + +-- Git Signs +require("gitsigns").setup() + +-- Which-Key (Keybind discoverability) require("which-key").setup() -local imap_expr = function(lhs, rhs) - vim.keymap.set("i", lhs, rhs, { expr = true }) -end -imap_expr("", [[pumvisible() ? "\" : "\"]]) -imap_expr("", [[pumvisible() ? "\" : "\"]]) -_G.cr_action = function() - -- If there is selected item in popup, accept it with - if vim.fn.complete_info()["selected"] ~= -1 then - return "\25" + +-- Lualine (Statusline) +local function active_lsp() + local clients = vim.lsp.get_clients({ bufnr = 0 }) + if next(clients) == nil then + return "No LSP" end - -- Fall back to plain ``. You might want to customize this - -- according to other plugins. For example if 'mini.pairs' is set up, replace - -- next line with `return MiniPairs.cr()` - return "\r" + local client_names = {} + for _, client in ipairs(clients) do + table.insert(client_names, client.name) + end + return "⚙ " .. table.concat(client_names, ", ") end -vim.keymap.set("i", "", "v:lua.cr_action()", { expr = true }) +require("lualine").setup({ + options = { + theme = require("catppuccin.utils.lualine")(), + component_separators = { left = "|", right = "|" }, + section_separators = { left = "", right = "" }, + globalstatus = true, + }, + sections = { + lualine_a = { "mode" }, + lualine_b = { "branch", "diff" }, + lualine_c = { { "filename", path = 1 }, "diagnostics" }, + lualine_x = { active_lsp }, + lualine_y = { "encoding", "fileformat", "filetype" }, + lualine_z = { "location", "progress" }, + }, +}) + +-- Render Markdown +require("render-markdown").setup({ + enabled = true, + anti_conceal = { enabled = true }, + heading = { + icons = { "1. ", "2. ", "3. ", "4. ", "5. ", "6. " }, + backgrounds = { + "RenderMarkdownH1Bg", + "RenderMarkdownH2Bg", + "RenderMarkdownH3Bg", + "RenderMarkdownH4Bg", + "RenderMarkdownH5Bg", + "RenderMarkdownH6Bg", + }, + }, +}) + +-- ============================================================================ +-- 5. TOOLS & INTEGRATIONS +-- ============================================================================ + +-- Toggleterm require("toggleterm").setup({ size = function(term) if term.direction == "horizontal" then @@ -140,58 +183,97 @@ require("toggleterm").setup({ persist_size = true, direction = "float", close_on_exit = true, - shell = vim.o.shell, }) -require("nvim-treesitter.configs").setup({ - ensure_installed = { "lua", "rust", "toml", "c_sharp", "python", "typst" }, - auto_install = true, - highlight = { - enable = true, - additional_vim_regex_highlighting = false, - }, - ident = { enable = true }, - rainbow = { - enable = true, - extended_mode = true, - max_file_lines = nil, +-- Typst Preview +require("typst-preview").setup({ + debug = false, + port = 0, + host = "127.0.0.1", + invert_colors = "never", + follow_cursor = true, + dependencies_bin = { + ["tinymist"] = "/home/narl/.local/share/nvim/mason/bin/tinymist", + ["websocat"] = "/usr/bin/websocat", }, + get_root = function(path_of_main_file) + local root = os.getenv("TYPST_ROOT") + if root then + return root + end + local main_dir = vim.fs.dirname(vim.fn.fnamemodify(path_of_main_file, ":p")) + local found = vim.fs.find({ "typst.toml", ".git" }, { path = main_dir, upward = true }) + if #found > 0 then + return vim.fs.dirname(found[1]) + end + return main_dir + end, }) + +-- ============================================================================ +-- 6. TREESITTER, LSP, & AUTOCOMPLETION +-- ============================================================================ + +-- Treesitter +require("nvim-treesitter.configs").setup({ + ensure_installed = { "lua", "rust", "toml", "c_sharp", "python", "typst", "markdown", "markdown_inline" }, + auto_install = true, + highlight = { enable = true }, + ident = { enable = true }, + rainbow = { enable = true, extended_mode = true }, +}) + +-- Mason (Package Installer) require("mason").setup({ registries = { "github:mason-org/mason-registry", "github:Crashdummyy/mason-registry", }, - ui = { - icons = { - package_installed = "✓", - package_pending = "➜", - package_uninstalled = "✗", - }, - }, }) -local capabilities = require('blink.cmp').get_lsp_capabilities() - +-- Mason LSPConfig require("mason-lspconfig").setup({ ensure_installed = { - "lua_ls", -- Lua - "gopls", -- Go - "clangd", -- C/C++ - "html", -- HTML - "cssls", -- CSS - "jsonls", -- JSON - "yamlls", -- YAML - "bashls", -- Bash/Shell - "pyright", -- Python - "ts_ls", -- JS/TS/React - "rust_analyzer", -- Rust - "robotcode", -- Robot Framework - "tinymist", -- Typst + "lua_ls", + "gopls", + "clangd", + "html", + "cssls", + "jsonls", + "yamlls", + "bashls", + "pyright", + "ts_ls", + "rust_analyzer", + "robotcode", + "tinymist", }, }) --- List out the servers you are using +-- Blink.cmp (Autocompletion) +require("blink.cmp").setup({ + keymap = { + preset = "none", + [""] = { "accept", "fallback" }, + [""] = { "select_next", "snippet_forward", "fallback" }, + [""] = { "select_prev", "snippet_backward", "fallback" }, + [""] = { "select_prev", "fallback" }, + [""] = { "select_next", "fallback" }, + [""] = { "show", "show_documentation", "hide_documentation" }, + }, + completion = { + list = { selection = { preselect = false, auto_insert = true } }, + }, + appearance = { + use_nvim_cmp_as_default = true, + nerd_font_variant = "mono", + }, + sources = { default = { "lsp", "path", "snippets", "buffer" } }, + signature = { enabled = true }, +}) + +-- Global LSP Setup (Using Blink capabilities) +local capabilities = require("blink.cmp").get_lsp_capabilities() local servers = { "lua_ls", "gopls", @@ -206,174 +288,41 @@ local servers = { "rust_analyzer", "robotcode", "tinymist", + "marksman", } --- Configure capabilities for each server using Neovim's native API for _, server in ipairs(servers) do - vim.lsp.config(server, { - capabilities = capabilities, - }) + vim.lsp.config(server, { capabilities = capabilities }) end +-- Dedicated C# Setup require("roslyn").setup({ - config = { - -- the rest of your Roslyn configuration - handlers = require("rzls.roslyn_handlers"), - }, + config = { handlers = require("rzls.roslyn_handlers") }, }) -require("catppuccin").setup({ - flavour = "auto", -- latte, frappe, macchiato, mocha - background = { -- :h background - light = "latte", - dark = "mocha", - }, - transparent_background = false, -- disables setting the background color. - show_end_of_buffer = false, -- shows the '~' characters after the end of buffers - term_colors = false, -- sets terminal colors (e.g. `g:terminal_color_0`) - dim_inactive = { - enabled = false, -- dims the background color of inactive window - shade = "dark", - percentage = 0.15, -- percentage of the shade to apply to the inactive window - }, - no_italic = false, -- Force no italic - no_bold = false, -- Force no bold - no_underline = false, -- Force no underline - styles = { -- Handles the styles of general hi groups (see `:h highlight-args`): - comments = { "italic" }, -- Change the style of comments - conditionals = { "italic" }, - loops = {}, - functions = {}, - keywords = {}, - strings = {}, - variables = {}, - numbers = {}, - booleans = {}, - properties = {}, - types = {}, - operators = {}, - -- miscs = {}, -- Uncomment to turn off hard-coded styles - }, - color_overrides = {}, - custom_highlights = {}, - default_integrations = true, - integrations = { - cmp = true, - gitsigns = true, - nvimtree = true, - treesitter = true, - notify = false, - mini = { - enabled = true, - indentscope_color = "", - }, - -- For more plugins integrations please scroll down (https://github.com/catppuccin/nvim#integrations) - }, -}) +-- ============================================================================ +-- 7. DIAGNOSTICS, FORMATTING, & LINTING +-- ============================================================================ +-- Diagnostics Configuration local sign = function(opts) - vim.fn.sign_define(opts.name, { - texthl = opts.name, - text = opts.text, - numhl = "", - }) + vim.fn.sign_define(opts.name, { texthl = opts.name, text = opts.text, numhl = "" }) end - sign({ name = "DiagnosticSignError", text = "" }) sign({ name = "DiagnosticSignWarn", text = "" }) sign({ name = "DiagnosticSignHint", text = "" }) sign({ name = "DiagnosticSignInfo", text = "" }) -vim.opt.completeopt = { "menuone", "noselect", "noinsert" } -vim.opt.shortmess = vim.opt.shortmess + { c = true } -vim.api.nvim_set_option("updatetime", 300) - -vim.cmd([[ -set signcolumn=yes -autocmd CursorHold * lua vim.diagnostic.open_float(nil, { focusable = false }) -]]) - vim.diagnostic.config({ virtual_text = false, signs = true, update_in_insert = true, underline = true, severity_sort = false, - float = { - border = "rounded", - source = "always", - header = "", - prefix = "", - }, -}) - -vim.cmd.colorscheme("catppuccin") - -vim.keymap.set("n", "w", "write", { desc = "Save file" }) -vim.keymap.set("n", "q", "quitall", { desc = "Exit vim" }) - -vim.keymap.set("n", "e", "lua MiniFiles.open()", { desc = "File explorer" }) -vim.keymap.set("n", "", "Pick buffers", { desc = "Search open files" }) -vim.keymap.set("n", "ff", "Pick files", { desc = "Search all files" }) -vim.keymap.set("n", "fh", "Pick help", { desc = "Search help tags" }) - -vim.keymap.set("n", "h", "wincmd h") -vim.keymap.set("n", "l", "wincmd l") -vim.keymap.set("n", "j", "wincmd j") -vim.keymap.set("n", "k", "wincmd k") - -require("typst-preview").setup({ - debug = false, - open_cmd = nil, - port = 0, - host = "127.0.0.1", - invert_colors = "never", - follow_cursor = true, - dependencies_bin = { - ["tinymist"] = "/home/narl/.local/share/nvim/mason/bin/tinymist", - ["websocat"] = "/usr/bin/websocat", - }, - extra_args = nil, - get_root = function(path_of_main_file) - local root = os.getenv("TYPST_ROOT") - if root then - return root - end - - local main_dir = vim.fs.dirname(vim.fn.fnamemodify(path_of_main_file, ":p")) - local found = vim.fs.find({ "typst.toml", ".git" }, { path = main_dir, upward = true }) - if #found > 0 then - return vim.fs.dirname(found[1]) - end - - return main_dir - end, - get_main_file = function(path_of_buffer) - return path_of_buffer - end, -}) - -require('blink.cmp').setup({ - -- 'default' maps match standard nvim-cmp behavior (, , , ) - -- 'super-tab' uses your Tab key for everything - keymap = { preset = 'default' }, - - appearance = { - -- Sets the fallback highlight groups to nvim-cmp's highlight groups - use_nvim_cmp_as_default = true, - -- Set to 'mono' for 'Nerd Font Mono' or 'normal' for 'Nerd Font' - nerd_font_variant = 'mono' - }, - - -- Default list of enabled providers - sources = { - default = { 'lsp', 'path', 'snippets', 'buffer' }, - }, - - -- Enable displaying function signatures as you type parameters - signature = { enabled = true } + float = { border = "rounded", source = "always", header = "", prefix = "" }, }) +-- Formatting (Conform) require("conform").setup({ formatters_by_ft = { cs = { "csharpier" }, @@ -395,52 +344,92 @@ require("conform").setup({ typescriptreact = { "prettier" }, typst = { "typstyle" }, xml = { "xmlformatter" }, + markdown = { "prettier", "injected" }, }, - format_on_save = function(bufnr) if vim.bo[bufnr].filetype ~= "rust" then return end - - return { - timeout_ms = 3000, - lsp_fallback = true, - } + return { timeout_ms = 3000, lsp_fallback = true } end, }) -vim.keymap.set({ "n", "v" }, "f", function() - require("conform").format({ - lsp_fallback = true, - async = false, - timeout_ms = 3000, - }) -end, { desc = "Format file or range" }) - --- Nvim-Lint Configuration +-- Linting (Nvim-Lint) require("lint").linters_by_ft = { python = { "flake8" }, } +-- ============================================================================ +-- 8. AUTOCOMMANDS +-- ============================================================================ + +-- Show floating diagnostic on cursor hold +vim.cmd([[ + set signcolumn=yes + autocmd CursorHold * lua vim.diagnostic.open_float(nil, { focusable = false }) +]]) + -- Trigger linting on file save vim.api.nvim_create_autocmd({ "BufWritePost" }, { callback = function() require("lint").try_lint() end, }) -vim.api.nvim_create_autocmd('LspAttach', { - callback = function(event) - local opts = { buffer = event.buf } - - -- Press 'K' to show hover documentation - vim.keymap.set('n', 'K', vim.lsp.buf.hover, opts) - -- Press 'gd' to jump to a function/variable definition - vim.keymap.set('n', 'gd', vim.lsp.buf.definition, opts) - -- Press 'rn' to rename a variable across the whole project - vim.keymap.set('n', 'rn', vim.lsp.buf.rename, opts) - -- Press 'ca' to see code actions (like quick fixes) - vim.keymap.set('n', 'ca', vim.lsp.buf.code_action, opts) - -- Press 'gr' to find all references of the word under your cursor - vim.keymap.set('n', 'gr', vim.lsp.buf.references, opts) - end, + +-- Markdown specific settings +vim.api.nvim_create_autocmd("FileType", { + pattern = "markdown", + callback = function() + vim.opt_local.wrap = true + vim.keymap.set("n", "j", "gj", { buffer = true, desc = "Move down visual line" }) + vim.keymap.set("n", "k", "gk", { buffer = true, desc = "Move up visual line" }) + end, }) + +-- Dynamic LSP Keymaps (Loaded only when LSP attaches to a buffer) +vim.api.nvim_create_autocmd("LspAttach", { + callback = function(event) + local opts = { buffer = event.buf } + vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) + vim.keymap.set("n", "gd", vim.lsp.buf.definition, 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", "gr", vim.lsp.buf.references, opts) + end, +}) + +-- ============================================================================ +-- 9. GLOBAL KEYMAPS +-- ============================================================================ + +-- General Operations +vim.keymap.set("n", "w", "write", { desc = "Save file" }) +vim.keymap.set("n", "q", "quitall", { desc = "Exit Neovim" }) + +-- Window Navigation +vim.keymap.set("n", "h", "wincmd h", { desc = "Move to left split" }) +vim.keymap.set("n", "l", "wincmd l", { desc = "Move to right split" }) +vim.keymap.set("n", "j", "wincmd j", { desc = "Move to lower split" }) +vim.keymap.set("n", "k", "wincmd k", { desc = "Move to upper split" }) + +-- Search & Navigation (Mini Pick & Files) +vim.keymap.set("n", "e", "lua MiniFiles.open()", { desc = "Open File Explorer" }) +vim.keymap.set("n", "", "Pick buffers", { desc = "Search open buffers" }) +vim.keymap.set("n", "ff", "Pick files", { desc = "Search all files" }) +vim.keymap.set("n", "fh", "Pick help", { desc = "Search help tags" }) + +-- Formatting Trigger +vim.keymap.set({ "n", "v" }, "f", function() + require("conform").format({ lsp_fallback = true, async = false, timeout_ms = 3000 }) +end, { desc = "Format file or range" }) + +-- Diagnostics Navigation +vim.keymap.set("n", "fd", "Pick diagnostic", { desc = "Search all diagnostics" }) +vim.keymap.set("n", "]d", vim.diagnostic.goto_next, { desc = "Next diagnostic" }) +vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, { desc = "Previous diagnostic" }) +vim.keymap.set("n", "]e", function() + vim.diagnostic.goto_next({ severity = vim.diagnostic.severity.ERROR }) +end, { desc = "Next error" }) +vim.keymap.set("n", "[e", function() + vim.diagnostic.goto_prev({ severity = vim.diagnostic.severity.ERROR }) +end, { desc = "Previous error" })