From bb91392a215e70ad66bce3b8d200b9c541ec1b286157f533cc21363cf4ea9140 Mon Sep 17 00:00:00 2001 From: Wesley van Tilburg Date: Mon, 9 Mar 2026 16:07:08 +0000 Subject: [PATCH] initial config push --- KEYBINDS.md | 150 +++++++++++++++++++++++++++ init.lua | 10 ++ lua/core/autocmds.lua | 201 +++++++++++++++++++++++++++++++++++++ lua/core/options.lua | 98 ++++++++++++++++++ lua/core/plugins.lua | 9 ++ lua/plugins/cmp.lua | 6 ++ lua/plugins/lsp.lua | 133 ++++++++++++++++++++++++ lua/plugins/oil.lua | 150 +++++++++++++++++++++++++++ lua/plugins/overseer.lua | 1 + lua/plugins/theme.lua | 5 + lua/plugins/treesitter.lua | 3 + nvim-pack-lock.json | 37 +++++++ session.vim | 95 ++++++++++++++++++ 13 files changed, 898 insertions(+) create mode 100644 KEYBINDS.md create mode 100644 init.lua create mode 100644 lua/core/autocmds.lua create mode 100644 lua/core/options.lua create mode 100644 lua/core/plugins.lua create mode 100644 lua/plugins/cmp.lua create mode 100644 lua/plugins/lsp.lua create mode 100644 lua/plugins/oil.lua create mode 100644 lua/plugins/overseer.lua create mode 100644 lua/plugins/theme.lua create mode 100644 lua/plugins/treesitter.lua create mode 100644 nvim-pack-lock.json create mode 100644 session.vim diff --git a/KEYBINDS.md b/KEYBINDS.md new file mode 100644 index 0000000..7162709 --- /dev/null +++ b/KEYBINDS.md @@ -0,0 +1,150 @@ +# Neovim Keybinds & Commands Cheatsheet + +## LSP (built-in, Neovim 0.11+) + +| Key | Action | +|-----|--------| +| `grn` | Rename symbol | +| `grr` | Go to references | +| `gra` | Code action | +| `gri` | Go to implementation | +| `gO` | Document symbols | +| `gd` | Go to definition | +| `gD` | Go to declaration | +| `K` | Hover documentation | +| `` (insert) | Signature help | + +## Diagnostics (built-in) + +| Key / Command | Action | +|---------------|--------| +| `[d` | Previous diagnostic | +| `]d` | Next diagnostic | +| `d` | Open diagnostic float | +| `:lua vim.diagnostic.setqflist()` | All diagnostics to quickfix | +| `:lua vim.diagnostic.setloclist()` | Buffer diagnostics to loclist | + +## Autocompletion (blink.cmp) + +| Key | Action | +|-----|--------| +| `` | Trigger completion menu | +| `` | Next item | +| `` | Previous item | +| `` | Confirm selection | +| `` | Dismiss menu | +| `` | Scroll docs up | +| `` | Scroll docs down | + +Sources: LSP, buffer words, file paths. + +## Buffer Navigation + +| Key | Action | +|-----|--------| +| `` | Next buffer | +| `` | Previous buffer | +| `x` | Close current buffer | + +Each split window shows its own filename bar (winbar) at the top. + +## File Explorer (oil.nvim) + +| Key / Command | Action | +|---------------|--------| +| `e` | Toggle file tree (left sidebar) | +| `-` or `` | Go up one directory (in file tree) | +| `` | Open file in last used code window (auto-focuses there) | +| `g.` | Toggle hidden files | +| `` | Preview file | +| `` | Close oil | +| `:w` (in oil buffer) | Save filesystem changes (renames, deletes, etc.) | + +Edit filenames directly in the buffer, then `:w` to apply. + +## Task Runner (overseer.nvim) + +| Command | Action | +|---------|--------| +| `:OverseerRun` | Pick and run a task | +| `:OverseerToggle` | Toggle task list panel | +| `:OverseerInfo` | Show overseer status/info | +| `:OverseerBuild` | Build a task from scratch | +| `:OverseerQuickAction` | Run quick action on recent task | +| `:OverseerTaskAction` | Pick a task, then an action | +| `:OverseerClearCache` | Clear cached tasks | + +Tasks integrate with quickfix: errors from tasks populate the quickfix list. + +## Mason (LSP server management) + +| Command | Action | +|---------|--------| +| `:Mason` | Open Mason UI | +| `:MasonInstall ` | Install a server | +| `:MasonUninstall ` | Remove a server | +| `:MasonUpdate` | Update all servers | +| `:MasonLog` | View install logs | + +Auto-installed servers: `gopls`, `bashls`, `ansiblels`, `yamlls`. + +## Treesitter + +| Command | Action | +|---------|--------| +| `:TSInstall ` | Install a parser | +| `:TSUpdate` | Update all parsers | +| `:TSInstall go bash yaml lua` | Install all configured parsers | + +Syntax highlighting is automatic once a parser is installed. + +## Quickfix List (built-in) + +| Key / Command | Action | +|---------------|--------| +| `:copen` | Open quickfix window | +| `:cclose` | Close quickfix window | +| `:cnext` / `]q` | Next quickfix item | +| `:cprev` / `[q` | Previous quickfix item | +| `:cfirst` | First item | +| `:clast` | Last item | + +## Window Resizing (built-in) + +| Key | Action | +|-----|--------| +| `>` | Wider (right) | +| `<` | Narrower (left) | +| `+` | Taller | +| `-` | Shorter | +| `=` | Equal size all | +| `10>` | Wider by 10 columns | + +## General (built-in) + +| Key | Action | +|-----|--------| +| `s` | Split horizontal | +| `v` | Split vertical | +| `` | Toggle floating popup terminal | +| `` | Move between panes (also works from terminal) | +| `h/j/k/l` | Move between panes (default) | +| `:e ` | Open file | +| `u` | Undo | +| `` | Redo | +| `.` | Repeat last change | +| `*` | Search word under cursor | +| `:noh` | Clear search highlight | + +## Sessions / Layout + +| Key | Action | +|-----|--------| +| `ss` | Save current layout/session | +| `sl` | Load saved layout/session | + +Saves window positions, sizes, buffers, and current directory. + +## Statusline + +Shows: `filename [modified] [readonly]` on the left, `git-branch | line:col percent` on the right. diff --git a/init.lua b/init.lua new file mode 100644 index 0000000..0c242b6 --- /dev/null +++ b/init.lua @@ -0,0 +1,10 @@ +require("core.options") +require("core.autocmds") +require("core.plugins") + +require("plugins.theme") +require("plugins.treesitter") +require("plugins.lsp") +require("plugins.cmp") +require("plugins.oil") +require("plugins.overseer") diff --git a/lua/core/autocmds.lua b/lua/core/autocmds.lua new file mode 100644 index 0000000..ffad7ac --- /dev/null +++ b/lua/core/autocmds.lua @@ -0,0 +1,201 @@ +-- Highlight on yank +vim.api.nvim_create_autocmd("TextYankPost", { + group = vim.api.nvim_create_augroup("highlight_yank", { clear = true }), + callback = function() + vim.hl.on_yank() + end, +}) + +-- Buffer tab navigation (scoped to current window) +local function cycle_win_buf(dir) + local bufs = _G.get_win_bufs() + if #bufs <= 1 then return end + local current = vim.api.nvim_get_current_buf() + for i, buf in ipairs(bufs) do + if buf == current then + local next = bufs[((i - 1 + dir) % #bufs) + 1] + vim.api.nvim_set_current_buf(next) + return + end + end +end +vim.keymap.set("n", "", function() cycle_win_buf(1) end, { desc = "Next buffer tab" }) +vim.keymap.set("n", "", function() cycle_win_buf(-1) end, { desc = "Previous buffer tab" }) +vim.keymap.set("n", "x", function() + local bufs = _G.get_win_bufs() + local current = vim.api.nvim_get_current_buf() + -- Switch to another buffer in this window, or create a blank one + local switched = false + for _, buf in ipairs(bufs) do + if buf ~= current then + vim.api.nvim_set_current_buf(buf) + switched = true + break + end + end + if not switched then + vim.cmd("enew") + vim.bo.bufhidden = "wipe" + end + vim.cmd("bdelete " .. current) +end, { desc = "Close buffer tab" }) + + +-- Splits duplicate current file (default Vim behavior) +vim.keymap.set("n", "v", ":vsplit", { desc = "Vertical split" }) +vim.keymap.set("n", "s", ":split", { desc = "Horizontal split" }) + +-- Move between panes with Alt+h/l, wraps around (works in normal and terminal mode) +local function wrap_move(dir) + local cur = vim.api.nvim_get_current_win() + vim.cmd("wincmd " .. dir) + if vim.api.nvim_get_current_win() == cur then + -- Didn't move, wrap around + local opposite = ({ h = "l", l = "h", j = "k", k = "j" })[dir] + -- Go to the far opposite end + vim.cmd("99wincmd " .. opposite) + end +end +vim.keymap.set("n", "", function() wrap_move("h") end, { desc = "Move to left pane (wrap)" }) +vim.keymap.set("n", "", function() wrap_move("l") end, { desc = "Move to right pane (wrap)" }) +vim.keymap.set("n", "", function() wrap_move("j") end, { desc = "Move to pane below (wrap)" }) +vim.keymap.set("n", "", function() wrap_move("k") end, { desc = "Move to pane above (wrap)" }) +vim.keymap.set("t", "", function() vim.cmd("stopinsert") wrap_move("h") end, { desc = "Move to left pane (wrap)" }) +vim.keymap.set("t", "", function() vim.cmd("stopinsert") wrap_move("l") end, { desc = "Move to right pane (wrap)" }) +vim.keymap.set("t", "", function() vim.cmd("stopinsert") wrap_move("j") end, { desc = "Move to pane below (wrap)" }) +vim.keymap.set("t", "", function() vim.cmd("stopinsert") wrap_move("k") end, { desc = "Move to pane above (wrap)" }) + +-- Floating popup terminal with tabs (toggle with ) +local popup_term = { bufs = {}, current = 1, win = nil } + +local function ensure_term_buf(idx) + if not popup_term.bufs[idx] or not vim.api.nvim_buf_is_valid(popup_term.bufs[idx]) then + popup_term.bufs[idx] = vim.api.nvim_create_buf(false, true) + end + return popup_term.bufs[idx] +end + +local function term_title() + local parts = {} + for i = 1, #popup_term.bufs do + if not vim.api.nvim_buf_is_valid(popup_term.bufs[i]) then break end + if i == popup_term.current then + parts[#parts + 1] = "[" .. i .. "]" + else + parts[#parts + 1] = " " .. i .. " " + end + end + return " Terminal " .. table.concat(parts) .. " " +end + +local function open_popup_win(buf) + local width = math.floor(vim.o.columns * 0.8) + local height = math.floor(vim.o.lines * 0.75) + popup_term.win = vim.api.nvim_open_win(buf, true, { + relative = "editor", + width = width, + height = height, + col = math.floor((vim.o.columns - width) / 2), + row = math.floor((vim.o.lines - height) / 2) - 1, + style = "minimal", + border = "rounded", + title = term_title(), + title_pos = "center", + }) +end + +local function update_title() + if popup_term.win and vim.api.nvim_win_is_valid(popup_term.win) then + vim.api.nvim_win_set_config(popup_term.win, { title = term_title() }) + end +end + +local function switch_term(idx) + if idx < 1 or idx > #popup_term.bufs then return end + popup_term.current = idx + local buf = ensure_term_buf(idx) + if popup_term.win and vim.api.nvim_win_is_valid(popup_term.win) then + vim.api.nvim_win_set_buf(popup_term.win, buf) + update_title() + if vim.bo[buf].buftype == "terminal" then + vim.cmd.startinsert() + end + end +end + +local function toggle_popup_term() + if popup_term.win and vim.api.nvim_win_is_valid(popup_term.win) then + vim.api.nvim_win_hide(popup_term.win) + popup_term.win = nil + return + end + + local buf = ensure_term_buf(popup_term.current) + open_popup_win(buf) + + if vim.bo[buf].buftype ~= "terminal" then + vim.cmd.terminal() + end + vim.cmd.startinsert() +end + +local function new_term_tab() + local idx = #popup_term.bufs + 1 + ensure_term_buf(idx) + popup_term.current = idx + if popup_term.win and vim.api.nvim_win_is_valid(popup_term.win) then + vim.api.nvim_win_set_buf(popup_term.win, popup_term.bufs[idx]) + update_title() + vim.cmd.terminal() + vim.cmd.startinsert() + end +end + +local function close_term_tab() + if #popup_term.bufs <= 1 then return end + local buf = popup_term.bufs[popup_term.current] + table.remove(popup_term.bufs, popup_term.current) + if popup_term.current > #popup_term.bufs then + popup_term.current = #popup_term.bufs + end + switch_term(popup_term.current) + if vim.api.nvim_buf_is_valid(buf) then + vim.api.nvim_buf_delete(buf, { force = true }) + end +end + +-- Init first tab +ensure_term_buf(1) + +vim.keymap.set("n", "", toggle_popup_term, { desc = "Toggle popup terminal" }) +vim.keymap.set("t", "", toggle_popup_term, { desc = "Toggle popup terminal" }) +vim.keymap.set("t", "", function() switch_term(popup_term.current % #popup_term.bufs + 1) end, { desc = "Next terminal tab" }) +vim.keymap.set("t", "", function() switch_term((popup_term.current - 2) % #popup_term.bufs + 1) end, { desc = "Prev terminal tab" }) +vim.keymap.set("t", "", new_term_tab, { desc = "New terminal tab" }) +vim.keymap.set("t", "", close_term_tab, { desc = "Close terminal tab" }) + +-- Terminal copy/paste +vim.keymap.set("t", "", function() + local reg = vim.fn.getreg("+") + if reg ~= "" then + vim.api.nvim_paste(reg, true, -1) + end +end, { desc = "Paste from clipboard" }) +vim.keymap.set("t", "", [[V]], { desc = "Select current line (normal mode)" }) +vim.keymap.set("t", "", [[]], { desc = "Exit to normal mode" }) + +-- Save/restore layout with :mksession +vim.opt.sessionoptions = "buffers,curdir,folds,winpos,winsize,terminal" +vim.keymap.set("n", "ss", ":mksession! ~/.config/nvim/session.vim", { desc = "Save session/layout" }) +vim.keymap.set("n", "sl", ":source ~/.config/nvim/session.vim", { desc = "Load session/layout" }) + +-- Trim trailing whitespace on save +vim.api.nvim_create_autocmd("BufWritePre", { + group = vim.api.nvim_create_augroup("trim_whitespace", { clear = true }), + pattern = "*", + callback = function() + local pos = vim.api.nvim_win_get_cursor(0) + vim.cmd([[%s/\s\+$//e]]) + vim.api.nvim_win_set_cursor(0, pos) + end, +}) diff --git a/lua/core/options.lua b/lua/core/options.lua new file mode 100644 index 0000000..6ded463 --- /dev/null +++ b/lua/core/options.lua @@ -0,0 +1,98 @@ +local opt = vim.opt + +-- Line numbers +opt.number = true +opt.relativenumber = false + +-- Search +opt.ignorecase = true +opt.smartcase = true +opt.hlsearch = true +opt.incsearch = true + +-- Tabs / indentation +opt.expandtab = true +opt.shiftwidth = 4 +opt.tabstop = 4 +opt.smartindent = true + +-- Undo +opt.undofile = true + +-- UI +opt.termguicolors = true +opt.signcolumn = "yes" +opt.scrolloff = 8 +opt.splitbelow = true +opt.splitright = true +opt.equalalways = false +opt.cursorline = true + +-- Per-window buffer tabs (winbar) +-- Track which buffers were opened in each window +_G.win_bufs = {} + +function _G.track_buf() + local win = vim.api.nvim_get_current_win() + local buf = vim.api.nvim_get_current_buf() + if not vim.bo[buf].buflisted or vim.bo[buf].filetype == "oil" then return end + if not _G.win_bufs[win] then _G.win_bufs[win] = {} end + -- Remove if already tracked, then add to end + for i, b in ipairs(_G.win_bufs[win]) do + if b == buf then table.remove(_G.win_bufs[win], i) break end + end + table.insert(_G.win_bufs[win], buf) +end + +function _G.get_win_bufs() + local win = vim.api.nvim_get_current_win() + local bufs = {} + for _, buf in ipairs(_G.win_bufs[win] or {}) do + if vim.api.nvim_buf_is_valid(buf) and vim.bo[buf].buflisted then + table.insert(bufs, buf) + end + end + _G.win_bufs[win] = bufs + return bufs +end + +function _G.winbar_tabs() + local bufs = _G.get_win_bufs() + if #bufs == 0 then return "" end + local current = vim.api.nvim_get_current_buf() + local parts = {} + for _, buf in ipairs(bufs) do + local name = vim.fn.fnamemodify(vim.api.nvim_buf_get_name(buf), ":t") + if name == "" then name = "[No Name]" end + local mod = vim.bo[buf].modified and " +" or "" + if buf == current then + table.insert(parts, "%#TabLineSel# " .. name .. mod .. " %#WinBar#") + else + table.insert(parts, " " .. name .. mod .. " ") + end + end + return table.concat(parts, "|") +end + +vim.api.nvim_create_autocmd("BufEnter", { + group = vim.api.nvim_create_augroup("track_win_bufs", { clear = true }), + callback = function() _G.track_buf() end, +}) + +opt.winbar = "%{%v:lua.winbar_tabs()%}" + +-- Clipboard (system) +opt.clipboard = "unnamedplus" + +-- Statusline (with git branch) +function _G.git_branch() + local branch = vim.fn.system("git -C " .. vim.fn.shellescape(vim.fn.expand("%:p:h")) .. " branch --show-current 2>/dev/null") + branch = branch:gsub("%s+", "") + if branch == "" then return "" end + return " " .. branch .. " |" +end +opt.statusline = " %f %m%r%=%{v:lua.git_branch()} %l:%c %p%% " + +-- Misc +opt.updatetime = 250 +opt.mouse = "a" diff --git a/lua/core/plugins.lua b/lua/core/plugins.lua new file mode 100644 index 0000000..5dd9d44 --- /dev/null +++ b/lua/core/plugins.lua @@ -0,0 +1,9 @@ +vim.pack.add({ + "https://github.com/rebelot/kanagawa.nvim", + "https://github.com/nvim-treesitter/nvim-treesitter", + "https://github.com/williamboman/mason.nvim", + "https://github.com/williamboman/mason-lspconfig.nvim", + { src = "https://github.com/saghen/blink.cmp", version = vim.version.range("1.*") }, + "https://github.com/stevearc/oil.nvim", + "https://github.com/stevearc/overseer.nvim", +}) diff --git a/lua/plugins/cmp.lua b/lua/plugins/cmp.lua new file mode 100644 index 0000000..936b73c --- /dev/null +++ b/lua/plugins/cmp.lua @@ -0,0 +1,6 @@ +require("blink.cmp").setup({ + keymap = { preset = "default" }, + sources = { + default = { "lsp", "path", "buffer" }, + }, +}) diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua new file mode 100644 index 0000000..4e4ccbd --- /dev/null +++ b/lua/plugins/lsp.lua @@ -0,0 +1,133 @@ +require("mason").setup() + +-- Add mason bin to PATH so vim.lsp.enable can find installed servers +vim.env.PATH = vim.fn.stdpath("data") .. "/mason/bin:" .. vim.env.PATH + +require("mason-lspconfig").setup({ + ensure_installed = { + "gopls", + "bashls", + "ansiblels", + "yamlls", + }, +}) + +vim.lsp.config("gopls", { + cmd = { "gopls" }, + filetypes = { "go", "gomod", "gowork", "gotmpl" }, + root_markers = { "go.mod", "go.work", ".git" }, + settings = { + gopls = { + analyses = { + unusedparams = true, + shadow = true, + nilness = true, + unusedwrite = true, + useany = true, + }, + staticcheck = true, + gofumpt = true, + }, + }, +}) +vim.lsp.config("bashls", { + cmd = { "bash-language-server", "start" }, + filetypes = { "sh", "bash" }, +}) +vim.lsp.config("ansiblels", { + cmd = { "ansible-language-server", "--stdio" }, + filetypes = { "yaml.ansible" }, + root_markers = { "ansible.cfg", ".ansible-lint", "playbooks" }, +}) +vim.lsp.config("yamlls", { + cmd = { "yaml-language-server", "--stdio" }, + filetypes = { "yaml", "yaml.docker-compose" }, +}) + +vim.lsp.enable({ "gopls", "bashls", "ansiblels", "yamlls" }) + +-- Diagnostics UI +vim.diagnostic.config({ + virtual_text = true, + signs = true, + underline = true, + update_in_insert = false, + float = { border = "rounded" }, +}) + +-- LSP keymaps (set when an LSP attaches) +vim.api.nvim_create_autocmd("LspAttach", { + group = vim.api.nvim_create_augroup("lsp_keymaps", { clear = true }), + callback = function(ev) + local opts = { buffer = ev.buf } + + -- Jump to definition, reusing an existing split if the file is already open + local function goto_definition_reuse() + local params = vim.lsp.util.make_position_params(0, "utf-8") + vim.lsp.buf_request(0, "textDocument/definition", params, function(err, result) + if err or not result or vim.tbl_isempty(result) then return end + local target = result[1] or result + local uri = target.uri or target.targetUri + local range = target.range or target.targetSelectionRange + local bufnr = vim.uri_to_bufnr(uri) + -- Check if file is already visible in a window + for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do + if vim.api.nvim_win_get_buf(win) == bufnr then + vim.api.nvim_set_current_win(win) + local pos = range.start + vim.api.nvim_win_set_cursor(win, { pos.line + 1, pos.character }) + return + end + end + -- Not open anywhere, use default behavior + vim.lsp.util.show_document(target, "utf-8", { focus = true }) + end) + end + + -- Navigation + vim.keymap.set("n", "gd", goto_definition_reuse, 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", "gt", vim.lsp.buf.type_definition, opts) + + -- Info + vim.keymap.set("n", "K", vim.lsp.buf.hover, opts) + vim.keymap.set("n", "", vim.lsp.buf.signature_help, opts) + vim.keymap.set("i", "", vim.lsp.buf.signature_help, opts) + + -- Actions + vim.keymap.set("n", "ca", vim.lsp.buf.code_action, opts) + vim.keymap.set("n", "rn", vim.lsp.buf.rename, opts) + vim.keymap.set("n", "f", function() vim.lsp.buf.format({ async = true }) end, opts) + + -- Diagnostics + vim.keymap.set("n", "[d", vim.diagnostic.goto_prev, opts) + vim.keymap.set("n", "]d", vim.diagnostic.goto_next, opts) + vim.keymap.set("n", "q", vim.diagnostic.setloclist, opts) + vim.keymap.set("n", "gl", vim.diagnostic.open_float, opts) + end, +}) + +-- Auto-format and organize imports on save for Go +vim.api.nvim_create_autocmd("BufWritePre", { + group = vim.api.nvim_create_augroup("go_organize_imports", { clear = true }), + pattern = "*.go", + callback = function() + -- Organize imports via code action + local params = vim.lsp.util.make_range_params(0, "utf-8") + params.context = { only = { "source.organizeImports" } } + local result = vim.lsp.buf_request_sync(0, "textDocument/codeAction", params, 1000) + for _, res in pairs(result or {}) do + for _, action in pairs(res.result or {}) do + if action.edit then + vim.lsp.util.apply_workspace_edit(action.edit, "utf-8") + elseif action.command then + vim.lsp.buf.execute_command(action.command) + end + end + end + -- Format + vim.lsp.buf.format({ async = false }) + end, +}) diff --git a/lua/plugins/oil.lua b/lua/plugins/oil.lua new file mode 100644 index 0000000..9ef6f38 --- /dev/null +++ b/lua/plugins/oil.lua @@ -0,0 +1,150 @@ +-- Track the last focused code window (not oil, not terminal) +_G.last_code_win = nil + +vim.api.nvim_create_autocmd("WinEnter", { + group = vim.api.nvim_create_augroup("track_code_win", { clear = true }), + callback = function() + local buf = vim.api.nvim_get_current_buf() + local ft = vim.bo[buf].filetype + local bt = vim.bo[buf].buftype + if ft ~= "oil" and bt ~= "terminal" then + _G.last_code_win = vim.api.nvim_get_current_win() + end + end, +}) + +require("oil").setup({ + watch_for_changes = true, + keymaps = { + [""] = false, -- disable default, we override below + [""] = false, -- don't override global (popup terminal) + }, +}) + +-- Override in oil buffers to open in last code window +vim.api.nvim_create_autocmd("FileType", { + group = vim.api.nvim_create_augroup("oil_open_in_code", { clear = true }), + pattern = "oil", + callback = function(ev) + -- Go up a directory with backspace or - + vim.keymap.set("n", "", function() + require("oil").open(require("oil").get_current_dir() .. "..") + end, { buffer = ev.buf, desc = "Go up directory" }) + + vim.keymap.set("n", "-", function() + require("oil").open(require("oil").get_current_dir() .. "..") + end, { buffer = ev.buf, desc = "Go up directory" }) + + -- Delete file under cursor + vim.keymap.set("n", "d", function() + local oil = require("oil") + local entry = oil.get_cursor_entry() + if not entry then return end + local dir = oil.get_current_dir() + if not dir then return end + local path = dir .. entry.name + vim.ui.input({ prompt = "Delete " .. entry.name .. "? (y/n): " }, function(input) + if input == "y" then + vim.fn.delete(path, entry.type == "directory" and "rf" or "") + oil.discard_all_changes() + end + end) + end, { buffer = ev.buf, desc = "Delete file/dir" }) + + -- Open file in code window, then auto-focus back to code + vim.keymap.set("n", "", function() + local oil = require("oil") + local entry = oil.get_cursor_entry() + if not entry then return end + + -- Directories: navigate normally in oil + if entry.type == "directory" then + oil.select() + return + end + + local dir = oil.get_current_dir() + if not dir then return end + local filepath = dir .. entry.name + local target_win = nil + + -- Try last focused code window + if _G.last_code_win and vim.api.nvim_win_is_valid(_G.last_code_win) then + local buf = vim.api.nvim_win_get_buf(_G.last_code_win) + if vim.bo[buf].filetype ~= "oil" and vim.bo[buf].buftype ~= "terminal" then + target_win = _G.last_code_win + end + end + + -- Fallback: find any non-oil, non-terminal window + if not target_win then + local cur_win = vim.api.nvim_get_current_win() + for _, win in ipairs(vim.api.nvim_tabpage_list_wins(0)) do + if win ~= cur_win and vim.api.nvim_win_get_config(win).relative == "" then + local buf = vim.api.nvim_win_get_buf(win) + if vim.bo[buf].filetype ~= "oil" and vim.bo[buf].buftype ~= "terminal" then + target_win = win + break + end + end + end + end + + if target_win then + vim.api.nvim_set_current_win(target_win) + -- Remember blank buffer to clean up after opening + local old_buf = vim.api.nvim_get_current_buf() + local is_blank = vim.api.nvim_buf_get_name(old_buf) == "" + and not vim.bo[old_buf].modified + and vim.api.nvim_buf_line_count(old_buf) <= 1 + and vim.api.nvim_buf_get_lines(old_buf, 0, 1, false)[1] == "" + vim.cmd.edit(vim.fn.fnameescape(filepath)) + if is_blank and old_buf ~= vim.api.nvim_get_current_buf() then + vim.api.nvim_buf_delete(old_buf, { force = true }) + end + else + -- No code window exists: create a split to the right + vim.cmd("rightbelow vsplit " .. vim.fn.fnameescape(filepath)) + end + end, { buffer = ev.buf, desc = "Open file in code window" }) + end, +}) + +-- Toggle file tree on the left with e +_G.oil_tree_win = nil + +local function open_tree() + vim.cmd("topleft vsplit | vertical resize 30") + _G.oil_tree_win = vim.api.nvim_get_current_win() + require("oil").open() +end + +vim.keymap.set("n", "e", function() + if _G.oil_tree_win and vim.api.nvim_win_is_valid(_G.oil_tree_win) then + vim.api.nvim_win_close(_G.oil_tree_win, true) + _G.oil_tree_win = nil + else + open_tree() + end +end, { desc = "Toggle file tree" }) + +-- Open file tree on startup (deferred so oil is fully loaded) +vim.api.nvim_create_autocmd("VimEnter", { + group = vim.api.nvim_create_augroup("oil_startup", { clear = true }), + callback = function() + vim.schedule(function() + open_tree() + vim.cmd("wincmd l") + end) + end, +}) + +-- Keep oil tree pinned at 30 columns after layout changes +vim.api.nvim_create_autocmd("WinResized", { + group = vim.api.nvim_create_augroup("oil_pin_width", { clear = true }), + callback = function() + if _G.oil_tree_win and vim.api.nvim_win_is_valid(_G.oil_tree_win) then + vim.api.nvim_win_set_width(_G.oil_tree_win, 30) + end + end, +}) diff --git a/lua/plugins/overseer.lua b/lua/plugins/overseer.lua new file mode 100644 index 0000000..68433d0 --- /dev/null +++ b/lua/plugins/overseer.lua @@ -0,0 +1 @@ +require("overseer").setup() diff --git a/lua/plugins/theme.lua b/lua/plugins/theme.lua new file mode 100644 index 0000000..c40ddcd --- /dev/null +++ b/lua/plugins/theme.lua @@ -0,0 +1,5 @@ +require("kanagawa").setup({ + theme = "wave", +}) + +vim.cmd.colorscheme("kanagawa") diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua new file mode 100644 index 0000000..812ccf7 --- /dev/null +++ b/lua/plugins/treesitter.lua @@ -0,0 +1,3 @@ +-- nvim-treesitter on 0.12+ only provides :TSInstall for parser management +-- Treesitter highlighting is enabled automatically when a parser is available +-- Run :TSInstall go bash yaml lua to install parsers diff --git a/nvim-pack-lock.json b/nvim-pack-lock.json new file mode 100644 index 0000000..44d48b3 --- /dev/null +++ b/nvim-pack-lock.json @@ -0,0 +1,37 @@ +{ + "plugins": { + "blink.cmp": { + "rev": "e9556f9b981f395e22a6bfd69fd5f3008a2a6cd9", + "src": "https://github.com/saghen/blink.cmp", + "version": "1.0.0 - 2.0.0" + }, + "kanagawa.nvim": { + "rev": "aef7f5cec0a40dbe7f3304214850c472e2264b10", + "src": "https://github.com/rebelot/kanagawa.nvim" + }, + "mason-lspconfig.nvim": { + "rev": "a324581a3c83fdacdb9804b79de1cbe00ce18550", + "src": "https://github.com/williamboman/mason-lspconfig.nvim" + }, + "mason.nvim": { + "rev": "44d1e90e1f66e077268191e3ee9d2ac97cc18e65", + "src": "https://github.com/williamboman/mason.nvim" + }, + "nvim-lspconfig": { + "rev": "2b87d107942b9eebef768512f5849330335a9493", + "src": "https://github.com/neovim/nvim-lspconfig" + }, + "nvim-treesitter": { + "rev": "1970f0d3bbb99c7659e58914948749437c7b7398", + "src": "https://github.com/nvim-treesitter/nvim-treesitter" + }, + "oil.nvim": { + "rev": "0fcc83805ad11cf714a949c98c605ed717e0b83e", + "src": "https://github.com/stevearc/oil.nvim" + }, + "overseer.nvim": { + "rev": "2802c15182dae2de71f9c82e918d7ba850b90c22", + "src": "https://github.com/stevearc/overseer.nvim" + } + } +} \ No newline at end of file diff --git a/session.vim b/session.vim new file mode 100644 index 0000000..6534834 --- /dev/null +++ b/session.vim @@ -0,0 +1,95 @@ +let SessionLoad = 1 +let s:so_save = &g:so | let s:siso_save = &g:siso | setg so=0 siso=0 | setl so=-1 siso=-1 +let v:this_session=expand(":p") +doautoall SessionLoadPre +silent only +cd ~ +if expand('%') == '' && !&modified && line('$') <= 1 && getline(1) == '' + let s:wipebuf = bufnr('%') +endif +let s:shortmess_save = &shortmess +set shortmess+=aoO +badd +1 ~/Projects/Referit-Monitoring/devops/azure-pipeline.yml +badd +1 ~/Projects/Referit-Monitoring/devops/jobs/deploy-bicep.yml +badd +1 ~/Projects/Referit-Monitoring/devops/jobs/detect-changes.yml +argglobal +%argdel +edit ~/Projects/Referit-Monitoring/devops/jobs/detect-changes.yml +let s:save_splitbelow = &splitbelow +let s:save_splitright = &splitright +set splitbelow splitright +wincmd _ | wincmd | +vsplit +1wincmd h +wincmd w +let &splitbelow = s:save_splitbelow +let &splitright = s:save_splitright +wincmd t +let s:save_winminheight = &winminheight +let s:save_winminwidth = &winminwidth +set winminheight=0 +set winheight=1 +set winminwidth=0 +set winwidth=1 +wincmd = +argglobal +balt ~/Projects/Referit-Monitoring/devops/jobs/deploy-bicep.yml +setlocal foldmethod=manual +setlocal foldexpr=0 +setlocal foldmarker={{{,}}} +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldenable +silent! normal! zE +let &fdl = &fdl +let s:l = 56 - ((55 * winheight(0) + 36) / 73) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 56 +normal! 08| +wincmd w +argglobal +if bufexists(fnamemodify("~/Projects/Referit-Monitoring/devops/azure-pipeline.yml", ":p")) | buffer ~/Projects/Referit-Monitoring/devops/azure-pipeline.yml | else | edit ~/Projects/Referit-Monitoring/devops/azure-pipeline.yml | endif +if &buftype ==# 'terminal' + silent file ~/Projects/Referit-Monitoring/devops/azure-pipeline.yml +endif +balt ~/Projects/Referit-Monitoring/devops/jobs/detect-changes.yml +setlocal foldmethod=manual +setlocal foldexpr=0 +setlocal foldmarker={{{,}}} +setlocal foldignore=# +setlocal foldlevel=0 +setlocal foldminlines=1 +setlocal foldnestmax=20 +setlocal foldenable +silent! normal! zE +let &fdl = &fdl +let s:l = 1 - ((0 * winheight(0) + 36) / 73) +if s:l < 1 | let s:l = 1 | endif +keepjumps exe s:l +normal! zt +keepjumps 1 +normal! 0 +wincmd w +wincmd = +if exists('s:wipebuf') && len(win_findbuf(s:wipebuf)) == 0 && getbufvar(s:wipebuf, '&buftype') isnot# 'terminal' + silent exe 'bwipe ' . s:wipebuf +endif +unlet! s:wipebuf +set winheight=1 winwidth=20 +let &shortmess = s:shortmess_save +let &winminheight = s:save_winminheight +let &winminwidth = s:save_winminwidth +let s:sx = expand(":p:r")."x.vim" +if filereadable(s:sx) + exe "source " . fnameescape(s:sx) +endif +let &g:so = s:so_save | let &g:siso = s:siso_save +set hlsearch +nohlsearch +doautoall SessionLoadPost +unlet SessionLoad +" vim: set ft=vim :