diff options
| author | steven-na <141802725+steven-na@users.noreply.github.com> | 2026-07-17 02:49:38 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2026-07-17 02:49:38 -0700 |
| commit | ac44574134dba1a687e5782d11b0dcd0aedaafe9 (patch) | |
| tree | e728cb95be609b163598d4d7b1f4f10459253b3f | |
| parent | 6abeaadbe4cea91eb444cf23241b7f0320f2dc33 (diff) | |
Alpine Linux Neovim config
| -rw-r--r-- | alpine/nvim/init.lua | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/alpine/nvim/init.lua b/alpine/nvim/init.lua new file mode 100644 index 0000000..db30dc7 --- /dev/null +++ b/alpine/nvim/init.lua @@ -0,0 +1,386 @@ +-- Bootstrap lazy.nvim +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not vim.uv.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) + +-- Leader +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +-- ============================================================ +-- Options (adjusted for a raw TTY) +-- ============================================================ + +local opt = vim.opt + +-- Line numbers +opt.number = true +opt.relativenumber = true + +-- Indentation +opt.expandtab = true +opt.tabstop = 4 +opt.shiftwidth = 4 +opt.softtabstop = 4 + +-- Visual +opt.cursorline = true +opt.scrolloff = 20 +opt.signcolumn = "yes" +opt.list = true +opt.listchars = { tab = " ", trail = ".", nbsp = "_" } +opt.fillchars:append({ fold = "-" }) +opt.termguicolors = false +opt.colorcolumn = "" + +-- Behaviour +opt.swapfile = false +opt.undofile = true +opt.updatetime = 250 +opt.timeoutlen = 300 +opt.splitbelow = true +opt.splitright = true +opt.ignorecase = true +opt.smartcase = true +opt.inccommand = "split" +opt.hlsearch = true +opt.breakindent = true + +-- Folding (nvim-ufo, see plugin list below) +opt.foldcolumn = "0" +opt.foldlevel = 99 +opt.foldlevelstart = 99 +opt.foldenable = true + +local map = vim.keymap.set + +-- ============================================================ +-- Keymaps +-- ============================================================ + +-- Disable Space in normal/visual (used as leader) +map({ "n", "v" }, "<Space>", "<Nop>", { silent = true }) + +-- Save +map({ "n", "i" }, "<C-s>", "<cmd>w<CR>", { desc = "Save" }) + +-- Clear search highlight +map("n", "<Esc>", "<cmd>nohlsearch<CR>") + +-- Exit terminal mode +map("t", "<Esc><Esc>", "<C-\\><C-n>", { desc = "Exit terminal" }) + +-- Better up/down on wrapped lines +map({ "n", "v" }, "j", "gj") +map({ "n", "v" }, "k", "gk") + +-- Buffer navigation +map("n", "<S-h>", "<cmd>bprevious<CR>", { desc = "Prev buffer" }) +map("n", "<S-l>", "<cmd>bnext<CR>", { desc = "Next buffer" }) +map("n", "<leader>bd", "<cmd>bdelete<CR>", { desc = "Delete buffer" }) + +-- Splits +map("n", "<leader>sv", "<C-w>v", { desc = "Split vertical" }) +map("n", "<leader>sh", "<C-w>s", { desc = "Split horizontal" }) +map("n", "<leader>se", "<C-w>=", { desc = "Equal splits" }) +map("n", "<leader>sx", "<cmd>close<CR>", { desc = "Close split" }) + +-- Move lines +map("n", "<C-S-Down>", "<cmd>m .+1<CR>==", { desc = "Move line down" }) +map("n", "<C-S-Up>", "<cmd>m .-2<CR>==", { desc = "Move line up" }) +map("v", "<C-S-Down>", ":m '>+1<CR>gv=gv", { desc = "Move selection down" }) +map("v", "<C-S-Up>", ":m '<-2<CR>gv=gv", { desc = "Move selection up" }) + +-- Stay in visual after indent +map("v", "<", "<gv") +map("v", ">", ">gv") + +-- ============================================================ +-- Completion helper +-- ============================================================ + +local function expand_menu() + local cfg = require("blink.cmp.config").completion + cfg.menu.max_height = 10 + cfg.documentation.auto_show = true + pcall(function() + require("blink.cmp.completion.windows.menu").update_position() + end) +end + +vim.api.nvim_create_autocmd("User", { + pattern = "BlinkCmpMenuClose", + callback = function() + local ok, cfg = pcall(function() return require("blink.cmp.config").completion end) + if not ok then return end + cfg.menu.max_height = 5 + cfg.documentation.auto_show = false + end, +}) + +-- ============================================================ +-- Fold text helper +-- ============================================================ + +local function ufo_ascii_foldtext(virtText, lnum, endLnum, width, truncate) + local newVirtText = {} + local suffix = (" ... %d lines "):format(endLnum - lnum) + local sufWidth = vim.fn.strdisplaywidth(suffix) + local targetWidth = width - sufWidth + local curWidth = 0 + for _, chunk in ipairs(virtText) do + local chunkText = chunk[1] + local chunkWidth = vim.fn.strdisplaywidth(chunkText) + if targetWidth > curWidth + chunkWidth then + table.insert(newVirtText, chunk) + else + chunkText = truncate(chunkText, targetWidth - curWidth) + local hlGroup = chunk[2] + table.insert(newVirtText, { chunkText, hlGroup }) + chunkWidth = vim.fn.strdisplaywidth(chunkText) + if curWidth + chunkWidth < targetWidth then + suffix = suffix .. (" "):rep(targetWidth - curWidth - chunkWidth) + end + break + end + curWidth = curWidth + chunkWidth + end + table.insert(newVirtText, { suffix, "Comment" }) + return newVirtText +end + +-- ============================================================ +-- Plugins: leap, oil, treesitter, nvim-ufo, clangd, blink.cmp +-- ============================================================ + +require("lazy").setup({ + + -- Motion: s + two chars to jump anywhere + { + url = "https://codeberg.org/andyg/leap.nvim", + keys = { + { "s", "<Plug>(leap)", mode = { "n", "x", "o" }, desc = "Leap" }, + { "S", "<Plug>(leap-from-window)", mode = { "n", "o" }, desc = "Leap from window" }, + }, + }, + + -- Buffer-based file explorer + { + "stevearc/oil.nvim", + lazy = false, + keys = { + { "<leader>e", "<cmd>Oil<CR>", desc = "File explorer" }, + { "-", "<cmd>Oil<CR>", desc = "Open parent dir" }, + }, + opts = { + default_file_explorer = true, + view_options = { show_hidden = true }, + constrain_cursor = false, + }, + }, + + -- Treesitter (syntax highlighting + textobjects) + { + "nvim-treesitter/nvim-treesitter", + branch = "main", + lazy = false, + build = ":TSUpdate", + dependencies = { + { "nvim-treesitter/nvim-treesitter-textobjects", branch = "main" }, + }, + config = function() + require("nvim-treesitter").setup({}) + require("nvim-treesitter").install({ "c" }) + + vim.api.nvim_create_autocmd("FileType", { + callback = function(args) + local lang = vim.treesitter.language.get_lang(vim.bo[args.buf].filetype) + if lang and vim.treesitter.language.add(lang) then + pcall(vim.treesitter.start, args.buf, lang) + vim.bo[args.buf].indentexpr = "v:lua.require'nvim-treesitter'.indentexpr()" + end + end, + }) + + local ok_to, to = pcall(require, "nvim-treesitter-textobjects") + if not ok_to then return end + to.setup({ + select = { lookahead = true }, + move = { set_jumps = true }, + }) + local sel = require("nvim-treesitter-textobjects.select") + local move = require("nvim-treesitter-textobjects.move") + local swap = require("nvim-treesitter-textobjects.swap") + local tmap = vim.keymap.set + + local objs = { + { "af", "@function.outer", "around function" }, + { "if", "@function.inner", "inside function" }, + { "ac", "@class.outer", "around class" }, + { "ic", "@class.inner", "inside class" }, + { "aa", "@parameter.outer", "around argument" }, + { "ia", "@parameter.inner", "inside argument" }, + { "ab", "@block.outer", "around block" }, + { "ib", "@block.inner", "inside block" }, + { "ai", "@conditional.outer", "around conditional" }, + { "ii", "@conditional.inner", "inside conditional" }, + { "al", "@loop.outer", "around loop" }, + { "il", "@loop.inner", "inside loop" }, + } + for _, o in ipairs(objs) do + local lhs, q, d = o[1], o[2], o[3] + tmap({ "x", "o" }, lhs, function() sel.select_textobject(q, "textobjects") end, { desc = d }) + end + + local nmo = { "n", "x", "o" } + tmap(nmo, "]m", function() move.goto_next_start("@function.outer", "textobjects") end, { desc = "next func start" }) + tmap(nmo, "[m", function() move.goto_previous_start("@function.outer", "textobjects") end, { desc = "prev func start" }) + tmap(nmo, "]M", function() move.goto_next_end("@function.outer", "textobjects") end, { desc = "next func end" }) + tmap(nmo, "[M", function() move.goto_previous_end("@function.outer", "textobjects") end, { desc = "prev func end" }) + tmap(nmo, "]]", function() move.goto_next_start("@class.outer", "textobjects") end, { desc = "next class start" }) + tmap(nmo, "[[", function() move.goto_previous_start("@class.outer", "textobjects") end, { desc = "prev class start" }) + tmap(nmo, "][", function() move.goto_next_end("@class.outer", "textobjects") end, { desc = "next class end" }) + tmap(nmo, "[]", function() move.goto_previous_end("@class.outer", "textobjects") end, { desc = "prev class end" }) + + tmap("n", "<leader>a", function() swap.swap_next("@parameter.inner") end, { desc = "Swap arg with next" }) + tmap("n", "<leader>A", function() swap.swap_previous("@parameter.inner") end, { desc = "Swap arg with prev" }) + end, + }, + + -- Folding + { + "kevinhwang91/nvim-ufo", + dependencies = { "kevinhwang91/promise-async" }, + event = "BufReadPost", + keys = { + { + "zR", + function() + require("ufo").openAllFolds() + end, + desc = "Open all folds", + }, + { + "zM", + function() + require("ufo").closeAllFolds() + end, + desc = "Close all folds", + }, + }, + opts = { + provider_selector = function() + return { "treesitter", "indent" } + end, + fold_virt_text_handler = ufo_ascii_foldtext, + }, + }, + + -- Completion engine + { + "saghen/blink.cmp", + version = "*", + dependencies = { "L3MON4D3/LuaSnip", "rafamadriz/friendly-snippets" }, + opts = { + keymap = { + preset = "none", + ["<C-Space>"] = { "show", "show_documentation", "hide_documentation" }, + ["<C-e>"] = { "hide" }, + ["<CR>"] = { "accept", "fallback" }, + ["<Tab>"] = { expand_menu, "select_next", "fallback" }, + ["<S-Tab>"] = { "select_prev", "fallback" }, + ["<C-b>"] = { "scroll_documentation_up", "fallback" }, + ["<C-f>"] = { "scroll_documentation_down", "fallback" }, + ["<C-n>"] = { "select_next", "fallback" }, + ["<C-p>"] = { "select_prev", "fallback" }, + ["<C-k>"] = { "snippet_forward", "fallback" }, + ["<C-j>"] = { "snippet_backward", "fallback" }, + }, + sources = { + default = { "lsp", "path", "snippets", "buffer" }, + }, + snippets = { preset = "luasnip" }, + completion = { + documentation = { auto_show = false, auto_show_delay_ms = 200 }, + ghost_text = { enabled = false }, + menu = { + auto_show = true, + max_height = 5, + draw = { + -- no kind_icon column -- plain text only, no nerd font glyphs + columns = { { "label", "label_description", gap = 1 } }, + }, + }, + }, + }, + }, + { + "L3MON4D3/LuaSnip", + event = "InsertEnter", + dependencies = { "rafamadriz/friendly-snippets" }, + config = function() + require("luasnip.loaders.from_vscode").lazy_load() + end, + }, + + -- LSP + { + "neovim/nvim-lspconfig", + event = { "BufReadPre", "BufNewFile" }, + dependencies = { "saghen/blink.cmp" }, + config = function() + vim.lsp.config("*", { + capabilities = require("blink.cmp").get_lsp_capabilities(), + }) + + vim.lsp.enable({ "clangd" }) + + vim.api.nvim_create_autocmd("LspAttach", { + callback = function(ev) + local m = function(keys, func, desc) + vim.keymap.set("n", keys, func, { buffer = ev.buf, desc = "LSP: " .. desc }) + end + if vim.lsp.inlay_hint then + vim.lsp.inlay_hint.enable(true, { bufnr = ev.buf }) + end + m("gd", vim.lsp.buf.definition, "Goto definition") + m("gD", vim.lsp.buf.declaration, "Goto declaration") + m("gr", vim.lsp.buf.references, "Goto references") + m("gI", vim.lsp.buf.implementation, "Goto implementation") + m("K", vim.lsp.buf.hover, "Hover docs") + m("<leader>rn", vim.lsp.buf.rename, "Rename") + m("[d", vim.diagnostic.goto_prev, "Prev diagnostic") + m("]d", vim.diagnostic.goto_next, "Next diagnostic") + m("<leader>e", vim.diagnostic.open_float, "Show diagnostic") + end, + }) + + vim.diagnostic.config({ + virtual_text = true, + signs = { + text = { + [vim.diagnostic.severity.ERROR] = "E", + [vim.diagnostic.severity.WARN] = "W", + [vim.diagnostic.severity.INFO] = "I", + [vim.diagnostic.severity.HINT] = "H", + }, + }, + underline = true, + update_in_insert = false, + }) + end, + }, + +}, { + install = { colorscheme = { "vim" } }, + checker = { enabled = false }, + change_detection = { notify = false }, +}) + +vim.cmd.colorscheme("vim") |