aboutsummaryrefslogtreecommitdiff
path: root/lua/user
diff options
context:
space:
mode:
authorsrdusr <trevorgray@srdusr.com>2025-09-24 00:14:04 +0200
committersrdusr <trevorgray@srdusr.com>2025-09-24 00:14:04 +0200
commit966d12ac730c83da90d60ab24eae539b2ea69441 (patch)
tree702f5f832796b572d0faee31c0eb15507e91f49a /lua/user
parent2a8020a2e9b7ef2ee77ddee14892127a4eb95187 (diff)
downloaddotfiles-966d12ac730c83da90d60ab24eae539b2ea69441.tar.gz
dotfiles-966d12ac730c83da90d60ab24eae539b2ea69441.zip
Update/Overhaul
Diffstat (limited to 'lua/user')
-rwxr-xr-x[-rw-r--r--]lua/user/keys.lua752
-rwxr-xr-x[-rw-r--r--]lua/user/mods.lua634
-rwxr-xr-x[-rw-r--r--]lua/user/opts.lua341
-rw-r--r--lua/user/pack.lua403
-rwxr-xr-x[-rw-r--r--]lua/user/view.lua245
5 files changed, 1494 insertions, 881 deletions
diff --git a/lua/user/keys.lua b/lua/user/keys.lua
index 87d852b..63b64fa 100644..100755
--- a/lua/user/keys.lua
+++ b/lua/user/keys.lua
@@ -1,19 +1,134 @@
-local keymap = vim.keymap
+-- ============================================================================
+-- Key Mappings
+-- ============================================================================
+
local map = function(mode, l, r, opts)
- opts = opts or {}
- opts.silent = true
- opts.noremap = true
- keymap.set(mode, l, r, opts)
+ if r == nil then
+ vim.notify("Attempted to map key '" .. l .. "' but RHS is nil", vim.log.levels.WARN)
+ return
+ end
+ opts = vim.tbl_extend('force', {
+ silent = true,
+ noremap = true
+ }, opts or {})
+ vim.keymap.set(mode, l, r, opts)
end
-local term_opts = { noremap = true, silent = false }
-local mods = require("user.mods")
-local bufnr = vim.api.nvim_get_current_buf()
--- Semi-colon as leader key
+-- Leader key
vim.g.mapleader = ";"
+vim.g.maplocalleader = "\\"
+
+-- Tmux/Vim navigation
+local function smart_move(direction, tmux_cmd)
+ local curwin = vim.api.nvim_get_current_win()
+ vim.cmd('wincmd ' .. direction)
+ if curwin == vim.api.nvim_get_current_win() then
+ vim.fn.system('tmux select-pane ' .. tmux_cmd)
+ end
+end
+
+-- Window Navigation
+map('n', '<C-h>', function() smart_move('h', '-L') end)
+map('n', '<C-j>', function() smart_move('j', '-D') end)
+map('n', '<C-k>', function() smart_move('k', '-U') end)
+map('n', '<C-l>', function() smart_move('l', '-R') end)
+
+-- Buffer Navigation
+map('n', '<leader>bn', '<cmd>bnext<CR>')
+map('n', '<leader>bp', '<cmd>bprevious<CR>')
+--map('n', '<leader>bd', '<cmd>bdelete<CR>')
+map('n', '<leader>ba', '<cmd>%bdelete<CR>')
+
+
+
+-- Get list of loaded buffers in order
+local function get_buffers()
+ local bufs = {}
+ for _, buf in ipairs(vim.api.nvim_list_bufs()) do
+ if vim.api.nvim_buf_is_loaded(buf) then
+ table.insert(bufs, buf)
+ end
+ end
+ return bufs
+end
+
+-- Swap two buffers by index in the buffer list
+local function swap_buffers(idx1, idx2)
+ local bufs = get_buffers()
+ local buf1 = bufs[idx1]
+ local buf2 = bufs[idx2]
+ if not buf1 or not buf2 then return end
+ local name1 = vim.api.nvim_buf_get_name(buf1)
+ local name2 = vim.api.nvim_buf_get_name(buf2)
+ vim.cmd("b " .. buf1)
+ vim.cmd("file " .. name2)
+ vim.cmd("b " .. buf2)
+ vim.cmd("file " .. name1)
+end
+
+-- Move current buffer left
+vim.keymap.set("n", "<leader>bh", function()
+ local bufs = get_buffers()
+ local curr = vim.api.nvim_get_current_buf()
+ local idx
+ for i, b in ipairs(bufs) do if b == curr then idx = i break end end
+ if idx and idx > 1 then
+ swap_buffers(idx, idx-1)
+ end
+end, { noremap = true, silent = true })
+
+-- Move current buffer right
+vim.keymap.set("n", "<leader>bl", function()
+ local bufs = get_buffers()
+ local curr = vim.api.nvim_get_current_buf()
+ local idx
+ for i, b in ipairs(bufs) do if b == curr then idx = i break end end
+ if idx and idx < #bufs then
+ swap_buffers(idx, idx+1)
+ end
+end, { noremap = true, silent = true })
+-- Save and Quit
+map('n', '<leader>w', '<cmd>w<CR>')
+map('n', '<leader>q', '<cmd>q<CR>')
+map('n', '<leader>wq', '<cmd>wq<CR>')
+map('n', '<leader>Q', '<cmd>qa!<CR>')
+
+-- Resize Windows
+map('n', '<M-Up>', '<cmd>resize -2<CR>')
+map('n', '<M-Down>', '<cmd>resize +2<CR>')
+map('n', '<M-Left>', '<cmd>vertical resize -2<CR>')
+map('n', '<M-Right>', '<cmd>vertical resize +2<CR>')
+
+-- Quickfix and Location List
+map('n', ']q', '<cmd>cnext<CR>zz')
+map('n', '[q', '<cmd>cprev<CR>zz')
+map('n', ']l', '<cmd>lnext<CR>zz')
+map('n', '[l', '<cmd>lprev<CR>zz')
+
+-- Terminal Mode
+map('t', '<Esc>', '<C-\\><C-n>')
+map('t', '<C-h>', '<C-\\><C-n><C-w>h')
+map('t', '<C-j>', '<C-\\><C-n><C-w>j')
+map('t', '<C-k>', '<C-\\><C-n><C-w>k')
+map('t', '<C-l>', '<C-\\><C-n><C-w>l')
+
+-- Insert mode escape
+map('i', 'jk', '<ESC>')
+
+-- Tmux/(n)vim navigation
+local function smart_move(direction, tmux_cmd)
+ local curwin = vim.api.nvim_get_current_win()
+ vim.cmd('wincmd ' .. direction)
+ if curwin == vim.api.nvim_get_current_win() then
+ vim.fn.system('tmux select-pane ' .. tmux_cmd)
+ end
+end
+
+map('n', '<C-h>', function() smart_move('h', '-L') end, {silent = true})
+map('n', '<C-j>', function() smart_move('j', '-D') end, {silent = true})
+map('n', '<C-k>', function() smart_move('k', '-U') end, {silent = true})
+map('n', '<C-l>', function() smart_move('l', '-R') end, {silent = true})
--- "jk" and "kj" to exit insert-mode
-map("i", "jk", "<esc>")
-- Jump to next match on line using `.` instead of `;` NOTE: commented out in favour of "ggandor/flit.nvim"
--map("n", ".", ";")
@@ -23,29 +138,84 @@ map("i", "jk", "<esc>")
-- Reload nvim config
map("n", "<leader><CR>",
- "<cmd>luafile ~/.config/nvim/init.lua<CR> | :echom ('Nvim config loading...') | :sl! | echo ('')<CR>")
+"<cmd>luafile ~/.config/nvim/init.lua<CR> | :echom ('Nvim config loading...') | :sl! | echo ('')<CR>")
+
+vim.keymap.set("t", "<Esc>", "<C-\\><C-n>", { desc = "Exit terminal mode" })
+vim.keymap.set("t", "<C-b>", "<C-\\><C-n>", { desc = "Exit terminal mode" })
--------------- Extended Operations ---------------
-- Conditional 'q' to quit on floating/quickfix/help windows otherwise still use it for macros
-- TODO: Have a list of if available on system/packages, example "Zen Mode" to not work on it (quit Zen Mode)
map("n", "q", function()
- local config = vim.api.nvim_win_get_config(0)
- if config.relative ~= "" then -- is_floating_window?
- return ":silent! close!<CR>"
- elseif vim.o.buftype == "quickfix" then
- return ":quit<CR>"
- elseif vim.o.buftype == "help" then
- return ":close<CR>"
- else
- return "q"
- end
+ local config = vim.api.nvim_win_get_config(0)
+ if config.relative ~= "" then -- is_floating_window?
+ return ":silent! close!<CR>"
+ elseif vim.o.buftype == "quickfix" then
+ return ":quit<CR>"
+ elseif vim.o.buftype == "help" then
+ return ":close<CR>"
+ else
+ return "q"
+ end
end, { expr = true, replace_keycodes = true })
+-- Minimalist Tab Completion
+map("i", "<Tab>", function()
+ local col = vim.fn.col('.') - 1
+ local line = vim.fn.getline('.')
+ local prev_char = line:sub(col, col)
+ if vim.fn.pumvisible() == 1 or prev_char:match("%w") then
+ return vim.api.nvim_replace_termcodes("<C-n>", true, true, true)
+ else
+ return vim.api.nvim_replace_termcodes("<Tab>", true, true, true)
+ end
+end, { expr = true })
+
+-- Shift-Tab for reverse completion
+map("i", "<S-Tab>", function()
+ if vim.fn.pumvisible() == 1 then
+ return vim.api.nvim_replace_termcodes("<C-p>", true, true, true)
+ else
+ return vim.api.nvim_replace_termcodes("<S-Tab>", true, true, true)
+ end
+end, { expr = true })
+
+
+-- Toggle completion
+map("n", "<Leader>tc", ':lua require("user.mods").toggle_completion()<CR>')
+
+-- Minimalist Auto Completion
+map("i", "<CR>", function()
+ -- Exit this keymap if nvim-cmp is present
+ local cmp_is_present, _ = pcall(require, "cmp")
+ if cmp_is_present and require("cmp").visible() then
+ return vim.api.nvim_replace_termcodes("<C-y>", true, true, true)
+ elseif cmp_is_present then
+ return vim.api.nvim_replace_termcodes("<CR>", true, true, true)
+ end
+
+ -- when cmp is NOT present
+ if vim.fn.pumvisible() == 1 then
+ return vim.api.nvim_replace_termcodes("<C-y>", true, true, true)
+ else
+ return vim.api.nvim_replace_termcodes("<CR>", true, true, true)
+ end
+end, { expr = true })
+
+-- Closing compaction in insert mode
+map("i", "[", "[]<Left>")
+map("i", "(", "()<Left>")
+map("i", "{", "{}<Left>")
+map("i", "/*", "/**/<Left><Left>")
+
-- Edit new file
-map("n", "<leader>;", [[:e <C-R>=expand("%:h")..'/'<CR>]], { noremap = true, silent = true, desc = "New file" })
+map("n", "<leader>e", [[:e <C-R>=expand("%:h")..'/'<CR>]], { noremap = true, silent = true, desc = "New file" })
-- Write as sudo
-map("c", "W", "exe 'w !sudo tee >/dev/null %:p:S' | setl nomod", { silent = true, desc = "Write as Sudo" })
+map("c", "W!", "exe 'w !sudo tee >/dev/null %:p:S' | setl nomod", { silent = true, desc = "Write as Sudo" })
+
+-- Don't format on save
+map("c", "F!", ":noautocmd w<CR>")
-- Combine buffers list with buffer name
map("n", "<Leader>b", ":buffers<CR>:buffer<Space>")
@@ -60,20 +230,25 @@ map("n", "<leader>d", ":bd<cr>")
map("n", "<TAB>", ":bnext<CR>")
map("n", "<S-TAB>", ":bprevious<CR>")
+-- Close all buffers and reopen last one
+map("n", "<leader>D", ":update | %bdelete | edit # | normal `<CR>")
+
-- Delete file of current buffer
map("n", "<leader>rm", "<CMD>call delete(expand('%')) | bdelete!<CR>")
-- List marks
-map("n", "<Leader>m", ":marks<CR>")
+map("n", "<Leader>M", ":marks<CR>")
-- Messages
-map("n", "<Leader>M", ":messages<CR>")
+map("n", "<Leader>m", ":messages<CR>")
--- Clear messages or just refresh/redraw the screen
-map("n", "<leader>i", "<cmd>lua require('notify').dismiss()<CR>")
-
--- Unsets the 'last search pattern' register by hitting return
---map("n", "<CR>", "!silent :noh<CR><CR>")
+map("n", "<leader>i", function()
+ local ok, notify = pcall(require, "notify")
+ if ok then
+ notify.dismiss()
+ end
+end)
-- Toggle set number
map("n", "<leader>$", ":NumbersToggle<CR>")
@@ -89,20 +264,36 @@ map("t", "<C-l>", "<C-\\><C-N><C-l>")
-- Split window
map("n", "<leader>-", ":split<CR>")
map("n", "<leader>\\", ":vsplit<CR>")
-map("n", "<leader>c", "<C-w>c")
+
+-- Close window
+--map("n", "<leader>c", "<C-w>c")
+map({ "n", "t", "c" }, "<leader>c", function()
+ local winid = vim.api.nvim_get_current_win()
+ local config = vim.api.nvim_win_get_config(winid)
+
+ if config.relative ~= "" then
+ -- This is a floating window
+ vim.cmd("CloseFloatingWindows")
+ else
+ -- Not a float/close window
+ vim.cmd("close")
+ end
+end, { desc = "Close current float or all floating windows" })
-- Resize Panes
---map('n', '<Leader>+', ':resize +5<CR>')
---map('n', '<Leader>-', ':resize -5<CR>')
map("n", "<Leader><", ":vertical resize +5<CR>")
map("n", "<Leader>>", ":vertical resize -5<CR>")
map("n", "<Leader>=", "<C-w>=")
+-- Mapping for left and right arrow keys in command-line mode
+vim.api.nvim_set_keymap("c", "<A-h>", "<Left>", { noremap = true, silent = false }) -- Left Arrow
+vim.api.nvim_set_keymap("c", "<A-l>", "<Right>", { noremap = true, silent = false }) -- Right Arrow
+
-- Map Alt+(h/j/k/l) in insert(include terminal/command) mode to move directional
-map({ "i", "t", "c" }, "<A-h>", "<left>")
-map({ "i", "t", "c" }, "<A-j>", "<down>")
-map({ "i", "t", "c" }, "<A-k>", "<up>")
-map({ "i", "t", "c" }, "<A-l>", "<right>")
+map({ "i", "t" }, "<A-h>", "<Left>")
+map({ "i", "t" }, "<A-j>", "<Down>")
+map({ "i", "t" }, "<A-k>", "<Up>")
+map({ "i", "t" }, "<A-l>", "<Right>")
-- Create tab, edit and move between them
map("n", "<C-T>n", ":tabnew<CR>")
@@ -110,10 +301,6 @@ map("n", "<C-T>e", ":tabedit")
map("n", "<leader>[", ":tabprev<CR>")
map("n", "<leader>]", ":tabnext<CR>")
--- "Zoom" a split window into a tab and/or close it
---map("n", "<Leader>,", ":tabnew %<CR>")
---map("n", "<Leader>.", ":tabclose<CR>")
-
-- Vim TABs
map("n", "<leader>1", "1gt<CR>")
map("n", "<leader>2", "2gt<CR>")
@@ -134,10 +321,26 @@ map("n", "<leader>0", "10gt<CR>")
--map("n", ">", ">>", term_opts)
--map("x", "<", "<gv", term_opts)
--map("x", ">", ">gv", term_opts)
-map("v", "<", "<gv")
-map("v", ">", ">gv")
-map("n", "<", "<S-v><<esc>")
-map("n", ">", "<S-v>><esc>")
+--map("v", "<", "<gv")
+--map("v", ">", ">gv")
+--map("n", "<", "<S-v><<esc>change mode to normal")
+--map("n", ">", "<S-v>><esc>change mode to normal")
+
+-- Visual mode: Indent and reselect the visual area, like default behavior but explicit
+map("v", "<", "<gv", { desc = "Indent left and reselect" })
+map("v", ">", ">gv", { desc = "Indent right and reselect" })
+
+-- Normal mode: Indent current line and enter Visual Line mode to repeat easily
+map("n", "<", "v<<", { desc = "Indent left and select" })
+map("n", ">", "v>>", { desc = "Indent right and select" })
+
+---- Visual mode: Indent and reselect the visual area, like default behavior but explicit
+--map("v", "<", "<", { desc = "Indent left" })
+--map("v", ">", ">", { desc = "Indent right" })
+--
+---- Normal mode: Indent current line and enter Visual Line mode to repeat easily
+--map("n", "<", "v<<", { desc = "Indent left and select" })
+--map("n", ">", "v>>", { desc = "Indent right and select" })
-- Set alt+(j/k) to switch lines of texts or simply move them
map("n", "<A-k>", ':let save_a=@a<Cr><Up>"add"ap<Up>:let @a=save_a<Cr>')
@@ -163,33 +366,31 @@ map("n", "<leader><C-l>", "<Cmd>!clear<CR>")
-- Change file to an executable
map("n", "<Leader>x",
- ":lua require('user.mods').Toggle_executable()<CR> | :echom ('Toggle executable')<CR> | :sl! | echo ('')<CR>")
+":lua require('user.mods').Toggle_executable()<CR> | :echom ('Toggle executable')<CR> | :sl! | echo ('')<CR>")
-- map("n", "<leader>x", ":!chmod +x %<CR>")
+vim.keymap.set("n", "<leader>cm", function()
+ vim.cmd("redir @+")
+ vim.cmd("silent messages")
+ vim.cmd("redir END")
+ vim.notify("Copied :messages to clipboard")
+end, { desc = "Copy :messages to clipboard" })
+
-- Paste without replace clipboard
map("v", "p", '"_dP')
--- Swap two pieces of text, use x to cut in visual mode, then use Ctrl-x in
--- visual mode to select text to swap with
---map("v", "<C-X>", "<Esc>`.``gvP``P")
+map("n", "]p", 'm`o<Esc>"+p``', opts)
+
+map("n", "[p", 'm`O<Esc>"+p``', opts)
+
+-- Bind Ctrl-V to paste in insert/normal/command mode
+map("i", "<C-v>", "<C-G>u<C-R><C-P>+", opts)
+map("n", "<C-v>", '"+p', { noremap = true, silent = true })
+vim.api.nvim_set_keymap("c", "<C-v>", "<C-R>=getreg('+')<CR><BS>", { noremap = true, silent = false })
-- Change Working Directory to current project
map("n", "<leader>cd", ":cd %:p:h<CR>:pwd<CR>")
--- Open the current file in the default program (on Mac this should just be just `open`)
-map("n", "<leader>o", ":!xdg-open %<cr><cr>")
-
--- URL handling
-if vim.fn.has("mac") == 1 then
- map("", "gx", '<Cmd>call jobstart(["open", expand("<cfile>")], {"detach": v:true})<CR>', {})
-elseif vim.fn.has("unix") == 1 then
- map("", "gx", '<Cmd>call jobstart(["xdg-open", expand("<cfile>")], {"detach": v:true})<CR>', {})
-elseif vim.fn.has("wsl") == 1 then
- map("", "gx", '<Cmd>call jobstart(["wslview", expand("<cfile>")], {"detach": v:true})<CR>', {})
-else
- map[""].gx = { '<Cmd>lua print("Error: gx is not supported on this OS!")<CR>' }
-end
-
-- Search and replace
map("v", "<leader>sr", 'y:%s/<C-r><C-r>"//g<Left><Left>c')
@@ -197,13 +398,6 @@ map("v", "<leader>sr", 'y:%s/<C-r><C-r>"//g<Left><Left>c')
map("n", "<leader>s", ":%s//g<Left><Left>")
map("v", "<leader>s", ":s//g<Left><Left>")
--- Toggle completion
-map("n", "<Leader>tc", ':lua require("user.mods").toggle_completion()<CR>')
-
--- Disable default completion.
-map("i", "<C-n>", "<Nop>")
-map("i", "<C-p>", "<Nop>")
-
-- Set line wrap
map("n", "<M-z>", function()
local wrap_status = vim.api.nvim_exec("set wrap ?", true)
@@ -223,12 +417,14 @@ map("n", "<Space>", "&foldlevel ? 'zM' : 'zR'", { expr = true })
-- Use space to toggle fold
--map("n", "<Space>", "za")
--- Make a copy of current file
---vim.cmd([[
--- map <leader>s :up \| saveas! %:p:r-<C-R>=strftime("%y.%m.%d-%H:%M")<CR>-bak.<C-R>=expand("%:e")<CR> \| 3sleep \| e #<CR>
---]])
map("n", "<leader>.b", ":!cp % %.backup<CR>")
+-- Go to next window
+map("n", "<leader>wn", "<C-w>w", { desc = "Next window" })
+
+-- Go to previous window
+map("n", "<leader>wp", "<C-w>W", { desc = "Previous window" })
+
-- Toggle transparency
map("n", "<leader>tb", ":call utils#Toggle_transparent_background()<CR>")
@@ -240,7 +436,136 @@ map("n", "<C-w>z", "<C-w>|<C-w>_")
map("n", "<leader>sl", ":call utils#ToggleHiddenAll()<CR>")
-- Open last closed buffer
-map("n", "<C-t>", ":call OpenLastClosed()<CR>")
+map("n", "<C-t>", ":call utils#OpenLastClosed()<CR>")
+
+
+-- Automatically set LSP keymaps when LSP attaches to a buffer
+--vim.api.nvim_create_autocmd("LspAttach", {
+-- callback = function(args)
+-- local bufnr = args.buf
+-- local opts = { buffer = bufnr }
+-- map("n", "K", vim.lsp.buf.hover)
+-- map("n", "gd", "<cmd>lua require('goto-preview').goto_preview_definition()<CR>")
+-- map("n", "gi", "<cmd>lua require('goto-preview').goto_preview_implementation()<CR>")
+-- map("n", "gr", "<cmd>lua require('goto-preview').goto_preview_references()<CR>")
+-- map("n", "gD", vim.lsp.buf.declaration)
+-- map("n", "<leader>k", vim.lsp.buf.signature_help)
+-- map("n", "gt", "<cmd>lua require('goto-preview').goto_preview_type_definition()<CR>")
+-- map("n", "gn", vim.lsp.buf.rename)
+-- map("n", "ga", vim.lsp.buf.code_action)
+-- map("n", "gf", function() vim.lsp.buf.format({ async = true }) end)
+-- map("n", "go", vim.diagnostic.open_float)
+-- map("n", "<leader>go", ":call utils#ToggleDiagnosticsOpenFloat()<CR> | :echom ('Toggle Diagnostics Float open/close...')<CR> | :sl! | echo ('')<CR>")
+-- map("n", "gq", vim.diagnostic.setloclist)
+-- map("n", "[d", vim.diagnostic.goto_prev)
+-- map("n", "]d", vim.diagnostic.goto_next)
+-- map("n", "gs", vim.lsp.buf.document_symbol)
+-- map("n", "gw", vim.lsp.buf.workspace_symbol)
+-- map("n", "<leader>wa", vim.lsp.buf.add_workspace_folder)
+-- map("n", "<leader>wr", vim.lsp.buf.remove_workspace_folder)
+-- map("n", "<leader>wl", function()
+-- print(vim.inspect(vim.lsp.buf.list_workspace_folders()))
+-- end)
+-- end,
+--})
+
+---- LSP Global Keymaps (available in all buffers)
+--map("n", "[d", vim.diagnostic.goto_prev, { desc = "LSP: Previous Diagnostic" })
+--map("n", "]d", vim.diagnostic.goto_next, { desc = "LSP: Next Diagnostic" })
+--map("n", "go", vim.diagnostic.open_float, { desc = "LSP: Open Diagnostic Float" })
+--
+---- LSP Buffer-local keymaps function (to be called from LSP on_attach)
+--_G.setup_lsp_keymaps = function(bufnr)
+-- local bmap = function(mode, l, r, opts)
+-- opts = opts or {}
+-- opts.silent = true
+-- opts.noremap = true
+-- opts.buffer = bufnr
+-- vim.keymap.set(mode, l, r, opts)
+-- end
+--
+-- bmap("n", "K", vim.lsp.buf.hover, { desc = "LSP: Hover Documentation" })
+-- bmap("n", "gd", vim.lsp.buf.definition, { desc = "LSP: Go to Definition" })
+-- bmap("n", "gD", vim.lsp.buf.declaration, { desc = "LSP: Go to Declaration" })
+-- bmap("n", "gi", vim.lsp.buf.implementation, { desc = "LSP: Go to Implementation" })
+-- bmap("n", "gt", vim.lsp.buf.type_definition, { desc = "LSP: Go to Type Definition" })
+-- bmap("n", "gr", vim.lsp.buf.references, { desc = "LSP: Go to References" })
+-- bmap("n", "gn", vim.lsp.buf.rename, { desc = "LSP: Rename" })
+-- bmap("n", "ga", vim.lsp.buf.code_action, { desc = "LSP: Code Action" })
+-- bmap("n", "<leader>k", vim.lsp.buf.signature_help, { desc = "LSP: Signature Help" })
+-- bmap("n", "gs", vim.lsp.buf.document_symbol, { desc = "LSP: Document Symbols" })
+--end
+
+-- LSP Global Keymaps (available in all buffers)
+map("n", "[d", vim.diagnostic.goto_prev, { desc = "LSP: Previous Diagnostic" })
+map("n", "]d", vim.diagnostic.goto_next, { desc = "LSP: Next Diagnostic" })
+map("n", "go", vim.diagnostic.open_float, { desc = "LSP: Open Diagnostic Float" })
+map("n", "<leader>go", ":call utils#ToggleDiagnosticsOpenFloat()<CR> | :echom ('Toggle Diagnostics Float open/close...')<CR> | :sl! | echo ('')<CR>")
+
+-- LSP Buffer-local keymaps function (to be called from LSP on_attach)
+_G.setup_lsp_keymaps = function(bufnr)
+ local bmap = function(mode, l, r, opts)
+ opts = opts or {}
+ opts.silent = true
+ opts.noremap = true
+ opts.buffer = bufnr
+ vim.keymap.set(mode, l, r, opts)
+ end
+
+ -- Your preferred keybindings
+ bmap("n", "K", function()
+ vim.lsp.buf.hover { border = "single", max_height = 25, max_width = 120 }
+ end, { desc = "LSP: Hover Documentation" })
+
+ bmap("n", "gd", function()
+ vim.lsp.buf.definition {
+ on_list = function(options)
+ -- Custom logic to avoid showing multiple definitions for Lua patterns like:
+ -- `local M.my_fn_name = function() ... end`
+ local unique_defs = {}
+ local def_loc_hash = {}
+
+ for _, def_location in pairs(options.items) do
+ local hash_key = def_location.filename .. def_location.lnum
+ if not def_loc_hash[hash_key] then
+ def_loc_hash[hash_key] = true
+ table.insert(unique_defs, def_location)
+ end
+ end
+
+ options.items = unique_defs
+ vim.fn.setloclist(0, {}, " ", options)
+
+ -- Open location list if multiple definitions, otherwise jump directly
+ if #options.items > 1 then
+ vim.cmd.lopen()
+ else
+ vim.cmd([[silent! lfirst]])
+ end
+ end,
+ }
+ end, { desc = "LSP: Go to Definition" })
+
+ bmap("n", "<C-]>", vim.lsp.buf.definition, { desc = "LSP: Go to Definition (Alt)" })
+ bmap("n", "gD", vim.lsp.buf.declaration, { desc = "LSP: Go to Declaration" })
+ bmap("n", "gi", vim.lsp.buf.implementation, { desc = "LSP: Go to Implementation" })
+ bmap("n", "gt", vim.lsp.buf.type_definition, { desc = "LSP: Go to Type Definition" })
+ bmap("n", "gr", vim.lsp.buf.references, { desc = "LSP: Go to References" })
+ bmap("n", "gn", vim.lsp.buf.rename, { desc = "LSP: Rename" })
+ bmap("n", "<leader>rn", vim.lsp.buf.rename, { desc = "LSP: Rename (Alt)" })
+ bmap("n", "ga", vim.lsp.buf.code_action, { desc = "LSP: Code Action" })
+ bmap("n", "<leader>ca", vim.lsp.buf.code_action, { desc = "LSP: Code Action (Alt)" })
+ bmap("n", "<leader>k", vim.lsp.buf.signature_help, { desc = "LSP: Signature Help" })
+ bmap("n", "<C-k>", vim.lsp.buf.signature_help, { desc = "LSP: Signature Help (Alt)" })
+ bmap("n", "gs", vim.lsp.buf.document_symbol, { desc = "LSP: Document Symbols" })
+
+ -- Workspace folder management
+ bmap("n", "<leader>wa", vim.lsp.buf.add_workspace_folder, { desc = "LSP: Add Workspace Folder" })
+ bmap("n", "<leader>wr", vim.lsp.buf.remove_workspace_folder, { desc = "LSP: Remove Workspace Folder" })
+ bmap("n", "<leader>wl", function()
+ vim.print(vim.lsp.buf.list_workspace_folders())
+ end, { desc = "LSP: List Workspace Folders" })
+end
---------------- Plugin Operations ----------------
-- Packer
@@ -250,12 +575,6 @@ map("n", "<leader>Ps", "<cmd>PackerSync<cr>")
map("n", "<leader>PS", "<cmd>PackerStatus<cr>")
map("n", "<leader>Pu", "<cmd>PackerUpdate<cr>")
--- Tmux navigation (aserowy/tmux.nvim)
-map("n", "<C-h>", "<CMD>NavigatorLeft<CR>")
-map("n", "<C-l>", "<CMD>NavigatorRight<CR>")
-map("n", "<C-k>", "<CMD>NavigatorUp<CR>")
-map("n", "<C-j>", "<CMD>NavigatorDown<CR>")
-
-- ToggleTerm
map({ "n", "t" }, "<leader>tt", "<cmd>ToggleTerm<CR>")
map({ "n", "t" }, "<leader>th", "<cmd>lua Horizontal_term_toggle()<CR>")
@@ -270,9 +589,9 @@ map("n", "<leader>tg", "<cmd>lua Gh_dash()<CR>")
map("n", "<leader>gs", vim.cmd.Git)
map("n", "<leader>ga", ":Git add %:p<CR><CR>")
--map("n", "<leader>gs", ":Gstatus<CR>")
-map("n", "<leader>gc", ":Gcommit -v -q<CR>")
+--map("n", "<leader>gc", ":Gcommit -v -q<CR>")
map("n", "<leader>gt", ":Gcommit -v -q %:p<CR>")
---map("n", "<leader>gd", ":Gdiff<CR>")
+map("n", "<leader>gd", ":Gdiff<CR>")
map("n", "<leader>ge", ":Gedit<CR>")
--map("n", "<leader>gr", ":Gread<Cj>")
map("n", "<leader>gw", ":Gwrite<CR><CR>")
@@ -287,42 +606,128 @@ map("n", "<leader>gm", ":Gmove<Space>")
--map("n", "<leader>gpl", ":Dispatch! git pull<CR>")
-- Telescope
-map("n", "<leader>ff", ":cd %:p:h<CR>:pwd<CR><cmd>lua require('telescope.builtin').find_files()<cr>") -- find files with hidden option
+-- Safe load of your custom Telescope module
+-- This initial pcall for "plugins.telescope" is fine because it just checks if YOUR module is there.
+-- The actual checks for Telescope's core modules happen *inside* your wrapper functions when called.
+local telescope_ok, telescope_module = pcall(require, "plugins.telescope")
+
+if telescope_ok and telescope_module then
+
+ -- Direct function calls from your plugins.telescope module
+ -- M.safe_find_files handles its own internal `builtin` check
+ map("n", "<leader>ff", telescope_module.safe_find_files, { desc = "Find files" })
+
+ -- For `find all files`, use your `safe_telescope_builtin` wrapper
+ -- You need to wrap it in a function to pass the options correctly.
+ map("n", "<leader>f.", function()
+ telescope_module.safe_telescope_builtin("find_files")({ hidden = true, no_ignore = true })
+ end, { desc = "Find all files" })
+
+
+ ---
+ --- Built-in Telescope functions
+ --- Note: safe_telescope_builtin returns a function, so you map directly to it.
+ ---
+ map("n", "<leader>fg", function() telescope_module.safe_telescope_builtin("live_grep")() end, { desc = "Live grep" })
+ map("n", "<leader>fb", function() telescope_module.safe_telescope_builtin("buffers")() end, { desc = "Find buffers" })
+ map("n", "<leader>fh", function() telescope_module.safe_telescope_builtin("help_tags")() end, { desc = "Help tags" })
+ map("n", "<leader>fc", function() telescope_module.safe_telescope_builtin("commands")() end, { desc = "Commands" })
+ map("n", "<leader>fd", function() telescope_module.safe_telescope_builtin("diagnostics")() end, { desc = "Diagnostics" })
+ map("n", "<leader>fk", function() telescope_module.safe_telescope_builtin("keymaps")() end, { desc = "Keymaps" })
+ map("n", "<leader>fr", function() telescope_module.safe_telescope_builtin("registers")() end, { desc = "Registers" })
+ map("n", "<leader>ffc", function() telescope_module.safe_telescope_builtin("current_buffer_fuzzy_find")() end, { desc = "Current buffer fuzzy find" })
+ -- Corrected the previous `fp` mapping that pointed to `pickers`
+ map("n", "<leader>fp", function() telescope_module.safe_telescope_builtin("oldfiles")() end, { desc = "Recently opened files" })
+
+
+ ---
+ --- Telescope Extension functions
+ --- Note: safe_telescope_extension returns a function, so you map directly to it.
+ ---
+ map("n", "<leader>cf", function() telescope_module.safe_telescope_extension("changed_files", "changed_files")() end, { desc = "Changed files" })
+ map("n", "<leader>fm", function() telescope_module.safe_telescope_extension("media_files", "media_files")() end, { desc = "Media files" })
+ map("n", "<leader>fi", function() telescope_module.safe_telescope_extension("notify", "notify")() end, { desc = "Notifications" })
+ map("n", "<Leader>fs", function() telescope_module.safe_telescope_extension("session-lens", "search_session")() end, { desc = "Search sessions" })
+ map("n", "<Leader>frf", function() telescope_module.safe_telescope_extension("recent_files", "pick")() end, { desc = "Recent files" })
+ map("n", "<Leader>f/", function() telescope_module.safe_telescope_extension("file_browser", "file_browser")() end, { desc = "File browser" })
+
+
+ ---
+ --- Custom functions defined in plugins.telescope.lua
+ --- Note: safe_telescope_call returns a function, so you map directly to it.
+ --- (These were already correct as safe_telescope_call returns a callable function)
+ ---
+ map("n", "<leader>ffd", telescope_module.safe_telescope_call("plugins.telescope", "find_dirs"), { desc = "Find directories" })
+ map("n", "<leader>ff.", telescope_module.safe_telescope_call("plugins.telescope", "find_configs"), { desc = "Find configs" })
+ map("n", "<leader>ffs", telescope_module.safe_telescope_call("plugins.telescope", "find_scripts"), { desc = "Find scripts" })
+ map("n", "<leader>ffw", telescope_module.safe_telescope_call("plugins.telescope", "find_projects"), { desc = "Find projects" })
+ map("n", "<leader>ffB", telescope_module.safe_telescope_call("plugins.telescope", "find_books"), { desc = "Find books" })
+ map("n", "<leader>ffn", telescope_module.safe_telescope_call("plugins.telescope", "find_notes"), { desc = "Find notes" })
+ map("n", "<leader>fgn", telescope_module.safe_telescope_call("plugins.telescope", "grep_notes"), { desc = "Grep notes" })
+ map("n", "<leader>fpp", telescope_module.safe_telescope_call("plugins.telescope", "find_private"), { desc = "Find private notes" })
+ map("n", "<leader>fgc", telescope_module.safe_telescope_call("plugins.telescope", "grep_current_dir"), { desc = "Grep current directory" })
+
+end
+---- Fallback keymaps when telescope is not available
+--map("n", "<leader>ff", function()
+-- local file = vim.fn.input("Open file: ", "", "file")
+-- if file ~= "" then
+-- vim.cmd("edit " .. file)
+-- end
+--end, { desc = "Find files (fallback)" })
+
+---- You can add other basic fallbacks here
+--map("n", "<leader>fg", function()
+-- vim.notify("Live grep requires telescope plugin", vim.log.levels.WARN)
+--end, { desc = "Live grep (unavailable)" })
+----end
+
+
map("n", "<leader>fF", ":cd %:p:h<CR>:pwd<CR><cmd>lua require('user.mods').findFilesInCwd()<CR>",
- { noremap = true, silent = true, desc = "Find files in cwd" })
-map("n", "<leader>f.", function()
- require("telescope.builtin").find_files({ hidden = true, no_ignore = true })
-end) -- find all files
-map("n", "<leader>fg", "<cmd>lua require('telescope.builtin').live_grep()<cr>")
-map("n", "<leader>fb", "<cmd>lua require('telescope.builtin').buffers()<cr>")
-map("n", "<leader>fh", "<cmd>lua require('telescope.builtin').help_tags()<cr>")
-map("n", "<leader>fc", "<cmd>lua require('telescope.builtin').commands()<cr>")
-map("n", "<leader>cf", "<cmd>Telescope changed_files<cr>")
-map("n", "<leader>fp", "<cmd>Telescope pickers<cr>")
-map("n", "<leader>fd", "<cmd>lua require('telescope.builtin').diagnostics()<cr>")
-map("n", "<leader>fk", "<cmd>lua require('telescope.builtin').keymaps()<cr>")
-map("n", "<leader>fr", "<cmd>lua require('telescope.builtin').registers({})<CR>") -- registers picker
-map("n", "<leader>fm", "<cmd>lua require('telescope').extensions.media_files.media_files({})<cr>") -- find media files
-map("n", "<leader>fi", "<cmd>lua require('telescope').extensions.notify.notify({})<cr>") -- find notifications
-map("n", "<Leader>fs", '<cmd>lua require("session-lens").search_session()<CR>')
-map("n", "<leader>ffd", [[<Cmd>lua require'plugins.telescope'.find_dirs()<CR>]]) -- find dies
-map("n", "<leader>ff.", [[<Cmd>lua require'plugins.telescope'.find_configs()<CR>]]) -- find configs
-map("n", "<leader>ffs", [[<Cmd>lua require'plugins.telescope'.find_scripts()<CR>]]) -- find scripts
-map("n", "<leader>ffw", [[<Cmd>lua require'plugins.telescope'.find_projects()<CR>]]) -- find projects
-map("n", "<leader>ffb", [[<Cmd>lua require'plugins.telescope'.find_books()<CR>]]) -- find books
-map("n", "<leader>ffn", [[<Cmd>lua require'plugins.telescope'.find_notes()<CR>]]) -- find notes
-map("n", "<leader>fgn", [[<Cmd>lua require'plugins.telescope'.grep_notes()<CR>]]) -- search notes
-map("n", "<Leader>frf", "<cmd>lua require('telescope').extensions.recent_files.pick()<CR>")
-map("n", "<leader>ffc", "<cmd>lua require('telescope.builtin').current_buffer_fuzzy_find()<cr>")
-map("n", "<Leader>f/", "<cmd>lua require('telescope').extensions.file_browser.file_browser()<CR>")
---map("n", "<leader>f/", "<cmd>lua require('plugins.telescope').curbuf()<cr>") -- find files with hidden option
--- Map a shortcut to open the picker.
+{ noremap = true, silent = true, desc = "Find files in cwd" })
-- FZF
-map("n", "<leader>fz", "<cmd>lua require('fzf-lua').files()<CR>")
+map("n", "<leader>fz", function()
+ local ok, fzf_lua = pcall(require, "fzf-lua")
+ if ok then
+ fzf_lua.files() -- no config, just open
+ else
+ local handle = io.popen("find . -type f | fzf")
+ if handle then
+ local result = handle:read("*a")
+ handle:close()
+ result = result:gsub("\n", "")
+ if result ~= "" then
+ vim.cmd("edit " .. vim.fn.fnameescape(result))
+ end
+ else
+ vim.notify("fzf not found or failed to run", vim.log.levels.ERROR)
+ end
+ end
+end, { desc = "FZF file picker (fzf-lua or fallback)" })
+
+map("n", "gA", ":FzfLua lsp_code_actions<CR>")
-- Nvim-tree
-map("n", "<leader>e", "<cmd>Rooter<CR>:NvimTreeToggle<CR>", {})
+local function safe_nvim_tree_toggle()
+ local ok_tree, tree_api = pcall(require, "nvim-tree.api")
+ if ok_tree then
+ pcall(vim.cmd, "Rooter") -- silently run Rooter if available
+ tree_api.tree.toggle()
+ else
+ -- Fallback to netrw
+ local cur_buf = vim.api.nvim_get_current_buf()
+ local ft = vim.api.nvim_get_option_value("filetype", { buf = cur_buf })
+
+ if ft == "netrw" then
+ vim.cmd("close")
+ else
+ vim.cmd("Lexplore")
+ end
+ end
+end
+
+map("n", "<leader>f", safe_nvim_tree_toggle, { desc = "Toggle file explorer" })
-- Undotree
map("n", "<leader>u", vim.cmd.UndotreeToggle)
@@ -338,29 +743,77 @@ map("n", "<leader>ww", "<cmd>lua require('user.mods').Toggle_autopairs()<CR>")
map("n", "<leader>zm", "<CMD>ZenMode<CR> | :echom ('Zen Mode')<CR> | :sl! | echo ('')<CR>")
-- Vim-rooter
-map("n", "<leader>ro", "<CMD>Rooter<CR> | :echom ('cd to root/project directory')<CR> | :sl! | echo ('')<CR>", term_opts)
+local function safe_project_root()
+ if vim.fn.exists(":Rooter") == 2 then
+ vim.cmd("Rooter")
+ else
+ vim.cmd("cd %:p:h")
+ end
+end
+vim.keymap.set("n", "<leader>ro", safe_project_root, { desc = "Project root" })
-- Trouble (UI to show diagnostics)
-map("n", "<leader>t", ":cd %:p:h<CR>:pwd<CR><CMD>TroubleToggle<CR>")
-map("n", "<leader>tw", ":cd %:p:h<CR>:pwd<CR><CMD>TroubleToggle workspace_diagnostics<CR>")
-map("n", "<leader>td", ":cd %:p:h<CR>:pwd<CR><CMD>TroubleToggle document_diagnostics<CR>")
-map("n", "<leader>tq", ":cd %:p:h<CR>:pwd<CR><CMD>TroubleToggle quickfix<CR>")
-map("n", "<leader>tl", ":cd %:p:h<CR>:pwd<CR><CMD>TroubleToggle loclist<CR>")
-map("n", "gR", "<CMD>TroubleToggle lsp_references<CR>")
+local function safe_trouble_toggle(view, opts)
+ local ok, _ = pcall(require, "trouble")
+ if ok then
+ local cmd = "Trouble"
+ if view then
+ cmd = cmd .. " " .. view .. " toggle"
+ if opts then
+ cmd = cmd .. " " .. opts
+ end
+ else
+ cmd = cmd .. " diagnostics toggle"
+ end
+ vim.cmd(cmd)
+ else
+ vim.cmd("copen")
+ end
+end
+
+-- Replace 'map' with 'vim.keymap.set' if not already a global alias
+vim.keymap.set("n", "<leader>t", function()
+ safe_trouble_toggle()
+end, { desc = "Diagnostics (Workspace)" })
+
+vim.keymap.set("n", "<leader>tw", function()
+ vim.cmd("cd %:p:h | pwd")
+ safe_trouble_toggle("diagnostics")
+end, { desc = "Diagnostics (Workspace)" })
+
+vim.keymap.set("n", "<leader>td", function()
+ vim.cmd("cd %:p:h | pwd")
+ safe_trouble_toggle("diagnostics", "filter.buf=0")
+end, { desc = "Diagnostics (Buffer)" })
+
+vim.keymap.set("n", "<leader>tq", function()
+ vim.cmd("cd %:p:h | pwd")
+ safe_trouble_toggle("qflist")
+end, { desc = "Quickfix List" })
+
+vim.keymap.set("n", "<leader>tl", function()
+ vim.cmd("cd %:p:h | pwd")
+ safe_trouble_toggle("loclist")
+end, { desc = "Location List" })
+
+vim.keymap.set("n", "gR", function()
+ safe_trouble_toggle("lsp")
+end, { desc = "LSP References/Definitions" })
-- Null-ls
-map("n", "<leader>ls", "<CMD>NullLsToggle<CR>")
+map("n", "<leader>ls", ':lua require("null-ls").toggle({})<CR>')
+
-- Replacer
map("n", "<Leader>qr", ':lua require("replacer").run()<CR>')
-- Quickfix
map("n", "<leader>q", function()
- if vim.fn.getqflist({ winid = 0 }).winid ~= 0 then
- require("plugins.quickfix").close()
- else
- require("plugins.quickfix").open()
- end
+ if vim.fn.getqflist({ winid = 0 }).winid ~= 0 then
+ require("plugins.quickfix").close()
+ else
+ require("plugins.quickfix").open()
+ end
end, { desc = "Toggle quickfix window" })
-- Move to the next and previous item in the quickfixlist
@@ -375,17 +828,17 @@ local dap_ok, dap = pcall(require, "dap")
local dap_ui_ok, ui = pcall(require, "dapui")
if not (dap_ok and dap_ui_ok) then
- require("notify")("nvim-dap or dap-ui not installed!", "warning")
- return
+ --require("notify")("nvim-dap or dap-ui not installed!", "warning")
+ return
end
vim.fn.sign_define("DapBreakpoint", { text = "🐞" })
-- Start debugging session
map("n", "<leader>ds", function()
- dap.continue()
- ui.toggle({})
- vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-w>=", false, true, true), "n", false) -- Spaces buffers evenly
+ dap.continue()
+ ui.toggle({})
+ vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes("<C-w>=", false, true, true), "n", false) -- Spaces buffers evenly
end)
-- Set breakpoints, get variable values, step into/out of functions, etc.
@@ -394,31 +847,34 @@ map("n", "<leader>dC", dap.continue)
-- map("n", "<leader>dt", dap.terminate)
map("n", "<leader>dt", ui.toggle)
map("n", "<leader>dd", function()
- dap.disconnect({ terminateDebuggee = true })
+ dap.disconnect({ terminateDebuggee = true })
end)
map("n", "<leader>dn", dap.step_over)
map("n", "<leader>di", dap.step_into)
map("n", "<leader>do", dap.step_out)
map("n", "<leader>db", dap.toggle_breakpoint)
map("n", "<leader>dB", function()
- dap.clear_breakpoints()
- require("notify")("Breakpoints cleared", "warn")
+ dap.clear_breakpoints()
+ require("notify")("Breakpoints cleared", "warn")
+end)
+map("n", "<leader>dl", function()
+ local ok, dap_widgets = pcall(require, "dap.ui.widgets")
+ if ok then dap_widgets.hover() end
end)
-map("n", "<leader>dl", require("dap.ui.widgets").hover)
map("n", "<leader>de", function()
- require("dapui").float_element()
+ require("dapui").float_element()
end, { desc = "Open Element" })
map("n", "<leader>dq", function()
- require("dapui").close()
- require("dap").repl.close()
- local session = require("dap").session()
- if session then
- require("dap").terminate()
- end
- require("nvim-dap-virtual-text").refresh()
+ require("dapui").close()
+ require("dap").repl.close()
+ local session = require("dap").session()
+ if session then
+ require("dap").terminate()
+ end
+ require("nvim-dap-virtual-text").refresh()
end, { desc = "Terminate Debug" })
map("n", "<leader>dc", function()
- require("telescope").extensions.dap.commands()
+ require("telescope").extensions.dap.commands()
end, { desc = "DAP-Telescope: Commands" })
--vim.keymap.set("n", "<leader>B", ":lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: '))<CR>")
--vim.keymap.set("v", "<leader>B", ":lua require'dap'.set_breakpoint(vim.fn.input('Breakpoint condition: '))<CR>")
@@ -459,10 +915,10 @@ map("n", "<leader>rr", '<CMD>lua require("user.mods").toggleCodeRunner()<CR>')
-- Run executable file
map("n", "<leader>rx",
- ":lua require('user.mods').RunCurrentFile()<CR>:echom 'Running executable file...'<CR>:sl!<CR>:echo ''<CR>")
+":lua require('user.mods').RunCurrentFile()<CR>:echom 'Running executable file...'<CR>:sl!<CR>:echo ''<CR>")
--- Close all floating windows
-map({ "n", "t", "c" }, "<leader>w", "<CMD>CloseFloatingWindows<CR>")
+-- Set Files to current location as dir
+map({ "n" }, "<leader>cf", "<CMD>e %:h<CR>")
-- Vimtex
map("n", "<Leader>lc", ":VimtexCompile<cr>")
diff --git a/lua/user/mods.lua b/lua/user/mods.lua
index c20c687..b4e1579 100644..100755
--- a/lua/user/mods.lua
+++ b/lua/user/mods.lua
@@ -1,15 +1,84 @@
+-- ============================================================================
+-- Modules/Utility functions
+-- ============================================================================
+
local M = {}
---- Shorten Function Names
+-- Shorten Function Names
local fn = vim.fn
+local api = vim.api
+
+--- Check if an executable exists
+---@param name string The name of the executable to check
+---@return boolean
function M.executable(name)
- if fn.executable(name) > 0 then
- return true
+ return fn.executable(name) > 0
+end
+
+--- Check if a feature is available in Neovim
+---@param feat string The feature to check (e.g., 'nvim-0.7')
+---@return boolean
+function M.has(feat)
+ return fn.has(feat) == 1
+end
+
+--- Setup command aliases
+---@param from string The alias
+---@param to string The command to alias to
+function M.setup_command_alias(from, to)
+ local cmd = string.format('cnoreabbrev <expr> %s (getcmdtype() == ":" && getcmdline() == "%s") ? "%s" : "%s"',
+ from, from, to, from)
+ api.nvim_command(cmd)
+end
+
+--- Preserve cursor position while formatting
+---@param cmd string The command to run
+function M.preserve_cursor(cmd)
+ local cursor = api.nvim_win_get_cursor(0)
+ vim.cmd(cmd)
+ api.nvim_win_set_cursor(0, cursor)
+end
+
+--- Toggle quickfix window
+function M.toggle_quickfix()
+ local qf_exists = false
+ for _, win in pairs(fn.getwininfo()) do
+ if win.quickfix == 1 then
+ qf_exists = true
+ break
+ end
end
+ if qf_exists then
+ vim.cmd('cclose')
+ else
+ vim.cmd('copen')
+ end
+end
- return false
+--- Toggle location list
+function M.toggle_location()
+ local loc_exists = false
+ for _, win in pairs(fn.getwininfo()) do
+ if win.loclist == 1 then
+ loc_exists = true
+ break
+ end
+ end
+ if loc_exists then
+ vim.cmd('lclose')
+ else
+ vim.cmd('lopen')
+ end
end
+-- Setup command aliases
+M.setup_command_alias('W', 'w')
+M.setup_command_alias('Wq', 'wq')
+M.setup_command_alias('WQ', 'wq')
+M.setup_command_alias('Q', 'q')
+M.setup_command_alias('Qa', 'qa')
+M.setup_command_alias('QA', 'qa')
+
--------------------------------------------------
--- Check whether a feature exists in Nvim
@@ -28,49 +97,76 @@ end
-- Format on save
local format_augroup = vim.api.nvim_create_augroup("LspFormatting", {})
-require("null-ls").setup({
- -- you can reuse a shared lspconfig on_attach callback here
- on_attach = function(client, bufnr)
- if client.supports_method("textDocument/formatting") then
- vim.api.nvim_clear_autocmds({ group = format_augroup, buffer = bufnr })
- vim.api.nvim_create_autocmd("BufWritePre", {
- group = format_augroup,
- buffer = bufnr,
- callback = function()
- -- on 0.8, you should use vim.lsp.buf.format({ bufnr = bufnr }) instead
- --vim.lsp.buf.formatting_seq_sync()
- vim.lsp.buf.format({ bufnr = bufnr })
- end,
- })
- end
- end,
-})
+
+local ok, null_ls = pcall(require, "null-ls")
+if ok then
+ null_ls.setup({
+ on_attach = function(client, bufnr)
+ if client.supports_method("textDocument/formatting") then
+ vim.api.nvim_clear_autocmds({ group = format_augroup, buffer = bufnr })
+ vim.api.nvim_create_autocmd("BufWritePre", {
+ group = format_augroup,
+ buffer = bufnr,
+ callback = function()
+ if vim.lsp.buf.format then
+ vim.lsp.buf.format({ bufnr = bufnr })
+ else
+ vim.lsp.buf.formatting_seq_sync()
+ end
+ end,
+ })
+ end
+ end,
+ })
+end
vim.cmd([[autocmd BufWritePre <buffer> lua vim.lsp.buf.format()]])
---vim.cmd [[autocmd BufWritePre * lua vim.lsp.buf.format()]]
+
--------------------------------------------------
---Determine if a value of any type is empty
---@param item any
---@return boolean?
+
+--- Checks if an item is considered "empty".
+--
+-- An item is considered empty if:
+-- - It is nil.
+-- - It is an empty string.
+-- - It is an empty table.
+-- - It is a number equal to 0 (you might want to adjust this based on your definition of "empty" for numbers).
+--
+-- @param item any The item to check.
+-- @return boolean True if the item is empty, false otherwise.
function M.empty(item)
- if not item then
+ -- Case 1: item is nil
+ if item == nil then
return true
end
+
local item_type = type(item)
+
+ -- Case 2: empty string
if item_type == "string" then
return item == ""
end
- if item_type == "number" then
- return item <= 0
- end
+
if item_type == "table" then
return vim.tbl_isempty(item)
end
- return item ~= nil
+ if item_type == "number" then
+ return item == 0 -- Changed from item <= 0 for a stricter "empty" definition for numbers
+ end
+
+ if item_type == "boolean" then
+ return not item -- Returns true if item is false, false if item is true
+ end
+
+ return false
end
+
--------------------------------------------------
--- Create a dir if it does not exist
@@ -533,22 +629,34 @@ function M.DeleteCurrentBuffer()
-- Delay before closing the nvim-tree window
end
-vim.cmd([[autocmd FileType NvimTree lua require("user.mods").DeleteCurrentBuffer()]])
-- On :bd nvim-tree should behave as if it wasn't opened
+-- Only run DeleteCurrentBuffer if NvimTree is loaded
+vim.api.nvim_create_autocmd("FileType", {
+ pattern = "NvimTree",
+ callback = function()
+ local ok, mods = pcall(require, "user.mods")
+ if ok and type(mods.DeleteCurrentBuffer) == "function" then
+ mods.DeleteCurrentBuffer()
+ end
+ end,
+})
+
+-- Handle NvimTree window closure safely
vim.api.nvim_create_autocmd("BufEnter", {
nested = true,
callback = function()
- -- Only 1 window with nvim-tree left: we probably closed a file buffer
- if #vim.api.nvim_list_wins() == 1 and require("nvim-tree.utils").is_nvim_tree_buf() then
- local api = require("nvim-tree.api")
- -- Required to let the close event complete. An error is thrown without this.
+ local ok_utils, utils = pcall(require, "nvim-tree.utils")
+ if not ok_utils then return end
+
+ if #vim.api.nvim_list_wins() == 1 and utils.is_nvim_tree_buf() then
+ local ok_api, api = pcall(require, "nvim-tree.api")
+ if not ok_api then return end
+
vim.defer_fn(function()
- -- close nvim-tree: will go to the last buffer used before closing
- api.tree.toggle({ find_file = true, focus = true })
- -- re-open nivm-tree
- api.tree.toggle({ find_file = true, focus = true })
- -- nvim-tree is still the active window. Go to the previous window.
+ -- Safely toggle tree off and on
+ pcall(api.tree.toggle, { find_file = true, focus = true })
+ pcall(api.tree.toggle, { find_file = true, focus = true })
vim.cmd("wincmd p")
end, 0)
end
@@ -741,105 +849,105 @@ end
--------------------------------------------------
--- Intercept file open
-local augroup = vim.api.nvim_create_augroup("user-autocmds", { clear = true })
-local intercept_file_open = true
-vim.api.nvim_create_user_command("InterceptToggle", function()
- intercept_file_open = not intercept_file_open
- local intercept_state = "`Enabled`"
- if not intercept_file_open then
- intercept_state = "`Disabled`"
- end
- vim.notify("Intercept file open set to " .. intercept_state, vim.log.levels.INFO, {
- title = "Intercept File Open",
- ---@param win integer The window handle
- on_open = function(win)
- vim.api.nvim_buf_set_option(vim.api.nvim_win_get_buf(win), "filetype", "markdown")
- end,
- })
-end, { desc = "Toggles intercepting BufNew to open files in custom programs" })
-
--- NOTE: Add "BufReadPre" to the autocmd events to also intercept files given on the command line, e.g.
--- `nvim myfile.txt`
-vim.api.nvim_create_autocmd({ "BufNew" }, {
- group = augroup,
- callback = function(args)
- ---@type string
- local path = args.match
- ---@type integer
- local bufnr = args.buf
-
- ---@type string? The file extension if detected
- local extension = vim.fn.fnamemodify(path, ":e")
- ---@type string? The filename if detected
- local filename = vim.fn.fnamemodify(path, ":t")
-
- ---Open a given file path in a given program and remove the buffer for the file.
- ---@param buf integer The buffer handle for the opening buffer
- ---@param fpath string The file path given to the program
- ---@param fname string The file name used in notifications
- ---@param prog string The program to execute against the file path
- local function open_in_prog(buf, fpath, fname, prog)
- vim.notify(string.format("Opening `%s` in `%s`", fname, prog), vim.log.levels.INFO, {
- title = "Open File in External Program",
- ---@param win integer The window handle
- on_open = function(win)
- vim.api.nvim_buf_set_option(vim.api.nvim_win_get_buf(win), "filetype", "markdown")
- end,
- })
- local mods = require("user.mods")
- local nvim_ver = mods.get_nvim_version()
-
- local version_major, version_minor = string.match(nvim_ver, "(%d+)%.(%d+)")
- version_major = tonumber(version_major)
- version_minor = tonumber(version_minor)
-
- if version_major > 0 or (version_major == 0 and version_minor >= 10) then
- vim.system({ prog, fpath }, { detach = true })
- else
- vim.fn.jobstart({ prog, fpath }, { detach = true })
- end
- vim.api.nvim_buf_delete(buf, { force = true })
- end
-
- local extension_callbacks = {
- ["pdf"] = function(buf, fpath, fname)
- open_in_prog(buf, fpath, fname, "zathura")
- end,
- ["epub"] = function(buf, fpath, fname)
- open_in_prog(buf, fpath, fname, "zathura")
- end,
- ["mobi"] = "pdf",
- ["png"] = function(buf, fpath, fname)
- open_in_prog(buf, fpath, fname, "vimiv")
- end,
- ["jpg"] = "png",
- ["mp4"] = function(buf, fpath, fname)
- open_in_prog(buf, fpath, fname, "vlc")
- end,
- ["gif"] = "mp4",
- }
-
- ---Get the extension callback for a given extension. Will do a recursive lookup if an extension callback is actually
- ---of type string to get the correct extension
- ---@param ext string A file extension. Example: `png`.
- ---@return fun(bufnr: integer, path: string, filename: string?) extension_callback The extension callback to invoke, expects a buffer handle, file path, and filename.
- local function extension_lookup(ext)
- local callback = extension_callbacks[ext]
- if type(callback) == "string" then
- callback = extension_lookup(callback)
- end
- return callback
- end
-
- if extension ~= nil and not extension:match("^%s*$") and intercept_file_open then
- local callback = extension_lookup(extension)
- if type(callback) == "function" then
- callback(bufnr, path, filename)
- end
- end
- end,
-})
+---- Intercept file open
+--local augroup = vim.api.nvim_create_augroup("user-autocmds", { clear = true })
+--local intercept_file_open = true
+--vim.api.nvim_create_user_command("InterceptToggle", function()
+-- intercept_file_open = not intercept_file_open
+-- local intercept_state = "`Enabled`"
+-- if not intercept_file_open then
+-- intercept_state = "`Disabled`"
+-- end
+-- vim.notify("Intercept file open set to " .. intercept_state, vim.log.levels.INFO, {
+-- title = "Intercept File Open",
+-- ---@param win integer The window handle
+-- on_open = function(win)
+-- vim.api.nvim_buf_set_option(vim.api.nvim_win_get_buf(win), "filetype", "markdown")
+-- end,
+-- })
+--end, { desc = "Toggles intercepting BufNew to open files in custom programs" })
+
+---- NOTE: Add "BufReadPre" to the autocmd events to also intercept files given on the command line, e.g.
+---- `nvim myfile.txt`
+--vim.api.nvim_create_autocmd({ "BufNew" }, {
+-- group = augroup,
+-- callback = function(args)
+-- ---@type string
+-- local path = args.match
+-- ---@type integer
+-- local bufnr = args.buf
+--
+-- ---@type string? The file extension if detected
+-- local extension = vim.fn.fnamemodify(path, ":e")
+-- ---@type string? The filename if detected
+-- local filename = vim.fn.fnamemodify(path, ":t")
+--
+-- ---Open a given file path in a given program and remove the buffer for the file.
+-- ---@param buf integer The buffer handle for the opening buffer
+-- ---@param fpath string The file path given to the program
+-- ---@param fname string The file name used in notifications
+-- ---@param prog string The program to execute against the file path
+-- local function open_in_prog(buf, fpath, fname, prog)
+-- vim.notify(string.format("Opening `%s` in `%s`", fname, prog), vim.log.levels.INFO, {
+-- title = "Open File in External Program",
+-- ---@param win integer The window handle
+-- on_open = function(win)
+-- vim.api.nvim_buf_set_option(vim.api.nvim_win_get_buf(win), "filetype", "markdown")
+-- end,
+-- })
+-- local mods = require("user.mods")
+-- local nvim_ver = mods.get_nvim_version()
+--
+-- local version_major, version_minor = string.match(nvim_ver, "(%d+)%.(%d+)")
+-- version_major = tonumber(version_major)
+-- version_minor = tonumber(version_minor)
+--
+-- if version_major > 0 or (version_major == 0 and version_minor >= 10) then
+-- vim.system({ prog, fpath }, { detach = true })
+-- else
+-- vim.fn.jobstart({ prog, fpath }, { detach = true })
+-- end
+-- vim.api.nvim_buf_delete(buf, { force = true })
+-- end
+--
+-- local extension_callbacks = {
+-- ["pdf"] = function(buf, fpath, fname)
+-- open_in_prog(buf, fpath, fname, "zathura")
+-- end,
+-- ["epub"] = function(buf, fpath, fname)
+-- open_in_prog(buf, fpath, fname, "zathura")
+-- end,
+-- ["mobi"] = "pdf",
+-- ["png"] = function(buf, fpath, fname)
+-- open_in_prog(buf, fpath, fname, "vimiv")
+-- end,
+-- ["jpg"] = "png",
+-- ["mp4"] = function(buf, fpath, fname)
+-- open_in_prog(buf, fpath, fname, "vlc")
+-- end,
+-- ["gif"] = "mp4",
+-- }
+--
+-- ---Get the extension callback for a given extension. Will do a recursive lookup if an extension callback is actually
+-- ---of type string to get the correct extension
+-- ---@param ext string A file extension. Example: `png`.
+-- ---@return fun(bufnr: integer, path: string, filename: string?) extension_callback The extension callback to invoke, expects a buffer handle, file path, and filename.
+-- local function extension_lookup(ext)
+-- local callback = extension_callbacks[ext]
+-- if type(callback) == "string" then
+-- callback = extension_lookup(callback)
+-- end
+-- return callback
+-- end
+--
+-- if extension ~= nil and not extension:match("^%s*$") and intercept_file_open then
+-- local callback = extension_lookup(extension)
+-- if type(callback) == "function" then
+-- callback(bufnr, path, filename)
+-- end
+-- end
+-- end,
+--})
--------------------------------------------------
@@ -1061,5 +1169,259 @@ end, { bang = true, nargs = 0 })
--------------------------------------------------
+
+-- Platform detection
+local uname = vim.loop.os_uname().sysname
+local has = vim.fn.has
+
+local is_mac = has("mac") == 1
+local is_linux = uname == "Linux"
+local is_windows = has("win32") == 1 or uname:find("Windows")
+local is_wsl = has("wsl") == 1 or (uname:find("Linux") and (os.getenv("WSL_DISTRO_NAME") ~= nil))
+local is_termux = has("termux") == 1 or (os.getenv("PREFIX") and os.getenv("PREFIX"):find("com.termux"))
+local os_name = (is_mac and "mac") or (is_linux and "linux") or (is_windows and "windows") or (is_wsl and "wsl") or (is_termux and "termux") or uname:lower()
+
+-- Check if a command exists
+local function command_exists(cmd)
+ local handle = io.popen(cmd .. " --version 2>/dev/null")
+ if handle then
+ local result = handle:read("*a")
+ handle:close()
+ return result ~= ""
+ end
+ return false
+end
+
+-- Detect clipboard tool on Linux
+local function detect_clipboard_tool()
+ if command_exists("xclip") then return "xclip" end
+ if command_exists("xsel") then return "xsel" end
+ if command_exists("wl-copy") and command_exists("wl-paste") then return "wl-clipboard" end
+ return nil
+end
+
+-- OSC52 clipboard copy fallback
+local function osc52_copy(text)
+ local encoded = vim.fn.system("base64 | tr -d '\n'", text)
+ io.write(string.format("\027]52;c;%s\007", encoded))
+end
+
+---- Set clipboard
+--function set_clipboard(text)
+-- if not text or text == "" then return end
+--
+-- if is_mac then
+-- local handle = io.popen("pbcopy", "w")
+-- if handle then
+-- handle:write(text)
+-- handle:close()
+-- end
+-- elseif is_linux then
+-- local tool = detect_clipboard_tool()
+-- if tool == "xclip" then
+-- local handle = io.popen("xclip -selection clipboard", "w")
+-- if handle then handle:write(text) handle:close() end
+-- elseif tool == "xsel" then
+-- local handle = io.popen("xsel --clipboard --input", "w")
+-- if handle then handle:write(text) handle:close() end
+-- elseif tool == "wl-clipboard" then
+-- local handle = io.popen("wl-copy", "w")
+-- if handle then handle:write(text) handle:close() end
+-- else
+-- osc52_copy(text)
+-- vim.notify("Using OSC52 for clipboard (install xclip, xsel, or wl-clipboard for better support)", vim.log.levels.INFO)
+-- end
+-- elseif is_wsl or is_windows then
+-- local handle = io.popen("clip", "w")
+-- if handle then handle:write(text) handle:close() end
+-- elseif is_termux then
+-- local handle = io.popen("termux-clipboard-set", "w")
+-- if handle then handle:write(text) handle:close() end
+-- else
+-- vim.notify("No clipboard support for OS: " .. os_name, vim.log.levels.WARN)
+-- end
+--end
+--
+---- Clipboard sync autocmd setup
+--local function setup_clipboard_sync()
+-- local ok, Job = pcall(require, "plenary.job")
+-- if not ok then
+-- -- plenary not available, skip
+-- return
+-- end
+--
+-- vim.api.nvim_create_augroup("clipboard_sync", { clear = true })
+-- vim.api.nvim_create_autocmd("TextYankPost", {
+-- group = "clipboard_sync",
+-- desc = "Sync yanked text to system clipboard",
+-- pattern = "*",
+-- callback = function()
+-- local text = vim.fn.getreg("\"")
+-- if text ~= nil and text ~= "" then
+-- set_clipboard(text)
+-- end
+-- end,
+-- })
+--end
+--setup_clipboard_sync()
+--
+---- Terminal clear function (optional)
+--function clear_terminal()
+-- vim.opt.scrollback = 1
+-- vim.api.nvim_feedkeys("i", "n", false)
+-- vim.api.nvim_feedkeys("clear\r", "n", false)
+-- vim.api.nvim_feedkeys("\x1b", "n", false)
+-- vim.api.nvim_feedkeys("i", "n", false)
+-- vim.defer_fn(function()
+-- vim.opt.scrollback = 10000
+-- end, 100)
+--end
+--
+---- Get clipboard content (optional)
+--function GetClipboard()
+-- local handle
+--
+-- if is_mac then
+-- handle = io.popen("pbpaste", "r")
+-- elseif is_linux then
+-- local tool = detect_clipboard_tool()
+-- if tool == "xclip" then
+-- handle = io.popen("xclip -selection clipboard -o", "r")
+-- elseif tool == "xsel" then
+-- handle = io.popen("xsel --clipboard --output", "r")
+-- elseif tool == "wl-clipboard" then
+-- handle = io.popen("wl-paste", "r")
+-- end
+-- elseif is_wsl or is_windows then
+-- handle = io.popen("powershell.exe Get-Clipboard", "r")
+-- elseif is_termux then
+-- handle = io.popen("termux-clipboard-get", "r")
+-- end
+--
+-- if handle then
+-- local result = handle:read("*a")
+-- handle:close()
+-- return result or ""
+-- end
+--
+-- return ""
+--end
+
+--------------------------------------------------
+
+-- Cross-platform file/URL opener
+function M.open_file_or_url(path)
+ local commands = {
+ mac = string.format('open "%s"', path),
+ linux = string.format('xdg-open "%s" &', path),
+ wsl = string.format('wslview "%s" &', path),
+ windows = string.format('start "" "%s"', path),
+ termux = string.format('am start -a android.intent.action.VIEW -d "%s"', path),
+ }
+
+ local cmd = commands[M.os_name]
+ if cmd then
+ os.execute(cmd)
+ else
+ vim.notify("No supported file opener for this OS: " .. tostring(M.os_name), vim.log.levels.WARN)
+ end
+end
+
+--------------------------------------------------
+
+-- Automcmd to close netrw buffer when file is opened
+vim.api.nvim_create_autocmd("FileType", {
+ pattern = "netrw",
+ callback = function()
+ vim.api.nvim_create_autocmd("BufEnter", {
+ once = true,
+ callback = function()
+ if vim.bo.filetype ~= "netrw" then
+ for _, buf in ipairs(vim.api.nvim_list_bufs()) do
+ if vim.bo[buf].filetype == "netrw" then
+ vim.api.nvim_buf_delete(buf, { force = true })
+ end
+ end
+ end
+ end,
+ })
+ end,
+})
+
+--------------------------------------------------
+
+-- Autocomplete
+vim.api.nvim_create_autocmd("InsertCharPre", {
+ callback = function()
+ -- Exit the autocmd if nvim-cmp is present
+ local cmp_is_present, _ = pcall(require, "cmp")
+ if cmp_is_present then
+ return
+ end
+
+ -- Skip unwanted buffer types (Telescope, NvimTree, etc.)
+ local ft = vim.bo.filetype
+ local bt = vim.bo.buftype
+ local ignore_ft = {
+ "TelescopePrompt",
+ "prompt",
+ "nofile",
+ "terminal",
+ "help",
+ "quickfix",
+ "lazy",
+ "neo-tree",
+ "NvimTree",
+ "starter",
+ "packer",
+ }
+
+ if bt ~= "" or vim.tbl_contains(ignore_ft, ft) then
+ return
+ end
+
+ local col = vim.fn.col(".")
+ local line = vim.fn.getline(".")
+ local function safe_sub(i)
+ return line:sub(i, i)
+ end
+
+ local prev3 = safe_sub(col - 3)
+ local prev2 = safe_sub(col - 2)
+ local prev1 = safe_sub(col - 1)
+ local curr = vim.v.char
+
+ if curr:match("%w") and prev3:match("%W") and prev2:match("%w") and prev1:match("%w") then
+ vim.api.nvim_feedkeys(
+ vim.api.nvim_replace_termcodes("<C-n>", true, true, true),
+ "n",
+ true
+ )
+ end
+ end,
+})
+--------------------------------------------------
+
+M.has_treesitter = function ( bufnr )
+ if not bufnr then
+ bufnr = vim.api.nvim_get_current_buf()
+ end
+
+ local highlighter = require( "vim.treesitter.highlighter" )
+
+ if highlighter.active[ bufnr ] then
+ return true
+ else
+ return false
+ end
+end
+
+M.parse_treesitter = function ( bufnr, range )
+ local parser = vim.treesitter.get_parser( bufnr )
+
+ -- XXX https://neovim.io/doc/user/treesitter.html#LanguageTree%3Aparse()
+ parser:parse( range )
+end
+
-- ...
return M
diff --git a/lua/user/opts.lua b/lua/user/opts.lua
index cc8debc..bac80c3 100644..100755
--- a/lua/user/opts.lua
+++ b/lua/user/opts.lua
@@ -1,40 +1,137 @@
---[[ opts.lua ]]
-
--- Environment
---vim.opt.shell = "zsh" --
-vim.o.updatetime = 250
-vim.o.shell = '/bin/zsh'
-vim.scriptencoding = 'utf-8' --
-vim.opt.encoding = 'utf-8' --
-vim.opt.fileencoding = 'utf-8' --
-vim.g.python3_host_prog = '/usr/bin/python3' --
+-- ============================================================================
+-- Options
+-- ============================================================================
+
+local uname = vim.loop.os_uname()
+local system = uname.sysname
+local shell = nil
+
+if system == "Windows_NT" then
+ -- Windows options
+ if vim.fn.executable("pwsh") == 1 then
+ shell = "pwsh"
+ elseif vim.fn.executable("powershell") == 1 then
+ shell = "powershell"
+ elseif vim.fn.executable("bash") == 1 then
+ shell = "bash"
+ end
+else
+ -- Unix-like systems: use the user's default shell
+ local env_shell = os.getenv("SHELL")
+ if env_shell and vim.fn.executable(env_shell) == 1 then
+ shell = env_shell
+ else
+ -- fallback logic
+ if vim.fn.executable("zsh") == 1 then
+ shell = vim.fn.exepath("zsh")
+ elseif vim.fn.executable("bash") == 1 then
+ shell = vim.fn.exepath("bash")
+ end
+ end
+end
+
+-- Finally set the shell if we found one
+if shell then
+ vim.o.shell = shell
+end
+
+-- Core Settings
+vim.opt.encoding = 'utf-8'
+vim.opt.fileencoding = 'utf-8'
+vim.scriptencoding = 'utf-8'
+vim.opt.termguicolors = true
+vim.opt.mouse = 'a'
+vim.opt.clipboard = 'unnamedplus'
+vim.opt.hidden = true
+vim.opt.updatetime = 300
+vim.opt.timeoutlen = 500
+vim.opt.ttimeoutlen = 10
+
+-- Display
+vim.opt.number = true
+vim.opt.relativenumber = true
+vim.opt.cursorline = true
+vim.opt.signcolumn = 'yes'
+vim.opt.showcmd = true
+vim.opt.showmode = true
+vim.opt.showmatch = true
+vim.opt.laststatus = 2
+vim.opt.cmdheight = 1
+vim.opt.scrolloff = 5
+vim.opt.sidescrolloff = 5
+vim.opt.display = 'lastline'
+
+-- Indentation
+vim.opt.autoindent = true
+vim.opt.smartindent = true
+vim.opt.expandtab = true
+vim.opt.tabstop = 2
+vim.opt.shiftwidth = 2
+vim.opt.softtabstop = 2
+vim.opt.shiftround = true
+
+-- Search
+vim.opt.hlsearch = true
+vim.opt.incsearch = true
+vim.opt.ignorecase = true
+vim.opt.smartcase = true
+vim.opt.inccommand = 'split'
+
+-- Window Management
+vim.opt.splitright = true
+vim.opt.splitbelow = true
+vim.opt.winminwidth = 1
+vim.opt.winwidth = 5
+
+-- File Handling
+vim.opt.autoread = true
+--vim.opt.autowrite = true
+vim.opt.backup = true
+vim.opt.backupdir = vim.fn.stdpath('cache') .. '/backup//'
+vim.opt.directory = vim.fn.stdpath('cache') .. '/swap//'
+vim.opt.undofile = true
+vim.opt.undodir = vim.fn.stdpath('cache') .. '/undo//'
+vim.opt.swapfile = false
+
+-- Wildmenu
+vim.opt.wildmenu = true
+vim.opt.wildmode = 'longest:full,full'
+vim.opt.wildignorecase = true
+vim.opt.wildignore = '*.o,*.obj,.git,*.rbc,*.pyc,__pycache__'
+
+
+vim.scriptencoding = "utf-8" --
+vim.opt.encoding = "utf-8" --
+vim.opt.fileencoding = "utf-8" --
+vim.g.python3_host_prog = "/usr/bin/python3" --
vim.g.loaded_python3_provider = 1 --
vim.g.sh_noisk = 1 -- iskeyword word boundaries when editing a 'sh' file
vim.o.autochdir = true
--vim.o.writeany= true
-- Clipboard
-vim.opt.clipboard:append({ 'unnamedplus' }) -- Install xclip or this will slowdown startup
+vim.opt.clipboard:append({ "unnamedplus" }) -- Install xclip or this will slowdown startup
-- Behaviour
-vim.opt.backspace = { 'start', 'eol', 'indent' } -- Make backspace work as you would expect.
+vim.opt.backspace = { "start", "eol", "indent" } -- Make backspace work as you would expect.
vim.opt.hidden = true -- Switch between buffers without having to save first.
+vim.opt.conceallevel = 2
vim.opt.splitbelow = true -- make split put the new buffer below the current buffer
vim.opt.splitright = true -- make vsplit put the new buffer on the right of the current buffer
vim.opt.scrolloff = 8 --
vim.opt.sidescrolloff = 8 -- how many lines to scroll when using the scrollbar
vim.opt.autoread = true -- reload files if changed externally
-vim.opt.display = 'lastline' -- Show as much as possible of the last line.
-vim.opt.inccommand = 'split' --
+vim.opt.display = "lastline" -- Show as much as possible of the last line.
+vim.opt.inccommand = "split" --
vim.opt.ttyfast = true -- Faster redrawing.
vim.opt.lazyredraw = false -- Only redraw when necessary
-vim.opt.keywordprg = ':help' -- :help options
+vim.opt.keywordprg = ":help" -- :help options
vim.opt.ruler = true --
vim.opt.errorbells = false --
vim.opt.list = true -- Show non-printable characters.
vim.opt.showmatch = true --
vim.opt.matchtime = 3 --
-vim.opt.showbreak = '↪ ' --
+vim.opt.showbreak = "↪ " --
vim.opt.linebreak = true --
vim.opt.exrc = true --
--vim.opt.autochdir = true -- or use this to use <:e> to create a file in current directory
@@ -59,10 +156,28 @@ vim.opt.shiftround = true -- >> indents to next multiple of 'shiftwidth'.
vim.opt.smartindent = true -- smart indent
-- Column/statusline/Cl
-vim.opt.number = true --
+
+-- Enable number and relativenumber by default
+vim.opt.number = true
+vim.opt.relativenumber = true
+
+-- Entering insert mode: disable relativenumber
+vim.api.nvim_create_autocmd("InsertEnter", {
+ callback = function()
+ vim.opt.relativenumber = false
+ end,
+})
+
+-- Leaving insert mode: enable relativenumber
+vim.api.nvim_create_autocmd("InsertLeave", {
+ callback = function()
+ vim.opt.relativenumber = true
+ end,
+})
+
vim.opt.title = true --
--vim.opt.colorcolumn = "+1" --
-vim.opt.signcolumn = 'yes:1' -- always show the sign column
+vim.opt.signcolumn = "yes:1" -- always show the sign column
--vim.opt.signcolumn = "yes:" .. vim.o.numberwidth
--vim.opt.signcolumn = "number"
--vim.opt.signcolumn = "no" --
@@ -90,51 +205,52 @@ vim.opt.report = 0 -- Always report changed lines.
--vim.opt.stl = " "
-- Backup/undo/swap
-local prefix = vim.env.XDG_CONFIG_HOME or vim.fn.expand('~/.config')
+local prefix = vim.env.XDG_CONFIG_HOME or vim.fn.expand("~/.config")
--vim.opt.undodir = os.getenv("HOME") .. "/.vim/undodir"
-vim.opt.undodir = { prefix .. '/nvim/tmp/.undo//' }
-vim.opt.directory = { prefix .. '/nvim/tmp/.swp//' }
-vim.opt.backupdir = { prefix .. '/nvim/tmp/.backup//' }
+--vim.opt.undodir = { prefix .. "/nvim/tmp/.undo//" }
+vim.opt.undodir = os.getenv("HOME") .. "/.vim/undodir"
+vim.opt.directory = { prefix .. "/nvim/tmp/.swp//" }
+vim.opt.backupdir = { prefix .. "/nvim/tmp/.backup//" }
vim.opt.undofile = true --
vim.opt.swapfile = true --
vim.opt.backup = true --
--vim.opt.backupcopy =
-- Add timestamp as extension for backup files
-vim.api.nvim_create_autocmd('BufWritePre', {
- group = vim.api.nvim_create_augroup('timestamp_backupext', { clear = true }),
- desc = 'Add timestamp to backup extension',
- pattern = '*',
+vim.api.nvim_create_autocmd("BufWritePre", {
+ group = vim.api.nvim_create_augroup("timestamp_backupext", { clear = true }),
+ desc = "Add timestamp to backup extension",
+ pattern = "*",
callback = function()
- vim.opt.backupext = '-' .. vim.fn.strftime('%Y%m%d%H%M')
+ vim.opt.backupext = "-" .. vim.fn.strftime("%Y%m%d%H%M")
end,
})
-- Format
--vim.opt.textwidth = 80 --
-vim.opt.isfname:append('@-@')
+vim.opt.isfname:append("@-@")
vim.cmd([[let &t_Cs = "\e[4:3m"]]) -- Undercurl
vim.cmd([[let &t_Ce = "\e[4:0m"]]) --
-vim.opt.path:append({ '**' }) -- Finding files - Search down into subfolder
-vim.cmd('set whichwrap+=<,>,[,],h,l') --
+vim.opt.path:append({ "**" }) -- Finding files - Search down into subfolder
+vim.cmd("set whichwrap+=<,>,[,],h,l") --
vim.cmd([[set iskeyword+=-]]) --
--vim.cmd([[set formatoptions-=cro]]) -- TODO: this doesn't seem to work
vim.opt.formatoptions = vim.opt.formatoptions
- - 't' -- wrap with text width
- + 'c' -- wrap comments
- + 'r' -- insert comment after enter
- - 'o' -- insert comment after o/O
- - 'q' -- allow formatting of comments with gq
- - 'a' -- format paragraphs
- + 'n' -- recognized numbered lists
- - '2' -- use indent of second line for paragraph
- + 'l' -- long lines are not broken
- + 'j' -- remove comment when joining lines
+ - "t" -- wrap with text width
+ + "c" -- wrap comments
+ + "r" -- insert comment after enter
+ - "o" -- insert comment after o/O
+ - "q" -- allow formatting of comments with gq
+ - "a" -- format paragraphs
+ + "n" -- recognized numbered lists
+ - "2" -- use indent of second line for paragraph
+ + "l" -- long lines are not broken
+ + "j" -- remove comment when joining lines
vim.opt.wrapscan = true -- " Searches wrap around end-of-file.
--vim.wo.number = true --
--vim.opt.wrap = false -- No Wrap lines
--vim.opt.foldmethod = 'manual' --
--vim.opt.foldmethod = "expr" --
-vim.opt.foldmethod = 'manual'
+vim.opt.foldmethod = "manual"
vim.opt.foldlevel = 3
vim.opt.confirm = false
--vim.opt.shortmess:append("sI")
@@ -142,42 +258,42 @@ vim.opt.confirm = false
--vim.opt.shortmess = "sI"
--vim.o.shortmess = vim.o.shortmess:gsub('s', '')
vim.opt.shortmess = table.concat({ -- Use abbreviations and short messages in command menu line.
- 'f', -- Use "(3 of 5)" instead of "(file 3 of 5)".
- 'i', -- Use "[noeol]" instead of "[Incomplete last line]".
- 'l', -- Use "999L, 888C" instead of "999 lines, 888 characters".
- 'm', -- Use "[+]" instead of "[Modified]".
- 'n', -- Use "[New]" instead of "[New File]".
- 'r', -- Use "[RO]" instead of "[readonly]".
- 'w', -- Use "[w]", "[a]" instead of "written", "appended".
- 'x', -- Use "[dos]", "[unix]", "[mac]" instead of "[dos format]", "[unix format]", "[mac format]".
- 'o', -- Overwrite message for writing a file with subsequent message.
- 'O', -- Message for reading a file overwrites any previous message.
- 's', -- Disable "search hit BOTTOM, continuing at TOP" such messages.
- 't', -- Truncate file message at the start if it is too long.
- 'T', -- Truncate other messages in the middle if they are too long.
- 'I', -- Don't give the :intro message when starting.
- 'c', -- Don't give ins-completion-menu messages.
- 'F', -- Don't give the file info when editing a file.
+ "f", -- Use "(3 of 5)" instead of "(file 3 of 5)".
+ "i", -- Use "[noeol]" instead of "[Incomplete last line]".
+ "l", -- Use "999L, 888C" instead of "999 lines, 888 characters".
+ "m", -- Use "[+]" instead of "[Modified]".
+ "n", -- Use "[New]" instead of "[New File]".
+ "r", -- Use "[RO]" instead of "[readonly]".
+ "w", -- Use "[w]", "[a]" instead of "written", "appended".
+ "x", -- Use "[dos]", "[unix]", "[mac]" instead of "[dos format]", "[unix format]", "[mac format]".
+ "o", -- Overwrite message for writing a file with subsequent message.
+ "O", -- Message for reading a file overwrites any previous message.
+ "s", -- Disable "search hit BOTTOM, continuing at TOP" such messages.
+ "t", -- Truncate file message at the start if it is too long.
+ "T", -- Truncate other messages in the middle if they are too long.
+ "I", -- Don't give the :intro message when starting.
+ "c", -- Don't give ins-completion-menu messages.
+ "F", -- Don't give the file info when editing a file.
})
vim.opt.fillchars = {
- horiz = '─',
- horizup = '┴',
- horizdown = '┬',
- vert = '│',
- vertleft = '┤',
- vertright = '├',
- verthoriz = '┼',
- foldopen = '',
- foldsep = '│',
- foldclose = '',
- fold = '─',
- eob = ' ',
+ horiz = "─",
+ horizup = "┴",
+ horizdown = "┬",
+ vert = "│",
+ vertleft = "┤",
+ vertright = "├",
+ verthoriz = "┼",
+ foldopen = "",
+ foldsep = "│",
+ foldclose = "",
+ fold = "─",
+ eob = " ",
--diff = "┃",
- diff = '░',
- msgsep = '━',
+ diff = "░",
+ msgsep = "━",
--msgsep = "‾",
}
-vim.opt.listchars = { tab = '▸ ', trail = '·' } --
+vim.opt.listchars = { tab = "▸ ", trail = "·" } --
--vim.opt.fillchars:append({ eob = " " }) -- remove the ~ from end of buffer
vim.opt.modeline = true --
vim.opt.modelines = 3 -- modelines (comments that set vim options on a per-file basis)
@@ -194,40 +310,45 @@ vim.opt.smartcase = true -- smart case
vim.opt.synmaxcol = 200 -- Only highlight the first 200 columns.
--vim.opt.winblend = 30
--vim.opt.winblend = 5
-vim.opt.wildoptions = 'pum' --
+vim.opt.wildoptions = "pum" --
--vim.opt.pumblend = 5 --
vim.opt.pumblend = 12 --
--vim.opt.pumblend=15
vim.opt.pumheight = 10 -- pop up menu height
-- Better Completion
-vim.opt.complete = { '.', 'w', 'b', 'u', 't' } --
+vim.opt.complete = { ".", "w", "b", "u", "t" } --
--vim.opt.completeopt = { "longest,menuone,preview" } --
-vim.opt.completeopt = { 'menu', 'menuone', 'noselect' }
+vim.opt.completeopt = { "menu", "menuone", "noselect" }
--vim.opt.completeopt = { "menuone", "noselect" } -- mostly just for cmp
--vim.opt.completeopt = { "menu", "menuone", "noselect" } --
+-- Spellcheck
+vim.opt.spelllang = { "en_gb", "en_us" } -- Set a list of preferred dictionaries
+vim.opt.spell = true
+--vim.opt.spellfile = "~/.config/nvim/spell/en.utf-8.add" -- Specify a personal dictionary file
+
-- Wildmenu completion --
vim.opt.wildmenu = true --
-vim.opt.wildmode = { 'list:longest' } --
-vim.opt.wildignore:append({ '.hg', '.git', '.svn' }) -- Version control
-vim.opt.wildignore:append({ '*.aux', '*.out', '*.toc' }) -- LaTeX intermediate files
-vim.opt.wildignore:append({ '*.jpg', '*.bmp', '*.gif', '*.png', '*.jpeg' }) -- binary images
-vim.opt.wildignore:append({ '*.o', '*.obj', '*.exe', '*.dll', '*.manifest' }) -- compiled object files
-vim.opt.wildignore:append({ '*.spl' }) -- compiled spelling word lists
-vim.opt.wildignore:append({ '*.sw?' }) -- Vim swap files
-vim.opt.wildignore:append({ '*.DS_Store' }) -- OSX bullshit
-vim.opt.wildignore:append({ '*.luac' }) -- Lua byte code
-vim.opt.wildignore:append({ 'migrations' }) -- Django migrations
-vim.opt.wildignore:append({ '*.pyc' }) -- Python byte code
-vim.opt.wildignore:append({ '*.orig' }) -- Merge resolution files
-vim.opt.wildignore:append({ '*/node_modules/*' }) --
+vim.opt.wildmode = { "list:longest" } --
+vim.opt.wildignore:append({ ".hg", ".git", ".svn" }) -- Version control
+vim.opt.wildignore:append({ "*.aux", "*.out", "*.toc" }) -- LaTeX intermediate files
+vim.opt.wildignore:append({ "*.jpg", "*.bmp", "*.gif", "*.png", "*.jpeg" }) -- binary images
+vim.opt.wildignore:append({ "*.o", "*.obj", "*.exe", "*.dll", "*.manifest" }) -- compiled object files
+vim.opt.wildignore:append({ "*.spl" }) -- compiled spelling word lists
+vim.opt.wildignore:append({ "*.sw?" }) -- Vim swap files
+vim.opt.wildignore:append({ "*.DS_Store" }) -- OSX bullshit
+vim.opt.wildignore:append({ "*.luac" }) -- Lua byte code
+vim.opt.wildignore:append({ "migrations" }) -- Django migrations
+vim.opt.wildignore:append({ "*.pyc" }) -- Python byte code
+vim.opt.wildignore:append({ "*.orig" }) -- Merge resolution files
+vim.opt.wildignore:append({ "*/node_modules/*" }) --
-- Shada
vim.opt.shada = "!,'1000,f1,<1000,s100,:1000,/1000,h"
-- Sessions
-vim.opt.sessionoptions = 'blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal'
+vim.opt.sessionoptions = "blank,buffers,curdir,folds,help,tabpages,winsize,winpos,terminal"
--vim.opt.sessionoptions = "curdir,folds,help,options,tabpages,winsize,winpos,terminal,globals" --
--vim.opt.sessionoptions = "buffers,curdir,folds,help,tabpages,winsize,winpos,terminal"
--vim.opt.sessionoptions:remove({ "blank", "buffers", "globals" })
@@ -241,13 +362,8 @@ vim.g.netrw_winsize = 25
--vim.cmd([[
-- "filetype plugin indent on
--]])
-vim.cmd('filetype plugin on')
-vim.cmd('filetype indent off')
-
--- Let clipboard register be +
-vim.cmd([[
- let g:clipbrdDefaultReg = '+'
-]])
+vim.cmd("filetype plugin on")
+vim.cmd("filetype indent off")
--vim.cmd([[
-- "autocmd BufEnter * :syntax sync fromstart
@@ -256,6 +372,7 @@ vim.cmd([[
-- "autocmd FileType lua set comments=s1:---,m:--,ex:--
--]])
+
-- Fast macros without lazyredraw
vim.cmd([[
set re=0
@@ -280,7 +397,7 @@ vim.cmd([[ " Only show cursorline in the
augroup END
]])
vim.opt.cursorline = true --
-vim.opt.guicursor = 'i:ver100,r:hor100' --
+vim.opt.guicursor = "i:ver100,r:hor100" --
-- Trailing whitespace
vim.cmd([[ " Only show in insert mode
@@ -319,33 +436,3 @@ vim.cmd([[
let &scrollback=s:scroll_value
endfunction
]])
-
--- Yank to clipboard in Termux
-if vim.fn.has('termux') == 1 then
- local Job = require('plenary.job')
- vim.api.nvim_create_autocmd('TextYankPost', {
- pattern = '*',
- callback = function()
- Job:new({
- command = 'termux-clipboard-set',
- writer = vim.fn.getreg('@'),
- }):start()
- end,
- })
-end
-
-function GetTermuxClipboard()
- if vim.fn.has('termux') == 1 then
- local sysclip = vim.fn.system('termux-clipboard-get')
- if sysclip ~= '@' then
- vim.fn.setreg('@', sysclip)
- end
- end
- return ''
-end
-
-if vim.fn.has('termux') == 1 then
- vim.cmd('autocmd TextYankPost * call GetTermuxClipboard()')
- vim.cmd('noremap <expr> p Paste("p")')
- vim.cmd('noremap <expr> P Paste("P")')
-end
diff --git a/lua/user/pack.lua b/lua/user/pack.lua
deleted file mode 100644
index 7ed86db..0000000
--- a/lua/user/pack.lua
+++ /dev/null
@@ -1,403 +0,0 @@
-local fn = vim.fn
-
---------------------------------------------------
-
--- Automatically install packer
-local install_path = fn.stdpath("data") .. "/site/pack/packer/start/packer.nvim"
-if fn.empty(fn.glob(install_path)) > 0 then
- PACKER_BOOTSTRAP = fn.system({
- "git",
- "clone",
- "--depth",
- "1",
- "https://github.com/wbthomason/packer.nvim",
- install_path,
- })
- print("Installing packer, please close and reopen Neovim...")
- vim.cmd([[packadd packer.nvim]])
-end
-
---------------------------------------------------
-
--- Autocommand that reloads neovim whenever you save this file
-vim.cmd([[
- augroup packer_user_config
- autocmd!
- autocmd BufWritePost pack.lua source <afile> | PackerSync
- augroup end
-]])
-
---------------------------------------------------
-
--- Use a protected call so don't error out on first use
-local status_ok, packer = pcall(require, "packer")
-if not status_ok then
- return
-end
-
---------------------------------------------------
-
--- Have packer use a popup window and set a maximum number of jobs
-packer.init({
- auto_reload_compiled = true,
- --max_jobs = 90,
- display = {
- open_fn = function()
- return require("packer.util").float({ border = "rounded" })
- end,
- },
-})
-
---------------------------------------------------
-
--- Install plugins here
-return packer.startup(function(use)
- -- Defaults
- use("wbthomason/packer.nvim") -- Have packer manage itself (package manager)
- use("nvim-lua/plenary.nvim") -- Useful lua functions used by lots of plugins
- use("lewis6991/impatient.nvim") -- Faster loading/startup times
-
- -- Tree-sitter
- use({ "nvim-treesitter/nvim-treesitter", run = ":TSUpdate" }) -- For language parsing, examples: highlighting, folding, jumping, refactoring...
- use("nvim-treesitter/nvim-treesitter-refactor") -- Refactor module for nvim-treesitter
-
- -- lsp
- use("williamboman/mason.nvim") -- Package manager to install and manage LSP servers, DAP servers, linters and formatters
- use("neovim/nvim-lspconfig") -- Collection of LSP configs
- use("williamboman/mason-lspconfig.nvim") -- Bridges mason.nvim with nvim-lspconfig to help use them together
- use({
- "https://git.sr.ht/~whynothugo/lsp_lines.nvim",
- config = function()
- require("lsp_lines").setup()
- end,
- })
- use("rmagatti/goto-preview")
-
- -- Debugger
- use("mfussenegger/nvim-dap") -- Debug Adapter Protocol client implementation for Neovim
- use("rcarriga/nvim-dap-ui") -- UI for nvim-dap
- --use { "rcarriga/nvim-dap-ui", requires = {"mfussenegger/nvim-dap"} }
- use("theHamsta/nvim-dap-virtual-text")
- use("gabrielpoca/replacer.nvim")
- use("jayp0521/mason-nvim-dap.nvim")
- --use({
- -- "jayp0521/mason-nvim-dap.nvim",
- -- config = function()
- -- require("mason-nvim-dap").setup({
- -- automatic_installation = true,
- -- ensure_installed = { "python", "cppdbg", "codelldb" },
- -- })
- -- end,
- --})
-
- -- Linters/Formatters
- use("mhartington/formatter.nvim")
- use("jay-babu/mason-null-ls.nvim")
- --use({"jayp0521/mason-null-ls.nvim",
- -- config = function()
- -- require('mason-null-ls.nvim').setup({
- -- automatic_setup = true,
- -- })
- -- end
- --})
- use({
- "jose-elias-alvarez/null-ls.nvim", -- Provides LSP: linters, formatters, diagnostics, code actions and etc...
- requires = { "jay-babu/mason-null-ls.nvim" },
- })
-
- -- Completion
- use("hrsh7th/nvim-cmp") -- Completion engine plugin
- use("hrsh7th/cmp-nvim-lsp") -- Completion source for nvim-lsp
- use("hrsh7th/cmp-buffer") -- Completion source for content of current buffer
- use("hrsh7th/cmp-path") -- Completion source for paths
- use("hrsh7th/cmp-cmdline") -- Completion source for command-line
- use("petertriho/cmp-git") -- Completion source for git
- use("tamago324/cmp-zsh") -- Completion source for zsh
- use("f3fora/cmp-spell") -- Completion source for spell-checking
- use("hrsh7th/cmp-calc") -- Completion source for math calculation
- use("saadparwaiz1/cmp_luasnip") -- Completion source for snippets, specifically for luasnip
- use("hrsh7th/cmp-nvim-lsp-signature-help") -- Completion source for displaying function signatures with the current parameter emphasized
- use("rcarriga/cmp-dap")
-
- -- Snippets
- use("L3MON4D3/LuaSnip") -- Snippet engine
- use("rafamadriz/friendly-snippets") -- Collection of snippets to use
-
- -- Git
- use("tpope/vim-fugitive") --
- --use("dinhhuy258/git.nvim") -- For git blame & browse
- use("kdheepak/lazygit.nvim") -- Terminal UI for git commands
- use("lewis6991/gitsigns.nvim") -- Git decorations
-
- -- File explorer/fuzzy finder
- use("kyazdani42/nvim-tree.lua") -- File explorer
- use("ibhagwan/fzf-lua") -- Fuzzy finder
- use("ThePrimeagen/harpoon")
- --use("nvim-telescope/telescope.nvim") -- Fuzzy finder with lots of features/extendabilities
- use({
- "nvim-telescope/telescope.nvim",
- branch = "0.1.x",
- --config = function()
- -- require('plugins.telescope').setup()
- --end,
- requires = {
- "nvim-lua/plenary.nvim",
- "nvim-telescope/telescope-live-grep-args.nvim",
- "nvim-telescope/telescope-file-browser.nvim",
- { "nvim-telescope/telescope-fzf-native.nvim", run = "make" },
- },
- })
- use({ "nvim-telescope/telescope-fzf-native.nvim", run = "make" }) -- Support fzf syntax/algorithm
- use("nvim-telescope/telescope-ui-select.nvim") --
- use("nvim-telescope/telescope-project.nvim") --
- use("nvim-telescope/telescope-media-files.nvim") --
- use("nvim-telescope/telescope-file-browser.nvim") --
- use({ "nvim-telescope/telescope-symbols.nvim", after = "telescope.nvim" }) -- Search emoji(s) and other symbols
- use("nvim-telescope/telescope-dap.nvim")
- use("axkirillov/telescope-changed-files") --
- use("smartpde/telescope-recent-files")
- use("rmagatti/auto-session")
- use("rmagatti/session-lens")
-
- -- UX
- use("folke/neodev.nvim")
- use({
- "numToStr/Navigator.nvim", -- Navigate between Tmux and Nvim
- config = function()
- require("Navigator").setup()
- end,
- })
- use({ "tpope/vim-eunuch", cmd = { "Rename", "Delete", "Mkdir" } }) -- Handy unix commands inside Vim (Rename, Move etc.)
- --use("tpope/vim-obsession") --
- use("tpope/vim-unimpaired") --
- --use("tpope/vim-surround") --
- use({
- "kylechui/nvim-surround",
- tag = "*", -- Use for stability; omit to use `main` branch for the latest features
- })
- --use("vimpostor/vim-tpipeline") --
- --use("nathom/filetype.nvim") --
- use("mbbill/undotree")
- use({
- "myusuf3/numbers.vim", --
- vim.cmd("let g:numbers_exclude = ['dashboard']"),
- })
- use("windwp/nvim-autopairs") --
- use("numToStr/Comment.nvim") --
- use("akinsho/toggleterm.nvim") --
- use("tweekmonster/startuptime.vim") --
- use("qpkorr/vim-bufkill")
- use({
- "ggandor/leap.nvim", --
- config = function()
- require("leap").add_default_mappings()
- --require("leap").set_default_keymaps()
- --vim.keymap.set('n', '-', '<Plug>(leap-forward)', {})
- --vim.keymap.set('n', '_', '<Plug>(leap-backward)', {})
- end,
- })
- use({
- "ggandor/flit.nvim", --
- config = function()
- require("flit").setup()
- end,
- })
- use("folke/which-key.nvim") --
- use("folke/zen-mode.nvim") --
- use("romainl/vim-cool") --
- use("antoinemadec/FixCursorHold.nvim") --
- use({
- "folke/trouble.nvim",
- requires = "nvim-tree/nvim-web-devicons",
- })
- use({
- "airblade/vim-rooter", --
- --vim.cmd("let g:rooter_change_directory_for_non_project_files = ''"),
- --vim.cmd("let g:rooter_change_directory_for_non_project_files = 'current'")
- })
- use({ "michaelb/sniprun", run = "bash ./install.sh" })
- use({ "stevearc/overseer.nvim" })
- --use("vim-test/vim-test") --
- --use({
- -- "rcarriga/vim-ultest", --
- -- requires = { "vim-test/vim-test" },
- -- run = ":UpdateRemotePlugins",
- -- config = function()
- -- require("plugins.ultest")
- -- end,
- --})
- --use({"rcarriga/neotest",
- -- config = function()
- -- require("neotest").setup()
- --end,
- --})
- use({
- "nvim-neotest/neotest",
- requires = {
- {
- "nvim-neotest/neotest-python",
- "nvim-neotest/neotest-plenary",
- "nvim-neotest/neotest-vim-test",
- },
- },
- })
- use("kawre/leetcode.nvim")
- use("m4xshen/hardtime.nvim")
- use({
- "luckasRanarison/nvim-devdocs",
- config = function()
- require("nvim-devdocs").setup()
- end,
- })
-
- -- Colorschemes
- use("bluz71/vim-nightfly-guicolors")
- use("ayu-theme/ayu-vim")
- use("joshdick/onedark.vim")
- use("NTBBloodbath/doom-one.nvim")
- use("nyngwang/nvimgelion")
- use("projekt0n/github-nvim-theme")
- use("folke/tokyonight.nvim")
- use("ribru17/bamboo.nvim")
-
- -- UI
- use("kyazdani42/nvim-web-devicons") --
- use("onsails/lspkind-nvim") --
- use({ "kevinhwang91/nvim-ufo", requires = "kevinhwang91/promise-async" }) -- Fold code
- use("lukas-reineke/indent-blankline.nvim")
- use({
- "luukvbaal/statuscol.nvim",
- config = function()
- local builtin = require("statuscol.builtin")
- require("statuscol").setup({
- relculright = true,
- segments = {
- { text = { builtin.foldfunc }, click = "v:lua.ScFa" },
- { text = { "%s" }, click = "v:lua.ScSa" },
- { text = { builtin.lnumfunc, " " }, click = "v:lua.ScLa" },
- },
- })
- end,
- })
- use({
- "glepnir/dashboard-nvim",
- --event = 'VimEnter',
- requires = { "nvim-tree/nvim-web-devicons" },
- })
- use("rcarriga/nvim-notify") -- Notification plugin
- use("karb94/neoscroll.nvim") -- Faster/smooth scrolling
- --use("MunifTanjim/prettier.nvim") -- Prettier plugin for Neovim's built-in LSP client
- use({
- "norcalli/nvim-colorizer.lua", -- colorize hexa and rgb strings
- cmd = { "ColorizerToggle", "ColorizerAttachToBuffer" },
- config = function()
- require("colorizer").setup({
- --'*';
- user_default_options = {
- RGB = true,
- RRGGBB = true,
- names = false,
- RRGGBBAA = false,
- css = false,
- css_fn = true,
- mode = "foreground",
- },
- })
- end,
- })
- use("MunifTanjim/nui.nvim")
- use({
- "j-hui/fidget.nvim",
- tag = "legacy",
- }) -- UI to show nvim-lsp progress
- use("metakirby5/codi.vim")
- use({
- "simrat39/symbols-outline.nvim", --
- config = function()
- require("symbols-outline").setup({
- auto_close = true,
- })
- end,
- })
- use({
- "kosayoda/nvim-lightbulb", --
- requires = "antoinemadec/FixCursorHold.nvim",
- })
- use({
- "SmiteshP/nvim-navic", -- Statusline/Winbar component that uses LSP to show current code context
- requires = "neovim/nvim-lspconfig",
- })
- use({
- "rebelot/heirline.nvim", -- Statusline that is highly configurable
- --requires = 'kyazdani42/nvim-web-devicons',
- --event = 'VimEnter',
- })
- use({
- "samodostal/image.nvim",
- config = function()
- require("image").setup({})
- end,
- })
- -- Language specific tools
- use("simrat39/rust-tools.nvim") -- Rust tooling ecosystem
- use({
- "saecki/crates.nvim", --
- requires = { "nvim-lua/plenary.nvim" },
- config = function()
- require("crates").setup()
- end,
- })
- use({
- "akinsho/flutter-tools.nvim",
- requires = {
- "nvim-lua/plenary.nvim",
- "stevearc/dressing.nvim", -- optional for vim.ui.select
- },
- config = function()
- require("flutter-tools").setup({
- debugger = {
- enabled = true,
- run_via_dap = true,
- },
- })
- end,
- })
- use({
- "iamcco/markdown-preview.nvim", -- Markdown Preview
- run = function()
- vim.fn["mkdp#util#install"]()
- end,
- vim.cmd("let g:mkdp_auto_close = 0"),
- })
- use({
- "ellisonleao/glow.nvim", -- Markdown Preview
- config = function()
- local glow_path
-
- -- Check if glow exists in ~/.local/bin
- if vim.fn.executable("~/.local/bin/glow") == 1 then
- glow_path = "~/.local/bin/glow"
- else
- -- Fallback to /usr/bin/glow
- glow_path = "/usr/bin/glow"
- end
-
- require("glow").setup({
- style = "dark",
- glow_path = glow_path,
- })
- end,
- })
- use({
- "lervag/vimtex",
- })
- use("micangl/cmp-vimtex")
-
- --------------------------------------------------
-
- -- Automatically set up your configuration after cloning packer.nvim
- -- Put this at the end after all plugins
- if PACKER_BOOTSTRAP then
- require("packer").sync()
- end
-end)
diff --git a/lua/user/view.lua b/lua/user/view.lua
index 837fce4..f243194 100644..100755
--- a/lua/user/view.lua
+++ b/lua/user/view.lua
@@ -1,69 +1,180 @@
--- Colorscheme
-
--- Colors
-vim.opt.termguicolors = true
-
--- Available colorschemes:
--- [[ nightfly ayu onedark doom-one nvimgelion github_dark tokyonight bamboo ]]
-
-require('tokyonight').setup({
- style = 'night',
- transparent = true,
- transparent_sidebar = true,
- dim_inactive = false,
- styles = {
- sidebars = 'transparent',
- floats = 'transparent',
- },
-})
-
--- Define default color scheme
-local default_colorscheme = 'tokyonight-night'
-local fallback_colorscheme = 'desert'
-
--- Attempt to set the default color scheme
-local status_ok, _ = pcall(vim.cmd, 'colorscheme ' .. default_colorscheme)
-
--- If the default color scheme is not found, use the fallback color scheme
-if not status_ok then
- vim.cmd('colorscheme ' .. fallback_colorscheme)
+-- ============================================================================
+-- View/UI
+-- ============================================================================
+
+local M = {}
+
+-- List of available themes (for reference or user selection UI)
+M.available_themes = {
+ "nightfly", "ayu", "onedark", "doom-one", "nvimgelion", "github_dark", "tokyonight", "bamboo", "oxocarbon"
+}
+
+-- Configuration
+local default_colorscheme = "tokyonight"
+local fallback_colorscheme = "default"
+
+-- Diagnostic icons
+local Signs = {
+ Error = "✘",
+ Warn = "",
+ Hint = "◉",
+ Info = "",
+}
+
+-- Setup Function
+function M.setup()
+ -- Truecolor & syntax
+ vim.opt.termguicolors = true
+ vim.cmd("syntax on")
+
+ -- Colorscheme setup with fallback
+ local ok = pcall(vim.cmd, "colorscheme " .. default_colorscheme)
+ if not ok then
+ vim.cmd("colorscheme " .. fallback_colorscheme)
+ end
+
+ -- Optional: Tokyonight configuration
+ pcall(function()
+ require("tokyonight").setup({
+ style = "night",
+ transparent = true,
+ transparent_sidebar = true,
+ dim_inactive = false,
+ styles = {
+ sidebars = "transparent",
+ floats = "transparent",
+ },
+ })
+ end)
+
+ -- Highlight groups
+ local highlights = {
+ -- Core UI
+ { group = "Normal", options = { bg = "none" } },
+ { group = "NormalNC", options = { bg = "none" } },
+ { group = "NormalFloat", options = { bg = "none" } },
+ { group = "Float", options = { bg = "none" } },
+ { group = "FloatBorder", options = { bg = "none", fg = "#7f8493" } },
+ { group = "StatusLine", options = { bg = "none" } },
+ { group = "TabLine", options = { bg = "#333842", bold = true } },
+ { group = "TabLineSel", options = { bg = "#333842", bold = true } },
+ { group = "TabLineFill", options = { bg = "none", bold = true } },
+ { group = "WinBar", options = { bg = "none", bold = true } },
+ { group = "WinBarNC", options = { bg = "none" } },
+ { group = "WinSeparator", options = { bg = "none", fg = "#444b62", bold = true } },
+ { group = "EndOfBuffer", options = { bg = "none", fg = "#7f8493" } },
+ { group = "NonText", options = { bg = "none", fg = "#555b71" } },
+ { group = "LineNr", options = { bg = "none", fg = "#555b71" } },
+ { group = "SignColumn", options = { bg = "none" } },
+ { group = "FoldColumn", options = { bg = "none" } },
+ { group = "CursorLine", options = { bg = "#3a3f52" } },
+ { group = "CursorLineNr", options = { bg = "#3a3f52", fg = "#cdd6f4" } },
+ { group = "CursorLineSign", options = { bg = "none" } },
+ { group = "Title", options = { bg = "none", bold = true } },
+ { group = "Comment", options = { bg = "none", fg = "#6b7089" } },
+ { group = "MsgSeparator", options = { bg = "none" } },
+ { group = "WarningMsg", options = { bg = "none", fg = "#e6c384" } },
+ { group = "MoreMsg", options = { bg = "none", fg = "#7f8493" } },
+
+ -- Pop-up / menu
+ { group = "Pmenu", options = { bg = "none" } },
+ { group = "PmenuSel", options = { fg = "black", bg = "white" } },
+ { group = "PmenuThumb", options = { bg = "none" } },
+ { group = "PmenuSbar", options = { bg = "none" } },
+ { group = "PmenuExtra", options = { bg = "none" } },
+ { group = "PmenuExtraSel", options = { bg = "none" } },
+ { group = "WildMenu", options = { link = "PmenuSel" } },
+
+ -- Telescope
+ { group = "TelescopeNormal", options = { bg = "none" } },
+ { group = "TelescopePromptNormal", options = { bg = "none" } },
+ { group = "TelescopeResultsNormal", options = { bg = "none" } },
+ { group = "TelescopePreviewNormal", options = { bg = "none" } },
+ { group = "TelescopeBorder", options = { bg = "none", fg = "#7f8493" } },
+ { group = "TelescopeMatching", options = { fg = "#cba6f7", bold = true } },
+
+ -- Blending
+ { group = "Winblend", options = { bg = "none" } },
+ { group = "Pumblend", options = { bg = "none" } },
+
+ ---- NvimTree
+ --{ group = "NvimTreeNormal", options = { bg = "none", fg = "NONE" } },
+ --{ group = "NvimTreeNormalNC", options = { bg = "none", fg = "NONE" } },
+ --{ group = "NvimTreeNormalFloat", options = { bg = "none" } },
+ --{ group = "NvimTreeEndOfBuffer", options = { bg = "none" } },
+ --{ group = "NvimTreeCursorLine", options = { bg = "#50fa7b", fg = "#000000" } },
+ --{ group = "NvimTreeSymlinkFolderName", options = { fg = "#f8f8f2", bg = "none" } },
+ --{ group = "NvimTreeFolderName", options = { fg = "#f8f8f2", bg = "none" } },
+ --{ group = "NvimTreeRootFolder", options = { fg = "#f8f8f2", bg = "none" } },
+ --{ group = "NvimTreeEmptyFolderName", options = { fg = "#f8f8f2", bg = "none" } },
+ --{ group = "NvimTreeOpenedFolderName", options = { fg = "#f8f8f2", bg = "none" } },
+ --{ group = "NvimTreeOpenedFile", options = { fg = "#50fa7b", bg = "none" } },
+ --{ group = "NvimTreeExecFile", options = { fg = "#ff882a", bg = "none" } },
+ }
+
+ for _, hl in ipairs(highlights) do
+ vim.api.nvim_set_hl(0, hl.group, hl.options)
+ end
+
+ -- Reapply highlights on ColorScheme change
+ vim.api.nvim_create_autocmd("ColorScheme", {
+ group = vim.api.nvim_create_augroup("CustomHighlights", { clear = true }),
+ pattern = "*",
+ callback = function()
+ for _, hl in ipairs(highlights) do
+ vim.api.nvim_set_hl(0, hl.group, hl.options)
+ end
+ end,
+ })
+
+ -- Optional window separator styling
+ vim.cmd([[
+ augroup CustomWinSeparator
+ autocmd!
+ autocmd WinEnter * setlocal winhl=WinSeparator:WinSeparatorA
+ autocmd WinLeave * setlocal winhl=WinSeparator:WinSeparator
+ augroup END
+ ]])
+
+ -- Diagnostics configuration
+ local border = "rounded"
+ vim.diagnostic.config({
+ signs = {
+ text = {
+ [vim.diagnostic.severity.ERROR] = Signs.Error,
+ [vim.diagnostic.severity.WARN] = Signs.Warn,
+ [vim.diagnostic.severity.HINT] = Signs.Hint,
+ [vim.diagnostic.severity.INFO] = Signs.Info,
+ },
+ },
+ underline = true,
+ virtual_text = false,
+ virtual_lines = false,
+ float = {
+ show_header = true,
+ source = "always",
+ border = border,
+ focusable = true,
+ },
+ update_in_insert = false,
+ severity_sort = true,
+ })
+
+ -- Fallback statusline if heirline is missing
+ local heirline_ok, _ = pcall(require, "heirline")
+ if not heirline_ok then
+ local statusline_path = vim.fn.stdpath("config") .. "/autoload/statusline.vim"
+ if vim.fn.filereadable(statusline_path) == 1 then
+ vim.cmd.source(statusline_path)
+ vim.api.nvim_create_autocmd("VimEnter", {
+ callback = function()
+ vim.cmd("call autoload#statusline#ActivateStatusline()")
+ end,
+ })
+ else
+ vim.notify("Fallback statusline script not found:\n" .. statusline_path, vim.log.levels.ERROR)
+ end
+ end
end
-vim.api.nvim_command('syntax on')
-vim.api.nvim_command('highlight Normal guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight NormalNC guibg=NONE')
-vim.api.nvim_command('highlight NormalFloat guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight Float guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight NonText guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight SignColumn guibg=NONE')
-vim.api.nvim_command('highlight FoldColumn guibg=NONE')
-vim.api.nvim_command('highlight CursorLineSign guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight Title guibg=NONE gui=bold')
-vim.api.nvim_command('highlight TabLine guibg=#333842 gui=bold')
-vim.api.nvim_command('highlight TabLineSel guibg=#333842 gui=bold')
-vim.api.nvim_command('highlight TabLineFill guibg=NONE gui=bold')
-vim.api.nvim_command('highlight WinBar guibg=NONE ctermbg=NONE gui=bold')
-vim.api.nvim_command('highlight WinBarNC guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight LineNr guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight WinSeparator guibg=NONE gui=bold ctermbg=NONE')
-vim.api.nvim_command('highlight MsgSeparator guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight EndOfBuffer guibg=NONE guifg=Normal')
-vim.api.nvim_command('highlight Comment guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight Winblend guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight NormalFloat guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight Pumblend guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight WildMenu guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight WarningMsg guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight Pmenu guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight PmenuSel guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight PmenuThumb guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight PmenuSbar guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight PmenuExtra guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight PmenuExtraSel guibg=NONE ctermbg=NONE')
-vim.api.nvim_command('highlight MoreMsg guibg=NONE ctermbg=NONE')
-
--- Set different window separator colorscheme
-vim.cmd([[
-au WinEnter * setl winhl=WinSeparator:WinSeparatorA
-au WinLeave * setl winhl=WinSeparator:WinSeparator
-]])
+return M