diff options
Diffstat (limited to 'lua/user')
| -rwxr-xr-x[-rw-r--r--] | lua/user/keys.lua | 752 | ||||
| -rwxr-xr-x[-rw-r--r--] | lua/user/mods.lua | 634 | ||||
| -rwxr-xr-x[-rw-r--r--] | lua/user/opts.lua | 341 | ||||
| -rw-r--r-- | lua/user/pack.lua | 403 | ||||
| -rwxr-xr-x[-rw-r--r--] | lua/user/view.lua | 245 |
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 |
