initial config push
This commit is contained in:
201
lua/core/autocmds.lua
Normal file
201
lua/core/autocmds.lua
Normal file
@@ -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", "<Tab>", function() cycle_win_buf(1) end, { desc = "Next buffer tab" })
|
||||
vim.keymap.set("n", "<S-Tab>", function() cycle_win_buf(-1) end, { desc = "Previous buffer tab" })
|
||||
vim.keymap.set("n", "<leader>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", "<C-w>v", ":vsplit<CR>", { desc = "Vertical split" })
|
||||
vim.keymap.set("n", "<C-w>s", ":split<CR>", { 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", "<A-h>", function() wrap_move("h") end, { desc = "Move to left pane (wrap)" })
|
||||
vim.keymap.set("n", "<A-l>", function() wrap_move("l") end, { desc = "Move to right pane (wrap)" })
|
||||
vim.keymap.set("n", "<A-j>", function() wrap_move("j") end, { desc = "Move to pane below (wrap)" })
|
||||
vim.keymap.set("n", "<A-k>", function() wrap_move("k") end, { desc = "Move to pane above (wrap)" })
|
||||
vim.keymap.set("t", "<A-h>", function() vim.cmd("stopinsert") wrap_move("h") end, { desc = "Move to left pane (wrap)" })
|
||||
vim.keymap.set("t", "<A-l>", function() vim.cmd("stopinsert") wrap_move("l") end, { desc = "Move to right pane (wrap)" })
|
||||
vim.keymap.set("t", "<A-j>", function() vim.cmd("stopinsert") wrap_move("j") end, { desc = "Move to pane below (wrap)" })
|
||||
vim.keymap.set("t", "<A-k>", function() vim.cmd("stopinsert") wrap_move("k") end, { desc = "Move to pane above (wrap)" })
|
||||
|
||||
-- Floating popup terminal with tabs (toggle with <C-t>)
|
||||
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", "<C-t>", toggle_popup_term, { desc = "Toggle popup terminal" })
|
||||
vim.keymap.set("t", "<C-t>", toggle_popup_term, { desc = "Toggle popup terminal" })
|
||||
vim.keymap.set("t", "<A-]>", function() switch_term(popup_term.current % #popup_term.bufs + 1) end, { desc = "Next terminal tab" })
|
||||
vim.keymap.set("t", "<A-[>", function() switch_term((popup_term.current - 2) % #popup_term.bufs + 1) end, { desc = "Prev terminal tab" })
|
||||
vim.keymap.set("t", "<C-n>", new_term_tab, { desc = "New terminal tab" })
|
||||
vim.keymap.set("t", "<C-w>", close_term_tab, { desc = "Close terminal tab" })
|
||||
|
||||
-- Terminal copy/paste
|
||||
vim.keymap.set("t", "<C-v>", 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", "<C-y>", [[<C-\><C-n>V]], { desc = "Select current line (normal mode)" })
|
||||
vim.keymap.set("t", "<Esc>", [[<C-\><C-n>]], { desc = "Exit to normal mode" })
|
||||
|
||||
-- Save/restore layout with :mksession
|
||||
vim.opt.sessionoptions = "buffers,curdir,folds,winpos,winsize,terminal"
|
||||
vim.keymap.set("n", "<leader>ss", ":mksession! ~/.config/nvim/session.vim<CR>", { desc = "Save session/layout" })
|
||||
vim.keymap.set("n", "<leader>sl", ":source ~/.config/nvim/session.vim<CR>", { 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,
|
||||
})
|
||||
98
lua/core/options.lua
Normal file
98
lua/core/options.lua
Normal file
@@ -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"
|
||||
9
lua/core/plugins.lua
Normal file
9
lua/core/plugins.lua
Normal file
@@ -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",
|
||||
})
|
||||
Reference in New Issue
Block a user