diff options
| author | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2025-01-24 20:35:27 +0900 |
|---|---|---|
| committer | TheSiahxyz <164138827+TheSiahxyz@users.noreply.github.com> | 2025-01-24 20:35:27 +0900 |
| commit | c80a54e42b52ce297f0f2f71af23c562832025c7 (patch) | |
| tree | dcce8bb977a770f473325d48f6f70b21d9818a40 /ar/.config/TheSiahxyz/lua | |
init
Diffstat (limited to 'ar/.config/TheSiahxyz/lua')
63 files changed, 10655 insertions, 0 deletions
diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/core/autocmds.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/autocmds.lua new file mode 100644 index 0000000..10c1085 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/autocmds.lua @@ -0,0 +1,381 @@ +local function augroup(name) + return vim.api.nvim_create_augroup("TheSiahxyz_" .. name, { clear = true }) +end + +local autocmd = vim.api.nvim_create_autocmd + +-- Change the color of symlink files to distinguish between directory and symlink files +autocmd("FileType", { + group = augroup("highlight_linked_files"), + pattern = "netrw", + callback = function() + vim.cmd("highlight NetrwSymlink guifg=#689D6A ctermfg=214") + end, +}) + +-- Check if we need to reload the file when it changed +autocmd({ "FocusGained", "TermClose", "TermLeave" }, { + group = augroup("check_time"), + callback = function() + if vim.o.buftype ~= "nofile" then + vim.cmd("checktime") + end + end, +}) + +-- Highlight on yank +autocmd("TextYankPost", { + group = augroup("highlight_yank"), + callback = function() + vim.highlight.on_yank() + end, +}) + +-- resize splits if window got resized +autocmd({ "VimResized" }, { + group = augroup("window_config"), + callback = function() + local current_tab = vim.fn.tabpagenr() + vim.cmd("tabdo wincmd =") + vim.cmd("tabnext " .. current_tab) + end, +}) + +-- go to last loc when opening a buffer +autocmd("BufReadPost", { + group = augroup("last_loc"), + callback = function(event) + local exclude = { "gitcommit" } + local buf = event.buf + if vim.tbl_contains(exclude, vim.bo[buf].filetype) or vim.b[buf].thesiahxyz_last_loc then + return + end + vim.b[buf].thesiahxyz_last_loc = true + local mark = vim.api.nvim_buf_get_mark(buf, '"') + local lcount = vim.api.nvim_buf_line_count(buf) + if mark[1] > 0 and mark[1] <= lcount then + pcall(vim.api.nvim_win_set_cursor, 0, mark) + end + end, +}) + +-- close some filetypes with <q> +autocmd("FileType", { + group = augroup("close_with_q"), + pattern = { + "checkhealth", + "help", + "lspinfo", + "neotest-output", + "neotest-output-panel", + "neotest-summary", + "notify", + "PlenaryTestPopup", + "qf", + "query", + "spectre_panel", + "startuptime", + "terminal", + "tsplayground", + }, + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.keymap.set("n", "q", "<cmd>close<cr>", { buffer = event.buf, silent = true }) + end, +}) +autocmd("FileType", { + group = augroup("q_as_bd"), + pattern = "netrw", + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.keymap.set("n", "q", function() + vim.cmd("bd") + end, { buffer = event.buf, silent = true }) + end, +}) + +-- Start insert mode in terminal +autocmd("TermOpen", { + group = augroup("terminal"), + pattern = "*", + callback = function() + vim.cmd("startinsert") + end, +}) + +-- Make it easier to close man-files when opened inline +autocmd("FileType", { + group = augroup("man_close"), + pattern = { "man" }, + callback = function(event) + vim.bo[event.buf].buflisted = false + end, +}) + +-- Wrap and check for spell in text filetypes +autocmd("FileType", { + group = augroup("wrap_spell"), + pattern = { "text", "plaintex", "typst", "gitcommit", "markdown" }, + callback = function() + vim.opt_local.wrap = true + vim.opt_local.spell = true + vim.opt_local.spelllang = { "en", "cjk" } + vim.opt_local.spellsuggest = { "best", "9" } + end, +}) + +-- Fix conceallevel for json files +autocmd({ "FileType" }, { + group = augroup("json_config"), + pattern = { "json", "jsonc", "json5" }, + callback = function() + vim.opt_local.conceallevel = 0 + end, +}) + +-- Auto create dir when saving a file, in case some intermediate directory does not exist +autocmd({ "BufWritePre" }, { + group = augroup("create_dir"), + callback = function(event) + if event.match:match("^%w%w+:[\\/][\\/]") then + return + end + local file = vim.uv.fs_realpath(event.match) or event.match + vim.fn.mkdir(vim.fn.fnamemodify(file, ":p:h"), "p") + end, +}) + +-- Automatically delete all trailing whitespace and newlines at end of file on save +local file_save = augroup("file_save") +autocmd("BufWritePre", { + group = file_save, + pattern = "*", + callback = function() + -- Remove trailing spaces + vim.cmd([[ %s/\s\+$//e ]]) + -- Remove trailing newlines + vim.cmd([[ %s/\n\+\%$//e ]]) + end, +}) + +-- Add a trailing newline for C files +autocmd("BufWritePre", { + group = file_save, + pattern = "*.[ch]", + callback = function() + vim.cmd([[ %s/\%$/\r/e ]]) + end, +}) + +-- Correct email signature delimiter in neomutt files +autocmd("BufWritePre", { + group = file_save, + pattern = "*neomutt*", + callback = function() + vim.cmd([[ %s/^--$/-- /e ]]) + end, +}) + +local function organize_imports() + local params = { + command = "pyright.organizeimports", + arguments = { vim.uri_from_bufnr(0) }, + } + vim.lsp.buf.execute_command(params) +end + +autocmd("LspAttach", { + group = augroup("lsp_attach"), + callback = function(e) + local client = vim.lsp.get_client_by_id(e.data.client_id) + if client and client.name == "pyright" then + vim.api.nvim_create_user_command( + "PyrightOrganizeImports", + organize_imports, + { desc = "Organize imports (lsp)" } + ) + end + vim.keymap.set("n", "gD", function() + vim.lsp.buf.definition() + end, { buffer = e.buf, desc = "Go to definition (lsp)" }) + vim.keymap.set("n", "K", function() + vim.lsp.buf.hover() + end, { buffer = e.buf, desc = "Go to keywords (lsp)" }) + vim.keymap.set("n", "<leader>ls", function() + vim.lsp.buf.workspace_symbol() + end, { buffer = e.buf, desc = "Workspace symbol (lsp)" }) + vim.keymap.set("n", "<leader>lo", function() + vim.diagnostic.open_float() + end, { buffer = e.buf, desc = "Open diagnostic" }) + vim.keymap.set("n", "<leader>lc", function() + vim.lsp.buf.code_action() + end, { buffer = e.buf, desc = "Code action (lsp)" }) + vim.keymap.set("n", "<leader>lr", function() + vim.lsp.buf.references() + end, { buffer = e.buf, desc = "References (lsp)" }) + vim.keymap.set("n", "<leader>ln", function() + vim.lsp.buf.rename() + end, { buffer = e.buf, desc = "Rename (lsp)" }) + vim.keymap.set("n", "<leader>lh", function() + vim.lsp.buf.signature_help() + end, { buffer = e.buf, desc = "Signature help (lsp)" }) + vim.keymap.set("n", "]d", function() + vim.diagnostic.goto_next() + end, { buffer = e.buf, desc = "Next diagnostic" }) + vim.keymap.set("n", "[d", function() + vim.diagnostic.goto_prev() + end, { buffer = e.buf, desc = "Previous diagnostic" }) + end, +}) + +-- Save file as sudo on files that require root permission +vim.api.nvim_create_user_command("SudoWrite", function() + vim.cmd([[ + write !sudo tee % 2>/dev/null + edit! + ]]) +end, {}) +vim.api.nvim_create_user_command("SudoWritequit", function() + vim.cmd([[ + write !sudo tee % 2>/dev/null + edit! + quit! + ]]) +end, {}) + +-- Markdown for specific files and directories +vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + pattern = { "/tmp/calcurse*", "~/.calcurse/notes/*" }, + command = "set filetype=markdown", +}) + +-- Groff for specific file extensions +vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + pattern = { "*.ms", "*.me", "*.mom", "*.man" }, + callback = function() + vim.cmd([[ + set columns=90 + set filetype=groff + set linebreak + set textwidth=0 + set wrap + set wrapmargin=0 + ]]) + end, +}) + +-- TeX for .tex files +vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + pattern = { "*.tex" }, + command = "set filetype=tex", +}) + +-- When shortcut files are updated, renew bash and lf configs with new material: +vim.api.nvim_create_autocmd("BufWritePost", { + group = augroup("bookmarks"), + pattern = { "bm-files", "bm-dirs" }, + callback = function() + -- Execute the 'shortcuts' shell command + local result = vim.fn.system("shortcuts") + -- Display an error message only if the 'shortcuts' command fails + if vim.v.shell_error ~= 0 then + -- Display an error message if the 'shortcuts' command fails + vim.api.nvim_echo({ { "failed to update shortcuts: " .. result, "ErrorMsg" } }, true, {}) + end + end, +}) + +-- Source lfrc if it's edited +local lf_config = augroup("lf_config") +vim.api.nvim_create_autocmd("BufWritePost", { + group = lf_config, + pattern = { "lfrc" }, + callback = function() + vim.cmd("silent !source ~/.config/lf/lfrc") + end, +}) + +-- Run xrdb whenever Xdefaults or Xresources are updated. +local x_config = augroup("x_config") +vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + group = x_config, + pattern = { "Xresources", "Xdefaults", "xresources", "xdefaults" }, + callback = function() + vim.bo.filetype = "xdefaults" + end, +}) +vim.api.nvim_create_autocmd("BufWritePost", { + group = x_config, + pattern = { "Xresources", "Xdefaults", "xresources", "xdefaults" }, + callback = function() + vim.cmd("silent !xrdb %") + end, +}) + +-- Recompile suckless programs on config edit. +local home = os.getenv("HOME") +local suckless_config = vim.api.nvim_create_augroup("suckless_config", { clear = true }) + +vim.api.nvim_create_autocmd("BufWritePost", { + group = suckless_config, + pattern = home .. "/.local/src/suckless/dmenu/config.h", + callback = function() + vim.cmd("silent !cd " .. home .. "/.local/src/suckless/dmenu/ && sudo make install") + end, +}) + +vim.api.nvim_create_autocmd("BufWritePost", { + group = suckless_config, + pattern = home .. "/.local/src/suckless/dwmblocks/config.h", + callback = function() + vim.cmd( + "silent !cd " + .. home + .. "/.local/src/suckless/dwmblocks/ && sudo make install && { killall -q dwmblocks; setsid -f dwmblocks; }" + ) + end, +}) + +vim.api.nvim_create_autocmd("BufWritePost", { + group = suckless_config, + pattern = home .. "/.local/src/suckless/slock/config.h", + callback = function() + vim.cmd("silent !cd " .. home .. "/.local/src/suckless/slock/ && sudo make install") + end, +}) + +local suckless_keys = augroup("suckless_keys") +vim.api.nvim_create_autocmd("BufWritePost", { + group = suckless_keys, + pattern = home .. "/.local/src/suckless/dwm/config.h", + callback = function() + vim.cmd("silent !" .. home .. "/.local/bin/extractkeys") + end, +}) + +vim.api.nvim_create_autocmd("BufWritePost", { + group = suckless_keys, + pattern = home .. "/.local/src/suckless/st/config.h", + callback = function() + vim.cmd("silent !" .. home .. "/.local/bin/extractkeys") + end, +}) + +vim.api.nvim_create_autocmd("BufWritePost", { + group = augroup("suckless_doc"), + pattern = home .. "/.local/src/suckless/dwm/thesiah-default.mom", + callback = function() + vim.cmd("silent !cd " .. home .. "/.local/src/suckless/dwm/ && rm -f thesiah.mom") + end, +}) + +vim.api.nvim_create_autocmd({ "BufRead", "BufEnter" }, { + pattern = { "*.c", "*.cpp", "*.h", "*.hpp" }, + callback = function() + local suckless_path = vim.fn.expand("~/.local/src/suckless"):gsub("/+$", "") + local file_path = vim.fn.expand("%:p"):gsub("/+$", "") + if file_path:sub(1, #suckless_path) == suckless_path then + vim.b.autoformat = false + end + end, +}) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/core/keymaps.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/keymaps.lua new file mode 100644 index 0000000..162b71a --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/keymaps.lua @@ -0,0 +1,806 @@ +-- Init leader Keys +vim.g.mapleader = " " +vim.g.maplocalleader = "\\" + +-- Ascii +vim.keymap.set("n", "<leader>a1", ":.!toilet -w 200 -f bfraktur<cr>", { desc = "Ascii art bfraktur" }) +vim.keymap.set("n", "<leader>a2", ":.!toilet -w 200 -f emboss<cr>", { desc = "Ascii art emboss" }) +vim.keymap.set("n", "<leader>a3", ":.!toilet -w 200 -f emboss2<cr>", { desc = "Ascii art emboss2" }) +vim.keymap.set("n", "<leader>a4", ":.!toilet -w 200 -f future<cr>", { desc = "Ascii art future" }) +vim.keymap.set("n", "<leader>a5", ":.!toilet -w 200 -f pagga<cr>", { desc = "Ascii art pagga" }) +vim.keymap.set("n", "<leader>a6", ":.!toilet -w 200 -f wideterm<cr>", { desc = "Ascii art wideterm" }) +vim.keymap.set("n", "<leader>a7", ":.!figlet -w 200 -f standard<cr>", { desc = "Ascii art standard" }) +vim.keymap.set("n", "<leader>a8", ":.!figlet -w 200 -f slant<cr>", { desc = "Ascii art slant" }) +vim.keymap.set("n", "<leader>a9", ":.!figlet -w 200 -f big<cr>", { desc = "Ascii art big" }) +vim.keymap.set("n", "<leader>a0", ":.!figlet -w 200 -f shadow<cr>", { desc = "Ascii art shadow" }) + +-- Buffers +vim.keymap.set({ "n", "v", "x", "t" }, "<A-x>", "<cmd>bd!<cr>", { desc = "Delete buffer" }) +vim.keymap.set({ "i", "n", "t" }, "<C-p>", "<cmd>bprevious<cr>", { desc = "Previous buffer" }) +vim.keymap.set({ "i", "n", "t" }, "<C-n>", "<cmd>bnext<cr>", { desc = "Next buffer" }) +vim.keymap.set({ "n", "t" }, "<S-h>", "<cmd>bprevious<cr>", { desc = "Previous buffer" }) +vim.keymap.set({ "n", "t" }, "<S-l>", "<cmd>bnext<cr>", { desc = "Next buffer" }) +vim.keymap.set("n", "<leader><leader>", "<cmd>e #<cr>", { desc = "Switch to last buffer" }) +vim.keymap.set({ "n", "v", "x", "t" }, "<leader>bd", "<cmd>:bd<cr>", { desc = "Close buffer" }) +vim.keymap.set({ "n", "v", "x", "t" }, "<leader>BD", "<cmd>:bd!<cr>", { desc = "Force close buffer" }) +vim.keymap.set("n", "<leader>bn", "<cmd>enew<cr>", { desc = "New buffer" }) +vim.keymap.set({ "i", "x", "n", "s" }, "<C-s>", "<cmd>w<cr><esc>", { desc = "Save current buffer" }) +vim.keymap.set({ "n", "v" }, "<leader>wq", "<cmd>wq<cr>", { desc = "Save current buffer and quit" }) +vim.keymap.set({ "n", "v" }, "<leader>WQ", "<cmd>wqa<cr>", { desc = "Save all buffers and quit" }) +vim.keymap.set({ "n", "v" }, "<leader>qq", "<cmd>q!<cr>", { desc = "Force quit" }) +vim.keymap.set({ "n", "v" }, "<leader>QQ", "<cmd>qa!<cr>", { desc = "Force quit all" }) +vim.keymap.set("n", "<leader>rn", function() + local current_name = vim.fn.expand("%:p") -- Get the full path of the current file + local directory = vim.fn.expand("%:p:h") -- Get the directory of the current file + local new_name = vim.fn.input("New filename: ", directory .. "/") -- Prompt for the new name + if new_name == "" or new_name == current_name then + return -- Do nothing if no input or name hasn't changed + end + vim.cmd("silent !mv " .. vim.fn.shellescape(current_name) .. " " .. vim.fn.shellescape(new_name)) + vim.cmd("edit " .. vim.fn.fnameescape(new_name)) + vim.cmd("bdelete " .. vim.fn.bufnr(current_name)) +end, { noremap = true, silent = true, desc = "Rename file" }) +vim.keymap.set("n", "<leader>ms", function() + vim.cmd("new | put=execute('messages') | setlocal buftype=nofile") + local buf = vim.api.nvim_get_current_buf() + local lines = vim.api.nvim_buf_get_lines(buf, 0, -1, false) + local filtered_lines = {} + for _, line in ipairs(lines) do + local trimmed_line = line:match("^%s*(.-)%s*$") -- Remove leading and trailing whitespace + if trimmed_line ~= "" then + table.insert(filtered_lines, trimmed_line) -- Only add non-empty lines + end + end + vim.fn.setreg('"', table.concat(filtered_lines, "\n")) + vim.api.nvim_buf_set_lines(buf, 0, -1, false, filtered_lines) + vim.keymap.set("n", "q", function() + vim.api.nvim_buf_delete(buf, { force = true }) + end, { buffer = buf, desc = "Close message buffer" }) +end, { desc = "Open messages, trim, and copy content" }) + +-- Cd +vim.keymap.set("n", "gcd", ":cd %:p:h<cr>:pwd<cr>", { desc = "Go to current file path" }) +vim.keymap.set("n", "gcD", function() + local realpath = vim.fn.systemlist("readlink -f " .. vim.fn.shellescape(vim.fn.expand("%:p")))[1] + vim.cmd("cd " .. vim.fn.fnameescape(vim.fn.fnamemodify(realpath, ":h"))) + vim.cmd("pwd") +end, { desc = "Go to real path of current file" }) +vim.keymap.set("n", "gc.", ":cd ..<cr>:pwd<cr>", { desc = "Go to current file path" }) + +-- Check health +vim.keymap.set("n", "<leader>ch", ":checkhealth<cr>", { desc = "Check neovim health" }) + +-- Clear search with <esc> +vim.keymap.set({ "i", "n" }, "<esc>", "<cmd>noh<cr><esc>", { desc = "Clear search highlights" }) + +-- Clear search / diff update / redraw +vim.keymap.set( + "n", + "<leader>R", + "<cmd>nohlsearch<bar>diffupdate<bar>normal! <C-l><cr>", + { desc = "Redraw / Clear hlsearch / Diff Update" } +) + +-- Copy +vim.keymap.set("n", "<leader>cp", function() + local filepath = vim.fn.expand("%") -- Get the current filepath + local filename = vim.fn.expand("%:t") -- Get the current filename + local file_root = vim.fn.expand("%:r") -- Get the file root (without extension) + local file_ext = vim.fn.expand("%:e") -- Get the file extension + local new_filename = file_root .. "_copied" -- Start with the base for new filename + local num = 1 + while vim.fn.filereadable(new_filename .. "." .. file_ext) == 1 do + new_filename = file_root .. "_copied_" .. num + num = num + 1 + end + new_filename = new_filename .. "." .. file_ext + local cmd = "cp " .. filepath .. " " .. new_filename + + -- Wrap input in pcall to handle Ctrl-c interruptions + local ok, confirm = pcall(vim.fn.input, 'Do you want to copy "' .. filename .. '"? (y/n): ') + + -- If interrupted (Ctrl-c), return silently + if not ok or confirm == nil or confirm == "" then + return + end + + -- Handle positive confirmation + if confirm:lower() == "y" or confirm:lower() == "yes" then + vim.cmd("silent !" .. cmd) + vim.cmd("silent edit " .. new_filename) + end +end, { silent = true, desc = "Copy current file" }) +vim.keymap.set( + "n", + "<leader>cP", + ':let @+ = expand("%:p")<cr>:lua print("Copied path to: " .. vim.fn.expand("%:p"))<cr>', + { desc = "Copy current file name and path" } +) + +-- Cut, Yank & Paste +vim.keymap.set({ "n", "v" }, "<leader>y", [["+y]], { desc = "Yank to clipboard" }) +vim.keymap.set("n", "<leader>Y", [["+Y]], { desc = "Yank line to clipboard" }) +vim.keymap.set({ "n", "v" }, "<leader><C-y>", ":%y<cr>", { desc = "Yank current file to clipboard" }) +vim.keymap.set({ "n", "v", "x" }, "<leader>pp", [["+p]], { desc = "Paste from clipboard after cursor" }) +vim.keymap.set({ "n", "v", "x" }, "<leader>PP", [["+P]], { desc = "Paste from clipboard before cursor" }) +vim.keymap.set({ "n", "v", "x" }, "<leader>pP", [["_dP]], { desc = "Paste over and preserve clipboard" }) +vim.keymap.set({ "n", "v" }, "<leader>dd", [["+d]], { desc = "Delete and yank to clipboard" }) +vim.keymap.set({ "n", "v" }, "<leader>DD", [["_d]], { desc = "Delete without storing in clipboard" }) +vim.keymap.set("n", "<leader><C-d>", ":%d_<cr>", { desc = "Delete all to black hole register" }) + +-- Diagnostic +local diagnostic_goto = function(next, severity) + local go = next and vim.diagnostic.goto_next or vim.diagnostic.goto_prev + severity = severity and vim.diagnostic.severity[severity] or nil + return function() + go({ severity = severity }) + end +end +-- vim.keymap.set("n", "[d", diagnostic_goto(false), { desc = "Previous diagnostic" }) +-- vim.keymap.set("n", "]d", diagnostic_goto(true), { desc = "Next diagnostic" }) +vim.keymap.set("n", "<leader>[e", diagnostic_goto(false, "ERROR"), { desc = "Previous error" }) +vim.keymap.set("n", "<leader>]e", diagnostic_goto(true, "ERROR"), { desc = "Next error" }) +vim.keymap.set("n", "<leader>[w", diagnostic_goto(false, "WARN"), { desc = "Previous warning" }) +vim.keymap.set("n", "<leader>]w", diagnostic_goto(true, "WARN"), { desc = "Next warning" }) +vim.keymap.set("n", "<leader>od", vim.diagnostic.open_float, { desc = "Open diagnostic message" }) +vim.keymap.set("n", "<leader>la", vim.diagnostic.setloclist, { desc = "Add diagnostics to location list" }) + +-- Disable +vim.keymap.set("n", "Q", "<nop>", { desc = "Disable q command" }) + +-- Explore +vim.keymap.set("n", "<leader>ex", vim.cmd.Ex, { desc = "Open explorer" }) +vim.keymap.set("n", "<leader>es", vim.cmd.Sex, { desc = "Open explorer (horizontal split)" }) +vim.keymap.set("n", "<leader>ev", vim.cmd.Vex, { desc = "Open explorer (vertical split)" }) +vim.keymap.set("n", "<leader>qe", function() + if vim.bo.filetype == "netrw" then + vim.cmd("bd") + end +end, { desc = "Close explorer (netrw)" }) + +-- Files +vim.keymap.set("n", "<leader>fn", "<cmd>enew<cr>", { desc = "Open new buffer" }) + +-- Fix List & Trouble +vim.keymap.set("n", "[o", "<cmd>lprev<cr>zz", { desc = "Previous location" }) +vim.keymap.set("n", "]o", "<cmd>lnext<cr>zz", { desc = "Next location" }) +vim.keymap.set("n", "[q", "<cmd>cprev<cr>zz", { desc = "Previous quickfix" }) +vim.keymap.set("n", "]q", "<cmd>cnext<cr>zz", { desc = "Next quickfix" }) +vim.keymap.set( + "n", + "<leader>rw", + [[:%s/\<<C-r><C-w>\>/<C-r><C-w>/gI<Left><Left><Left>]], + { desc = "Search and replace word under cursor" } +) +vim.keymap.set("n", "<leader>oo", "<cmd>lopen<cr>", { desc = "Open location list" }) +vim.keymap.set("n", "<leader>oq", "<cmd>copen<cr>", { desc = "Open quickfix list" }) + +-- Formats +vim.keymap.set("n", "<leader>cF", vim.lsp.buf.format, { desc = "Format buffer by default lsp" }) + +-- Git +-- create repository +vim.keymap.set("n", "<leader>gR", function() + -- Check if GitHub CLI is installed + local gh_installed = vim.fn.system("command -v gh") + if gh_installed == "" then + print("GitHub CLI is not installed. Please install it using 'brew install gh'.") + return + end + -- Get the current working directory and extract the repository name + local cwd = vim.fn.getcwd() + local repo_name = vim.fn.fnamemodify(cwd, ":t") + if repo_name == "" then + print("Failed to extract repository name from the current directory.") + return + end + -- Display the message and ask for confirmation + local confirmation = vim.fn.input('The name of the repo will be: "' .. repo_name .. '"\nType "yes" to continue: ') + if confirmation:lower() ~= "yes" then + print("Operation canceled.") + return + end + -- Check if the repository already exists on GitHub + local check_repo_command = + string.format("gh repo view %s/%s", vim.fn.system("gh api user --jq '.login'"):gsub("%s+", ""), repo_name) + local check_repo_result = vim.fn.systemlist(check_repo_command) + if not string.find(table.concat(check_repo_result), "Could not resolve to a Repository") then + print("Repository '" .. repo_name .. "' already exists on GitHub.") + return + end + -- Prompt for repository type + local repo_type = vim.fn.input("Enter the repository type (private/public): "):lower() + if repo_type ~= "private" and repo_type ~= "public" then + print("Invalid repository type. Please enter 'private' or 'public'.") + return + end + -- Set the repository type flag + local repo_type_flag = repo_type == "private" and "--private" or "--public" + -- Initialize the git repository and create the GitHub repository + local init_command = string.format("cd %s && git init", vim.fn.shellescape(cwd)) + vim.fn.system(init_command) + local create_command = + string.format("cd %s && gh repo create %s %s --source=.", vim.fn.shellescape(cwd), repo_name, repo_type_flag) + local create_result = vim.fn.system(create_command) + -- Print the result of the repository creation command + if string.find(create_result, "https://github.com") then + print("Repository '" .. repo_name .. "' created successfully.") + else + print("Failed to create the repository: " .. create_result) + end +end, { desc = "Create GitHub repository" }) +-- open repository +local function open_github_link(use_root) + -- Get the full path of the current file + local file_path = vim.fn.expand("%:p") + if file_path == "" then + print("No file is currently open") + return + end + + -- Get the Git repository root + local git_root = vim.fn.systemlist("git rev-parse --show-toplevel")[1] + if not git_root or git_root == "" then + print("Could not determine the root directory for the GitHub repository") + return + end + + -- Get the origin URL of the repository + local origin_url = vim.fn.systemlist("git config --get remote.origin.url")[1] + if not origin_url or origin_url == "" then + print("Could not determine the origin URL for the GitHub repository") + return + end + + -- Get the current branch name + local branch_name = vim.fn.systemlist("git rev-parse --abbrev-ref HEAD")[1] + if not branch_name or branch_name == "" then + print("Could not determine the current branch name") + return + end + + -- Convert the origin URL to a GitHub HTTPS URL + local repo_url = origin_url:gsub("git@github.com:", "https://github.com/"):gsub("%.git$", "") + + local github_url + if use_root then + -- Use the root repository URL + github_url = repo_url + else + -- Generate the link for the current file + local relative_path = file_path:sub(#git_root + 2) -- Extract the relative path + github_url = repo_url .. "/blob/" .. branch_name .. "/" .. relative_path + end + + -- Open the URL in the default browser + local command = "xdg-open " .. vim.fn.shellescape(github_url) + vim.fn.system(command) + + -- Print the opened URL + print("Opened GitHub link: " .. github_url) +end + +-- Keybinding for opening the current file link +vim.keymap.set("n", "<leader>go", function() + open_github_link(false) -- Use the current file link +end, { desc = "Open GitHub link for the current file" }) + +-- Keybinding for opening the repository root link +vim.keymap.set("n", "<leader>gO", function() + open_github_link(true) -- Use the root repository URL +end, { desc = "Open GitHub repository root" }) + +-- paste a github link and add it in this format +vim.keymap.set({ "n", "v", "i" }, "<M-;>", function() + -- Insert the text in the desired format + vim.cmd('normal! a[](){:target="_blank"} ') + vim.cmd("normal! F(pv2F/lyF[p") + -- Leave me in normal mode or command mode + vim.cmd("stopinsert") +end, { desc = "Paste github link" }) + +-- Health +vim.keymap.set("n", "<leader>ch", ":checkhealth<cr>", { desc = "Check neovim health" }) + +-- Highlights under cursor +vim.keymap.set("n", "<leader>ip", vim.show_pos, { desc = "Inspect position" }) + +-- Keywordprg +vim.keymap.set("n", "<leader>K", "<cmd>norm! K<cr>", { desc = "Look up keyword" }) + +-- Lines +-- vim.keymap.set("n", "<A-,>", "<cmd>m .-2<cr>==", { desc = "Move line up" }) +-- vim.keymap.set("n", "<A-.>", "<cmd>m .+1<cr>==", { desc = "Move line down" }) +vim.keymap.set( + "i", + "<A-,>", + "<esc><cmd>m .-2<cr>==gi", + { noremap = true, silent = true, desc = "Move line up in insert mode" } +) +vim.keymap.set( + "i", + "<A-.>", + "<esc><cmd>m .+1<cr>==gi", + { noremap = true, silent = true, desc = "Move line down in insert mode" } +) +vim.keymap.set("v", "<C-,>", ":m '<-2<cr>gv=gv", { desc = "Move selected lines up" }) +vim.keymap.set("v", "<C-.>", ":m '>+1<cr>gv=gv", { desc = "Move selected lines down" }) + +-- Markdown +vim.keymap.set({ "n", "v" }, "gk", function() + -- `?` - Start a search backwards from the current cursor position. + -- `^` - Match the beginning of a line. + -- `##` - Match 2 ## symbols + -- `\\+` - Match one or more occurrences of prev element (#) + -- `\\s` - Match exactly one whitespace character following the hashes + -- `.*` - Match any characters (except newline) following the space + -- `$` - Match extends to end of line + vim.cmd("silent! ?^##\\+\\s.*$") + -- Clear the search highlight + vim.cmd("nohlsearch") +end, { desc = "Go to previous markdown header" }) +vim.keymap.set({ "n", "v" }, "gj", function() + -- `/` - Start a search forwards from the current cursor position. + -- `^` - Match the beginning of a line. + -- `##` - Match 2 ## symbols + -- `\\+` - Match one or more occurrences of prev element (#) + -- `\\s` - Match exactly one whitespace character following the hashes + -- `.*` - Match any characters (except newline) following the space + -- `$` - Match extends to end of line + vim.cmd("silent! /^##\\+\\s.*$") + -- Clear the search highlight + vim.cmd("nohlsearch") +end, { desc = "Go to next markdown header" }) + +-- Marks +vim.keymap.set("n", "<leader>mD", function() + -- Delete all marks in the current buffer + vim.cmd("delmarks!") + print("All marks deleted.") +end, { desc = "Delete all marks" }) + +-- Ownerships +vim.keymap.set("n", "<leader>cx", "<cmd>!chmod +x %<cr>", { silent = true, desc = "Make file executable" }) + +-- Remap Default +vim.keymap.set("i", "jk", "<esc>", { noremap = true, silent = true, desc = "Escape to normal mode" }) +vim.keymap.set("i", "<C-c>", "<esc>", { noremap = true, silent = true, desc = "Escape to normal mode" }) +vim.keymap.set("i", "<C-a>", "<home>", { noremap = true, silent = true, desc = "Insert at beginning of line" }) +vim.keymap.set("i", "<C-e>", "<end>", { noremap = true, silent = true, desc = "Move to end of line" }) +vim.keymap.set("i", "<C-h>", "<left>", { noremap = true, silent = true, desc = "Move left" }) +vim.keymap.set("i", "<C-l>", "<right>", { noremap = true, silent = true, desc = "Move right" }) +vim.keymap.set("i", "<C-j>", "<down>", { noremap = true, silent = true, desc = "Move down" }) +vim.keymap.set("i", "<C-k>", "<up>", { noremap = true, silent = true, desc = "Move up" }) +vim.keymap.set("i", "<C-b>", "<up><end><cr>", { noremap = true, silent = true, desc = "New line above" }) +vim.keymap.set("i", "<C-f>", "<end><cr>", { noremap = true, silent = true, desc = "New line below" }) +vim.keymap.set("n", "<C-c>", ":", { noremap = true, desc = "Enter command mode" }) +vim.keymap.set("n", "J", "mzJ`z", { noremap = true, desc = "Join lines and keep cursor position" }) +vim.keymap.set("n", "n", "'Nn'[v:searchforward].'zv'", { expr = true, desc = "Next search result and center" }) +vim.keymap.set("x", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result in visual mode" }) +vim.keymap.set("o", "n", "'Nn'[v:searchforward]", { expr = true, desc = "Next search result in operator-pending mode" }) +vim.keymap.set("n", "N", "'nN'[v:searchforward].'zv'", { expr = true, desc = "Previous search result and center" }) +vim.keymap.set("x", "N", "'nN'[v:searchforward]", { expr = true, desc = "Previous search result in visual mode" }) +vim.keymap.set( + "o", + "N", + "'nN'[v:searchforward]", + { expr = true, desc = "Previous search result in operator-pending mode" } +) +vim.keymap.set("n", "x", '"_x', { desc = "Delete character without yanking" }) +local scroll_percentage = 0.50 +vim.keymap.set("n", "<C-d>", function() + local lines = math.floor(vim.api.nvim_win_get_height(0) * scroll_percentage) + vim.cmd("normal! " .. lines .. "jzz") +end, { noremap = true, silent = true, desc = "Scroll down and center" }) +vim.keymap.set("n", "<C-u>", function() + local lines = math.floor(vim.api.nvim_win_get_height(0) * scroll_percentage) + vim.cmd("normal! " .. lines .. "kzz") +end, { noremap = true, silent = true, desc = "Scroll up and center" }) +-- vim.keymap.set("n", "<C-d>", "<C-d>zz", { noremap = true, silent = true, desc = "Scroll down and center" }) +-- vim.keymap.set("n", "<C-u>", "<C-u>zz", { noremap = true, silent = true, desc = "Scroll up and center" }) +vim.keymap.set("n", "<C-b>", "<C-b>zz", { noremap = true, silent = true, desc = "Page up and center" }) +vim.keymap.set("n", "<C-f>", "<C-f>zz", { noremap = true, silent = true, desc = "Page down and center" }) +vim.keymap.set("n", "{", "{zz", { noremap = true, silent = true, desc = "Move to previous paragraph and center" }) +vim.keymap.set("n", "}", "}zz", { noremap = true, silent = true, desc = "Move to next paragraph and center" }) +vim.keymap.set("n", "G", "Gzz", { noremap = true, silent = true, desc = "Go to bottom of file and center" }) +vim.keymap.set("n", "gg", "ggzz", { noremap = true, silent = true, desc = "Go to top of file and center" }) +vim.keymap.set("n", "gd", "gdzz", { noremap = true, silent = true, desc = "Go to definition and center" }) +vim.keymap.set("n", "<C-i>", "<C-i>zz", { noremap = true, silent = true, desc = "Jump forward in jumplist and center" }) +vim.keymap.set( + "n", + "<C-o>", + "<C-o>zz", + { noremap = true, silent = true, desc = "Jump backward in jumplist and center" } +) +vim.keymap.set( + "n", + "%", + "%zz", + { noremap = true, silent = true, desc = "Jump to matching pair (e.g. brackets) and center" } +) +vim.keymap.set( + "n", + "*", + "*zz", + { noremap = true, silent = true, desc = "Search for next occurrence of word under cursor and center" } +) +vim.keymap.set( + "n", + "#", + "#zz", + { noremap = true, silent = true, desc = "Search for previous occurrence of word under cursor and center" } +) + +vim.keymap.set( + { "n", "x" }, + "j", + "v:count == 0 ? 'gj' : 'j'", + { expr = true, silent = true, desc = "Move down (visual line)" } +) +vim.keymap.set( + { "n", "x" }, + "<down>", + "v:count == 0 ? 'gj' : 'j'", + { expr = true, silent = true, desc = "Move down (visual line)" } +) +vim.keymap.set( + { "n", "x" }, + "k", + "v:count == 0 ? 'gk' : 'k'", + { expr = true, silent = true, desc = "Move up (visual line)" } +) +vim.keymap.set( + { "n", "x" }, + "<up>", + "v:count == 0 ? 'gk' : 'k'", + { expr = true, silent = true, desc = "Move up (visual line)" } +) +vim.keymap.set("v", "<", "<gv", { desc = "Indent left and stay in visual mode" }) +vim.keymap.set("v", ">", ">gv", { desc = "Indent right and stay in visual mode" }) +vim.keymap.set("v", "J", ":m '>+1<cr>gv=gv", { desc = "Move line down in visual mode" }) +vim.keymap.set("v", "K", ":m '<-2<cr>gv=gv", { desc = "Move line up in visual mode" }) +vim.keymap.set("n", "sl", "vg_", { desc = "Select to end of line" }) +vim.keymap.set("n", "sp", "ggVGp", { desc = "Select all and paste" }) +vim.keymap.set("n", "sv", "ggVG", { desc = "Select all" }) +vim.keymap.set("n", "gp", "`[v`]", { desc = "Select pasted text" }) +vim.keymap.set("n", "ss", ":s/\\v", { desc = "Search and replace on line" }) +vim.keymap.set("n", "SS", ":%s/\\v", { desc = "Search and replace in file" }) +vim.keymap.set("v", "<leader><C-s>", ":s/\\%V", { desc = "Search only in visual selection using %V atom" }) +vim.keymap.set("v", "<C-r>", '"hy:%s/\\v<C-r>h//g<left><left>', { desc = "Change selection" }) + +-- Remove +local function delete_current_file() + local filepath = vim.fn.expand("%:p") + local filename = vim.fn.expand("%:t") -- Get the current filename + if filepath and filepath ~= "" then + -- Check if trash utility is installed + if vim.fn.executable("trash") == 0 then + vim.api.nvim_echo({ + { "- Trash utility not installed. Make sure to install it first\n", "ErrorMsg" }, + { "- Install `trash-cli`\n", nil }, + }, false, {}) + return + end + -- Prompt for confirmation before deleting the file + vim.ui.input({ + prompt = 'Do you want to delete "' .. filename .. '"? (y/n): ', + }, function(input) + if input == nil then + return + end + + if input:lower() == "y" or input:lower() == "yes" then + -- Delete the file using trash app + local success, _ = pcall(function() + vim.fn.system({ "trash", vim.fn.fnameescape(filepath) }) + end) + if success then + vim.api.nvim_echo({ + { "File deleted from disk:\n", "Normal" }, + { filepath, "Normal" }, + }, false, {}) + -- Close the buffer after deleting the file + vim.cmd("bd!") + else + vim.api.nvim_echo({ + { "Failed to delete file:\n", "ErrorMsg" }, + { filepath, "ErrorMsg" }, + }, false, {}) + end + else + vim.api.nvim_echo({ + { "File deletion canceled.", "Normal" }, + }, false, {}) + end + end) + else + vim.api.nvim_echo({ + { "No file to delete", "WarningMsg" }, + }, false, {}) + end +end + +vim.keymap.set("n", "<leader>rm", function() + delete_current_file() +end, { desc = "Remove current file" }) + +-- Scripts +vim.api.nvim_set_keymap( + "n", + "<leader>rr", + ':w!<cr>:lua vim.cmd("split | resize 10 | terminal compiler " .. vim.fn.expand("%:p"))<cr>', + { noremap = true, silent = true, desc = "Run compiler interactively" } +) +vim.api.nvim_set_keymap( + "n", + "<leader>ov", + ":!opout <C-r>%<cr><cr>", + { noremap = true, silent = true, desc = "Docs viewer" } +) + +-- Source +-- source nvim config +vim.keymap.set("n", "<leader>SO", function() + vim.cmd("so") +end, { desc = "Source current file" }) +-- reload zsh configuration by sourcing ~/.config/zsh/.zshrc in a separate shell +vim.keymap.set("n", "<leader>SZ", function() + -- Define the command to source zshrc + local command = "source ~/.config/zsh/.zshrc" + -- Execute the command in a new Zsh shell + local full_command = "zsh -c '" .. command .. "'" + -- Run the command and capture the output + local output = vim.fn.system(full_command) + -- Check the exit status of the command + local exit_code = vim.v.shell_error + if exit_code == 0 then + vim.api.nvim_echo({ { "Successfully sourced ~/.config/zsh/.zshrc", "NormalMsg" } }, false, {}) + else + vim.api.nvim_echo({ + { "Failed to source ~/.config/zsh/.zshrc:", "ErrorMsg" }, + { output, "ErrorMsg" }, + }, false, {}) + end +end, { desc = "Source zshrc" }) +-- source shortcuts from bm-files and bm-folders +local shortcuts_file = vim.fn.expand("~/.config/nvim/shortcuts.lua") +local file = io.open(shortcuts_file, "r") +if file then + file:close() + vim.cmd("silent! source " .. shortcuts_file) +end + +-- Spell +vim.keymap.set("n", "zp", function() + vim.opt.spelllang = { "en", "cjk" } + vim.cmd("echo 'Spell language set to English and CJK'") +end, { desc = "Spelling language English and CJK" }) +-- repeat the replacement done by |z=| for all matches with the replaced word in the current window. +vim.keymap.set("n", "z.", function() + vim.api.nvim_feedkeys(vim.api.nvim_replace_termcodes(":spellr\n", true, false, true), "m", true) +end, { desc = "Spelling repeat" }) + +-- Sudo +vim.keymap.set("n", "<leader>SW", "<cmd>SudoWrite<cr><cr>", { silent = true, desc = "Save file with sudo" }) +vim.keymap.set("n", "<leader>SWQ", "<cmd>SudoWritequit<cr>", { silent = true, desc = "Save and quit with sudo" }) + +-- Surround +vim.keymap.set("n", "sau", function() + local line = vim.api.nvim_get_current_line() + local col = vim.api.nvim_win_get_cursor(0)[2] + 1 -- Adjust for 0-index in Lua + -- This makes the `s` optional so it matches both http and https + local pattern = "https?://[^ ,;'\"<>%s)]*" + -- Find the starting and ending positions of the URL + local s, e = string.find(line, pattern) + while s and e do + if s <= col and e >= col then + -- When the cursor is within the URL + local url = string.sub(line, s, e) + -- Update the line with backticks around the URL + local new_line = string.sub(line, 1, s - 1) .. "`" .. url .. "`" .. string.sub(line, e + 1) + vim.api.nvim_set_current_line(new_line) + vim.cmd("silent write") + return + end + -- Find the next URL in the line + s, e = string.find(line, pattern, e + 1) + -- Save the file to update trouble list + end + print("No URL found under cursor") +end, { desc = "Add surrounding to URL" }) +vim.keymap.set("v", "<leader>bl", function() + -- Get the selected text range + local start_row, start_col = unpack(vim.fn.getpos("'<"), 2, 3) + local end_row, end_col = unpack(vim.fn.getpos("'>"), 2, 3) + -- Get the selected lines + local lines = vim.api.nvim_buf_get_lines(0, start_row - 1, end_row, false) + local selected_text = table.concat(lines, "\n"):sub(start_col, #lines == 1 and end_col or -1) + if selected_text:match("^%*%*.*%*%*$") then + vim.notify("Text already bold", vim.log.levels.INFO) + else + vim.cmd("normal 2gsa*") + end +end, { desc = "Bold current selection" }) +vim.keymap.set("n", "gbd", function() + local cursor_pos = vim.api.nvim_win_get_cursor(0) + local current_buffer = vim.api.nvim_get_current_buf() + local start_row = cursor_pos[1] - 1 + local col = cursor_pos[2] + -- Get the current line + local line = vim.api.nvim_buf_get_lines(current_buffer, start_row, start_row + 1, false)[1] + -- Check if the cursor is on an asterisk + if line:sub(col + 1, col + 1):match("%*") then + vim.notify("Cursor is on an asterisk, run inside the bold text", vim.log.levels.WARN) + return + end + -- Search for '**' to the left of the cursor position + local left_text = line:sub(1, col) + local bold_start = left_text:reverse():find("%*%*") + if bold_start then + bold_start = col - bold_start + end + -- Search for '**' to the right of the cursor position and in following lines + local right_text = line:sub(col + 1) + local bold_end = right_text:find("%*%*") + local end_row = start_row + while not bold_end and end_row < vim.api.nvim_buf_line_count(current_buffer) - 1 do + end_row = end_row + 1 + local next_line = vim.api.nvim_buf_get_lines(current_buffer, end_row, end_row + 1, false)[1] + if next_line == "" then + break + end + right_text = right_text .. "\n" .. next_line + bold_end = right_text:find("%*%*") + end + if bold_end then + bold_end = col + bold_end + end + -- Remove '**' markers if found, otherwise bold the word + if bold_start and bold_end then + -- Extract lines + local text_lines = vim.api.nvim_buf_get_lines(current_buffer, start_row, end_row + 1, false) + local text = table.concat(text_lines, "\n") + -- Calculate positions to correctly remove '**' + -- vim.notify("bold_start: " .. bold_start .. ", bold_end: " .. bold_end) + local new_text = text:sub(1, bold_start - 1) .. text:sub(bold_start + 2, bold_end - 1) .. text:sub(bold_end + 2) + local new_lines = vim.split(new_text, "\n") + -- Set new lines in buffer + vim.api.nvim_buf_set_lines(current_buffer, start_row, end_row + 1, false, new_lines) + -- vim.notify("Unbolded text", vim.log.levels.INFO) + else + -- Bold the word at the cursor position if no bold markers are found + local before = line:sub(1, col) + local after = line:sub(col + 1) + local inside_surround = before:match("%*%*[^%*]*$") and after:match("^[^%*]*%*%*") + if inside_surround then + vim.cmd("normal gsd*.") + else + vim.cmd("normal viw") + vim.cmd("normal 2gsa*") + end + vim.notify("Bolded current word", vim.log.levels.INFO) + end +end, { desc = "Toggle bold" }) + +-- Tab +vim.keymap.set("n", "<leader><tab>l", "<cmd>tablast<cr>", { desc = "Last Tab" }) +vim.keymap.set("n", "]]<tab>", "<cmd>tablast<cr>", { desc = "Last Tab" }) +vim.keymap.set("n", "<leader><tab>o", "<cmd>tabonly<cr>", { desc = "Close Other Tabs" }) +vim.keymap.set("n", "<leader><tab>f", "<cmd>tabfirst<cr>", { desc = "First Tab" }) +vim.keymap.set("n", "[[<tab>", "<cmd>tabfirst<cr>", { desc = "First Tab" }) +vim.keymap.set("n", "<leader><tab><tab>", "<cmd>tabnew<cr>", { desc = "New Tab" }) +vim.keymap.set("n", "<leader><tab>n", "<cmd>tabnext<cr>", { desc = "Next Tab" }) +vim.keymap.set("n", "]<tab>", "<cmd>tabnext<cr>", { desc = "Next Tab" }) +vim.keymap.set("n", "<leader><tab>d", "<cmd>tabclose<cr>", { desc = "Close Tab" }) +vim.keymap.set("n", "<leader><tab>p", "<cmd>tabprevious<cr>", { desc = "Previous Tab" }) +vim.keymap.set("n", "[<tab>", "<cmd>tabprevious<cr>", { desc = "Previous Tab" }) + +-- Terminal +vim.keymap.set("n", "<leader>te", "<cmd>term<cr>", { desc = "Open terminal" }) +vim.keymap.set("n", "<leader>t-", "<cmd>sp term://zsh | startinsert<cr>", { desc = "Split terminal (horizontal)" }) +vim.keymap.set("n", "<leader>t|", "<cmd>vsp term://zsh | startinsert<cr>", { desc = "Split terminal (vertical)" }) +vim.keymap.set("t", "<esc><esc>", "<C-\\><C-n>", { desc = "Escape terminal mode" }) +vim.keymap.set("t", "<C-h>", "<cmd>wincmd h<cr>", { desc = "Move to left window" }) +vim.keymap.set("t", "<C-j>", "<cmd>wincmd j<cr>", { desc = "Move to window below" }) +vim.keymap.set("t", "<C-k>", "<cmd>wincmd k<cr>", { desc = "Move to window above" }) +vim.keymap.set("t", "<C-l>", "<cmd>wincmd l<cr>", { desc = "Move to right window" }) +vim.keymap.set("t", "<C-Space>l", "clear<cr>", { silent = true, desc = "Clear terminal" }) +vim.keymap.set("t", "<C-\\>", "<C-\\><C-n>iexit<cr>", { desc = "Close terminal" }) +vim.keymap.set("t", "<C-/>", "<cmd>close<cr>", { desc = "Close terminal" }) +vim.keymap.set("t", "<C-_>", "<cmd>close<cr>", { desc = "Close terminal" }) + +-- Tmux +if vim.env.TMUX then + vim.keymap.set( + "n", + "<leader>tm", + "<cmd>silent !~/.config/tmux/plugins/tmux-fzf/scripts/session.sh<cr>", + { desc = "Find tmux session" } + ) + vim.keymap.set("n", "<leader>RS", function() + vim.fn.system("restartnvim") + end, { noremap = true, silent = true, desc = "Restart nvim (tmux)" }) +end + +-- Todo +-- detect todos and toggle between ":" and ";", or show a message if not found +-- this is to "mark them as done" +vim.keymap.set("n", "<leader>td", function() + -- Get the current line + local current_line = vim.fn.getline(".") + -- Get the current line number + local line_number = vim.fn.line(".") + if string.find(current_line, "TODO:") then + -- Replace the first occurrence of ":" with ";" + local new_line = current_line:gsub("TODO:", "TODO;") + -- Set the modified line + vim.fn.setline(line_number, new_line) + elseif string.find(current_line, "TODO;") then + -- Replace the first occurrence of ";" with ":" + local new_line = current_line:gsub("TODO;", "TODO:") + -- Set the modified line + vim.fn.setline(line_number, new_line) + else + vim.cmd("echo 'todo item not detected'") + end +end, { desc = "Toggle TODO item done or not" }) + +-- Windows +vim.keymap.set("n", "<C-h>", "<C-w><C-h>", { desc = "Move to left window" }) +vim.keymap.set("n", "<C-j>", "<C-w><C-j>", { desc = "Move to window below" }) +vim.keymap.set("n", "<C-k>", "<C-w><C-k>", { desc = "Move to window above" }) +vim.keymap.set("n", "<C-l>", "<C-w><C-l>", { desc = "Move to right window" }) +-- vim.keymap.set("n", "<C-up>", "<cmd>resize +2<cr>", { desc = "Increase window height" }) +-- vim.keymap.set("n", "<C-down>", "<cmd>resize -2<cr>", { desc = "Decrease window height" }) +-- vim.keymap.set("n", "<C-left>", "<cmd>vertical resize -2<cr>", { desc = "Decrease window width" }) +-- vim.keymap.set("n", "<C-right>", "<cmd>vertical resize +2<cr>", { desc = "Increase window width" }) + +function WordDefinition(input) + -- Function to run the dict command and return its output + local function get_output(word) + local escaped_word = vim.fn.shellescape(word) + return vim.fn.system("dict " .. escaped_word) + end + + -- Function to process the word for singular/plural handling + local function get_definition(word) + -- Attempt to derive the singular form + local singular = word + if word:sub(-2) == "es" then + singular = word:sub(1, -3) -- Remove 'es' + elseif word:sub(-1) == "s" then + singular = word:sub(1, -2) -- Remove 's' + end + + -- Fetch output for both singular and original word + local singular_output = get_output(singular) + local original_output = get_output(word) + + -- Determine which output to prioritize + if singular ~= word and not vim.startswith(singular_output, "No definitions found") then + return singular_output -- Use singular if valid and different + else + return original_output -- Otherwise, use the original word + end + end + + -- Get the definition and output for the word + local output = get_definition(input) + + -- Create a new buffer and display the result + local bufnr = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_current_buf(bufnr) + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, vim.split(output, "\n")) +end +vim.api.nvim_set_keymap( + "n", + "<leader>k", + ":lua WordDefinition(vim.fn.expand('<cword>'))<cr>", + { noremap = true, silent = true, desc = "Word definition" } +) + +-- Lazy +vim.keymap.set("n", "<leader>L", "<cmd>Lazy<cr>", { desc = "Open lazy plugin manager" }) + +-- Mason +vim.keymap.set("n", "<leader>M", "<cmd>Mason<cr>", { desc = "Open mason" }) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/core/lazy.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/lazy.lua new file mode 100644 index 0000000..8097325 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/lazy.lua @@ -0,0 +1,17 @@ +local lazypath = vim.fn.stdpath("data") .. "/lazy/lazy.nvim" +if not vim.loop.fs_stat(lazypath) then + local lazyrepo = "https://github.com/folke/lazy.nvim.git" + vim.fn.system({ "git", "clone", "--filter=blob:none", "--branch=stable", lazyrepo, lazypath }) +end ---@diagnostic disable-next-line: undefined-field +vim.opt.rtp:prepend(lazypath) + +require("lazy").setup({ + spec = { + { import = "thesiahxyz.plugins" }, + }, + install = { + colorscheme = { "catppuccin" }, + }, + change_detection = { notify = false }, + checker = { enabled = false }, +}) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/core/options.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/options.lua new file mode 100644 index 0000000..9c1a6a6 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/core/options.lua @@ -0,0 +1,42 @@ +vim.g.have_nerd_font = true +-- vim.g.netrw_browse_split = 0 +-- vim.g.netrw_banner = 1 +-- vim.g.netrw_browsex_viewer = "xdg-open" +-- vim.g.netrw_liststyle = 0 +-- vim.g.netrw_list_hide = "^.git" +-- vim.g.netrw_winsize = 25 +-- vim.g.loaded_netrw = 1 +-- vim.g.loaded_netrwPlugin = 1 +vim.opt.backup = false +vim.opt.breakindent = true +vim.opt.conceallevel = 1 +vim.opt.cursorline = true +vim.opt.expandtab = true +vim.opt.hlsearch = true +vim.opt.ignorecase = true +vim.opt.inccommand = "split" +vim.opt.incsearch = true +vim.opt.isfname:append("@-@") +vim.opt.list = true +vim.opt.listchars = { tab = " ", trail = " ", nbsp = " " } +vim.opt.mouse = "a" +vim.opt.number = true +vim.opt.relativenumber = true +vim.opt.scrolloff = 8 +vim.opt.shiftwidth = 2 +vim.opt.showmode = false +vim.opt.signcolumn = "yes" +vim.opt.smartcase = true +vim.opt.smartindent = true +vim.opt.softtabstop = 2 +vim.opt.spellfile = vim.fn.expand(vim.fn.stdpath("config") .. "/lua/thesiahxyz/spells/en.utf-8.add") +vim.opt.splitbelow = true +vim.opt.splitright = true +vim.opt.swapfile = false +vim.opt.tabstop = 2 +vim.opt.termguicolors = true +vim.opt.timeoutlen = 300 +vim.opt.updatetime = 300 +vim.opt.undofile = true +vim.opt.undodir = os.getenv("HOME") .. "/.local/share/history/vim_history" +vim.opt.wrap = false diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/health.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/health.lua new file mode 100644 index 0000000..dba5f3a --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/health.lua @@ -0,0 +1,45 @@ +local check_version = function() + local verstr = string.format("%s.%s.%s", vim.version().major, vim.version().minor, vim.version().patch) + if not vim.version.cmp then + vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) + return + end + + if vim.version.cmp(vim.version(), { 0, 9, 4 }) >= 0 then + vim.health.ok(string.format("Neovim version is: '%s'", verstr)) + else + vim.health.error(string.format("Neovim out of date: '%s'. Upgrade to latest stable or nightly", verstr)) + end +end + +local check_external_reqs = function() + -- Basic utils: `git`, `make`, `unzip` + for _, exe in ipairs({ "git", "make", "unzip", "rg" }) do + local is_executable = vim.fn.executable(exe) == 1 + if is_executable then + vim.health.ok(string.format("Found executable: '%s'", exe)) + else + vim.health.warn(string.format("Could not find executable: '%s'", exe)) + end + end + + return true +end + +return { + check = function() + vim.health.start("TheSiahxyz") + + vim.health.info([[NOTE: Not every warning is a 'must-fix' in `:checkhealth` + + Fix only warnings for plugins and languages you intend to use. + Mason will give warnings for languages that are not installed. + You do not need to install, unless you want to use those languages!]]) + + local uv = vim.uv or vim.loop + vim.health.info("System Information: " .. vim.inspect(uv.os_uname())) + + check_version() + check_external_reqs() + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/init.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/init.lua new file mode 100644 index 0000000..2a8bc78 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/init.lua @@ -0,0 +1,15 @@ +-- Core +require("thesiahxyz.core.autocmds") +require("thesiahxyz.core.keymaps") +require("thesiahxyz.core.options") +require("thesiahxyz.core.lazy") + +-- Custom +for _, file in ipairs(vim.fn.readdir(vim.fn.stdpath("config") .. "/lua/thesiahxyz/utils", [[v:val =~ '\.lua$']])) do + require("thesiahxyz.utils." .. file:gsub("%.lua$", "")) +end + +-- Plenary +function R(name) + require("plenary.reload").reload_module(name) +end diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/ai.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/ai.lua new file mode 100644 index 0000000..2fca9f7 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/ai.lua @@ -0,0 +1,286 @@ +return { + { + "robitx/gp.nvim", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>G", group = "GPT" }, + { "<leader>Gg", group = "Gp" }, + { "<leader>GW", group = "Whisper" }, + }) + end, + config = function() + local function keymapOptions(desc) + return { + noremap = true, + silent = true, + nowait = true, + desc = desc, + } + end + + local conf = { + -- For customization, refer to Install > Configuration in the Documentation/Readme + -- openai_api_key = { "pass", "show", "api/chatGPT/nvim" }, + openai_api_key = { "pass", "show", "api/chatGPT/nvim" }, + providers = { + openai = { + disable = false, + endpoint = "https://api.openai.com/v1/chat/completions", + -- secret = { "pass", "show", "api/chatGPT/nvim" }, + }, + }, + hooks = { + -- GpInspectPlugin provides a detailed inspection of the plugin state + InspectPlugin = function(plugin, params) + local bufnr = vim.api.nvim_create_buf(false, true) + local copy = vim.deepcopy(plugin) + local key = copy.config.openai_api_key or "" + copy.config.openai_api_key = key:sub(1, 3) .. string.rep("*", #key - 6) .. key:sub(-3) + local plugin_info = string.format("Plugin structure:\n%s", vim.inspect(copy)) + local params_info = string.format("Command params:\n%s", vim.inspect(params)) + local lines = vim.split(plugin_info .. "\n" .. params_info, "\n") + vim.api.nvim_buf_set_lines(bufnr, 0, -1, false, lines) + vim.api.nvim_win_set_buf(0, bufnr) + end, + + -- GpInspectLog for checking the log file + InspectLog = function(plugin, params) + local log_file = plugin.config.log_file + local buffer = plugin.helpers.get_buffer(log_file) + if not buffer then + vim.cmd("e " .. log_file) + else + vim.cmd("buffer " .. buffer) + end + end, + + -- GpImplement rewrites the provided selection/range based on comments in it + Implement = function(gp, params) + local template = "Having following from {{filename}}:\n\n" + .. "```{{filetype}}\n{{selection}}\n```\n\n" + .. "Please rewrite this according to the contained instructions." + .. "\n\nRespond exclusively with the snippet that should replace the selection above." + + local agent = gp.get_command_agent() + gp.logger.info("Implementing selection with agent: " .. agent.name) + + gp.Prompt( + params, + gp.Target.rewrite, + agent, + template, + nil, -- command will run directly without any prompting for user input + nil -- no predefined instructions (e.g. speech-to-text from Whisper) + ) + end, + + -- your own functions can go here, see README for more examples like + -- :GpExplain, :GpUnitTests.., :GpTranslator etc. + + -- example of making :%GpChatNew a dedicated command which + -- opens new chat with the entire current buffer as a context + BufferChatNew = function(gp, _) + -- call GpChatNew command in range mode on whole buffer + vim.api.nvim_command("%" .. gp.config.cmd_prefix .. "ChatNew") + end, + + -- example of adding command which opens new chat dedicated for translation + Translator = function(gp, params) + local chat_system_prompt = "You are a Translator, please translate between English and Korean." + gp.cmd.ChatNew(params, chat_system_prompt) + + -- -- you can also create a chat with a specific fixed agent like this: + -- local agent = gp.get_chat_agent("ChatGPT4o") + -- gp.cmd.ChatNew(params, chat_system_prompt, agent) + end, + + -- example of adding command which writes unit tests for the selected code + UnitTests = function(gp, params) + local template = "I have the following code from {{filename}}:\n\n" + .. "```{{filetype}}\n{{selection}}\n```\n\n" + .. "Please respond by writing table driven unit tests for the code above." + local agent = gp.get_command_agent() + gp.Prompt(params, gp.Target.enew, agent, template) + end, + + -- example of adding command which explains the selected code + Explain = function(gp, params) + local template = "I have the following code from {{filename}}:\n\n" + .. "```{{filetype}}\n{{selection}}\n```\n\n" + .. "Please respond by explaining the code above." + local agent = gp.get_chat_agent() + gp.Prompt(params, gp.Target.popup, agent, template) + end, + + -- example of usig enew as a function specifying type for the new buffer + CodeReview = function(gp, params) + local template = "I have the following code from {{filename}}:\n\n" + .. "```{{filetype}}\n{{selection}}\n```\n\n" + .. "Please analyze for code smells and suggest improvements." + local agent = gp.get_chat_agent() + gp.Prompt(params, gp.Target.enew("markdown"), agent, template) + end, + }, + } + require("gp").setup(conf) + + -- Setup shortcuts here (see Usage > Shortcuts in the Documentation/Readme) + vim.keymap.set({ "n", "i" }, "<leader>Gc", "<cmd>GpChatNew<cr>", keymapOptions("New chat")) + vim.keymap.set({ "n", "i" }, "<leader>Gb", "<cmd>GpBufferChatNew<cr>", keymapOptions("New buffer chat")) + vim.keymap.set({ "n", "i" }, "<leader>Gt", "<cmd>GpChatToggle<cr>", keymapOptions("Toggle chat")) + vim.keymap.set({ "n", "i" }, "<leader>Gf", "<cmd>GpChatFinder<cr>", keymapOptions("Chat finder")) + + vim.keymap.set("v", "<leader>Gc", ":<C-u>'<,'>GpChatNew<cr>", keymapOptions("Chat new")) + vim.keymap.set("v", "<leader>Gb", ":<C-u>'<,'>GpBufferChatNew<cr>", keymapOptions("Buffer chat new")) + vim.keymap.set("v", "<leader>Gp", ":<C-u>'<,'>GpChatPaste<cr>", keymapOptions("Chat paste")) + vim.keymap.set("v", "<leader>Gt", ":<C-u>'<,'>GpChatToggle<cr>", keymapOptions("Toggle chat")) + + vim.keymap.set({ "n", "i" }, "<leader>Gh", "<cmd>gpchatnew split<cr>", keymapOptions("New chat split")) + vim.keymap.set({ "n", "i" }, "<leader>Gv", "<cmd>gpchatnew vsplit<cr>", keymapOptions("New chat vsplit")) + vim.keymap.set({ "n", "i" }, "<leader>Gn", "<cmd>gpchatnew tabnew<cr>", keymapOptions("New chat tabnew")) + + vim.keymap.set("v", "<leader>Gh", ":<C-u>'<,'>GpChatNew split<cr>", keymapOptions("Chat new split")) + vim.keymap.set("v", "<leader>Gv", ":<C-u>'<,'>GpChatNew vsplit<cr>", keymapOptions("Chat new vsplit")) + vim.keymap.set("v", "<leader>Gn", ":<C-u>'<,'>GpChatNew tabnew<cr>", keymapOptions("Chat new tabnew")) + + -- Prompt commands + vim.keymap.set({ "n", "i" }, "<leader>Gw", "<cmd>GpRewrite<cr>", keymapOptions("Inline rewrite")) + vim.keymap.set({ "n", "i" }, "<leader>Gr", "<cmd>GpCodeReview<cr>", keymapOptions("Code review")) + vim.keymap.set({ "n", "i" }, "<leader>G]", "<cmd>GpAppend<cr>", keymapOptions("Append (after)")) + vim.keymap.set({ "n", "i" }, "<leader>G[", "<cmd>GpPrepend<cr>", keymapOptions("Prepend (before)")) + + vim.keymap.set("v", "<leader>Gw", ":<C-u>'<,'>GpRewrite<cr>", keymapOptions("Rewrite")) + vim.keymap.set("v", "<leader>Gr", ":<C-u>'<,'>GpCodeReview<cr>", keymapOptions("Code review")) + vim.keymap.set("v", "<leader>G]", ":<C-u>'<,'>GpAppend<cr>", keymapOptions("Append (after)")) + vim.keymap.set("v", "<leader>G[", ":<C-u>'<,'>GpPrepend<cr>", keymapOptions("Prepend (before)")) + vim.keymap.set("v", "<leader>Gi", ":<C-u>'<,'>GpImplement<cr>", keymapOptions("Implement selection")) + + vim.keymap.set({ "n", "i" }, "<leader>Ggp", "<cmd>GpPopup<cr>", keymapOptions("Popup")) + vim.keymap.set({ "n", "i" }, "<leader>Gge", "<cmd>GpEnew<cr>", keymapOptions("GpEnew")) + vim.keymap.set({ "n", "i" }, "<leader>Ggc", "<cmd>GpNew<cr>", keymapOptions("GpNew")) + vim.keymap.set({ "n", "i" }, "<leader>Ggv", "<cmd>GpVnew<cr>", keymapOptions("GpVnew")) + vim.keymap.set({ "n", "i" }, "<leader>Ggn", "<cmd>GpTabnew<cr>", keymapOptions("GpTabnew")) + + vim.keymap.set("v", "<leader>Ggp", ":<C-u>'<,'>GpPopup<cr>", keymapOptions("Popup")) + vim.keymap.set("v", "<leader>Gge", ":<C-u>'<,'>GpEnew<cr>", keymapOptions("GpEnew")) + vim.keymap.set("v", "<leader>Ggc", ":<C-u>'<,'>GpNew<cr>", keymapOptions("GpNew")) + vim.keymap.set("v", "<leader>Ggv", ":<C-u>'<,'>GpVnew<cr>", keymapOptions("GpVnew")) + vim.keymap.set("v", "<leader>Ggn", ":<C-u>'<,'>GpTabnew<cr>", keymapOptions("GpTabnew")) + + vim.keymap.set({ "n", "i" }, "<leader>Gx", "<cmd>GpContext<cr>", keymapOptions("Toggle context")) + vim.keymap.set("v", "<leader>Gx", ":<C-u>'<,'>GpContext<cr>", keymapOptions("Toggle context")) + + vim.keymap.set({ "n", "i", "v", "x" }, "<leader>Ggs", "<cmd>GpStop<cr>", keymapOptions("Stop")) + vim.keymap.set({ "n", "i", "v", "x" }, "<leader>Gg]", "<cmd>GpNextAgent<cr>", keymapOptions("Next agent")) + + -- optional Whisper commands with prefix <C-g>w + vim.keymap.set({ "n", "i" }, "<leader>GWw", "<cmd>GpWhisper<cr>", keymapOptions("Whisper")) + vim.keymap.set("v", "<leader>GWw", ":<C-u>'<,'>GpWhisper<cr>", keymapOptions("Whisper")) + + vim.keymap.set({ "n", "i" }, "<leader>GWr", "<cmd>GpWhisperRewrite<cr>", keymapOptions("Inline rewrite")) + vim.keymap.set({ "n", "i" }, "<leader>GW]", "<cmd>GpWhisperAppend<cr>", keymapOptions("Append (after)")) + vim.keymap.set({ "n", "i" }, "<leader>GW[", "<cmd>GpWhisperPrepend<cr>", keymapOptions("Prepend (before) ")) + + vim.keymap.set("v", "<leader>GWr", ":<C-u>'<,'>GpWhisperRewrite<cr>", keymapOptions("Rewrite")) + vim.keymap.set("v", "<leader>GW]", ":<C-u>'<,'>GpWhisperAppend<cr>", keymapOptions("Append (after)")) + vim.keymap.set("v", "<leader>GW[", ":<C-u>'<,'>GpWhisperPrepend<cr>", keymapOptions("Prepend (before)")) + + vim.keymap.set({ "n", "i" }, "<leader>GWp", "<cmd>GpWhisperPopup<cr>", keymapOptions("Popup")) + vim.keymap.set({ "n", "i" }, "<leader>GWe", "<cmd>GpWhisperEnew<cr>", keymapOptions("Enew")) + vim.keymap.set({ "n", "i" }, "<leader>GWc", "<cmd>GpWhisperNew<cr>", keymapOptions("New")) + vim.keymap.set({ "n", "i" }, "<leader>GWv", "<cmd>GpWhisperVnew<cr>", keymapOptions("Vnew")) + vim.keymap.set({ "n", "i" }, "<leader>GWn", "<cmd>GpWhisperTabnew<cr>", keymapOptions("Tabnew")) + + vim.keymap.set("v", "<leader>GWp", ":<C-u>'<,'>GpWhisperPopup<cr>", keymapOptions("Popup")) + vim.keymap.set("v", "<leader>GWe", ":<C-u>'<,'>GpWhisperEnew<cr>", keymapOptions("Enew")) + vim.keymap.set("v", "<leader>GWc", ":<C-u>'<,'>GpWhisperNew<cr>", keymapOptions("New")) + vim.keymap.set("v", "<leader>GWv", ":<C-u>'<,'>GpWhisperVnew<cr>", keymapOptions("Vnew")) + vim.keymap.set("v", "<leader>GWn", ":<C-u>'<,'>GpWhisperTabnew<cr>", keymapOptions("Tabnew")) + end, + }, + { + "zbirenbaum/copilot.lua", + cmd = "Copilot", + build = ":Copilot auth", + event = "InsertEnter", + dependencies = { + "hrsh7th/nvim-cmp", + { "AndreM222/copilot-lualine" }, + { + "zbirenbaum/copilot-cmp", + config = function() + require("copilot_cmp").setup() + end, + }, + }, + config = function() + require("copilot").setup({ + panel = { + enabled = true, + auto_refresh = true, + keymap = { + jump_prev = "[a", + jump_next = "]a", + accept = "<CR>", + refresh = "gr", + open = "<C-CR>", + }, + layout = { + position = "right", -- | top | left | right + ratio = 0.4, + }, + }, + suggestion = { + enabled = true, + auto_trigger = true, + hide_during_completion = true, + debounce = 75, + keymap = { + accept = "<C-q>", + accept_word = false, + accept_line = false, + next = "<C-n>", + prev = "<C-p>", + dismiss = "<C-\\>", + }, + }, + filetypes = { + cvs = false, + gitcommit = false, + gitrebase = false, + help = true, + hgcommit = false, + markdown = true, + sh = function() + if string.match(vim.fs.basename(vim.api.nvim_buf_get_name(0)), "^%.env.*") then + -- disable for .env files + return false + end + return true + end, + svn = false, + yaml = false, + ["."] = false, + ["*"] = true, + }, + copilot_node_command = "node", -- Node.js version must be > 18.x + server_opts_overrides = {}, + }) + + local cmp = require("cmp") + cmp.event:on("menu_opened", function() + vim.b.copilot_suggestion_hidden = true + end) + + cmp.event:on("menu_closed", function() + vim.b.copilot_suggestion_hidden = false + end) + end, + + vim.keymap.set("n", "<leader>ct", function() + require("copilot.suggestion").toggle_auto_trigger() + end, { noremap = true, silent = true, desc = "Toggle copilot" }), + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/cloak.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/cloak.lua new file mode 100644 index 0000000..09b14d8 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/cloak.lua @@ -0,0 +1,42 @@ +return { + "laytan/cloak.nvim", + lazy = false, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>c", group = "Cloak" }, + }) + end, + config = function() + require("cloak").setup({ + enabled = true, + cloak_character = "*", + -- The applied highlight group (colors) on the cloaking, see `:h highlight`. + highlight_group = "Comment", + patterns = { + { + -- Match any file starting with ".env". + -- This can be a table to match multiple file patterns. + file_pattern = { + ".env*", + "wrangler.toml", + ".dev.vars", + "address*", + "*api*", + }, + -- Match an equals sign and any character after it. + -- This can also be a table of patterns to cloak, + -- example: cloak_pattern = { ":.+", "-.+" } for yaml files. + cloak_pattern = { "=.+", ":.+", "-.+" }, + }, + }, + }) + end, + keys = { + { "<leader>ce", "<cmd>CloakEnable<cr>", desc = "Enable cloak" }, + { "<leader>cd", "<cmd>CloakDisable<cr>", desc = "Disable cloak" }, + { "<leader>cl", "<cmd>CloakPreviewLine<cr>", desc = "Preview line cloak" }, + { "<leader>zC", "<cmd>CloakToggle<cr>", desc = "Toggle cloak" }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/cmp.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/cmp.lua new file mode 100644 index 0000000..276215d --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/cmp.lua @@ -0,0 +1,326 @@ +local trigger_text = ";" + +return { + { + "hrsh7th/nvim-cmp", + event = "InsertEnter", + dependencies = { + "hrsh7th/cmp-buffer", -- source for text in buffer + "hrsh7th/cmp-path", -- source for file system paths + { + "L3MON4D3/LuaSnip", + version = "v2.*", -- Replace <CurrentMajor> by the latest released major (first number of latest release) + build = "make install_jsregexp", + }, + "saadparwaiz1/cmp_luasnip", -- for autocompletion + "rafamadriz/friendly-snippets", -- useful snippets + "onsails/lspkind.nvim", -- vs-code like pictograms + "uga-rosa/cmp-dictionary", -- dictionary & spell + }, + config = function() + local cmp = require("cmp") + local luasnip = require("luasnip") + local has_words_before = function() + unpack = unpack or table.unpack + local line, col = unpack(vim.api.nvim_win_get_cursor(0)) + return col ~= 0 + and vim.api.nvim_buf_get_lines(0, line - 1, line, true)[1]:sub(col, col):match("%s") == nil + end + + require("luasnip.loaders.from_vscode").lazy_load() + + cmp.setup({ + completion = { + completeopt = "menu,menuone,preview,noselect", + }, + snippet = { -- configure how nvim-cmp interacts with snippet engine + expand = function(args) + require("luasnip").lsp_expand(args.body) + end, + }, + mapping = cmp.mapping.preset.insert({ + ["<C-p>"] = cmp.mapping.select_prev_item(), -- previous suggestion + ["<C-n>"] = cmp.mapping.select_next_item(), -- next suggestion + ["<C-d>"] = cmp.mapping.scroll_docs(-4), + ["<C-u>"] = cmp.mapping.scroll_docs(4), + ["<C-Space>"] = cmp.mapping.complete(), -- show completion suggestions + ["<C-x>"] = cmp.mapping.abort(), -- close completion window + ["<C-c>"] = cmp.mapping.close(), + ["<CR>"] = cmp.mapping.confirm({ + behavior = cmp.ConfirmBehavior.Replace, + select = true, + }), + ["<Tab>"] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + -- You could replace the expand_or_jumpable() calls with expand_or_locally_jumpable() + -- this way you will only jump inside the snippet region + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + elseif has_words_before() then + cmp.complete() + else + fallback() + end + end, { "i", "s" }), + ["<S-Tab>"] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif luasnip.jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { "i", "s" }), + }), + -- sources for autocompletion + sources = cmp.config.sources({ + { name = "buffer" }, -- text within current buffer + { name = "crates" }, + { name = "copilot" }, + { name = "dictionary", keyword_length = 2 }, + { name = "emoji" }, + { name = "luasnip" }, -- snippets + { name = "nvim_lsp" }, + { name = "nvim_lua", priority = 100 }, + { name = "path" }, -- file system paths + { name = "projects", priority = 100 }, + { name = "snippets" }, + { name = "vim-dadbod-completion" }, -- Enable dadbod completion source + { name = "vsnip" }, + }), + + -- configure lspkind for vs-code like pictograms in completion menu + formatting = { + expandable_indicator = true, + fields = { + "abbr", + "kind", + "menu", + }, + format = require("lspkind").cmp_format({ + mode = "symbol_text", + maxwidth = 50, + ellipsis_char = "...", + menu = { + buffer = "[Buffer]", + luasnip = "[LuaSnip]", + nvim_lsp = "[LSP]", + nvim_lua = "[Lua]", + projects = "[Projects]", + emoji = "[Emoji]", + vsnip = "[Snippet]", + }, + }), + }, + }) + + -- Use buffer source for `/` and `?` (if you enabled `native_menu`, this won't work anymore). + cmp.setup.cmdline({ "/", "?" }, { + mapping = cmp.mapping.preset.cmdline(), + sources = { + { name = "buffer" }, + }, + }) + + -- Use cmdline & path source for ':' (if you enabled `native_menu`, this won't work anymore). + cmp.setup.cmdline(":", { + mapping = cmp.mapping.preset.cmdline(), + sources = cmp.config.sources({ + { name = "path" }, + }, { + { name = "cmdline" }, + }), + matching = { disallow_symbol_nonprefix_matching = false }, + }) + + -- sql + cmp.setup.filetype({ "sql" }, { + sources = { + { name = "vim-dadbod-completion" }, + { name = "buffer" }, + }, + }) + + local lspkind = require("lspkind") + lspkind.init({ + symbol_map = { + Copilot = "", + }, + }) + + vim.api.nvim_set_hl(0, "CmpItemKindCopilot", { fg = "#6CC644" }) + + require("cmp_dictionary").setup({ + paths = { + "/usr/share/dict/words", + vim.fn.expand(vim.fn.stdpath("config") .. "/lua/thesiahxyz/spells/en.utf-8.add"), + }, + exact_length = 2, + }) + end, + }, + -- { + -- "saghen/blink.cmp", + -- version = "*", + -- -- build = "cargo build --release", + -- opts_extend = { + -- "sources.completion.enabled_providers", + -- "sources.compat", + -- "sources.default", + -- }, + -- enabled = true, + -- dependencies = { + -- { + -- "L3MON4D3/LuaSnip", + -- version = "v2.*", + -- build = "make install_jsregexp", + -- }, + -- "rafamadriz/friendly-snippets", + -- { + -- "saghen/blink.compat", + -- optional = true, -- make optional so it's only enabled if any extras need it + -- opts = {}, + -- version = "*", + -- }, + -- "kristjanhusak/vim-dadbod-completion", + -- "giuxtaposition/blink-cmp-copilot", + -- }, + -- event = "InsertEnter", + -- opts = function(_, opts) + -- opts.sources = vim.tbl_deep_extend("force", opts.sources or {}, { + -- default = { "lsp", "path", "snippets", "buffer", "copilot", "luasnip", "dadbod" }, + -- providers = { + -- lsp = { + -- name = "lsp", + -- enabled = true, + -- module = "blink.cmp.sources.lsp", + -- fallbacks = { "snippets", "luasnip", "buffer" }, + -- score_offset = 90, -- the higher the number, the higher the priority + -- }, + -- luasnip = { + -- name = "luasnip", + -- enabled = true, + -- module = "blink.cmp.sources.luasnip", + -- min_keyword_length = 2, + -- fallbacks = { "snippets" }, + -- score_offset = 85, + -- max_items = 8, + -- }, + -- path = { + -- name = "Path", + -- module = "blink.cmp.sources.path", + -- score_offset = 3, + -- -- When typing a path, I would get snippets and text in the + -- -- suggestions, I want those to show only if there are no path + -- -- suggestions + -- fallbacks = { "snippets", "luasnip", "buffer" }, + -- opts = { + -- trailing_slash = false, + -- label_trailing_slash = true, + -- get_cwd = function(context) + -- return vim.fn.expand(("#%d:p:h"):format(context.bufnr)) + -- end, + -- show_hidden_files_by_default = true, + -- }, + -- }, + -- buffer = { + -- name = "Buffer", + -- enabled = true, + -- max_items = 3, + -- module = "blink.cmp.sources.buffer", + -- min_keyword_length = 4, + -- }, + -- snippets = { + -- name = "Snippets", + -- enabled = true, + -- max_items = 3, + -- module = "blink.cmp.sources.snippets", + -- min_keyword_length = 4, + -- score_offset = 80, -- the higher the number, the higher the priority + -- }, + -- -- Example on how to configure dadbod found in the main repo + -- -- https://github.com/kristijanhusak/vim-dadbod-completion + -- dadbod = { + -- name = "Dadbod", + -- module = "vim_dadbod_completion.blink", + -- score_offset = 85, -- the higher the number, the higher the priority + -- }, + -- -- Third class citizen mf always talking shit + -- copilot = { + -- name = "Copilot", + -- enabled = true, + -- module = "blink-cmp-copilot", + -- min_keyword_length = 6, + -- score_offset = -100, -- the higher the number, the higher the priority + -- async = true, + -- }, + -- }, + -- -- command line completion, thanks to dpetka2001 in reddit + -- -- https://www.reddit.com/r/neovim/comments/1hjjf21/comment/m37fe4d/?utm_source=share&utm_medium=web3x&utm_name=web3xcss&utm_term=1&utm_content=share_button + -- cmdline = function() + -- local type = vim.fn.getcmdtype() + -- if type == "/" or type == "?" then + -- return { "buffer" } + -- end + -- if type == ":" then + -- return { "cmdline" } + -- end + -- return {} + -- end, + -- }) + -- + -- -- This comes from the luasnip extra, if you don't add it, won't be able to + -- -- jump forward or backward in luasnip snippets + -- opts.snippets = { + -- expand = function(snippet) + -- require("luasnip").lsp_expand(snippet) + -- end, + -- active = function(filter) + -- if filter and filter.direction then + -- return require("luasnip").jumpable(filter.direction) + -- end + -- return require("luasnip").in_snippet() + -- end, + -- jump = function(direction) + -- require("luasnip").jump(direction) + -- end, + -- } + -- + -- opts.appearance = { + -- -- sets the fallback highlight groups to nvim-cmp's highlight groups + -- -- useful for when your theme doesn't support blink.cmp + -- -- will be removed in a future release, assuming themes add support + -- use_nvim_cmp_as_default = false, + -- -- set to 'mono' for 'Nerd Font Mono' or 'normal' for 'Nerd Font' + -- -- adjusts spacing to ensure icons are aligned + -- nerd_font_variant = "mono", + -- } + -- + -- opts.completion = { + -- accept = { + -- -- experimental auto-brackets support + -- auto_brackets = { + -- enabled = true, + -- }, + -- }, + -- menu = { + -- draw = { + -- treesitter = { "lsp" }, + -- }, + -- }, + -- documentation = { + -- auto_show = true, + -- auto_show_delay_ms = 200, + -- }, + -- ghost_text = { enabled = true }, + -- } + -- + -- opts.keymap = { + -- preset = "super-tab", + -- } + -- + -- return opts + -- end, + -- }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/colorschemes.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/colorschemes.lua new file mode 100644 index 0000000..dd6296d --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/colorschemes.lua @@ -0,0 +1,268 @@ +function ColorMyPencils(color) + color = color or "catppuccin" + vim.cmd.colorscheme(color) + vim.api.nvim_set_hl(0, "Normal", { bg = "NONE" }) + vim.api.nvim_set_hl(0, "NormalFloat", { bg = "NONE" }) +end + +return { + { "junegunn/seoul256.vim" }, + { + "catppuccin/nvim", + name = "catppuccin", + config = function() + require("catppuccin").setup({ + flavour = "auto", -- latte, frappe, macchiato, mocha + background = { -- :h background + light = "latte", + dark = "mocha", + }, + transparent_background = true, -- disables setting the background color. + show_end_of_buffer = false, -- shows the '~' characters after the end of buffers + term_colors = false, -- sets terminal colors (e.g. `g:terminal_color_0`) + dim_inactive = { + enabled = true, -- dims the background color of inactive window + shade = "dark", + percentage = 0.15, -- percentage of the shade to apply to the inactive window + }, + no_italic = false, -- Force no italic + no_bold = false, -- Force no bold + no_underline = false, -- Force no underline + styles = { -- Handles the styles of general hi groups (see `:h highlight-args`): + comments = { "italic" }, -- Change the style of comments + conditionals = { "italic" }, + loops = {}, + functions = {}, + keywords = {}, + strings = {}, + variables = {}, + numbers = {}, + booleans = {}, + properties = {}, + types = {}, + operators = {}, + -- miscs = {}, -- Uncomment to turn off hard-coded styles + }, + color_overrides = {}, + custom_highlights = {}, + default_integrations = true, + integrations = { + aerial = true, + alpha = true, + blink_cmp = true, + cmp = true, + dashboard = true, + flash = true, + gitsigns = true, + headlines = true, + illuminate = true, + indent_blankline = { enabled = true, scope_color = "peach", colored_indent_levels = true }, + leap = true, + lsp_trouble = true, + mason = true, + markdown = true, + mini = true, + native_lsp = { + enabled = true, + underlines = { + errors = { "undercurl" }, + hints = { "undercurl" }, + warnings = { "undercurl" }, + information = { "undercurl" }, + }, + }, + navic = { enabled = true, custom_bg = "NONE" }, + neotest = true, + neotree = true, + noice = true, + notify = true, + semantic_tokens = true, + telescope = true, + treesitter = true, + treesitter_context = true, + which_key = true, + }, + highlight_overrides = { + mocha = function(mocha) + return { + LineNr = { fg = mocha.overlay2 }, + CursorLineNr = { fg = mocha.sky }, + Normal = { bg = "NONE" }, -- normal text + NormalNC = { bg = "NONE" }, + } + end, + }, + }) + + ColorMyPencils() + end, + }, + { + "ellisonleao/gruvbox.nvim", + priority = 1000, + -- opts = ..., + config = function() + require("gruvbox").setup({ + terminal_colors = true, -- add neovim terminal colors + undercurl = true, + underline = true, + bold = true, + italic = { + strings = true, + emphasis = true, + comments = true, + operators = false, + folds = true, + }, + strikethrough = true, + invert_selection = false, + invert_signs = false, + invert_tabline = false, + invert_intend_guides = false, + inverse = true, -- invert background for search, diffs, statuslines and errors + contrast = "", -- can be "hard", "soft" or empty string + palette_overrides = { + dark1 = "NONE", + }, + overrides = {}, + dim_inactive = true, + transparent_mode = true, + }) + end, + }, + { + "rose-pine/neovim", + name = "rose-pine", + config = function() + require("rose-pine").setup({ + variant = "auto", -- auto, main, moon, or dawn + dark_variant = "main", -- main, moon, or dawn + dim_inactive_windows = false, + extend_background_behind_borders = true, + enable = { + terminal = true, + legacy_highlights = true, -- Improve compatibility for previous versions of Neovim + migrations = true, -- Handle deprecated options automatically + }, + styles = { + bold = true, + italic = false, + transparency = true, + }, + groups = { + border = "muted", + link = "iris", + panel = "surface", + + error = "love", + hint = "iris", + info = "foam", + note = "pine", + todo = "rose", + warn = "gold", + + git_add = "foam", + git_change = "rose", + git_delete = "love", + git_dirty = "rose", + git_ignore = "muted", + git_merge = "iris", + git_rename = "pine", + git_stage = "iris", + git_text = "rose", + git_untracked = "subtle", + + h1 = "iris", + h2 = "foam", + h3 = "rose", + h4 = "gold", + h5 = "pine", + h6 = "foam", + }, + palette = { + -- Override the builtin palette per variant + -- moon = { + -- base = '#18191a', + -- overlay = '#363738', + -- }, + }, + highlight_groups = { + -- Comment = { fg = "foam" }, + -- VertSplit = { fg = "muted", bg = "muted" }, + }, + before_highlight = function(group, highlight, palette) + -- Disable all undercurls + -- if highlight.undercurl then + -- highlight.undercurl = false + -- end + -- + -- Change palette colour + -- if highlight.fg == palette.pine then + -- highlight.fg = palette.foam + -- end + end, + }) + -- vim.cmd("colorscheme rose-pine") + -- vim.cmd("colorscheme rose-pine-main") + -- vim.cmd("colorscheme rose-pine-moon") + -- vim.cmd("colorscheme rose-pine-dawn") + end, + }, + { + "Mofiqul/dracula.nvim", + config = function() + local dracula = require("dracula") + dracula.setup({ + -- customize dracula color palette + colors = { + bg = "#282A36", + fg = "#F8F8F2", + selection = "#44475A", + comment = "#6272A4", + red = "#FF5555", + orange = "#FFB86C", + yellow = "#F1FA8C", + green = "#50fa7b", + purple = "#BD93F9", + cyan = "#8BE9FD", + pink = "#FF79C6", + bright_red = "#FF6E6E", + bright_green = "#69FF94", + bright_yellow = "#FFFFA5", + bright_blue = "#D6ACFF", + bright_magenta = "#FF92DF", + bright_cyan = "#A4FFFF", + bright_white = "#FFFFFF", + menu = "#21222C", + visual = "#3E4452", + gutter_fg = "#4B5263", + nontext = "#3B4048", + white = "#ABB2BF", + black = "#191A21", + }, + -- show the '~' characters after the end of buffers + show_end_of_buffer = true, -- default false + -- use transparent background + transparent_bg = true, -- default false + -- set custom lualine background color + lualine_bg_color = "#44475a", -- default nil + -- set italic comment + italic_comment = true, -- default false + -- overrides the default highlights with table see `:h synIDattr` + overrides = {}, + -- You can use overrides as table like this + -- overrides = { + -- NonText = { fg = "white" }, -- set NonText fg to white + -- NvimTreeIndentMarker = { link = "NonText" }, -- link to NonText highlight + -- Nothing = {} -- clear highlight of Nothing + -- }, + -- Or you can also use it like a function to get color from theme + -- overrides = function (colors) + -- return { + -- NonText = { fg = colors.white }, -- set NonText fg to white of theme + -- } + -- end, + }) + end, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/comment.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/comment.lua new file mode 100644 index 0000000..fe82b02 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/comment.lua @@ -0,0 +1,50 @@ +return { + { + "numToStr/Comment.nvim", + lazy = false, + opts = {}, + config = function() + require("Comment").setup() + end, + }, + { + "folke/todo-comments.nvim", + dependencies = { "nvim-lua/plenary.nvim" }, + opts = {}, + cmd = { "TodoTrouble", "TodoTelescope" }, + config = function() + require("todo-comments").setup() + end, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>t", group = "TODO" }, + }) + end, + keys = { + { + "]t", + function() + require("todo-comments").jump_next() + end, + desc = "Next Todo Comment", + }, + { + "[t", + function() + require("todo-comments").jump_prev() + end, + desc = "Previous Todo Comment", + }, + { "<leader>tt", "<cmd>Trouble todo toggle<cr>", desc = "Toggle TODO (Trouble)" }, + { + "<leader>tT", + "<cmd>Trouble todo toggle filter = {tag = {TODO,FIX,FIXME}}<cr>", + desc = "Toggle Todo/Fix/Fixme (Trouble)", + }, + { "<leader>ft", "<cmd>TodoTelescope<cr>", desc = "Find Todo" }, + { "<leader>fT", "<cmd>TodoTelescope keywords=TODO,FIX,FIXME<cr>", desc = "Find Todo/Fix/Fixme" }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/compiler.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/compiler.lua new file mode 100644 index 0000000..d760594 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/compiler.lua @@ -0,0 +1,53 @@ +return { + { -- This plugin + "Zeioth/compiler.nvim", + cmd = { "CompilerOpen", "CompilerToggleResults", "CompilerRedo" }, + dependencies = { "stevearc/overseer.nvim", "nvim-telescope/telescope.nvim" }, + opts = {}, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>r", group = "Compiler/Refactoring" }, + }) + end, + keys = { + -- Open compiler + vim.api.nvim_set_keymap( + "n", + "<leader>ro", + "<cmd>CompilerOpen<cr>", + { noremap = true, silent = true, desc = "Open compiler" } + ), + + -- Redo last selected option + vim.api.nvim_set_keymap( + "n", + "<leader>rc", + "<cmd>CompilerStop<cr>" -- (Optional, to dispose all tasks before redo) + .. "<cmd>CompilerRedo<cr>", + { noremap = true, silent = true, desc = "Recompile" } + ), + -- Toggle compiler results + vim.api.nvim_set_keymap( + "n", + "<leader>rt", + "<cmd>CompilerToggleResults<cr>", + { noremap = true, silent = true, desc = "Toggle compiler" } + ), + }, + }, + { -- The task runner we use + "stevearc/overseer.nvim", + commit = "6271cab7ccc4ca840faa93f54440ffae3a3918bd", + cmd = { "CompilerOpen", "CompilerToggleResults", "CompilerRedo" }, + opts = { + task_list = { + direction = "bottom", + min_height = 25, + max_height = 25, + default_detail = 1, + }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/context.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/context.lua new file mode 100644 index 0000000..e8979c8 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/context.lua @@ -0,0 +1,26 @@ +return { + "nvim-treesitter/nvim-treesitter-context", + cmd = { "TSContextEnable", "TSContextDisable", "TSContextToggle" }, + config = function() + require("treesitter-context").setup({ + enable = false, -- Enable this plugin (Can be enabled/disabled later via commands) + max_lines = 3, -- How many lines the window should span. Values <= 0 mean no limit. + min_window_height = 1, -- Minimum editor window height to enable context. Values <= 0 mean no limit. + line_numbers = true, + multiline_threshold = 20, -- Maximum number of lines to show for a single context + trim_scope = "outer", -- Which context lines to discard if `max_lines` is exceeded. Choices: 'inner', 'outer' + mode = "cursor", -- Line used to calculate context. Choices: 'cursor', 'topline' + -- Separator between context and content. Should be a single character string, like '-'. + -- When separator is set, the context will only show up when there are at least 2 lines above cursorline. + separator = nil, + zindex = 20, -- The Z-index of the context window + on_attach = nil, -- (fun(buf: integer): boolean) return false to disable attaching + }) + end, + keys = { + vim.keymap.set("n", "[t", function() + require("treesitter-context").go_to_context(vim.v.count1) + end, { silent = true, desc = "Go to context" }), + vim.keymap.set({ "n", "v" }, "<leader>zc", "<cmd>TSContextToggle<cr>", { desc = "Toggle context" }), + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/csv.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/csv.lua new file mode 100644 index 0000000..0805d1d --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/csv.lua @@ -0,0 +1,88 @@ +return { + { + "cameron-wags/rainbow_csv.nvim", + config = function() + require("rainbow_csv").setup() + -- vim.g.rcsv_colorpairs = { + -- { "red", "red" }, + -- { "blue", "blue" }, + -- { "green", "green" }, + -- { "magenta", "magenta" }, + -- { "NONE", "NONE" }, + -- { "darkred", "darkred" }, + -- { "darkblue", "darkblue" }, + -- { "darkgreen", "darkgreen" }, + -- { "darkmagenta", "darkmagenta" }, + -- { "darkcyan", "darkcyan" }, + -- } + end, + ft = { + "csv", + "tsv", + "csv_semicolon", + "csv_whitespace", + "csv_pipe", + "rfc_csv", + "rfc_semicolon", + }, + cmd = { + "RainbowDelim", + "RainbowDelimSimple", + "RainbowDelimQuoted", + "RainbowMultiDelim", + }, + }, + { + "hat0uma/csvview.nvim", + cmd = { "CsvViewEnable", "CsvViewDisable", "CsvViewToggle" }, + event = { "BufReadPre *.csv" }, -- Lazy-load the plugin when a CSV file is about to be read + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>cs", group = "csv" }, + }) + end, + config = function() + require("csvview").setup() + + vim.api.nvim_create_autocmd("BufRead", { + pattern = "*.csv", + callback = function() + vim.cmd("CsvViewEnable") + end, + }) + + vim.api.nvim_create_autocmd("FileType", { + pattern = "csv", + callback = function() + vim.keymap.set( + "n", + "<leader>zv", + "<cmd>CsvViewToggle<cr>", + { desc = "Toggle CSV view", buffer = true } + ) + end, + }) + end, + keys = { + { + "<leader>csv", + function() + local delimiter = vim.fn.input("Delimiter (e.g., ,): ") + local quote_char = vim.fn.input("Quote char (e.g., '): ") + local comment = vim.fn.input("Comment char (e.g., #): ") + local command = string.format( + ":CsvViewToggle delimiter=%s quote_char=%s comment=%s<CR>", + delimiter, + quote_char, + comment + ) + + vim.cmd(command) + end, + desc = "Toggle CSV view", + }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/dadbod.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/dadbod.lua new file mode 100644 index 0000000..41adb5a --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/dadbod.lua @@ -0,0 +1,52 @@ +return { + "kristijanhusak/vim-dadbod-ui", + dependencies = { + { "tpope/vim-dadbod", lazy = true }, + { "kristijanhusak/vim-dadbod-completion", ft = { "sql", "mysql", "plsql" }, lazy = true }, + }, + cmd = { + "DBUI", + "DBUIToggle", + "DBUIAddConnection", + "DBUIFindBuffer", + }, + init = function() + -- Your DBUI configuration + vim.g.db_ui_use_nerd_fonts = 1 + local home = vim.fn.expand("~") + vim.g.dbs = { + firefox = "sqlite://" .. home .. "/.mozilla/firefox/si.default/places.sqlite", + mysql = "mariadb://user:password@localhost/mysql", + postsql = "postgresql://postgres:mypassword@localhost:5432/postgresql", + sqlite = "sqlite://" .. home .. "/.local/share/db/sqlite.db", + } + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<localleader>d", group = "DB" }, + }) + end, + config = function() + local function db_completion() + require("cmp").setup.buffer({ sources = { { name = "vim-dadbod-completion" } } }) + end + vim.api.nvim_create_autocmd("FileType", { + pattern = { + "sql", + "mysql", + "plsql", + }, + callback = function() + vim.schedule(db_completion) + end, + }) + end, + keys = { + { "<localleader>du", "<cmd>DBUI<cr>", desc = "DB UI" }, + { "<localleader>dt", "<cmd>DBUIToggle<cr>", desc = "Toggle DB UI" }, + { "<localleader>da", "<cmd>DBUIAddConnection<cr>", desc = "Add connection" }, + { "<localleader>df", "<cmd>DBUIFindBuffer<cr>", desc = "Find buffer" }, + { "<localleader>dr", "<cmd>DBUIRenameBuffer<cr>", desc = "Rename buffer" }, + { "<localleader>di", "<cmd>DBUILastQueryInfo<cr>", desc = "Last query info" }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/dap.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/dap.lua new file mode 100644 index 0000000..d1ef5d7 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/dap.lua @@ -0,0 +1,295 @@ +local function get_args(config) + local args = type(config.args) == "function" and (config.args() or {}) or config.args or {} + config = vim.deepcopy(config) + ---@cast args string[] + config.args = function() + local new_args = vim.fn.input("Run with args: ", table.concat(args, " ")) --[[@as string]] + return vim.split(vim.fn.expand(new_args) --[[@as string]], " ") + end + return config +end + +return { + { + "mfussenegger/nvim-dap", + recommended = true, + desc = "Debugging support. Requires language specific adapters to be configured. (see lang extras)", + dependencies = { + "rcarriga/nvim-dap-ui", + -- virtual text for the debugger + { + "theHamsta/nvim-dap-virtual-text", + opts = {}, + }, + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<localleader>dp", group = "Debug" }, + { "<localleader>dP", group = "Debug (Python)" }, + }) + end, + config = function() + -- load mason-nvim-dap here, after all adapters have been setup + vim.api.nvim_set_hl(0, "DapStoppedLine", { default = true, link = "Visual" }) + + local dap = require("dap") + dap.configurations.java = { + { + type = "java", + request = "attach", + name = "Debug (Attach) - Remote", + hostName = "127.0.0.1", + port = 5005, + }, + } + + local dap_icons = { + Stopped = { " ", "DiagnosticWarn", "DapStoppedLine" }, + Breakpoint = " ", + BreakpointCondition = " ", + BreakpointRejected = { " ", "DiagnosticError" }, + LogPoint = ".>", + } + + for name, sign in pairs(dap_icons) do + sign = type(sign) == "table" and sign or { sign } + vim.fn.sign_define( + "Dap" .. name, + { text = sign[1], texthl = sign[2] or "DiagnosticInfo", linehl = sign[3], numhl = sign[3] } + ) + end + + -- setup dap config by VsCode launch.json file + local vscode = require("dap.ext.vscode") + local json = require("plenary.json") + vscode.json_decode = function(str) + return vim.json.decode(json.json_strip_comments(str)) + end + end, + keys = { + { + "<localleader>dpB", + function() + require("dap").set_breakpoint(vim.fn.input("Breakpoint condition: ")) + end, + desc = "Dap breakpoint condition", + }, + { + "<localleader>dpb", + function() + require("dap").toggle_breakpoint() + end, + desc = "Dap toggle breakpoint", + }, + { + "<localleader>dpc", + function() + require("dap").continue() + end, + desc = "Dap continue", + }, + { + "<localleader>dpa", + function() + require("dap").continue({ before = get_args }) + end, + desc = "Dap run with args", + }, + { + "<localleader>dpC", + function() + require("dap").run_to_cursor() + end, + desc = "Dap run to cursor", + }, + { + "<localleader>dpg", + function() + require("dap").goto_() + end, + desc = "Dap go to line (no execute)", + }, + { + "<localleader>dpi", + function() + require("dap").step_into() + end, + desc = "Dap step into", + }, + { + "<localleader>dpj", + function() + require("dap").down() + end, + desc = "Dap down", + }, + { + "<localleader>dpk", + function() + require("dap").up() + end, + desc = "Dap up", + }, + { + "<localleader>dpl", + function() + require("dap").run_last() + end, + desc = "Dap run last", + }, + { + "<localleader>dpo", + function() + require("dap").step_out() + end, + desc = "Dap step out", + }, + { + "<localleader>dpO", + function() + require("dap").step_over() + end, + desc = "Dap step over", + }, + { + "<localleader>dpp", + function() + require("dap").pause() + end, + desc = "Dap pause", + }, + { + "<localleader>dpr", + function() + require("dap").repl.toggle() + end, + desc = "Dap toggle repl", + }, + { + "<localleader>dps", + function() + require("dap").session() + end, + desc = "Dap session", + }, + { + "<localleader>dpt", + function() + require("dap").terminate() + end, + desc = "Dap terminate", + }, + { + "<localleader>dpw", + function() + require("dap.ui.widgets").hover() + end, + desc = "Dap widgets", + }, + { + "<localleader>dpR", + "<cmd>lua require('dapui').open({ reset = true })<cr>", + desc = "Dap UI reset", + }, + }, + }, + { + "mfussenegger/nvim-dap-python", + ft = "python", + dependencies = { "mfussenegger/nvim-dap", "rcarriga/nvim-dap-ui" }, + config = function() + local path = "~/.local/share/nvim/mason/packages/debugpy/venv/bin/python" + require("dap-python").setup(path) + end, + keys = { + { + "<localleader>dPt", + function() + require("dap-python").test_method() + end, + desc = "Dap debug method", + ft = "python", + }, + { + "<localleader>dPc", + function() + require("dap-python").test_class() + end, + desc = "Dap debug class", + ft = "python", + }, + }, + }, + { + "rcarriga/nvim-dap-ui", + dependencies = { "mfussenegger/nvim-dap", "nvim-neotest/nvim-nio" }, + config = function() + local dap = require("dap") + local dapui = require("dapui") + dapui.setup() + + dap.listeners.before.attach.dapui_config = function() + dapui.open() + end + dap.listeners.before.launch.dapui_config = function() + dapui.open() + end + dap.listeners.before.event_terminated.dapui_config = function() + dapui.close() + end + dap.listeners.before.event_exited.dapui_config = function() + dapui.close() + end + + dap.listeners.after.event_initialized["dapui_config"] = function() + dapui.open() + end + dap.listeners.after.event_terminated["dapui_config"] = function() + dapui.close() + end + dap.listeners.after.event_exited["dapui_config"] = function() + dapui.close() + end + end, + keys = { + { + "<localleader>dpu", + function() + require("dapui").toggle() + end, + desc = "Dap UI", + }, + { + "<localleader>dpe", + function() + require("dapui").eval() + end, + desc = "Dap eval", + }, + }, + }, + { + "jay-babu/mason-nvim-dap.nvim", + dependencies = "mason.nvim", + cmd = { "DapInstall", "DapUninstall" }, + opts = { + -- Makes a best effort to setup the various debuggers with + -- reasonable debug configurations + automatic_installation = true, + + -- You can provide additional configuration to the handlers, + -- see mason-nvim-dap README for more information + handlers = {}, + + -- You'll need to check that you have the required things installed + -- online, please don't ask me how to install them :) + ensure_installed = { + -- Update this to ensure that you have the debuggers for the langs you want + }, + }, + -- mason-nvim-dap is loaded when nvim-dap loads + config = function() end, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/docker.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/docker.lua new file mode 100644 index 0000000..7bc26d5 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/docker.lua @@ -0,0 +1,222 @@ +return { + "https://codeberg.org/esensar/nvim-dev-container", + dependencies = "nvim-treesitter/nvim-treesitter", + config = function() + require("devcontainer").setup({ + config_search_start = function() + -- By default this function uses vim.loop.cwd() + -- This is used to find a starting point for .devcontainer.json file search + -- Since by default, it is searched for recursively + -- That behavior can also be disabled + end, + workspace_folder_provider = function() + -- By default this function uses first workspace folder for integrated lsp if available and vim.loop.cwd() as a fallback + -- This is used to replace `${localWorkspaceFolder}` in devcontainer.json + -- Also used for creating default .devcontainer.json file + end, + terminal_handler = function(command) + -- By default this function creates a terminal in a new tab using :terminal command + -- It also removes statusline when that tab is active, to prevent double statusline + -- It can be overridden to provide custom terminal handling + end, + nvim_installation_commands_provider = function(path_binaries, version_string) + -- Returns table - list of commands to run when adding neovim to container + -- Each command can either be a string or a table (list of command parts) + -- Takes binaries available in path on current container and version_string passed to the command or current version of neovim + end, + devcontainer_json_template = function() + -- Returns table - list of lines to set when creating new devcontainer.json files + -- As a template + -- Used only when using functions from commands module or created commands + end, + -- Can be set to false to prevent generating default commands + -- Default commands are listed below + generate_commands = true, + -- By default no autocommands are generated + -- This option can be used to configure automatic starting and cleaning of containers + autocommands = { + -- can be set to true to automatically start containers when devcontainer.json is available + init = false, + -- can be set to true to automatically remove any started containers and any built images when exiting vim + clean = false, + -- can be set to true to automatically restart containers when devcontainer.json file is updated + update = false, + }, + -- can be changed to increase or decrease logging from library + log_level = "info", + -- can be set to true to disable recursive search + -- in that case only .devcontainer.json and .devcontainer/devcontainer.json files will be checked relative + -- to the directory provided by config_search_start + disable_recursive_config_search = false, + -- can be set to false to disable image caching when adding neovim + -- by default it is set to true to make attaching to containers faster after first time + cache_images = true, + -- By default all mounts are added (config, data and state) + -- This can be changed to disable mounts or change their options + -- This can be useful to mount local configuration + -- And any other mounts when attaching to containers with this plugin + attach_mounts = { + neovim_config = { + -- enables mounting local config to /root/.config/nvim in container + enabled = false, + -- makes mount readonly in container + options = { "readonly" }, + }, + neovim_data = { + -- enables mounting local data to /root/.local/share/nvim in container + enabled = false, + -- no options by default + options = {}, + }, + -- Only useful if using neovim 0.8.0+ + neovim_state = { + -- enables mounting local state to /root/.local/state/nvim in container + enabled = false, + -- no options by default + options = {}, + }, + }, + -- This takes a list of mounts (strings) that should always be added to every run container + -- This is passed directly as --mount option to docker command + -- Or multiple --mount options if there are multiple values + always_mount = {}, + -- This takes a string (usually either "podman" or "docker") representing container runtime - "devcontainer-cli" is also partially supported + -- That is the command that will be invoked for container operations + -- If it is nil, plugin will use whatever is available (trying "podman" first) + container_runtime = nil, + -- Similar to container runtime, but will be used if main runtime does not support an action - useful for "devcontainer-cli" + backup_runtime = nil, + -- This takes a string (usually either "podman-compose" or "docker-compose") representing compose command - "devcontainer-cli" is also partially supported + -- That is the command that will be invoked for compose operations + -- If it is nil, plugin will use whatever is available (trying "podman-compose" first) + compose_command = nil, + -- Similar to compose command, but will be used if main command does not support an action - useful for "devcontainer-cli" + backup_compose_command = nil, + }) + end, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<leader>d", group = "Docker" }, + { "<leader>db", group = "Build (docker)" }, + { "<leader>dc", group = "Compose (docker)" }, + { "<leader>do", group = "Open (docker)" }, + { "<leader>dr", group = "Run (docker)" }, + }) + end, + keys = { + { + "<leader>dcu", + function() + require("devcontainer.commands").compose_up() + end, + desc = "Compose up (docker)", + }, + { + "<leader>dcd", + function() + require("devcontainer.commands").compose_down() + end, + desc = "Compose down (docker)", + }, + { + "<leader>dcD", + function() + require("devcontainer.commands").compose_rm() + end, + desc = "Compose remove (docker)", + }, + { + "<leader>dbb", + function() + require("devcontainer.commands").docker_build() + end, + desc = "Build (docker)", + }, + { + "<leader>dri", + function() + require("devcontainer.commands").docker_image_run() + end, + desc = "Image run (docker)", + }, + { + "<leader>dbr", + function() + require("devcontainer.commands").docker_build_and_run() + end, + desc = "Build & run (docker)", + }, + { + "<leader>dba", + function() + require("devcontainer.commands").docker_build_run_and_attach() + end, + desc = "Build & attach (docker)", + }, + { + "<leader>ds", + function() + require("devcontainer.commands").start_auto() + end, + desc = "Start (docker)", + }, + { + "<leader>da", + function() + require("devcontainer.commands").attach_auto() + end, + desc = "Attach (docker)", + }, + { + "<leader>drr", + function() + require("devcontainer.commands").exec("devcontainer", "ls", { on_success = function(result) end }) + end, + desc = "Execute (docker)", + }, + { + "<leader>dx", + function() + require("devcontainer.commands").stop_auto() + end, + desc = "Stop (docker)", + }, + { + "<leader>dX", + function() + require("devcontainer.commands").stop_all() + end, + desc = "Stop all (docker)", + }, + { + "<leader>dD", + function() + require("devcontainer.commands").remove_all() + end, + desc = "Remove all (docker)", + }, + { + "<leader>dol", + function() + require("devcontainer.commands").open_logs() + end, + desc = "Open logs (docker)", + }, + { + "<leader>doc", + function() + require("devcontainer.commands").open_nearest_devcontainer_config() + end, + desc = "Open nearest config (docker)", + }, + { + "<leader>de", + function() + require("devcontainer.commands").edit_devcontainer_config() + end, + desc = "Edit nearest config (docker)", + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/git.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/git.lua new file mode 100644 index 0000000..9f856b6 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/git.lua @@ -0,0 +1,221 @@ +return { + { + "moyiz/git-dev.nvim", + event = "VeryLazy", + opts = {}, + config = function() + require("git-dev").setup() + + local function copy_git_repo_url() + -- Get the Git repository root + local git_root = vim.fn.system("git rev-parse --show-toplevel"):gsub("\n", "") + if git_root == "" then + vim.notify("Not inside a Git repository", vim.log.levels.WARN) + return nil + end + + -- Get the remote URL + local remote_url = vim.fn.system("git config --get remote.origin.url"):gsub("\n", "") + if remote_url == "" then + vim.notify("No remote URL found", vim.log.levels.WARN) + return nil + end + + -- Convert SSH URL to HTTPS if needed + if remote_url:match("^git@") then + remote_url = remote_url:gsub("git@", "https://"):gsub(":", "/") + end + + -- Remove `.git` from the remote URL + remote_url = remote_url:gsub("%.git$", "") + + -- Get the relative path of the current file + local file_path = vim.fn.expand("%:~:.") + if file_path == "" then + vim.notify("No file currently open", vim.log.levels.WARN) + return nil + end + + -- Get the relative path to the repository root + local relative_path = + vim.fn.system("git ls-files --full-name " .. vim.fn.shellescape(file_path)):gsub("\n", "") + + -- Combine the remote URL with the relative file path + local full_url = remote_url .. "/" .. relative_path + + -- Copy to clipboard + vim.fn.setreg("+", full_url) + vim.notify("Copied to clipboard: " .. full_url, vim.log.levels.INFO) + + return full_url + end + + -- Keybinding to copy the Git repository URL + vim.keymap.set("n", "<leader>cg", function() + copy_git_repo_url() + end, { desc = "Copy git repository URL to clipboard" }) + + -- Function to open a repository from the clipboard + vim.keymap.set("n", "<leader>er", function() + local url = vim.fn.getreg("+") -- Get URL from clipboard + if not url or url == "" then + vim.notify("Clipboard is empty. Copy a valid URL first.", vim.log.levels.WARN) + return + end + if url:match("^https://") then + require("git-dev").open(url) + else + vim.notify("Not a valid URL: " .. url, vim.log.levels.ERROR) + end + end, { desc = "Open Git repository from clipboard" }) + end, + }, + { + "lewis6991/gitsigns.nvim", + opts = { + signs = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "" }, + topdelete = { text = "" }, + changedelete = { text = "▎" }, + untracked = { text = "▎" }, + }, + signs_staged = { + add = { text = "▎" }, + change = { text = "▎" }, + delete = { text = "" }, + topdelete = { text = "" }, + changedelete = { text = "▎" }, + }, + on_attach = function(buffer) + local gs = package.loaded.gitsigns + + local function map(mode, l, r, desc) + vim.keymap.set(mode, l, r, { buffer = buffer, desc = desc }) + end + + -- stylua: ignore start + map("n", "]h", function() + if vim.wo.diff then + vim.cmd.normal({ "]c", bang = true }) + else + gs.nav_hunk("next") + end + end, "Next hunk") + map("n", "[h", function() + if vim.wo.diff then + vim.cmd.normal({ "[c", bang = true }) + else + gs.nav_hunk("prev") + end + end, "Previous hunk") + map("n", "]H", function() gs.nav_hunk("last") end, "Last hunk") + map("n", "[H", function() gs.nav_hunk("first") end, "First hunk") + map({ "n", "v" }, "<leader>gs", ":Gitsigns stage_hunk<CR>", "Stage hunk") + map({ "n", "v" }, "<leader>gr", ":Gitsigns reset_hunk<CR>", "Reset hunk") + map("n", "<leader>gS", gs.stage_buffer, "Stage buffer") + map("n", "<leader>gu", gs.undo_stage_hunk, "Undo stage hunk") + map("n", "<leader>gR", gs.reset_buffer, "Reset buffer") + map("n", "<leader>gpv", gs.preview_hunk_inline, "Preview hunk inline") + map("n", "<leader>gb", function() gs.blame_line({ full = true }) end, "Blame line") + map("n", "<leader>gB", function() gs.blame() end, "Blame buffer") + map("n", "<leader>gd", gs.diffthis, "Diff this") + map("n", "<leader>gD", function() gs.diffthis("~") end, "Diff this ~") + -- map("n", "<leader>gD", function() gs.diffthis("@") end, "Diff this @") + map({ "o", "x" }, "ih", ":<C-U>Gitsigns select_hunk<CR>", "GitSigns select hunk") + map("n", "<leader>gtb", gs.toggle_current_line_blame, "Toggle line blame") + map("n", "<leader>gtd", gs.toggle_deleted, "Toggle delete") + end, + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>g", group = "Git" }, + }) + end, + }, + { + "kdheepak/lazygit.nvim", + cmd = { + "LazyGit", + "LazyGitConfig", + "LazyGitCurrentFile", + "LazyGitFilter", + "LazyGitFilterCurrentFile", + }, + -- optional for floating window border decoration + dependencies = { + "nvim-lua/plenary.nvim", + }, + -- setting the keybinding for LazyGit with 'keys' is recommended in + -- order to load the plugin when the command is run for the first time + keys = { + { "<leader>gg", "<cmd>LazyGit<cr>", desc = "Lazygit" }, + }, + }, + { + "mbbill/undotree", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>gt", group = "Toggle" }, + }) + end, + config = function() + vim.keymap.set("n", "<leader>gtu", vim.cmd.UndotreeToggle, { desc = "Toggle undo tree" }) + end, + }, + { + "tpope/vim-fugitive", + config = function() + local TheSiahxyz_Fugitive = vim.api.nvim_create_augroup("TheSiahxyz_Fugitive", {}) + local autocmd = vim.api.nvim_create_autocmd + autocmd("BufWinEnter", { + group = TheSiahxyz_Fugitive, + pattern = "*", + callback = function() + if vim.bo.ft ~= "fugitive" then + return + end + + local bufnr = vim.api.nvim_get_current_buf() + vim.keymap.set("n", "<leader>P", function() + vim.cmd.Git("push") + end, { buffer = bufnr, remap = false, desc = "Git push" }) + vim.keymap.set("n", "<leader>p", function() + vim.cmd.Git({ "pull", "--rebase" }) + end, { buffer = bufnr, remap = false, desc = "Git pull" }) + vim.keymap.set( + "n", + "<leader>o", + ":Git push -u origin ", + { buffer = bufnr, remap = false, desc = "Git push origin" } + ) + vim.keymap.set( + "n", + "<leader>h", + ":Git push home ", + { buffer = bufnr, remap = false, desc = "Git push home" } + ) + end, + }) + autocmd("FileType", { + group = TheSiahxyz_Fugitive, + pattern = "fugitive", + callback = function(event) + vim.bo[event.buf].buflisted = false + vim.keymap.set("n", "q", "<cmd>close<cr>", { buffer = event.buf, silent = true }) + end, + }) + end, + keys = { + { mode = "n", "<leader>g<leader>", ":Git ", desc = "Git" }, + { mode = "n", "<leader>gf", vim.cmd.Git, desc = "Git fugitive" }, + { mode = "n", "gm", "<cmd>diffget //2<cr>", desc = "Git diff on my side" }, + { mode = "n", "go", "<cmd>diffget //3<cr>", desc = "Git diff on their side" }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/goyo.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/goyo.lua new file mode 100644 index 0000000..d78fe5e --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/goyo.lua @@ -0,0 +1,39 @@ +return { + "junegunn/goyo.vim", + dependencies = "junegunn/seoul256.vim", + config = function() + -- Enable Goyo by default for mutt writing + vim.api.nvim_create_autocmd({ "BufRead", "BufNewFile" }, { + group = vim.api.nvim_create_augroup("TheSiahxyz_goyo_config", { clear = true }), + pattern = "/tmp/neomutt*", + callback = function() + vim.g.goyo_width = 80 + vim.g.seoul256_background = 235 + vim.cmd([[ + Goyo + set bg=light + set linebreak + set wrap + set textwidth=0 + set wrapmargin=0 + set background=dark + colorscheme seoul256 + ]]) + vim.api.nvim_buf_set_keymap( + 0, + "n", + "<leader>gd", + ":Goyo|x!<CR>", + { noremap = true, silent = true, desc = "Goyo quit" } + ) + vim.api.nvim_buf_set_keymap( + 0, + "n", + "<leader>gq", + ":Goyo|q!<CR>", + { noremap = true, silent = true, desc = "Goyo abort" } + ) + end, + }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/harpoon2.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/harpoon2.lua new file mode 100644 index 0000000..942f326 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/harpoon2.lua @@ -0,0 +1,103 @@ +return { + "ThePrimeagen/harpoon", + branch = "harpoon2", + opts = { + menu = { + width = vim.api.nvim_win_get_width(0) - 4, + }, + settings = { + save_on_toggle = true, + }, + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<leader>h", group = "Harpoon" }, + { "<leader>hr", group = "Replace harpoon slot" }, + { "<M-x>", group = "Harpoon list delete" }, + }) + end, + config = function(_, opts) + local harpoon = require("harpoon") + + -- Apply the base configuration + harpoon.setup(opts) + + -- Extend functionality + harpoon:extend({ + UI_CREATE = function(cx) + vim.keymap.set("n", "<C-v>", function() + harpoon.ui:select_menu_item({ vsplit = true }) + end, { buffer = cx.bufnr }) + + vim.keymap.set("n", "<C-s>", function() + harpoon.ui:select_menu_item({ split = true }) + end, { buffer = cx.bufnr }) + + vim.keymap.set("n", "<C-t>", function() + harpoon.ui:select_menu_item({ tabedit = true }) + end, { buffer = cx.bufnr }) + end, + }) + end, + keys = function() + local keys = { + { + "<leader>ha", + function() + require("harpoon"):list():add() + end, + desc = "Add buffer to harpoon list", + }, + { + "<C-q>", + function() + local harpoon = require("harpoon") + harpoon.ui:toggle_quick_menu(harpoon:list()) + end, + desc = "Open harpoon list menu", + }, + { + "<C-S-P>", + function() + require("harpoon"):list():prev({ ui_nav_wrap = false }) + end, + desc = "Previous harpoon list", + }, + { + "<C-S-N>", + function() + require("harpoon"):list():next({ ui_nav_wrap = false }) + end, + desc = "Next harpoon list", + }, + } + + for i = 1, 5 do + table.insert(keys, { + "<M-" .. i .. ">", + function() + require("harpoon"):list():select(i) + end, + desc = "Harpoon list " .. i, + }) + table.insert(keys, { + "<leader>h" .. i, + function() + require("harpoon"):list():select(i) + end, + desc = "Harpoon list " .. i, + }) + table.insert(keys, { + "<leader>hr" .. i, + function() + require("harpoon"):list():replace_at(i) + end, + desc = "Replace buffer at harpoon slot " .. i, + }) + end + + return keys + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/image.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/image.lua new file mode 100644 index 0000000..a117e28 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/image.lua @@ -0,0 +1,210 @@ +return { + "HakonHarnes/img-clip.nvim", + event = "VeryLazy", + opts = { + -- add options here + -- or leave it empty to use the default settings + }, + config = function(_, opts) + require("img-clip").setup(opts) + + vim.keymap.set({ "n", "v", "i" }, "<M-i>", function() + local pasted_image = require("img-clip").paste_image() + if pasted_image then + -- "Update" saves only if the buffer has been modified since the last save + vim.cmd("silent! update") + -- Get the current line + local line = vim.api.nvim_get_current_line() + -- Move cursor to end of line + vim.api.nvim_win_set_cursor(0, { vim.api.nvim_win_get_cursor(0)[1], #line }) + -- I reload the file, otherwise I cannot view the image after pasted + vim.cmd("edit!") + end + end, { desc = "Paste image from clipboard" }) + + vim.keymap.set("n", "<leader>oi", function() + local function get_image_path() + -- Get the current line + local line = vim.api.nvim_get_current_line() + -- Patterns to match image paths + local patterns = { + "%[.-%]%((.-)%)", -- Markdown style:  + "%[%[(.-)%]%]", -- Double square brackets: [[image_path]] + } + + for _, pattern in ipairs(patterns) do + local _, _, image_path = string.find(line, pattern) + if image_path then + return image_path + end + end + + return nil -- Return nil if no pattern matches + end + + local function file_exists(filepath) + -- Check if the file exists + local f = io.open(filepath, "r") + if f then + f:close() + return true + end + return false + end + + -- Get the image path + local image_path = get_image_path() + if image_path then + -- Check if the image path starts with "http" or "https" + if string.sub(image_path, 1, 4) == "http" then + print("URL image, use 'gx' to open it in the default browser.") + else + -- Construct absolute image path + local current_file_path = vim.fn.expand("%:p:h") + local absolute_image_path = current_file_path .. "/" .. image_path + -- Check if the image exists in the current path + if not file_exists(absolute_image_path) then + -- If not found, search ../Screenshots/ + local fallback_path = vim.fn.fnamemodify(current_file_path, ":h") + .. "/Screenshots/" + .. image_path + if file_exists(fallback_path) then + absolute_image_path = fallback_path + else + print("Image not found in either current directory or ../Screenshots/") + return + end + end + -- Construct command to open image in Preview + local command = "nsxiv -aiop " .. vim.fn.shellescape(absolute_image_path) + -- Execute the command + local success = os.execute(command) + if success then + print("Opened image: " .. absolute_image_path) + else + print("Failed to open image: " .. absolute_image_path) + end + end + else + print("No image found under the cursor") + end + end, { desc = "Open image under cursor" }) + + vim.keymap.set("n", "<leader>di", function() + local function get_image_path() + local line = vim.api.nvim_get_current_line() + -- Patterns to match image paths + local patterns = { + "%[.-%]%((.-)%)", -- Markdown style:  + "%[%[(.-)%]%]", -- Double square brackets: [[image_path]] + } + + for _, pattern in ipairs(patterns) do + local _, _, image_path = string.find(line, pattern) + if image_path then + return image_path + end + end + + return nil -- Return nil if no pattern matches + end + + local function file_exists(filepath) + local f = io.open(filepath, "r") + if f then + f:close() + return true + end + return false + end + + local image_path = get_image_path() + if image_path then + if string.sub(image_path, 1, 4) == "http" then + vim.api.nvim_echo({ { "URL image cannot be deleted from disk.", "WarningMsg" } }, false, {}) + return + end + + local current_file_path = vim.fn.expand("%:p:h") + local absolute_image_path = current_file_path .. "/" .. image_path + + -- Check if file exists + if not file_exists(absolute_image_path) then + -- Search fallback directory + local fallback_path = vim.fn.fnamemodify(current_file_path, ":h") .. "/Screenshots/" .. image_path + if file_exists(fallback_path) then + absolute_image_path = fallback_path + else + print("Image not found in either current directory or ../Screenshots/") + return + end + end + + -- Verify if trash utility exists + if vim.fn.executable("trash") == 0 then + vim.api.nvim_echo({ + { "- Trash utility not installed. Install `trash-cli`.\n", "ErrorMsg" }, + }, false, {}) + return + end + + vim.ui.select({ "yes", "no" }, { prompt = "Delete image file? " }, function(choice) + if choice == "yes" then + -- Attempt to delete using trash + local command = { "trash", absolute_image_path } + local success, err = pcall(vim.fn.system, command) + + -- Debug message for troubleshooting + print("Debug: Trash command -", table.concat(command, " ")) + + if success and vim.fn.filereadable(absolute_image_path) == 0 then + vim.api.nvim_echo({ + { "Image file deleted using trash:\n", "Normal" }, + { absolute_image_path, "Normal" }, + }, false, {}) + require("image").clear() + vim.cmd("edit!") + vim.cmd("normal! dd") + else + -- If trash fails, log the error + vim.api.nvim_echo({ + { "Trash deletion failed. Error:\n", "ErrorMsg" }, + { err or "Unknown error", "ErrorMsg" }, + }, false, {}) + end + else + vim.api.nvim_echo({ { "Image deletion canceled.", "Normal" } }, false, {}) + end + end) + else + print("No image found under the cursor") + end + end, { desc = "Delete image file under cursor" }) + + -- Refresh the images in the current buffer + -- Useful if you delete an actual image file and want to see the changes + -- without having to re-open neovim + vim.keymap.set("n", "<leader>ir", function() + -- First I clear the images + require("image").clear() + -- I'm using [[ ]] to escape the special characters in a command + -- vim.cmd([[lua require("image").clear()]]) + -- Reloads the file to reflect the changes + vim.cmd("edit!") + print("Images refreshed") + end, { desc = "Refresh images" }) + + -- Set up a keymap to clear all images in the current buffer + vim.keymap.set("n", "<leader>ic", function() + -- This is the command that clears the images + require("image").clear() + -- I'm using [[ ]] to escape the special characters in a command + -- vim.cmd([[lua require("image").clear()]]) + print("Images cleared") + end, { desc = "Clear images" }) + end, + keys = { + -- suggested keymap + { "<leader>pi", "<cmd>PasteImage<cr>", desc = "Paste image from clipboard" }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/init.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/init.lua new file mode 100644 index 0000000..0bcf162 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/init.lua @@ -0,0 +1,83 @@ +return { + { "nvim-lua/plenary.nvim" }, + { + "aserowy/tmux.nvim", + config = function() + require("tmux").setup({ + copy_sync = { + -- enables copy sync. by default, all registers are synchronized. + -- to control which registers are synced, see the `sync_*` options. + enable = false, + + -- ignore specific tmux buffers e.g. buffer0 = true to ignore the + -- first buffer or named_buffer_name = true to ignore a named tmux + -- buffer with name named_buffer_name :) + ignore_buffers = { empty = false }, + + -- TMUX >= 3.2: all yanks (and deletes) will get redirected to system + -- clipboard by tmux + redirect_to_clipboard = false, + + -- offset controls where register sync starts + -- e.g. offset 2 lets registers 0 and 1 untouched + register_offset = 0, + + -- overwrites vim.g.clipboard to redirect * and + to the system + -- clipboard using tmux. If you sync your system clipboard without tmux, + -- disable this option! + sync_clipboard = true, + + -- synchronizes registers *, +, unnamed, and 0 till 9 with tmux buffers. + sync_registers = true, + + -- synchronizes registers when pressing p and P. + sync_registers_keymap_put = true, + + -- synchronizes registers when pressing (C-r) and ". + sync_registers_keymap_reg = true, + + -- syncs deletes with tmux clipboard as well, it is adviced to + -- do so. Nvim does not allow syncing registers 0 and 1 without + -- overwriting the unnamed register. Thus, ddp would not be possible. + sync_deletes = true, + + -- syncs the unnamed register with the first buffer entry from tmux. + sync_unnamed = true, + }, + navigation = { + -- cycles to opposite pane while navigating into the border + cycle_navigation = false, + + -- enables default keybindings (C-hjkl) for normal mode + enable_default_keybindings = true, + + -- prevents unzoom tmux when navigating beyond vim border + persist_zoom = true, + }, + resize = { + -- enables default keybindings (A-hjkl) for normal mode + enable_default_keybindings = false, + + -- sets resize steps for x axis + resize_step_x = 2, + + -- sets resize steps for y axis + resize_step_y = 2, + }, + }) + + vim.keymap.set("n", "<C-left>", function() + require("tmux").resize_left() + end, { desc = "Decrease window width" }) + vim.keymap.set("n", "<C-down>", function() + require("tmux").resize_bottom() + end, { desc = "Decrease window height" }) + vim.keymap.set("n", "<C-up>", function() + require("tmux").resize_top() + end, { desc = "Increase window height" }) + vim.keymap.set("n", "<C-right>", function() + require("tmux").resize_right() + end, { desc = "Increase window width" }) + end, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/keys.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/keys.lua new file mode 100644 index 0000000..5927c53 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/keys.lua @@ -0,0 +1,278 @@ +return { + { + "nvzone/showkeys", + cmd = "ShowkeysToggle", + opts = {}, + keys = { + { "<leader>zk", "<cmd>ShowkeysToggle<cr>", desc = "Toggle keys" }, + }, + }, + { + "folke/which-key.nvim", + event = "VeryLazy", + cmd = "WhichKey", + dependencies = { "echasnovski/mini.icons", "nvim-tree/nvim-web-devicons" }, + opts = {}, + config = function() + local wk = require("which-key") + wk.setup({ + ---@type false | "classic" | "modern" | "helix" + preset = "classic", + -- Delay before showing the popup. Can be a number or a function that returns a number. + ---@type number | fun(ctx: { keys: string, mode: string, plugin?: string }):number + delay = function(ctx) + return ctx.plugin and 0 or 200 + end, + ---@param mapping wk.Mapping + filter = function(mapping) + -- example to exclude mappings without a description + -- return mapping.desc and mapping.desc ~= "" + return true + end, + --- You can add any mappings here, or use `require('which-key').add()` later + ---@type wk.Spec + spec = {}, + -- show a warning when issues were detected with your mappings + notify = true, + -- Which-key automatically sets up triggers for your mappings. + -- But you can disable this and setup the triggers manually. + -- Check the docs for more info. + ---@type wk.Spec + triggers = { + { "<auto>", mode = "nxso" }, + }, + -- Start hidden and wait for a key to be pressed before showing the popup + -- Only used by enabled xo mapping modes. + ---@param ctx { mode: string, operator: string } + defer = function(ctx) + return ctx.mode == "V" or ctx.mode == "<C-V>" + end, + plugins = { + marks = true, -- shows a list of your marks on ' and ` + registers = true, -- shows your registers on " in NORMAL or <C-r> in INSERT mode + -- the presets plugin, adds help for a bunch of default keybindings in Neovim + -- No actual key bindings are created + spelling = { + enabled = true, -- enabling this will show WhichKey when pressing z= to select spelling suggestions + suggestions = 20, -- how many suggestions should be shown in the list? + }, + presets = { + operators = true, -- adds help for operators like d, y, ... + motions = true, -- adds help for motions + text_objects = true, -- help for text objects triggered after entering an operator + windows = true, -- default bindings on <c-w> + nav = true, -- misc bindings to work with windows + z = true, -- bindings for folds, spelling and others prefixed with z + g = true, -- bindings for prefixed with g + }, + }, + ---@type wk.Win.opts + win = { + -- don't allow the popup to overlap with the cursor + no_overlap = true, + -- width = 1, + -- height = { min = 4, max = 25 }, + -- col = 0, + -- row = math.huge, + -- border = "none", + padding = { 1, 2 }, -- extra window padding [top/bottom, right/left] + title = true, + title_pos = "center", + zindex = 1000, + -- Additional vim.wo and vim.bo options + bo = {}, + wo = { + -- winblend = 10, -- value between 0-100 0 for fully opaque and 100 for fully transparent + }, + }, + layout = { + width = { min = 20 }, -- min and max width of the columns + spacing = 3, -- spacing between columns + }, + keys = { + scroll_down = "<c-e>", + scroll_up = "<c-y>", + }, + ---@type (string|wk.Sorter)[] + --- Mappings are sorted using configured sorters and natural sort of the keys + --- Available sorters: + --- * local: buffer-local mappings first + --- * order: order of the items (Used by plugins like marks / registers) + --- * group: groups last + --- * alphanum: alpha-numerical first + --- * mod: special modifier keys last + --- * manual: the order the mappings were added + --- * case: lower-case first + sort = { "local", "order", "group", "alphanum", "mod" }, + ---@type number|fun(node: wk.Node):boolean? + expand = 0, -- expand groups when <= n mappings + -- expand = function(node) + -- return not node.desc -- expand all nodes without a description + -- end, + -- Functions/Lua Patterns for formatting the labels + ---@type table<string, ({[1]:string, [2]:string}|fun(str:string):string)[]> + replace = { + key = { + function(key) + return require("which-key.view").format(key) + end, + -- { "<Space>", "SPC" }, + }, + desc = { + { "<Plug>%(?(.*)%)?", "%1" }, + { "^%+", "" }, + { "<[cC]md>", "" }, + { "<[cC][rR]>", "" }, + { "<[sS]ilent>", "" }, + { "^lua%s+", "" }, + { "^call%s+", "" }, + { "^:%s*", "" }, + }, + }, + icons = { + breadcrumb = "»", -- symbol used in the command line area that shows your active key combo + separator = "➜", -- symbol used between a key and it's label + group = "+", -- symbol prepended to a group + ellipsis = "…", + -- set to false to disable all mapping icons, + -- both those explicitly added in a mapping + -- and those from rules + mappings = true, + --- See `lua/which-key/icons.lua` for more details + --- Set to `false` to disable keymap icons from rules + ---@type wk.IconRule[]|false + rules = {}, + -- use the highlights from mini.icons + -- When `false`, it will use `WhichKeyIcon` instead + colors = true, + -- used by key format + keys = { + Up = " ", + Down = " ", + Left = " ", + Right = " ", + C = " ", + M = " ", + D = " ", + S = " ", + CR = " ", + Esc = " ", + ScrollWheelDown = " ", + ScrollWheelUp = " ", + NL = " ", + BS = "", + Space = " ", + Tab = " ", + F1 = "", + F2 = "", + F3 = "", + F4 = "", + F5 = "", + F6 = "", + F7 = "", + F8 = "", + F9 = "", + F10 = "", + F11 = "", + F12 = "", + }, + }, + show_help = true, -- show a help message in the command line for using WhichKey + show_keys = true, -- show the currently pressed key and its label as a message in the command line + -- disable WhichKey for certain buf types and file types. + disable = { + ft = {}, + bt = {}, + }, + debug = false, -- enable wk.log in the current directory + }) + + wk.add({ + { + mode = { "n", "v" }, + { "g", group = "Goto" }, + { "g`", group = "Marks" }, + { "g'", group = "Marks" }, + { "gs", group = "Search/Surround" }, + { "s", group = "Surround/Search & replace on line" }, + { "S", group = "Surround/Search & replace in file" }, + { "z", group = "Fold" }, + { "`", group = "Marks" }, + { "'", group = "Marks" }, + { '"', group = "Registers" }, + { "]", group = "Next" }, + { "]]", group = "Next" }, + { "[", group = "Prev" }, + { "[[", group = "Prev" }, + { "=", group = "Line paste" }, + { "gx", desc = "Open with system app" }, + { "<C-w>", group = "Windows" }, + { "<leader>", group = "Leader" }, + { "<leader>a", group = "Ascii" }, + { + "<leader>b", + group = "Buffer", + expand = function() + return require("which-key.extras").expand.buf() + end, + }, + { "<leader>B", group = "Buffer (force)" }, + { "<leader>C", group = "Goto realpath" }, + { "<leader>d", group = "Delete" }, + { "<leader>D", group = "Delete (blackhole)" }, + { "<leader>e", group = "Explorer" }, + { "<leader>i", group = "Inspect" }, + { "<leader>l", group = "Location" }, + { "<leader>L", group = "Lazy" }, + { "<leader>M", group = "Mason" }, + { "<leader>o", group = "Open" }, + { "<leader>p", group = "Paste" }, + { "<leader>P", group = "Paste" }, + { "<leader>q", group = "Quit" }, + { "<leader>sk", group = "Keys" }, + { "<leader>S", group = "Save/Source" }, + { "<leader>w", group = "Which-key" }, + { "<leader>W", group = "Save all" }, + { "<leader>z", group = "Toggle" }, + { "<leader><tab>", group = "Tabs" }, + { "<localleader>", group = "Local Leader (bookmarks)" }, + { "<localleader><leader>", group = "Bookmarks (explorer)" }, + { "<localleader><localleader>", group = "Bookmarks (mini)" }, + { "<localleader>t", group = "Task" }, + }, + { + mode = { "n", "v", "x" }, + { "gw", desc = "Visible in window" }, + { "g%", desc = "Match backward" }, + { "g;", desc = "Last change" }, + { "<leader>Q", group = "Quit all" }, + }, + }) + end, + keys = { + { + "<leader>?", + function() + require("which-key").show({ global = false }) + end, + desc = "Buffer local keymaps (which-key)", + }, + { + "<leader>wk", + function() + local ok, input = pcall(vim.fn.input, "WhichKey: ") + if ok and input ~= "" then + vim.cmd("WhichKey " .. input) + end + end, + desc = "Which-key query lookup", + }, + { + mode = { "n", "v", "x" }, + "<leader>wK", + "<cmd>WhichKey<cr>", + desc = "Which-key all key", + }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lf.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lf.lua new file mode 100644 index 0000000..b055c6b --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lf.lua @@ -0,0 +1,121 @@ +return { + "lmburns/lf.nvim", + dependencies = { + { + "akinsho/toggleterm.nvim", + version = "*", + config = function() + require("toggleterm").setup({ + open_mapping = [[<leader><c-s>]], -- or { [[<c-\>]], [[<c-¥>]] } if you also use a Japanese keyboard. + }) + vim.keymap.set( + "n", + "<leader><C-\\>", + "<cmd>ToggleTerm direction=float name=Terminal<cr>", + { desc = "Toggle float terminal" } + ) + vim.keymap.set( + "n", + "<leader><C-t>", + "<cmd>ToggleTermToggleAll<cr>", + { desc = "Toggle all float terminals" } + ) + vim.keymap.set("n", "<leader><C-u>", "<cmd>TermSelect<cr>", { desc = "Select float terminal" }) + + local function set_opfunc(opfunc) + _G._opfunc = opfunc -- Define the function globally + vim.go.operatorfunc = "v:lua._opfunc" -- Assign the global function + end + + local trim_spaces = false + vim.keymap.set("v", "<leader><C-l>", function() + require("toggleterm").send_lines_to_terminal("single_line", trim_spaces, { args = vim.v.count }) + end, { desc = "Send line to terminal" }) + -- Replace with these for the other two options + -- require("toggleterm").send_lines_to_terminal("visual_lines", trim_spaces, { args = vim.v.count }) + -- require("toggleterm").send_lines_to_terminal("visual_selection", trim_spaces, { args = vim.v.count }) + + -- For use as an operator map: + -- Send motion to terminal + vim.keymap.set("n", "<leader><C-l>", function() + set_opfunc(function(motion_type) + require("toggleterm").send_lines_to_terminal(motion_type, false, { args = vim.v.count }) + end) + vim.api.nvim_feedkeys("g@", "n", false) + end, { desc = "Send motions to terminal" }) + -- Double the command to send line to terminal + vim.keymap.set("n", "<leader><C-a>", function() + set_opfunc(function(motion_type) + require("toggleterm").send_lines_to_terminal(motion_type, false, { args = vim.v.count }) + end) + vim.api.nvim_feedkeys("g@_", "n", false) + end, { desc = "Send double command to terminal" }) + -- Send whole file + vim.keymap.set("n", "<leader><C-g>", function() + set_opfunc(function(motion_type) + require("toggleterm").send_lines_to_terminal(motion_type, false, { args = vim.v.count }) + end) + vim.api.nvim_feedkeys("ggg@G''", "n", false) + end, { desc = "Send whole file to terminal (clipboard)" }) + end, + }, + }, + config = function() + vim.g.lf_netrw = 1 + local fn = vim.fn + + -- Defaults + require("lf").setup({ + default_action = "drop", -- Default action when `Lf` opens a file + default_actions = { + ["e"] = "tabedit", + ["<C-t>"] = "tab drop", + ["<C-v>"] = "vsplit", + ["<C-x>"] = "split", + }, + winblend = 0, -- Pseudotransparency level + direction = "float", -- Window type + border = "rounded", -- Border kind + height = fn.float2nr(fn.round(0.75 * vim.o.lines)), -- Height of the *floating* window + width = fn.float2nr(fn.round(0.75 * vim.o.columns)), -- Width of the *floating* window + escape_quit = true, -- Map escape to the quit command + focus_on_open = true, -- Focus the current file when opening Lf + mappings = true, -- Enable terminal buffer mapping + tmux = true, -- Tmux statusline can be disabled + disable_netrw_warning = true, -- Don't display a message when opening a directory + highlights = { + Normal = { link = "Normal" }, -- Use normal highlighting + NormalFloat = { link = "NormalFloat" }, -- Use float highlighting + FloatBorder = { link = "@constant" }, -- Use constant highlighting + }, + + -- Layout configurations + layout_mapping = "<M-r>", -- Resize window with this key + views = { + { width = 0.800, height = 0.800 }, + { width = 0.600, height = 0.600 }, + { width = 0.950, height = 0.950 }, + { width = 0.500, height = 0.500, col = 0, row = 0 }, + { width = 0.500, height = 0.500, col = 0, row = 0.5 }, + { width = 0.500, height = 0.500, col = 0.5, row = 0 }, + { width = 0.500, height = 0.500, col = 0.5, row = 0.5 }, + }, + }) + + vim.keymap.set("n", "<leader>el", "<Cmd>Lf<CR>") + + -- Autocommand to set key mapping in terminal buffer + vim.api.nvim_create_autocmd("User", { + pattern = "LfTermEnter", + callback = function(a) + vim.api.nvim_buf_set_keymap( + a.buf, + "t", + "q", + "<cmd>q<CR>", + { nowait = true, noremap = true, silent = true } + ) + end, + }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lsp.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lsp.lua new file mode 100644 index 0000000..16b95fe --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lsp.lua @@ -0,0 +1,643 @@ +return { + { + "neovim/nvim-lspconfig", + event = { "BufReadPre", "BufNewFile" }, + dependencies = { + "williamboman/mason.nvim", + "williamboman/mason-lspconfig.nvim", + "WhoIsSethDaniel/mason-tool-installer.nvim", + "hrsh7th/cmp-nvim-lsp", + "hrsh7th/cmp-buffer", + "hrsh7th/cmp-path", + "hrsh7th/cmp-cmdline", + "hrsh7th/nvim-cmp", + { + "L3MON4D3/LuaSnip", + version = "v2.*", + build = "make install_jsregexp", + }, + "mfussenegger/nvim-lint", + "saadparwaiz1/cmp_luasnip", + "j-hui/fidget.nvim", + { "folke/neoconf.nvim", cmd = "Neoconf", config = false, dependencies = { "nvim-lspconfig" } }, + { + "folke/lazydev.nvim", + ft = "lua", -- only load on lua files + opts = { + library = { + -- See the configuration section for more details + -- Load luvit types when the `vim.uv` word is found + { path = "${3rd}/luv/library", words = { "vim%.uv" } }, + }, + }, + }, + "stevearc/conform.nvim", + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>tf", group = "Format" }, + }) + end, + config = function() + local cmp = require("cmp") + local cmp_lsp = require("cmp_nvim_lsp") + local capabilities = vim.tbl_deep_extend( + "force", + {}, + vim.lsp.protocol.make_client_capabilities(), + cmp_lsp.default_capabilities() + ) + local lspconfig = require("lspconfig") + + require("fidget").setup({ + progress = { + poll_rate = false, -- How and when to poll for progress messages + suppress_on_insert = true, -- Suppress new messages while in insert mode + ignore_done_already = true, -- Ignore new tasks that are already complete + ignore_empty_message = true, -- Ignore new tasks that don't contain a message + clear_on_detach = function(client_id) -- Clear notification group when LSP server detaches + local client = vim.lsp.get_client_by_id(client_id) + return client and client.name or nil + end, + -- ignore = { "lua_ls" }, + }, + notification = { + window = { + normal_hl = "Comment", -- Base highlight group in the notification window + winblend = 0, -- Background color opacity in the notification window + border = "none", -- Border around the notification window + zindex = 45, -- Stacking priority of the notification window + max_width = 0, -- Maximum width of the notification window + max_height = 0, -- Maximum height of the notification window + x_padding = 1, -- Padding from right edge of window boundary + y_padding = 0, -- Padding from bottom edge of window boundary + align = "bottom", -- How to align the notification window + relative = "editor", -- What the notification window position is relative to + }, + }, + integration = { + ["nvim-tree"] = { + enable = false, -- Integrate with nvim-tree/nvim-tree.lua (if installed) + }, + }, + }) + + require("mason").setup() + require("mason-lspconfig").setup({ + ensure_installed = { + "dockerls", + "docker_compose_language_service", + "jdtls", + "jsonls", + "lua_ls", + "pyright", + "ruff", + }, + automatic_installation = true, + handlers = { + function(server_name) -- default handler (optional) + require("lspconfig")[server_name].setup({ + capabilities = capabilities, + }) + end, + ["dockerls"] = function() + lspconfig.dockerls.setup({ + capabilities = capabilities, + -- settings = { + -- python = { + -- disableLanguageServices = false, + -- disableOrganizeImports = false, + -- }, + -- }, + }) + end, + ["docker_compose_language_service"] = function() + lspconfig.docker_compose_language_service.setup({ + capabilities = capabilities, + -- settings = { + -- python = { + -- disableLanguageServices = false, + -- disableOrganizeImports = false, + -- }, + -- }, + }) + end, + ["lua_ls"] = function() + lspconfig.lua_ls.setup({ + capabilities = capabilities, + settings = { + Lua = { + runtime = { version = "Lua 5.4" }, + diagnostics = { + globals = { "bit", "vim", "it", "describe", "before_each", "after_each" }, + }, + }, + }, + }) + end, + ["pyright"] = function() + lspconfig.pyright.setup({ + capabilities = capabilities, + settings = { + python = { + disableLanguageServices = false, + disableOrganizeImports = false, + }, + }, + }) + end, + ["ruff"] = function() + lspconfig.ruff.setup({ + capabilities = capabilities, + -- settings = { + -- python = { + -- disableLanguageServices = false, + -- disableOrganizeImports = false, + -- }, + -- }, + }) + end, + ["jdtls"] = function() + lspconfig.jdtls.setup({ + capabilities = capabilities, + }) + end, + ["jsonls"] = function() + lspconfig.jsonls.setup({ + capabilities = capabilities, + settings = { + json = { + format = { + enable = true, + }, + validate = { enable = true }, + }, + }, + }) + end, + }, + }) + + local lint = require("lint") + lint.linters_by_ft = { + dockerfile = { "hadolint" }, + javascript = { "eslint_d" }, + typescript = { "eslint_d" }, + javascriptreact = { "eslint_d" }, + typescriptreact = { "eslint_d" }, + svelte = { "eslint_d" }, + python = { "pylint" }, + sh = { "shellcheck" }, + } + + local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true }) + vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave", "TextChanged" }, { + group = lint_augroup, + callback = function() + lint.try_lint() + end, + }) + + require("mason-tool-installer").setup({ + ensure_installed = { + "beautysh", -- zsh formatter + "black", -- python formatter + "debugpy", -- python debuger + "eslint_d", -- eslint linter + "hadolint", -- docker linter + "isort", -- python formatter + "java-debug-adapter", -- java debugger + "java-test", -- java test + "markdown-toc", -- markdown toc + "prettier", -- prettier formatter + "pylint", -- python linter + "ruff", -- python formatter + "shellcheck", -- bash lint + "shfmt", -- sh formatter + "stylua", -- lua formatter + }, + integrations = { + ["mason-lspconfig"] = true, + ["mason-null-ls"] = false, + ["mason-nvim-dap"] = true, + }, + }) + + local cmp_select = { behavior = cmp.SelectBehavior.Select } + local luasnip = require("luasnip") + + cmp.setup({ + snippet = { + expand = function(args) + luasnip.lsp_expand(args.body) -- For `luasnip` users. + end, + }, + mapping = cmp.mapping.preset.insert({ + ["<C-u>"] = cmp.mapping.scroll_docs(-4), -- Up + ["<C-d>"] = cmp.mapping.scroll_docs(4), -- Down + ["<C-p>"] = cmp.mapping.select_prev_item(cmp_select), + ["<C-n>"] = cmp.mapping.select_next_item(cmp_select), + ["<CR>"] = cmp.mapping.confirm({ + behavior = cmp.ConfirmBehavior.Replace, + select = true, + }), + ["<C-Space>"] = cmp.mapping.complete(), + ["<Tab>"] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_next_item() + elseif luasnip.expand_or_jumpable() then + luasnip.expand_or_jump() + else + fallback() + end + end, { "i", "s" }), + ["<S-Tab>"] = cmp.mapping(function(fallback) + if cmp.visible() then + cmp.select_prev_item() + elseif luasnip.jumpable(-1) then + luasnip.jump(-1) + else + fallback() + end + end, { "i", "s" }), + }), + sources = cmp.config.sources({ + { name = "nvim_lsp" }, + { name = "luasnip" }, -- For luasnip users. + { name = "buffer" }, + }), + }) + + vim.diagnostic.config({ + -- update_in_insert = true, + float = { + header = "", + border = "rounded", + prefix = "", + source = "if_many", + }, + }) + + require("conform").setup({ + formatters_by_ft = { + bash = { "shfmt" }, + css = { "prettier" }, + graphql = { "prettier" }, + html = { "prettier" }, + javascript = { "prettier" }, + javascriptreact = { "prettier" }, + json = { "prettier" }, + liquid = { "prettier" }, + lua = { "stylua" }, + markdown = { "prettier" }, + python = { "ruff", "isort", "black" }, + sh = { "shfmt" }, + svelte = { "prettier" }, + typescript = { "prettier" }, + typescriptreact = { "prettier" }, + yaml = { "prettier" }, + zsh = { "beautysh" }, + }, + default_format_opts = {}, + format_on_save = function(bufnr) + -- Disable with a global or buffer-local variable + if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + return + end + return { lsp_format = "fallback", timeout_ms = 1000, async = false } + end, + }) + + vim.api.nvim_create_user_command("FormatDisable", function(args) + if args.bang then + vim.b.disable_autoformat = true + else + vim.g.disable_autoformat = true + end + end, { + desc = "Disable autoformat-on-save", + bang = true, + }) + vim.api.nvim_create_user_command("FormatEnable", function() + vim.b.disable_autoformat = false + vim.g.disable_autoformat = false + end, { + desc = "Re-enable autoformat-on-save", + }) + end, + keys = { + { + mode = { "n", "v" }, + "<leader>lf", + function() + require("conform").format({ async = true }) + end, + desc = "Format buffer by lsp", + }, + { + "<leader>ci", + "<cmd>PyrightOrganizeImports<cr>", + desc = "Organize imports", + }, + { + "<leader>bl", + function() + require("lint").try_lint() + end, + desc = "Buffer lint", + }, + { + "<leader>le", + "<cmd>FormatEnable<CR>", + desc = "Enable format", + }, + { + "<leader>ld", + "<cmd>FormatDisable<CR>", + desc = "Disable format", + }, + { + "<leader>lD", + "<cmd>FormatDisable!<CR>", + desc = "Disable current buffer format", + }, + }, + }, + -- { + -- "neovim/nvim-lspconfig", + -- event = { "BufReadPre", "BufNewFile" }, + -- dependencies = { + -- "williamboman/mason.nvim", + -- "williamboman/mason-lspconfig.nvim", + -- "WhoIsSethDaniel/mason-tool-installer.nvim", + -- "hrsh7th/cmp-nvim-lsp", + -- "hrsh7th/cmp-buffer", + -- "hrsh7th/cmp-path", + -- "hrsh7th/cmp-cmdline", + -- { + -- "L3MON4D3/LuaSnip", + -- version = "v2.*", + -- build = "make install_jsregexp", + -- }, + -- "mfussenegger/nvim-lint", + -- "saadparwaiz1/cmp_luasnip", + -- "j-hui/fidget.nvim", + -- { "folke/neoconf.nvim", cmd = "Neoconf", config = false, dependencies = { "nvim-lspconfig" } }, + -- { + -- "folke/lazydev.nvim", + -- ft = "lua", -- only load on lua files + -- opts = { + -- library = { + -- -- See the configuration section for more details + -- -- Load luvit types when the `vim.uv` word is found + -- { path = "${3rd}/luv/library", words = { "vim%.uv" } }, + -- }, + -- }, + -- }, + -- "stevearc/conform.nvim", + -- "saghen/blink.cmp", + -- }, + -- init = function() + -- local wk = require("which-key") + -- wk.add({ + -- mode = { "n", "v", "x" }, + -- { "<leader>tf", group = "Format" }, + -- }) + -- end, + -- opts = { + -- servers = { + -- lua_ls = { + -- settings = { + -- Lua = { + -- workspace = { + -- checkThirdParty = false, + -- }, + -- codeLens = { + -- enable = true, + -- }, + -- completion = { + -- callSnippet = "Replace", + -- }, + -- doc = { + -- privateName = { "^_" }, + -- }, + -- hint = { + -- enable = true, + -- setType = false, + -- paramType = true, + -- paramName = "Disable", + -- semicolon = "Disable", + -- arrayIndex = "Disable", + -- }, + -- runtime = { version = "Lua 5.4" }, + -- diagnostics = { + -- globals = { "bit", "vim", "it", "describe", "before_each", "after_each" }, + -- }, + -- }, + -- }, + -- }, + -- pyright = { + -- settings = { + -- python = { + -- disableLanguageServices = false, + -- disableOrganizeImports = false, + -- }, + -- }, + -- }, + -- }, + -- }, + -- config = function(_, opts) + -- local cmp = require("blink.cmp") + -- local lspconfig = require("lspconfig") + -- + -- require("mason").setup() + -- + -- for server, config in pairs(opts.servers) do + -- -- passing config.capabilities to blink.cmp merges with the capabilities in your + -- -- `opts[server].capabilities, if you've defined it + -- config.capabilities = cmp.get_lsp_capabilities(config.capabilities) + -- lspconfig[server].setup(config) + -- require("mason-lspconfig").setup({ + -- ensure_installed = { server }, + -- handlers = { + -- [server] = function() + -- lspconfig[server].setup(config) + -- end, + -- }, + -- }) + -- end + -- + -- require("fidget").setup({ + -- progress = { + -- poll_rate = 0, -- How and when to poll for progress messages + -- suppress_on_insert = true, -- Suppress new messages while in insert mode + -- ignore_done_already = true, -- Ignore new tasks that are already complete + -- ignore_empty_message = true, -- Ignore new tasks that don't contain a message + -- clear_on_detach = function(client_id) -- Clear notification group when LSP server detaches + -- local client = vim.lsp.get_client_by_id(client_id) + -- return client and client.name or nil + -- end, + -- ignore = { "lua_ls" }, + -- }, + -- notification = { + -- window = { + -- normal_hl = "Comment", -- Base highlight group in the notification window + -- winblend = 0, -- Background color opacity in the notification window + -- border = "none", -- Border around the notification window + -- zindex = 45, -- Stacking priority of the notification window + -- max_width = 0, -- Maximum width of the notification window + -- max_height = 0, -- Maximum height of the notification window + -- x_padding = 1, -- Padding from right edge of window boundary + -- y_padding = 0, -- Padding from bottom edge of window boundary + -- align = "bottom", -- How to align the notification window + -- relative = "editor", -- What the notification window position is relative to + -- }, + -- }, + -- integration = { + -- ["nvim-tree"] = { + -- enable = false, -- Integrate with nvim-tree/nvim-tree.lua (if installed) + -- }, + -- }, + -- }) + -- + -- local lint = require("lint") + -- lint.linters_by_ft = { + -- javascript = { "eslint_d" }, + -- typescript = { "eslint_d" }, + -- javascriptreact = { "eslint_d" }, + -- typescriptreact = { "eslint_d" }, + -- svelte = { "eslint_d" }, + -- python = { "pylint" }, + -- sh = { "shellcheck" }, + -- } + -- + -- local lint_augroup = vim.api.nvim_create_augroup("lint", { clear = true }) + -- vim.api.nvim_create_autocmd({ "BufEnter", "BufWritePost", "InsertLeave", "TextChanged" }, { + -- group = lint_augroup, + -- callback = function() + -- lint.try_lint() + -- end, + -- }) + -- + -- require("mason-tool-installer").setup({ + -- ensure_installed = { + -- "beautysh", -- zsh formatter + -- "black", -- python formatter + -- "debugpy", -- python debuger + -- "eslint_d", -- eslint linter + -- "isort", -- python formatter + -- "markdown-toc", -- markdown toc + -- "prettier", -- prettier formatter + -- "pylint", -- python linter + -- "ruff", -- python formatter + -- "shellcheck", -- bash lint + -- "shfmt", -- sh formatter + -- "stylua", -- lua formatter + -- }, + -- integrations = { + -- ["mason-lspconfig"] = true, + -- ["mason-null-ls"] = false, + -- ["mason-nvim-dap"] = true, + -- }, + -- }) + -- + -- vim.diagnostic.config({ + -- -- update_in_insert = true, + -- float = { + -- focusable = false, + -- style = "minimal", + -- border = "rounded", + -- source = "always", + -- header = "", + -- prefix = "", + -- }, + -- }) + -- + -- require("conform").setup({ + -- formatters_by_ft = { + -- bash = { "shfmt" }, + -- css = { "prettier" }, + -- graphql = { "prettier" }, + -- html = { "prettier" }, + -- javascript = { "prettier" }, + -- javascriptreact = { "prettier" }, + -- json = { "prettier" }, + -- liquid = { "prettier" }, + -- lua = { "stylua" }, + -- markdown = { "prettier" }, + -- python = { "ruff", "isort", "black" }, + -- sh = { "shfmt" }, + -- svelte = { "prettier" }, + -- typescript = { "prettier" }, + -- typescriptreact = { "prettier" }, + -- yaml = { "prettier" }, + -- zsh = { "beautysh" }, + -- }, + -- default_format_opts = {}, + -- format_on_save = function(bufnr) + -- -- Disable with a global or buffer-local variable + -- if vim.g.disable_autoformat or vim.b[bufnr].disable_autoformat then + -- return + -- end + -- return { lsp_format = "fallback", timeout_ms = 1000, async = false } + -- end, + -- }) + -- + -- vim.api.nvim_create_user_command("FormatDisable", function(args) + -- if args.bang then + -- vim.b.disable_autoformat = true + -- else + -- vim.g.disable_autoformat = true + -- end + -- end, { + -- desc = "Disable autoformat-on-save", + -- bang = true, + -- }) + -- vim.api.nvim_create_user_command("FormatEnable", function() + -- vim.b.disable_autoformat = false + -- vim.g.disable_autoformat = false + -- end, { + -- desc = "Re-enable autoformat-on-save", + -- }) + -- end, + -- keys = { + -- { + -- mode = { "n", "v" }, + -- "<leader>lf", + -- function() + -- require("conform").format({ async = true }) + -- end, + -- desc = "Format buffer by lsp", + -- }, + -- { + -- "<leader>ci", + -- "<cmd>PyrightOrganizeImports<cr>", + -- desc = "Organize imports", + -- }, + -- { + -- "<leader>bl", + -- function() + -- require("lint").try_lint() + -- end, + -- desc = "Buffer lint", + -- }, + -- { + -- "<leader>le", + -- "<cmd>FormatEnable<CR>", + -- desc = "Enable format", + -- }, + -- { + -- "<leader>ld", + -- "<cmd>FormatDisable<CR>", + -- desc = "Disable format", + -- }, + -- { + -- "<leader>lD", + -- "<cmd>FormatDisable!<CR>", + -- desc = "Disable current buffer format", + -- }, + -- }, + -- }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lualine.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lualine.lua new file mode 100644 index 0000000..e9323b5 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/lualine.lua @@ -0,0 +1,259 @@ +return { + "nvim-lualine/lualine.nvim", + dependencies = { "nvim-tree/nvim-web-devicons" }, + config = function() + local navic = require("nvim-navic") + require("lualine").setup({ + options = { + icons_enabled = true, + theme = "auto", + section_separators = { left = "", right = "" }, + component_separators = { left = "", right = "" }, + disabled_filetypes = { + statusline = {}, + winbar = {}, + }, + ignore_focus = {}, + always_divide_middle = true, + globalstatus = false, + refresh = { + statusline = 100, + tabline = 100, + winbar = 100, + }, + }, + sections = { + lualine_a = { + { + "mode", + fmt = function(str) + return str:sub(1, 1) + end, + }, + { + function() + local has_noice, noice = pcall(require, "noice") + if has_noice and noice.api and noice.api.status and noice.api.status.mode then + return noice.api.status.mode.get() or "" + else + return "" + end + end, + cond = function() + local has_noice, noice = pcall(require, "noice") + return has_noice + and noice.api + and noice.api.status + and noice.api.status.mode + and noice.api.status.mode.has() + end, + color = { bg = "#ff9e64" }, + }, + }, + lualine_b = { + "branch", + { + "diff", + colored = true, -- Displays a colored diff status if set to true + diff_color = { + -- Same color values as the general color option can be used here. + added = "LuaLineDiffAdd", -- Changes the diff's added color + modified = "LuaLineDiffChange", -- Changes the diff's modified color + removed = "LuaLineDiffDelete", -- Changes the diff's removed color you + }, + symbols = { added = "+", modified = "~", removed = "-" }, -- Changes the symbols used by the diff. + source = nil, -- A function that works as a data source for diff. + -- It must return a table as such: + -- { added = add_count, modified = modified_count, removed = removed_count } + -- or nil on failure. count <= 0 won't be displayed. + }, + { + "diagnostics", + -- Table of diagnostic sources, available sources are: + -- 'nvim_lsp', 'nvim_diagnostic', 'nvim_workspace_diagnostic', 'coc', 'ale', 'vim_lsp'. + -- or a function that returns a table as such: + -- { error=error_cnt, warn=warn_cnt, info=info_cnt, hint=hint_cnt } + sources = { "nvim_lsp", "nvim_diagnostic", "nvim_workspace_diagnostic", "coc" }, + + -- Displays diagnostics for the defined severity types + sections = { "error", "warn", "info", "hint" }, + + diagnostics_color = { + -- Same values as the general color option can be used here. + error = "DiagnosticError", -- Changes diagnostics' error color. + warn = "DiagnosticWarn", -- Changes diagnostics' warn color. + info = "DiagnosticInfo", -- Changes diagnostics' info color. + hint = "DiagnosticHint", -- Changes diagnostics' hint color. + }, + symbols = { error = "E", warn = "W", info = "I", hint = "H" }, + colored = true, -- Displays diagnostics status in color if set to true. + update_in_insert = true, -- Update diagnostics in insert mode. + always_visible = false, -- Show diagnostics even if there are none. + }, + }, + lualine_c = { + { + "filename", + file_status = true, -- Displays file status (readonly status, modified status) + newfile_status = true, -- Display new file status (new file means no write after created) + path = 3, -- 0: Just the filename + -- 1: Relative path + -- 2: Absolute path + -- 3: Absolute path, with tilde as the home directory + -- 4: Filename and parent dir, with tilde as the home directory + + shorting_target = 40, -- Shortens path to leave 40 spaces in the window + -- for other components. (terrible name, any suggestions?) + symbols = { + modified = "[*]", -- Text to show when the file is modified. + readonly = "[r]", -- Text to show when the file is non-modifiable or readonly. + unnamed = "[?]", -- Text to show for unnamed buffers. + newfile = "[%%]", -- Text to show for newly created file before first write + }, + }, + }, + lualine_x = { + { + function() + local has_noice, noice = pcall(require, "noice") + if has_noice and noice.api and noice.api.status and noice.api.status.mode then + return noice.api.status.search.get() or "" + else + return "" + end + end, + cond = function() + local has_noice, noice = pcall(require, "noice") + return has_noice + and noice.api + and noice.api.status + and noice.api.status.search + and noice.api.status.search.has() + end, + color = { bg = "#ff9e64" }, + }, + "copilot", + { + function() + return require("molten.status").initialized() + end, + }, + "encoding", + "fileformat", + { + "filetype", + colored = true, -- Displays filetype icon in color if set to true + icon_only = true, -- Display only an icon for filetype + icon = { align = "right" }, -- Display filetype icon on the right hand side + -- icon = {'X', align='right'} + -- Icon string ^ in table is ignored in filetype component + }, + }, + lualine_y = { + "progress", + }, + lualine_z = { + { + function() + local is_tmux = os.getenv("TMUX") ~= nil + if is_tmux then + return "" + end + return os.date("%H:%M") + end, + }, + }, + }, + inactive_sections = {}, + tabline = { + lualine_a = { + { + "tabs", + tab_max_length = 40, -- Maximum width of each tab. The content will be shorten dynamically (example: apple/orange -> a/orange) + max_length = vim.o.columns / 3, -- Maximum width of tabs component. + -- Note: + -- It can also be a function that returns + -- the value of `max_length` dynamically. + mode = 0, -- 0: Shows tab_nr + -- 1: Shows tab_name + -- 2: Shows tab_nr + tab_name + + path = nil, -- 0: just shows the filename + -- 1: shows the relative path and shorten $HOME to ~ + -- 2: shows the full path + -- 3: shows the full path and shorten $HOME to ~ + + -- Automatically updates active tab color to match color of other components (will be overidden if buffers_color is set) + use_mode_colors = true, + + -- tabs_color = { + -- -- Same values as the general color option can be used here. + -- active = "lualine_{section}_normal", -- Color for active tab. + -- inactive = "lualine_{section}_inactive", -- Color for inactive tab. + -- }, + -- + show_modified_status = false, -- Shows a symbol next to the tab name if the file has been modified. + symbols = { + modified = "*", -- Text to show when the file is modified. + }, + + fmt = function(name, context) + -- Show + if buffer is modified in tab + local buflist = vim.fn.tabpagebuflist(context.tabnr) + local winnr = vim.fn.tabpagewinnr(context.tabnr) + local bufnr = buflist[winnr] + local mod = vim.fn.getbufvar(bufnr, "&mod") + + return name .. (mod == 1 and " +" or "") + end, + }, + }, + lualine_b = { + { + function() + local function buffer_status() + local buffers = vim.fn.getbufinfo({ buflisted = true }) + local current_buf = vim.fn.bufnr() + local current_buffer_index = 0 + local modified_symbol = vim.bo.modified and "●" or "" + for i, buf in ipairs(buffers) do + if buf.bufnr == current_buf then + current_buffer_index = i + break + end + end + return string.format("%s%d/%d", modified_symbol, current_buffer_index, #buffers) + end + return buffer_status() + end, + }, + }, + lualine_c = { + { + function() + return navic.get_location() + end, + cond = function() + return navic.is_available() + end, + }, + }, + lualine_x = {}, + lualine_y = {}, + lualine_z = {}, + }, + winbar = {}, + inactive_winbar = {}, + extensions = {}, + }) + + local lualine_hidden = true + vim.keymap.set({ "n", "v" }, "<leader>zl", function() + lualine_hidden = not lualine_hidden + require("lualine").hide({ + place = { "statusline", "tabline", "winbar" }, + unhide = lualine_hidden, + }) + end, { desc = "Toggle lualine" }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/markdown.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/markdown.lua new file mode 100644 index 0000000..fa5051e --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/markdown.lua @@ -0,0 +1,454 @@ +-- Select the current cell +local function select_cell() + local bufnr = vim.api.nvim_get_current_buf() + local current_row = vim.api.nvim_win_get_cursor(0)[1] + local current_col = vim.api.nvim_win_get_cursor(0)[2] + + local start_line = nil + local end_line = nil + local line_count = vim.api.nvim_buf_line_count(bufnr) + + -- Find the start of the cell (looking for opening markers or headers) + for line = current_row, 1, -1 do + local line_content = vim.api.nvim_buf_get_lines(bufnr, line - 1, line, false)[1] + if line_content:match("^```%s*[%w_%-]+") or line_content:match("^%s*#+%s") then + start_line = line + break + end + end + + -- If no start line is found, assume start of the file + if not start_line then + start_line = 1 + end + + -- Find the end of the cell (looking for the next opening marker or header) + for line = start_line + 1, line_count do + local line_content = vim.api.nvim_buf_get_lines(bufnr, line - 1, line, false)[1] + if line_content:match("^```%s*[%w_%-]+") or line_content:match("^%s*#+%s") then + end_line = line - 1 + break + end + end + + -- If no end line is found, assume end of the file + if not end_line then + end_line = line_count + end + + return current_row, current_col, start_line, end_line +end + +-- Delete the current cell +local function delete_cell() + local _, _, start_line, end_line = select_cell() -- Use select_cell to get start and end lines of the cell + if start_line and end_line then + -- Move cursor to the start of the cell + vim.api.nvim_win_set_cursor(0, { start_line, 0 }) + + -- Enter visual line mode to select the cell + vim.cmd("normal! V") + -- Move cursor to the end of the cell to extend selection + vim.api.nvim_win_set_cursor(0, { end_line, 0 }) + + -- Delete the selected lines + vim.cmd("normal! d") + end +end + +-- Navigate to the next or previous cell +local function navigate_cell(up) + local bufnr = vim.api.nvim_get_current_buf() + local line_count = vim.api.nvim_buf_line_count(bufnr) + local _, _, start_line, end_line = select_cell() -- Get the start and end lines of the current cell + + local target_line = nil + + if up then + -- Find the previous cell start, skipping any closing markers + for line = start_line - 1, 1, -1 do + local line_content = vim.api.nvim_buf_get_lines(bufnr, line - 1, line, false)[1] + if line_content:match("^```%s*[%w_%-]+") or line_content:match("^%s*#+%s") then + target_line = line + break + end + end + else + -- Find the next cell start, skipping any closing markers + for line = end_line + 1, line_count do + local line_content = vim.api.nvim_buf_get_lines(bufnr, line - 1, line, false)[1] + if line_content:match("^```%s*[%w_%-]+") or line_content:match("^%s*#+%s") then + target_line = line + break + end + end + end + + -- Navigate to the target line if found, otherwise stay at the current position + if target_line then + -- If the target is a code block, move cursor to the line right after the opening marker + local target_line_content = vim.api.nvim_buf_get_lines(bufnr, target_line - 1, target_line, false)[1] + if target_line_content:match("^```%s*[%w_%-]+") then + vim.api.nvim_win_set_cursor(0, { target_line + 1, 0 }) -- Move inside the code block + else + vim.api.nvim_win_set_cursor(0, { target_line, 0 }) -- Move to the markdown header line + end + else + if up then + vim.api.nvim_win_set_cursor(0, { 1, 0 }) -- Move to start of file if no previous cell found + else + vim.api.nvim_win_set_cursor(0, { line_count, 0 }) -- Move to end of file if no next cell found + end + end +end + +-- Insert a new cell with specific content +local function insert_cell(content) + local _, _, _, end_line = select_cell() + local bufnr = vim.api.nvim_get_current_buf() + local line = end_line + if end_line ~= 1 then + line = end_line - 1 + vim.api.nvim_win_set_cursor(0, { end_line - 1, 0 }) + else + line = end_line + vim.api.nvim_win_set_cursor(0, { end_line, 0 }) + end + + vim.cmd("normal!2o") + vim.api.nvim_buf_set_lines(bufnr, line, line + 1, false, { content }) + vim.cmd("normal!2o") + vim.cmd("normal!k") +end + +-- Insert a new code cell +local function insert_code_cell() + insert_cell("```python") -- For regular code cells +end + +return { + -- { + -- "ixru/nvim-markdown", + -- config = function() + -- vim.g.vim_markdown_no_default_key_mappings = 1 + -- end, + -- }, + { + "MeanderingProgrammer/render-markdown.nvim", + enabled = true, + -- dependencies = { "nvim-treesitter/nvim-treesitter", "echasnovski/mini.nvim" }, -- if you use the mini.nvim suite + dependencies = { "nvim-treesitter/nvim-treesitter", "echasnovski/mini.icons" }, -- if you use standalone mini plugins + -- dependencies = { 'nvim-treesitter/nvim-treesitter', 'nvim-tree/nvim-web-devicons' }, -- if you prefer nvim-web-devicons + ---@module 'render-markdown' + ---@type render.md.UserConfig + opts = {}, + config = function() + -- require("obsidian").get_client().opts.ui.enable = false + -- vim.api.nvim_buf_clear_namespace(0, vim.api.nvim_get_namespaces()["ObsidianUI"], 0, -1) + require("render-markdown").setup({ + bullet = { + -- Turn on / off list bullet rendering + enabled = true, + }, + heading = { + sign = false, + icons = { " ", " ", " ", " ", " ", " " }, + }, + file_types = { "markdown", "vimwiki" }, + }) + vim.treesitter.language.register("markdown", "vimwiki") + end, + }, + { + -- Install markdown preview, use npx if available. + "iamcco/markdown-preview.nvim", + cmd = { "MarkdownPreviewToggle", "MarkdownPreview", "MarkdownPreviewStop" }, + ft = { "markdown" }, + build = function(plugin) + if vim.fn.executable("npx") then + vim.cmd("!cd " .. plugin.dir .. " && cd app && npx --yes yarn install") + else + vim.cmd([[Lazy load markdown-preview.nvim]]) + vim.fn["mkdp#util#install"]() + end + end, + init = function() + if vim.fn.executable("npx") then + vim.g.mkdp_filetypes = { "markdown" } + end + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>m", group = "Markdown/Map" }, + }) + end, + keys = { + { "<leader>mp", "<cmd>MarkdownPreview<CR>", desc = "Markdown Preview" }, + { "<leader>mx", "<cmd>MarkdownPreviewStop<CR>", desc = "Markdown Stop" }, + { "<leader>md", "<cmd>MarkdownPreviewToggle<CR>", desc = "Markdown Toggle" }, + }, + }, + { + "dhruvasagar/vim-open-url", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "g<CR>", group = "Search word under curosr" }, + { "gB", group = "Open url in browser" }, + { "gG", group = "Google search word under cursor" }, + { "gW", group = "Wikipedia search word under cursor" }, + }) + end, + }, + { + "AckslD/nvim-FeMaco.lua", + config = function() + require("femaco").setup() + end, + }, + { + "goerz/jupytext.vim", + lazy = false, + build = "pip install jupytext", + dependencies = { "neovim/nvim-lspconfig" }, + config = function() + -- The destination format: 'ipynb', 'markdown' or 'script', or a file extension: 'md', 'Rmd', 'jl', 'py', 'R', ..., 'auto' (script + -- extension matching the notebook language), or a combination of an extension and a format name, e.g. md:markdown, md:pandoc, + -- md:myst or py:percent, py:light, py:nomarker, py:hydrogen, py:sphinx. The default format for scripts is the 'light' format, + -- which uses few cell markers (none when possible). Alternatively, a format compatible with many editors is the 'percent' format, + -- which uses '# %%' as cell markers. The main formats (markdown, light, percent) preserve notebooks and text documents in a + -- roundtrip. Use the --test and and --test-strict commands to test the roundtrip on your files. Read more about the available + -- formats at https://jupytext.readthedocs.io/en/latest/formats.html (default: None) + vim.g.jupytext_fmt = "markdown" + end, + keys = { + { "<A-i>", insert_code_cell, desc = "Insert Code Cell" }, + { "<A-x>", delete_cell, desc = "Delete Cell" }, + { + "<S-Tab>", + function() + navigate_cell(true) + end, + desc = "Previous Cell", + }, + { "<Tab>", navigate_cell, desc = "Next Cell" }, + }, + }, + { + "vhyrro/luarocks.nvim", + priority = 1001, -- this plugin needs to run before anything else + init = function() + package.path = package.path + .. ";" + .. vim.fn.expand("$HOME") + .. "/.config/luarocks/share/lua/5.1/magick/init.lua;" + end, + opt = { + rocks = { "magick" }, + }, + }, + { "benlubas/image-save.nvim", cmd = "SaveImage" }, + { + "3rd/image.nvim", + dependencies = { "leafo/magick", "vhyrro/luarocks.nvim" }, + config = function() + require("image").setup({ + backend = "ueberzug", -- or "kitty", whatever backend you would like to use + processor = "magick_rock", -- or "magick_cli" + integrations = { + markdown = { + enabled = true, + clear_in_insert_mode = false, + download_remote_images = false, + only_render_image_at_cursor = false, + floating_windows = false, -- if true, images will be rendered in floating markdown windows + filetypes = { "markdown", "quarto" }, -- markdown extensions (ie. quarto) can go here + }, + neorg = { + enabled = true, + filetypes = { "norg" }, + }, + typst = { + enabled = true, + filetypes = { "typst" }, + }, + html = { + enabled = false, + }, + css = { + enabled = false, + }, + }, + max_width = 100, + max_height = 8, + max_height_window_percentage = math.huge, + max_width_window_percentage = math.huge, + window_overlap_clear_enabled = true, -- toggles images when windows are overlapped + window_overlap_clear_ft_ignore = { "cmp_menu", "cmp_docs", "fidget", "" }, + editor_only_render_when_focused = true, -- auto show/hide images when the editor gains/looses focus + tmux_show_only_in_active_window = true, -- auto show/hide images in the correct Tmux window (needs visual-activity off) + hijack_file_patterns = { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp", "*.avif" }, -- render image files as images when opened + }) + end, + }, + { + "quarto-dev/quarto-nvim", + dependencies = { + { + "jmbuhr/otter.nvim", + lazy = false, + dependencies = { + "nvim-treesitter/nvim-treesitter", + }, + opts = {}, + config = function() + require("otter").setup() + end, + }, + "nvim-cmp", + "neovim/nvim-lspconfig", + "nvim-treesitter/nvim-treesitter", + "otter.nvim", + }, + ft = { "quarto", "markdown" }, + command = "QuartoActivate", + config = function() + require("quarto").setup({ + lspFeatures = { + languages = { "r", "python", "rust", "lua" }, + chunks = "all", + diagnostics = { + enabled = true, + triggers = { "BufWritePost" }, + }, + completion = { + enabled = true, + }, + }, + keymap = { + hover = "H", + definition = "gd", + rename = "<leader>rn", + references = "gr", + format = "<leader>gf", + }, + codeRunner = { + enabled = true, + default_method = "molten", + ft_runners = { + bash = "slime", + python = "molten", + }, + never_run = { "yaml" }, -- filetypes which are never sent to a code runner + }, + }) + local runner = require("quarto.runner") + vim.keymap.set("n", "<leader>jc", runner.run_cell, { silent = true, desc = "Run cell" }) + vim.keymap.set("n", "<leader>jC", runner.run_above, { silent = true, desc = "Run above cell" }) + vim.keymap.set("n", "<leader>jl", runner.run_line, { silent = true, desc = "Run line" }) + vim.keymap.set("v", "<leader>jv", runner.run_range, { silent = true, desc = "Run block" }) + vim.keymap.set("n", "<leader>jA", runner.run_all, { silent = true, desc = "Run all" }) + vim.keymap.set( + "n", + "<leader>qp", + require("quarto").quartoPreview, + { noremap = true, silent = true, desc = "Preview the quarto document" } + ) + -- to create a cell in insert mode, I have the ` snippet + vim.keymap.set( + "n", + "<leader>cc", + "i```python\n```<Esc>O", + { silent = true, desc = "Create a new code cell" } + ) + vim.keymap.set( + "n", + "<leader>cs", + "i```\r\r```{}<left>", + { noremap = true, silent = true, desc = "Split code cell" } + ) + end, + }, + { + "benlubas/molten-nvim", + version = "^1.0.0", -- use version <2.0.0 to avoid breaking changes + dependencies = { "3rd/image.nvim" }, + build = ":UpdateRemotePlugins", + init = function() + vim.g.molten_auto_image_popup = true + vim.g.molten_auto_init_behavior = "raise" + vim.g.molten_auto_open_html_in_browser = false + -- I find auto open annoying, keep in mind setting this option will require setting + -- a keybind for `:noautocmd MoltenEnterOutput` to open the output again + vim.g.molten_auto_open_output = true + vim.g.molten_cover_empty_lines = false + vim.g.molten_cover_lines_starting_with = {} + vim.g.molten_copy_output = false + vim.g.molten_enter_output_behavior = "open_then_enter" + -- this guide will be using image.nvim + -- Don't forget to setup and install the plugin if you want to view image outputs + vim.g.molten_image_provider = "image.nvim" + vim.g.molten_output_show_more = false + vim.g.molten_output_win_max_height = 30 + vim.g.molten_output_win_style = "minimal" + -- this will make it so the output shows up below the \`\`\` cell delimiter + vim.g.molten_virt_lines_off_by_1 = true + -- Output as virtual text. Allows outputs to always be shown, works with images, but can + -- be buggy with longer images + vim.g.molten_virt_text_output = true + -- optional, works for virt text and the output window + vim.g.molten_wrap_output = true + vim.g.molten_virt_text_max_lines = 20 + + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>j", group = "Molten (Jupyter)" }, + }) + end, + config = function() + -- image nvim options table. Pass to `require('image').setup` + vim.keymap.set("n", "<leader>jJ", ":MoltenInit<CR>", { silent = true, desc = "Init molten" }) + vim.keymap.set( + "n", + "<leader>jo", + ":MoltenEvaluateOperator<CR>", + { silent = true, desc = "Evaluate operator" } + ) + vim.keymap.set("n", "<leader>jL", ":MoltenEvaluateLine<CR>", { silent = true, desc = "Evaluate line" }) + vim.keymap.set("n", "<leader>jr", ":MoltenReevaluateCell<CR>", { silent = true, desc = "Re-evaluate cell" }) + vim.keymap.set( + "v", + "<leader>jV", + ":<C-u>MoltenEvaluateVisual<CR>gv<Esc>", + { silent = true, desc = "Evaluate visual block" } + ) + vim.keymap.set("n", "<leader>jd", ":MoltenDelete<CR>", { silent = true, desc = "Delete molten" }) + vim.keymap.set("n", "<leader>jh", ":MoltenHideOutput<CR>", { silent = true, desc = "Hide output" }) + vim.keymap.set( + "n", + "<leader>jm", + ":noautocmd MoltenEnterOutput<CR>", + { silent = true, desc = "Enter output" } + ) + vim.api.nvim_create_autocmd("User", { + pattern = "MoltenInitPost", + callback = function() + require("quarto").activate() + end, + }) + vim.keymap.set("n", "<leader>ji", ":MoltenImagePopup<CR>", { silent = true, desc = "Pop-up image" }) + vim.keymap.set("n", "<leader>jw", ":MoltenOpenInBrowser<CR>", { silent = true, desc = "Open in browser" }) + vim.keymap.set("n", "<leader>jj", function() + local venv = os.getenv("WORKON_HOME") + if venv ~= nil then + venv = string.match(venv, "/.+/(.+)") + vim.cmd(("MoltenInit %s"):format(venv)) + else + vim.cmd("MoltenInit python3") + end + end, { desc = "Init default molten" }) + end, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/marks.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/marks.lua new file mode 100644 index 0000000..d59d0f1 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/marks.lua @@ -0,0 +1,16 @@ +return { + "chentoast/marks.nvim", + config = function() + require("marks").setup() + end, + init = function() + local wk = require("which-key") + wk.add({ + { + mode = { "n", "v" }, + { "m", group = "Marks" }, + { "dm", desc = "Delete marks" }, + }, + }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/mini.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/mini.lua new file mode 100644 index 0000000..d520afc --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/mini.lua @@ -0,0 +1,1132 @@ +-- Updated pattern to match what Echasnovski has in the documentation +-- https://github.com/echasnovski/mini.nvim/blob/c6eede272cfdb9b804e40dc43bb9bff53f38ed8a/doc/mini-files.txt#L508-L529 + +-- Define a function to update MiniJump highlight based on Search +local function update_mini_jump_highlight() + local search_hl = vim.api.nvim_get_hl(0, { name = "Search" }) + vim.api.nvim_set_hl(0, "MiniJump", { + fg = search_hl.fg, + bg = search_hl.bg, + bold = search_hl.bold or false, + }) +end + +return { + { + "echasnovski/mini.ai", + version = false, + config = function() + require("mini.ai").setup({ + -- Table with textobject id as fields, textobject specification as values. + -- Also use this to disable builtin textobjects. See |MiniAi.config|. + custom_textobjects = nil, + + -- Module mappings. Use `''` (empty string) to disable one. + mappings = { + -- Main textobject prefixes + around = "a", + inside = "i", + + -- Next/last variants + around_next = "an", + inside_next = "in", + around_last = "al", + inside_last = "il", + + -- Move cursor to corresponding edge of `a` textobject + goto_left = "g[", + goto_right = "g]", + }, + + -- Number of lines within which textobject is searched + n_lines = 50, + + -- How to search for object (first inside current line, then inside + -- neighborhood). One of 'cover', 'cover_or_next', 'cover_or_prev', + -- 'cover_or_nearest', 'next', 'previous', 'nearest'. + search_method = "cover_or_next", + + -- Whether to disable showing non-error feedback + -- This also affects (purely informational) helper messages shown after + -- idle time if user input is required. + silent = false, + }) + end, + }, + { + "echasnovski/mini.bracketed", + version = false, + config = function() + require("mini.bracketed").setup({ + buffer = { suffix = "", options = {} }, + comment = { suffix = "", options = {} }, + conflict = { suffix = "", options = {} }, + diagnostic = { suffix = "", options = {} }, + file = { suffix = "", options = {} }, + indent = { suffix = "", options = {} }, + jump = { suffix = "", options = {} }, + location = { suffix = "", options = {} }, + oldfile = { suffix = "", options = {} }, + quickfix = { suffix = "", options = {} }, + treesitter = { suffix = "", options = {} }, + undo = { suffix = "", options = {} }, + window = { suffix = "", options = {} }, + yank = { suffix = "", options = {} }, + }) + + vim.keymap.set("n", "<leader>[B", "<Cmd>lua MiniBracketed.buffer('first')<cr>", { desc = "Buffer first" }) + vim.keymap.set( + "n", + "<leader>[b", + "<Cmd>lua MiniBracketed.buffer('backward')<cr>", + { desc = "Buffer backward" } + ) + vim.keymap.set( + "n", + "<leader>]b", + "<Cmd>lua MiniBracketed.buffer('forward')<cr>", + { desc = "Buffer forward" } + ) + vim.keymap.set("n", "<leader>]B", "<Cmd>lua MiniBracketed.buffer('last')<cr>", { desc = "Buffer last" }) + vim.keymap.set("n", "<leader>[C", "<Cmd>lua MiniBracketed.comment('first')<cr>", { desc = "Comment first" }) + vim.keymap.set( + "n", + "<leader>[c", + "<Cmd>lua MiniBracketed.comment('backward')<cr>", + { desc = "Comment backward" } + ) + vim.keymap.set( + "n", + "<leader>]c", + "<Cmd>lua MiniBracketed.comment('forward')<cr>", + { desc = "Comment forward" } + ) + vim.keymap.set("n", "<leader>]C", "<Cmd>lua MiniBracketed.comment('last')<cr>", { desc = "Comment last" }) + vim.keymap.set( + "n", + "<leader>[X", + "<Cmd>lua MiniBracketed.conflict('first')<cr>", + { desc = "Conflict first" } + ) + vim.keymap.set( + "n", + "<leader>[x", + "<Cmd>lua MiniBracketed.conflict('backward')<cr>", + { desc = "Conflict backward" } + ) + vim.keymap.set( + "n", + "<leader>]x", + "<Cmd>lua MiniBracketed.conflict('forward')<cr>", + { desc = "Conflict forward" } + ) + vim.keymap.set("n", "<leader>]X", "<Cmd>lua MiniBracketed.conflict('last')<cr>", { desc = "Conflict last" }) + vim.keymap.set( + "n", + "<leader>[D", + "<Cmd>lua MiniBracketed.diagnostic('first')<cr>", + { desc = "Diagnostic first" } + ) + vim.keymap.set( + "n", + "<leader>[d", + "<Cmd>lua MiniBracketed.diagnostic('backward')<cr>", + { desc = "Diagnostic backward" } + ) + vim.keymap.set( + "n", + "<leader>]d", + "<Cmd>lua MiniBracketed.diagnostic('forward')<cr>", + { desc = "Diagnostic forward" } + ) + vim.keymap.set( + "n", + "<leader>]D", + "<Cmd>lua MiniBracketed.diagnostic('last')<cr>", + { desc = "Diagnostic last" } + ) + vim.keymap.set("n", "<leader>[F", "<Cmd>lua MiniBracketed.file('first')<cr>", { desc = "File first" }) + vim.keymap.set("n", "<leader>[f", "<Cmd>lua MiniBracketed.file('backward')<cr>", { desc = "File backward" }) + vim.keymap.set("n", "<leader>]f", "<Cmd>lua MiniBracketed.file('forward')<cr>", { desc = "File forward" }) + vim.keymap.set("n", "<leader>]F", "<Cmd>lua MiniBracketed.file('last')<cr>", { desc = "File last" }) + vim.keymap.set("n", "<leader>[I", "<Cmd>lua MiniBracketed.indent('first')<cr>", { desc = "Indent first" }) + vim.keymap.set( + "n", + "<leader>[i", + "<Cmd>lua MiniBracketed.indent('backward')<cr>", + { desc = "Indent backward" } + ) + vim.keymap.set( + "n", + "<leader>]i", + "<Cmd>lua MiniBracketed.indent('forward')<cr>", + { desc = "Indent forward" } + ) + vim.keymap.set("n", "<leader>]I", "<Cmd>lua MiniBracketed.indent('last')<cr>", { desc = "Indent last" }) + vim.keymap.set("n", "<leader>[J", "<Cmd>lua MiniBracketed.jump('first')<cr>", { desc = "Jump first" }) + vim.keymap.set("n", "<leader>[j", "<Cmd>lua MiniBracketed.jump('backward')<cr>", { desc = "Jump backward" }) + vim.keymap.set("n", "<leader>]j", "<Cmd>lua MiniBracketed.jump('forward')<cr>", { desc = "Jump forward" }) + vim.keymap.set("n", "<leader>]J", "<Cmd>lua MiniBracketed.jump('last')<cr>", { desc = "Jump last" }) + vim.keymap.set( + "n", + "<leader>[L", + "<Cmd>lua MiniBracketed.location('first')<cr>", + { desc = "Location first" } + ) + vim.keymap.set( + "n", + "<leader>[l", + "<Cmd>lua MiniBracketed.location('backward')<cr>", + { desc = "Location backward" } + ) + vim.keymap.set( + "n", + "<leader>]l", + "<Cmd>lua MiniBracketed.location('forward')<cr>", + { desc = "Location forward" } + ) + vim.keymap.set("n", "<leader>]L", "<Cmd>lua MiniBracketed.location('last')<cr>", { desc = "Location last" }) + vim.keymap.set("n", "<leader>[O", "<Cmd>lua MiniBracketed.oldfile('first')<cr>", { desc = "Oldfile first" }) + vim.keymap.set( + "n", + "<leader>[o", + "<Cmd>lua MiniBracketed.oldfile('backward')<cr>", + { desc = "Oldfile backward" } + ) + vim.keymap.set( + "n", + "<leader>]o", + "<Cmd>lua MiniBracketed.oldfile('forward')<cr>", + { desc = "Oldfile forward" } + ) + vim.keymap.set("n", "<leader>]O", "<Cmd>lua MiniBracketed.oldfile('last')<cr>", { desc = "Oldfile last" }) + vim.keymap.set( + "n", + "<leader>[Q", + "<Cmd>lua MiniBracketed.quickfix('first')<cr>", + { desc = "Quickfix first" } + ) + vim.keymap.set( + "n", + "<leader>[q", + "<Cmd>lua MiniBracketed.quickfix('backward')<cr>", + { desc = "Quickfix backward" } + ) + vim.keymap.set( + "n", + "<leader>]q", + "<Cmd>lua MiniBracketed.quickfix('forward')<cr>", + { desc = "Quickfix forward" } + ) + vim.keymap.set("n", "<leader>]Q", "<Cmd>lua MiniBracketed.quickfix('last')<cr>", { desc = "Quickfix last" }) + vim.keymap.set( + "n", + "<leader>[T", + "<Cmd>lua MiniBracketed.treesitter('first')<cr>", + { desc = "Treesitter first" } + ) + vim.keymap.set( + "n", + "<leader>[t", + "<Cmd>lua MiniBracketed.treesitter('backward')<cr>", + { desc = "Treesitter backward" } + ) + vim.keymap.set( + "n", + "<leader>]t", + "<Cmd>lua MiniBracketed.treesitter('forward')<cr>", + { desc = "Treesitter forward" } + ) + vim.keymap.set( + "n", + "<leader>]T", + "<Cmd>lua MiniBracketed.treesitter('last')<cr>", + { desc = "Treesitter last" } + ) + vim.keymap.set("n", "<leader>[U", "<Cmd>lua MiniBracketed.undo('first')<cr>", { desc = "Undo first" }) + vim.keymap.set("n", "<leader>[u", "<Cmd>lua MiniBracketed.undo('backward')<cr>", { desc = "Undo backward" }) + vim.keymap.set("n", "<leader>]u", "<Cmd>lua MiniBracketed.undo('forward')<cr>", { desc = "Undo forward" }) + vim.keymap.set("n", "<leader>]U", "<Cmd>lua MiniBracketed.undo('last')<cr>", { desc = "Undo last" }) + vim.keymap.set("n", "<leader>w0", "<Cmd>lua MiniBracketed.window('first')<cr>", { desc = "Window first" }) + vim.keymap.set( + "n", + "<leader>w[", + "<Cmd>lua MiniBracketed.window('backward')<cr>", + { desc = "Window backward" } + ) + vim.keymap.set( + "n", + "<leader>w]", + "<Cmd>lua MiniBracketed.window('forward')<cr>", + { desc = "Window forward" } + ) + vim.keymap.set("n", "<leader>w$", "<Cmd>lua MiniBracketed.window('last')<cr>", { desc = "Window last" }) + vim.keymap.set("n", "<leader>[Y", "<Cmd>lua MiniBracketed.yank('first')<cr>", { desc = "Yank first" }) + vim.keymap.set("n", "<leader>[y", "<Cmd>lua MiniBracketed.yank('backward')<cr>", { desc = "Yank backward" }) + vim.keymap.set("n", "<leader>]y", "<Cmd>lua MiniBracketed.yank('forward')<cr>", { desc = "Yank forward" }) + vim.keymap.set("n", "<leader>]Y", "<Cmd>lua MiniBracketed.yank('last')<cr>", { desc = "Yank last" }) + end, + }, + { + "echasnovski/mini.files", + opts = { + -- I didn't like the default mappings, so I modified them + -- Module mappings created only inside explorer. + -- Use `''` (empty string) to not create one. + mappings = { + close = "q", + -- Use this if you want to open several files + go_in = "l", + -- This opens the file, but quits out of mini.files (default L) + go_in_plus = "<CR>", + -- I swapped the following 2 (default go_out: h) + -- go_out_plus: when you go out, it shows you only 1 item to the right + -- go_out: shows you all the items to the right + go_out = "H", + go_out_plus = "h", + -- Default <BS> + reset = ",", + -- Default @ + reveal_cwd = ".", + show_help = "g?", + -- Default = + synchronize = "s", + trim_left = "<", + trim_right = ">", + toggle_hidden = nil, + change_cwd = nil, + go_in_horizontal = nil, + go_in_vertical = nil, + go_in_horizontal_plus = nil, + go_in_vertical_plus = nil, + }, + options = { + use_as_default_explorer = true, + permanent_delete = false, + }, + windows = { + preview = true, + width_focus = 25, + width_preview = 40, + }, + }, + keys = { + { + "<leader>e", + function() + if not MiniFiles.close() then + require("mini.files").open(vim.api.nvim_buf_get_name(0), true) + end + end, + desc = "Open mini.files", + }, + { + "<leader>E", + function() + require("mini.files").open(vim.uv.cwd(), true) + end, + desc = "Open mini.files (cwd)", + }, + }, + config = function(_, opts) + require("mini.files").setup(opts) + + local show_dotfiles = true + local filter_show = function(fs_entry) + return true + end + local filter_hide = function(fs_entry) + return not vim.startswith(fs_entry.name, ".") + end + + local toggle_dotfiles = function() + show_dotfiles = not show_dotfiles + local new_filter = show_dotfiles and filter_show or filter_hide + require("mini.files").refresh({ content = { filter = new_filter } }) + end + + local map_split = function(buf_id, lhs, direction, close_on_file) + local rhs = function() + local new_target_window + local cur_target_window = require("mini.files").get_explorer_state().arget_window + + if cur_target_window ~= nil then + vim.api.nvim_win_call(cur_target_window, function() + vim.cmd("belowright " .. direction .. " split") + new_target_window = vim.api.nvim_get_current_win() + end) + + require("mini.files").set_target_window(new_target_window) + require("mini.files").go_in({ close_on_file = close_on_file }) + end + end + + local desc = "Open in " .. direction .. " split" + if close_on_file then + desc = desc .. " and close" + end + vim.keymap.set("n", lhs, rhs, { buffer = buf_id, desc = desc }) + end + + local files_set_cwd = function() + local cur_entry_path = MiniFiles.get_fs_entry().path + local cur_directory = vim.fs.dirname(cur_entry_path) + if cur_directory ~= nil then + vim.fn.chdir(cur_directory) + end + end + + local mini_files = require("mini.files") + local tmux_pane_function = require("thesiahxyz.utils.tmux").tmux_pane_function + + local open_tmux_pane = function() + local curr_entry = mini_files.get_fs_entry() + if curr_entry then + if curr_entry.fs_type == "directory" then + tmux_pane_function(curr_entry.path) + elseif curr_entry.fs_type == "file" then + local parent_dir = vim.fn.fnamemodify(curr_entry.path, ":h") + tmux_pane_function(parent_dir) + elseif curr_entry.fs_type == "link" then + local resolved_path = vim.fn.resolve(curr_entry.path) + if vim.fn.isdirectory(resolved_path) == 1 then + tmux_pane_function(resolved_path) + else + local parent_dir = vim.fn.fnamemodify(resolved_path, ":h") + tmux_pane_function(parent_dir) + end + else + vim.notify("Unsupported file system entry type", vim.log.levels.WARN) + end + else + vim.notify("No entry selected", vim.log.levels.WARN) + end + end + + local copy_to_clipboard = function() + local curr_entry = mini_files.get_fs_entry() + if curr_entry then + local path = curr_entry.path + -- Escape the path for shell command + local escaped_path = vim.fn.fnameescape(path) + local cmd = vim.fn.has("mac") == 1 + and string.format([[osascript -e 'set the clipboard to POSIX file "%s"']], escaped_path) + or string.format([[echo -n %s | xclip -selection clipboard]], escaped_path) + local result = vim.fn.system(cmd) + if vim.v.shell_error ~= 0 then + vim.notify("Copy failed: " .. result, vim.log.levels.ERROR) + else + vim.notify(vim.fn.fnamemodify(path, ":t"), vim.log.levels.INFO) + vim.notify("Copied to system clipboard", vim.log.levels.INFO) + end + else + vim.notify("No file or directory selected", vim.log.levels.WARN) + end + end + + local zip_and_copy_to_clipboard = function() + local curr_entry = require("mini.files").get_fs_entry() + if curr_entry then + local path = curr_entry.path + local name = vim.fn.fnamemodify(path, ":t") -- Extract the file or directory name + local parent_dir = vim.fn.fnamemodify(path, ":h") -- Get the parent directory + local timestamp = os.date("%y%m%d%H%M%S") -- Append timestamp to avoid duplicates + local zip_path = string.format("/tmp/%s_%s.zip", name, timestamp) -- Path in macOS's tmp directory + -- Create the zip file + local zip_cmd = string.format( + "cd %s && zip -r %s %s", + vim.fn.shellescape(parent_dir), + vim.fn.shellescape(zip_path), + vim.fn.shellescape(name) + ) + local result = vim.fn.system(zip_cmd) + if vim.v.shell_error ~= 0 then + vim.notify("Failed to create zip file: " .. result, vim.log.levels.ERROR) + return + end + -- Copy the zip file to the system clipboard + local copy_cmd = vim.fn.has("mac") == 1 + and string.format([[osascript -e 'set the clipboard to POSIX file "%s"']], zip_path) + or string.format([[echo -n %s | xclip -selection clipboard]], zip_path) + local copy_result = vim.fn.system(copy_cmd) + if vim.v.shell_error ~= 0 then + vim.notify("Failed to copy zip file to clipboard: " .. copy_result, vim.log.levels.ERROR) + return + end + vim.notify(zip_path, vim.log.levels.INFO) + vim.notify("Zipped and copied to clipboard: ", vim.log.levels.INFO) + else + vim.notify("No file or directory selected", vim.log.levels.WARN) + end + end + + local paste_from_clipboard = function() + -- vim.notify("Starting the paste operation...", vim.log.levels.INFO) + if not mini_files then + vim.notify("mini.files module not loaded.", vim.log.levels.ERROR) + return + end + local curr_entry = mini_files.get_fs_entry() -- Get the current file system entry + if not curr_entry then + vim.notify("Failed to retrieve current entry in mini.files.", vim.log.levels.ERROR) + return + end + local curr_dir = curr_entry.fs_type == "directory" and curr_entry.path + or vim.fn.fnamemodify(curr_entry.path, ":h") -- Use parent directory if entry is a file + -- vim.notify("Current directory: " .. curr_dir, vim.log.levels.INFO) + local script = [[ + tell application "System Events" + try + set theFile to the clipboard as alias + set posixPath to POSIX path of theFile + return posixPath + on error + return "error" + end try + end tell + ]] + local output = vim.fn.has("mac") == 1 and vim.fn.system("osascript -e " .. vim.fn.shellescape(script)) + or vim.fn.system("xclip -o -selection clipboard") + if vim.v.shell_error ~= 0 or output:find("error") then + vim.notify("Clipboard does not contain a valid file or directory.", vim.log.levels.WARN) + return + end + local source_path = output:gsub("%s+$", "") -- Trim whitespace from clipboard output + if source_path == "" then + vim.notify("Clipboard is empty or invalid.", vim.log.levels.WARN) + return + end + local dest_path = curr_dir .. "/" .. vim.fn.fnamemodify(source_path, ":t") -- Destination path in current directory + local copy_cmd = vim.fn.isdirectory(source_path) == 1 and { "cp", "-R", source_path, dest_path } + or { "cp", source_path, dest_path } -- Construct copy command + local result = vim.fn.system(copy_cmd) -- Execute the copy command + if vim.v.shell_error ~= 0 then + vim.notify("Paste operation failed: " .. result, vim.log.levels.ERROR) + return + end + -- vim.notify("Pasted " .. source_path .. " to " .. dest_path, vim.log.levels.INFO) + mini_files.synchronize() -- Refresh mini.files to show updated directory content + vim.notify("Pasted successfully.", vim.log.levels.INFO) + end + + local copy_path_to_clipboard = function() + -- Get the current entry (file or directory) + local curr_entry = mini_files.get_fs_entry() + if curr_entry then + -- Convert path to be relative to home directory + local home_dir = vim.fn.expand("~") + local relative_path = curr_entry.path:gsub("^" .. home_dir, "~") + vim.fn.setreg("+", relative_path) -- Copy the relative path to the clipboard register + vim.notify(vim.fn.fnamemodify(relative_path, ":t"), vim.log.levels.INFO) + vim.notify("Path copied to clipboard: ", vim.log.levels.INFO) + else + vim.notify("No file or directory selected", vim.log.levels.WARN) + end + end + + local preview_image = function() + local curr_entry = mini_files.get_fs_entry() + if curr_entry then + -- Preview the file using Quick Look + if vim.fn.has("mac") == 1 then + vim.system({ "qlmanage", "-p", curr_entry.path }, { + stdout = false, + stderr = false, + }) + vim.defer_fn(function() + vim.system({ "osascript", "-e", 'tell application "qlmanage" to activate' }) + end, 200) + else + -- TODO: add previewer for linux + vim.notify("Preview not supported on Linux.", vim.log.levels.WARN) + end + else + vim.notify("No file selected", vim.log.levels.WARN) + end + end + + local preview_image_popup = function() + -- Clear any existing images before rendering the new one + require("image").clear() + local curr_entry = mini_files.get_fs_entry() + if curr_entry and curr_entry.fs_type == "file" then + local ext = vim.fn.fnamemodify(curr_entry.path, ":e"):lower() + local supported_image_exts = { "png", "jpg", "jpeg", "gif", "bmp", "webp", "avif" } + -- Check if the file has a supported image extension + if vim.tbl_contains(supported_image_exts, ext) then + -- Save mini.files state (current path and focused entry) + local current_dir = vim.fn.fnamemodify(curr_entry.path, ":h") + local focused_entry = vim.fn.fnamemodify(curr_entry.path, ":t") -- Extract filename + -- Create a floating window for the image preview + local popup_width = math.floor(vim.o.columns * 0.6) + local popup_height = math.floor(vim.o.lines * 0.6) + local col = math.floor((vim.o.columns - popup_width) / 2) + local row = math.floor((vim.o.lines - popup_height) / 2) + local buf = vim.api.nvim_create_buf(false, true) -- Create a scratch buffer + local win = vim.api.nvim_open_win(buf, true, { + relative = "editor", + row = row, + col = col, + width = popup_width, + height = popup_height, + style = "minimal", + border = "rounded", + }) + -- Declare img_width and img_height at the top + local img_width, img_height + -- Get image dimensions using ImageMagick's identify command + local dimensions = vim.fn.systemlist( + string.format("identify -format '%%w %%h' %s", vim.fn.shellescape(curr_entry.path)) + ) + if #dimensions > 0 then + img_width, img_height = dimensions[1]:match("(%d+) (%d+)") + img_width = tonumber(img_width) + img_height = tonumber(img_height) + end + -- Calculate image display size while maintaining aspect ratio + local display_width = popup_width + local display_height = popup_height + if img_width and img_height then + local aspect_ratio = img_width / img_height + if aspect_ratio > (popup_width / popup_height) then + -- Image is wider than the popup window + display_height = math.floor(popup_width / aspect_ratio) + else + -- Image is taller than the popup window + display_width = math.floor(popup_height * aspect_ratio) + end + end + -- Center the image within the popup window + local image_x = math.floor((popup_width - display_width) / 2) + local image_y = math.floor((popup_height - display_height) / 2) + -- Use image.nvim to render the image + local img = require("image").from_file(curr_entry.path, { + id = curr_entry.path, -- Unique ID + window = win, -- Bind the image to the popup window + buffer = buf, -- Bind the image to the popup buffer + x = image_x, + y = image_y, + width = display_width, + height = display_height, + with_virtual_padding = true, + }) + -- Render the image + if img ~= nil then + img:render() + end + -- Use `stat` or `ls` to get the file size in bytes + local file_size_bytes = "" + if vim.fn.has("mac") == 1 or vim.fn.has("unix") == 1 then + -- For macOS or Linux systems + local handle = io.popen( + "stat -f%z " + .. vim.fn.shellescape(curr_entry.path) + .. " || ls -l " + .. vim.fn.shellescape(curr_entry.path) + .. " | awk '{print $5}'" + ) + if handle then + file_size_bytes = handle:read("*a"):gsub("%s+$", "") -- Trim trailing whitespace + handle:close() + end + else + -- Fallback message if the command isn't available + file_size_bytes = "0" + end + -- Convert the size to MB (if valid) + local file_size_mb = tonumber(file_size_bytes) and tonumber(file_size_bytes) / (1024 * 1024) + or 0 + local file_size_mb_str = string.format("%.2f", file_size_mb) -- Format to 2 decimal places as a string + -- Add image information (filename, size, resolution) + local image_info = {} + table.insert(image_info, "Image File: " .. focused_entry) -- Add only the filename + if tonumber(file_size_bytes) > 0 then + table.insert(image_info, "Size: " .. file_size_mb_str .. " MB") -- Use the formatted string + else + table.insert(image_info, "Size: Unable to detect") -- Fallback if size isn't found + end + if img_width and img_height then + table.insert(image_info, "Resolution: " .. img_width .. " x " .. img_height) + else + table.insert(image_info, "Resolution: Unable to detect") + end + -- Append the image information after the image + local line_count = vim.api.nvim_buf_line_count(buf) + vim.api.nvim_buf_set_lines(buf, line_count, -1, false, { "", "", "" }) -- Add 3 empty lines + vim.api.nvim_buf_set_lines(buf, -1, -1, false, image_info) + -- Keymap for closing the popup and reopening mini.files + local function reopen_mini_files() + if img ~= nil then + img:clear() + end + vim.api.nvim_win_close(win, true) + -- Reopen mini.files in the same directory + require("mini.files").open(current_dir, true) + vim.defer_fn(function() + -- Simulate navigation to the file by searching for the line matching the file + local lines = vim.api.nvim_buf_get_lines(0, 0, -1, false) -- Get all lines in the buffer + for i, line in ipairs(lines) do + if line:match(focused_entry) then + vim.api.nvim_win_set_cursor(0, { i, 0 }) -- Move cursor to the matching line + break + end + end + end, 50) -- Small delay to ensure mini.files is initialized + end + vim.keymap.set("n", "<esc>", reopen_mini_files, { buffer = buf, noremap = true, silent = true }) + else + vim.notify("Not an image file.", vim.log.levels.WARN) + end + else + vim.notify("No file selected or not a file.", vim.log.levels.WARN) + end + end + + local follow_symlink = function() + local curr_entry = mini_files.get_fs_entry() + if curr_entry and curr_entry.fs_type == "file" then + local resolved_path = vim.fn.resolve(curr_entry.path) -- Resolve symlink to original file + if resolved_path ~= curr_entry.path then + vim.notify("Following symlink to: " .. resolved_path, vim.log.levels.INFO) + mini_files.open(resolved_path, true) -- Open the original file in mini.files + else + vim.notify("The file is not a symlink.", vim.log.levels.WARN) + end + else + vim.notify("No file selected or not a valid file.", vim.log.levels.WARN) + end + end + + vim.api.nvim_create_autocmd("User", { + pattern = "MiniFilesBufferCreate", + callback = function() + local buf_id = vim.api.nvim_get_current_buf() + + vim.keymap.set( + "n", + opts.mappings and opts.mappings.toggle_hidden or "g.", + toggle_dotfiles, + { buffer = buf_id, desc = "Toggle hidden files" } + ) + + vim.keymap.set( + "n", + opts.mappings and opts.mappings.change_cwd or "gc", + files_set_cwd, + { buffer = buf_id, desc = "Set cwd" } + ) + + map_split(buf_id, opts.mappings and opts.mappings.go_in_horizontal or "<C-w>s", "horizontal", false) + map_split(buf_id, opts.mappings and opts.mappings.go_in_vertical or "<C-w>v", "vertical", false) + map_split( + buf_id, + opts.mappings and opts.mappings.go_in_horizontal_plus or "<C-w>S", + "horizontal", + true + ) + map_split(buf_id, opts.mappings and opts.mappings.go_in_vertical_plus or "<C-w>V", "vertical", true) + + vim.keymap.set( + "n", + "zt", + open_tmux_pane, + { buffer = buf_id, noremap = true, silent = true, desc = "Open tmux pane" } + ) + vim.keymap.set( + "n", + "zy", + copy_to_clipboard, + { buffer = buf_id, noremap = true, silent = true, desc = "Copy to clipboard" } + ) + vim.keymap.set( + "n", + "zY", + copy_path_to_clipboard, + { buffer = buf_id, desc = "Copy path to clipboard" } + ) + vim.keymap.set( + "n", + "zc", + zip_and_copy_to_clipboard, + { buffer = buf_id, noremap = true, silent = true, desc = "Zip and copy" } + ) + vim.keymap.set( + "n", + "zp", + paste_from_clipboard, + { buffer = buf_id, noremap = true, silent = true, desc = "Paste from clipboard" } + ) + vim.keymap.set( + "n", + "zi", + preview_image, + { buffer = buf_id, noremap = true, silent = true, desc = "Preview image" } + ) + vim.keymap.set( + "n", + "zI", + preview_image_popup, + { buffer = buf_id, noremap = true, silent = true, desc = "Pop-up preview image" } + ) + vim.keymap.set( + "n", + "gl", + follow_symlink, + { buffer = buf_id, noremap = true, silent = true, desc = "Follow link" } + ) + end, + }) + + -- Git status + local nsMiniFiles = vim.api.nvim_create_namespace("mini_files_git") + local autocmd = vim.api.nvim_create_autocmd + local _, MiniFiles = pcall(require, "mini.files") + + -- Cache for git status + local gitStatusCache = {} + local cacheTimeout = 2000 -- Cache timeout in milliseconds + + ---@type table<string, {symbol: string, hlGroup: string}> + ---@param status string + ---@return string symbol, string hlGroup + local function mapSymbols(status) + local statusMap = { + -- stylua: ignore start + [" M"] = { symbol = "•", hlGroup = "GitSignsChange"}, -- Modified in the working directory + ["M "] = { symbol = "✹", hlGroup = "GitSignsChange"}, -- modified in index + ["MM"] = { symbol = "≠", hlGroup = "GitSignsChange"}, -- modified in both working tree and index + ["A "] = { symbol = "+", hlGroup = "GitSignsAdd" }, -- Added to the staging area, new file + ["AA"] = { symbol = "≈", hlGroup = "GitSignsAdd" }, -- file is added in both working tree and index + ["D "] = { symbol = "-", hlGroup = "GitSignsDelete"}, -- Deleted from the staging area + ["AM"] = { symbol = "⊕", hlGroup = "GitSignsChange"}, -- added in working tree, modified in index + ["AD"] = { symbol = "-•", hlGroup = "GitSignsChange"}, -- Added in the index and deleted in the working directory + ["R "] = { symbol = "→", hlGroup = "GitSignsChange"}, -- Renamed in the index + ["U "] = { symbol = "‖", hlGroup = "GitSignsChange"}, -- Unmerged path + ["UU"] = { symbol = "⇄", hlGroup = "GitSignsAdd" }, -- file is unmerged + ["UA"] = { symbol = "⊕", hlGroup = "GitSignsAdd" }, -- file is unmerged and added in working tree + ["??"] = { symbol = "?", hlGroup = "GitSignsDelete"}, -- Untracked files + ["!!"] = { symbol = "!", hlGroup = "GitSignsChange"}, -- Ignored files + -- stylua: ignore end + } + + local result = statusMap[status] or { symbol = "?", hlGroup = "NonText" } + return result.symbol, result.hlGroup + end + + ---@param cwd string + ---@param callback function + ---@return nil + local function fetchGitStatus(cwd, callback) + local function on_exit(content) + if content.code == 0 then + callback(content.stdout) + vim.g.content = content.stdout + end + end + vim.system({ "git", "status", "--ignored", "--porcelain" }, { text = true, cwd = cwd }, on_exit) + end + + ---@param str string? + local function escapePattern(str) + return str:gsub("([%^%$%(%)%%%.%[%]%*%+%-%?])", "%%%1") + end + + ---@param buf_id integer + ---@param gitStatusMap table + ---@return nil + local function updateMiniWithGit(buf_id, gitStatusMap) + vim.schedule(function() + local nlines = vim.api.nvim_buf_line_count(buf_id) + local cwd = vim.fs.root(buf_id, ".git") + local escapedcwd = escapePattern(cwd) + if vim.fn.has("win32") == 1 then + escapedcwd = escapedcwd:gsub("\\", "/") + end + + for i = 1, nlines do + local entry = MiniFiles.get_fs_entry(buf_id, i) + if not entry then + break + end + local relativePath = entry.path:gsub("^" .. escapedcwd .. "/", "") + local status = gitStatusMap[relativePath] + + if status then + local symbol, hlGroup = mapSymbols(status) + vim.api.nvim_buf_set_extmark(buf_id, nsMiniFiles, i - 1, 0, { + -- NOTE: if you want the signs on the right uncomment those and comment + -- the 3 lines after + -- virt_text = { { symbol, hlGroup } }, + -- virt_text_pos = "right_align", + sign_text = symbol, + sign_hl_group = hlGroup, + priority = 2, + }) + else + end + end + end) + end + + -- Thanks for the idea of gettings https://github.com/refractalize/oil-git-status.nvim signs for dirs + ---@param content string + ---@return table + local function parseGitStatus(content) + local gitStatusMap = {} + -- lua match is faster than vim.split (in my experience ) + for line in content:gmatch("[^\r\n]+") do + local status, filePath = string.match(line, "^(..)%s+(.*)") + -- Split the file path into parts + local parts = {} + for part in filePath:gmatch("[^/]+") do + table.insert(parts, part) + end + -- Start with the root directory + local currentKey = "" + for i, part in ipairs(parts) do + if i > 1 then + -- Concatenate parts with a separator to create a unique key + currentKey = currentKey .. "/" .. part + else + currentKey = part + end + -- If it's the last part, it's a file, so add it with its status + if i == #parts then + gitStatusMap[currentKey] = status + else + -- If it's not the last part, it's a directory. Check if it exists, if not, add it. + if not gitStatusMap[currentKey] then + gitStatusMap[currentKey] = status + end + end + end + end + return gitStatusMap + end + + ---@param buf_id integer + ---@return nil + local function updateGitStatus(buf_id) + if not vim.fs.root(vim.uv.cwd(), ".git") then + return + end + + local cwd = vim.fn.expand("%:p:h") + local currentTime = os.time() + if gitStatusCache[cwd] and currentTime - gitStatusCache[cwd].time < cacheTimeout then + updateMiniWithGit(buf_id, gitStatusCache[cwd].statusMap) + else + fetchGitStatus(cwd, function(content) + local gitStatusMap = parseGitStatus(content) + gitStatusCache[cwd] = { + time = currentTime, + statusMap = gitStatusMap, + } + updateMiniWithGit(buf_id, gitStatusMap) + end) + end + end + + ---@return nil + local function clearCache() + gitStatusCache = {} + end + + local function augroup(name) + return vim.api.nvim_create_augroup("MiniFiles_" .. name, { clear = true }) + end + + autocmd("User", { + group = augroup("start"), + pattern = "MiniFilesExplorerOpen", + callback = function() + local bufnr = vim.api.nvim_get_current_buf() + updateGitStatus(bufnr) + end, + }) + + autocmd("User", { + group = augroup("close"), + pattern = "MiniFilesExplorerClose", + callback = function() + clearCache() + end, + }) + + autocmd("User", { + group = augroup("update"), + pattern = "MiniFilesBufferUpdate", + callback = function(sii) + local bufnr = sii.data.buf_id + local cwd = vim.fn.expand("%:p:h") + if gitStatusCache[cwd] then + updateMiniWithGit(bufnr, gitStatusCache[cwd].statusMap) + end + end, + }) + end, + }, + { + "echasnovski/mini.hipatterns", + version = false, + config = function() + local hipatterns = require("mini.hipatterns") + hipatterns.setup({ + highlighters = { + -- Highlight standalone 'FIXME', 'HACK', 'TODO', 'NOTE' + fixme = { pattern = "%f[%w]()FIXME()%f[%W]", group = "MiniHipatternsFixme" }, + hack = { pattern = "%f[%w]()HACK()%f[%W]", group = "MiniHipatternsHack" }, + todo = { pattern = "%f[%w]()TODO()%f[%W]", group = "MiniHipatternsTodo" }, + note = { pattern = "%f[%w]()NOTE()%f[%W]", group = "MiniHipatternsNote" }, + + -- Highlight hex color strings (`#rrggbb`) using that color + hex_color = hipatterns.gen_highlighter.hex_color(), + }, + }) + end, + }, + { + "echasnovski/mini.indentscope", + version = false, -- wait till new 0.7.0 release to put it back on semver + event = "VeryLazy", + opts = { + mappings = { + -- Textobjects + object_scope = "i-", + object_scope_with_border = "a-", + + -- Motions (jump to respective border line; if not present - body line) + goto_top = "g,", + goto_bottom = "g;", + }, + draw = { + animation = function() + return 0 + end, + }, + options = { try_as_border = true }, + symbol = "│", + }, + init = function() + vim.api.nvim_create_autocmd("FileType", { + pattern = { + "help", + "Trouble", + "trouble", + "lazy", + "mason", + }, + callback = function() + vim.b.miniindentscope_disable = true + end, + }) + end, + }, + { + "echasnovski/mini.map", + version = false, + config = function() + require("mini.map").setup( + -- No need to copy this inside `setup()`. Will be used automatically. + { + -- Highlight integrations (none by default) + integrations = nil, + + -- Symbols used to display data + symbols = { + -- Encode symbols. See `:h MiniMap.config` for specification and + -- `:h MiniMap.gen_encode_symbols` for pre-built ones. + -- Default: solid blocks with 3x2 resolution. + encode = nil, + + -- Scrollbar parts for view and line. Use empty string to disable any. + scroll_line = "█", + scroll_view = "┃", + }, + + -- Window options + window = { + -- Whether window is focusable in normal way (with `wincmd` or mouse) + focusable = true, + + -- Side to stick ('left' or 'right') + side = "right", + + -- Whether to show count of multiple integration highlights + show_integration_count = true, + + -- Total width + width = 10, + + -- Value of 'winblend' option + winblend = 25, + + -- Z-index + zindex = 10, + }, + } + ) + end, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>m", group = "Markdown/Map" }, + { "<leader>mt", group = "Toggle" }, + }) + end, + keys = { + { "<leader>mo", "<cmd>lua MiniMap.open()<cr>", desc = "Open map" }, + { "<leader>mr", "<cmd>lua MiniMap.refresh()<cr>", desc = "Refresh map" }, + { "<leader>mc", "<cmd>lua MiniMap.close()<cr>", desc = "Close map" }, + { "<leader>mtm", "<cmd>lua MiniMap.toggle()<cr>", desc = "Toggle map" }, + { "<leader>mts", "<cmd>lua MiniMap.toggle_side()<cr>", desc = "Toggle side map" }, + }, + }, + { + "echasnovski/mini.move", + version = false, + config = function() + -- No need to copy this inside `setup()`. Will be used automatically. + require("mini.move").setup({ + -- Module mappings. Use `''` (empty string) to disable one. + mappings = { + -- Move visual selection in Visual mode. Defaults are Alt (Meta) + hjkl. + left = "<M-m>", + right = "<M-/>", + down = "<M-,>", + up = "<M-.>", + + -- Move current line in Normal mode + line_left = "<M-m>", + line_right = "<M-/>", + line_down = "<M-,>", + line_up = "<M-.>", + }, + + -- Options which control moving behavior + options = { + -- Automatically reindent selection during linewise vertical move + reindent_linewise = true, + }, + }) + end, + }, + { + "echasnovski/mini.pairs", + version = false, + event = "VeryLazy", + config = function() + require("mini.pairs").setup() + end, + keys = { + { + "<leader>zp", + function() + vim.g.minipairs_disable = not vim.g.minipairs_disable + end, + desc = "Toggle auto pairs", + }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/navic.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/navic.lua new file mode 100644 index 0000000..89cfa81 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/navic.lua @@ -0,0 +1,52 @@ +return { + "SmiteshP/nvim-navic", + dependencies = { + "neovim/nvim-lspconfig", + }, + config = function() + require("nvim-navic").setup({ + icons = { + File = " ", + Module = " ", + Namespace = " ", + Package = " ", + Class = " ", + Method = " ", + Property = " ", + Field = " ", + Constructor = " ", + Enum = "", + Interface = "", + Function = " ", + Variable = " ", + Constant = " ", + String = " ", + Number = " ", + Boolean = "◩ ", + Array = " ", + Object = " ", + Key = " ", + Null = " ", + EnumMember = " ", + Struct = " ", + Event = " ", + Operator = " ", + TypeParameter = " ", + }, + lsp = { + auto_attach = true, + preference = nil, + }, + highlight = true, + separator = " > ", + depth_limit = 5, + depth_limit_indicator = "..", + safe_output = true, + lazy_update_context = false, + click = true, + format_text = function(text) + return text + end, + }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/obsidian.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/obsidian.lua new file mode 100644 index 0000000..ea8e893 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/obsidian.lua @@ -0,0 +1,616 @@ +return { + "epwalsh/obsidian.nvim", + version = "*", -- recommended, use latest release instead of latest commit + lazy = true, + ft = "markdown", + -- Replace the above line with this if you only want to load obsidian.nvim for markdown files in your vault: + -- event = { + -- -- If you want to use the home shortcut '~' here you need to call 'vim.fn.expand'. + -- -- E.g. "BufReadPre " .. vim.fn.expand "~" .. "/my-vault/*.md" + -- -- refer to `:h file-pattern` for more examples + -- "BufReadPre path/to/my-vault/*.md", + -- "BufNewFile path/to/my-vault/*.md", + -- }, + dependencies = { + -- Required. + "nvim-lua/plenary.nvim", + -- see below for full list of optional dependencies 👇 + "hrsh7th/nvim-cmp", + "nvim-telescope/telescope.nvim", + "nvim-treesitter/nvim-treesitter", + { + "epwalsh/pomo.nvim", + dependencies = "nvim-lualine/lualine.nvim", + config = function() + require("lualine").setup({ + sections = { + lualine_x = { + function() + local ok, pomo = pcall(require, "pomo") + if not ok then + return "" + end + + local timer = pomo.get_first_to_finish() + if timer == nil then + return "" + end + + return " " .. tostring(timer) + end, + "encoding", + "fileformat", + "filetype", + }, + }, + }) + + require("telescope").load_extension("pomodori") + + vim.keymap.set("n", "<leader>mp", function() + require("telescope").extensions.pomodori.timers() + end, { desc = "Manage pomodori" }) + end, + }, + }, + cmd = { + "ObsidianOpen", + "ObsidianNew", + "ObsidianQuickSwitch", + "ObsidianFollowLink", + "ObsidianBacklinks", + "ObsidianTags", + "ObsidianToday", + "ObsidianYesterday", + "ObsidianTomorrow", + "ObsidianDailies", + "ObsidianTemplate", + "ObsidianSearch", + "ObsidianLink", + "ObsidianLinkNew", + "ObsidianExtractNote", + "ObsidianWorkspace", + "ObsidianPasteImg", + "ObsidianRename", + "ObsidianToggleCheckbox", + "ObsidianNewFromTemplate", + "ObsidianTOC", + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>o", group = "Open/Obsidian" }, + { "<leader>of", group = "Find files (Obsidian)" }, + { "<leader>on", group = "Notes (Obsidian)" }, + { "<leader>op", group = "Paste (Obsidian)" }, + { "<leader>ot", group = "Templates (Obsidian)" }, + }) + end, + config = function() + require("obsidian").setup({ + -- A list of workspace names, paths, and configuration overrides. + -- If you use the Obsidian app, the 'path' of a workspace should generally be + -- your vault root (where the `.obsidian` folder is located). + -- When obsidian.nvim is loaded by your plugin manager, it will automatically set + -- the workspace to the first workspace in the list whose `path` is a parent of the + -- current markdown file being edited. + workspaces = { + { + name = "personal", + path = "~/Private/repos/Obsidian/SI", + -- Optional, override certain settings. + overrides = { + notes_subdir = "", + }, + }, + }, + + -- Alternatively - and for backwards compatibility - you can set 'dir' to a single path instead of + -- 'workspaces'. For example: + -- dir = "~/vaults/work", + + -- Optional, if you keep notes in a specific subdirectory of your vault. + notes_subdir = "", + + -- Optional, set the log level for obsidian.nvim. This is an integer corresponding to one of the log + -- levels defined by "vim.log.levels.*". + log_level = vim.log.levels.INFO, + + daily_notes = { + -- Optional, if you keep daily notes in a separate directory. + folder = "Area/Notes", + -- Optional, if you want to change the date format for the ID of daily notes. + date_format = "%Y-%m-%d", + -- Optional, if you want to change the date format of the default alias of daily notes. + alias_format = "%B %-d, %Y", + -- Optional, default tags to add to each new daily note created. + default_tags = { "daily-notes" }, + -- Optional, if you want to automatically insert a template from your template directory like 'daily.md' + template = nil, + }, + + -- Optional, completion of wiki links, local markdown links, and tags using nvim-cmp. + completion = { + -- Set to false to disable completion. + nvim_cmp = true, + -- Trigger completion at 2 chars. + min_chars = 2, + }, + + -- Optional, configure key mappings. These are the defaults. If you don't want to set any keymappings this + -- way then set 'mappings = {}'. + mappings = { + -- Smart action depending on context, either follow link or toggle checkbox. + ["<cr>"] = { + action = function() + return require("obsidian").util.smart_action() + end, + opts = { buffer = true, expr = true }, + }, + }, + + -- Where to put new notes. Valid options are + -- * "current_dir" - put new notes in same directory as the current buffer. + -- * "notes_subdir" - put new notes in the default notes subdirectory. + new_notes_location = "current_dir", + + -- Optional, customize how note IDs are generated given an optional title. + ---@param title string|? + ---@return string + note_id_func = function(title) + -- Create note IDs in a Zettelkasten format with a timestamp and a suffix. + -- In this case a note with the title 'My new note' will be given an ID that looks + -- like '1657296016-my-new-note', and therefore the file name '1657296016-my-new-note.md' + local suffix = "" + if title ~= nil then + -- If title is given, transform it into valid file name. + suffix = title:gsub(" ", "-"):gsub("[^A-Za-z0-9-]", ""):lower() + else + -- If title is nil, just add 4 random uppercase letters to the suffix. + for _ = 1, 4 do + suffix = suffix .. string.char(math.random(65, 90)) + end + end + return suffix + end, + + -- Optional, customize how note file names are generated given the ID, target directory, and title. + ---@param spec { id: string, dir: obsidian.Path, title: string|? } + ---@return string|obsidian.Path The full path to the new note. + note_path_func = function(spec) + -- This is equivalent to the default behavior. + local path = spec.dir / "Contents" / tostring(spec.title) + return path:with_suffix(".md") + end, + + -- Optional, customize how wiki links are formatted. You can set this to one of: + -- * "use_alias_only", e.g. '[[Foo Bar]]' + -- * "prepend_note_id", e.g. '[[foo-bar|Foo Bar]]' + -- * "prepend_note_path", e.g. '[[foo-bar.md|Foo Bar]]' + -- * "use_path_only", e.g. '[[foo-bar.md]]' + -- Or you can set it to a function that takes a table of options and returns a string, like this: + wiki_link_func = function(opts) + return require("obsidian.util").wiki_link_path_prefix(opts) + end, + + -- Optional, customize how markdown links are formatted. + markdown_link_func = function(opts) + return require("obsidian.util").markdown_link(opts) + end, + + -- Either 'wiki' or 'markdown'. + preferred_link_style = "wiki", + + -- Optional, boolean or a function that takes a filename and returns a boolean. + -- `true` indicates that you don't want obsidian.nvim to manage frontmatter. + disable_frontmatter = false, + + -- -- Optional, alternatively you can customize the frontmatter data. + -- ---@return table + -- note_frontmatter_func = function(note) + -- -- Add the title of the note as an alias. + -- if note.title then + -- note:add_alias(note.title) + -- end + -- + -- local out = { id = note.id, aliases = note.aliases, tags = note.tags } + -- + -- -- `note.metadata` contains any manually added fields in the frontmatter. + -- -- So here we just make sure those fields are kept in the frontmatter. + -- if note.metadata ~= nil and not vim.tbl_isempty(note.metadata) then + -- for k, v in pairs(note.metadata) do + -- out[k] = v + -- end + -- end + -- + -- return out + -- end, + + -- Optional, for templates (see below). + templates = { + folder = "Resource/Templates", + date_format = "%Y-%m-%d", + time_format = "%H:%M", + -- A map for custom variables, the key should be the variable and the value a function + substitutions = {}, + }, + + -- Optional, by default when you use `:ObsidianFollowLink` on a link to an external + -- URL it will be ignored but you can customize this behavior here. + ---@param url string + follow_url_func = function(url) + -- Open the URL in the default web browser. + -- vim.fn.jobstart({ "open", url }) -- Mac OS + vim.fn.jobstart({ "xdg-open", url }) -- linux + -- vim.cmd(':silent exec "!start ' .. url .. '"') -- Windows + -- vim.ui.open(url) -- need Neovim 0.10.0+ + end, + + -- Optional, by default when you use `:ObsidianFollowLink` on a link to an image + -- file it will be ignored but you can customize this behavior here. + ---@param img string + follow_img_func = function(img) + -- vim.fn.jobstart({ "qlmanage", "-p", img }) -- Mac OS quick look preview + vim.fn.jobstart({ "nsxiv", "-aiop", img }) -- linux + -- vim.cmd(':silent exec "!start ' .. url .. '"') -- Windows + end, + + -- Optional, set to true if you use the Obsidian Advanced URI plugin. + -- https://github.com/Vinzent03/obsidian-advanced-uri + use_advanced_uri = false, + + -- Optional, set to true to force ':ObsidianOpen' to bring the app to the foreground. + open_app_foreground = false, + + picker = { + -- Set your preferred picker. Can be one of 'telescope.nvim', 'fzf-lua', or 'mini.pick'. + name = "telescope.nvim", + -- Optional, configure key mappings for the picker. These are the defaults. + -- Not all pickers support all mappings. + note_mappings = { + -- Create a new note from your query. + new = "<C-x>", + -- Insert a link to the selected note. + insert_link = "<C-l>", + }, + tag_mappings = { + -- Add tag(s) to current note. + tag_note = "<C-x>", + -- Insert a tag at the current location. + insert_tag = "<C-l>", + }, + }, + + -- Optional, sort search results by "path", "modified", "accessed", or "created". + -- The recommend value is "modified" and `true` for `sort_reversed`, which means, for example, + -- that `:ObsidianQuickSwitch` will show the notes sorted by latest modified time + sort_by = "modified", + sort_reversed = true, + + -- Set the maximum number of lines to read from notes on disk when performing certain searches. + search_max_lines = 1000, + + -- Optional, determines how certain commands open notes. The valid options are: + -- 1. "current" (the default) - to always open in the current window + -- 2. "vsplit" - to open in a vertical split if there's not already a vertical split + -- 3. "hsplit" - to open in a horizontal split if there's not already a horizontal split + open_notes_in = "current", + + -- Optional, define your own callbacks to further customize behavior. + callbacks = { + -- Runs at the end of `require("obsidian").setup()`. + ---@param client obsidian.Client + post_setup = function(client) end, + + -- Runs anytime you enter the buffer for a note. + ---@param client obsidian.Client + ---@param note obsidian.Note + enter_note = function(client, note) end, + + -- Runs anytime you leave the buffer for a note. + ---@param client obsidian.Client + ---@param note obsidian.Note + leave_note = function(client, note) end, + + -- Runs right before writing the buffer for a note. + ---@param client obsidian.Client + ---@param note obsidian.Note + pre_write_note = function(client, note) end, + + -- Runs anytime the workspace is set/changed. + ---@param client obsidian.Client + ---@param workspace obsidian.Workspace + post_set_workspace = function(client, workspace) end, + }, + + -- Optional, configure additional syntax highlighting / extmarks. + -- This requires you have `conceallevel` set to 1 or 2. See `:help conceallevel` for more details. + ui = { + enable = false, -- set to false to disable all additional syntax features + update_debounce = 200, -- update delay after a text change (in milliseconds) + max_file_length = 5000, -- disable UI features for files with more than this many lines + -- Define how various check-boxes are displayed + checkboxes = { + -- NOTE: the 'char' value has to be a single character, and the highlight groups are defined below. + [" "] = { char = "", hl_group = "ObsidianTodo" }, + ["x"] = { char = "", hl_group = "ObsidianDone" }, + [">"] = { char = "", hl_group = "ObsidianRightArrow" }, + ["~"] = { char = "", hl_group = "ObsidianTilde" }, + ["!"] = { char = "", hl_group = "ObsidianImportant" }, + -- Replace the above with this if you don't have a patched font: + -- [" "] = { char = "☐", hl_group = "ObsidianTodo" }, + -- ["x"] = { char = "✔", hl_group = "ObsidianDone" }, + + -- You can also add more custom ones... + }, + -- Use bullet marks for non-checkbox lists. + bullets = { char = "•", hl_group = "ObsidianBullet" }, + external_link_icon = { char = "", hl_group = "ObsidianExtLinkIcon" }, + -- Replace the above with this if you don't have a patched font: + -- external_link_icon = { char = "", hl_group = "ObsidianExtLinkIcon" }, + reference_text = { hl_group = "ObsidianRefText" }, + highlight_text = { hl_group = "ObsidianHighlightText" }, + tags = { hl_group = "ObsidianTag" }, + block_ids = { hl_group = "ObsidianBlockID" }, + hl_groups = { + -- The options are passed directly to `vim.api.nvim_set_hl()`. See `:help nvim_set_hl`. + ObsidianTodo = { bold = true, fg = "#f78c6c" }, + ObsidianDone = { bold = true, fg = "#89ddff" }, + ObsidianRightArrow = { bold = true, fg = "#f78c6c" }, + ObsidianTilde = { bold = true, fg = "#ff5370" }, + ObsidianImportant = { bold = true, fg = "#d73128" }, + ObsidianBullet = { bold = true, fg = "#89ddff" }, + ObsidianRefText = { underline = true, fg = "#c792ea" }, + ObsidianExtLinkIcon = { fg = "#c792ea" }, + ObsidianTag = { italic = true, fg = "#89ddff" }, + ObsidianBlockID = { italic = true, fg = "#89ddff" }, + ObsidianHighlightText = { bg = "#75662e" }, + }, + }, + + -- Specify how to handle attachments. + attachments = { + -- The default folder to place images in via `:ObsidianPasteImg`. + -- If this is a relative path it will be interpreted as relative to the vault root. + -- You can always override this per image by passing a full path to the command instead of just a filename. + img_folder = "assets/imgs", -- This is the default + + -- Optional, customize the default name or prefix when pasting images via `:ObsidianPasteImg`. + ---@return string + img_name_func = function() + -- Prefix image names with timestamp. + return string.format("%s-", os.time()) + end, + + -- A function that determines the text to insert in the note when pasting an image. + -- It takes two arguments, the `obsidian.Client` and an `obsidian.Path` to the image file. + -- This is the default implementation. + ---@param client obsidian.Client + ---@param path obsidian.Path the absolute path to the image file + ---@return string + img_text_func = function(client, path) + path = client:vault_relative_path(path) or path + return string.format("", path.name, path) + end, + }, + }) + + vim.api.nvim_create_autocmd("FileType", { + pattern = "markdown", + callback = function() + vim.keymap.set("n", "gl", function() + if require("obsidian").util.cursor_on_markdown_link() then + return "<cmd>ObsidianFollowLink<cr>" + else + return "gl" + end + end, { noremap = false, expr = true, desc = "Follow link (Obsidian)" }) + end, + }) + end, + keys = { + { + "<leader>zb", + function() + return require("obsidian").util.toggle_checkbox() + end, + buffer = true, + ft = "markdown", + desc = "Toggle check box (Obsidian)", + }, + { + "<leader>ob", + function() + local query = vim.fn.input("Enter query: ") + if query and #query > 0 then + vim.cmd("ObsidianOpen " .. query) + end + end, + ft = "markdown", + desc = "Open note (Obsidian)", + }, + { + "<leader>onn", + function() + local title = vim.fn.input("Enter title: ") + if title and #title > 0 then + vim.cmd("ObsidianNew " .. title) + end + end, + ft = "markdown", + desc = "New note (Obsidian)", + }, + { + "<leader>os", + "<cmd>ObsidianQuickSwitch<cr>", + ft = "markdown", + desc = "Quick switch (Obsidian)", + }, + { + "<leader>oL", + "<cmd>ObsidianFollowLink<cr>", + ft = "markdown", + desc = "Follow link (Obsidian)", + }, + { + "<leader>oH", + "<cmd>ObsidianBacklinks<cr>", + ft = "markdown", + desc = "Back link (Obsidian)", + }, + { + "<leader>oft", + function() + local tags = vim.fn.input("Enter tag: ") + if tags and #tags > 0 then + vim.cmd("ObsidianTags " .. tags) + end + end, + ft = "markdown", + desc = "Search tag notes (Obsidian)", + }, + { + "<leader>ont", + function() + local offset = vim.fn.input("Enter offset: ") + if offset and #offset > 0 then + vim.cmd("ObsidianToday " .. offset) + else + vim.cmd("ObsidianToday") + end + end, + ft = "markdown", + desc = "Today note (Obsidian)", + }, + { + "<leader>ony", + "<cmd>ObsidianYesterday<cr>", + ft = "markdown", + desc = "Yesterday note (Obsidian)", + }, + { + "<leader>ont", + "<cmd>ObsidianTomorrow<cr>", + ft = "markdown", + desc = "Tomorrow note (Obsidian)", + }, + { + "<leader>ond", + function() + local offset = vim.fn.input("Enter offset: ") + if offset and #offset > 0 then + vim.cmd("ObsidianDailies " .. offset) + else + vim.cmd("ObsidianDailies") + end + end, + ft = "markdown", + desc = "Daily notes (Obsidian)", + }, + { + "<leader>oti", + "<cmd>ObsidianTemplate<cr>", + ft = "markdown", + desc = "Insert templates (Obsidian)", + }, + { + "<leader>ofn", + function() + local note = vim.fn.input("Enter note: ") + if note and #note > 0 then + vim.cmd("ObsidianSearch " .. note) + end + end, + ft = "markdown", + desc = "Search note (Obsidian)", + }, + { + "<leader>ow", + function() + local name = vim.fn.input("Enter name: ") + if name and #name > 0 then + vim.cmd("ObsidianWorkspace " .. name) + end + end, + ft = "markdown", + desc = "Workspace name (Obsidian)", + }, + { + "<leader>opi", + function() + local image = vim.fn.input("Enter image: ") + if image and #image > 0 then + vim.cmd("ObsidianPasteImg " .. image) + end + end, + ft = "markdown", + desc = "Paste image (Obsidian)", + }, + { + "<leader>onr", + function() + local name = vim.fn.input("Enter name: ") + if name and #name > 0 then + vim.cmd("ObsidianRename " .. name) + end + end, + ft = "markdown", + desc = "Rename note (Obsidian)", + }, + { + mode = "v", + "<leader>ol", + function() + local query = vim.fn.input("Enter query: ") + if query and #query > 0 then + vim.cmd("ObsidianLink " .. query) + else + vim.cmd("ObsidianLink") + end + end, + ft = "markdown", + desc = "Link query (Obsidian)", + }, + { + mode = "v", + "<leader>onl", + function() + local note = vim.fn.input("Enter note: ") + if note and #note > 0 then + vim.cmd("ObsidianLinkNew " .. note) + else + vim.cmd("ObsidianLinkNew") + end + end, + ft = "markdown", + desc = "New link note (Obsidian)", + }, + { + mode = "v", + "<leader>ox", + function() + local note = vim.fn.input("Enter note: ") + if note and #note > 0 then + vim.cmd("ObsidianExtractNote " .. note) + else + vim.cmd("ObsidianExtractNote") + end + end, + ft = "markdown", + desc = "New extract text (Obsidian)", + }, + { + "<leader>otn", + "<cmd>ObsidianNewFromTemplate<cr>", + ft = "markdown", + desc = "Open new note with template (Obsidian)", + }, + { + "<leader>oc", + "<cmd>ObsidianTOC<cr>", + ft = "markdown", + desc = "Open contents (Obsidian)", + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/outline.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/outline.lua new file mode 100644 index 0000000..e5b98f8 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/outline.lua @@ -0,0 +1,11 @@ +return { + "hedyhli/outline.nvim", + lazy = true, + cmd = { "Outline", "OutlineOpen" }, + keys = { -- Example mapping to toggle outline + { "<leader>zo", "<cmd>Outline<cr>", desc = "Toggle outline" }, + }, + opts = { + -- Your setup opts here + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/project.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/project.lua new file mode 100644 index 0000000..a27afd4 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/project.lua @@ -0,0 +1,12 @@ +return { + "ahmedkhalf/project.nvim", + dependencies = "nvim-telescope/telescope.nvim", + config = function() + require("project_nvim").setup() + require("telescope").load_extension("projects") + + vim.keymap.set("n", "<leader>fpj", function() + require("telescope").extensions.projects.projects() + end, { desc = "Find projects" }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/python.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/python.lua new file mode 100644 index 0000000..3e53ddb --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/python.lua @@ -0,0 +1,59 @@ +return { + -- { + -- "bps/vim-textobj-python", + -- dependencies = { "kana/vim-textobj-user" }, + -- }, + { + "nvim-neotest/neotest", + optional = true, + dependencies = { + "nvim-neotest/neotest-python", + }, + opts = { + adapters = { + ["neotest-python"] = { + -- Here you can specify the settings for the adapter, i.e. + -- runner = "pytest", + -- python = ".venv/bin/python", + }, + }, + }, + }, + { + "linux-cultist/venv-selector.nvim", + dependencies = { + "neovim/nvim-lspconfig", + "mfussenegger/nvim-dap", + "mfussenegger/nvim-dap-python", --optional + { "nvim-telescope/telescope.nvim", branch = "0.1.x", dependencies = { "nvim-lua/plenary.nvim" } }, + }, + lazy = false, + branch = "regexp", -- This is the regexp branch, use this for the new version + ft = "python", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>v", group = "Virtual envs" }, + }) + end, + config = function() + require("venv-selector").setup({ + settings = { + options = { + notify_user_on_venv_activation = true, + }, + search = { + venvs = { + command = "fd /bin/python$ ~/.local/share/venvs --full-path", + }, + }, + }, + }) + end, + keys = { + { "<leader>vs", "<cmd>VenvSelect<cr>", desc = "Select virtual env", ft = "python" }, + { "<leader>vc", "<cmd>VenvSelectCached<cr>", desc = "Select venv (cache)", ft = "python" }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/quickfix.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/quickfix.lua new file mode 100644 index 0000000..9a3998e --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/quickfix.lua @@ -0,0 +1,76 @@ +return { + { + "folke/trouble.nvim", + cmd = { "Trouble" }, + opts = { + modes = { + lsp = { + win = { position = "right" }, + }, + preview_float = { + mode = "diagnostics", + preview = { + type = "float", + relative = "editor", + border = "rounded", + title = "Preview", + title_pos = "center", + position = { 0, -2 }, + size = { width = 0.3, height = 0.3 }, + zindex = 200, + }, + }, + }, + }, + config = function(_, opts) + require("trouble").setup(opts) + end, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>x", group = "Quickfix (trouble)" }, + }) + end, + keys = { + { "<leader>xd", "<cmd>Trouble diagnostics toggle<cr>", desc = "Toggle diagnostics (Trouble)" }, + { + "<leader>xD", + "<cmd>Trouble diagnostics toggle filter.buf=0<cr>", + desc = "Toggle buffer Diagnostics (Trouble)", + }, + { "<leader>xs", "<cmd>Trouble symbols toggle<cr>", desc = "Toggle symbols (Trouble)" }, + { "<leader>xS", "<cmd>Trouble lsp toggle<cr>", desc = "Toggle LSP def/ref/... (Trouble)" }, + { "<leader>xl", "<cmd>Trouble loclist toggle<cr>", desc = "Toggle location List (Trouble)" }, + { "<leader>xq", "<cmd>Trouble qflist toggle<cr>", desc = "Toggle quickfix List (Trouble)" }, + { + "[x", + function() + if require("trouble").is_open() then + require("trouble").prev({ skip_groups = true, jump = true }) + else + local ok, err = pcall(vim.cmd.cprev) + if not ok then + vim.notify(err, vim.log.levels.ERROR) + end + end + end, + desc = "Previous quickfix (trouble)", + }, + { + "]x", + function() + if require("trouble").is_open() then + require("trouble").next({ skip_groups = true, jump = true }) + else + local ok, err = pcall(vim.cmd.cnext) + if not ok then + vim.notify(err, vim.log.levels.ERROR) + end + end + end, + desc = "Next quickfix (trouble)", + }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/refactoring.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/refactoring.lua new file mode 100644 index 0000000..9c0603c --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/refactoring.lua @@ -0,0 +1,60 @@ +return { + "ThePrimeagen/refactoring.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-treesitter/nvim-treesitter", + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v", "x" }, + { "<leader>r", group = "Compiler/Refactoring" }, + }) + end, + config = function() + require("refactoring").setup({ + prompt_func_return_type = { + c = true, + cpp = true, + cxx = true, + go = true, + h = true, + hpp = true, + java = true, + lua = true, + python = true, + }, + prompt_func_param_type = { + c = true, + cpp = true, + cxx = true, + go = true, + h = true, + hpp = true, + java = true, + lua = true, + python = true, + }, + printf_statements = {}, + print_var_statements = {}, + show_success_message = false, + }) + vim.keymap.set("x", "<leader>re", ":Refactor extract ", { desc = "Extract" }) + vim.keymap.set("x", "<leader>rf", ":Refactor extract_to_file ", { desc = "Extract to file" }) + vim.keymap.set("x", "<leader>rv", ":Refactor extract_var ", { desc = "Extract variable" }) + vim.keymap.set({ "n", "x" }, "<leader>ri", ":Refactor inline_var", { desc = "Refactor inline variable" }) + vim.keymap.set("n", "<leader>rI", ":Refactor inline_func", { desc = "Refactor inline function" }) + vim.keymap.set("n", "<leader>rb", ":Refactor extract_block", { desc = "Extract block" }) + vim.keymap.set("n", "<leader>rbf", ":Refactor extract_block_to_file", { desc = "Extract block to file" }) + -- prompt for a refactor to apply when the remap is triggered + vim.keymap.set({ "n", "x" }, "<leader>rs", function() + require("refactoring").select_refactor() + end, { desc = "Refactor selection" }) + -- Note that not all refactor support both normal and visual mode + -- load refactoring Telescope extension + require("telescope").load_extension("refactoring") + vim.keymap.set({ "n", "x" }, "<leader>rf", function() + require("telescope").extensions.refactoring.refactors() + end, { desc = "Open refactor" }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/sessions.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/sessions.lua new file mode 100644 index 0000000..c0be47b --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/sessions.lua @@ -0,0 +1,32 @@ +return { + "folke/persistence.nvim", + event = "BufReadPre", -- this will only start session saving when an actual file was opened + config = function() + require("persistence").setup({ + dir = vim.fn.stdpath("state") .. "/sessions/", -- directory where session files are saved + -- minimum number of file buffers that need to be open to save + -- Set to 0 to always save + need = 0, + branch = true, -- use git branch to save session + }) + + vim.keymap.set("n", "<leader>qs", function() + require("persistence").load() + end, { desc = "Load session" }) + + -- select a session to load + vim.keymap.set("n", "<leader>fs", function() + require("persistence").select() + end, { desc = "Find session" }) + + -- load the last session + vim.keymap.set("n", "<leader>ql", function() + require("persistence").load({ last = true }) + end, { desc = "Last session" }) + + -- stop Persistence => session won't be saved on exit + vim.keymap.set("n", "<leader>qx", function() + require("persistence").stop() + end, { desc = "Stop session" }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/silicon.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/silicon.lua new file mode 100644 index 0000000..ed63558 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/silicon.lua @@ -0,0 +1,145 @@ +return { + "michaelrommel/nvim-silicon", + lazy = true, + cmd = "Silicon", + main = "nvim-silicon", + opts = { + -- Configuration here, or leave empty to use defaults + -- disable_defaults will disable all builtin default settings apart + -- from the base arguments, that are needed to call silicon at all, see + -- mandatory_options below, also those options can be overridden + -- all of the settings could be overridden in the lua setup call, + -- but this clashes with the use of an external silicon --config=file, + -- see issue #9 + disable_defaults = false, + -- turn on debug messages + debug = false, + -- most of them could be overridden with other + -- the font settings with size and fallback font + -- Example: font = "VictorMono NF=34;Noto Emoji", + font = nil, + -- the theme to use, depends on themes available to silicon + theme = "gruvbox-dark", + -- the background color outside the rendered os window + -- (in hexcode string e.g "#076678") + background = nil, + -- a path to a background image + background_image = nil, + -- the paddings to either side + pad_horiz = 100, + pad_vert = 80, + -- whether to have the os window rendered with rounded corners + no_round_corner = false, + -- whether to put the close, minimize, maximise traffic light + -- controls on the border + no_window_controls = false, + -- whether to turn off the line numbers + no_line_number = false, + -- with which number the line numbering shall start + line_offset = 1, + -- here a function is used to return the actual source code line number + -- line_offset = function(args) + -- return args.line1 + -- end, + + -- the distance between lines of code + line_pad = 0, + -- the rendering of tab characters as so many space characters + tab_width = 4, + -- with which language the syntax highlighting shall be done, should be + -- a function that returns either a language name or an extension like "js" + -- it is set to nil, so you can override it, if you do not set it, we try the + -- filetype first, and if that fails, the extension + language = nil, + -- language = function() + -- return vim.bo.filetype + -- end, + -- language = function() + -- return vim.fn.fnamemodify( + -- vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()), + -- ":e" + -- ) + -- end, + + -- if the shadow below the os window should have be blurred + shadow_blur_radius = 16, + -- the offset of the shadow in x and y directions + shadow_offset_x = 8, + shadow_offset_y = 8, + -- the color of the shadow (in hexcode string e.g "#100808") + shadow_color = nil, + -- whether to strip of superfluous leading whitespace + gobble = true, + -- a string to pad each line with after gobbling removed larger indents, + num_separator = nil, + -- here a bar glyph is used to draw a vertial line and some space + -- num_separator = "\u{258f} ", + + -- whether to put the image onto the clipboard, may produce an error, + -- if run on WSL2 + to_clipboard = false, + -- a string or function returning a string that defines the title + -- showing in the image, only works in silicon versions greater than v0.5.1 + window_title = nil, + -- here a function is used to get the name of the current buffer + -- window_title = function() + -- return vim.fn.fnamemodify( + -- vim.api.nvim_buf_get_name(vim.api.nvim_get_current_buf()), + -- ":t" + -- ) + -- end, + + -- how to deal with the clipboard on WSL2 + -- possible values are: never, always, auto + wslclipboard = nil, + -- what to do with the temporary screenshot image file when using the Windows + -- clipboard from WSL2, possible values are: keep, delete + wslclipboardcopy = nil, + -- the silicon command, put an absolute location here, if the + -- command is not in your ${PATH} + command = "silicon", + -- a string or function that defines the path to the output image + -- output = nil, + -- here a function is used to create a file in the current directory + output = function() + local home_dir = vim.fn.expand("~") -- Get home directory + local timestamp = os.date("!%Y-%m-%d_%H-%M-%S") -- Get timestamp + local file_name = vim.fn.expand("%:t:r") -- Get the file name without extension + local file_extension = vim.fn.expand("%:e") + return home_dir .. "/" .. timestamp .. "_" .. file_name .. "_" .. file_extension .. ".png" + end, + }, + keys = { + { + mode = "v", + "<leader>sc", + function() + require("nvim-silicon").clip() + end, + desc = "Copy code screenshot to clipboard", + }, + { + mode = "v", + "<leader>sf", + function() + require("nvim-silicon").file() + end, + desc = "Save code screenshot as file", + }, + { + mode = "v", + "<leader>ss", + function() + require("nvim-silicon").shoot() + end, + desc = "Create code screenshot", + }, + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "v" }, + { "<leader>s", group = "Snapshot" }, + }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/snippets.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/snippets.lua new file mode 100644 index 0000000..eac9161 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/snippets.lua @@ -0,0 +1,72 @@ +return { + { + "L3MON4D3/LuaSnip", + version = "v2.*", + build = "make install_jsregexp", + dependencies = { + "rafamadriz/friendly-snippets", + config = function() + require("luasnip.loaders.from_vscode").lazy_load() + end, + }, + config = function() + local ls = require("luasnip") + ls.setup({ + link_children = true, + link_roots = false, + keep_roots = false, + update_events = { "TextChanged", "TextChangedI" }, + }) + local c = ls.choice_node + ls.choice_node = function(pos, choices, opts) + if opts then + opts.restore_cursor = true + else + opts = { restore_cursor = true } + end + return c(pos, choices, opts) + end + + require("luasnip.loaders.from_vscode").lazy_load({ + paths = { '"' .. vim.fn.stdpath("config") .. '/lua/thesiahxyz/snippets"' }, + }) + + vim.cmd.runtime({ args = { "lua/thesiahxyz/snippets/*.lua" }, bang = true }) -- load custom snippets + + vim.keymap.set({ "i", "x" }, "<A-L>", function() + if ls.expand_or_jumpable() then + ls.expand_or_jump() + end + end, { silent = true, desc = "Expand snippet or jump to the next snippet node" }) + + vim.keymap.set({ "i", "x" }, "<A-H>", function() + if ls.jumpable(-1) then + ls.jump(-1) + end + end, { silent = true, desc = "Previous spot in the snippet" }) + + vim.keymap.set({ "i", "x" }, "<A-l>", function() + if ls.choice_active() then + ls.change_choice(1) + end + end, { silent = true, desc = "Next snippet choice" }) + + vim.keymap.set({ "i", "x" }, "<A-h>", function() + if ls.choice_active() then + ls.change_choice(-1) + end + end, { silent = true, desc = "Previous snippet choice" }) + end, + keys = { + vim.keymap.set("i", "<tab>", function() + return require("luasnip").jumpable(1) and "<Plug>luasnip-jump-next" or "<tab>" + end, { expr = true, silent = true, desc = "Jump to next snippet" }), + vim.keymap.set("s", "<tab>", function() + require("luasnip").jump(1) + end, { desc = "Jump to next snippet" }), + vim.keymap.set({ "i", "s" }, "<s-tab>", function() + require("luasnip").jump(-1) + end, { desc = "Jump to Previous Snippet" }), + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/surround.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/surround.lua new file mode 100644 index 0000000..f3e0174 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/surround.lua @@ -0,0 +1,14 @@ +return { + "echasnovski/mini.surround", + version = "*", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "s", group = "Surround/Search & replace on line" }, + }) + end, + config = function() + require("mini.surround").setup() + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/telescope.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/telescope.lua new file mode 100644 index 0000000..ceb6872 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/telescope.lua @@ -0,0 +1,1041 @@ +local have_make = vim.fn.executable("make") == 1 +local have_cmake = vim.fn.executable("cmake") == 1 + +function vim.live_grep_from_project_git_root() + local function get_git_toplevel() + local path = vim.fn.system("git rev-parse --show-toplevel") + if vim.v.shell_error then + return nil + end + return path + end + + local opts = { cwd = get_git_toplevel() } + + require("telescope.builtin").live_grep(opts) +end + +local function find_nvim_plugin_files(prompt_bufnr) + local actions = require("telescope.actions") + local action_state = require("telescope.actions.state") + + actions.close(prompt_bufnr) + + local selection = action_state.get_selected_entry() + if selection and selection.value then + -- Construct the full path + local base_path = vim.fn.stdpath("data") + local full_path = vim.fn.resolve(base_path .. "/" .. selection.value) + + require("mini.files").open(full_path, true) + end +end + +return { + { + "nvim-telescope/telescope-file-browser.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-telescope/telescope.nvim", + }, + -- init = function() + -- vim.api.nvim_create_autocmd("VimEnter", { + -- group = vim.api.nvim_create_augroup("TelescopeFileBrowserStartDirectory", { clear = true }), + -- desc = "Start telescope-file-browser with directory", + -- once = true, + -- callback = function() + -- if package.loaded["telescope-file-browser.nvim"] then + -- return + -- else + -- local stats = vim.uv.fs_stat(vim.fn.argv(0)) + -- if stats and stats.type == "directory" then + -- require("telescope").extensions.file_browser.file_browser() + -- end + -- end + -- end, + -- }) + -- end, + config = function() + local fb_actions = require("telescope._extensions.file_browser.actions") + + require("telescope").setup({ + extensions = { + file_browser = { + path = vim.uv.cwd(), + cwd = vim.uv.cwd(), + cwd_to_path = false, + grouped = true, + files = true, + add_dirs = true, + depth = 1, + auto_depth = true, + select_buffer = true, + hidden = { file_browser = false, folder_browser = false }, + respect_gitignore = vim.fn.executable("fd") == 1, + no_ignore = true, + follow_symlinks = true, + browse_files = require("telescope._extensions.file_browser.finders").browse_files, + browse_folders = require("telescope._extensions.file_browser.finders").browse_folders, + hide_parent_dir = false, + collapse_dirs = true, + prompt_path = true, + quiet = true, + dir_icon = "", + dir_icon_hl = "Default", + display_stat = { date = true, size = true, mode = true }, + hijack_netrw = false, + use_fd = true, + git_status = true, + mappings = { + ["i"] = { + ["<C-a>"] = fb_actions.create, + ["<C-e>"] = fb_actions.create_from_prompt, + ["<C-r>"] = fb_actions.rename, + ["<C-d>"] = fb_actions.move, + ["<C-y>"] = fb_actions.copy, + ["<Del>"] = fb_actions.remove, + ["<C-o>"] = fb_actions.open, + ["<C-h>"] = fb_actions.goto_parent_dir, + ["<C-Space>"] = fb_actions.goto_home_dir, + ["<C-w>"] = fb_actions.goto_cwd, + ["<C-g>"] = fb_actions.change_cwd, + ["<C-f>"] = fb_actions.toggle_browser, + ["<C-_>"] = fb_actions.toggle_hidden, + ["<C-t>"] = fb_actions.toggle_all, + ["<bs>"] = fb_actions.backspace, + }, + ["n"] = { + ["a"] = fb_actions.create, + ["n"] = fb_actions.create_from_prompt, + ["r"] = fb_actions.rename, + ["d"] = fb_actions.move, + ["y"] = fb_actions.copy, + ["Del"] = fb_actions.remove, + ["o"] = fb_actions.open, + ["h"] = fb_actions.goto_parent_dir, + ["gh"] = fb_actions.goto_home_dir, + ["<C-w>"] = fb_actions.goto_cwd, + ["<C-g>"] = fb_actions.change_cwd, + ["f"] = fb_actions.toggle_browser, + ["/"] = fb_actions.toggle_hidden, + ["t"] = fb_actions.toggle_all, + }, + }, + results_title = vim.fn.fnamemodify(vim.uv.cwd(), ":~"), + }, + }, + }) + + require("telescope").load_extension("file_browser") + + vim.keymap.set( + "n", + "<leader>et", + ":Telescope file_browser path=%:p:h select_buffer=true<CR>", + { desc = "File browser (cwd)" } + ) + vim.keymap.set("n", "<leader>eT", ":Telescope file_browser<CR>", { desc = "File browser" }) + end, + }, + { + "nvim-telescope/telescope.nvim", + branch = "master", + dependencies = { + { "nvim-lua/plenary.nvim" }, + { + "nvim-telescope/telescope-fzf-native.nvim", + build = have_make and "make" + or "cmake -S. -Bbuild -DCMAKE_BUILD_TYPE=Release && cmake --build build --config Release && cmake --install build --prefix build", + enabled = have_make or have_cmake, + config = function() + require("telescope").load_extension("fzf") + end, + }, + { + "nvim-telescope/telescope-github.nvim", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<leader>gh", group = "gh" }, + }) + end, + config = function() + require("telescope").load_extension("gh") + vim.keymap.set({ "n", "v" }, "<leader>gi", ":Telescope gh issues ", { desc = "Find gh issues" }) + vim.keymap.set( + { "n", "v" }, + "<leader>gp", + ":Telescope gh pull_request ", + { desc = "Find gh pull request" } + ) + vim.keymap.set({ "n", "v" }, "<leader>ght", ":Telescope gh gist ", { desc = "Find gh gist" }) + vim.keymap.set({ "n", "v" }, "<leader>ghr", ":Telescope gh run ", { desc = "Find gh run" }) + end, + }, + { + "nvim-telescope/telescope-ui-select.nvim", + config = function() + require("telescope").setup({ + extensions = { + ["ui-select"] = { + require("telescope.themes").get_dropdown({ + -- even more opts + }), + + -- pseudo code / specification for writing custom displays, like the one + -- for "codeactions" + -- specific_opts = { + -- make_indexed = function(items) -> indexed_items, width, + -- [kind] = { + -- make_displayer = function(widths) -> displayer + -- make_display = function(displayer) -> function(e) + -- make_ordinal = function(e) -> string + -- }, + -- -- for example to disable the custom builtin "codeactions" display + -- do the following + -- codeactions = false, + -- } + }, + }, + }) + require("telescope").load_extension("ui-select") + end, + }, + { + "jvgrootveld/telescope-zoxide", + dependencies = { "nvim-lua/popup.nvim" }, + config = function() + require("telescope").setup({ + extensions = { + zoxide = { + prompt_title = "[ TheSiahxyz ]", + mappings = { + default = { + action = function(selection) + vim.cmd.cd(selection.path) + end, + after_action = function(selection) + print("Update to (" .. selection.z_score .. ") " .. selection.path) + end, + }, + ["<C-s>"] = { + action = require("telescope._extensions.zoxide.utils").create_basic_command( + "split" + ), + opts = { desc = "split" }, + }, + ["<C-v>"] = { + action = require("telescope._extensions.zoxide.utils").create_basic_command( + "vsplit" + ), + }, + ["<C-e>"] = { + action = require("telescope._extensions.zoxide.utils").create_basic_command( + "edit" + ), + }, + ["<C-b>"] = { + keepinsert = true, + action = function(selection) + require("telescope").extensions.file_browser.file_browser({ + cwd = selection.path, + }) + end, + }, + }, + }, + }, + }) + require("telescope").load_extension("zoxide") + + vim.keymap.set("n", "<leader>fz", function() + require("telescope").extensions.zoxide.list() + end, { desc = "Find files (zoxide)" }) + end, + }, + { + "nvim-telescope/telescope-live-grep-args.nvim", + -- This will not install any breaking changes. + -- For major updates, this must be adjusted manually. + version = "^1.0.0", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>f", group = "Find" }, + { "<leader>fl", group = "Live grep" }, + }) + end, + config = function() + local lga_actions = require("telescope-live-grep-args.actions") + local actions = require("telescope.actions") + + require("telescope").setup({ + extensions = { + live_grep_args = { + auto_quoting = true, -- enable/disable auto-quoting + -- define mappings, e.g. + mappings = { -- extend mappings + i = { + ["<C-w>"] = lga_actions.quote_prompt(), + ["<C-i>"] = lga_actions.quote_prompt({ postfix = " --iglob " }), + -- freeze the current list and start a fuzzy search in the frozen list + ["<C-space>"] = actions.to_fuzzy_refine, + }, + }, + vimgrep_arguments = { + "rg", + "--color=never", + "--no-heading", + "--with-filename", + "--line-number", + "--column", + "--smart-case", + "--follow", + "--hidden", + "--no-ignore", + }, + -- ... also accepts theme settings, for example: + -- theme = "dropdown", -- use dropdown theme + -- theme = { }, -- use own theme spec + -- layout_config = { mirror=true }, -- mirror preview pane + }, + }, + }) + require("telescope").load_extension("live_grep_args") + vim.keymap.set( + "n", + "<leader>flf", + ":lua require('telescope').extensions.live_grep_args.live_grep_args()<CR>", + { desc = "Find live grep args" } + ) + + local live_grep_args_shortcuts = require("telescope-live-grep-args.shortcuts") + vim.keymap.set( + "n", + "<leader>ss", + live_grep_args_shortcuts.grep_word_under_cursor, + { desc = "Search shortcuts (Live grep)" } + ) + + local function search_git(visual) + -- Retrieve the git root path + local handle = io.popen("git rev-parse --show-toplevel") + if not handle then + print("Error: Unable to open git handle") + return + end + + local git_root_path = handle:read("*a"):gsub("%s+", "") + handle:close() + + if not git_root_path or git_root_path == "" then + print("Error: Unable to retrieve git root path") + return + end + + local opts = { + prompt_title = visual and ("Visual-Grep in " .. git_root_path) + or ("Live-Grep in " .. git_root_path), + shorten_path = false, + cwd = git_root_path, + file_ignore_patterns = { ".git", ".png", "tags" }, + initial_mode = "insert", + selection_strategy = "reset", + theme = require("telescope.themes").get_dropdown({}), + } + + if visual then + -- Capture the selected text in visual mode + vim.cmd('normal! "vy') + local visual_selection = vim.fn.getreg("v") + opts.search = visual_selection + require("telescope.builtin").grep_string(opts) + else + require("telescope.builtin").live_grep(opts) + end + end + + vim.keymap.set("n", "<leader>flg", function() + search_git(false) + end, { remap = true, silent = false, desc = "Live grep in the git root folder" }) + + vim.keymap.set("v", "<leader>flg", function() + search_git(true) + end, { remap = true, silent = false, desc = "Grep in the git root folder" }) + -- Retrieve the current tmux session path + -- This will not change when we navigate to a different pane + local function search_tmux(visual) + local handle = io.popen("tmux display-message -p '#{session_path}'") + if not handle then + print("Error: Unable to open tmux handle") + return + end + + local tmux_session_path = handle:read("*a"):gsub("%s+", "") + handle:close() + + if not tmux_session_path or tmux_session_path == "" then + print("Error: Unable to retrieve tmux session path") + return + end + + local opts = { + prompt_title = visual and ("Visual-Grep in " .. tmux_session_path) + or ("Live-Grep in " .. tmux_session_path), + shorten_path = false, + cwd = tmux_session_path, + file_ignore_patterns = { ".git", ".png", "tags" }, + initial_mode = "insert", + selection_strategy = "reset", + theme = require("telescope.themes").get_dropdown({}), + } + + if visual then + require("telescope.builtin").grep_string(opts) + else + require("telescope.builtin").live_grep(opts) + end + end + + vim.keymap.set("n", "<leader>flt", function() + search_tmux(false) + end, { remap = true, silent = false, desc = "Live grep in the current tmux session folder" }) + + vim.keymap.set("v", "<leader>flt", function() + search_tmux(true) + end, { remap = true, silent = false, desc = "Grep string in the current tmux session folder" }) + vim.api.nvim_set_keymap( + "v", + "<leader>fls", + 'y<esc>:Telescope live_grep default_text=<c-r>0<cr> search_dirs={"$PWD"}', + { noremap = true, silent = true, desc = "Live grep default text" } + ) + vim.keymap.set("n", "<leader>f/", function() + require("telescope.builtin").current_buffer_fuzzy_find( + require("telescope.themes").get_dropdown({ + winblend = 10, + previewer = false, + relative = "editor", + }) + ) + end, { desc = "Find in current buffer" }) + end, + }, + { + "xiyaowong/telescope-emoji.nvim", + config = function() + require("telescope").setup({ + extensions = { + emoji = { + action = function(emoji) + -- argument emoji is a table. + -- {name="", value="", cagegory="", description=""} + + vim.fn.setreg("*", emoji.value) + print([[Press p or "*p to paste this emoji]] .. emoji.value) + + -- insert emoji when picked + -- vim.api.nvim_put({ emoji.value }, 'c', false, true) + end, + }, + }, + }) + require("telescope").load_extension("emoji") + end, + keys = { + { "<leader>se", ":Telescope emoji<cr>", desc = "Search emoji" }, + }, + }, + { + "ThePrimeagen/harpoon", + branch = "harpoon2", + dependencies = { "nvim-lua/plenary.nvim" }, + }, + { + "folke/trouble.nvim", + }, + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<leader>f", group = "Find" }, + { "<leader>fp", group = "Private/Public" }, + { "<leader>s", group = "Search" }, + { "<leader>sb", group = "Buffer" }, + }) + end, + config = function() + local actions = require("telescope.actions") + local actions_state = require("telescope.actions.state") + local actions_layout = require("telescope.actions.layout") + local open_with_trouble = require("trouble.sources.telescope").open + local add_to_trouble = require("trouble.sources.telescope").add + + require("telescope").setup({ + defaults = { + mappings = { + i = { + ["<C-a>"] = add_to_trouble, + ["<C-e>"] = actions.complete_tag, + ["<C-g>"] = function(prompt_bufnr) + local selection = actions_state.get_selected_entry() + local dir = vim.fn.fnamemodify(selection.path, ":p:h") + actions.close(prompt_bufnr) + -- Depending on what you want put `cd`, `lcd`, `tcd` + vim.cmd(string.format("silent lcd %s", dir)) + end, + ["<C-u>"] = actions.nop, + ["<C-d>"] = actions.nop, + ["<C-b>"] = actions.nop, + ["<C-f>"] = actions_layout.toggle_preview, + ["<C-j>"] = actions.preview_scrolling_down, + ["<C-k>"] = actions.preview_scrolling_up, + ["<C-h>"] = actions.preview_scrolling_left, + ["<C-l>"] = actions.preview_scrolling_right, + ["<C-q>"] = actions.send_to_qflist + actions.open_qflist, + ["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist, + ["<C-t>"] = open_with_trouble, + ["<C-z>"] = actions.select_horizontal, + ["<C-w>"] = { "<c-s-w>", type = "command" }, + ["<C-o><C-w>"] = actions.insert_original_cword, + ["<C-o><C-a>"] = actions.insert_original_cWORD, + ["<C-o><C-f>"] = actions.insert_original_cfile, + ["<C-o><C-l>"] = actions.insert_original_cline, + ["<M-f>"] = actions.nop, + ["<M-k>"] = actions.nop, + }, + n = { + ["q"] = actions.close, + ["<C-a>"] = add_to_trouble, + ["<C-c>"] = actions.close, + ["<C-d>"] = actions.nop, + ["<C-u>"] = actions.nop, + ["<C-f>"] = actions_layout.toggle_preview, + ["<C-b>"] = actions.nop, + ["<C-e>"] = actions.complete_tag, + ["<C-g>"] = { + function(prompt_bufnr) + local selection = actions_state.get_selected_entry() + local dir = vim.fn.fnamemodify(selection.path, ":p:h") + actions.close(prompt_bufnr) + -- Depending on what you want put `cd`, `lcd`, `tcd` + vim.cmd(string.format("silent lcd %s", dir)) + end, + opts = { desc = "Change directory" }, + }, + ["<C-j>"] = actions.preview_scrolling_down, + ["<C-k>"] = actions.preview_scrolling_up, + ["<C-h>"] = actions.preview_scrolling_left, + ["<C-l>"] = actions.preview_scrolling_right, + ["<C-q>"] = actions.send_to_qflist + actions.open_qflist, + ["<M-q>"] = actions.send_selected_to_qflist + actions.open_qflist, + ["<C-t>"] = open_with_trouble, + ["<C-z>"] = actions.select_horizontal, + ["<M-f"] = actions.nop, + ["<M-k"] = actions.nop, + }, + }, + file_ignore_patterns = { + "node_modules", + "yarn.lock", + ".git", + "^.git/", + "%/bin/zsh/", + ".sl", + "_build", + ".next", + "LICENSE", + "%lock%.json", + }, + find_command = { + "rg", + "--files", + "--follow", + "--hidden", + "--no-ignore", + "--sortr=modified", + }, + hidden = true, + path_display = { + "filename_first", + }, + git_worktrees = { + { + home = vim.env.HOME, + private = vim.env.HOME .. "/Private/repos", + public = vim.env.HOME .. "/Public/repos", + }, + }, + results_title = vim.fn.fnamemodify(vim.uv.cwd(), ":~"), + scroll_strategy = "limit", + }, + pickers = { + buffers = { + mappings = { + i = { + ["<C-x>"] = actions.delete_buffer, + }, + n = { + ["dd"] = actions.delete_buffer, + ["<C-x>"] = actions.delete_buffer, + }, + }, + }, + find_files = { + -- `hidden = true` will still show the inside of `.git/` as it's not `.gitignore`d. + find_command = { + "rg", + "--files", + "--follow", + "--hidden", + "--sortr=modified", + }, + }, + }, + }) + + -- find + vim.keymap.set({ "i", "n" }, "<C-g>", function() + require("telescope.builtin").buffers({ + sort_mru = true, + sort_lastused = true, + initial_mode = "normal", + }) + end, { desc = "Find buffer files" }) + vim.keymap.set("n", "<leader>fb", function() + require("telescope.builtin").buffers({ + sort_mru = true, + sort_lastused = true, + initial_mode = "normal", + }) + end, { desc = "Find buffer files" }) + vim.keymap.set("n", "<leader>fc", function() + require("telescope.builtin").find_files({ cwd = vim.fn.expand("~/.config") }) + end, { desc = "Find config files" }) + vim.keymap.set("n", "<leader>fd", function() + require("telescope.builtin").find_files({ cwd = vim.fn.expand("~/.dotfiles") }) + end, { desc = "Find dotfiles files" }) + vim.keymap.set("n", "<leader>ff", function() + require("telescope.builtin").find_files() + end, { desc = "Find files" }) + vim.keymap.set("n", "<leader>f<leader>", function() + local pickers = require("telescope.pickers") + local finders = require("telescope.finders") + local sorters = require("telescope.config").values.generic_sorter + local previewers = require("telescope.previewers") + local entry_display = require("telescope.pickers.entry_display") + + -- Get list of open buffers + local opened_files = {} + for _, buf in ipairs(vim.api.nvim_list_bufs()) do + if vim.api.nvim_buf_is_loaded(buf) then + local name = vim.api.nvim_buf_get_name(buf) + if name ~= "" then + opened_files[name] = true + end + end + end + + -- Create the custom picker + pickers + .new({}, { + prompt_title = "Find Files", + finder = finders.new_oneshot_job({ "fd", "--type", "f" }, { + entry_maker = function(entry) + local is_open = opened_files[vim.fn.fnamemodify(entry, ":p")] -- Match absolute paths + local displayer = entry_display.create({ + separator = " ", + items = { + { width = 1 }, -- Marker width + { remaining = true }, -- Filepath + }, + }) + + return { + value = entry, + ordinal = entry, + display = function() + return displayer({ is_open and "*" or " ", entry }) + end, + path = entry, + } + end, + }), + sorter = sorters({}), + previewer = previewers.vim_buffer_cat.new({}), + }) + :find() + end, { desc = "Find files with open markers" }) + + vim.keymap.set("n", "<leader>fF", function() + require("telescope.builtin").find_files({ + cwd = vim.fn.expand("~"), + find_command = { + "rg", + "--files", + "--follow", + "--hidden", + "--glob", + "!**/.cache/*/*/*", + "--glob", + "!**/.mozilla/*", + "--glob", + "!**/.local/lib/*/*", + "--glob", + "!**/.local/share/*/*", + "--glob", + "!**/.local/state/*/*/*/*", + "--sortr=modified", + }, + }) + end, { desc = "Find root files" }) + vim.keymap.set("n", "<leader>fk", function() + require("telescope.builtin").find_files({ + cwd = vim.fn.expand("~/.local/src/suckless/"), + find_command = { + "find", + "-maxdepth", + "2", + "-type", + "f", + "-name", + ".git", + "-prune", + "-o", + }, + }) + end, { desc = "Find suckless files" }) + vim.keymap.set("n", "<leader>fg", function() + require("telescope.builtin").git_files() + end, { desc = "Find git files" }) + vim.keymap.set("n", "<leader>fo", function() + require("telescope.builtin").oldfiles({}) + end, { desc = "Find old files" }) + vim.keymap.set("n", "<leader>fpv", function() + require("telescope.builtin").find_files({ cwd = vim.fn.expand("~/Private") }) + end, { desc = "Find private files" }) + vim.keymap.set("n", "<leader>fpb", function() + require("telescope.builtin").find_files({ cwd = vim.fn.expand("~/Public") }) + end, { desc = "Find public files" }) + vim.keymap.set("n", "<leader>fr", function() + require("telescope.builtin").find_files({ + cwd = vim.fn.expand("~/.local/bin"), + }) + end, { desc = "Find script files" }) + vim.keymap.set("n", "<leader>fv", function() + require("telescope.builtin").find_files({ + cwd = vim.fn.stdpath("config"), + find_command = { "fd", "--type", "f", "--follow", "--color", "never", "--extension", "lua" }, + }) + end, { desc = "Find neovim config files" }) + vim.keymap.set("n", "<leader>fV", function() + require("telescope.builtin").find_files({ + cwd = vim.fn.stdpath("data"), + find_command = { + "find", + "-maxdepth", + "2", + "-type", + "d", + "-iname", + ".git", + "-prune", + "-o", + }, + attach_mappings = function(_, map) + map("i", "<CR>", find_nvim_plugin_files) + map("n", "<CR>", find_nvim_plugin_files) + return true + end, + }) + end, { desc = "Find neovim plugin files" }) + -- git + vim.keymap.set("n", "<leader>gc", function() + require("telescope.builtin").git_commits() + end, { desc = "Find git commits" }) + vim.keymap.set("n", "<leader>gC", function() + require("telescope.builtin").git_bcommits() + end, { desc = "Find buffer git commits" }) + vim.keymap.set("n", "<leader>gb", function() + require("telescope.builtin").git_branches() + end, { desc = "Find branches" }) + vim.keymap.set("n", "<leader>gl", function() + require("telescope.builtin").git_bcommits_range() + end, { desc = "Find lines git commits" }) + vim.keymap.set("v", "<leader>gl", function() + require("telescope.builtin").git_bcommits_range() + end, { desc = "Find lines git commits" }) + vim.keymap.set("n", "<leader>gs", function() + require("telescope.builtin").git_status() + end, { desc = "Find git status" }) + vim.keymap.set("n", "<leader>gS", function() + require("telescope.builtin").git_stash() + end, { desc = "Find git stash" }) + -- lsp + vim.keymap.set("n", "gd", function() + require("telescope.builtin").lsp_definitions({}) + end, { desc = "Find definitions" }) + vim.keymap.set("n", "gR", function() + require("telescope.builtin").lsp_references({}) + end, { desc = "Find references" }) + -- search + vim.keymap.set("n", "<leader>cc", function() + require("telescope.builtin").colorscheme({}) + end, { desc = "Search color scheme" }) + vim.keymap.set("n", "<leader>sa", function() + require("telescope.builtin").autocommands({}) + end, { desc = "Search auto commands" }) + vim.keymap.set("n", "<leader>sbf", function() + require("telescope.builtin").current_buffer_fuzzy_find({}) + end, { desc = "Search current buffers " }) + vim.keymap.set("n", "<leader>sbt", function() + require("telescope.builtin").current_buffer_tags({}) + end, { desc = "Search current buffer tags" }) + vim.keymap.set("n", "<leader>sc", function() + require("telescope.builtin").commands({}) + end, { desc = "Search commands" }) + vim.keymap.set("n", "<leader>sC", function() + require("telescope.builtin").command_history({}) + end, { desc = "Search history" }) + vim.keymap.set("n", "<leader>sd", function() + require("telescope.builtin").diagnostics({}) + end, { desc = "Search diagonostics" }) + vim.keymap.set("n", "<leader>sg", vim.live_grep_from_project_git_root, { desc = "Live grep (git)" }) + vim.keymap.set("n", "<leader>sh", function() + require("telescope.builtin").help_tags({}) + end, { desc = "Search help tags" }) + vim.keymap.set("n", "<leader>sH", function() + require("telescope.builtin").highlights({}) + end, { desc = "Search highlights" }) + vim.keymap.set("n", "<leader>sj", function() + require("telescope.builtin").jumplist({}) + end, { desc = "Search jump list" }) + vim.keymap.set("n", "<leader>skb", function() + require("telescope.builtin").keymaps({}) + end, { desc = "Search key bindings" }) + vim.keymap.set("n", "<leader>skk", function() + local word = vim.fn.expand("<cword>") + require("telescope.builtin").grep_string({ search = word }) + end, { desc = "Search words under cursor" }) + vim.keymap.set("n", "<leader>skK", function() + local word = vim.fn.expand("<cWORD>") + require("telescope.builtin").grep_string({ search = word }) + end, { desc = "Search all words under cursor" }) + vim.keymap.set("n", "<leader>sl", function() + require("telescope.builtin").loclist({}) + end, { desc = "Search location list" }) + vim.keymap.set("n", "<leader>sm", function() + require("telescope.builtin").marks({}) + end, { desc = "Search marks" }) + vim.keymap.set("n", "<leader>sM", function() + require("telescope.builtin").man_pages({}) + end, { desc = "Search man pages" }) + vim.keymap.set("n", "<leader>so", function() + require("telescope.builtin").vim_options({}) + end, { desc = "Search vim options" }) + vim.keymap.set("n", "<leader>sq", function() + require("telescope.builtin").quickfix({}) + end, { desc = "Search quickfix list" }) + vim.keymap.set("n", "<leader>sQ", function() + require("telescope.builtin").quickfixhistory({}) + end, { desc = "Search quickfix history" }) + vim.keymap.set("n", "<leader>sr", function() + require("telescope.builtin").registers({}) + end, { desc = "Search registers" }) + vim.keymap.set("n", "<leader>sR", function() + require("telescope.builtin").resume({}) + end, { desc = "Search resume" }) + vim.keymap.set("n", "<leader>st", function() + require("telescope.builtin").filetypes({}) + end, { desc = "Search file types" }) + vim.keymap.set("n", "<leader>sw", function() + require("telescope.builtin").live_grep({}) + end, { desc = "Search word (Live grep)" }) + vim.keymap.set("n", "<leader>sW", function() + require("telescope.builtin").grep_string({}) + end, { desc = "Search word (Grep)" }) + end, + }, + { + "cljoly/telescope-repo.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-telescope/telescope.nvim", + }, + config = function() + require("telescope").setup({ + extensions = { + repo = { + list = { + fd_opts = { + "--no-ignore-vcs", + }, + file_ignore_patterns = { + "^" .. vim.env.HOME .. "/%.cache/", + "^" .. vim.env.HOME .. "/%.cargo/", + }, + }, + }, + }, + }) + + require("telescope").load_extension("repo") + end, + keys = { + { mode = "n", "<leader>fG", "<cmd>Telescope repo list<cr>", desc = "Find git files (repo)" }, + }, + }, + { + "debugloop/telescope-undo.nvim", + dependencies = { -- note how they're inverted to above example + { + "nvim-telescope/telescope.nvim", + dependencies = { "nvim-lua/plenary.nvim" }, + }, + }, + opts = { + -- don't use `defaults = { }` here, do this in the main telescope spec + extensions = { + undo = { + -- telescope-undo.nvim config, see below + }, + -- no other extensions here, they can have their own spec too + }, + }, + config = function(_, opts) + -- Calling telescope's setup from multiple specs does not hurt, it will happily merge the + -- configs for us. We won't use data, as everything is in it's own namespace (telescope + -- defaults, as well as each extension). + require("telescope").setup(opts) + require("telescope").load_extension("undo") + end, + keys = { + { -- lazy style key map + "<leader>fu", + "<cmd>Telescope undo<cr>", + desc = "Find undo history", + }, + }, + }, + { + "nvim-telescope/telescope-frecency.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-telescope/telescope.nvim", + }, + config = function() + require("telescope").setup({ + extensions = { + frecency = { + auto_validate = false, + matcher = "fuzzy", + }, + }, + }) + + require("telescope").load_extension("frecency") + + vim.keymap.set("n", "<leader>fq", function() + require("telescope").extensions.frecency.frecency({ + workspace = "CWD", + }) + end, { desc = "Find frequency files" }) + + vim.keymap.set("n", "<leader>flq", function() + local frecency = require("telescope").extensions.frecency + require("telescope.builtin").live_grep({ + search_dirs = frecency.query({}), + }) + end, { desc = "Find frequency live grep" }) + + vim.keymap.set("n", "<leader>qd", "<cmd>FrecencyDelete<cr>", { desc = "Delete current buffer frequency" }) + end, + }, + { + "nvim-telescope/telescope-media-files.nvim", + dependencies = { + "nvim-lua/popup.nvim", + "nvim-lua/plenary.nvim", + "nvim-telescope/telescope.nvim", + }, + config = function() + require("telescope").setup({ + extensions = { + media_files = { + -- filetypes whitelist + -- defaults to {"png", "jpg", "mp4", "webm", "pdf"} + filetypes = { "png", "jpg", "mp4", "mkv", "webm", "pdf" }, + -- find command (defaults to `fd`) + find_cmd = "rg", + }, + }, + }) + require("telescope").load_extension("media_files") + end, + keys = { + { + "<leader>fm", + "<cmd>Telescope media_files<cr>", + desc = "Find media files", + }, + }, + }, + { + "nvim-telescope/telescope-project.nvim", + dependencies = { + "nvim-telescope/telescope.nvim", + "nvim-telescope/telescope-file-browser.nvim", + }, + config = function() + local project_actions = require("telescope._extensions.project.actions") + require("telescope").setup({ + extensions = { + project = { + base_dirs = { + { path = "~/Private", max_depth = 2 }, + { path = "~/Public", max_depth = 2 }, + }, + mappings = { + i = { + ["<C-x>"] = project_actions.delete_project, + ["<C-r>"] = project_actions.rename_project, + ["<C-a>"] = project_actions.add_project, + ["<C-A>"] = project_actions.add_project_cwd, + ["<C-f>"] = project_actions.find_project_files, + ["<C-b>"] = project_actions.browse_project_files, + ["<C-s>"] = project_actions.search_in_project_files, + ["<C-o>"] = project_actions.recent_project_files, + ["<C-g>"] = project_actions.change_working_directory, + ["<C-l>"] = project_actions.next_cd_scope, + ["<C-w>"] = project_actions.change_workspace, + }, + n = { + ["x"] = project_actions.delete_project, + ["r"] = project_actions.rename_project, + ["c"] = project_actions.add_project, + ["C"] = project_actions.add_project_cwd, + ["f"] = project_actions.find_project_files, + ["b"] = project_actions.browse_project_files, + ["s"] = project_actions.search_in_project_files, + ["o"] = project_actions.recent_project_files, + ["g"] = project_actions.change_working_directory, + ["l"] = project_actions.next_cd_scope, + }, + }, + }, + }, + }) + require("telescope").load_extension("project") + end, + keys = { + { + "<leader>fpj", + "<cmd>Telescope projects<cr>", + desc = "Find projects", + }, + }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/textobject.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/textobject.lua new file mode 100644 index 0000000..3002fc0 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/textobject.lua @@ -0,0 +1,140 @@ +return { + "nvim-treesitter/nvim-treesitter-textobjects", + dependencies = { + { "nvim-treesitter", build = ":TSUpdate" }, + { "nvim-treesitter/nvim-treesitter" }, + { + "chrisgrieser/nvim-various-textobjs", + event = "UIEnter", + opts = { + keymaps = { + useDefaults = true, + }, + }, + }, + }, + init = function() + local wk = require("which-key") + wk.add({ + { + mode = { "n", "v", "x" }, + { "g>", group = "Swap next" }, + { "g<", group = "Swap prev" }, + { "<leader>]", group = "Next" }, + { "<leader>[", group = "Prev" }, + }, + }) + end, + config = function() + require("nvim-treesitter.configs").setup({ + textobjects = { + select = { + enable = true, + + -- Automatically jump forward to textobj, similar to targets.vim + lookahead = true, + + keymaps = { + -- You can use the capture groups defined in textobjects.scm + ["a="] = { query = "@assignment.outer", desc = "Select outer part of an assignment" }, + ["i="] = { query = "@assignment.inner", desc = "Select inner part of an assignment" }, + ["h="] = { query = "@assignment.lhs", desc = "Select left hand side of an assignment" }, + ["l="] = { query = "@assignment.rhs", desc = "Select right hand side of an assignment" }, + + -- works for javascript/typescript files (custom capture I created in after/queries/ecma/textobjects.scm) + ["a:"] = { query = "@property.outer", desc = "Select outer part of an object property" }, + ["i:"] = { query = "@property.inner", desc = "Select inner part of an object property" }, + ["h:"] = { query = "@property.lhs", desc = "Select left part of an object property" }, + ["l:"] = { query = "@property.rhs", desc = "Select right part of an object property" }, + + ["aa"] = { query = "@parameter.outer", desc = "Select outer part of a parameter/argument" }, + ["ia"] = { query = "@parameter.inner", desc = "Select inner part of a parameter/argument" }, + + ["an"] = { query = "@conditional.outer", desc = "Select outer part of a conditional" }, + ["in"] = { query = "@conditional.inner", desc = "Select inner part of a conditional" }, + + ["ap"] = { query = "@loop.outer", desc = "Select outer part of a loop" }, + ["ip"] = { query = "@loop.inner", desc = "Select inner part of a loop" }, + + ["af"] = { query = "@call.outer", desc = "Select outer part of a function call" }, + ["if"] = { query = "@call.inner", desc = "Select inner part of a function call" }, + + ["am"] = { + query = "@function.outer", + desc = "Select outer part of a method/function definition", + }, + ["im"] = { + query = "@function.inner", + desc = "Select inner part of a method/function definition", + }, + + ["ac"] = { query = "@class.outer", desc = "Select outer part of a class" }, + ["ic"] = { query = "@class.inner", desc = "Select inner part of a class" }, + }, + }, + swap = { + enable = true, + swap_next = { + ["g>a"] = { query = "@parameter.inner", desc = "swap parameters/argument with next" }, + ["g>:"] = { query = "@property.outer", desc = "swap object property with next" }, + ["g>m"] = { query = "@function.outer", desc = "swap function with next" }, + }, + swap_previous = { + ["g<a"] = { query = "@parameter.inner", desc = "swap parameters/argument with prev" }, + ["g<:"] = { query = "@property.outer", desc = "swap object property with prev" }, + ["g<m"] = { query = "@function.outer", desc = "swap function with previous" }, + }, + }, + move = { + enable = true, + set_jumps = true, -- whether to set jumps in the jumplist + goto_next_start = { + ["]f"] = { query = "@call.outer", desc = "Next function call start" }, + ["]m"] = { query = "@function.outer", desc = "Next method/function def start" }, + ["]c"] = { query = "@class.outer", desc = "Next class start" }, + ["]="] = { query = "@conditional.outer", desc = "Next conditional start" }, + ["]l"] = { query = "@loop.outer", desc = "Next loop start" }, + + -- You can pass a query group to use query from `queries/<lang>/<query_group>.scm file in your runtime path. + -- Below example nvim-treesitter's `locals.scm` and `folds.scm`. They also provide highlights.scm and indent.scm. + ["]-"] = { query = "@scope", query_group = "locals", desc = "Next scope" }, + ["]z"] = { query = "@fold", query_group = "folds", desc = "Next fold" }, + }, + goto_next_end = { + ["]F"] = { query = "@call.outer", desc = "Next function call end" }, + ["]M"] = { query = "@function.outer", desc = "Next method/function def end" }, + ["]C"] = { query = "@class.outer", desc = "Next class end" }, + ["]+"] = { query = "@conditional.outer", desc = "Next conditional end" }, + ["]L"] = { query = "@loop.outer", desc = "Next loop end" }, + }, + goto_previous_start = { + ["[f"] = { query = "@call.outer", desc = "Prev function call start" }, + ["[m"] = { query = "@function.outer", desc = "Prev method/function def start" }, + ["[c"] = { query = "@class.outer", desc = "Prev class start" }, + ["[="] = { query = "@conditional.outer", desc = "Prev conditional start" }, + ["[l"] = { query = "@loop.outer", desc = "Prev loop start" }, + }, + goto_previous_end = { + ["[F"] = { query = "@call.outer", desc = "Prev function call end" }, + ["[M"] = { query = "@function.outer", desc = "Prev method/function def end" }, + ["[C"] = { query = "@class.outer", desc = "Prev class end" }, + ["[+"] = { query = "@conditional.outer", desc = "Prev conditional end" }, + ["[L"] = { query = "@loop.outer", desc = "Prev loop end" }, + }, + }, + }, + }) + + local ts_repeat_move = require("nvim-treesitter.textobjects.repeatable_move") + + -- vim way: ; goes to the direction you were moving. + vim.keymap.set({ "n", "x", "o" }, ";", ts_repeat_move.repeat_last_move) + vim.keymap.set({ "n", "x", "o" }, ",", ts_repeat_move.repeat_last_move_opposite) + + -- Optionally, make builtin f, F, t, T also repeatable with ; and , + vim.keymap.set({ "n", "x", "o" }, "f", ts_repeat_move.builtin_f_expr, { expr = true }) + vim.keymap.set({ "n", "x", "o" }, "F", ts_repeat_move.builtin_F_expr, { expr = true }) + vim.keymap.set({ "n", "x", "o" }, "t", ts_repeat_move.builtin_t_expr, { expr = true }) + vim.keymap.set({ "n", "x", "o" }, "T", ts_repeat_move.builtin_T_expr, { expr = true }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/treesitter.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/treesitter.lua new file mode 100644 index 0000000..c486343 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/treesitter.lua @@ -0,0 +1,62 @@ +return { + "nvim-treesitter/nvim-treesitter", + build = ":TSUpdate", + dependencies = { "nvim-treesitter/nvim-treesitter-textobjects" }, + config = function() + require("nvim-treesitter.configs").setup({ + -- A list of parser names, or "all" + ensure_installed = { + "bash", + "c", + "cpp", + "dockerfile", + "html", + "java", + "json5", + "latex", + "lua", + "markdown", + "markdown_inline", + "python", + "sql", + "vim", + "vimdoc", + }, + + -- Install parsers synchronously (only applied to `ensure_installed`) + sync_install = true, + + -- Automatically install missing parsers when entering buffer + -- Recommendation: set to false if you don"t have `tree-sitter` CLI installed locally + auto_install = true, + + -- List of parsers to ignore installing (or "all") + ignore_install = {}, + + highlight = { + -- `false` will disable the whole extension + enable = true, + disable = { "csv" }, + -- Setting this to true will run `:h syntax` and tree-sitter at the same time. + -- Set this to `true` if you depend on "syntax" being enabled (like for indentation). + -- Using this option may slow down your editor, and you may see some duplicate highlights. + -- Instead of true it can also be a list of languages + additional_vim_regex_highlighting = { "markdown" }, + }, + }) + + local treesitter_parser_config = require("nvim-treesitter.parsers").get_parser_configs() + treesitter_parser_config.templ = { + install_info = { + url = "https://github.com/vrischmann/tree-sitter-templ.git", + files = { "src/parser.c", "src/scanner.c" }, + branch = "master", + }, + } + + vim.treesitter.language.register("templ", "templ") + end, + keys = { + { "<leader>T", ":TSUpdate<cr>", desc = "Update treesitter" }, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/ufo.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/ufo.lua new file mode 100644 index 0000000..acce8d0 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/ufo.lua @@ -0,0 +1,56 @@ +return { + "kevinhwang91/nvim-ufo", + dependencies = { + "kevinhwang91/promise-async", + }, + config = function() + vim.o.foldcolumn = "0" -- '0' is not bad + vim.o.foldlevel = 99 -- Using ufo provider need a large value, feel free to decrease the value + vim.o.foldlevelstart = 99 + vim.o.foldenable = true + + -- Using ufo provider need remap `zR` and `zM`. If Neovim is 0.6.1, remap yourself + vim.keymap.set("n", "zR", require("ufo").openAllFolds) + vim.keymap.set("n", "zM", require("ufo").closeAllFolds) + + -- Option 1: coc.nvim as LSP client + -- { "neoclide/coc.nvim", branch = "master", run = "yarn install --frozen-lockfile" } + -- require("ufo").setup() + + -- Option 2: nvim lsp as LSP client + -- Tell the server the capability of foldingRange, + -- Neovim hasn't added foldingRange to default capabilities, users must add it manually + local capabilities = vim.lsp.protocol.make_client_capabilities() + capabilities.textDocument.foldingRange = { + dynamicRegistration = false, + lineFoldingOnly = true, + } + local language_servers = require("lspconfig").util._available_servers() -- or list servers manually like {'gopls', 'clangd'} + for _, ls in ipairs(language_servers) do + require("lspconfig")[ls].setup({ + capabilities = capabilities, + -- you can add other fields for setting up lsp server in this table + }) + end + require("ufo").setup() + + -- Option 3: treesitter as a main provider instead + -- (Note: the `nvim-treesitter` plugin is *not* needed.) + -- ufo uses the same query files for folding (queries/<lang>/folds.scm) + -- performance and stability are better than `foldmethod=nvim_treesitter#foldexpr()` + -- require("ufo").setup({ + -- provider_selector = function(bufnr, filetype, buftype) + -- return { "treesitter", "indent" } + -- end, + -- }) + -- + + -- Option 4: disable all providers for all buffers + -- Not recommend, AFAIK, the ufo's providers are the best performance in Neovim + -- require("ufo").setup({ + -- provider_selector = function(bufnr, filetype, buftype) + -- return "" + -- end, + -- }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/urlview.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/urlview.lua new file mode 100644 index 0000000..c1a7108 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/urlview.lua @@ -0,0 +1,103 @@ +return { + "axieax/urlview.nvim", + dependencies = "nvim-telescope/telescope.nvim", + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n", "v" }, + { "<leader>u", group = "URLs" }, + { "<leader>uc", group = "Copy URLs" }, + }) + end, + config = function() + -- Load urlview + require("urlview").setup({}) + + -- Define custom search for thesiah_urls + local thesiah = require("urlview.search") + thesiah["thesiah_urls"] = function() + local urls = {} + local files = { + vim.fn.expand("~/.local/share/thesiah/urls"), + vim.fn.expand("~/.local/share/thesiah/snippets"), + } + + -- Check if the file exists and read each file + for _, filepath in ipairs(files) do + if vim.fn.filereadable(filepath) == 1 then + local file = io.open(filepath, "r") + if file then + for line in file:lines() do + -- Match and capture URLs + for url in line:gmatch("https?://[%w%./%-_%%]+") do + table.insert(urls, url) + end + end + file:close() + else + vim.notify("Unable to open " .. filepath, vim.log.levels.ERROR) + end + else + vim.notify("File not found: " .. filepath, vim.log.levels.WARN) + end + end + + return urls + end + + local search = require("urlview.search") + local search_helpers = require("urlview.search.helpers") + + -- Custom search function for Tmux plugins + search["tmux_plugins"] = function() + local urls = {} + local filepath = vim.fn.expand("~/.config/tmux/tmux.conf") + + -- Check if the tmux.conf file exists + if vim.fn.filereadable(filepath) == 1 then + local file = io.open(filepath, "r") + if file then + for line in file:lines() do + -- Match lines that contain Tmux plugin URLs (TPM syntax) + -- Example: set -g @plugin 'tmux-plugins/tpm' + local url = line:match("@plugin%s+'([^']+)'") + if url then + -- Convert to full GitHub URL if not already a full URL + if not url:match("^https?://") then + url = "https://github.com/" .. url + end + table.insert(urls, url) + end + end + file:close() + else + vim.notify("Unable to open " .. filepath, vim.log.levels.ERROR) + end + else + vim.notify("File not found: " .. filepath, vim.log.levels.WARN) + end + + return urls + end + + -- Add a keymap for the Tmux plugins search context + vim.keymap.set("n", "<leader>ub", "<cmd>UrlView thesiah_urls<cr>", { desc = "Bookmarks URLs" }) + vim.keymap.set("n", "<leader>ul", "<cmd>UrlView lazy<cr>", { desc = "Lazy plugin URLs" }) + vim.keymap.set("n", "<leader>ur", "<cmd>UrlView<cr>", { desc = "Buffer URLs" }) + vim.keymap.set("n", "<leader>ut", "<cmd>UrlView tmux_plugins<cr>", { desc = "Tmux plugin URLs" }) + vim.keymap.set( + "n", + "<leader>ucb", + "<cmd>UrlView thesiah_urls action=clipboard<cr>", + { desc = "clipboard bookmarks URLs" } + ) + vim.keymap.set("n", "<leader>ucl", "<cmd>UrlView lazy action=clipboard<cr>", { desc = "Copy Lazy plugin URLs" }) + vim.keymap.set("n", "<leader>ucr", "<cmd>UrlView action=clipboard<cr>", { desc = "Copy buffer URLs" }) + vim.keymap.set( + "n", + "<leader>uct", + "<cmd>UrlView tmux_plugins action=clipboard<cr>", + { desc = "clipboard tmux plugin URLs" } + ) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/vimwiki.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/vimwiki.lua new file mode 100644 index 0000000..73ed91c --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/vimwiki.lua @@ -0,0 +1,64 @@ +return { + { + "vimwiki/vimwiki", + cmd = { + "VimwikiIndex", + "VimwikiDeleteFile", + "Vimwiki2HTML", + "VimwikiAll2HTML", + "Vimwiki2HTMLBrowse", + "VimwikiGoto", + "VimwikiRenameFile", + "VimwikiSplitLink", + "VimwikiVSplitLink", + "VimwikiColorize", + "VimwikiDiaryGenerateLinks", + }, + init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "<leader>w", group = "Vimwiki" }, + { "<leader>w<leader>", group = "Diary" }, + }) + end, + config = function() + -- Ensure files are read with the desired filetype + vim.g.vimwiki_ext2syntax = { + [".Rmd"] = "markdown", + [".rmd"] = "markdown", + [".md"] = "markdown", + [".markdown"] = "markdown", + [".mdown"] = "markdown", + } + -- Set up Vimwiki list + vim.g.vimwiki_list = { + { + path = vim.fn.expand("~/.local/share/vimwiki"), + syntax = "markdown", + ext = ".md", + }, + } + end, + keys = { + { "<leader>ww", ":VimwikiIndex<CR>", desc = "Vimwiki index" }, + }, + }, + { + "tools-life/taskwiki", + cmd = { "TaskWikiInfo", "TaskWikiSummary", "TaskWikiStart", "TaskWikiMod" }, + dependencies = { + "vimwiki/vimwiki", + "powerman/vim-plugin-AnsiEsc", + "majutsushi/tagbar", + "farseer90718/vim-taskwarrior", + }, + config = function() + require("taskwiki").setup() + vim.keymap.set("n", "<leader>tvi", ":TaskWikiInfo<CR>", { desc = "Task wiki info" }) + vim.keymap.set("n", "<leader>tvS", ":TaskWikiSummary<CR>", { desc = "Task wiki summary" }) + vim.keymap.set("n", "<leader>tvm", ":TaskWikiMod<CR>", { desc = "Task wiki modify" }) + vim.keymap.set("n", "<leader>tvs", ":TaskWikiMod<CR>", { desc = "Task wiki modify" }) + end, + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/zenmode.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/zenmode.lua new file mode 100644 index 0000000..beb48f5 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/plugins/zenmode.lua @@ -0,0 +1,46 @@ +return { + "folke/zen-mode.nvim", + opts = {}, + config = function() + vim.keymap.set("n", "<leader>zz", function() + require("zen-mode").toggle({ + -- callback where you can add custom code when the Zen window opens + on_open = function() + vim.wo.wrap = true + vim.wo.number = true + vim.wo.rnu = true + end, + -- callback where you can add custom code when the Zen window closes + on_close = function() + vim.wo.wrap = false + vim.wo.number = true + vim.wo.rnu = true + ColorMyPencils() + end, + }) + end, { desc = "Toggle zenmode" }) + + vim.keymap.set("n", "<leader>zZ", function() + require("zen-mode").toggle({ + window = { + width = 90, + }, + -- callback where you can add custom code when the Zen window opens + on_open = function() + vim.wo.wrap = true + vim.wo.number = false + vim.wo.rnu = false + vim.opt.colorcolumn = "0" + ColorMyPencils("seoul256") + end, + -- callback where you can add custom code when the Zen window closes + on_close = function() + vim.wo.wrap = false + vim.wo.number = true + vim.wo.rnu = true + ColorMyPencils() + end, + }) + end, { desc = "Toggle zenmode (custom)" }) + end, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/markdown.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/markdown.lua new file mode 100644 index 0000000..7d91fab --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/markdown.lua @@ -0,0 +1,187 @@ +local ls = require("luasnip") + +local s = ls.snippet +local t = ls.text_node +local i = ls.insert_node +local f = ls.function_node + +local function clipboard() + return vim.fn.getreg("+") +end + +-- ##################################################################### +-- Markdown +-- ##################################################################### + +-- Helper function to create code block snippets +local function create_code_block_snippet(lang) + return s(lang, { + t({ "```" .. lang, "" }), + i(1), + t({ "", "```" }), + }) +end + +-- Define languages for code blocks +local languages = { + "txt", + "lua", + "sql", + "go", + "regex", + "bash", + "markdown", + "markdown_inline", + "yaml", + "json", + "jsonc", + "cpp", + "csv", + "java", + "javascript", + "python", + "dockerfile", + "html", + "css", + "templ", + "php", +} + +-- Generate snippets for all languages +local snippets = {} + +for _, lang in ipairs(languages) do + table.insert(snippets, create_code_block_snippet(lang)) +end + +table.insert( + snippets, + s({ + trig = "chirpy", + name = "Disable markdownlint and prettier for chirpy", + }, { + t({ + " ", + "<!-- markdownlint-disable -->", + "<!-- prettier-ignore-start -->", + " ", + "<!-- tip=green, info=blue, warning=yellow, danger=red -->", + " ", + "> ", + }), + i(1), + t({ + "", + "{: .prompt-", + }), + -- In case you want to add a default value "tip" here, but I'm having + -- issues with autosave + -- i(2, "tip"), + i(2), + t({ + " }", + " ", + "<!-- prettier-ignore-end -->", + "<!-- markdownlint-restore -->", + }), + }) +) + +table.insert( + snippets, + s({ + trig = "markdownlint", + name = "Add markdownlint disable and restore headings", + }, { + t({ + " ", + "<!-- markdownlint-disable -->", + " ", + "> ", + }), + i(1), + t({ + " ", + " ", + "<!-- markdownlint-restore -->", + }), + }) +) + +table.insert( + snippets, + s({ + trig = "prettierignore", + name = "Add prettier ignore start and end headings", + }, { + t({ + " ", + "<!-- prettier-ignore-start -->", + " ", + "> ", + }), + i(1), + t({ + " ", + " ", + "<!-- prettier-ignore-end -->", + }), + }) +) + +table.insert( + snippets, + s({ + trig = "link", + name = "Add this -> []()", + }, { + t("["), + i(1), + t("]("), + i(2), + t(")"), + }) +) + +table.insert( + snippets, + s({ + trig = "linkt", + name = 'Add this -> [](){:target="_blank"}', + }, { + t("["), + i(1), + t("]("), + i(2), + t('){:target="_blank"}'), + }) +) + +table.insert( + snippets, + s({ + trig = "todo", + name = "Add TODO: item", + }, { + t("<!-- TODO: "), + i(1), + t(" -->"), + }) +) + +-- Paste clipboard contents in link section, move cursor to () +table.insert( + snippets, + s({ + trig = "linkclip", + name = "Paste clipboard as .md link", + }, { + t("["), + i(1), + t("]("), + f(clipboard, {}), + t(")"), + }) +) + +ls.add_snippets("markdown", snippets) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/neetcode1.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/neetcode1.lua new file mode 100644 index 0000000..85da742 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/neetcode1.lua @@ -0,0 +1,103 @@ +local ls = require("luasnip") +local s = ls.snippet +local i = ls.insert_node +local fmt = require("luasnip.extras.fmt").fmt +local rep = require("luasnip.extras").rep +local f = ls.function_node -- Import function_node for dynamic content + +-- Function to get the filename without the path +local function get_filename() + local filepath = vim.api.nvim_buf_get_name(0) + local filename = vim.fn.fnamemodify(filepath, ":t:r") -- Get filename without path and extension + return filename:gsub("_", " ") -- Replace underscores with spaces +end + +local neetcode_snippet = s( + "neetcode", + fmt( + [[ +""" +Question + +{1} +""" + + +from typing import Dict + +class Solution: + """ + A class to solve {file_name} from {2} + """ + def {3}(self, {4}) -> {5}: + """ + {file_name} from the input {parameters_type} using a {func_name} approach. + + Args: + {parameters_type}: {6} + + Returns: + {return_type}: {7} + """ + return {8} + + def print(self, examples: Dict[str, {parameters_type}]) -> None: + for name, example in examples.items(): + result = self.{3}(example) + print(f"{{name}}: {{result}}") + + def main(self): + cases = {{ + "case1" : {9}, + "case2" : {10}, + "case3" : {11}, + }} + + self.print(cases) + + +solution = Solution() +solution.main() + +""" +Solution + +url: {12} +video: {13} + +1. {func_name} +time: {14} +space: {15} +code: +```python +{16} +``` +""" +]], + { + i(1, '"Describe the question here"'), + file_name = f(get_filename), -- Insert the filename dynamicall + i(2, '"Describe the class here"'), + i(3, '"Function name"'), -- Primary insert node for method name + func_name = rep(3), -- Repeat the method name + i(4, '"parameters"'), + parameters_type = rep(4), + i(5, '"return_type"'), + return_type = rep(5), + i(6, '"parameters_desc"'), + i(7, '"return_type_desc"'), + i(8, '"return"'), + i(9, '"case1"'), + i(10, '"case2"'), + i(11, '"case3"'), + i(12, '"url"'), + i(13, '"video"'), + i(14, '"time_complexity"'), + i(15, '"space_complexity"'), + i(16, '"code"'), + } + ) +) + +-- Add the snippets for multiple filetypes +ls.add_snippets("python", { neetcode_snippet }) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/neetcode2.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/neetcode2.lua new file mode 100644 index 0000000..98e7258 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/neetcode2.lua @@ -0,0 +1,104 @@ +local ls = require("luasnip") +local s = ls.snippet +local i = ls.insert_node +local fmt = require("luasnip.extras.fmt").fmt +local rep = require("luasnip.extras").rep +local f = ls.function_node -- Import function_node for dynamic content + +-- Function to get the filename without the path +local function get_filename() + local filepath = vim.api.nvim_buf_get_name(0) + local filename = vim.fn.fnamemodify(filepath, ":t:r") -- Get filename without path and extension + return filename:gsub("_", " ") -- Replace underscores with spaces +end + +local neetcode_snippet = s( + "neetcode", + fmt( + [[ +""" +Question + +{1} +""" + + +from typing import Dict + +class Solution: + """ + A class to solve {file_name} from {2} + """ + def {3}(self, {4}) -> {5}: + """ + {file_name} from the input {parameters_type} using a {func_name} approach. + + Args: + {parameters_type}: {6} + + Returns: + {return_type}: {7} + """ + return {8} + + def print(self, examples: Dict[str, {parameters_type}]) -> None: + for name, (param1, param2) in examples.items(): + result = self.{3}(param1, param2) + print(f"{{name}}: {{result}}") + + def main(self): + cases = {{ + "case1" : ({9}), + "case2" : ({10}), + "case3" : ({11}), + }} + + self.print(cases) + + + +solution = Solution() +solution.main() + +""" +Solution + +url: {12} +video: {13} + +1. {func_name} +time: {14} +space: {15} +code: +```python +{16} +``` +""" +]], + { + i(1, '"Describe the question here"'), + file_name = f(get_filename), -- Insert the filename dynamicall + i(2, '"Describe the class here"'), + i(3, '"Function name"'), -- Primary insert node for method name + func_name = rep(3), -- Repeat the method name + i(4, '"parameters"'), + parameters_type = rep(4), + i(5, '"return_type"'), + return_type = rep(5), + i(6, '"parameters_desc"'), + i(7, '"return_type_desc"'), + i(8, '"return"'), + i(9, '"case1"'), + i(10, '"case2"'), + i(11, '"case3"'), + i(12, '"url"'), + i(13, '"video"'), + i(14, '"time_complexity"'), + i(15, '"space_complexity"'), + i(16, '"code"'), + } + ) +) + +-- Add the snippets for multiple filetypes +ls.add_snippets("python", { neetcode_snippet }) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/quarto.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/quarto.lua new file mode 100644 index 0000000..74b9fb8 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/quarto.lua @@ -0,0 +1,28 @@ +local ls = require("luasnip") + +local s = ls.snippet +local i = ls.insert_node +local t = ls.text_node +-- local d = ls.dynamic_node +local c = ls.choice_node +-- local f = ls.function_node +-- local r = ls.restore_node +local fmt = require("luasnip.extras.fmt").fmta +-- local h = require("thesiahxyz.utils.snippet") + +local code_cell_snippet = s( + "`", + fmt( + [[```<lang> +<last> +``]], + { + lang = c(1, { t("python"), t("") }), + last = i(0), -- Place cursor here after expanding the snippet + } + ) +) + +-- Add the snippets for multiple filetypes +ls.add_snippets("markdown", { code_cell_snippet }) +ls.add_snippets("quarto", { code_cell_snippet }) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/whichkey.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/whichkey.lua new file mode 100644 index 0000000..fab5853 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/snippets/whichkey.lua @@ -0,0 +1,18 @@ +local ls = require("luasnip") + +-- Using parse_snippet instead of fmt to avoid curly brace issues +local whichkey_snippet = ls.parser.parse_snippet( + "whichkey", + [[ +init = function() + local wk = require("which-key") + wk.add({ + mode = { "n" }, + { "${1:Key}", group = "${2:Name}" }, + }) +end, +]] +) + +-- Add the snippets for the Lua filetype +ls.add_snippets("lua", { whichkey_snippet }) diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/spells/en.utf-8.add b/ar/.config/TheSiahxyz/lua/thesiahxyz/spells/en.utf-8.add new file mode 100644 index 0000000..a60a241 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/spells/en.utf-8.add @@ -0,0 +1,113 @@ +#eplacement +AI +API +ASAP +AUR +AWS +ArchLinux +Asana +Azure +BTW +Bitbucket +CD +CI +CLI +CSS +CV +Cloudflare +DNS +DevOps +DigitalOcean +Django +Docker +ETA +FAQ +FYI +FYI +Fedora +Figma +Flask +GCP +GPG +GUI +Git +GitHub +GitLab +Google +HTML +HTTP +HTTPS +IDE +IDK +IMO +IP +IoT +JSON +JWT +JavaScript +JetBrains +Kubernetes +Linode +Linux +Lorem +Lua +ML +MVP +Markdown +MySQL +NLP +Neovim +Node.js +Notion +OAuth +OK +OKRs +POSIX +PostgreSQL +PyCharm +PyPI +R&D +React +Redis +SQL +SQLite +SSH +SSL +Slack +TBD +TCP +TLS +Trello +TypeScript +UI +URL +UX +Ubuntu +VSCode +Vue +WebStorm +YAML +YouTube +Zoom +alt +backend +blockquote +conda +config +ctrl +dotfiles +frontend +highlighter +inline +ipsum +kbd +meta +msmtp +npm +pip +plaintext +super +syntax +typst +vimrc +window diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/spells/en.utf-8.add.spl b/ar/.config/TheSiahxyz/lua/thesiahxyz/spells/en.utf-8.add.spl Binary files differnew file mode 100644 index 0000000..ab8358b --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/spells/en.utf-8.add.spl diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet.lua new file mode 100644 index 0000000..dd5130a --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet.lua @@ -0,0 +1,13 @@ +local options = { + cheatsheet = { + theme = "grid", -- Options: "simple" or "grid" + excluded_groups = { "terminal (t)", "autopairs", "Nvim", "Opens" }, -- Exclude specific groups + }, +} + +-- Define a keymap for opening the cheatsheet +vim.keymap.set("n", "<leader>skc", function() + require("thesiahxyz.utils.cheatsheet.grid")() +end, { desc = "Open Cheatsheet" }) + +return options diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet/grid.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet/grid.lua new file mode 100644 index 0000000..6616b1e --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet/grid.lua @@ -0,0 +1,105 @@ +local api = vim.api +local ch = require("thesiahxyz.utils.cheatsheet.init") +local state = ch.state + +local ascii = { + " ", + " ", + "█▀▀ █░█ █▀▀ ▄▀█ ▀█▀ █▀ █░█ █▀▀ █▀▀ ▀█▀", + "█▄▄ █▀█ ██▄ █▀█ ░█░ ▄█ █▀█ ██▄ ██▄ ░█░", + " ", + " ", +} + +return function(buf, win, action) + action = action or "open" + + local ns = api.nvim_create_namespace("thesiah_cheatsheet") + + if action == "open" then + state.mappings_tb = ch.organize_mappings() + + buf = buf or api.nvim_create_buf(false, true) + win = win or api.nvim_get_current_win() + + api.nvim_set_current_win(win) + + -- Calculate maximum widths for lhs and rhs + local lhs_max_width, rhs_max_width = 0, 0 + for _, section in pairs(state.mappings_tb) do + for _, mapping in ipairs(section) do + lhs_max_width = math.max(lhs_max_width, vim.fn.strdisplaywidth(mapping[1])) + rhs_max_width = math.max(rhs_max_width, vim.fn.strdisplaywidth(mapping[2])) + end + end + + local total_width = lhs_max_width + rhs_max_width + 6 -- Add spacing for readability + local center_offset = math.floor((total_width - vim.fn.strdisplaywidth(ascii[1])) / 2) + + -- Align ASCII art to the center + local ascii_header = vim.tbl_values(ascii) + for i, line in ipairs(ascii_header) do + ascii_header[i] = string.rep(" ", center_offset) .. line + end + + -- Center-align the title + local title = "Cheatsheet" + local title_padding = math.floor((total_width - vim.fn.strdisplaywidth(title)) / 2) + local title_line = string.rep(" ", title_padding) .. title + + -- Prepare buffer lines + local lines = {} + for _, line in ipairs(ascii_header) do + table.insert(lines, line) + end + table.insert(lines, "") -- Blank line after ASCII art + table.insert(lines, title_line) + table.insert(lines, "") -- Blank line after title + + -- Add mappings grouped by section + for section_name, mappings in pairs(state.mappings_tb) do + -- Center-align the section name + local section_padding = math.floor((total_width - vim.fn.strdisplaywidth(section_name)) / 2) + table.insert(lines, string.rep(" ", section_padding) .. section_name) -- Section header + + -- Add mappings aligned to lhs and rhs + for _, mapping in ipairs(mappings) do + local lhs = mapping[1] + local rhs = mapping[2] + local lhs_padding = string.rep(" ", lhs_max_width - vim.fn.strdisplaywidth(lhs)) + local rhs_padding = string.rep(" ", rhs_max_width - vim.fn.strdisplaywidth(rhs)) + table.insert(lines, lhs .. lhs_padding .. " " .. rhs_padding .. rhs) + end + table.insert(lines, "") -- Blank line after each section + end + + -- Set lines into the buffer + api.nvim_buf_set_lines(buf, 0, -1, false, lines) + + -- Highlight ASCII art and title + for i = 1, #ascii_header do + api.nvim_buf_add_highlight(buf, ns, "ThesiahAsciiHeader", i - 1, 0, -1) + end + api.nvim_buf_add_highlight(buf, ns, "Title", #ascii + 1, 0, -1) + + -- Highlight section headers + local current_line = #ascii + 3 -- Adjust for blank lines and title + for section_name, mappings in pairs(state.mappings_tb) do + api.nvim_buf_add_highlight(buf, ns, "ThesiahSection", current_line, 0, -1) + current_line = current_line + #mappings + 2 -- Count section header, mappings, and blank line + end + + -- Configure the buffer + vim.bo[buf].modifiable = false + vim.bo[buf].readonly = false + vim.bo[buf].buftype = "" + vim.bo[buf].buflisted = true + vim.bo[buf].filetype = "cheatsheet" + + -- Set up autocmds for the cheatsheet + ch.autocmds(buf, win) + + -- Focus on the cheatsheet buffer + api.nvim_set_current_buf(buf) + end +end diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet/init.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet/init.lua new file mode 100644 index 0000000..c4cc1f0 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/cheatsheet/init.lua @@ -0,0 +1,116 @@ +local M = {} +local api = vim.api +local config = require("thesiahxyz.utils.cheatsheet") -- Load cheatsheet options + +local function capitalize(str) + return (str:gsub("^%l", string.upper)) +end + +M.get_mappings = function(mappings, tb_to_add) + local excluded_groups = config.cheatsheet.excluded_groups + + for _, v in ipairs(mappings) do + local desc = v.desc + + if not desc or (select(2, desc:gsub("%S+", "")) <= 1) or string.find(desc, "\n") then + goto continue + end + + local heading = desc:match("%S+") -- Get first word + heading = (v.mode ~= "n" and heading .. " (" .. v.mode .. ")") or heading + + if + vim.tbl_contains(excluded_groups, heading) + or vim.tbl_contains(excluded_groups, desc:match("%S+")) + or string.find(v.lhs, "<Plug>") + then + goto continue + end + + heading = capitalize(heading) + + if not tb_to_add[heading] then + tb_to_add[heading] = {} + end + + local keybind = string.sub(v.lhs, 1, 1) == " " and "<leader> +" .. v.lhs or v.lhs + + desc = v.desc:match("%s(.+)") -- Remove first word from description + desc = capitalize(desc) + + table.insert(tb_to_add[heading], { desc, keybind }) + + ::continue:: + end +end + +M.organize_mappings = function() + local tb_to_add = {} + local modes = { "n", "i", "v", "t" } + + for _, mode in ipairs(modes) do + local keymaps = api.nvim_get_keymap(mode) + M.get_mappings(keymaps, tb_to_add) + + local bufkeymaps = api.nvim_buf_get_keymap(0, mode) + M.get_mappings(bufkeymaps, tb_to_add) + end + + return tb_to_add +end + +M.rand_hlgroup = function() + local hlgroups = { + "blue", + "red", + "green", + "yellow", + "orange", + "baby_pink", + "purple", + "white", + "cyan", + "vibrant_green", + "teal", + } + + return "ThesiahHead" .. hlgroups[math.random(1, #hlgroups)] +end + +M.autocmds = function(buf, win) + -- Set buffer options to make it searchable and navigable + vim.bo[buf].buflisted = true + vim.bo[buf].buftype = "" -- Treat it as a regular buffer + vim.bo[buf].swapfile = false + vim.bo[buf].modifiable = false -- Prevent accidental edits + vim.bo[buf].readonly = false -- Enable navigation and search + vim.bo[buf].filetype = "cheatsheet" -- Optional, to customize behavior + + -- Create autocmd group for cheatsheet + local group_id = api.nvim_create_augroup("ThesiahCheatsheet", { clear = true }) + + -- Clean up when buffer is closed + api.nvim_create_autocmd("BufWinLeave", { + group = group_id, + buffer = buf, + callback = function() + vim.g.thesiah_cheatsheet_displayed = false + api.nvim_del_augroup_by_id(group_id) + end, + }) + + -- Keymaps for cheatsheet buffer + vim.keymap.set("n", "q", function() + api.nvim_buf_delete(buf, { force = true }) + end, { buffer = buf }) + + vim.keymap.set("n", "<ESC>", function() + api.nvim_buf_delete(buf, { force = true }) + end, { buffer = buf }) +end + +M.state = { + mappings_tb = {}, +} + +return M diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/icons.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/icons.lua new file mode 100644 index 0000000..22d5f2d --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/icons.lua @@ -0,0 +1,168 @@ +return { + diagnostics = { + Error = " ", + Hint = " ", + Information = " ", + Question = " ", + Warning = " ", + }, + documents = { + File = " ", + FileEmpty = " ", + Files = " ", + Folder = " ", + FolderEmpty = " ", + OpenFolder = " ", + OpenFolderEmpty = " ", + SymLink = " ", + SymlinkFolder = " ", + Import = " ", + }, + git = { + Add = " ", + AddAlt = " ", + Branch = " ", + Diff = " ", + DiffAlt = " ", + Ignore = "◌ ", + Mod = " ", + Octoface = " ", + Remove = " ", + RemoveAlt = " ", + Rename = " ", + Repo = " ", + Tag = " ", + Untrack = " ", + }, + kind = { + Class = " ", + Color = " ", + Constant = " ", + Constructor = " ", + Copilot = " ", + Enum = " ", + EnumMember = " ", + Event = " ", + Field = " ", + File = " ", + Folder = " ", + Function = " ", + Interface = " ", + Keyword = " ", + Language = " ", + Method = " ", + Module = "", + Operator = " ", + Property = " ", + Reference = " ", + Snippet = " ", + Struct = " ", + Text = " ", + TypeParameter = " ", + Unit = " ", + Value = " ", + Variable = " ", + }, + type = { + Array = " ", + Boolean = "⏻ ", + Number = " ", + Object = " ", + String = " ", + }, + ui = { + Arrow = " ", + ArrowClosed = " ", + ArrowLeft = " ", + ArrowOpen = " ", + ArrowRight = " ", + Bluetooth = " ", + Bookmark = " ", + Bug = " ", + Calendar = " ", + Camera = " ", + Check = " ", + ChevronRight = "", + Circle = " ", + CircleSmall = "● ", + CircleSmallEmpty = "○ ", + Clipboard = " ", + Close = " ", + Code = " ", + Collection = " ", + Color = " ", + Command = " ", + Comment = " ", + Copilot = " ", + CopilotError = " ", + Corner = "└ ", + Dashboard = " ", + Database = " ", + Download = " ", + Edit = " ", + Edge = "│ ", + Electric = " ", + Eye = " ", + Fire = " ", + Firefox = " ", + Flag = " ", + Game = " ", + Gear = " ", + GitHub = " ", + Heart = " ", + History = " ", + Home = " ", + Incoming = " ", + Jump = " ", + Keyboard = " ", + Ligthbulb = " ", + List = "", + Lock = " ", + Minus = "‒ ", + Music = " ", + Neovim = " ", + NewFile = " ", + None = " ", + Note = " ", + Outgoing = " ", + Package = " ", + Paint = " ", + Pause = " ", + Pencil = " ", + Person = " ", + Pin = " ", + Play = " ", + Plug = " ", + Plus = " ", + Power = " ", + PowerlineArrowLeft = "", + PowerlineArrowRight = "", + PowerlineLeftRound = "", + PowerlineRightRound = "", + Project = " ", + Question = " ", + Refresh = " ", + Reload = " ", + Rocket = " ", + Save = " ", + Search = " ", + Separator = "▊ ", + SeparatorLight = "▍", + SeparatorDashed = "┆", + SignIn = " ", + SignOut = " ", + Sleep = " ", + Star = " ", + Table = " ", + Telescope = " ", + Terminal = " ", + Test = " ", + Time = " ", + Topline = "‾", + Trash = " ", + User = " ", + Vim = " ", + Wifi = " ", + Windows = " ", + }, +} diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/markdown.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/markdown.lua new file mode 100644 index 0000000..1b1c591 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/markdown.lua @@ -0,0 +1,26 @@ +local M = {} + +-- foldtext for Neovim < 0.10.0 +function M.foldtext() + return vim.api.nvim_buf_get_lines(0, vim.v.lnum - 1, vim.v.lnum, false)[1] +end + +-- optimized treesitter foldexpr for Neovim >= 0.10.0 +function M.foldexpr() + local buf = vim.api.nvim_get_current_buf() + if vim.b[buf].ts_folds == nil then + -- as long as we don't have a filetype, don't bother + -- checking if treesitter is available (it won't) + if vim.bo[buf].filetype == "" then + return "0" + end + if vim.bo[buf].filetype:find("dashboard") then + vim.b[buf].ts_folds = false + else + vim.b[buf].ts_folds = pcall(vim.treesitter.get_parser, buf) + end + end + return vim.b[buf].ts_folds and vim.treesitter.foldexpr() or "0" +end + +return M diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/snippet.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/snippet.lua new file mode 100644 index 0000000..57bb211 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/snippet.lua @@ -0,0 +1,38 @@ +local ls = require("luasnip") +-- local s = ls.snippet +local i = ls.insert_node +local t = ls.text_node +-- local d = ls.dynamic_node +-- local f = ls.function_node +local c = ls.choice_node +-- local rep = require("luasnip.extras").rep +-- local k = require("luasnip.nodes.key_indexer").new_key +local r = ls.restore_node +local fmt = require("luasnip.extras.fmt").fmt + +local M = {} +M.i = 0 + +M.js_quotes = function(index) + M.i = M.i + 1 + return c(index, { fmt("'{}'", { r(1, M.i) }), fmt("`{}`", { r(1, M.i) }), fmt('"{}"', { r(1, M.i) }), t("") }) +end + +M.js_selector = function(index) + return c(index, { fmt("/{}/i", { i(1) }), fmt("'{}'", { i(1) }), fmt("`{}`", { i(1) }), t("") }) +end + +M.rtl_selector = function(index) + return c(index, { t("screen.get"), t("await screen.find"), t("screen.query") }) +end + +M.tracked_i_nodes = {} + +M.tin = function(index, key) + if not M.tracked_i_nodes[key] then + M.tracked_i_nodes[key] = i(index) + end + return M.tracked_i_nodes[key] +end + +return M diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/tasks.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/tasks.lua new file mode 100644 index 0000000..34d5636 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/tasks.lua @@ -0,0 +1,227 @@ +-- ~/.config/nvim/lua/user_functions/tasks.lua +local M = {} + +-- Import the create_floating_scratch function from utils.lua +local utils = require("thesiahxyz.utils.utils") + +function M.create_or_update_task() + local current_line = vim.fn.getline(".") + local cursor_pos = vim.fn.col(".") + local file_path = vim.fn.expand("%:p") -- Get full path of current file + local line_number = vim.fn.line(".") -- Get current line number + + -- Keywords we are looking for + local keywords = { "TODO", "HACK", "NOTE", "PERF", "TEST", "WARN" } + + for _, keyword in ipairs(keywords) do + local start_index, end_index = string.find(current_line, keyword) + if start_index then + local task_description = string.sub(current_line, end_index + 2, cursor_pos - 1) + task_description = string.gsub(task_description, "%(siah%)", "") + local task_tag = "+" .. string.lower(keyword) + + -- Ask for project and other tags + local project = vim.fn.input("Enter project name: ") + local additional_tags_input = vim.fn.input("Enter additional tags separated by spaces: ") + local additional_tags = {} + + -- Prefix each additional tag with a "+" + for tag in additional_tags_input:gmatch("%S+") do + table.insert(additional_tags, "+" .. tag) + end + + -- Prepare the task command + local task_cmd = string.format('task add %s "%s"', task_tag, task_description) + + -- Add additional tags if available + if #additional_tags > 0 then + task_cmd = task_cmd .. " " .. table.concat(additional_tags, " ") + end + + -- Add project if available + if project and #project > 0 then + task_cmd = task_cmd .. " project:" .. project + end + + -- Execute the task add command + local output = vim.fn.system(task_cmd) + print("Output: ", output) + + for line in output:gmatch("[^\r\n]+") do + local task_id = string.match(line, "Created task (%d+)%.") + if task_id then + print("Task ID extracted: ", task_id) + + -- Annotate task with filename and line number in the nvimline format + local annotation = string.format("nvimline:%s:%s", line_number, file_path) + local annotate_cmd = string.format('task %s annotate "%s"', task_id, annotation) + local annotate_output = vim.fn.system(annotate_cmd) + + print("Annotation output: ", annotate_output) + return + else + print("Failed to extract task ID") + end + end + end + end +end + +vim.api.nvim_set_keymap( + "i", + "<C-t>", + "<cmd>lua require('thesiahxyz.utils.tasks').create_or_update_task()<cr>", + { noremap = true, silent = true, desc = "Create/Update task" } +) + +function M.mark_task_done() + -- Get the current line and parse it + local line = vim.api.nvim_get_current_line() + print("Original line: ", line) + + -- Uncomment the line + vim.cmd("normal! gcc") + line = vim.api.nvim_get_current_line() + -- Remove (piotr1215) from the line + line = string.gsub(line, "%s*%(siah%)%s*", " ") + print("Uncommented line: ", line) + + local patterns = { "TODO:", "HACK:", "NOTE:", "PERF:", "TEST:", "WARN:" } + local taskDescription = nil + for _, pattern in ipairs(patterns) do + local start_idx = string.find(line, pattern) + if start_idx then + taskDescription = string.sub(line, start_idx + string.len(pattern) + 1) + break + end + end + print("Task description: ", taskDescription or "nil") + + -- If a task description was found, mark it as done + if taskDescription then + local output = vim.fn.system("yes | task description~'" .. taskDescription .. "' done") + print("Command output: ", output) + -- Check the command's output to make sure the task was marked done + if string.find(output, "Completed") then + -- Delete the current line + vim.cmd([[normal dd]]) + end + end +end + +vim.api.nvim_set_keymap( + "n", + "<localleader>td", + "<Cmd>lua require('thesiahxyz.utils.tasks').mark_task_done()<CR>", + { noremap = true, silent = true, desc = "Mark task done" } +) + +function M.go_to_task_in_taskwarrior_tui() + -- Get the current line and save it as the original line + local original_line = vim.api.nvim_get_current_line() + + -- Uncomment the line + vim.cmd("normal! gcc") + local uncommented_line = vim.api.nvim_get_current_line() + + local patterns = { "TODO:", "HACK:", "NOTE:", "PERF:", "TEST:", "WARN:" } + local taskDescription = nil + + for _, pattern in ipairs(patterns) do + local start_idx = string.find(uncommented_line, pattern) + if start_idx then + taskDescription = string.sub(uncommented_line, start_idx + string.len(pattern) + 1) + taskDescription = string.sub(taskDescription, 1, 50) + break + end + end + + -- If a task description was found, use it to go to the task in taskwarrior-tui + if taskDescription then + -- print("Sleeping for 2 seconds before tmux switch...") + -- vim.cmd("sleep 2") -- sleep for 2 seconds + local output = vim.fn.system(" ~/.local/bin/opentasktui '" .. taskDescription .. "'") + end + + -- Replace the line back with the original + vim.api.nvim_set_current_line(original_line) +end + +vim.api.nvim_set_keymap( + "n", + "<localleader>tt", + "<Cmd>lua require('thesiahxyz.utils.tasks').go_to_task_in_taskwarrior_tui()<CR>", + { noremap = true, silent = true, desc = "Open taskwarrior-tui" } +) + +function M.process_task_list(start_line, end_line, ...) + local args = { ... } + local modifiers = table.concat(args, " ") + local lines + + -- If no range is provided, use the entire buffer. + if not start_line or not end_line then + start_line, end_line = 1, vim.api.nvim_buf_line_count(0) + end + + lines = vim.api.nvim_buf_get_lines(0, start_line - 1, end_line, false) + + local new_lines = { "#!/bin/sh", "set -e" } + + for _, line in ipairs(lines) do + local trimmed_line = line:gsub("^[•*%-%+]+%s*", "") + local links = {} + + trimmed_line = trimmed_line:gsub("(https?://[%w%.%-%_/&%?=%~]+)", function(link) + table.insert(links, link) + return "" + end) + + if #trimmed_line > 0 then + -- No more "\n" before "# Adding task:"; instead, just ensure it's a new entry in the table. + table.insert(new_lines, "") -- Ensure there's an empty line before adding a new task if desired. + table.insert(new_lines, "# Adding task: " .. trimmed_line) + table.insert( + new_lines, + "output=$(task add " .. (modifiers ~= "" and modifiers .. " " or "") .. '"' .. trimmed_line .. '")' + ) + table.insert( + new_lines, + 'task_id=$(echo "$output" | grep -o "Created task [0-9]*." | cut -d " " -f 3 | tr -d ".")' + ) + + for _, link in ipairs(links) do + table.insert(new_lines, "task $task_id annotate -- " .. link) + end + end + end + + -- Call the create_floating_scratch function from utils.lua + utils.create_floating_scratch(new_lines) +end + +function M.my_custom_complete(arg_lead, cmd_line, cursor_pos) + -- This is your list of arguments. + local items = { "project:", "due:", "+next", "duration:" } + + -- Filter the items based on the argument lead. + local matches = {} + for _, item in ipairs(items) do + if item:find(arg_lead) == 1 then + table.insert(matches, item) + end + end + + return matches +end + +vim.api.nvim_create_user_command("ProcessTaskList", function(input) + M.process_task_list(1, vim.api.nvim_buf_line_count(0), unpack(input.fargs)) +end, { + nargs = "*", + complete = function(arg_lead, cmd_line, cursor_pos) + -- Call the custom completion function + return M.my_custom_complete(arg_lead, cmd_line, cursor_pos) + end, +}) +return M diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/tmux.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/tmux.lua new file mode 100644 index 0000000..41869f8 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/tmux.lua @@ -0,0 +1,63 @@ +local M = {} + +M.tmux_pane_function = function(dir) + -- NOTE: variable that controls the auto-cd behavior + local auto_cd_to_new_dir = true + -- NOTE: Variable to control pane direction: 'right' or 'bottom' + -- If you modify this, make sure to also modify TMUX_PANE_DIRECTION in the + -- zsh-vi-mode section on the .zshrc file + -- Also modify this in your tmux.conf file if you want it to work when in tmux + -- copy-mode + local pane_direction = vim.g.tmux_pane_direction or "right" + -- NOTE: Below, the first number is the size of the pane if split horizontally, + -- the 2nd number is the size of the pane if split vertically + local pane_size = (pane_direction == "right") and 60 or 15 + local move_key = (pane_direction == "right") and "C-l" or "" + local split_cmd = (pane_direction == "right") and "-h" or "-v" + -- if no dir is passed, use the current file's directory + local file_dir = dir or vim.fn.expand("%:p:h") + -- Simplified this, was checking if a pane existed + local has_panes = vim.fn.system("tmux list-panes | wc -l"):gsub("%s+", "") ~= "1" + -- Check if the current pane is zoomed (maximized) + local is_zoomed = vim.fn.system("tmux display-message -p '#{window_zoomed_flag}'"):gsub("%s+", "") == "1" + -- Escape the directory path for shell + local escaped_dir = file_dir:gsub("'", "'\\''") + -- If any additional pane exists + if has_panes then + if is_zoomed then + -- Compare the stored pane directory with the current file directory + if auto_cd_to_new_dir and vim.g.tmux_pane_dir ~= escaped_dir then + -- If different, cd into the new dir + vim.fn.system("tmux send-keys -t :.+ 'cd \"" .. escaped_dir .. "\"' Enter") + -- Update the stored directory to the new one + vim.g.tmux_pane_dir = escaped_dir + end + -- If zoomed, unzoom and switch to the correct pane + vim.fn.system("tmux resize-pane -Z") + vim.fn.system("tmux send-keys " .. move_key) + else + -- If not zoomed, zoom current pane + vim.fn.system("tmux resize-pane -Z") + end + else + -- Store the initial directory in a Neovim variable + if vim.g.tmux_pane_dir == nil then + vim.g.tmux_pane_dir = escaped_dir + end + -- If no pane exists, open it with zsh and DISABLE_PULL variable + vim.fn.system( + "tmux split-window " + .. split_cmd + .. " -l " + .. pane_size + .. " 'cd \"" + .. escaped_dir + .. "\" && DISABLE_PULL=1 zsh'" + ) + vim.fn.system("tmux send-keys " .. move_key) + end +end + +vim.keymap.set({ "n", "v", "i" }, "<M-\\>", M.tmux_pane_function, { desc = "Toggle terminal in tmux" }) + +return M diff --git a/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/utils.lua b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/utils.lua new file mode 100644 index 0000000..2925569 --- /dev/null +++ b/ar/.config/TheSiahxyz/lua/thesiahxyz/utils/utils.lua @@ -0,0 +1,112 @@ +-- ~/.config/nvim/lua/thesiahxyz/utils/utils.lua +local M = {} + +function M.print_current_file_dir() + local dir = vim.fn.expand("%:p:h") + if dir ~= "" then + print(dir) + end +end + +function M.reload_module(name) + package.loaded[name] = nil + return require(name) +end + +-- Function to reload the current Lua file +function M.reload_current_file() + local current_file = vim.fn.expand("%:p") + + if current_file:match("%.lua$") then + vim.cmd("luafile " .. current_file) + print("Reloaded file: " .. current_file) + else + print("Current file is not a Lua file: " .. current_file) + end +end + +function M.insert_file_path() + local actions = require("telescope.actions") + local action_state = require("telescope.actions.state") + + require("telescope.builtin").find_files({ + cwd = "~/.config", -- Set the directory to search + attach_mappings = function(_, map) + map("i", "<CR>", function(prompt_bufnr) + local selected_file = action_state.get_selected_entry(prompt_bufnr).path + actions.close(prompt_bufnr) + + -- Replace the home directory with ~ + selected_file = selected_file:gsub(vim.fn.expand("$HOME"), "~") + + -- Ask the user if they want to insert the full path or just the file name + local choice = vim.fn.input("Insert full path or file name? (n[ame]/p[ath]): ") + local text_to_insert + if choice == "p" then + text_to_insert = selected_file + elseif choice == "n" then + text_to_insert = vim.fn.fnamemodify(selected_file, ":t") + end + + -- Move the cursor back one position + local col = vim.fn.col(".") - 1 + vim.fn.cursor(vim.fn.line("."), col) + + -- Insert the text at the cursor position + vim.api.nvim_put({ text_to_insert }, "c", true, true) + end) + return true + end, + }) +end + +vim.api.nvim_set_keymap( + "i", + "<M-p>", + "<cmd>lua require('thesiahxyz.utils.utils').insert_file_path()<cr>", + { noremap = true, silent = true } +) +function M.create_floating_scratch(content) + -- Get editor dimensions + local width = vim.api.nvim_get_option("columns") + local height = vim.api.nvim_get_option("lines") + + -- Calculate the floating window size + local win_height = math.ceil(height * 0.8) + 2 -- Adding 2 for the border + local win_width = math.ceil(width * 0.8) + 2 -- Adding 2 for the border + + -- Calculate window's starting position + local row = math.ceil((height - win_height) / 2) + local col = math.ceil((width - win_width) / 2) + + -- Create a buffer and set it as a scratch buffer + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_option(buf, "buftype", "nofile") + vim.api.nvim_buf_set_option(buf, "bufhidden", "wipe") + vim.api.nvim_buf_set_option(buf, "filetype", "sh") -- for syntax highlighting + + -- Create the floating window with a border and set some options + local win = vim.api.nvim_open_win(buf, true, { + relative = "editor", + row = row, + col = col, + width = win_width, + height = win_height, + border = "single", -- You can also use 'double', 'rounded', or 'solid' + }) + + -- Check if we've got content to populate the buffer with + if content then + vim.api.nvim_buf_set_lines(buf, 0, -1, true, content) + else + vim.api.nvim_buf_set_lines(buf, 0, -1, true, { "This is a scratch buffer in a floating window." }) + end + + vim.api.nvim_win_set_option(win, "wrap", false) + vim.api.nvim_win_set_option(win, "cursorline", true) + + -- Map 'q' to close the buffer in this window + vim.api.nvim_buf_set_keymap(buf, "n", "q", ":q!<CR>", { noremap = true, silent = true }) +end + +return M |
