commit 2da113baae46a33a3a7050c4ae85314ffe99a5ac Author: Nils Pukropp Date: Sun Mar 22 13:00:29 2026 +0100 neovim configuration diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..7075ae0 --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +pack/ +undodir/ +*.swp +*.tmp diff --git a/README.md b/README.md new file mode 100644 index 0000000..8dc525e --- /dev/null +++ b/README.md @@ -0,0 +1,18 @@ +# My Neovim Configuration + +A modular Neovim configuration using `mini.deps`. + +## Installation + +1. Clone this repository to `~/.config/nvim`: + ```bash + git clone ~/.config/nvim + ``` +2. Open Neovim. `mini.deps` will handle plugin installation automatically. +3. Run `:DepsInstall` if needed. + +## Structure + +- `init.lua`: Entry point. +- `lua/config/`: Core Neovim settings (options, keymaps, autocmds). +- `lua/plugins/`: Plugin management and configurations. diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..3bc04b1 --- /dev/null +++ b/init.lua @@ -0,0 +1,16 @@ +-- Entry point for Neovim configuration + +-- Load core configuration +require("config.options") + +-- Initialize plugin manager and add plugins +require("plugins") + +-- Load plugin configurations +require("plugins.ui") +require("plugins.tools") +require("plugins.lsp") + +-- Load remaining core configuration +require("config.autocmds") +require("config.keymaps") diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua new file mode 100644 index 0000000..e66ea8e --- /dev/null +++ b/lua/config/autocmds.lua @@ -0,0 +1,22 @@ +-- 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, +}) + +-- 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, +}) diff --git a/lua/config/keymaps.lua b/lua/config/keymaps.lua new file mode 100644 index 0000000..659c6b5 --- /dev/null +++ b/lua/config/keymaps.lua @@ -0,0 +1,26 @@ +-- 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" }) + +-- 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" }) diff --git a/lua/config/options.lua b/lua/config/options.lua new file mode 100644 index 0000000..1bde04b --- /dev/null +++ b/lua/config/options.lua @@ -0,0 +1,14 @@ +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 -- 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 diff --git a/lua/plugins/init.lua b/lua/plugins/init.lua new file mode 100644 index 0000000..b6e45e6 --- /dev/null +++ b/lua/plugins/init.lua @@ -0,0 +1,52 @@ +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 = "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 = "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", + checkout = "master", + monitor = "main", + hooks = { + post_checkout = function() + vim.cmd("TSUpdate") + end, + }, +}) diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua new file mode 100644 index 0000000..05a5b3b --- /dev/null +++ b/lua/plugins/lsp.lua @@ -0,0 +1,148 @@ +-- Mason (Package Installer) +require("mason").setup({ + registries = { + "github:mason-org/mason-registry", + "github:Crashdummyy/mason-registry", + }, +}) + +-- Mason LSPConfig +require("mason-lspconfig").setup({ + ensure_installed = { + "lua_ls", + "gopls", + "clangd", + "html", + "cssls", + "jsonls", + "yamlls", + "bashls", + "pyright", + "ts_ls", + "rust_analyzer", + "robotcode", + "tinymist", + }, +}) + +-- 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", + "clangd", + "html", + "cssls", + "jsonls", + "yamlls", + "bashls", + "pyright", + "ts_ls", + "rust_analyzer", + "robotcode", + "tinymist", + "marksman", +} + +for _, server in ipairs(servers) do + vim.lsp.config(server, { capabilities = capabilities }) +end + +-- Dedicated C# Setup +require("roslyn").setup({ + config = { handlers = require("rzls.roslyn_handlers") }, +}) + +-- Diagnostics Configuration +local sign = function(opts) + 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.diagnostic.config({ + virtual_text = false, + signs = true, + update_in_insert = true, + underline = true, + severity_sort = false, + float = { border = "rounded", source = "always", header = "", prefix = "" }, +}) + +-- Formatting (Conform) +require("conform").setup({ + formatters_by_ft = { + cs = { "csharpier" }, + rust = { "rustfmt" }, + lua = { "stylua" }, + go = { "gofmt" }, + c = { "clang-format" }, + cpp = { "clang-format" }, + html = { "prettier" }, + css = { "prettier" }, + json = { "prettier" }, + yaml = { "prettier" }, + sh = { "shfmt" }, + bash = { "shfmt" }, + python = { "isort", "black" }, + javascript = { "prettier" }, + typescript = { "prettier" }, + javascriptreact = { "prettier" }, + 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 } + end, +}) + +-- 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" }) + +-- Linting (Nvim-Lint) +require("lint").linters_by_ft = { + python = { "flake8" }, +} + +-- 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, +}) diff --git a/lua/plugins/tools.lua b/lua/plugins/tools.lua new file mode 100644 index 0000000..393a12a --- /dev/null +++ b/lua/plugins/tools.lua @@ -0,0 +1,63 @@ +-- Mini Modules +require("mini.extra").setup() +require("mini.icons").setup({ style = "ascii" }) +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() + +-- Toggleterm +require("toggleterm").setup({ + size = function(term) + if term.direction == "horizontal" then + return 30 + elseif term.direction == "vertical" then + return 69 + end + end, + open_mapping = [[]], + hide_numbers = true, + shade_terminals = true, + persist_size = true, + direction = "float", + close_on_exit = true, +}) + +-- 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, +}) + +-- 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 }, +}) diff --git a/lua/plugins/ui.lua b/lua/plugins/ui.lua new file mode 100644 index 0000000..ab28441 --- /dev/null +++ b/lua/plugins/ui.lua @@ -0,0 +1,68 @@ +-- 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() + +-- Lualine (Statusline) +local function active_lsp() + local clients = vim.lsp.get_clients({ bufnr = 0 }) + if next(clients) == nil then + return "No LSP" + end + local client_names = {} + for _, client in ipairs(clients) do + table.insert(client_names, client.name) + end + return "{ " .. table.concat(client_names, " | ") .. " }" +end + +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", + }, + }, +})