diff --git a/init.lua b/init.lua index de6b89c..445486b 100644 --- a/init.lua +++ b/init.lua @@ -1,6 +1,5 @@ --- load config -require('config.options') -require('config.keys') -require('config.autocmd') -require('config.lazy') -require('config.lsp') +require("pack_helper") +require("keys") +require("options") +require("autocmd") +require('lsp') diff --git a/lazy-lock.json b/lazy-lock.json deleted file mode 100644 index 46f3862..0000000 --- a/lazy-lock.json +++ /dev/null @@ -1,48 +0,0 @@ -{ - "Comment.nvim": { "branch": "master", "commit": "e30b7f2008e52442154b66f7c519bfd2f1e32acb" }, - "LuaSnip": { "branch": "master", "commit": "642b0c595e11608b4c18219e93b88d7637af27bc" }, - "Navigator.nvim": { "branch": "master", "commit": "91d86506ac2a039504d5205d32a1d4bc7aa57072" }, - "bento.nvim": { "branch": "main", "commit": "aee8a542bc1839ff1764992ef2aa41c981d0bba4" }, - "better-escape.nvim": { "branch": "master", "commit": "3f4bc0b326606264ff75967f59091b5ddada0554" }, - "blink.cmp": { "branch": "main", "commit": "78336bc89ee5365633bcf754d93df01678b5c08f" }, - "codesnap.nvim": { "branch": "main", "commit": "0a0941340376439a25d6cd8a4d1d2b372edbfdbd" }, - "conform.nvim": { "branch": "master", "commit": "dca1a190aa85f9065979ef35802fb77131911106" }, - "friendly-snippets": { "branch": "main", "commit": "6cd7280adead7f586db6fccbd15d2cac7e2188b9" }, - "gitignore.nvim": { "branch": "master", "commit": "0344f643768c4d64af4add8c1bdddf6f7d4c9010" }, - "gitsigns.nvim": { "branch": "main", "commit": "6d808f99bd63303646794406e270bd553ad7792e" }, - "gruvbox.nvim": { "branch": "main", "commit": "154eb5ff5b96d0641307113fa385eaf0d36d9796" }, - "hardtime.nvim": { "branch": "main", "commit": "b4e431934af1fe224a3a801f632c008278cb7628" }, - "lazy.nvim": { "branch": "main", "commit": "306a05526ada86a7b30af95c5cc81ffba93fef97" }, - "lazygit.nvim": { "branch": "main", "commit": "a04ad0dbc725134edbee3a5eea29290976695357" }, - "lspsaga.nvim": { "branch": "main", "commit": "c532fb86c3d211c5829ad58d2a0783012739bb65" }, - "markdown-preview.nvim": { "branch": "master", "commit": "a923f5fc5ba36a3b17e289dc35dc17f66d0548ee" }, - "markview.nvim": { "branch": "main", "commit": "86cf4bcede58e88497f7e5214efb281d4a6f633d" }, - "mason-conform.nvim": { "branch": "main", "commit": "48da2ebd5efbaf8a99566eadc3ece82d523f03c5" }, - "mason-lspconfig.nvim": { "branch": "main", "commit": "0c2823e0418f3d9230ff8b201c976e84de1cb401" }, - "mason-nvim-lint": { "branch": "main", "commit": "cafbc5d82d8eb4af0daf0057332a325ddf2f436b" }, - "mason.nvim": { "branch": "main", "commit": "12ddd182d9efbdc848b540f16484a583d52da0fb" }, - "mdx.nvim": { "branch": "main", "commit": "6c3dc7c4a4b58b5d86404c21a9b4655282ca08c5" }, - "mini.nvim": { "branch": "main", "commit": "be81509b7160aa02264a59789164a2e1c4a6750a" }, - "neogen": { "branch": "main", "commit": "23e7e9f883d01289ebd90e98025acc860ea26366" }, - "neoscroll.nvim": { "branch": "master", "commit": "c8d29979cb0cb3a2437a8e0ae683fd82f340d3b8" }, - "nvim-autopairs": { "branch": "master", "commit": "59bce2eef357189c3305e25bc6dd2d138c1683f5" }, - "nvim-genghis": { "branch": "main", "commit": "12d62b0aaeb0bf6e52f2335d532813a8b8105baa" }, - "nvim-lint": { "branch": "master", "commit": "eab58b48eb11d7745c11c505e0f3057165902461" }, - "nvim-lspconfig": { "branch": "master", "commit": "8fde495949782bb61c2605174e231d145a048d8c" }, - "nvim-treesitter": { "branch": "main", "commit": "4916d6592ede8c07973490d9322f187e07dfefac" }, - "nvim-ts-autotag": { "branch": "main", "commit": "88c1453db4ba7dd24131086fe51fdf74e587d275" }, - "nvim-ts-context-commentstring": { "branch": "main", "commit": "6141a40173c6efa98242dc951ed4b6f892c97027" }, - "nvim-ufo": { "branch": "main", "commit": "ab3eb124062422d276fae49e0dd63b3ad1062cfc" }, - "promise-async": { "branch": "main", "commit": "119e8961014c9bfaf1487bf3c2a393d254f337e2" }, - "smartcolumn.nvim": { "branch": "main", "commit": "b9cdbdf42f7ac5a659204cd5926017c7ff724a19" }, - "snacks.nvim": { "branch": "main", "commit": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e" }, - "tiny-code-action.nvim": { "branch": "main", "commit": "0d040ed81f7953118b81cd12681fcdfcac069803" }, - "tiny-inline-diagnostic.nvim": { "branch": "main", "commit": "147af4e49f51dd48f41972de26552872b8ba7b25" }, - "todo-comments.nvim": { "branch": "main", "commit": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668" }, - "toggleterm.nvim": { "branch": "main", "commit": "50ea089fc548917cc3cc16b46a8211833b9e3c7c" }, - "vim-suda": { "branch": "master", "commit": "c492741b4679b3cdd4d9e34138209784e061d916" }, - "vim-visual-multi": { "branch": "master", "commit": "a6975e7c1ee157615bbc80fc25e4392f71c344d4" }, - "vim-wakatime": { "branch": "master", "commit": "8217dfb5a5a3ad3a509365d8a39d7daca12b1745" }, - "which-key.nvim": { "branch": "main", "commit": "3aab2147e74890957785941f0c1ad87d0a44c15a" }, - "windsurf.vim": { "branch": "main", "commit": "3c0a4f8a7be75113a6e19be13b7cc37210d6e26a" } -} diff --git a/lua/autocmd.lua b/lua/autocmd.lua new file mode 100644 index 0000000..9ca9bba --- /dev/null +++ b/lua/autocmd.lua @@ -0,0 +1,194 @@ +local function augroup(name) + return vim.api.nvim_create_augroup("nvim_" .. name, { clear = true }) +end + +-- ----------------------------------------------------------------------------- +-- General UI & Behavior +-- ----------------------------------------------------------------------------- + +-- Secure .env Masking (Conceal method) +local function toggle_env_mask() + local buf = vim.api.nvim_get_current_buf() + if vim.wo.conceallevel > 0 then + vim.wo.conceallevel = 0 + vim.notify("Env masking disabled", vim.log.levels.INFO, { title = "Security" }) + else + vim.wo.conceallevel = 2 + vim.wo.concealcursor = "n" -- Show when editing (insert mode) + vim.notify("Env masking enabled", vim.log.levels.INFO, { title = "Security" }) + end +end + +-- Auto-mask .env files on load +vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile" }, { + group = augroup("env_masking"), + pattern = { ".env", ".env.*", "*.env" }, + callback = function() + vim.opt_local.conceallevel = 2 + vim.opt_local.concealcursor = "n" + -- Match everything after '=' (only if not empty) and conceal it with '*' + vim.fn.matchadd("Conceal", [[=\zs.\+]], 10, -1, { conceal = "*" }) + end, +}) + +vim.keymap.set("n", "ot", toggle_env_mask, { desc = "Toggle .env masking" }) + + +-- Strip trailing spaces before write +vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup("strip_space"), + pattern = "*", + callback = function() + local save = vim.fn.winsaveview() + vim.cmd([[keeppatterns %s/\s\+$//e]]) + vim.fn.winrestview(save) + end, +}) + +-- Highlight on yank +vim.api.nvim_create_autocmd("TextYankPost", { + group = augroup("highlight_yank"), + callback = function() + vim.highlight.on_yank({ timeout = 200 }) + end, +}) + +-- Resize splits if window got resized +vim.api.nvim_create_autocmd("VimResized", { + group = augroup("resize_splits"), + callback = function() + vim.cmd("tabdo wincmd =") + end, +}) + +-- Go to last location when opening a buffer +vim.api.nvim_create_autocmd("BufReadPost", { + group = augroup("last_loc"), + callback = function() + local mark = vim.api.nvim_buf_get_mark(0, '"') + local lcount = vim.api.nvim_buf_line_count(0) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +-- Close specific filetypes with +vim.api.nvim_create_autocmd("FileType", { + group = augroup("close_with_q"), + pattern = { + "help", "lspinfo", "man", "notify", "qf", "query", "spectre_panel", + "startuptime", "tsplayground", "neotest-output", "checkhealth", + }, + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.keymap.set("n", "q", "close", { buffer = event.buf, silent = true }) + end, +}) + +-- Auto-create directories on save +vim.api.nvim_create_autocmd("BufWritePre", { + group = augroup("auto_create_dir"), + callback = function(event) + if event.match:match("^%w%w+://") then + return + end + local file = vim.loop.fs_realpath(event.match) or event.match + vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p") + end, +}) + +-- ----------------------------------------------------------------------------- +-- LSP Related +-- ----------------------------------------------------------------------------- + +-- Document Highlight on CursorHold +vim.api.nvim_create_autocmd("LspAttach", { + group = augroup("lsp_attach_autocmds"), + callback = function(args) + local client = vim.lsp.get_client_by_id(args.data.client_id) + if client and client.supports_method("textDocument/documentHighlight") then + vim.api.nvim_create_autocmd({ "CursorHold", "CursorHoldI" }, { + buffer = args.buf, + callback = vim.lsp.buf.document_highlight, + }) + vim.api.nvim_create_autocmd({ "CursorMoved", "CursorMovedI" }, { + buffer = args.buf, + callback = vim.lsp.buf.clear_references, + }) + end + end, +}) + +-- ----------------------------------------------------------------------------- +-- Filetype Specific +-- ----------------------------------------------------------------------------- + +-- Wrap and spellcheck in text filetypes +vim.api.nvim_create_autocmd("FileType", { + group = augroup("wrap_spell"), + pattern = { "gitcommit", "markdown", "text" }, + callback = function() + vim.opt_local.wrap = true + vim.opt_local.spell = true + end, +}) + +-- Disable auto-commenting on new lines +vim.api.nvim_create_autocmd("FileType", { + group = augroup("no_auto_comment"), + callback = function() + vim.opt_local.formatoptions:remove({ "c", "r", "o" }) + end, +}) + + +-- Manual Treesitter Installation command +vim.api.nvim_create_user_command("TSInstallAll", function() + local parsers = require("extensions").ts_parsers + vim.notify("Installing all configured Tree-sitter parsers...", vim.log.levels.INFO, { title = "Tree-sitter" }) + require("nvim-treesitter.install").install(parsers) +end, { desc = "Install all configured Tree-sitter parsers" }) + +-- ----------------------------------------------------------------------------- +-- Macro Notifications +-- ----------------------------------------------------------------------------- + +vim.api.nvim_create_autocmd("RecordingEnter", { + callback = function() + vim.notify("Recording macro...", vim.log.levels.INFO, { title = "Macro", timeout = 1000 }) + end, +}) + +vim.api.nvim_create_autocmd("RecordingLeave", { + callback = function() + local reg = vim.v.recording + vim.notify("Stopped recording @" .. reg, vim.log.levels.INFO, { title = "Macro", timeout = 1000 }) + end, +}) + +-- ----------------------------------------------------------------------------- +-- Auto-Save (3s Debounce) +-- ----------------------------------------------------------------------------- + +local save_timer = nil +vim.api.nvim_create_autocmd({ "TextChanged", "InsertLeave", "BufLeave", "FocusLost" }, { + group = augroup("autosave"), + callback = function(args) + if not vim.bo[args.buf].modified or vim.bo[args.buf].buftype ~= "" then + return + end + if save_timer then + save_timer:stop() + end + + local delay = (args.event == "BufLeave" or args.event == "FocusLost") and 0 or 3000 + save_timer = vim.defer_fn(function() + if vim.api.nvim_buf_is_valid(args.buf) and vim.bo[args.buf].modified then + vim.api.nvim_buf_call(args.buf, function() + vim.cmd("silent! write") + end) + end + end, delay) + end, +}) diff --git a/lua/config/autocmd.lua b/lua/config/autocmd.lua deleted file mode 100644 index a36092c..0000000 --- a/lua/config/autocmd.lua +++ /dev/null @@ -1,325 +0,0 @@ -local function augroup(name) - return vim.api.nvim_create_augroup('nvim' .. name, { clear = true }) -end - --- hide sensetive data in .env --- local group = vim.api.nvim_create_augroup('EnvMask', { clear = true }) --- local hidden = {} --- --- local function mask_line(line) --- if line:match('^%s*#') or line:match('^%s*$') then --- return line --- end --- --- local key, value = line:match('^([%w_]+)%s*=%s*(.*)') --- if not key or not value then --- return line --- end --- --- return key .. '=' .. string.rep('*', #value) --- end --- --- local function hide(buf) --- if hidden[buf] then --- return --- end --- --- local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) --- hidden[buf] = lines --- --- local masked = {} --- for i, line in ipairs(lines) do --- masked[i] = mask_line(line) --- end --- --- vim.api.nvim_buf_set_lines(buf, 0, -1, false, masked) --- end --- --- local function show(buf) --- if not hidden[buf] then --- return --- end --- vim.api.nvim_buf_set_lines(buf, 0, -1, false, hidden[buf]) --- hidden[buf] = nil --- end --- --- vim.api.nvim_create_autocmd('BufReadPost', { --- group = group, --- pattern = { '.env', '.env.*', '*.env' }, --- callback = function(args) --- vim.cmd('silent! noautocmd redraw') --- hide(args.buf) --- end, --- }) --- --- vim.keymap.set('n', 'ot', function() --- local buf = vim.api.nvim_get_current_buf() --- if hidden[buf] then --- show(buf) --- else --- hide(buf) --- end --- end, { desc = 'Toggle env masking' }) - --- Strip trailing spaces before write -vim.api.nvim_create_autocmd({ 'BufWritePre' }, { - group = augroup('strip_space'), - pattern = { '*' }, - callback = function() - vim.cmd([[ %s/\s\+$//e ]]) - end, -}) - --- Check if we need to reload the file when it changed -vim.api.nvim_create_autocmd({ 'FocusGained', 'TermClose', 'TermLeave' }, { - group = augroup('checktime'), - command = 'checktime', -}) - --- Highlight on yank -vim.api.nvim_create_autocmd('TextYankPost', { - group = augroup('highlight_yank'), - callback = function() - vim.highlight.on_yank({ timeout = 200, visual = true }) - end, -}) - --- resize splits if window got resized -vim.api.nvim_create_autocmd({ 'VimResized' }, { - group = augroup('resize_splits'), - callback = function() - vim.cmd('tabdo wincmd =') - end, -}) - --- go to last loc when opening a buffer --- vim.api.nvim_create_autocmd('BufReadPost', { --- group = augroup('last_loc'), --- callback = function() --- local mark = vim.api.nvim_buf_get_mark(0, '"') --- local lcount = vim.api.nvim_buf_line_count(0) --- if mark[1] > 0 and mark[1] <= lcount then --- pcall(vim.api.nvim_win_set_cursor, 0, mark) --- end --- end, --- }) - --- restore cursor to file position in previous editing session --- vim.api.nvim_create_autocmd('BufReadPost', { --- callback = function(args) --- local mark = vim.api.nvim_buf_get_mark(args.buf, '"') --- local line_count = vim.api.nvim_buf_line_count(args.buf) --- if mark[1] > 0 and mark[1] <= line_count then --- vim.api.nvim_win_set_cursor(0, mark) --- -- defer centering slightly so it's applied after render --- vim.schedule(function() --- vim.cmd('normal! zz') --- end) --- end --- end, --- }) - --- open help in vertical split -vim.api.nvim_create_autocmd('FileType', { - pattern = 'help', - command = 'wincmd L', -}) - --- no auto continue comments on new line -vim.api.nvim_create_autocmd('FileType', { - group = vim.api.nvim_create_augroup('no_auto_comment', {}), - callback = function() - vim.opt_local.formatoptions:remove({ 'c', 'r', 'o' }) - end, -}) - --- show cursorline only in active window enable -vim.api.nvim_create_autocmd({ 'WinEnter', 'BufEnter' }, { - group = vim.api.nvim_create_augroup('active_cursorline', { clear = true }), - callback = function() - vim.opt_local.cursorline = true - end, -}) - --- show cursorline only in active window disable -vim.api.nvim_create_autocmd({ 'WinLeave', 'BufLeave' }, { - group = 'active_cursorline', - callback = function() - vim.opt_local.cursorline = false - end, -}) - --- ide like highlight when stopping cursor -vim.api.nvim_create_autocmd('CursorMoved', { - group = vim.api.nvim_create_augroup('LspReferenceHighlight', { clear = true }), - desc = 'Highlight references under cursor', - callback = function() - -- Only run if the cursor is not in insert mode - if vim.fn.mode() ~= 'i' then - local clients = vim.lsp.get_clients({ bufnr = 0 }) - local supports_highlight = false - for _, client in ipairs(clients) do - if client.server_capabilities.documentHighlightProvider then - supports_highlight = true - break -- Found a supporting client, no need to check others - end - end - - -- 3. Proceed only if an LSP is active AND supports the feature - if supports_highlight then - vim.lsp.buf.clear_references() - vim.lsp.buf.document_highlight() - end - end - end, -}) - --- ide like highlight when stopping cursor -vim.api.nvim_create_autocmd('CursorMovedI', { - group = 'LspReferenceHighlight', - desc = 'Clear highlights when entering insert mode', - callback = function() - vim.lsp.buf.clear_references() - end, -}) - --- close some filetypes with -vim.api.nvim_create_autocmd('FileType', { - group = augroup('close_with_q'), - pattern = { - 'Jaq', - 'PlenaryTestPopup', - 'Avante', - 'AvanteInput', - 'AvanteSelectedFiles', - 'fugitive', - 'git', - 'help', - 'lir', - 'lspinfo', - 'man', - 'netrw', - 'notify', - 'qf', - 'spectre_panel', - 'startuptime', - 'tsplayground', - }, - callback = function(event) - vim.bo[event.buf].buflisted = false - vim.keymap.set('n', 'q', 'close', { buffer = event.buf, silent = true }) - end, -}) - --- wrap and check for spell in text filetypes -vim.api.nvim_create_autocmd('FileType', { - group = augroup('wrap_spell'), - pattern = { 'gitcommit', 'markdown' }, - callback = function() - vim.opt_local.wrap = true - vim.opt_local.spell = true - end, -}) - --- Auto create dir when saving a file, in case some intermediate directory does not exist -vim.api.nvim_create_autocmd({ 'BufWritePre' }, { - group = augroup('auto_create_dir'), - callback = function(event) - local file = vim.loop.fs_realpath(event.match) or event.match - vim.fn.mkdir(vim.fn.fnamemodify(file, ':p:h'), 'p') - end, -}) - --- Set arb filetype -vim.api.nvim_create_autocmd({ 'BufEnter' }, { - group = augroup('set_file_type'), - pattern = { '*.arb' }, - command = 'setfiletype arb', -}) - --- Disable format options -vim.api.nvim_create_autocmd('FileType', { - group = augroup('disable_formatoptions'), - pattern = '*', - callback = function() - vim.opt_local.formatoptions:remove({ 'c', 'r', 'o' }) - end, -}) - -local function enable_autoformat() - vim.api.nvim_create_autocmd({ 'BufWritePre' }, { - group = augroup('autoformat'), - pattern = { '*' }, - callback = function() - vim.lsp.buf.format() - end, - }) -end - -enable_autoformat() - -vim.api.nvim_create_user_command('WriteNoFormat', function() - -- Temporarily disable the autoformat autocmd - vim.api.nvim_del_augroup_by_name('keycodex_autoformat') - vim.cmd('write') - -- Re-enable the autoformat autocmd - enable_autoformat() -end, {}) - --- Macro recording notifications -vim.api.nvim_create_autocmd('RecordingEnter', { - callback = function() - vim.notify('Macro recording started', vim.log.levels.INFO, { - title = 'Macro', - timeout = 2000, - }) - -- Print to command line for debugging - vim.cmd("echo 'Recording macro...'") - end, -}) - -vim.api.nvim_create_autocmd('RecordingLeave', { - callback = function() - vim.notify('Macro recording stopped', vim.log.levels.INFO, { - title = 'Macro', - timeout = 2000, - }) - -- Print to command line for debugging - vim.cmd("echo 'Macro recording stopped'") - end, -}) - --- Function to show macro replay notification -local function show_macro_replay(count) - local message = count > 1 and string.format('Replaying macro %d times', count) or 'Replaying macro' - vim.notify(message, vim.log.levels.INFO, { - title = 'Macro', - timeout = 2000, - }) -end - --- Function to clear all macros -local function clear_all_macros() - -- Clear all registers from a to z - for i = 97, 122 do -- ASCII values for 'a' to 'z' - vim.fn.setreg(string.char(i), '') - end - -- Clear all registers from 0 to 9 - for i = 48, 57 do -- ASCII values for '0' to '9' - vim.fn.setreg(string.char(i), '') - end - vim.notify('All macros cleared', vim.log.levels.INFO, { - title = 'Macro', - timeout = 2000, - }) -end - --- Create keymaps for macro replay with notifications -vim.keymap.set('n', '@', function() - local count = vim.v.count1 - show_macro_replay(count) - return '@' -end, { expr = true }) - --- Add keybinding to clear all macros -vim.keymap.set('n', 'oc', clear_all_macros, { desc = 'Clear all macros' }) diff --git a/lua/config/extensions.lua b/lua/config/extensions.lua deleted file mode 100644 index abb815d..0000000 --- a/lua/config/extensions.lua +++ /dev/null @@ -1,66 +0,0 @@ -local treesitter_parsers = { - "c", - "markdown", - "python", - "java", - "cpp", - "bash", - "lua", - "make", - "json", - "jsonc", - "sql", - "yaml", - "toml", - "javascript", - "typescript", - "gitignore", - "go", - "rust", - "html", - "css", - "scss", - "markdown_inline", -} - -local lsp_server = { - "ts_ls", - "html", - "cssls", - "tailwindcss", - "lua_ls", - "basedpyright", - "bashls", - "clangd", - "rust_analyzer", -} - -local formatter = { - "clang_format", - "ruff", - "stylua", - "prettier", - "markdown-toc", - "markdownlint-cli2", - "biome", -} - -local linter = { - "eslint_d", - "hadolint", - "write_good", - "markdownlint", - "shellcheck", - "actionlint", - "djlint", - "ruff", - "codespell", - "cspell", -} - -return { - ts_parsers = treesitter_parsers, - lsp_server = lsp_server, - formatter = formatter, - linter = linter, -} diff --git a/lua/config/keys.lua b/lua/config/keys.lua deleted file mode 100644 index 1f185cc..0000000 --- a/lua/config/keys.lua +++ /dev/null @@ -1,143 +0,0 @@ -local function map(mode, lhs, rhs, opts) - opts = opts or {} - opts.silent = opts.silent ~= false - vim.keymap.set(mode, lhs, rhs, opts) -end -local opts = { noremap = true, silent = true } - --- Space as leader -map('n', '', '', opts) -vim.g.mapleader = ' ' -vim.g.maplocalleader = ' ' - --- Modes --- normal_mode = "n", insert_mode = "i", visual_mode = "v", --- visual_block_mode = "x", term_mode = "t", command_mode = "c", - --- Terminal Mappings -map('t', 'jk', '') -map('t', 'kj', '') -map('t', '', '') - --- Clear search, diff update and redraw -map({ 'i', 'n' }, '', 'noh', { desc = 'Escape and clear hlsearch' }) - -map({ 'i', 'c' }, '', '') -map({ 'i', 'c' }, '', '') - -map('n', 'rL', vim.lsp.buf.rename, { desc = 'Rename Lsp Symbol' }) -map('n', '`', "'", { noremap = true }) -- better marks - -map({ 'n', 'v' }, 'H', '^', { desc = 'Move to the beginning of the line' }) -map({ 'n', 'v' }, 'L', '$', { desc = 'Move to the end of the line' }) - --- Visual overwrite paste -map({ 'v', 'x' }, 'p', '"_dP', opts) - --- Do not copy on x -map({ 'v', 'x' }, 'x', '"_x', opts) -map('n', 'X', '"_D', opts) -map('n', 'dd', '"_dd', opts) -map({ 'v', 'x' }, 'X', '"_d', opts) - --- Select all - --- Select all -map('n', 'a', 'ggVG', { desc = 'Select all' }) -map('n', '', 'ggVG', { desc = 'Select all' }) -map('i', '', 'ggVG', { desc = 'Select all' }) - --- Move text up and down -map({ 'v', 'x' }, 'K', ":move '<-2gv-gv", opts) -map({ 'v', 'x' }, 'J', ":move '>+1gv-gv", opts) - --- Line operations -map('n', '', ':m .-2==', { desc = 'Move line up' }) -map('n', '', ':m .+1==', { desc = 'Move line down' }) -map('i', '', ':m .-2==gi', { desc = 'Move line up' }) -map('i', '', ':m .+1==gi', { desc = 'Move line down' }) -map('v', '', ":m '<-2gv=gv", { desc = 'Move selection up' }) -map('v', '', ":m '>+1gv=gv", { desc = 'Move selection down' }) - --- Line manipulation -map('n', '', '>>', { desc = 'Indent line' }) -map('n', '', '<<', { desc = 'Unindent line' }) -map('i', '', '>>', { desc = 'Indent line' }) -map('i', '', '<<', { desc = 'Unindent line' }) - --- Quick word operations -map('n', '', 'db', { desc = 'Delete word backward' }) -map('i', '', '', { desc = 'Delete word backward' }) -map('n', '', 'dw', { desc = 'Delete word forward' }) -map('i', '', 'dw', { desc = 'Delete word forward' }) - -map('n', 'd', '"_d', { desc = 'Delete without replacing clipboard' }) -map('n', 'x', '"_x', { desc = 'Cut without replacing clipboard' }) -map('n', 'c', '"_c', { desc = 'Change without replacing clipboard' }) -map('v', 'p', '"_dP', { desc = 'Paste without replacing clipboard' }) - ---insert the following characters around the visual selection -map('v', '(', 's()Pll', { desc = 'wrap selection with parens' }) -map('v', '[', 's[]Pll', { desc = 'wrap selection with square braces' }) -map('v', '{', 's{}Pll', { desc = 'wrap selection with curly braces' }) -map('v', "'", "s''Pll", { desc = 'wrap selection with single quotes' }) -map('v', '"', 's""Pll', { desc = 'wrap selection with double quotes' }) - --- Insert mode cursor movement with Ctrl+hjkl -map({ 'i', 'c' }, '', '', { noremap = true, silent = true }) -map({ 'i', 'c' }, '', '', { noremap = true, silent = true }) -map({ 'i', 'c' }, '', '', { noremap = true, silent = true }) -map({ 'i', 'c' }, '', '', { noremap = true, silent = true }) - -map('n', 're', ':%s//', { desc = 'Shortcut to replace current word under cursor' }) - --- toggle inlay hints -vim.keymap.set('n', 'th', function() - vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) -end) - --- No arrow navigation -local modes = { 'n', 'v', 'i' } -local arrows = { '', '', '', '' } - -for _, mode in ipairs(modes) do - for _, key in ipairs(arrows) do - vim.api.nvim_set_keymap(mode, key, '', opts) - end -end - --- Go to Beginning or End of line -map({ 'n', 'v' }, 'H', '_^', { desc = 'Move to the beginning of the line' }) -map({ 'n', 'v' }, 'L', '$', { desc = 'Move to the end of the line' }) - --- Search inside visually highlighted text. -map('x', 'g/', '/\\%V', { silent = false, desc = 'Search inside visual selection' }) - --- Search & replace in current file/line -map('v', 'rw', '"9y:%s@9@9@g', { desc = 'Search & replace selection', silent = false }) -map('n', 'rw', 'viw"9y:%s@9@9@g', { desc = 'Search & replace word', silent = false }) -map( - 'v', - 'rl', - '"9y:s@9@9@g', - { desc = 'Search & replace in current line', silent = false } -) -map( - 'n', - 'rl', - 'viw"9y:s@9@9@g', - { desc = 'Search & replace word in current line', silent = false } -) - --- Folds -map('n', '<', function() - if not vim.opt.foldmethod then - vim.opt.foldmethod = 'indent' - end - vim.cmd('normal! zM') -end, { desc = 'Fold all' }) - -map('n', '>', function() - vim.opt.foldenable = false - vim.cmd('normal! zR') -end, { desc = 'Open all folds' }) diff --git a/lua/config/lazy.lua b/lua/config/lazy.lua deleted file mode 100644 index 2d6e473..0000000 --- a/lua/config/lazy.lua +++ /dev/null @@ -1,48 +0,0 @@ --------------------------------------------------------------------------------- --- Bootstrap lazy plugin manager --------------------------------------------------------------------------------- -local lazypath = vim.fn.stdpath('data') .. '/lazy/lazy.nvim' -if not (vim.uv or vim.loop).fs_stat(lazypath) then - local lazyrepo = 'https://github.com/folke/lazy.nvim.git' - local out = vim.fn.system({ 'git', 'clone', '--filter=blob:none', '--branch=stable', lazyrepo, lazypath }) - if vim.v.shell_error ~= 0 then - vim.api.nvim_echo({ - { 'Failed to clone lazy.nvim:\n', 'ErrorMsg' }, - { out, 'WarningMsg' }, - { '\nPress any key to exit...' }, - }, true, {}) - vim.fn.getchar() - os.exit(1) - end -end -vim.opt.rtp:prepend(lazypath) - --- lazy config -require('lazy').setup({ - spec = { - { import = 'plugins' }, - }, - install = { - missing = true, - colorscheme = { 'gruvbox' }, - }, - change_detection = { - enable = true, - notify = false, - }, - ui = { - border = 'rounded', - backdrop = 100, - }, - rtp = { - -- disable some rtp plugins - disabled_plugins = { - 'gzip', - 'tarPlugin', - 'tohtml', - 'tutor', - 'netrwPlugin', - 'zipPlugin', - }, - }, -}) diff --git a/lua/config/lsp.lua b/lua/config/lsp.lua deleted file mode 100644 index 31cac1b..0000000 --- a/lua/config/lsp.lua +++ /dev/null @@ -1,100 +0,0 @@ --------------------------------------------------------------------------------- --- LSP --------------------------------------------------------------------------------- - --- ts_ls -vim.lsp.config("ts_ls", { - settings = { - typescript = { - inlayHints = { - includeInlayParameterNameHints = "all", - includeInlayParameterNameHintsWhenArgumentMatchesName = false, - includeInlayFunctionParameterTypeHints = true, - includeInlayVariableTypeHints = true, - includeInlayPropertyDeclarationTypeHints = true, - includeInlayFunctionLikeReturnTypeHints = true, - includeInlayEnumMemberValueHints = true, - }, - }, - }, -}) -vim.lsp.enable("ts_ls") - -vim.lsp.enable("html") -vim.lsp.enable("cssls") -vim.lsp.enable("tailwindcss") - --- rust -vim.lsp.config("rust_analyzer", { - settings = { - ["rust-analyzer"] = { - diagnostics = { - enable = true, - experimental = { enable = true }, - }, - }, - }, -}) -vim.lsp.enable("rust_analyzer") - --- lua -vim.lsp.config("lua_ls", { - settings = { - Lua = { - diagnostics = { - disable = { - "missing-fields", - "undefined-global", - }, - }, - }, - }, -}) -vim.lsp.enable("lua_ls") - --- python -vim.lsp.config("basedpyright", { - settings = { - basedpyright = { - inlayHints = true, - analysis = { - diagnosticSeverityOverrides = { - reportUnusedImport = "none", - reportUnusedVariable = "none", - reportAttributeAccessIssue = "none", - reportUnusedClass = "none", - reportUnusedFunction = "none", - reportDuplicateImport = "none", - reportArgumentType = "error", - }, - typeCheckingMode = "standard", - }, - }, - }, -}) -vim.lsp.enable("basedpyright") - - - --- bash -vim.lsp.config("bashls", { - settings = { - bashIde = { - shellcheckArguments = { - "--exclude=SC1090,SC1091,SC2076,SC2164", - }, - }, - }, -}) -vim.lsp.enable("bashls") - --- cpp -vim.lsp.config("clangd", { - cmd = { - "clangd", - "--fallback-style=llvm", - "--header-insertion=iwyu", - "-j=4", - }, -}) -vim.lsp.enable("clangd") diff --git a/lua/config/options.lua b/lua/config/options.lua deleted file mode 100644 index c333208..0000000 --- a/lua/config/options.lua +++ /dev/null @@ -1,67 +0,0 @@ -local options = { - ai = true, - clipboard = 'unnamedplus', -- use system clipboard - number = true, - relativenumber = true, - undofile = true, -- save state of file on write - undodir = vim.fn.stdpath('cache') .. '/undo', - undolevels = 10000, - autoread = true, -- autoread changes from other sources - signcolumn = 'yes', - cursorline = true, - cursorlineopt = 'number', - wrap = false, - scrolloff = 3, - ruler = false, -- removes cursor position from lastline - pumheight = 10, -- size of completion window - showmode = false, -- do not show mode under statusline - swapfile = false, -- creates a swapfile - backup = false, -- creates a backup file - writebackup = false, -- do not edit backups - winminwidth = 5, -- Minimum window width - termguicolors = true, -- set term gui colors (most terminals support this) - showtabline = 0, -- always show tabs - showcmd = false, - mouse = 'a', -- allow the mouse to be used in neovim - confirm = true, -- Confirm to save changes before exiting modified buffer - - -- tabs - smarttab = true, - tabstop = 4, -- 1 tab represented as 4 spaces - expandtab = true, -- key will create " " instead of "\t" - shiftwidth = 4, -- indent change after backspace and >> << - softtabstop = 4, -- number of spaces instead of tab - autoindent = true, -- auto indent - smartindent = true, -- make indenting smarter again - list = true, - -- listchars = { trail = "", tab = "", nbsp = "_", extends = ">", precedes = "<" }, -- highlight - showbreak = string.rep(' ', 3), - - -- Search - ignorecase = true, - smartcase = true, - hlsearch = true, - wildmenu = true, - wildmode = 'longest:full,full', - wildoptions = 'pum', - - -- Window - splitright = true, - splitbelow = true, - title = true, -} - -for k, v in pairs(options) do - vim.opt[k] = v -end - -vim.g.loaded_netrw = 1 -vim.g.loaded_netrwPlugin = 1 - -vim.opt.path:append({ '**' }) -vim.opt.shortmess:append({ W = true, I = true, c = true }) -- disable greeting - --- Fix markdown indentation settings -vim.g.markdown_recommended_style = 0 - -vim.cmd([[set fillchars+=eob:\ ]]) diff --git a/lua/extensions.lua b/lua/extensions.lua new file mode 100644 index 0000000..abad39e --- /dev/null +++ b/lua/extensions.lua @@ -0,0 +1,66 @@ +local treesitter_parsers = { + "c", + "markdown", + "python", + "java", + "cpp", + "bash", + "lua", + "make", + "json", + "jsonc", + "sql", + "yaml", + "toml", + "javascript", + "typescript", + "gitignore", + "go", + "rust", + "html", + "css", + "scss", + "markdown_inline", +} + +local lsp_server = { + "ts_ls", + "html", + "cssls", + "tailwindcss", + "lua_ls", + "basedpyright", + "bashls", + "clangd", + "rust_analyzer", +} + +local formatter = { + "clang_format", + "ruff", + "stylua", + "prettier", + "markdown-toc", + "markdownlint-cli2", + "biome", +} + +local linter = { + "eslint_d", + "hadolint", + "write_good", + "markdownlint", + "shellcheck", + "actionlint", + "djlint", + "ruff", + "codespell", + "cspell", +} + +return { + ts_parsers = treesitter_parsers, + lsp_server = lsp_server, + formatter = formatter, + linter = linter, +} diff --git a/lua/keys.lua b/lua/keys.lua new file mode 100644 index 0000000..83d4afa --- /dev/null +++ b/lua/keys.lua @@ -0,0 +1,143 @@ +local function map(mode, lhs, rhs, opts) + opts = opts or {} + opts.silent = opts.silent ~= false + vim.keymap.set(mode, lhs, rhs, opts) +end +local opts = { noremap = true, silent = true } + +-- Space as leader +map("n", "", "", opts) +vim.g.mapleader = " " +vim.g.maplocalleader = " " + +-- Modes +-- normal_mode = "n", insert_mode = "i", visual_mode = "v", +-- visual_block_mode = "x", term_mode = "t", command_mode = "c", + +-- Terminal Mappings +map("t", "jk", "") +map("t", "kj", "") +map("t", "", "") + +-- Clear search, diff update and redraw +map({ "i", "n" }, "", "noh", { desc = "Escape and clear hlsearch" }) + +map({ "i", "c" }, "", "") +map({ "i", "c" }, "", "") + +map("n", "rL", vim.lsp.buf.rename, { desc = "Rename Lsp Symbol" }) +map("n", "`", "'", { noremap = true }) -- better marks + +map({ "n", "v" }, "H", "^", { desc = "Move to the beginning of the line" }) +map({ "n", "v" }, "L", "$", { desc = "Move to the end of the line" }) + +-- Visual overwrite paste +map({ "v", "x" }, "p", '"_dP', opts) + +-- Do not copy on x +map({ "v", "x" }, "x", '"_x', opts) +map("n", "X", '"_D', opts) +map("n", "dd", '"_dd', opts) +map({ "v", "x" }, "X", '"_d', opts) + +-- Select all + +-- Select all +map("n", "a", "ggVG", { desc = "Select all" }) +map("n", "", "ggVG", { desc = "Select all" }) +map("i", "", "ggVG", { desc = "Select all" }) + +-- Move text up and down +map({ "v", "x" }, "K", ":move '<-2gv-gv", opts) +map({ "v", "x" }, "J", ":move '>+1gv-gv", opts) + +-- Line operations +map("n", "", ":m .-2==", { desc = "Move line up" }) +map("n", "", ":m .+1==", { desc = "Move line down" }) +map("i", "", ":m .-2==gi", { desc = "Move line up" }) +map("i", "", ":m .+1==gi", { desc = "Move line down" }) +map("v", "", ":m '<-2gv=gv", { desc = "Move selection up" }) +map("v", "", ":m '>+1gv=gv", { desc = "Move selection down" }) + +-- Line manipulation +map("n", "", ">>", { desc = "Indent line" }) +map("n", "", "<<", { desc = "Unindent line" }) +map("i", "", ">>", { desc = "Indent line" }) +map("i", "", "<<", { desc = "Unindent line" }) + +-- Quick word operations +map("n", "", "db", { desc = "Delete word backward" }) +map("i", "", "", { desc = "Delete word backward" }) +map("n", "", "dw", { desc = "Delete word forward" }) +map("i", "", "dw", { desc = "Delete word forward" }) + +map("n", "d", '"_d', { desc = "Delete without replacing clipboard" }) +map("n", "x", '"_x', { desc = "Cut without replacing clipboard" }) +map("n", "c", '"_c', { desc = "Change without replacing clipboard" }) +map("v", "p", '"_dP', { desc = "Paste without replacing clipboard" }) + +--insert the following characters around the visual selection +map("v", "(", "s()Pll", { desc = "wrap selection with parens" }) +map("v", "[", "s[]Pll", { desc = "wrap selection with square braces" }) +map("v", "{", "s{}Pll", { desc = "wrap selection with curly braces" }) +map("v", "'", "s''Pll", { desc = "wrap selection with single quotes" }) +map("v", '"', 's""Pll', { desc = "wrap selection with double quotes" }) + +-- Insert mode cursor movement with Ctrl+hjkl +map({ "i", "c" }, "", "", { noremap = true, silent = true }) +map({ "i", "c" }, "", "", { noremap = true, silent = true }) +map({ "i", "c" }, "", "", { noremap = true, silent = true }) +map({ "i", "c" }, "", "", { noremap = true, silent = true }) + +map("n", "re", ":%s//", { desc = "Shortcut to replace current word under cursor" }) + +-- toggle inlay hints +vim.keymap.set("n", "th", function() + vim.lsp.inlay_hint.enable(not vim.lsp.inlay_hint.is_enabled()) +end) + +-- No arrow navigation +local modes = { "n", "v", "i" } +local arrows = { "", "", "", "" } + +for _, mode in ipairs(modes) do + for _, key in ipairs(arrows) do + vim.api.nvim_set_keymap(mode, key, "", opts) + end +end + +-- Go to Beginning or End of line +map({ "n", "v" }, "H", "_^", { desc = "Move to the beginning of the line" }) +map({ "n", "v" }, "L", "$", { desc = "Move to the end of the line" }) + +-- Search inside visually highlighted text. +map("x", "g/", "/\\%V", { silent = false, desc = "Search inside visual selection" }) + +-- Search & replace in current file/line +map("v", "rw", '"9y:%s@9@9@g', { desc = "Search & replace selection", silent = false }) +map("n", "rw", 'viw"9y:%s@9@9@g', { desc = "Search & replace word", silent = false }) +map( + "v", + "rl", + '"9y:s@9@9@g', + { desc = "Search & replace in current line", silent = false } +) +map( + "n", + "rl", + 'viw"9y:s@9@9@g', + { desc = "Search & replace word in current line", silent = false } +) + +-- Folds +map("n", "<", function() + if not vim.opt.foldmethod then + vim.opt.foldmethod = "indent" + end + vim.cmd("normal! zM") +end, { desc = "Fold all" }) + +map("n", ">", function() + vim.opt.foldenable = false + vim.cmd("normal! zR") +end, { desc = "Open all folds" }) diff --git a/lua/lsp.lua b/lua/lsp.lua new file mode 100644 index 0000000..843f090 --- /dev/null +++ b/lua/lsp.lua @@ -0,0 +1,113 @@ +-------------------------------------------------------------------------------- +-- LSP +-------------------------------------------------------------------------------- + +vim.api.nvim_create_autocmd("User", { + pattern = "PackerComplete", -- Fallback or custom event if needed, but let's use a more standard one + callback = function() + -- This is where we would put it if we had a specific event. + -- Since we're using VimEnter, let's use that instead. + end, +}) + +-- Let's use a simple function and schedule it to run after plugins +vim.schedule(function() + vim.lsp.config("*", { + capabilities = require("blink.cmp").get_lsp_capabilities(), + }) + + -- ts_ls + vim.lsp.config("ts_ls", { + settings = { + typescript = { + inlayHints = { + includeInlayParameterNameHints = "all", + includeInlayParameterNameHintsWhenArgumentMatchesName = false, + includeInlayFunctionParameterTypeHints = true, + includeInlayVariableTypeHints = true, + includeInlayPropertyDeclarationTypeHints = true, + includeInlayFunctionLikeReturnTypeHints = true, + includeInlayEnumMemberValueHints = true, + }, + }, + }, + }) + vim.lsp.enable("ts_ls") + + vim.lsp.enable("html") + vim.lsp.enable("cssls") + vim.lsp.enable("tailwindcss") + + -- rust + vim.lsp.config("rust_analyzer", { + settings = { + ["rust-analyzer"] = { + diagnostics = { + enable = true, + experimental = { enable = true }, + }, + }, + }, + }) + vim.lsp.enable("rust_analyzer") + + -- lua + vim.lsp.config("lua_ls", { + settings = { + Lua = { + diagnostics = { + disable = { + "missing-fields", + "undefined-global", + }, + }, + }, + }, + }) + vim.lsp.enable("lua_ls") + + -- python + vim.lsp.config("basedpyright", { + settings = { + basedpyright = { + inlayHints = true, + analysis = { + diagnosticSeverityOverrides = { + reportUnusedImport = "none", + reportUnusedVariable = "none", + reportAttributeAccessIssue = "none", + reportUnusedClass = "none", + reportUnusedFunction = "none", + reportDuplicateImport = "none", + reportArgumentType = "error", + }, + typeCheckingMode = "standard", + }, + }, + }, + }) + vim.lsp.enable("basedpyright") + + -- bash + vim.lsp.config("bashls", { + settings = { + bashIde = { + shellcheckArguments = { + "--exclude=SC1090,SC1091,SC2076,SC2164", + }, + }, + }, + }) + vim.lsp.enable("bashls") + + -- cpp + vim.lsp.config("clangd", { + cmd = { + "clangd", + "--fallback-style=llvm", + "--header-insertion=iwyu", + "-j=4", + }, + }) + vim.lsp.enable("clangd") +end) diff --git a/lua/options.lua b/lua/options.lua new file mode 100644 index 0000000..e335ea4 --- /dev/null +++ b/lua/options.lua @@ -0,0 +1,67 @@ +local options = { + ai = true, + clipboard = "unnamedplus", -- use system clipboard + number = true, + relativenumber = true, + undofile = true, -- save state of file on write + undodir = vim.fn.stdpath("cache") .. "/undo", + undolevels = 10000, + autoread = true, -- autoread changes from other sources + signcolumn = "yes", + cursorline = true, + cursorlineopt = "number", + wrap = false, + scrolloff = 3, + ruler = false, -- removes cursor position from lastline + pumheight = 10, -- size of completion window + showmode = false, -- do not show mode under statusline + swapfile = false, -- creates a swapfile + backup = false, -- creates a backup file + writebackup = false, -- do not edit backups + winminwidth = 5, -- Minimum window width + termguicolors = true, -- set term gui colors (most terminals support this) + showtabline = 0, -- always show tabs + showcmd = false, + mouse = "a", -- allow the mouse to be used in neovim + confirm = true, -- Confirm to save changes before exiting modified buffer + + -- tabs + smarttab = true, + tabstop = 4, -- 1 tab represented as 4 spaces + expandtab = true, -- key will create " " instead of "\t" + shiftwidth = 4, -- indent change after backspace and >> << + softtabstop = 4, -- number of spaces instead of tab + autoindent = true, -- auto indent + smartindent = true, -- make indenting smarter again + list = true, + listchars = { tab = "» ", trail = "·", nbsp = "␣" }, + showbreak = string.rep(" ", 3), + + -- Search + ignorecase = true, + smartcase = true, + hlsearch = true, + wildmenu = true, + wildmode = "longest:full,full", + wildoptions = "pum", + + -- Window + splitright = true, + splitbelow = true, + title = true, +} + +for k, v in pairs(options) do + vim.opt[k] = v +end + +vim.g.loaded_netrw = 1 +vim.g.loaded_netrwPlugin = 1 + +vim.opt.path:append({ "**" }) +vim.opt.shortmess:append({ W = true, I = true, c = true }) -- disable greeting + +-- Fix markdown indentation settings +vim.g.markdown_recommended_style = 0 + +vim.cmd([[set fillchars+=eob:\ ]]) diff --git a/lua/pack_helper.lua b/lua/pack_helper.lua new file mode 100644 index 0000000..849cb82 --- /dev/null +++ b/lua/pack_helper.lua @@ -0,0 +1,71 @@ +local M = {} + +-- Define sources outside the function to avoid re-allocation +local SOURCES = { + gl = "https://gitlab.com/", + cb = "https://codeberg.org/", + gh = "https://github.com/", +} + +--- Resolves a shorthand URL or full URL to its canonical form. +local function resolve_url(url) + if not url or url:match("^https?://") then + return url + end + + -- Extract prefix if present (e.g., 'gl:user/repo') + local prefix, rest = url:match("^(%w+):(.+)$") + if prefix and SOURCES[prefix] then + return SOURCES[prefix] .. rest + end + + -- Default to GitHub if no prefix or unknown prefix + return SOURCES.gh .. url +end + +--- Normalizes a plugin specification. +local function normalize_spec(spec) + if type(spec) == "string" then + return resolve_url(spec) + elseif type(spec) == "table" and spec.src then + spec.src = resolve_url(spec.src) + return spec + end + return spec +end + +--- Global helper to add plugins to the package manager. +--- Supports shorthand for GitHub (default), GitLab (gl:), and Codeberg (cb:). +--- +--- Examples: +--- add("user/repo") --> https://github.com/user/repo +--- add("gl:user/repo") --> https://gitlab.com/user/repo +--- add("cb:user/repo") --> https://codeberg.org/user/repo +--- add({ "user/repo", version = "main" }) +--- add({ "user/repo", "gl:other/repo" }) +--- +_G.add = function(specs) + -- Normalize input to a table if a single spec is provided + local list = type(specs) == "table" and (specs.src or not specs[1]) and { specs } or specs + if type(list) ~= "table" then + list = { specs } + end + + local resolved = {} + for _, spec in ipairs(list) do + local normalized = normalize_spec(spec) + if normalized then + table.insert(resolved, normalized) + end + end + + if #resolved > 0 then + -- Wrap in pcall to handle potential vim.pack errors gracefully + local ok, err = pcall(vim.pack.add, resolved) + if not ok then + vim.notify("vim.pack.add failed: " .. tostring(err), vim.log.levels.ERROR, { title = "Pack Helper" }) + end + end +end + +return M diff --git a/lua/plugins/ai.lua b/lua/plugins/ai.lua deleted file mode 100644 index 1f0492d..0000000 --- a/lua/plugins/ai.lua +++ /dev/null @@ -1,14 +0,0 @@ -return { - { - 'Exafunction/windsurf.vim', - event = 'VeryLazy', - config = function() - vim.keymap.set('i', '', function() - return vim.fn['codeium#Accept']() - end, { expr = true, silent = true }) - vim.keymap.set('i', '', function() - return vim.fn['codeium#Clear']() - end, { expr = true, silent = true }) - end, - }, -} diff --git a/lua/plugins/coding.lua b/lua/plugins/coding.lua deleted file mode 100644 index f54be95..0000000 --- a/lua/plugins/coding.lua +++ /dev/null @@ -1,126 +0,0 @@ -return { - - -- completion - { - 'saghen/blink.cmp', - version = '*', - config = function() - require('blink.cmp').setup({ - fuzzy = { implementation = 'prefer_rust' }, - snippets = { preset = 'luasnip' }, - sources = { - default = { 'lsp', 'path', 'snippets', 'buffer' }, - providers = {}, - }, - - completion = { - ghost_text = { enabled = true }, - - list = { - selection = { - preselect = false, - auto_insert = true, - }, - }, - documentation = { - window = { border = 'rounded' }, - auto_show = true, - auto_show_delay_ms = 50, - }, - menu = { - border = 'rounded', - draw = { - components = { - kind_icon = { - text = function(ctx) - local kind_icon, _, _ = require('mini.icons').get('lsp', ctx.kind) - return kind_icon - end, - highlight = function(ctx) - local _, hl, _ = require('mini.icons').get('lsp', ctx.kind) - return hl - end, - }, - kind = { - highlight = function(ctx) - local _, hl, _ = require('mini.icons').get('lsp', ctx.kind) - return hl - end, - }, - }, - }, - }, - }, - signature = { - window = { border = 'rounded' }, - }, - keymap = { - preset = 'none', - [''] = { 'select_prev', 'snippet_backward', 'fallback' }, - [''] = { 'select_next', 'snippet_forward', 'fallback' }, - [''] = { 'accept', 'fallback' }, - [''] = { 'hide', 'show' }, - [''] = { 'show', 'show_documentation', 'hide_documentation' }, - [''] = { 'scroll_documentation_up', 'fallback' }, - [''] = { 'scroll_documentation_down', 'fallback' }, - }, - }) - end, - }, - - -- snippets - { - 'L3MON4D3/LuaSnip', - version = '*', - dependencies = { 'rafamadriz/friendly-snippets' }, - config = function() - local luasnip = require('luasnip') - require('luasnip.loaders.from_vscode').lazy_load() - require('luasnip.loaders.from_vscode').lazy_load({ - paths = { vim.fn.stdpath('config') .. '/snippets' }, - }) - - luasnip.filetype_extend('mdx', { 'markdown' }) - end, - }, - - -- comment - { - 'numToStr/Comment.nvim', - dependencies = { - 'JoosepAlviste/nvim-ts-context-commentstring', - }, - config = function() - require('Comment').setup({ - pre_hook = require('ts_context_commentstring.integrations.comment_nvim').create_pre_hook(), - mappings = { - basic = true, - extra = true, - }, - }) - end, - keys = { - { 'gcc', mode = 'n', desc = 'Toggle comment line' }, - { 'gc', mode = { 'n', 'o' }, desc = 'Toggle comment linewise' }, - { 'gc', mode = 'x', desc = 'Toggle comment linewise (visual)' }, - { 'gbc', mode = 'n', desc = 'Toggle comment block' }, - { 'gb', mode = { 'n', 'o' }, desc = 'Toggle comment blockwise' }, - { 'gb', mode = 'x', desc = 'Toggle comment blockwise (visual)' }, - }, - }, - - -- annotation generator - { - 'danymat/neogen', - opts = { - snippet_engine = 'luasnip', - languages = { - python = { - template = { - annotation_convention = 'google_docstrings', - }, - }, - }, - }, - }, -} diff --git a/lua/plugins/colorscheme.lua b/lua/plugins/colorscheme.lua deleted file mode 100644 index 4bf3efe..0000000 --- a/lua/plugins/colorscheme.lua +++ /dev/null @@ -1,39 +0,0 @@ -return { - "ellisonleao/gruvbox.nvim", - priority = 1000, - config = function() - local palette = require("gruvbox").palette - require("gruvbox").setup({ - bold = false, - italic = { - strings = false, - emphasis = false, - comments = false, - folds = false, - }, - contrast = "hard", - transparent_mode = true, - overrides = { - -- builtin - SignColumn = { bg = "None" }, - CursorLineNr = { bg = "None" }, - Whitespace = { fg = palette.dark0 }, - EndOfBuffer = { fg = palette.dark0_hard }, - Visual = { fg = "None", bg = palette.dark1 }, - Label = { link = "GruvboxPurple" }, - - -- blink.cmp - BlinkCmpMenu = { link = "Normal" }, - BlinkCmpMenuBorder = { link = "BlinkCmpMenu" }, - BlinkCmpMenuSelection = { fg = "None", bg = palette.dark1 }, - BlinkCmpLabelMatch = { fg = palette.bright_green }, - BlinkCmpScrollBarGutter = { bg = palette.dark2 }, - BlinkCmpScrollBarThumb = { bg = palette.light1 }, - - -- indent guides - MiniIndentscopeSymbol = { fg = palette.dark1 }, - }, - }) - vim.cmd.colorscheme("gruvbox") - end, -} diff --git a/lua/plugins/editor.lua b/lua/plugins/editor.lua deleted file mode 100644 index 6a04514..0000000 --- a/lua/plugins/editor.lua +++ /dev/null @@ -1,100 +0,0 @@ -return { - - -- Todo Comments - { - 'folke/todo-comments.nvim', - event = 'BufRead', - opts = {}, - }, - - -- Working with file permissions - { - 'lambdalisue/vim-suda', - cmd = { 'SudaRead', 'SudaWrite' }, - }, - - -- visual multi - { - 'mg979/vim-visual-multi', - event = 'VeryLazy', - init = function() - vim.g.VM_maps = { - ['Find Under'] = '', - ['Find Subword Under'] = '', - ['Select All'] = '', - ['Add Cursor Down'] = '', - ['Add Cursor Up'] = '', - } - end, - }, - - -- dimming the highlights of unused functions, variables, parameters, and more - { - 'zbirenbaum/neodim', - enabled = false, - event = 'LspAttach', - config = function() - require('neodim').setup({ - alpha = 0.5, - blend_color = nil, - hide = { - underline = true, - virtual_text = true, - signs = true, - }, - regex = { - '[uU]nused', - '[nN]ever [rR]ead', - '[nN]ot [rR]ead', - }, - priority = 128, - disable = {}, - }) - end, - }, - - -- file operations - { - 'chrisgrieser/nvim-genghis', - keys = { - { - 'fn', - function() - require('genghis').createNewFile() - end, - desc = 'New File', - }, - { - 'fd', - function() - require('genghis').duplicateFile() - end, - desc = 'Duplicate File', - }, - { - 'fr', - function() - require('genghis').renameFile() - end, - desc = 'Rename File', - }, - { - 'fz', - function() - require('genghis').chmodx() - end, - desc = 'Make Executable', - }, - }, - }, - - -- markdown preview - { - 'iamcco/markdown-preview.nvim', - cmd = { 'MarkdownPreviewToggle', 'MarkdownPreview', 'MarkdownPreviewStop' }, - ft = { 'markdown' }, - build = function() - vim.fn['mkdp#util#install']() - end, - }, -} diff --git a/lua/plugins/formatting.lua b/lua/plugins/formatting.lua deleted file mode 100644 index 9716fb3..0000000 --- a/lua/plugins/formatting.lua +++ /dev/null @@ -1,64 +0,0 @@ -return { - "stevearc/conform.nvim", - dependencies = { "zapling/mason-conform.nvim" }, - event = "BufWritePre", - cmd = "ConformInfo", - keys = { "tf" }, - config = function() - require("conform").setup({ - formatters = { - ["markdown-toc"] = { - condition = function(_, ctx) - for _, line in ipairs(vim.api.nvim_buf_get_lines(ctx.buf, 0, -1, false)) do - if line:find("") then - return true - end - end - end, - }, - ["markdownlint-cli2"] = { - condition = function(_, ctx) - local diag = vim.tbl_filter(function(d) - return d.source == "markdownlint" - end, vim.diagnostic.get(ctx.buf)) - return #diag > 0 - end, - }, - }, - formatters_by_ft = { - ["lua"] = { "stylua" }, - ["c"] = { "clang_format" }, - ["cpp"] = { "clang_format" }, - ["h"] = { "clang_format" }, - ["python"] = { "ruff_fix", "ruff_format", "ruff_organize_imports" }, - ["javascript"] = { "biome" }, - ["typescript"] = { "biome" }, - ["typescriptreact"] = { "biome" }, - ["markdown"] = { "prettier", "markdownlint-cli2", "markdown-toc" }, - ["markdown.mdx"] = { "prettier", "markdownlint-cli2", "markdown-toc" }, - ["mdx"] = { "prettier" }, - ["_"] = { "trim_whitespace" }, - }, - options = { - stop_after_first = true, - }, - format_after_save = function(bufnr) - if not vim.b[bufnr].conform_disable then - return { - lsp_format = "fallback", - } - end - end, - }) - - vim.keymap.set("n", "tf", function() - vim.b.conform_disable = not vim.b.conform_disable - local status = vim.b.conform_disable and "disabled" or "enabled" - vim.notify("Autoformat " .. status, vim.log.levels.INFO) - end, { desc = "Toggle autoformat" }) - require("mason-conform").setup({ - ensure_installed = require("config.extensions").formatter, - automatic_installation = true, - }) - end, -} diff --git a/lua/plugins/git.lua b/lua/plugins/git.lua deleted file mode 100644 index 5ea01a8..0000000 --- a/lua/plugins/git.lua +++ /dev/null @@ -1,61 +0,0 @@ -return { - -- gitignore generator - { - 'wintermute-cell/gitignore.nvim', - cmd = { 'Gitignore' }, - opts = {}, - }, - - -- git signs - { - 'lewis6991/gitsigns.nvim', - events = { 'BufReadPost', 'BufNewFile' }, - opts = { - signcolumn = true, - current_line_blame = true, - attach_to_untracked = false, - current_line_blame_formatter = ', - ', - watch_gitdir = { - follow_files = true, - }, - current_line_blame_opts = { - virt_text = true, - virt_text_pos = 'eol', -- 'eol' | 'overlay' | 'right_align' - delay = 1000, - ignore_whitespace = false, - virt_text_priority = 100, - use_focus = true, - }, - signs = { - add = { text = ' ' }, - change = { text = '󱗜 ' }, - delete = { text = '󰍵 ' }, - topdelete = { text = '󱥨 ' }, - changedelete = { text = '󰾟 ' }, - untracked = { text = '󰰧 ' }, - }, - }, - }, - - -- lazygit integration - { - 'kdheepak/lazygit.nvim', - lazy = true, - enabled = true, - cmd = { - 'LazyGit', - 'LazyGitConfig', - 'LazyGitCurrentFile', - 'LazyGitFilter', - 'LazyGitFilterCurrentFile', - }, - keys = { - { 'lg', 'LazyGit', desc = 'LazyGit' }, - }, - config = function() - vim.g.lazygit_floating_window_winblend = 0 - vim.g.lazygit_floating_window_scaling_factor = 0.9 - vim.g.lazygit_floating_window_border_chars = { '╭', '─', '╮', '│', '╯', '─', '╰', '│' } - end, - }, -} diff --git a/lua/plugins/linting.lua b/lua/plugins/linting.lua deleted file mode 100644 index 3836822..0000000 --- a/lua/plugins/linting.lua +++ /dev/null @@ -1,34 +0,0 @@ -return { - "mfussenegger/nvim-lint", - dependencies = { "rshkarin/mason-nvim-lint" }, - event = { "BufReadPost", "BufNewFile" }, - keys = { - { - "cL", - mode = { "n" }, - function() - require("lint").try_lint() - end, - desc = "Trigger linting for current file", - }, - }, - config = function() - require("lint").linters_by_ft = { - ["*"] = { "codespell" }, - ["javascript"] = { "eslint_d", "cspell" }, - ["typescript"] = { "eslint_d", "cspell" }, - ["javascriptreact"] = { "eslint_d", "cspell" }, - ["typescriptreact"] = { "eslint_d", "cspell" }, - ["dockerfile"] = { "hadolint" }, - ["markdown"] = { "write_good", "markdownlint" }, - ["text"] = { "write_good" }, - ["sh"] = { "shellcheck" }, - ["yaml"] = { "actionlint" }, - ["python"] = { "ruff" }, - } - require("mason-nvim-lint").setup({ - ensure_installed = require("config.extensions").linter, - automatic_installation = false, - }) - end, -} diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua deleted file mode 100644 index 03cee36..0000000 --- a/lua/plugins/lsp.lua +++ /dev/null @@ -1,109 +0,0 @@ -return { - -- default lsp configs - { - 'neovim/nvim-lspconfig', - config = function() end, - }, - - -- lsp installer - { - 'williamboman/mason.nvim', - dependencies = { - 'williamboman/mason-lspconfig.nvim', - }, - cmd = 'Mason', - config = function() - -- mason - require('mason').setup({ - ui = { - icons = { - package_installed = '✓', - package_pending = '➜', - package_uninstalled = '✗', - }, - border = 'rounded', - backdrop = 100, - }, - }) - require('mason-lspconfig').setup({ - ensure_installed = require('config.extensions').lsp_server, - automatic_installation = false, -- Don't auto-install or auto-configure - }) - end, - }, - - -- improve neovim lsp experience - { - 'nvimdev/lspsaga.nvim', - event = 'LspAttach', - config = function() - require('lspsaga').setup({ - ui = { - theme = 'round', - border = 'rounded', - devicon = true, - title = true, - winblend = 1, - expand = ' ', - collapse = ' ', - preview = '', - code_action = '󰠠 ', - diagnostic = ' ', - incoming = ' ', - outgoing = ' ', - hover = ' ', - }, - }) - end, - }, - - -- inline diagnostic - { - 'rachartier/tiny-inline-diagnostic.nvim', - event = 'VeryLazy', - priority = 1000, - config = function() - require('tiny-inline-diagnostic').setup({ - options = { - show_source = true, - multiple_diag_under_cursor = true, - -- break_line = { - -- enabled = true, - -- after = 60, - -- } - }, - }) - vim.diagnostic.config({ virtual_text = false }) -- Disable default virtual text - end, - }, - - -- code action - { - 'rachartier/tiny-code-action.nvim', - dependencies = { - { - 'folke/snacks.nvim', - opts = { - terminal = {}, - }, - }, - }, - event = 'LspAttach', - config = function() - local codeaction = require('tiny-code-action') - - codeaction.setup({ - picker = { - 'buffer', - opts = { - auto_preview = true, - hotkeys = true, - hotkeys_mode = 'sequential', - }, - }, - }) - - vim.keymap.set('n', '.', codeaction.code_action) - end, - }, -} diff --git a/lua/plugins/mini.lua b/lua/plugins/mini.lua deleted file mode 100644 index 6fc88b6..0000000 --- a/lua/plugins/mini.lua +++ /dev/null @@ -1,161 +0,0 @@ -return { - 'echasnovski/mini.nvim', - config = function() - require('mini.ai').setup() -- Extend and create a/i textobjects - require('mini.pairs').setup() -- Autopairs - require('mini.icons').setup() -- Icons - require('mini.bracketed').setup() -- Go forward/backward with square brackets - - -- File explorer - require('mini.files').setup({ - mappings = { - close = 'q', - go_in = 'L', - go_in_plus = 'l', - go_out = 'h', - go_out_plus = 'H', - mark_goto = "'", - mark_set = 'm', - reset = '', - reveal_cwd = '@', - show_help = 'g?', - synchronize = '', - trim_left = '<', - trim_right = '>', - }, - }) - - require('mini.misc').setup({ - -- restore cursor position on file reopen - require('mini.misc').setup_restore_cursor(), - -- automated change of current directory - require('mini.misc').setup_auto_root(), - }) - - -- splitjoin - require('mini.splitjoin').setup({ - mappings = { - toggle = 'tj', - split = '', - join = '', - }, - }) - - -- surround action - require('mini.surround').setup({ - mappings = { - add = 'msa', - delete = 'msd', - find = 'msf', - find_left = 'msF', - highlight = 'msh', - replace = 'msr', - update_n_lines = 'msn', - - suffix_last = 'l', - suffix_next = 'n', - }, - }) - - -- indents - require('mini.indentscope').setup({ - draw = { animation = require('mini.indentscope').gen_animation.linear({ ease = 'out', duration = 15 }) }, - options = { border = 'top', try_as_border = true, indent_at_cursor = false }, - }) - - vim.api.nvim_create_autocmd('BufEnter', { - pattern = '*', - callback = function(args) - if vim.bo[args.buf].buftype ~= '' then - vim.b[args.buf].miniindentscope_disable = true - end - end, - }) - - -- statusline - require('mini.statusline').setup({ - use_icons = true, - content = { - active = function() - local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 }) - local git = MiniStatusline.section_git({ trunc_width = 40 }) - local diff = MiniStatusline.section_diff({ trunc_width = 80 }) - local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 60 }) - local lsp = MiniStatusline.section_lsp({ trunc_width = 40 }) - local filename = MiniStatusline.section_filename({ trunc_width = 140 }) - - local function section_filetype(args) - if - MiniStatusline.is_truncated(args.trunc_width) - or vim.bo.filetype == '' - or vim.bo.buftype ~= '' - then - return '' - end - local ok, icons = pcall(require, 'mini.icons') - local icon = ok and select(1, icons.get('filetype', vim.bo.filetype)) or '' - return string.format('%s %s│', icon, vim.bo.filetype) - end - - local function section_lsp_clients(args) - if MiniStatusline.is_truncated(args.trunc_width) then - return '' - end - local clients = vim.lsp.get_clients({ bufnr = 0 }) - if not clients or #clients == 0 then - return '' - end - local names = vim.tbl_map(function(c) - return c.name - end, clients) - return string.format(' %s', table.concat(names, ', ')) - end - - local function section_searchcount(args) - if vim.v.hlsearch == 0 then - return '' - end - local ok, s = pcall(vim.fn.searchcount, { recompute = true }) - if not ok or s.current == nil or s.total == 0 then - return '' - end - local icon = MiniStatusline.is_truncated(args.trunc_width) and '' or ' ' - if s.incomplete == 1 then - return icon .. '?/?│' - end - local fmt = '>%d' - local cur = s.current > s.maxcount and fmt:format(s.maxcount) or s.current - local tot = s.total > s.maxcount and fmt:format(s.maxcount) or s.total - return ('%s%s/%s│'):format(icon, cur, tot) - end - - local function section_location(args) - return MiniStatusline.is_truncated(args.trunc_width) and '%-2l│%-2v' - or '󰉸 %-2l│󱥖 %-2v' - end - - local filetype = section_filetype({ trunc_width = 70 }) - local searchcount = section_searchcount({ trunc_width = 80 }) - local loc = section_location({ trunc_width = 120 }) - local lsp_clients = section_lsp_clients({ trunc_width = 60 }) - - return MiniStatusline.combine_groups({ - { hl = mode_hl, strings = { mode:upper() } }, - { hl = 'MiniStatuslineDevinfo', strings = { git, diff, diagnostics, lsp } }, - '%<', - { hl = 'MiniStatuslineFilename', strings = { filename } }, - '%=', - { hl = 'MiniStatuslineDevinfo', strings = { lsp_clients } }, - { hl = mode_hl, strings = { filetype, searchcount, loc } }, - }) - end, - - inactive = function() - return MiniStatusline.combine_groups({ - { hl = 'MiniStatuslineInactive', strings = { vim.fn.expand('%:t') } }, - }) - end, - }, - }) - end, -} diff --git a/lua/plugins/snacks.lua b/lua/plugins/snacks.lua deleted file mode 100644 index 83939ee..0000000 --- a/lua/plugins/snacks.lua +++ /dev/null @@ -1,367 +0,0 @@ -return { - 'folke/snacks.nvim', - priority = 1000, - lazy = false, - config = function() - local function files_layout(preview_width, height, width) - preview_width = preview_width or 0.6 - height = height or 0.8 - width = width or 0.9 - return { - layout = { - box = 'horizontal', - width = width, - min_width = 120, - height = height, - { - box = 'vertical', - border = 'rounded', - title = '{title} {live} {flags}', - { win = 'input', height = 1, border = 'bottom' }, - { win = 'list', border = 'none' }, - }, - { win = 'preview', title = '{preview}', border = 'rounded', width = preview_width }, - }, - } - end - - local function palette_layout(height, width) - height = height or 0.4 - width = width or 0.6 - return { - preview = false, - layout = { - backdrop = false, - row = 1, - width = width, - min_width = 80, - height = height, - border = 'rounded', - box = 'vertical', - { - win = 'input', - height = 1, - border = 'rounded', - title = '{title} {live} {flags}', - title_pos = 'center', - }, - { win = 'list', border = 'hpad' }, - { win = 'preview', title = '{preview}', border = 'rounded' }, - }, - } - end - - local Snacks = require('snacks') - Snacks.setup({ - animate = { - enabled = true, - duration = 20, -- ms per step - easing = 'linear', - fps = 60, - }, - bigfile = { - enabled = true, - notify = true, - size = 1000 * 1024, -- 1 MB instead of 100 KB - }, - bufdelete = { enabled = true }, - dashboard = { - preset = { - header = [[ -░█░█░█▀▀░█░█░█▀▀░█▀█░█▀▄░█▀▀░█░█ -░█▀▄░█▀▀░░█░░█░░░█░█░█░█░█▀▀░▄▀▄ -░▀░▀░▀▀▀░░▀░░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ - ]], - }, - sections = { - { section = 'header' }, - { - icon = ' ', - title = 'Keymaps', - section = 'keys', - indent = 2, - padding = 1, - }, - { - icon = ' ', - title = 'Recent Files', - section = 'recent_files', - indent = 2, - padding = 1, - }, - { - icon = ' ', - title = 'Projects', - section = 'projects', - indent = 2, - padding = 1, - }, - { section = 'startup' }, - }, - }, - debug = { enabled = true }, - dim = { - enabled = true, - scope = { - min_size = 5, - max_size = 20, - siblings = true, - }, - }, - explorer = { enabled = false }, - git = { enabled = true }, - gitbrowse = { enabled = true }, - image = { enabled = true }, - indent = { - enabled = true, - priority = 1, - char = '▍', - only_scope = false, - only_current = false, - hl = { - 'SnacksIndent1', - 'SnacksIndent2', - 'SnacksIndent3', - 'SnacksIndent4', - 'SnacksIndent5', - 'SnacksIndent6', - 'SnacksIndent7', - 'SnacksIndent8', - }, - }, - input = { - enabled = true, - icon = ' ', - icon_hl = 'SnacksInputIcon', - icon_pos = 'left', - prompt_pos = 'title', - win = { style = 'input' }, - expand = true, - }, - layout = { enabled = true }, - lazygit = { enabled = true }, - notifier = { - enabled = true, - timeout = 2000, - width = { min = 40, max = 0.4 }, - height = { min = 1, max = 0.6 }, - margin = { top = 0, right = 1, bottom = 0 }, - padding = true, - sort = { 'level', 'added' }, - level = vim.log.levels.TRACE, - icons = { - debug = ' ', - error = ' ', - info = ' ', - trace = ' ', - warn = ' ', - }, - style = 'compact', - top_down = true, - date_format = '%R', - more_format = ' ↓ %d lines ', - refresh = 50, - }, - notify = { enabled = true }, - picker = { - enabled = true, - icon = ' ', - icon_hl = 'SnacksPickerIcon', - icon_pos = 'left', - prompt_pos = 'title', - win = { style = 'picker' }, - expand = true, - matchers = { - frecency = true, - cwd_bonus = false, - }, - sources = { - -- layout options: dropdown, horizontal, vertical, vscode, ivy, ivy_split, telescope, top, left, right, bottom, sidebar - buffers = { layout = files_layout() }, - commands = { layout = palette_layout() }, - command_history = { layout = palette_layout() }, - files = { - hidden = true, - layout = files_layout(), - }, - icons = { - icon_sources = { 'nerd_fonts', 'emoji' }, - layout = palette_layout(), - }, - git_files = { layout = files_layout() }, - git_branches = { layout = { preset = 'vertical' } }, - git_status = { layout = files_layout() }, - help = { layout = { preset = 'ivy_split' } }, - man = { layout = { preset = 'ivy_split' } }, - notifications = { layout = palette_layout() }, - projects = { layout = files_layout(0.8) }, - recent = { layout = files_layout() }, - search_history = { layout = palette_layout() }, - smart = { layout = files_layout() }, - undo = { layout = { preset = 'ivy' } }, - zoxide = { layout = files_layout(0.7) }, - }, - layout = 'custom', - layouts = { - custom = { - layout = { - box = 'vertical', - backdrop = false, - row = -1, - width = 0, - height = 0.4, - border = 'top', - title = ' {title} {live} {flags}', - title_pos = 'left', - { - box = 'horizontal', - { win = 'list', border = 'rounded' }, - { win = 'preview', title = '{preview}', width = 0.6, border = 'left' }, - }, - { win = 'input', height = 1, border = 'top' }, - }, - }, - }, - }, - profiler = { enabled = true }, - quickfile = { enabled = true }, - rename = { enabled = true }, - scope = { - enabled = true, - keys = { - textobject = { - ii = { - min_size = 2, -- minimum size of the scope - edge = false, -- inner scope - cursor = false, - treesitter = { blocks = { enabled = false } }, - desc = 'inner scope', - }, - ai = { - cursor = false, - min_size = 2, -- minimum size of the scope - treesitter = { blocks = { enabled = false } }, - desc = 'full scope', - }, - }, - jump = { - ['[a'] = { - min_size = 1, -- allow single line scopes - bottom = false, - cursor = false, - edge = true, - treesitter = { blocks = { enabled = false } }, - desc = 'jump to top edge of scope', - }, - [']a'] = { - min_size = 1, -- allow single line scopes - bottom = true, - cursor = false, - edge = true, - treesitter = { blocks = { enabled = false } }, - desc = 'jump to bottom edge of scope', - }, - }, - }, - }, - scratch = { - enabled = true, - name = 'SCRATCH', - ft = function() - if vim.bo.buftype == '' and vim.bo.filetype ~= '' then - return vim.bo.filetype - end - return 'markdown' - end, - icon = nil, - root = vim.fn.stdpath('data') .. '/scratch', - autowrite = true, - filekey = { - cwd = true, - branch = true, - count = true, - }, - win = { - width = 120, - height = 40, - bo = { buftype = '', buflisted = false, bufhidden = 'hide', swapfile = false }, - minimal = false, - noautocmd = false, - zindex = 20, - wo = { winhighlight = 'NormalFloat:Normal' }, - border = 'rounded', - title_pos = 'center', - footer_pos = 'center', - - keys = { - ['execute'] = { - '', - function(_) - vim.cmd('%SnipRun') - end, - desc = 'Execute buffer', - mode = { 'n', 'x' }, - }, - }, - }, - win_by_ft = { - lua = { - keys = { - ['source'] = { - 'cr', - function(self) - local name = 'scratch.' - .. vim.fn.fnamemodify(vim.api.nvim_buf_get_name(self.buf), ':e') - Snacks.debug.run({ buf = self.buf, name = name }) - end, - desc = 'Source buffer', - mode = { 'n', 'x' }, - }, - }, - }, - }, - }, - scroll = { enabled = false }, - statuscolumn = { - enabled = false, -- Change this to false - left = { 'mark', 'sign' }, - right = { 'fold', 'git' }, - folds = { - open = false, - git_hl = false, - }, - git = { - patterns = { 'GitSign', 'MiniDiffSign' }, - }, - refresh = 50, - }, - terminal = { enabled = false }, - toggle = { enabled = false }, - win = { enabled = true }, - words = { enabled = false }, - zen = { - enabled = true, - toggles = { - dim = true, - git_signs = false, - mini_diff_signs = false, - -- diagnostics = false, - -- inlay_hints = false, - }, - show = { - statusline = false, - tabline = false, - }, - win = { style = 'zen' }, - zoom = { - toggles = {}, - show = { statusline = true, tabline = true }, - win = { - backdrop = false, - width = 0, - }, - }, - }, - }) - end, -} diff --git a/lua/plugins/syntax.lua b/lua/plugins/syntax.lua deleted file mode 100644 index c7a91bb..0000000 --- a/lua/plugins/syntax.lua +++ /dev/null @@ -1,78 +0,0 @@ -return { - - -- treesitter - { - 'nvim-treesitter/nvim-treesitter', - build = ':TSUpdate', - event = { 'BufReadPost', 'BufNewFile' }, - config = function() - require('nvim-treesitter').setup({ - ensure_installed = require('config.extensions').ts_parsers, - auto_install = true, - highlight = { - enable = true, - additional_vim_regex_highlighting = true, - }, - indent = { - enable = true, - }, - }) - end, - }, - - -- auto pairs - { - 'windwp/nvim-autopairs', - event = 'InsertEnter', - config = function() - local npairs = require('nvim-autopairs') - local Rule = require('nvim-autopairs.rule') - local conds = require('nvim-autopairs.conds') - - npairs.setup() - - -- Autoclosing angle-brackets. - npairs.add_rule(Rule('<', '>', { - -- Avoid conflicts with nvim-ts-autotag. - '-html', - '-javascriptreact', - '-typescriptreact', - }):with_pair(conds.before_regex('%a+:?:?$', 3)):with_move(function(opts) - return opts.char == '>' - end)) - end, - }, - - -- auto tag - { - 'windwp/nvim-ts-autotag', - ft = { - 'html', - 'xml', - 'javascript', - 'typescript', - 'javascriptreact', - 'typescriptreact', - 'jsx', - 'tsx', - 'vue', - 'svelte', - 'markdown', - 'htmldjango', - }, - event = 'InsertEnter', - lazy = true, - opts = { - -- Defaults - enable_close = true, -- Auto close tags - enable_rename = true, -- Auto rename pairs of tags - enable_close_on_slash = false, -- Auto close on trailing cv', 'Markview toggle', desc = 'Toggle markdown preview', mode = 'n' }, - }, - }, - - -- Better folding - { - 'kevinhwang91/nvim-ufo', - dependencies = 'kevinhwang91/promise-async', - event = 'BufReadPost', - keys = { - { - 'zR', - function() - require('ufo').openAllFolds() - end, - }, - { - 'zM', - function() - require('ufo').closeAllFolds() - end, - }, - { - 'zr', - function() - require('ufo').openFoldsExceptKinds() - end, - }, - { - 'zm', - function() - require('ufo').closeFoldsWith() - end, - }, - }, - config = function() - vim.o.foldcolumn = '1' - vim.o.foldlevel = 99 - vim.o.foldlevelstart = 99 - vim.o.foldenable = true - - require('ufo').setup({ - provider_selector = function() - return { 'treesitter', 'indent' } - end, - }) - end, - }, - - -- smooth scrolling - { - 'karb94/neoscroll.nvim', - opts = {}, - }, - - -- Smart column (colorcolumn only when needed) - { - 'm4xshen/smartcolumn.nvim', - event = { 'BufReadPost', 'BufNewFile' }, - opts = { - colorcolumn = '120', - disabled_filetypes = { - 'help', - 'text', - 'markdown', - 'dashboard', - 'snacks_dashboard', - 'lazy', - 'mason', - 'oil', - }, - }, - }, - - -- Screenshot Tool - { - 'mistricky/codesnap.nvim', - build = 'make', - cmd = { - 'CodeSnap', - 'CodeSnapSave', - 'CodeSnapHighlight', - 'CodeSnapSaveHighlight', - 'CodeSnapASCII', - }, - opts = { - bg_theme = 'dusk', - code_font_family = 'JetBrainsMono Nerd Font', - save_path = os.getenv('XDG_SCREENSHOTS_DIR') or (os.getenv('HOME') .. '/Pictures'), - watermark = 'SANKALP', - watermark_font_family = 'Anurati', - has_breadcrumbs = true, - breadcrumbs_separator = '/', - has_line_number = true, - }, - }, -} diff --git a/lua/plugins/util.lua b/lua/plugins/util.lua deleted file mode 100644 index b0f2fa7..0000000 --- a/lua/plugins/util.lua +++ /dev/null @@ -1,108 +0,0 @@ -return { - - -- better escape - { - 'max397574/better-escape.nvim', - config = function() - require('better_escape').setup({ - mappings = { - -- i for insert, other modes are the first letter too - i = { - -- map kj to exit insert mode - k = { - j = '', - }, - -- map jk and jj to exit insert mode - j = { - k = '', - j = '', - }, - -- disable jj - j = { - j = false, - }, - }, - }, - }) - end, - }, - - -- float terminal - { - 'akinsho/toggleterm.nvim', - cmd = { 'ToggleTerm' }, - version = '*', - config = function() - require('toggleterm').setup({ - size = 10, - open_mapping = [[]], - hide_numbers = true, - shade_filetypes = {}, - shade_terminals = true, - shading_factor = '2', - start_in_insert = true, - insert_mappings = true, - terminal_mappings = true, - persist_size = true, - direction = 'float', -- 'vertical' | 'horizontal' | 'tab' | 'float' - close_on_exit = true, - shell = vim.o.shell, - float_opts = { - border = 'curved', -- 'single', 'double', 'shadow', etc. - winblend = 0, -- Set to 0 for full transparency - highlights = { - border = 'Normal', - background = 'Normal', - }, - }, - }) - end, - }, - - -- discord presence - -- { - -- "vyfor/cord.nvim", - -- event = "VeryLazy", - -- }, - - -- wakatime - { 'wakatime/vim-wakatime', event = 'VimEnter', lazy = false }, - - -- workflow - { - 'm4xshen/hardtime.nvim', - lazy = false, - opts = {}, - }, - - -- buffer manager - { - 'serhez/bento.nvim', - opts = {}, - -- config = function() - -- require('bento').setup({ - -- ordering_metric = 'edit', - -- ui = { - -- mode = 'floating', - -- floating = { - -- position = 'middle-right', - -- minimal_menu = 'full', - -- }, - -- }, - -- }) - -- end, - }, - - -- navigator - { - 'numToStr/Navigator.nvim', - event = 'VeryLazy', - config = function() - require('Navigator').setup({ - auto_save = 'current', - disable_on_zoom = false, - mux = 'auto', - }) - end, - }, -} diff --git a/lua/plugins/whichkey.lua b/lua/plugins/whichkey.lua deleted file mode 100644 index 7bb67fe..0000000 --- a/lua/plugins/whichkey.lua +++ /dev/null @@ -1,307 +0,0 @@ -return { - 'folke/which-key.nvim', - event = 'VeryLazy', - config = function() - local wk = require('which-key') - wk.setup({ - preset = 'helix', - plugins = { - marks = true, - registers = true, - spelling = { - enabled = true, - suggestions = 30, - }, - }, - presets = { - operators = true, - motions = true, - text_objects = true, - windows = true, - nav = true, - z = true, - g = true, - }, - icons = { - breadcrumb = ' ', - separator = ' ', - group = '', - keys = { - Space = ' ', - }, - rules = false, -- enable auto icon rules - }, - show_help = false, - show_keys = true, - triggers = { - { '', mode = 'nvisoct' }, - { '', mode = { 'n', 'v' } }, - }, - }) - - local normal_mappings = { - mode = 'n', - { 'x', ':x', desc = ' Save and Quit' }, - - -- { "a", group = " AI" }, - - { 'b', group = ' Buffer' }, - - { 'c', group = ' Code' }, - { 'cF', ':retab', desc = 'Fix Tabs' }, - { 'cd', ':RootDir', desc = 'Root Directory' }, - { 'cf', ':lua vim.lsp.buf.format({async = true})', desc = 'Format File' }, - { 'cg', ':Neogen', desc = 'Generate Docstring' }, - { 'cl', '::g/^\\s*$/d', desc = 'Clean Empty Lines' }, - { 'cm', ':MarkdownPreviewToggle', desc = 'Markdown Preview' }, - { 'cq', ':lua Snacks.picker.qflist()', desc = 'Quickfix List' }, - - { 'e', group = ' Edit' }, - { 'ea', ':b#', desc = 'Alternate File' }, - { 'eC', group = 'Edit Configs' }, - { - 'ee', - function() - local minifiles = require('mini.files') - minifiles.open(vim.api.nvim_buf_get_name(0), true) - minifiles.reveal_cwd() - end, - desc = 'Explore Tree', - }, - { 'eE', ':lua Snacks.explorer()', desc = 'File Explorer' }, - { 'ef', 'gf', desc = 'File Under Cursor' }, - { 'em', ':e README.md', desc = 'Readme' }, - { 'en', ':enew', desc = 'New File' }, - { 'er', ":lua require('snacks').rename.rename_file()", desc = 'Rename Current File' }, - - { 'f', group = ' Find' }, - { 'fx', ':%bd|e#|bd#', desc = 'Close except current' }, - { 'ff', ':lua Snacks.picker.files()', desc = 'Find Files' }, - { 'fg', ':lua Snacks.picker.grep()', desc = 'Live Grep' }, - { 'fp', ':lua Snacks.picker.projects()', desc = 'Projects' }, - { - 'ct', - function() - local curr_path = vim.fn.expand('%:p') - Snacks.picker.todo_comments({ - transform = function(item) - local item_path = vim.fn.fnamemodify(item.cwd .. '/' .. item.file, ':p') - return item_path == curr_path - end, - }) - end, - desc = 'Search Todos in Current File', - }, - { 'fT', ':lua Snacks.picker.todo_comments()', desc = 'Search Todos' }, - { 'fu', ':lua Snacks.picker.undo()', desc = 'Undotree' }, - - { 'g', group = ' Git' }, - { 'gA', ':Gitsigns stage_buffer', desc = 'Stage Buffer' }, - { 'gR', ':Gitsigns reset_buffer', desc = 'Reset Buffer' }, - { 'ga', ':Gitsigns stage_hunk', desc = 'Stage Hunk' }, - { 'gb', ":lua require('gitsigns').blame_line({full = true})", desc = 'Blame' }, - { 'gB', ":lua require('snacks').git.blame_line()", desc = 'Detailed Blame' }, - { 'gc', ':Gitignore', desc = 'Generate .gitignore' }, - { 'gd', ':Gitsigns diffthis HEAD', desc = 'Git Diff' }, - { 'gF', ':Git', desc = 'Fugitive Panel' }, - { 'gi', ':Gitsigns preview_hunk', desc = 'Hunk Info' }, - { 'gj', ':Gitsigns next_hunk', desc = 'Next Hunk' }, - { 'gk', ':Gitsigns prev_hunk', desc = 'Prev Hunk' }, - { 'gl', ':lua Snacks.picker.git_log()', desc = 'Checkout commit' }, - { 'gr', ':Gitsigns reset_hunk', desc = 'Reset Hunk' }, - { 'gs', ':lua Snacks.picker.git_status()', desc = 'Open changed file' }, - { 'gu', ':Gitsigns undo_stage_hunk', desc = 'Undo Stage Hunk' }, - { 'gv', ':Gitsigns select_hunk', desc = 'Select Hunk' }, - { 'gw', ':lua require("snacks").gitbrowse()', desc = 'Git Browse' }, - { 'gp', ':lua Snacks.picker.git_branches()', desc = 'Pick and Switch Git Branches' }, - - { 'gt', group = 'Toggle' }, - { 'gtb', ':Gitsigns toggle_current_line_blame', desc = 'Blame' }, - { 'gtd', ':Gitsigns toggle_deleted', desc = 'Deleted' }, - { 'gtl', ':Gitsigns toggle_linehl', desc = 'Line HL' }, - { 'gtn', ':Gitsigns toggle_numhl', desc = 'Number HL' }, - { 'gts', ':Gitsigns toggle_signs', desc = 'Signs' }, - { 'gtw', ':Gitsigns toggle_word_diff', desc = 'Word Diff' }, - - { 'i', group = ' Insert' }, - { 'id', ":put =strftime('## %a, %d %b, %Y, %r')", desc = 'Date' }, - { 'if', ":put =expand('%:t')", desc = 'File Name' }, - { 'ip', ':put %', desc = 'Relative Path' }, - { 'iP', ':put %:p', desc = 'Absolute Path' }, - { 'it', ":put =strftime('## %r')", desc = 'Time' }, - - { 'l', group = ' LSP' }, - { 'la', ':Lspsaga code_action', desc = 'Code Action' }, - { 'ld', ':Lspsaga goto_definition', desc = 'Goto Definition' }, - { 'lf', ':Lspsaga finder', desc = 'Finder' }, - { 'lh', ':Lspsaga hover_doc', desc = 'Hover' }, - { 'lI', ':LspInfo', desc = 'LSP Info' }, - { 'lj', ':Lspsaga diagnostic_jump_next', desc = 'Next Diagnostic' }, - { 'lk', ':Lspsaga diagnostic_jump_prev', desc = 'Prev Diagnostic' }, - { 'lo', ':Lspsaga outline', desc = 'Outline' }, - { 'lp', ':Lspsaga peek_definition', desc = 'Peek Definition' }, - { 'lq', ':LspStop', desc = 'Stop LSP' }, - { 'lQ', ':LspRestart', desc = 'Restart LSP' }, - { 'lr', ':Lspsaga rename', desc = 'Rename' }, - { 'lR', ':Lspsaga project_replace', desc = 'Replace' }, - { 'lt', ':Lspsaga goto_type_definition', desc = 'Goto Type Definition' }, - { 'lT', ':Lspsaga peek_type_definition', desc = 'Peek Type Definition' }, - - { 'o', group = ' Options' }, - { 'oi', 'vim.show_pos', desc = 'Inspect Position' }, - { 'oN', ':lua Snacks.notifier.show_history()', desc = 'Notification History' }, - { 'or', ':set relativenumber!', desc = 'Relative Numbers' }, - - { 'p', group = ' Packages' }, - { 'pc', ':Lazy check', desc = 'Check' }, - { 'pd', ':Lazy debug', desc = 'Debug' }, - { 'pe', ':lua require("snacks").profiler.scratch()', desc = 'Profiler Scratch' }, - { 'pf', ':lua require("snacks").profiler.pick()', desc = 'Profiler Pick' }, - { 'pi', ':Lazy install', desc = 'Install' }, - { 'pl', ':Lazy log', desc = 'Log' }, - { 'pm', ':Mason', desc = 'Mason' }, - { 'pp', ':Lazy', desc = 'Plugins' }, - { 'pP', ':Lazy profile', desc = 'Profile' }, - { 'pr', ':Lazy restore', desc = 'Restore' }, - { 'ps', ':Lazy sync', desc = 'Sync' }, - { 'pt', ':lua require("snacks").profiler.toggle()', desc = 'Profiler Toggle' }, - { 'pu', ':Lazy update', desc = 'Update' }, - { 'px', ':Lazy clean', desc = 'Clean' }, - - { 'q', group = ' Quit' }, - { 'qa', ':qall', desc = 'Quit All' }, - { 'qb', ':bw', desc = 'Close Buffer' }, - { 'qd', ':lua require("snacks").bufdelete()', desc = 'Delete Buffer' }, - { 'qf', ':qall!', desc = 'Force Quit' }, - { 'qo', ':%bdelete|b#|bdelete#', desc = 'Close Others' }, - { 'qq', ':q', desc = 'Quit' }, - { 'qs', 'c', desc = 'Close Split' }, - { 'qw', ':wq', desc = 'Write and Quit' }, - - { 'r', group = ' Refactor' }, - { 'rd', '', desc = 'Go To Definition' }, -- treesitter navigation - { 'rD', '', desc = 'List Definition' }, - { 'rh', '', desc = 'List Definition Head' }, - { 'rj', '', desc = 'Next Usage' }, - { 'rk', '', desc = 'Previous Usage' }, - { 'rn', '', desc = 'Swap Next' }, - { 'rp', '', desc = 'Swap Previous' }, - { 'rr', '', desc = 'Smart Rename' }, - { 'rs', ':%s/\\<\\>//gI', desc = 'Replace Word Buffer' }, - - { 's', group = ' Split' }, - { 's+', ':resize +10', desc = 'Increase window height' }, - { 's-', ':vertical resize -20', desc = 'Decrease window width' }, - { 's/', 's', desc = 'Split Below' }, - { 's=', ':vertical resize +20', desc = 'Increase window width' }, - { 'sH', ':vertical resize -10', desc = 'Decrease window width' }, - { 'sJ', ':resize -5', desc = 'Decrease window height' }, - { 'sK', ':resize +5', desc = 'Increase window height' }, - { 'sL', ':vertical resize +10', desc = 'Increase window width' }, - { 's\\', 'v', desc = 'Split Right' }, - { 's_', ':resize -10', desc = 'Decrease window height' }, - { 's`', 'p', desc = 'Previous Window' }, - { 'sa', ':split', desc = 'Horizontal Split' }, - { 'sc', ':tabclose', desc = 'Close Tab' }, - { 'sf', ':tabfirst', desc = 'First Tab' }, - { 'sh', 'h', desc = 'Move Left' }, - { 'sj', 'j', desc = 'Move Down' }, - { 'sk', 'k', desc = 'Move Up' }, - { 'sl', 'l', desc = 'Move Right' }, - { 'sq', 'c', desc = 'Close Split' }, - { 'ss', ':vsplit', desc = 'Vertical Split' }, - - { 't', group = ' Terminal' }, - { 't1', '1ToggleTerm', desc = 'Toggle Terminal' }, - { 't2', '2ToggleTerm', desc = 'Toggle Terminal' }, - { 'tc', 'close', desc = 'Hide Terminal' }, - { 'th', group = 'Inlay Hints' }, - - { 'w', group = ' Writing' }, - { 'wc', ':set spell!', desc = 'Spellcheck' }, - { 'wd', ':lua require("snacks").dim.enable()', desc = 'Dim On' }, - { 'wD', ':lua require("snacks").dim.disable()', desc = 'Dim Off' }, - { 'wf', ":lua require'utils'.sudo_write()", desc = 'Force Write' }, - { 'wj', ']s', desc = 'Next Misspell' }, - { 'wk', '[s', desc = 'Prev Misspell' }, - { 'wn', ':WriteNoFormat', desc = 'Write Without Formatting' }, - { 'wq', ':wq', desc = 'Write and Quit' }, - { 'ww', ':w', desc = 'Write' }, - { 'wz', ':lua require("snacks").zen.zen()', desc = 'Zen' }, - { 'wZ', ':lua require("snacks").zen.zoom()', desc = 'Zoom' }, - - { 'y', group = ' Yank' }, - { 'yL', ':CopyAbsolutePathWithLine', desc = 'Absolute Path with Line' }, - { 'yP', ':CopyAbsolutePath', desc = 'Absolute Path' }, - { 'ya', ':%y+', desc = 'Copy Whole File' }, - { 'yf', ':CopyFileName', desc = 'File Name' }, - { 'yg', ':lua require"gitlinker".get_buf_range_url()', desc = 'Copy Git URL' }, - { 'yl', ':CopyRelativePathWithLine', desc = 'Relative Path with Line' }, - { 'yp', ':CopyRelativePath', desc = 'Relative Path' }, - } - - local visual_mappings = { - mode = 'v', - -- { "a", group = " AI" }, - - { 'c', group = ' Code' }, - { 'cS', ':sort!', desc = 'Sort Desc' }, - { 'ci', ':sort i', desc = 'Sort Case Insensitive' }, - { 'cs', ':sort', desc = 'Sort Asc' }, - { 'cu', ':!uniq', desc = 'Unique' }, - { 'cx', ':lua', desc = 'Execute Lua' }, - - { 'g', group = ' Git' }, - { 'ga', ":'<,'>Gitsigns stage_hunk", desc = 'Stage Hunk' }, - { 'gr', ":'<,'>Gitsigns reset_hunk", desc = 'Reset Hunk' }, - { 'gu', ":'<,'>Gitsigns undo_stage_hunk", desc = 'Undo Stage Hunk' }, - - { 'l', group = ' LSP' }, - { 'la', ':Lspsaga range_code_action', desc = 'Code Action' }, - - { 'o', group = ' Options' }, - { 'oc', ':CodeSnap', desc = 'CodeSnap into clipboard' }, - { 'oC', ':CodeSnapSave', desc = 'CodeSnap in ~/Pictures' }, - - { 'y', group = ' Yank' }, - { 'yg', ':lua require"gitlinker".get_buf_range_url("v")', desc = 'Copy Git URL' }, - } - - local no_leader_mappings = { - mode = 'n', - { '', ':resize -10', desc = 'Decrease window height' }, - { '', ':vertical resize -10', desc = 'Decrease window width' }, - { '', ':vertical resize +10', desc = 'Increase window width' }, - { '', ':resize +10', desc = 'Increase window height' }, - - { '', ':NavigatorLeft', desc = 'Move Left' }, - { '', ':NavigatorDown', desc = 'Move Down' }, - { '', ':NavigatorUp', desc = 'Move Up' }, - { '', ':NavigatorRight', desc = 'Move Right' }, - { '', ':NavigatorPrevious', desc = 'Previous Pane' }, - - -- { '', ':bprevious', desc = 'Previous Buffer' }, - -- { '', ':bnext', desc = 'Next Buffer' }, - { '', ':bnext', desc = 'Next Buffer' }, - { '', ':bprevious', desc = 'Previous Buffer' }, - - { 'K', ':Lspsaga hover_doc', desc = 'LSP Hover' }, - { 'Q', ':qall!', desc = 'Force Quit!' }, - { 'U', ':redo', desc = 'Redo' }, - - { '[', group = ' Previous' }, - { '[g', ':Gitsigns prev_hunk', desc = 'Git Hunk' }, - { '[o', group = 'Textobjects' }, - - { ']', group = ' Next' }, - { ']g', ':Gitsigns next_hunk', desc = 'Git Hunk' }, - { ']o', group = 'Textobjects' }, - - { 'gd', ':Lspsaga goto_definition', desc = 'Goto Definition' }, - } - - wk.add(normal_mappings) - wk.add(visual_mappings) - wk.add(no_leader_mappings) - end, -} diff --git a/nvim-pack-lock.json b/nvim-pack-lock.json new file mode 100644 index 0000000..90d74cd --- /dev/null +++ b/nvim-pack-lock.json @@ -0,0 +1,184 @@ +{ + "plugins": { + "Comment.nvim": { + "rev": "e30b7f2008e52442154b66f7c519bfd2f1e32acb", + "src": "https://github.com/numToStr/Comment.nvim" + }, + "Lspsaga.nvim": { + "rev": "e6c04f88836d79f2fd7e46fd170e7ee986c789d4", + "src": "https://github.com/nvimdev/Lspsaga.nvim" + }, + "LuaSnip": { + "rev": "a62e1083a3cfe8b6b206e7d3d33a51091df25357", + "src": "https://github.com/L3MON4D3/LuaSnip" + }, + "Navigator.nvim": { + "rev": "91d86506ac2a039504d5205d32a1d4bc7aa57072", + "src": "https://github.com/numToStr/Navigator.nvim" + }, + "bento.nvim": { + "rev": "aee8a542bc1839ff1764992ef2aa41c981d0bba4", + "src": "https://github.com/serhez/bento.nvim" + }, + "better-escape.nvim": { + "rev": "3f4bc0b326606264ff75967f59091b5ddada0554", + "src": "https://github.com/max397574/better-escape.nvim" + }, + "blink.cmp": { + "rev": "d3874d2a13aa19b095bdd10d37a82a8f0aa7cad3", + "src": "https://github.com/saghen/blink.cmp", + "version": "'v0.*'" + }, + "blink.lib": { + "rev": "f29d8bac6549bc1e7d699c83f680823d7def98bd", + "src": "https://github.com/saghen/blink.lib" + }, + "conform.nvim": { + "rev": "dca1a190aa85f9065979ef35802fb77131911106", + "src": "https://github.com/stevearc/conform.nvim" + }, + "friendly-snippets": { + "rev": "6cd7280adead7f586db6fccbd15d2cac7e2188b9", + "src": "https://github.com/rafamadriz/friendly-snippets" + }, + "gitignore": { + "rev": "0344f643768c4d64af4add8c1bdddf6f7d4c9010", + "src": "https://github.com/wintermute-cell/gitignore.nvim" + }, + "gitignore.nvim": { + "rev": "0344f643768c4d64af4add8c1bdddf6f7d4c9010", + "src": "https://github.com/wintermute-cell/gitignore.nvim" + }, + "gitsigns.nvim": { + "rev": "dd3f588bacbeb041be6facf1742e42097f62165d", + "src": "https://github.com/lewis6991/gitsigns.nvim" + }, + "gruvbox.nvim": { + "rev": "154eb5ff5b96d0641307113fa385eaf0d36d9796", + "src": "https://github.com/ellisonleao/gruvbox.nvim" + }, + "guess-indent.nvim": { + "rev": "84a4987ff36798c2fc1169cbaff67960aed9776f", + "src": "https://github.com/NMAC427/guess-indent.nvim" + }, + "hardtime.nvim": { + "rev": "b4e431934af1fe224a3a801f632c008278cb7628", + "src": "https://github.com/m4xshen/hardtime.nvim" + }, + "indent-blankline.nvim": { + "rev": "d28a3f70721c79e3c5f6693057ae929f3d9c0a03", + "src": "https://github.com/lukas-reineke/indent-blankline.nvim" + }, + "markview.nvim": { + "rev": "dbf74b6db11c1468d5128a38b26b6d99dc7316e9", + "src": "https://github.com/OXY2DEV/markview.nvim" + }, + "mason-conform.nvim": { + "rev": "48da2ebd5efbaf8a99566eadc3ece82d523f03c5", + "src": "https://github.com/zapling/mason-conform.nvim" + }, + "mason-lspconfig.nvim": { + "rev": "1423254f58a3407a5afd5ade0ccd901f3eecc6ba", + "src": "https://github.com/mason-org/mason-lspconfig.nvim", + "version": "'main'" + }, + "mason-nvim-lint": { + "rev": "cafbc5d82d8eb4af0daf0057332a325ddf2f436b", + "src": "https://github.com/rshkarin/mason-nvim-lint" + }, + "mason.nvim": { + "rev": "cb8445f8ce85d957416c106b780efd51c6298f89", + "src": "https://github.com/mason-org/mason.nvim", + "version": "'main'" + }, + "mdx.nvim": { + "rev": "6c3dc7c4a4b58b5d86404c21a9b4655282ca08c5", + "src": "https://github.com/davidmh/mdx.nvim" + }, + "mini.nvim": { + "rev": "48555f1615f08c6318150aacb52bf7d61a5af798", + "src": "https://github.com/nvim-mini/mini.nvim" + }, + "neodim": { + "rev": "1b8bda59a53b49ec2b59885e9fe78f8e90a1de76", + "src": "https://github.com/zbirenbaum/neodim" + }, + "neoscroll.nvim": { + "rev": "c8d29979cb0cb3a2437a8e0ae683fd82f340d3b8", + "src": "https://github.com/karb94/neoscroll.nvim" + }, + "nvim-autopairs": { + "rev": "59bce2eef357189c3305e25bc6dd2d138c1683f5", + "src": "https://github.com/windwp/nvim-autopairs" + }, + "nvim-highlight-colors": { + "rev": "e4c7af0211866162d999ce0bdd6a029302e19139", + "src": "https://github.com/brenoprata10/nvim-highlight-colors" + }, + "nvim-lint": { + "rev": "eab58b48eb11d7745c11c505e0f3057165902461", + "src": "https://github.com/mfussenegger/nvim-lint" + }, + "nvim-lspconfig": { + "rev": "cd576dd72d31ddffcbfa6d064c0dd697ca218758", + "src": "https://github.com/neovim/nvim-lspconfig" + }, + "nvim-treesitter": { + "rev": "4916d6592ede8c07973490d9322f187e07dfefac", + "src": "https://github.com/nvim-treesitter/nvim-treesitter" + }, + "nvim-ts-autotag": { + "rev": "88c1453db4ba7dd24131086fe51fdf74e587d275", + "src": "https://github.com/windwp/nvim-ts-autotag" + }, + "smartcolumn.nvim": { + "rev": "b9cdbdf42f7ac5a659204cd5926017c7ff724a19", + "src": "https://github.com/m4xshen/smartcolumn.nvim" + }, + "snacks.nvim": { + "rev": "ad9ede6a9cddf16cedbd31b8932d6dcdee9b716e", + "src": "https://github.com/folke/snacks.nvim" + }, + "suda.vim": { + "rev": "c492741b4679b3cdd4d9e34138209784e061d916", + "src": "https://github.com/lambdalisue/suda.vim" + }, + "tiny-code-action.nvim": { + "rev": "0d040ed81f7953118b81cd12681fcdfcac069803", + "src": "https://github.com/rachartier/tiny-code-action.nvim" + }, + "tiny-glimmer.nvim": { + "rev": "cc285167914e947fc130523d02927fdaf24636a6", + "src": "https://github.com/rachartier/tiny-glimmer.nvim" + }, + "tiny-inline-diagnostic.nvim": { + "rev": "147af4e49f51dd48f41972de26552872b8ba7b25", + "src": "https://github.com/rachartier/tiny-inline-diagnostic.nvim" + }, + "todo-comments.nvim": { + "rev": "31e3c38ce9b29781e4422fc0322eb0a21f4e8668", + "src": "https://github.com/folke/todo-comments.nvim" + }, + "toggleterm.nvim": { + "rev": "9a88eae817ef395952e08650b3283726786fb5fb", + "src": "https://github.com/akinsho/toggleterm.nvim", + "version": "'*'" + }, + "vim-visual-multi": { + "rev": "a6975e7c1ee157615bbc80fc25e4392f71c344d4", + "src": "https://github.com/mg979/vim-visual-multi" + }, + "vim-wakatime": { + "rev": "24495fb7cc9613eaf0ce45540fb8d096a30d08e9", + "src": "https://github.com/wakatime/vim-wakatime" + }, + "which-key.nvim": { + "rev": "3aab2147e74890957785941f0c1ad87d0a44c15a", + "src": "https://github.com/folke/which-key.nvim" + }, + "windsurf.vim": { + "rev": "3c0a4f8a7be75113a6e19be13b7cc37210d6e26a", + "src": "https://github.com/Exafunction/windsurf.vim" + } + } +} diff --git a/plugin/00-colorscheme.lua b/plugin/00-colorscheme.lua new file mode 100644 index 0000000..ce5a106 --- /dev/null +++ b/plugin/00-colorscheme.lua @@ -0,0 +1,34 @@ +add("ellisonleao/gruvbox.nvim") + +local palette = require("gruvbox").palette +require("gruvbox").setup({ + bold = false, + italic = { + strings = false, + emphasis = false, + comments = false, + folds = false, + }, + contrast = "hard", + transparent_mode = true, + overrides = { + -- builtin + SignColumn = { bg = "None" }, + CursorLineNr = { bg = "None" }, + Whitespace = { fg = palette.dark0 }, + EndOfBuffer = { fg = palette.dark0_hard }, + Visual = { fg = "None", bg = palette.dark1 }, + Label = { link = "GruvboxPurple" }, + + -- blink.cmp + BlinkCmpMenu = { link = "Normal" }, + BlinkCmpMenuBorder = { link = "BlinkCmpMenu" }, + BlinkCmpMenuSelection = { fg = "None", bg = palette.dark1 }, + BlinkCmpLabelMatch = { fg = palette.bright_green }, + BlinkCmpScrollBarGutter = { bg = palette.dark2 }, + BlinkCmpScrollBarThumb = { bg = palette.light1 }, + + -- indent guides + MiniIndentscopeSymbol = { fg = palette.dark1 }, + }, +}) diff --git a/plugin/01-lsp.lua b/plugin/01-lsp.lua new file mode 100644 index 0000000..470c893 --- /dev/null +++ b/plugin/01-lsp.lua @@ -0,0 +1,74 @@ +add({ + { src = "mason-org/mason.nvim", version = "main" }, -- lsp installer manager + { src = "mason-org/mason-lspconfig.nvim", version = "main" }, -- lsp installer + "neovim/nvim-lspconfig", -- lsp config + "nvimdev/Lspsaga.nvim", -- lsp ui + "rachartier/tiny-inline-diagnostic.nvim", -- inline diagnostic + "rachartier/tiny-code-action.nvim", -- code action +}) + +-- lsp installer +require("mason").setup({ + ui = { + icons = { + package_installed = "✓", + package_pending = "➜", + package_uninstalled = "✗", + }, + border = "rounded", + backdrop = 100, + }, +}) + +require("mason-lspconfig").setup({ + ensure_installed = require("extensions").lsp_server, + automatic_installation = false, -- Don't auto-install or auto-configure +}) + +-- improve neovim lsp experience +vim.api.nvim_create_autocmd("LspAttach", { + callback = function() + require("lspsaga").setup({ + ui = { + theme = "round", + border = "rounded", + devicon = true, + title = true, + winblend = 1, + expand = " ", + collapse = " ", + preview = "", + code_action = "󰠠 ", + diagnostic = " ", + incoming = " ", + outgoing = " ", + hover = " ", + }, + }) + + --inline diagnostic + require("tiny-inline-diagnostic").setup({ + options = { + show_source = true, + multiple_diag_under_cursor = true, + }, + }) + + --code action + require("tiny-code-action").setup({ + picker = { + "buffer", + opts = { + auto_preview = true, + hotkeys = true, + hotkeys_mode = "sequential", + }, + }, + }) + end, +}) + +vim.diagnostic.config({ virtual_text = false }) -- Disable default virtual text +vim.keymap.set("n", ".", function() + require("tiny-code-action").code_action() +end, { desc = "Code action" }) diff --git a/plugin/code_quality.lua b/plugin/code_quality.lua new file mode 100644 index 0000000..5804022 --- /dev/null +++ b/plugin/code_quality.lua @@ -0,0 +1,82 @@ +add({ + "mfussenegger/nvim-lint", -- linter + "rshkarin/mason-nvim-lint", -- linter installer + "stevearc/conform.nvim", -- autoformater + "zapling/mason-conform.nvim", -- formatter installer +}) + +-- linter +require("lint").linters_by_ft = { + ["*"] = { "codespell" }, + ["javascript"] = { "eslint_d", "cspell" }, + ["typescript"] = { "eslint_d", "cspell" }, + ["javascriptreact"] = { "eslint_d", "cspell" }, + ["typescriptreact"] = { "eslint_d", "cspell" }, + ["dockerfile"] = { "hadolint" }, + ["markdown"] = { "write_good", "markdownlint" }, + ["text"] = { "write_good" }, + ["sh"] = { "shellcheck" }, + ["yaml"] = { "actionlint" }, + ["python"] = { "ruff" }, +} +require("mason-nvim-lint").setup({ + ensure_installed = require("extensions").linter, + automatic_installation = false, +}) + +-- formatter +require("conform").setup({ + formatters = { + ["markdown-toc"] = { + condition = function(_, ctx) + for _, line in ipairs(vim.api.nvim_buf_get_lines(ctx.buf, 0, -1, false)) do + if line:find("") then + return true + end + end + end, + }, + ["markdownlint-cli2"] = { + condition = function(_, ctx) + local diag = vim.tbl_filter(function(d) + return d.source == "markdownlint" + end, vim.diagnostic.get(ctx.buf)) + return #diag > 0 + end, + }, + }, + formatters_by_ft = { + ["lua"] = { "stylua" }, + ["c"] = { "clang_format" }, + ["cpp"] = { "clang_format" }, + ["h"] = { "clang_format" }, + ["python"] = { "ruff_fix", "ruff_format", "ruff_organize_imports" }, + ["javascript"] = { "biome" }, + ["typescript"] = { "biome" }, + ["typescriptreact"] = { "biome" }, + ["markdown"] = { "prettier", "markdownlint-cli2", "markdown-toc" }, + ["markdown.mdx"] = { "prettier", "markdownlint-cli2", "markdown-toc" }, + ["mdx"] = { "prettier" }, + ["_"] = { "trim_whitespace" }, + }, + options = { + stop_after_first = true, + }, + format_after_save = function(bufnr) + if not vim.b[bufnr].conform_disable then + return { + lsp_format = "fallback", + } + end + end, +}) + +vim.keymap.set("n", "tf", function() + vim.b.conform_disable = not vim.b.conform_disable + local status = vim.b.conform_disable and "disabled" or "enabled" + vim.notify("Autoformat " .. status, vim.log.levels.INFO) +end, { desc = "Toggle autoformat" }) +require("mason-conform").setup({ + ensure_installed = require("extensions").formatter, + automatic_installation = true, +}) diff --git a/plugin/completion.lua b/plugin/completion.lua new file mode 100644 index 0000000..c18c6ee --- /dev/null +++ b/plugin/completion.lua @@ -0,0 +1,75 @@ +add({ + "saghen/blink.lib", + { src = "saghen/blink.cmp", version = "v0.*" }, + "L3MON4D3/LuaSnip", + "rafamadriz/friendly-snippets", +}) + +require("blink.cmp").setup({ + fuzzy = { implementation = "prefer_rust" }, + snippets = { preset = "luasnip" }, + sources = { + default = { "lsp", "path", "snippets", "buffer" }, + providers = {}, + }, + + completion = { + ghost_text = { enabled = true }, + + list = { + selection = { + preselect = false, + auto_insert = true, + }, + }, + documentation = { + window = { border = "rounded" }, + auto_show = true, + auto_show_delay_ms = 50, + }, + menu = { + border = "rounded", + draw = { + components = { + kind_icon = { + text = function(ctx) + local kind_icon, _, _ = require("mini.icons").get("lsp", ctx.kind) + return kind_icon + end, + highlight = function(ctx) + local _, hl, _ = require("mini.icons").get("lsp", ctx.kind) + return hl + end, + }, + kind = { + highlight = function(ctx) + local _, hl, _ = require("mini.icons").get("lsp", ctx.kind) + return hl + end, + }, + }, + }, + }, + }, + signature = { + window = { border = "rounded" }, + }, + keymap = { + preset = "none", + [""] = { "select_prev", "snippet_backward", "fallback" }, + [""] = { "select_next", "snippet_forward", "fallback" }, + [""] = { "accept", "fallback" }, + [""] = { "hide", "show" }, + [""] = { "show", "show_documentation", "hide_documentation" }, + [""] = { "scroll_documentation_up", "fallback" }, + [""] = { "scroll_documentation_down", "fallback" }, + }, +}) + +local luasnip = require("luasnip") +require("luasnip.loaders.from_vscode").lazy_load() +require("luasnip.loaders.from_vscode").lazy_load({ + paths = { vim.fn.stdpath("config") .. "/snippets" }, +}) + +luasnip.filetype_extend("mdx", { "markdown" }) diff --git a/plugin/editor.lua b/plugin/editor.lua new file mode 100644 index 0000000..7f5783f --- /dev/null +++ b/plugin/editor.lua @@ -0,0 +1,72 @@ +add({ + "windwp/nvim-autopairs", -- autopairs + "windwp/nvim-ts-autotag", -- autotag + "folke/todo-comments.nvim", -- todo comment highlights + "wakatime/vim-wakatime", --wakaTime coding time tracker + "lambdalisue/suda.vim", -- edit files as sudo (:SudaWrite) + "numToStr/Comment.nvim", -- smart comment toggling + "NMAC427/guess-indent.nvim", -- auto-detect tab/space indentation + "brenoprata10/nvim-highlight-colors", -- color highlighting + "davidmh/mdx.nvim", -- syntax highlighter for mdx + "nvim-treesitter/nvim-treesitter", -- nvim-treesitter + "Exafunction/windsurf.vim", -- windsurf ai for autocompletion + "numToStr/Navigator.nvim", -- navigator + "m4xshen/hardtime.nvim", -- workflow + "lukas-reineke/indent-blankline.nvim", --indent guides + "mg979/vim-visual-multi", -- multiple cursors +}) + +vim.g.VM_maps = { + ["Find Under"] = "", -- Alt + d | Select word under cursor and start multi-cursor + ["Find Subword Under"] = "", -- Alt + d | Select subword under cursor + ["Select All"] = "", -- Ctrl + Alt + d | Select all occurrences in the buffer + ["Add Cursor Down"] = "", -- Ctrl + Alt + j | Add a cursor on the line below + ["Add Cursor Up"] = "", -- Ctrl + Alt + k | Add a cursor on the line above +} + +-- lazy load insert mode enhancements +vim.api.nvim_create_autocmd("InsertEnter", { + callback = function() + require("nvim-autopairs").setup({}) + require("nvim-ts-autotag").setup({}) + end, + once = true, +}) + +-- lazy load general editor enhancements +vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile" }, { + callback = function() + require("todo-comments").setup({ signs = false }) + require("Comment").setup() + require("guess-indent").setup({}) + require("nvim-highlight-colors").setup({ render = "background" }) + require("Navigator").setup({ + auto_save = "current", + disable_on_zoom = false, + mux = "auto", + }) + end, +}) + +require("hardtime").setup({}) +require("ibl").setup({}) + +require("nvim-treesitter").setup({ + ensure_installed = require("extensions").ts_parsers, + auto_install = true, + highlight = { + enable = true, + additional_vim_regex_highlighting = true, + }, + indent = { + enable = true, + }, +}) + +-- windsurf +vim.keymap.set("i", "", function() + return vim.fn["codeium#Accept"]() +end, { expr = true, silent = true }) +vim.keymap.set("i", "", function() + return vim.fn["codeium#Clear"]() +end, { expr = true, silent = true }) diff --git a/plugin/git.lua b/plugin/git.lua new file mode 100644 index 0000000..74cdca3 --- /dev/null +++ b/plugin/git.lua @@ -0,0 +1,34 @@ +add({ + "lewis6991/gitsigns.nvim", + "wintermute-cell/gitignore.nvim", -- .gitignore generator +}) + +vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + callback = function() + require("gitsigns").setup({ + signcolumn = true, + current_line_blame = true, + attach_to_untracked = false, + current_line_blame_formatter = ", - ", + watch_gitdir = { + follow_files = true, + }, + current_line_blame_opts = { + virt_text = true, + virt_text_pos = "eol", -- 'eol' | 'overlay' | 'right_align' + delay = 1000, + ignore_whitespace = false, + virt_text_priority = 100, + use_focus = true, + }, + signs = { + add = { text = " " }, + change = { text = "󱗜 " }, + delete = { text = "󰍵 " }, + topdelete = { text = "󱥨 " }, + changedelete = { text = "󰾟 " }, + untracked = { text = "󰰧 " }, + }, + }) + end, +}) diff --git a/plugin/mini.lua b/plugin/mini.lua new file mode 100644 index 0000000..23d603c --- /dev/null +++ b/plugin/mini.lua @@ -0,0 +1,153 @@ +add("echasnovski/mini.nvim") + +require("mini.ai").setup() -- extend and create a/i textobjects +require("mini.pairs").setup() -- autopairs +require("mini.icons").setup() -- icons +require("mini.bracketed").setup() -- go forward/backward with square brackets + +-- File explorer +require("mini.files").setup({ + mappings = { + close = "q", + go_in = "L", + go_in_plus = "l", + go_out = "h", + go_out_plus = "H", + mark_goto = "'", + mark_set = "m", + reset = "", + reveal_cwd = "@", + show_help = "g?", + synchronize = "", + trim_left = "<", + trim_right = ">", + }, +}) + +require("mini.misc").setup({ + -- restore cursor position on file reopen + require("mini.misc").setup_restore_cursor(), + -- automated change of current directory + require("mini.misc").setup_auto_root(), +}) + +-- splitjoin +require("mini.splitjoin").setup({ + mappings = { + toggle = "tj", + split = "", + join = "", + }, +}) + +-- surround action +require("mini.surround").setup({ + mappings = { + add = "msa", + delete = "msd", + find = "msf", + find_left = "msF", + highlight = "msh", + replace = "msr", + update_n_lines = "msn", + + suffix_last = "l", + suffix_next = "n", + }, +}) + +-- indents +require("mini.indentscope").setup({ + draw = { animation = require("mini.indentscope").gen_animation.linear({ ease = "out", duration = 15 }) }, + options = { border = "top", try_as_border = true, indent_at_cursor = false }, +}) + +vim.api.nvim_create_autocmd("BufEnter", { + pattern = "*", + callback = function(args) + if vim.bo[args.buf].buftype ~= "" then + vim.b[args.buf].miniindentscope_disable = true + end + end, +}) + +-- statusline +require("mini.statusline").setup({ + use_icons = true, + content = { + active = function() + local mode, mode_hl = MiniStatusline.section_mode({ trunc_width = 120 }) + local git = MiniStatusline.section_git({ trunc_width = 40 }) + local diff = MiniStatusline.section_diff({ trunc_width = 80 }) + local diagnostics = MiniStatusline.section_diagnostics({ trunc_width = 60 }) + local lsp = MiniStatusline.section_lsp({ trunc_width = 40 }) + local filename = MiniStatusline.section_filename({ trunc_width = 140 }) + + local function section_filetype(args) + if MiniStatusline.is_truncated(args.trunc_width) or vim.bo.filetype == "" or vim.bo.buftype ~= "" then + return "" + end + local ok, icons = pcall(require, "mini.icons") + local icon = ok and select(1, icons.get("filetype", vim.bo.filetype)) or "" + return string.format("%s %s│", icon, vim.bo.filetype) + end + + local function section_lsp_clients(args) + if MiniStatusline.is_truncated(args.trunc_width) then + return "" + end + local clients = vim.lsp.get_clients({ bufnr = 0 }) + if not clients or #clients == 0 then + return "" + end + local names = vim.tbl_map(function(c) + return c.name + end, clients) + return string.format(" %s", table.concat(names, ", ")) + end + + local function section_searchcount(args) + if vim.v.hlsearch == 0 then + return "" + end + local ok, s = pcall(vim.fn.searchcount, { recompute = true }) + if not ok or s.current == nil or s.total == 0 then + return "" + end + local icon = MiniStatusline.is_truncated(args.trunc_width) and "" or " " + if s.incomplete == 1 then + return icon .. "?/?│" + end + local fmt = ">%d" + local cur = s.current > s.maxcount and fmt:format(s.maxcount) or s.current + local tot = s.total > s.maxcount and fmt:format(s.maxcount) or s.total + return ("%s%s/%s│"):format(icon, cur, tot) + end + + local function section_location(args) + return MiniStatusline.is_truncated(args.trunc_width) and "%-2l│%-2v" or "󰉸 %-2l│󱥖 %-2v" + end + + local filetype = section_filetype({ trunc_width = 70 }) + local searchcount = section_searchcount({ trunc_width = 80 }) + local loc = section_location({ trunc_width = 120 }) + local lsp_clients = section_lsp_clients({ trunc_width = 60 }) + + return MiniStatusline.combine_groups({ + { hl = mode_hl, strings = { mode:upper() } }, + { hl = "MiniStatuslineDevinfo", strings = { git, diff, diagnostics, lsp } }, + "%<", + { hl = "MiniStatuslineFilename", strings = { filename } }, + "%=", + { hl = "MiniStatuslineDevinfo", strings = { lsp_clients } }, + { hl = mode_hl, strings = { filetype, searchcount, loc } }, + }) + end, + + inactive = function() + return MiniStatusline.combine_groups({ + { hl = "MiniStatuslineInactive", strings = { vim.fn.expand("%:t") } }, + }) + end, + }, +}) diff --git a/plugin/snacks.lua b/plugin/snacks.lua new file mode 100644 index 0000000..060928c --- /dev/null +++ b/plugin/snacks.lua @@ -0,0 +1,367 @@ +add("folke/snacks.nvim") + +local function files_layout(preview_width, height, width) + preview_width = preview_width or 0.6 + height = height or 0.8 + width = width or 0.9 + return { + layout = { + box = "horizontal", + width = width, + min_width = 120, + height = height, + { + box = "vertical", + border = "rounded", + title = "{title} {live} {flags}", + { win = "input", height = 1, border = "bottom" }, + { win = "list", border = "none" }, + }, + { win = "preview", title = "{preview}", border = "rounded", width = preview_width }, + }, + } +end + +local function palette_layout(height, width) + height = height or 0.4 + width = width or 0.6 + return { + preview = false, + layout = { + backdrop = false, + row = 1, + width = width, + min_width = 80, + height = height, + border = "rounded", + box = "vertical", + { + win = "input", + height = 1, + border = "rounded", + title = "{title} {live} {flags}", + title_pos = "center", + }, + { win = "list", border = "hpad" }, + { win = "preview", title = "{preview}", border = "rounded" }, + }, + } +end + +local Snacks = require("snacks") +Snacks.setup({ + animate = { + enabled = true, + duration = 20, -- ms per step + easing = "linear", + fps = 60, + }, + bigfile = { + enabled = true, + notify = true, + size = 1000 * 1024, -- 1 MB instead of 100 KB + }, + bufdelete = { enabled = true }, + dashboard = { + preset = { + header = [[ +░█░█░█▀▀░█░█░█▀▀░█▀█░█▀▄░█▀▀░█░█ +░█▀▄░█▀▀░░█░░█░░░█░█░█░█░█▀▀░▄▀▄ +░▀░▀░▀▀▀░░▀░░▀▀▀░▀▀▀░▀▀░░▀▀▀░▀░▀ + ]], + }, + sections = { + { section = "header" }, + { + icon = " ", + title = "Keymaps", + section = "keys", + indent = 2, + padding = 1, + }, + { + icon = " ", + title = "Recent Files", + section = "recent_files", + indent = 2, + padding = 1, + }, + { + icon = " ", + title = "Projects", + section = "projects", + indent = 2, + padding = 1, + }, + + }, + }, + debug = { enabled = true }, + dim = { + enabled = true, + scope = { + min_size = 5, + max_size = 20, + siblings = true, + }, + }, + explorer = { enabled = false }, + projects = { + dirs = { + "~/Project", + "~/.config/Modus" + } + }, + git = { enabled = true }, + gitbrowse = { enabled = true }, + image = { enabled = true }, + indent = { + enabled = true, + priority = 1, + char = "▍", + only_scope = false, + only_current = false, + hl = { + "SnacksIndent1", + "SnacksIndent2", + "SnacksIndent3", + "SnacksIndent4", + "SnacksIndent5", + "SnacksIndent6", + "SnacksIndent7", + "SnacksIndent8", + }, + }, + input = { + enabled = true, + icon = " ", + icon_hl = "SnacksInputIcon", + icon_pos = "left", + prompt_pos = "title", + win = { style = "input" }, + expand = true, + }, + layout = { enabled = true }, + lazygit = { enabled = true }, + notifier = { + enabled = true, + timeout = 2000, + width = { min = 40, max = 0.4 }, + height = { min = 1, max = 0.6 }, + margin = { top = 0, right = 1, bottom = 0 }, + padding = true, + sort = { "level", "added" }, + level = vim.log.levels.TRACE, + icons = { + debug = " ", + error = " ", + info = " ", + trace = " ", + warn = " ", + }, + style = "compact", + top_down = true, + date_format = "%R", + more_format = " ↓ %d lines ", + refresh = 50, + }, + notify = { enabled = true }, + picker = { + enabled = true, + icon = " ", + icon_hl = "SnacksPickerIcon", + icon_pos = "left", + prompt_pos = "title", + win = { style = "picker" }, + expand = true, + matchers = { + frecency = true, + cwd_bonus = false, + }, + sources = { + -- layout options: dropdown, horizontal, vertical, vscode, ivy, ivy_split, telescope, top, left, right, bottom, sidebar + buffers = { layout = files_layout() }, + commands = { layout = palette_layout() }, + command_history = { layout = palette_layout() }, + files = { + hidden = true, + layout = files_layout(), + }, + icons = { + icon_sources = { "nerd_fonts", "emoji" }, + layout = palette_layout(), + }, + git_files = { layout = files_layout() }, + git_branches = { layout = { preset = "vertical" } }, + git_status = { layout = files_layout() }, + help = { layout = { preset = "ivy_split" } }, + man = { layout = { preset = "ivy_split" } }, + notifications = { layout = palette_layout() }, + projects = { layout = files_layout(0.8) }, + recent = { layout = files_layout() }, + search_history = { layout = palette_layout() }, + smart = { layout = files_layout() }, + undo = { layout = { preset = "ivy" } }, + zoxide = { layout = files_layout(0.7) }, + }, + layout = "custom", + layouts = { + custom = { + layout = { + box = "vertical", + backdrop = false, + row = -1, + width = 0, + height = 0.4, + border = "top", + title = " {title} {live} {flags}", + title_pos = "left", + { + box = "horizontal", + { win = "list", border = "rounded" }, + { win = "preview", title = "{preview}", width = 0.6, border = "left" }, + }, + { win = "input", height = 1, border = "top" }, + }, + }, + }, + }, + profiler = { enabled = true }, + quickfile = { enabled = true }, + rename = { enabled = true }, + scope = { + enabled = true, + keys = { + textobject = { + ii = { + min_size = 2, -- minimum size of the scope + edge = false, -- inner scope + cursor = false, + treesitter = { blocks = { enabled = false } }, + desc = "inner scope", + }, + ai = { + cursor = false, + min_size = 2, -- minimum size of the scope + treesitter = { blocks = { enabled = false } }, + desc = "full scope", + }, + }, + jump = { + ["[a"] = { + min_size = 1, -- allow single line scopes + bottom = false, + cursor = false, + edge = true, + treesitter = { blocks = { enabled = false } }, + desc = "jump to top edge of scope", + }, + ["]a"] = { + min_size = 1, -- allow single line scopes + bottom = true, + cursor = false, + edge = true, + treesitter = { blocks = { enabled = false } }, + desc = "jump to bottom edge of scope", + }, + }, + }, + }, + scratch = { + enabled = true, + name = "SCRATCH", + ft = function() + if vim.bo.buftype == "" and vim.bo.filetype ~= "" then + return vim.bo.filetype + end + return "markdown" + end, + icon = nil, + root = vim.fn.stdpath("data") .. "/scratch", + autowrite = true, + filekey = { + cwd = true, + branch = true, + count = true, + }, + win = { + width = 120, + height = 40, + bo = { buftype = "", buflisted = false, bufhidden = "hide", swapfile = false }, + minimal = false, + noautocmd = false, + zindex = 20, + wo = { winhighlight = "NormalFloat:Normal" }, + border = "rounded", + title_pos = "center", + footer_pos = "center", + + keys = { + ["execute"] = { + "", + function(_) + vim.cmd("%SnipRun") + end, + desc = "Execute buffer", + mode = { "n", "x" }, + }, + }, + }, + win_by_ft = { + lua = { + keys = { + ["source"] = { + "cr", + function(self) + local name = "scratch." .. vim.fn.fnamemodify(vim.api.nvim_buf_get_name(self.buf), ":e") + Snacks.debug.run({ buf = self.buf, name = name }) + end, + desc = "Source buffer", + mode = { "n", "x" }, + }, + }, + }, + }, + }, + scroll = { enabled = false }, + statuscolumn = { + enabled = false, -- Change this to false + left = { "mark", "sign" }, + right = { "fold", "git" }, + folds = { + open = false, + git_hl = false, + }, + git = { + patterns = { "GitSign", "MiniDiffSign" }, + }, + refresh = 50, + }, + terminal = { enabled = false }, + toggle = { enabled = false }, + win = { enabled = true }, + words = { enabled = false }, + zen = { + enabled = true, + toggles = { + dim = true, + git_signs = false, + mini_diff_signs = false, + -- diagnostics = false, + -- inlay_hints = false, + }, + show = { + statusline = false, + tabline = false, + }, + win = { style = "zen" }, + zoom = { + toggles = {}, + show = { statusline = true, tabline = true }, + win = { + backdrop = false, + width = 0, + }, + }, + }, +}) diff --git a/plugin/ui.lua b/plugin/ui.lua new file mode 100644 index 0000000..74857d2 --- /dev/null +++ b/plugin/ui.lua @@ -0,0 +1,104 @@ +add({ + "m4xshen/smartcolumn.nvim", -- smart column when needed + "karb94/neoscroll.nvim", -- smooth scrolling + "OXY2DEV/markview.nvim", -- rendering for html and markdown + "serhez/bento.nvim", -- buffer manager + { src = "akinsho/toggleterm.nvim", version = "*" }, --float terminal + "max397574/better-escape.nvim", -- better escape + "zbirenbaum/neodim", -- dimming the highlights of unused functions, variables, parameters, and more +}) + +-- lazy load UI enhancement plugins +vim.api.nvim_create_autocmd({ "BufReadPost", "BufNewFile" }, { + callback = function() + require("neoscroll").setup({ + mappings = { "", "", "", "", "", "", "zt", "zz", "zb" }, + }) + require("neodim").setup({ + alpha = 0.5, + blend_color = nil, + hide = { + underline = true, + virtual_text = true, + signs = true, + }, + regex = { + "[uU]nused", + "[nN]ever [rR]ead", + "[nN]ot [rR]ead", + }, + priority = 128, + disable = {}, + }) + end, +}) + +-- lazy load markdown preview +vim.api.nvim_create_autocmd("FileType", { + pattern = "markdown", + callback = function() + require("markview").setup({ + preview = { + icon_provider = "mini", + enable = false, + }, + }) + end, +}) +vim.keymap.set("n", "cv", "Markview toggle", { desc = "toggle markdown preview" }) + +-- smart column only when needed +require("smartcolumn").setup({ + colorcolumn = 120, + disabled_filetypes = { + "help", + "text", + "markdown", + "oil", + "snacks_dashboard", + "dashboard", + }, +}) + +require("bento").setup({}) + +require("toggleterm").setup({ + size = 10, + open_mapping = [[]], + hide_numbers = true, + shade_filetypes = {}, + shade_terminals = true, + shading_factor = "2", + start_in_insert = true, + insert_mappings = true, + terminal_mappings = true, + persist_size = true, + direction = "float", + close_on_exit = true, + shell = vim.o.shell, + float_opts = { + border = "curved", + winblend = 0, + highlights = { + border = "Normal", + background = "Normal", + }, + }, +}) + +-- lazy load better escape +vim.api.nvim_create_autocmd("InsertEnter", { + callback = function() + require("better_escape").setup({ + mappings = { + i = { + k = { j = "" }, + j = { k = "", j = "" }, + -- disable jj + -- j = { j = false }, + }, + }, + }) + end, + once = true, +}) diff --git a/plugin/whichkey.lua b/plugin/whichkey.lua new file mode 100644 index 0000000..8ed5ceb --- /dev/null +++ b/plugin/whichkey.lua @@ -0,0 +1,301 @@ +add("folke/which-key.nvim") + +local wk = require("which-key") +wk.setup({ + preset = "helix", + plugins = { + marks = true, + registers = true, + spelling = { + enabled = true, + suggestions = 30, + }, + }, + presets = { + operators = true, + motions = true, + text_objects = true, + windows = true, + nav = true, + z = true, + g = true, + }, + icons = { + breadcrumb = " ", + separator = " ", + group = "", + keys = { + Space = " ", + }, + rules = false, -- enable auto icon rules + }, + show_help = false, + show_keys = true, + triggers = { + { "", mode = "nvisoct" }, + { "", mode = { "n", "v" } }, + }, +}) + +local normal_mappings = { + mode = "n", + { "x", ":x", desc = " Save and Quit" }, + + -- { "a", group = " AI" }, + + { "b", group = " Buffer" }, + + { "c", group = " Code" }, + { "cF", ":retab", desc = "Fix Tabs" }, + { "cd", ":RootDir", desc = "Root Directory" }, + { "cf", ":lua vim.lsp.buf.format({async = true})", desc = "Format File" }, + { "cg", ":Neogen", desc = "Generate Docstring" }, + { "cl", "::g/^\\s*$/d", desc = "Clean Empty Lines" }, + { "cm", ":MarkdownPreviewToggle", desc = "Markdown Preview" }, + { "cq", ":lua Snacks.picker.qflist()", desc = "Quickfix List" }, + + { "e", group = " Edit" }, + { "ea", ":b#", desc = "Alternate File" }, + { "eC", group = "Edit Configs" }, + { + "ee", + function() + local minifiles = require("mini.files") + minifiles.open(vim.api.nvim_buf_get_name(0), true) + minifiles.reveal_cwd() + end, + desc = "Explore Tree", + }, + { "eE", ":lua Snacks.explorer()", desc = "File Explorer" }, + { "ef", "gf", desc = "File Under Cursor" }, + { "em", ":e README.md", desc = "Readme" }, + { "en", ":enew", desc = "New File" }, + { "er", ":lua require('snacks').rename.rename_file()", desc = "Rename Current File" }, + + { "f", group = " Find" }, + { "fx", ":%bd|e#|bd#", desc = "Close except current" }, + { "ff", ":lua Snacks.picker.files()", desc = "Find Files" }, + { "fg", ":lua Snacks.picker.grep()", desc = "Live Grep" }, + { "fp", ":lua Snacks.picker.projects()", desc = "Projects" }, + { + "ct", + function() + local curr_path = vim.fn.expand("%:p") + Snacks.picker.todo_comments({ + transform = function(item) + local item_path = vim.fn.fnamemodify(item.cwd .. "/" .. item.file, ":p") + return item_path == curr_path + end, + }) + end, + desc = "Search Todos in Current File", + }, + { "fT", ":lua Snacks.picker.todo_comments()", desc = "Search Todos" }, + { "fu", ":lua Snacks.picker.undo()", desc = "Undotree" }, + + { "g", group = " Git" }, + { "gA", ":Gitsigns stage_buffer", desc = "Stage Buffer" }, + { "gR", ":Gitsigns reset_buffer", desc = "Reset Buffer" }, + { "ga", ":Gitsigns stage_hunk", desc = "Stage Hunk" }, + { "gb", ":lua require('gitsigns').blame_line({full = true})", desc = "Blame" }, + { "gB", ":lua require('snacks').git.blame_line()", desc = "Detailed Blame" }, + { "gc", ":Gitignore", desc = "Generate .gitignore" }, + { "gd", ":Gitsigns diffthis HEAD", desc = "Git Diff" }, + { "gF", ":Git", desc = "Fugitive Panel" }, + { "gi", ":Gitsigns preview_hunk", desc = "Hunk Info" }, + { "gj", ":Gitsigns next_hunk", desc = "Next Hunk" }, + { "gk", ":Gitsigns prev_hunk", desc = "Prev Hunk" }, + { "gl", ":lua Snacks.picker.git_log()", desc = "Checkout commit" }, + { "gr", ":Gitsigns reset_hunk", desc = "Reset Hunk" }, + { "gs", ":lua Snacks.picker.git_status()", desc = "Open changed file" }, + { "gu", ":Gitsigns undo_stage_hunk", desc = "Undo Stage Hunk" }, + { "gv", ":Gitsigns select_hunk", desc = "Select Hunk" }, + { "gw", ':lua require("snacks").gitbrowse()', desc = "Git Browse" }, + { "gp", ":lua Snacks.picker.git_branches()", desc = "Pick and Switch Git Branches" }, + + { "gt", group = "Toggle" }, + { "gtb", ":Gitsigns toggle_current_line_blame", desc = "Blame" }, + { "gtd", ":Gitsigns toggle_deleted", desc = "Deleted" }, + { "gtl", ":Gitsigns toggle_linehl", desc = "Line HL" }, + { "gtn", ":Gitsigns toggle_numhl", desc = "Number HL" }, + { "gts", ":Gitsigns toggle_signs", desc = "Signs" }, + { "gtw", ":Gitsigns toggle_word_diff", desc = "Word Diff" }, + + { "i", group = " Insert" }, + { "id", ":put =strftime('## %a, %d %b, %Y, %r')", desc = "Date" }, + { "if", ":put =expand('%:t')", desc = "File Name" }, + { "ip", ":put %", desc = "Relative Path" }, + { "iP", ":put %:p", desc = "Absolute Path" }, + { "it", ":put =strftime('## %r')", desc = "Time" }, + + { "l", group = " LSP" }, + { "la", ":Lspsaga code_action", desc = "Code Action" }, + { "ld", ":Lspsaga goto_definition", desc = "Goto Definition" }, + { "lf", ":Lspsaga finder", desc = "Finder" }, + { "lh", ":Lspsaga hover_doc", desc = "Hover" }, + { "lI", ":LspInfo", desc = "LSP Info" }, + { "lj", ":Lspsaga diagnostic_jump_next", desc = "Next Diagnostic" }, + { "lk", ":Lspsaga diagnostic_jump_prev", desc = "Prev Diagnostic" }, + { "lo", ":Lspsaga outline", desc = "Outline" }, + { "lp", ":Lspsaga peek_definition", desc = "Peek Definition" }, + { "lq", ":LspStop", desc = "Stop LSP" }, + { "lQ", ":LspRestart", desc = "Restart LSP" }, + { "lr", ":Lspsaga rename", desc = "Rename" }, + { "lR", ":Lspsaga project_replace", desc = "Replace" }, + { "lt", ":Lspsaga goto_type_definition", desc = "Goto Type Definition" }, + { "lT", ":Lspsaga peek_type_definition", desc = "Peek Type Definition" }, + + { "o", group = " Options" }, + { "oi", "vim.show_pos", desc = "Inspect Position" }, + { "oN", ":lua Snacks.notifier.show_history()", desc = "Notification History" }, + { "or", ":set relativenumber!", desc = "Relative Numbers" }, + + { "p", group = " Packages" }, + { "pc", ":Lazy check", desc = "Check" }, + { "pd", ":Lazy debug", desc = "Debug" }, + { "pe", ':lua require("snacks").profiler.scratch()', desc = "Profiler Scratch" }, + { "pf", ':lua require("snacks").profiler.pick()', desc = "Profiler Pick" }, + { "pi", ":Lazy install", desc = "Install" }, + { "pl", ":Lazy log", desc = "Log" }, + { "pm", ":Mason", desc = "Mason" }, + { "pp", ":Lazy", desc = "Plugins" }, + { "pP", ":Lazy profile", desc = "Profile" }, + { "pr", ":Lazy restore", desc = "Restore" }, + { "ps", ":Lazy sync", desc = "Sync" }, + { "pt", ':lua require("snacks").profiler.toggle()', desc = "Profiler Toggle" }, + { "pu", ":Lazy update", desc = "Update" }, + { "px", ":Lazy clean", desc = "Clean" }, + + { "q", group = " Quit" }, + { "qa", ":qall", desc = "Quit All" }, + { "qb", ":bw", desc = "Close Buffer" }, + { "qd", ':lua require("snacks").bufdelete()', desc = "Delete Buffer" }, + { "qf", ":qall!", desc = "Force Quit" }, + { "qo", ":%bdelete|b#|bdelete#", desc = "Close Others" }, + { "qq", ":q", desc = "Quit" }, + { "qs", "c", desc = "Close Split" }, + { "qw", ":wq", desc = "Write and Quit" }, + + { "r", group = " Refactor" }, + { "rd", "", desc = "Go To Definition" }, -- treesitter navigation + { "rD", "", desc = "List Definition" }, + { "rh", "", desc = "List Definition Head" }, + { "rj", "", desc = "Next Usage" }, + { "rk", "", desc = "Previous Usage" }, + { "rn", "", desc = "Swap Next" }, + { "rp", "", desc = "Swap Previous" }, + { "rr", "", desc = "Smart Rename" }, + { "rs", ":%s/\\<\\>//gI", desc = "Replace Word Buffer" }, + + { "s", group = " Split" }, + { "s+", ":resize +10", desc = "Increase window height" }, + { "s-", ":vertical resize -20", desc = "Decrease window width" }, + { "s/", "s", desc = "Split Below" }, + { "s=", ":vertical resize +20", desc = "Increase window width" }, + { "sH", ":vertical resize -10", desc = "Decrease window width" }, + { "sJ", ":resize -5", desc = "Decrease window height" }, + { "sK", ":resize +5", desc = "Increase window height" }, + { "sL", ":vertical resize +10", desc = "Increase window width" }, + { "s\\", "v", desc = "Split Right" }, + { "s_", ":resize -10", desc = "Decrease window height" }, + { "s`", "p", desc = "Previous Window" }, + { "sa", ":split", desc = "Horizontal Split" }, + { "sc", ":tabclose", desc = "Close Tab" }, + { "sf", ":tabfirst", desc = "First Tab" }, + { "sh", "h", desc = "Move Left" }, + { "sj", "j", desc = "Move Down" }, + { "sk", "k", desc = "Move Up" }, + { "sl", "l", desc = "Move Right" }, + { "sq", "c", desc = "Close Split" }, + { "ss", ":vsplit", desc = "Vertical Split" }, + + { "t", group = " Terminal" }, + { "t1", "1ToggleTerm", desc = "Toggle Terminal" }, + { "t2", "2ToggleTerm", desc = "Toggle Terminal" }, + { "tc", "close", desc = "Hide Terminal" }, + { "th", group = "Inlay Hints" }, + + { "w", group = " Writing" }, + { "wc", ":set spell!", desc = "Spellcheck" }, + { "wd", ':lua require("snacks").dim.enable()', desc = "Dim On" }, + { "wD", ':lua require("snacks").dim.disable()', desc = "Dim Off" }, + { "wf", ":lua require'utils'.sudo_write()", desc = "Force Write" }, + { "wj", "]s", desc = "Next Misspell" }, + { "wk", "[s", desc = "Prev Misspell" }, + { "wn", ":WriteNoFormat", desc = "Write Without Formatting" }, + { "wq", ":wq", desc = "Write and Quit" }, + { "ww", ":w", desc = "Write" }, + { "wz", ':lua require("snacks").zen.zen()', desc = "Zen" }, + { "wZ", ':lua require("snacks").zen.zoom()', desc = "Zoom" }, + + { "y", group = " Yank" }, + { "yL", ":CopyAbsolutePathWithLine", desc = "Absolute Path with Line" }, + { "yP", ":CopyAbsolutePath", desc = "Absolute Path" }, + { "ya", ":%y+", desc = "Copy Whole File" }, + { "yf", ":CopyFileName", desc = "File Name" }, + { "yg", ':lua require"gitlinker".get_buf_range_url()', desc = "Copy Git URL" }, + { "yl", ":CopyRelativePathWithLine", desc = "Relative Path with Line" }, + { "yp", ":CopyRelativePath", desc = "Relative Path" }, +} + +local visual_mappings = { + mode = "v", + -- { "a", group = " AI" }, + + { "c", group = " Code" }, + { "cS", ":sort!", desc = "Sort Desc" }, + { "ci", ":sort i", desc = "Sort Case Insensitive" }, + { "cs", ":sort", desc = "Sort Asc" }, + { "cu", ":!uniq", desc = "Unique" }, + { "cx", ":lua", desc = "Execute Lua" }, + + { "g", group = " Git" }, + { "ga", ":'<,'>Gitsigns stage_hunk", desc = "Stage Hunk" }, + { "gr", ":'<,'>Gitsigns reset_hunk", desc = "Reset Hunk" }, + { "gu", ":'<,'>Gitsigns undo_stage_hunk", desc = "Undo Stage Hunk" }, + + { "l", group = " LSP" }, + { "la", ":Lspsaga range_code_action", desc = "Code Action" }, + + -- { "o", group = " Options" }, + + { "y", group = " Yank" }, + { "yg", ':lua require"gitlinker".get_buf_range_url("v")', desc = "Copy Git URL" }, +} + +local no_leader_mappings = { + mode = "n", + { "", ":resize -10", desc = "Decrease window height" }, + { "", ":vertical resize -10", desc = "Decrease window width" }, + { "", ":vertical resize +10", desc = "Increase window width" }, + { "", ":resize +10", desc = "Increase window height" }, + + { "", ":NavigatorLeft", desc = "Move Left" }, + { "", ":NavigatorDown", desc = "Move Down" }, + { "", ":NavigatorUp", desc = "Move Up" }, + { "", ":NavigatorRight", desc = "Move Right" }, + { "", ":NavigatorPrevious", desc = "Previous Pane" }, + + -- { '', ':bprevious', desc = 'Previous Buffer' }, + -- { '', ':bnext', desc = 'Next Buffer' }, + { "", ":bnext", desc = "Next Buffer" }, + { "", ":bprevious", desc = "Previous Buffer" }, + + { "K", ":Lspsaga hover_doc", desc = "LSP Hover" }, + { "Q", ":qall!", desc = "Force Quit!" }, + { "U", ":redo", desc = "Redo" }, + + { "[", group = " Previous" }, + { "[g", ":Gitsigns prev_hunk", desc = "Git Hunk" }, + { "[o", group = "Textobjects" }, + + { "]", group = " Next" }, + { "]g", ":Gitsigns next_hunk", desc = "Git Hunk" }, + { "]o", group = "Textobjects" }, + + { "gd", ":Lspsaga goto_definition", desc = "Goto Definition" }, +} + +wk.add(normal_mappings) +wk.add(visual_mappings) +wk.add(no_leader_mappings)