diff --git a/after/queries/markdown/highlights.scm b/after/queries/markdown/highlights.scm new file mode 100644 index 00000000..9f45b6c7 --- /dev/null +++ b/after/queries/markdown/highlights.scm @@ -0,0 +1,2 @@ +;extend + diff --git a/after/queries/markdown/textobjects.scm b/after/queries/markdown/textobjects.scm new file mode 100644 index 00000000..9f4d4391 --- /dev/null +++ b/after/queries/markdown/textobjects.scm @@ -0,0 +1,6 @@ +;extends + +(fenced_code_block (code_fence_content) @class.inner) @class.outer + +(paragraph) @function.outer @function.inner + diff --git a/after/queries/markdown_inline/highlights.scm b/after/queries/markdown_inline/highlights.scm new file mode 100644 index 00000000..445b09e3 --- /dev/null +++ b/after/queries/markdown_inline/highlights.scm @@ -0,0 +1,13 @@ +;extends + +[ + (shortcut_link) +] @nospell + +(strikethrough +(emphasis_delimiter) +(strikethrough + (emphasis_delimiter) + (emphasis_delimiter)) +(emphasis_delimiter))@markup.doublestrikethrough + diff --git a/after/queries/norg/injections.scm b/after/queries/norg/injections.scm new file mode 100644 index 00000000..fce214a4 --- /dev/null +++ b/after/queries/norg/injections.scm @@ -0,0 +1,12 @@ +; Injection for code blocks +(ranged_verbatim_tag (tag_name) @_tagname (tag_parameters .(tag_param) @injection.language) (ranged_verbatim_tag_content) @injection.content (#any-of? @_tagname "code" "embed")) +(ranged_verbatim_tag (tag_name) @_tagname (tag_parameters)? (ranged_verbatim_tag_content) @injection.content (#eq? @_tagname "math") (#set! injection.language "latex")) + +( + (inline_math) @injection.content + (#offset! @injection.content 0 1 0 -1) + (#set! injection.language "latex") +) + +(ranged_verbatim_tag (tag_name) @_tagname (ranged_verbatim_tag_content) @injection.content (#eq? @_tagname "document.meta") (#set! injection.language "norg_meta")) + diff --git a/after/queries/python/highlights.scm b/after/queries/python/highlights.scm new file mode 100644 index 00000000..db7a7b05 --- /dev/null +++ b/after/queries/python/highlights.scm @@ -0,0 +1,12 @@ +;extends +( +(comment) @comment +(#match? @comment "^\\#\\|") +) @text.literal + + +( +(comment) @content +(#match? @content "^\\# ?\\%\\%") +) @class.outer @text.literal + diff --git a/after/queries/python/textobjects.scm b/after/queries/python/textobjects.scm new file mode 100644 index 00000000..c5ec1440 --- /dev/null +++ b/after/queries/python/textobjects.scm @@ -0,0 +1,7 @@ +;extends + +( +(comment) @content1 +(#match? @content1 "^\\# ?\\%\\%") +) @class.inner + diff --git a/after/queries/r/highlights.scm b/after/queries/r/highlights.scm new file mode 100644 index 00000000..111ab3ef --- /dev/null +++ b/after/queries/r/highlights.scm @@ -0,0 +1,6 @@ +;extends +( +(comment) @comment +(#match? @comment "^\\#\\|") +) @text.literal + diff --git a/after/queries/r/textobjects.scm b/after/queries/r/textobjects.scm new file mode 100644 index 00000000..c5ec1440 --- /dev/null +++ b/after/queries/r/textobjects.scm @@ -0,0 +1,7 @@ +;extends + +( +(comment) @content1 +(#match? @content1 "^\\# ?\\%\\%") +) @class.inner + diff --git a/after/queries/rust/injections.scm b/after/queries/rust/injections.scm new file mode 100644 index 00000000..9930853a --- /dev/null +++ b/after/queries/rust/injections.scm @@ -0,0 +1,15 @@ +;extends +(macro_invocation +(scoped_identifier +path: (identifier) @path (#eq? @path "sqlx") +name: (identifier) @name (#match? @name "^query.*") +) + +(token_tree +(raw_string_literal) @injection.content +(#set! injection.language "sql") +(#set! injection.include-children) +) +(#offset! @injection.content 0 3 0 -2) +) + diff --git a/after/ftplugin/c.lua b/ftplugin/c.lua similarity index 100% rename from after/ftplugin/c.lua rename to ftplugin/c.lua diff --git a/after/ftplugin/crontab.lua b/ftplugin/crontab.lua similarity index 100% rename from after/ftplugin/crontab.lua rename to ftplugin/crontab.lua diff --git a/after/ftplugin/dockerfile.lua b/ftplugin/dockerfile.lua similarity index 100% rename from after/ftplugin/dockerfile.lua rename to ftplugin/dockerfile.lua diff --git a/after/ftplugin/go.lua b/ftplugin/go.lua similarity index 100% rename from after/ftplugin/go.lua rename to ftplugin/go.lua diff --git a/after/ftplugin/lua.lua b/ftplugin/lua.lua similarity index 79% rename from after/ftplugin/lua.lua rename to ftplugin/lua.lua index b3842696..de7c1ff5 100644 --- a/after/ftplugin/lua.lua +++ b/ftplugin/lua.lua @@ -1,6 +1,6 @@ vim.opt.expandtab = true -vim.opt.shiftwidth = 2 -vim.opt.tabstop = 2 +vim.opt.shiftwidth = 4 +vim.opt.tabstop = 4 vim.opt.expandtab = true vim.opt_local.formatoptions:remove('o') diff --git a/after/ftplugin/make.lua b/ftplugin/make.lua similarity index 100% rename from after/ftplugin/make.lua rename to ftplugin/make.lua diff --git a/after/ftplugin/ocaml.lua b/ftplugin/ocaml.lua similarity index 100% rename from after/ftplugin/ocaml.lua rename to ftplugin/ocaml.lua diff --git a/after/ftplugin/python.lua b/ftplugin/python.lua similarity index 100% rename from after/ftplugin/python.lua rename to ftplugin/python.lua diff --git a/after/ftplugin/rust.lua b/ftplugin/rust.lua similarity index 100% rename from after/ftplugin/rust.lua rename to ftplugin/rust.lua diff --git a/after/ftplugin/sh.lua b/ftplugin/sh.lua similarity index 100% rename from after/ftplugin/sh.lua rename to ftplugin/sh.lua diff --git a/after/ftplugin/sql.lua b/ftplugin/sql.lua similarity index 100% rename from after/ftplugin/sql.lua rename to ftplugin/sql.lua diff --git a/after/ftplugin/yaml.lua b/ftplugin/yaml.lua similarity index 100% rename from after/ftplugin/yaml.lua rename to ftplugin/yaml.lua diff --git a/init.lua b/init.lua index f2708180..fe87c701 100755 --- a/init.lua +++ b/init.lua @@ -13,6 +13,8 @@ if not vim.loop.fs_stat(lazypath) then end vim.opt.rtp:prepend(vim.env.LAZY or lazypath) +vim.cmd('filetype plugin on') + vim.g.mapleader = ' ' vim.g.maplocalleader = ' ' @@ -23,4 +25,3 @@ require('config.mappings') require('config.utils') require('config.themes') -vim.cmd('filetype plugin on') diff --git a/lua/config/autocmds.lua b/lua/config/autocmds.lua index 45b5288c..7f7c33f9 100755 --- a/lua/config/autocmds.lua +++ b/lua/config/autocmds.lua @@ -64,3 +64,29 @@ vim.cmd([[ autocmd TermOpen * tnoremap ]]) +-- Open PDF in the background when a .tex file is opened +vim.api.nvim_create_autocmd("BufEnter", { + pattern = "*.tex", + callback = function() + -- Construct an absolute path to the PDF file + local pdf_path = vim.fn.expand('%:p:h') .. "/output/" .. vim.fn.expand('%:t:r') .. '.pdf' + if vim.fn.filereadable(pdf_path) == 1 then + -- Start Zathura asynchronously in the background with an absolute path + vim.fn.jobstart({ 'nohup', 'zathura', pdf_path, '>/dev/null', '2>&1', '&' }, { detach = true }) + else + print("PDF file not found: " .. pdf_path) + end + end, +}) + +-- Close Zathura gracefully when leaving Neovim +vim.api.nvim_create_autocmd("VimLeavePre", { + callback = function() + -- Attempt to terminate Zathura gracefully with a grace period + vim.fn.system({ 'pkill', '-TERM', '-f', 'zathura' }) + vim.defer_fn(function() + vim.fn.system({ 'pkill', '-KILL', '-f', 'zathura' }) + end, 2000) -- Wait for 2 seconds before force killing if necessary + end, +}) + diff --git a/lua/config/mappings.lua b/lua/config/mappings.lua index 63450a3f..a6d3be5a 100755 --- a/lua/config/mappings.lua +++ b/lua/config/mappings.lua @@ -37,6 +37,10 @@ vim.keymap.set('n', 'bs', 'split', { desc = 'Openn Buf Horizont vim.keymap.set('n', 'bv', 'vsp', { desc = 'Open Buf Vertical Split' }) vim.keymap.set('n', 'bt', 'terminal') +-- -- open terminal for R and Python +-- vim.keymap.set('n', 'bR', 'terminal R', { desc = 'Open R Terminal' }) +-- vim.keymap.set('n', 'bP', 'terminal python', { desc = 'Open Python Terminal' }) + -- Editing Keymaps vim.keymap.set('x', 'p', [["_dP"]], { desc = 'Paste without register' }) vim.keymap.set({ 'n', 'v' }, 'd', [["_d"]], { desc = 'Delete without register' }) @@ -45,16 +49,16 @@ vim.keymap.set('n', 'Y', '"+Y') -- replace current word in current scope vim.keymap.set( 'n', - 'r', + 'rw', ':%s/\\<\\>//gI', - { desc = '[R]eplace Current Word in Current Scope' } + { desc = '[R]eplace Current [W]ord in Current Scope' } ) -- replace current word in file scope vim.keymap.set( 'n', - 'R', + 'rW', ':%s/\\<\\>//gI', - { desc = '[R]eplace Current Word in File Scope' } + { desc = '[R]eplace Current [W]ord in File Scope' } ) -- Open vertical split pane @@ -87,7 +91,7 @@ vim.keymap.set({ 'n', 'v' }, 'sw', function() end, { desc = '[S]earch current [W]ord' }) vim.keymap.set('n', 'sp', function() require('telescope.builtin').grep_string({ search = vim.fn.input('Grep Search > ') }) -end, { desc = '[S]search [P]roject' }) +end, { desc = '[S]earch [P]roject' }) vim.keymap.set('n', 'sG', require('telescope.builtin').live_grep, { desc = '[S]earch by [G]rep' }) vim.keymap.set('n', 'sg', ':LiveGrepGitRoot', { desc = '[S]earch by [G]rep on Git Root' }) vim.keymap.set('n', 'sd', require('telescope.builtin').diagnostics, { desc = '[S]earch [D]iagnostics' }) @@ -97,13 +101,43 @@ vim.keymap.set('n', 'sr', require('telescope.builtin').resume, { desc = -- Diagnostic keymaps vim.keymap.set('n', '[d', vim.diagnostic.goto_prev, { desc = 'Go to previous diagnostic message' }) vim.keymap.set('n', ']d', vim.diagnostic.goto_next, { desc = 'Go to next diagnostic message' }) -vim.keymap.set('n', 'e', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' }) --- vim.keymap.set('n', 'vd', function() +-- vim.keymap.set('n', 'ef', vim.diagnostic.open_float, { desc = 'Open floating diagnostic message' }) +-- vim.keymap.set('n', 'ee', function() -- vim.diagnostic.setloclist() -- vim.cmd('lopen') -- end, { desc = 'Open the diagnostics location list' }) --- Refactoring Keymaps +-- local runner = require("quarto.runner") +-- vim.keymap.set('n', 'qrc', runner.run_cell, { desc = '[R]un [C]ell', silent = true }) +-- vim.keymap.set('n', 'qra', runner.run_above, { desc = '[R]un cell and [A]bove', silent = true }) +-- vim.keymap.set('n', "qrA", runner.run_all, { desc = "run all cells", silent = true }) +-- vim.keymap.set('n', "qrl", runner.run_line, { desc = "run line", silent = true }) +-- vim.keymap.set('v', 'qr', runner.run_range, { desc = "run visual range", silent = true }) +-- vim.keymap.set('n', 'qRA', function() +-- runner.run_all(true) +-- end, { desc = "run all cells of all languages", silent = true }) + +-- Latex-specific Keymaps +-- Keybinding to compile LaTeX to PDF using xelatex with latexmk and output to the "output" directory +vim.keymap.set('n', 'll', ':!mkdir -p output && latexmk -pdf -xelatex -output-directory=output -synctex=1 %', + { + desc = 'Compile LaTeX to PDF using xelatex with SyncTeX in the output directory', + noremap = true, + silent = true + }) + + +-- Keybinding to view the compiled PDF in Zathura from the output directory +vim.keymap.set('n', 'lv', function() + local pdf_path = vim.fn.expand('%:p:h') .. '/output/' .. vim.fn.expand('%:t:r') .. '.pdf' + vim.cmd(':silent !nohup zathura ' .. pdf_path .. ' >/dev/null 2>&1 &') +end, { + desc = 'View PDF in Zathura from the output directory', + noremap = true, + silent = true +}) + +-- -- Refactoring Keymaps -- vim.keymap.set({ "x" }, "re", [[lua require('refactoring').refactor('Extract Function')]], -- { noremap = true, silent = true, expr = false, desc = "Extract Function" }) -- vim.keymap.set({ "x" }, "rf", [[lua require('refactoring').refactor('Extract Function To File')]], diff --git a/lua/config/utils.lua b/lua/config/utils.lua index cc6161cf..f9349b95 100755 --- a/lua/config/utils.lua +++ b/lua/config/utils.lua @@ -1,23 +1,27 @@ +-- Function to get the current visual selection +local function get_visual_selection() + vim.cmd 'noau normal! "vy"' + local text = vim.fn.getreg 'v' + vim.fn.setreg('v', {}) + + text = string.gsub(text, '\n', '') + if #text > 0 then + return text + else + return '' + end +end + +-- Function to get the current search query +local function get_search_query() + local word_under_cursor = vim.fn.expand '' + local visual_selection = require('config.utils').get_visual_selection() + + return visual_selection ~= '' and visual_selection or word_under_cursor +end + return { - -- Function to get the current visual selection - get_visual_selection = function() - vim.cmd 'noau normal! "vy"' - local text = vim.fn.getreg 'v' - vim.fn.setreg('v', {}) - - text = string.gsub(text, '\n', '') - if #text > 0 then - return text - else - return '' - end - end, - - -- Function to get the current search query - get_search_query = function() - local word_under_cursor = vim.fn.expand '' - local visual_selection = require('config.utils').get_visual_selection() - - return visual_selection ~= '' and visual_selection or word_under_cursor - end, + get_visual_selection = get_visual_selection, + get_search_query = get_search_query, } + diff --git a/lua/custom/plugins/cmp.lua b/lua/custom/plugins/cmp.lua index 84a9e5e2..9244fe9c 100755 --- a/lua/custom/plugins/cmp.lua +++ b/lua/custom/plugins/cmp.lua @@ -21,15 +21,19 @@ return { -- Set completion options vim.opt.completeopt = { 'menu', 'menuone', 'noselect' } - -- Lazy load snippets from friendly-snippets - require('luasnip.loaders.from_vscode').lazy_load() - -- Import required modules local cmp = require('cmp') local luasnip = require('luasnip') -- Setup luasnip - luasnip.config.setup({}) + luasnip.config.setup({ + history = true, + updateevents = 'TextChanged,TextChangedI', + }) + + -- Lazy load snippets from friendly-snippets and custom snippets + require('luasnip.loaders.from_vscode').lazy_load() + require('luasnip.loaders.from_vscode').load(vim.fn.stdpath('config') .. '/snippets') -- Setup nvim-cmp cmp.setup({ @@ -90,12 +94,6 @@ return { }), }) - -- Additional luasnip configuration - luasnip.config.set_config({ - history = true, - updateevents = 'TextChanged,TextChangedI', - }) - -- Setup for SQL filetype with vim-dadbod-completion cmp.setup.filetype('sql', { sources = cmp.config.sources({ diff --git a/lua/custom/plugins/formatting.lua b/lua/custom/plugins/formatting.lua index 38b695a0..987e1fb3 100755 --- a/lua/custom/plugins/formatting.lua +++ b/lua/custom/plugins/formatting.lua @@ -16,6 +16,10 @@ return { end end, go = { 'gofumpt', 'goimports' }, + yaml = { 'prettier' }, -- Added YAML formatter + bash = { 'shfmt' }, -- Added Bash formatter + rust = { 'rustfmt' }, -- Added Rust formatter + dockerfile = { 'hadolint' }, -- Added Dockerfile formatter } require('conform').setup({ @@ -28,12 +32,15 @@ return { require('mason-tool-installer').setup({ ensure_installed = { - 'stylua', - 'ruff', - 'isort', - 'black', - 'gofumpt', - 'goimports', + 'stylua', -- Lua + 'ruff', -- Python + 'isort', -- Python + 'black', -- Python + 'gofumpt', -- Go + 'goimports', -- Go + 'prettier', -- YAML, JSON, etc. + 'shfmt', -- Bash + 'hadolint', -- Dockerfile }, }) end, diff --git a/lua/custom/plugins/fugitive.lua b/lua/custom/plugins/fugitive.lua index a686da67..54ea0d8c 100755 --- a/lua/custom/plugins/fugitive.lua +++ b/lua/custom/plugins/fugitive.lua @@ -1,47 +1,46 @@ return { 'tpope/vim-fugitive', config = function() - vim.keymap.set('n', 'gs', vim.cmd.Git) + -- General key mappings for Fugitive + vim.keymap.set('n', 'gs', vim.cmd.Git, { desc = 'Open Git status' }) - local jfraeys_fugitive = vim.api.nvim_create_augroup('jfraeys_fugitive', {}) + -- Create an autocommand group for Fugitive-specific settings + local fugitive_augroup = vim.api.nvim_create_augroup('fugitive', { clear = true }) - local autocmd = vim.api.nvim_create_autocmd - autocmd('BufWinEnter', { - group = jfraeys_fugitive, + -- Set up autocommands for Fugitive buffers + vim.api.nvim_create_autocmd('BufWinEnter', { + group = fugitive_augroup, pattern = '*', callback = function() - if vim.bo.ft ~= 'fugitive' then - return - end + if vim.bo.ft ~= 'fugitive' then return end local bufnr = vim.api.nvim_get_current_buf() local opts = { buffer = bufnr, remap = false } - vim.keymap.set('n', 'p', function() - vim.cmd.Git 'push' - end, opts) - - -- rebase always - vim.keymap.set('n', 'P', function() - vim.cmd.Git { 'pull', '--rebase' } - end, opts) - - -- NOTE: It allows me to easily set the branch I am pushing and any tracking - -- needed if I did not set the branch up correctly + -- Key mappings specific to Fugitive buffers + vim.keymap.set('n', 'p', function() vim.cmd.Git('push') end, opts) + vim.keymap.set('n', 'P', function() vim.cmd.Git('pull --rebase') end, opts) vim.keymap.set('n', 't', ':Git push -u origin ', opts) end, }) - vim.keymap.set('n', 'gu', 'diffget //2') - vim.keymap.set('n', 'gh', 'diffget //3') + -- Additional key mappings outside of Fugitive buffers + vim.keymap.set('n', 'gu', 'diffget //2', { desc = 'Get diff for version 2' }) + vim.keymap.set('n', 'gh', 'diffget //3', { desc = 'Get diff for version 3' }) + + -- Set up a faster command for Fugitive in Lua + local function git_command(args) + local cmd = 'Git ' .. args + vim.cmd(cmd) + end + + vim.api.nvim_create_user_command('Git', function(params) + git_command(params.args) + end, { nargs = '*' }) end, cond = function() - -- Function to check if the current directory is a Git repository - local is_git_repo = function() - local git_dir = vim.fn.finddir('.git', '.;') - return git_dir and #git_dir > 0 - end - return is_git_repo() + -- Efficient Git repository check + return vim.fn.isdirectory('.git') == 1 end, } diff --git a/lua/custom/plugins/images.lua b/lua/custom/plugins/images.lua new file mode 100644 index 00000000..e995654c --- /dev/null +++ b/lua/custom/plugins/images.lua @@ -0,0 +1,104 @@ +return { + -- { + -- 'vhyrro/luarocks.nvim', + -- priority = 1001, + -- opts = { + -- rocks = { 'magick' }, + -- }, + -- event = 'VeryLazy', -- Adjust this based on your needs + -- }, + -- { + -- 'willothy/wezterm.nvim', + -- config = true, + -- event = 'BufWinEnter', -- Or another appropriate event + -- }, + -- { + -- '3rd/image.nvim', + -- enabled = true, + -- commit = 'deb158d', + -- dev = false, + -- ft = { 'markdown', 'quarto', 'vimwiki' }, + -- config = function() + -- local image = require 'image' + -- image.setup { + -- backend = 'wezterm', + -- integrations = { + -- markdown = { + -- enabled = true, + -- only_render_image_at_cursor = true, + -- filetypes = { 'markdown', 'vimwiki', 'quarto' }, + -- }, + -- }, + -- editor_only_render_when_focused = false, + -- window_overlap_clear_enabled = true, + -- tmux_show_only_in_active_window = true, + -- window_overlap_clear_ft_ignore = { 'cmp_menu', 'cmp_docs', 'scrollview', 'scrollview_sign' }, + -- max_width = nil, + -- max_height = nil, + -- max_width_window_percentage = nil, + -- max_height_window_percentage = 30, + -- kitty_method = 'normal', + -- } + -- + -- local function clear_all_images() + -- local bufnr = vim.api.nvim_get_current_buf() + -- local images = image.get_images { buffer = bufnr } + -- for _, img in ipairs(images) do + -- img:clear() + -- end + -- end + -- + -- local function get_image_at_cursor(buf) + -- local images = image.get_images { buffer = buf } + -- local row = vim.api.nvim_win_get_cursor(0)[1] - 1 + -- for _, img in ipairs(images) do + -- if img.geometry ~= nil and img.geometry.y == row then + -- local og_max_height = img.global_state.options.max_height_window_percentage + -- img.global_state.options.max_height_window_percentage = nil + -- return img, og_max_height + -- end + -- end + -- return nil + -- end + -- + -- local create_preview_window = function(img, og_max_height) + -- local buf = vim.api.nvim_create_buf(false, true) + -- local win_width = vim.api.nvim_get_option_value('columns', {}) + -- local win_height = vim.api.nvim_get_option_value('lines', {}) + -- local win = vim.api.nvim_open_win(buf, true, { + -- relative = 'editor', + -- style = 'minimal', + -- width = win_width, + -- height = win_height, + -- row = 0, + -- col = 0, + -- zindex = 1000, + -- }) + -- vim.keymap.set('n', 'q', function() + -- vim.api.nvim_win_close(win, true) + -- img.global_state.options.max_height_window_percentage = og_max_height + -- end, { buffer = buf }) + -- return { buf = buf, win = win } + -- end + -- + -- local handle_zoom = function(bufnr) + -- local img, og_max_height = get_image_at_cursor(bufnr) + -- if img == nil then + -- return + -- end + -- + -- local preview = create_preview_window(img, og_max_height) + -- image.hijack_buffer(img.path, preview.win, preview.buf) + -- end + -- + -- vim.keymap.set('n', 'io', function() + -- local bufnr = vim.api.nvim_get_current_buf() + -- handle_zoom(bufnr) + -- end, { buffer = true, desc = 'image [o]pen' }) + -- + -- vim.keymap.set('n', 'ic', clear_all_images, { desc = 'image [c]lear' }) + -- end, + -- }, + -- +} + diff --git a/lua/custom/plugins/linting.lua b/lua/custom/plugins/linting.lua index d7933cd0..c1283506 100755 --- a/lua/custom/plugins/linting.lua +++ b/lua/custom/plugins/linting.lua @@ -6,14 +6,21 @@ return { 'BufNewFile', }, config = function() + -- Linter configurations based on file type require('lint').linters_by_ft = { python = { 'ruff' }, go = { 'golangcilint' }, yaml = { 'yamllint' }, + bash = { 'shellcheck' }, + lua = { 'luacheck' }, -- Added Lua linter + rust = { 'clippy' }, -- Use `clippy` for Rust linting + dockerfile = { 'hadolint' }, -- Added Dockerfile linter } + -- Autocommand group for triggering linting local lint_augroup = vim.api.nvim_create_augroup('lint', { clear = true }) + -- Trigger linting on buffer enter, write, and insert leave vim.api.nvim_create_autocmd({ 'BufEnter', 'BufWritePost', 'InsertLeave' }, { group = lint_augroup, callback = function() @@ -21,17 +28,23 @@ return { end, }) + -- Keybinding to manually lint the current buffer vim.keymap.set('n', 'l', function() require('lint').try_lint() end, { desc = 'Lint the current buffer' }) + -- Mason tool installer setup require('mason-tool-installer').setup({ ensure_installed = { - 'ruff', - -- 'mypy', - 'golangci-lint', - 'yamllint', + 'ruff', -- Python + -- 'mypy', -- Uncomment if needed for additional Python linting + 'golangci-lint', -- Go + 'yamllint', -- YAML + 'shellcheck', -- Bash + 'luacheck', -- Lua + 'hadolint', -- Dockerfile }, }) end, } + diff --git a/lua/custom/plugins/lsp-config.lua b/lua/custom/plugins/lsp-config.lua index c226d213..9aac69bf 100755 --- a/lua/custom/plugins/lsp-config.lua +++ b/lua/custom/plugins/lsp-config.lua @@ -1,7 +1,6 @@ return { 'neovim/nvim-lspconfig', dependencies = { - -- Automatically install LSPs to stdpath for neovim { 'williamboman/mason.nvim', config = true }, 'williamboman/mason-lspconfig.nvim', 'WhoIsSethDaniel/mason-tool-installer.nvim', @@ -13,77 +12,35 @@ return { opts = {}, }, - -- Additional lua configuration, makes nvim stuff amazing! + -- Additional Lua configuration 'folke/neodev.nvim', }, config = function() - local on_attach = function(client, bufnr) - local nmap = function(keys, func, desc) - if desc then - desc = 'LSP: ' .. desc - end - vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) - end - - -- Key mappings for LSP features - nmap('rn', vim.lsp.buf.rename, '[R]e[n]ame') - nmap('ca', function() - vim.lsp.buf.code_action(require('telescope.themes').get_dropdown({ - winblend = 10, - previewer = false, - })) - end, '[C]ode [A]ction') - - nmap('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') - nmap('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') - nmap('gI', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') - nmap('D', require('telescope.builtin').lsp_type_definitions, 'Type [D]efinition') - nmap('ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') - nmap('ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') - - nmap('K', vim.lsp.buf.hover, 'Hover Documentation') - nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') - - nmap('gD', vim.lsp.buf.declaration, '[G]oto [D]eclaration') - nmap('gv', ':vsplit:lua vim.lsp.buf.declaration()', '[G]oto [V]irtual Text') - nmap('wa', vim.lsp.buf.add_workspace_folder, '[W]orkspace [A]dd Folder') - nmap('wr', vim.lsp.buf.remove_workspace_folder, '[W]orkspace [R]emove Folder') - nmap('wl', function() - print(vim.inspect(vim.lsp.buf.list_workspace_folders())) - end, '[W]orkspace [L]ist Folders') - end - + -- General capabilities for LSP servers local capabilities = vim.lsp.protocol.make_client_capabilities() - if pcall(require, 'cmp_nvim_lsp') then - capabilities = require('cmp_nvim_lsp').default_capabilities() + local has_cmp, cmp_nvim_lsp = pcall(require, 'cmp_nvim_lsp') + if has_cmp then + capabilities = cmp_nvim_lsp.default_capabilities() end - require('neodev').setup({ - library = { - plugins = { 'nvim-dap-ui' }, - types = true, - }, - }) - + -- LSP server configurations local servers = { + bashls = { filetypes = { 'sh', 'bash' } }, clangd = {}, gopls = { settings = { gopls = { + gofumpt = true, + staticcheck = true, completeUnimported = true, usePlaceholders = true, - analysis = { - unusedParams = true, + analyses = { + unusedparams = true, }, }, }, }, - htmx = { - filetypes = { 'html' }, - }, - ruff_lsp = { - filetypes = { 'python' }, - }, + ruff_lsp = { filetypes = { 'python' } }, pyright = { filetypes = { 'python' }, settings = { @@ -97,102 +54,99 @@ return { }, }, }, - rust_analyzer = { - cmd = { 'rustup', 'run', 'stable', 'rust-analyzer' }, + rust_analyzer = { cmd = { 'rustup', 'run', 'stable', 'rust-analyzer' } }, + texlab = { + flags = { + debounce_text_changes = 150, + }, + settings = { + texlab = { + build = { + executable = "latexmk", + args = { "-pdf", "-xelatex", "-output-directory=output", "-interaction=nonstopmode", "-synctex=1", "%f" }, + onSave = true, + }, + forwardSearch = { + executable = "zathura", + args = { "--synctex-forward", "%l:1:%f", "%p" }, + }, + }, + }, }, lua_ls = { filetypes = { 'lua' }, settings = { Lua = { - runtime = { - version = 'LuaJIT', - path = vim.split(package.path, ';'), - }, - diagnostics = { - globals = { 'vim' }, - }, + runtime = { version = 'LuaJIT', path = vim.split(package.path, ';') }, + diagnostics = { globals = { 'vim' } }, workspace = { library = vim.api.nvim_get_runtime_file('', true), checkThirdParty = false, }, - telemetry = { - enable = false, - }, + telemetry = { enable = false }, }, }, }, - ocamllsp = { - manual_install = true, - filetypes = { 'ocaml', 'ocaml.interface', 'ocaml.cram', 'ocaml.menhir' }, - settings = { - codelens = { enabled = true }, - inlayHints = { enable = true }, - }, - }, yamlls = { filetypes = { 'yaml' }, settings = { yaml = { schemas = { - ['https://json.schemasstore.org/github-workflow.json'] = '/.github/workflows/*.{yml,yaml}', + ['https://json.schemastore.org/github-workflow.json'] = '/.github/workflows/*.{yml,yaml}', }, }, }, }, - taplo = { - filetypes = { 'toml' }, - }, - dockerls = { - filetypes = { 'Dockerfile' }, - }, + taplo = { filetypes = { 'toml' } }, + dockerls = { filetypes = { 'Dockerfile' } }, } - local ensure_installed = vim.tbl_filter(function(key) - local t = servers[key] - if type(t) == 'table' then - return not t.manual_install - else - return t - end - end, vim.tbl_keys(servers)) - - require('mason').setup({ - ui = { - icons = { - package_installed = '✓', - package_pending = '➜', - package_uninstalled = '✗', - }, + -- Setup LSP servers via mason-lspconfig + require('mason-lspconfig').setup({ + ensure_installed = vim.tbl_keys(servers), + handlers = { + function(server_name) + require('lspconfig')[server_name].setup({ + capabilities = capabilities, + }) + end, }, }) - local mason_lspconfig = require('mason-lspconfig') - mason_lspconfig.setup({ - ensure_installed = ensure_installed, - }) + -- Setup specific LSP servers with custom configuration + for server, config in pairs(servers) do + require('lspconfig')[server].setup(vim.tbl_extend('force', { + capabilities = capabilities, + on_attach = function(client, bufnr) + local function nmap(keys, func, desc) + if desc then + desc = 'LSP: ' .. desc + end + vim.keymap.set('n', keys, func, { buffer = bufnr, desc = desc }) + end - for name, config in pairs(servers) do - if config then - require('lspconfig')[name].setup({ - capabilities = capabilities, - on_attach = on_attach, - settings = config.settings, - filetypes = config.filetypes, - cmd = config.cmd, - }) - end - end - - require('cmp') - - local sign = function(opts) - vim.fn.sign_define(opts.name, { - texthl = opts.name, - text = opts.text, - numhl = '', - }) + nmap('rn', vim.lsp.buf.rename, '[R]e[n]ame') + nmap('ca', function() + vim.lsp.buf.code_action(require('telescope.themes').get_dropdown({ + winblend = 10, + previewer = false, + })) + end, '[C]ode [A]ction') + + nmap('gd', require('telescope.builtin').lsp_definitions, '[G]oto [D]efinition') + nmap('gr', require('telescope.builtin').lsp_references, '[G]oto [R]eferences') + nmap('gI', require('telescope.builtin').lsp_implementations, '[G]oto [I]mplementation') + nmap('D', require('telescope.builtin').lsp_type_definitions, 'Type [D]efinition') + nmap('ds', require('telescope.builtin').lsp_document_symbols, '[D]ocument [S]ymbols') + nmap('ws', require('telescope.builtin').lsp_dynamic_workspace_symbols, '[W]orkspace [S]ymbols') + + nmap('K', vim.lsp.buf.hover, 'Hover Documentation') + nmap('', vim.lsp.buf.signature_help, 'Signature Documentation') + end, + }, config)) end + -- Diagnostics configuration vim.diagnostic.config({ underline = true, severity_sort = true, @@ -202,19 +156,34 @@ return { spacing = 2, }, float = { - source = 'if_many', + Source = 'if_many', border = 'rounded', }, }) + local sign = function(opts) + vim.fn.sign_define(opts.name, { + texthl = opts.name, + text = opts.text, + numhl = '', + }) + end + sign({ name = 'DiagnosticSignError', text = '✘' }) sign({ name = 'DiagnosticSignWarn', text = '▲' }) sign({ name = 'DiagnosticSignHint', text = '⚑' }) sign({ name = 'DiagnosticSignInfo', text = '»' }) - vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = 'rounded' }) - vim.lsp.handlers['textDocument/signatureHelp'] = - vim.lsp.with(vim.lsp.handlers.signature_help, { border = 'rounded' }) + -- Fidget configuration (LSP progress) + require('fidget').setup({}) + + -- Neodev setup for improved Lua development + require('neodev').setup({ + library = { + plugins = { 'nvim-dap-ui' }, + types = true, + }, + }) end, } diff --git a/lua/custom/plugins/markdown-preview.lua b/lua/custom/plugins/markdown-preview.lua new file mode 100644 index 00000000..ab48dc3a --- /dev/null +++ b/lua/custom/plugins/markdown-preview.lua @@ -0,0 +1,4 @@ +return { + 'iamcco/markdown-preview.nvim', +} + diff --git a/lua/custom/plugins/quarto.lua b/lua/custom/plugins/quarto.lua new file mode 100644 index 00000000..aa73c63a --- /dev/null +++ b/lua/custom/plugins/quarto.lua @@ -0,0 +1,72 @@ +return { + -- -- Quarto support for data science + -- { + -- 'quarto-dev/quarto-nvim', + -- ft = { 'quarto' }, + -- opts = { + -- codeRunner = { + -- enabled = true, + -- default_method = "molten", + -- }, + -- }, + -- dependencies = { + -- 'jmbuhr/otter.nvim', -- For language features in code cells + -- 'nvim-treesitter/nvim-treesitter', -- Syntax highlighting and code understanding + -- }, + -- }, + -- + -- -- Jupytext integration for working with Jupyter notebooks + -- { + -- 'GCBallesteros/jupytext.nvim', + -- opts = { + -- custom_language_formatting = { + -- python = { extension = 'qmd', style = 'quarto', force_ft = 'quarto' }, + -- r = { extension = 'qmd', style = 'quarto', force_ft = 'quarto' }, + -- }, + -- }, + -- }, + -- + -- -- Image management and clipboard integration + -- { + -- 'HakonHarnes/img-clip.nvim', + -- event = 'BufEnter', + -- ft = { 'markdown', 'quarto', 'latex' }, + -- opts = { + -- default = { dir_path = 'img' }, + -- filetypes = { + -- markdown = { url_encode_path = true, template = '![$CURSOR]($FILE_PATH)' }, + -- quarto = { url_encode_path = true, template = '![$CURSOR]($FILE_PATH)' }, + -- }, + -- }, + -- config = function(_, opts) + -- require('img-clip').setup(opts) + -- vim.keymap.set('n', 'ii', ':PasteImage', { desc = 'Insert image from clipboard' }) + -- end, + -- }, + -- + -- -- Equation preview in markdown/quarto files + -- { + -- 'jbyuki/nabla.nvim', + -- keys = { + -- { 'qm', ':lua require"nabla".toggle_virt()', { desc = 'Toggle math equations' } }, + -- }, + -- }, + -- + -- -- Molten for interactive code execution + -- { + -- 'benlubas/molten-nvim', + -- enabled = true, + -- build = ':UpdateRemotePlugins', + -- init = function() + -- vim.g.molten_image_provider = 'image.nvim' + -- vim.g.molten_output_win_max_height = 20 + -- vim.g.molten_auto_open_output = false + -- end, + -- keys = { + -- { 'n', 'mi', ':MoltenInit', { desc = 'Molten init' } }, + -- { 'v', 'mv', ':MoltenEvaluateVisual', { desc = 'Evaluate visual selection' } }, + -- { 'n', 'mr', ':MoltenReevaluateCell', { desc = 'Re-evaluate cell' } }, + -- }, + -- }, +} + diff --git a/lua/custom/plugins/refactoring.lua b/lua/custom/plugins/refactoring.lua index c948c743..fb450910 100755 --- a/lua/custom/plugins/refactoring.lua +++ b/lua/custom/plugins/refactoring.lua @@ -5,17 +5,17 @@ return { 'nvim-treesitter/nvim-treesitter', }, keys = { - { 'ef', ":lua require('refactoring').refactor('Extract Function')", mode = 'x', desc = 'Extract Function' }, - { 'eff', ":lua require('refactoring').refactor('Extract Function To File')", mode = 'x', desc = 'Extract Function To File' }, - { 'ev', ":lua require('refactoring').refactor('Extract Variable')", mode = 'x', desc = 'Extract Variable' }, - { 'eI', ":lua require('refactoring').refactor('Inline Function')", mode = 'n', desc = 'Inline Function' }, - { 'ei', ":lua require('refactoring').refactor('Inline Variable')", mode = { 'n', 'x' }, desc = 'Inline Variable' }, - { 'eb', ":lua require('refactoring').refactor('Extract Block')", mode = 'n', desc = 'Extract Block' }, - { 'ebf', ":lua require('refactoring').refactor('Extract Block To File')", mode = 'n', desc = 'Extract Block To File' }, + { 'ef', ":lua require('refactoring').refactor('Extract Function')", mode = 'x', desc = 'Extract Function' }, + { 'eff', ":lua require('refactoring').refactor('Extract Function To File')", mode = 'x', desc = 'Extract Function To File' }, + { 'ev', ":lua require('refactoring').refactor('Extract Variable')", mode = 'x', desc = 'Extract Variable' }, + { 'eI', ":lua require('refactoring').refactor('Inline Function')", mode = 'n', desc = 'Inline Function' }, + { 'ei', ":lua require('refactoring').refactor('Inline Variable')", mode = { 'n', 'x' }, desc = 'Inline Variable' }, + { 'eb', ":lua require('refactoring').refactor('Extract Block')", mode = 'n', desc = 'Extract Block' }, + { 'ebf', ":lua require('refactoring').refactor('Extract Block To File')", mode = 'n', desc = 'Extract Block To File' }, }, config = function() require('refactoring').setup({ - show_success_message = false, + show_success_message = true, }) end, } diff --git a/lua/custom/plugins/tree-sitter.lua b/lua/custom/plugins/tree-sitter.lua index c16b50ae..a22d7049 100755 --- a/lua/custom/plugins/tree-sitter.lua +++ b/lua/custom/plugins/tree-sitter.lua @@ -4,7 +4,6 @@ return { dependencies = { 'nvim-treesitter/nvim-treesitter-textobjects', 'https://github.com/apple/pkl-neovim.git', - 'windwp/nvim-ts-autotag', }, build = ':TSUpdate', config = function() @@ -12,7 +11,8 @@ return { local ts = require('nvim-treesitter.configs') ts.setup({ ensure_installed = { - 'c', 'cpp', 'lua', 'python', 'go', 'rust', 'vimdoc', 'vim' + 'bash', 'c', 'cpp', 'lua', 'python', 'go', 'markdown', 'markdown_inline', 'r', 'rust', 'vimdoc', 'vim', 'yaml', + 'query' }, ignore_install = { '' }, highlight = { @@ -23,10 +23,10 @@ return { incremental_selection = { enable = true, keymaps = { - init_selection = '', - node_incremental = '', - scope_incremental = '', - node_decremental = '', + init_selection = 'gnn', + node_incremental = 'grn', + scope_incremental = 'grc', + node_decremental = 'grm', }, }, textobjects = { @@ -73,16 +73,6 @@ return { }, }, }) - - -- Autotag setup - require('nvim-ts-autotag').setup({ - enable = true, - }) end, - opts = { - autotag = { - enable = true, - }, - }, } diff --git a/lua/custom/plugins/trouble.lua b/lua/custom/plugins/trouble.lua index acc8b660..afd8d018 100755 --- a/lua/custom/plugins/trouble.lua +++ b/lua/custom/plugins/trouble.lua @@ -2,11 +2,11 @@ return { 'folke/trouble.nvim', cmd = "Trouble", opts = { - auto_open = false, - auto_close = true, - auto_preview = true, - auto_fold = true, - use_diagnostic_signs = true, + auto_open = false, + auto_close = true, + auto_preview = true, + auto_fold = true, + use_diagnostic_signs = true, }, keys = { { "tt", "Trouble diagnostics toggle", desc = "Diagnostics (Trouble)" }, diff --git a/queries/markdown/textobjects.scm b/queries/markdown/textobjects.scm new file mode 100644 index 00000000..d3cfcccb --- /dev/null +++ b/queries/markdown/textobjects.scm @@ -0,0 +1,15 @@ +; (atx_heading +; heading_content: (_) @class.inner) @class.outer +; +; (setext_heading +; heading_content: (_) @class.inner) @class.outer +; +; (thematic_break) @class.outer + +(fenced_code_block (code_fence_content) @block.inner) @block.outer + +[ + (paragraph) + (list) +] @block.outer + diff --git a/queries/r/textobjects.scm b/queries/r/textobjects.scm new file mode 100644 index 00000000..2b834dec --- /dev/null +++ b/queries/r/textobjects.scm @@ -0,0 +1,50 @@ +; block +; call +(call) @call.outer + +(arguments) @call.inner + +; class +; comment +(comment) @comment.outer + +; conditional +(if_statement + condition: (_)? @conditional.inner) @conditional.outer + +; function +[ + (function_definition) +] @function.outer + +(function_definition + [ + (call) + (binary_operator) + ] @function.inner) @function.outer + + +; loop +[ + (while_statement) + (for_statement) + (repeat_statement) +] @loop.outer + +(while_statement + body: (_) @loop.inner) + +(repeat_statement + body: (_) @loop.inner) + +(for_statement + body: (_) @loop.inner) + +; statement + +(program + (_) @statement.outer) + +; number +(float) @number.inner +