diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index e96a388..fcf1db9 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -29,7 +29,7 @@ jobs: matrix: os: [ubuntu-latest, macos-latest] steps: - - uses: actions/checkout@v7 + - uses: actions/checkout@v4 - uses: wimpysworld/nothing-but-nix@main if: runner.os == 'Linux' with: @@ -37,7 +37,7 @@ jobs: - uses: cachix/install-nix-action@v31 with: github_access_token: ${{ secrets.GH_TOKEN }} - - uses: cachix/cachix-action@v17 + - uses: cachix/cachix-action@v14 with: name: rde authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' diff --git a/.github/workflows/flakehub-publish-rolling.yml b/.github/workflows/flakehub-publish-rolling.yml index 50ccb47..57250d0 100644 --- a/.github/workflows/flakehub-publish-rolling.yml +++ b/.github/workflows/flakehub-publish-rolling.yml @@ -10,7 +10,7 @@ jobs: id-token: "write" contents: "read" steps: - - uses: "actions/checkout@v7" + - uses: "actions/checkout@v5" with: persist-credentials: false - uses: "DeterminateSystems/determinate-nix-action@v3" diff --git a/.github/workflows/update.yml b/.github/workflows/update.yml index 3bd7493..a65fbdc 100644 --- a/.github/workflows/update.yml +++ b/.github/workflows/update.yml @@ -10,13 +10,13 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout repository - uses: actions/checkout@v7 + uses: actions/checkout@v4 - uses: wimpysworld/nothing-but-nix@main with: hatchet-protocol: 'carve' - name: Install Determinate Nix uses: DeterminateSystems/determinate-nix-action@v3 - - uses: cachix/cachix-action@v17 + - uses: cachix/cachix-action@v14 with: name: rde authToken: '${{ secrets.CACHIX_AUTH_TOKEN }}' diff --git a/init.lua b/init.lua index 11b9975..8db9da5 100644 --- a/init.lua +++ b/init.lua @@ -1,5 +1,7 @@ -local Config = require('config') -_G.Config = Config -- keep global alias for keymaps/backward compatibility +_G.Config = {} +local nix = require('config.nix').init { non_nix_value = true } +Config.isNixCats = nix.is_nix +Config.nixConfig = nix require('lze').register_handlers(require('nixCatsUtils.lzUtils').for_cat) @@ -10,11 +12,8 @@ if not Config.isNixCats then local mini_path = path_package .. 'pack/deps/start/mini.nvim' if not vim.uv.fs_stat(mini_path) then vim.cmd('echo "Installing `mini.nvim`" | redraw') - -- Pin to the stable branch for reproducible non-Nix installs. - -- Change the tag/branch here if you need a newer version. - local mini_nvim_tag = 'stable' local clone_cmd = { - 'git', 'clone', '--filter=blob:none', '--branch=' .. mini_nvim_tag, + 'git', 'clone', '--filter=blob:none', 'https://github.com/echasnovski/mini.nvim', mini_path } vim.fn.system(clone_cmd) diff --git a/lua/config/init.lua b/lua/config/init.lua deleted file mode 100644 index 60b80e5..0000000 --- a/lua/config/init.lua +++ /dev/null @@ -1,10 +0,0 @@ ---- Shared configuration / state table. ---- Plugin submodules attach their helpers to this table at runtime. -local M = {} - --- Detect whether this Neovim was launched via nixCats. -local nix = require('config.nix').init { non_nix_value = true } -M.isNixCats = nix.is_nix -M.nixConfig = nix - -return M diff --git a/lua/keymap/core.lua b/lua/keymap/core.lua deleted file mode 100644 index 8c0abe3..0000000 --- a/lua/keymap/core.lua +++ /dev/null @@ -1,44 +0,0 @@ -local Config = require('config') - --- Basic mappings ============================================================= --- NOTE: Most basic mappings come from 'mini.basics' --- Shorter version of the most frequent way of going outside of terminal window -vim.keymap.set('t', '', [[h]]) --- Select all --- vim.keymap.set({ "n", "v", "x" }, "", "gg3vG$", { noremap = true, silent = true, desc = "Select all" }) --- Escape deletes highlights -vim.keymap.set("n", "", "nohlsearch") --- Paste before/after linewise -local cmd = vim.fn.has('nvim-0.12') == 1 and 'iput' or 'put' -vim.keymap.set({ 'n', 'x' }, '[p', 'exe "' .. cmd .. '! " . v:register', { desc = 'Paste Above' }) -vim.keymap.set({ 'n', 'x' }, ']p', 'exe "' .. cmd .. ' " . v:register', { desc = 'Paste Below' }) - -vim.keymap.set({ "n", "v", "x" }, "p", '"+p', { noremap = true, silent = true, desc = "Paste from clipboard" }) -vim.keymap.set({ "n", "v", "x" }, "y", '"+y', { noremap = true, silent = true, desc = "Copy toclipboard" }) - --- Create global tables with information about clue group in certain modes --- Structure of tables is taken to be compatible with 'mini.clue'. -Config.leader_group_clues = { - { mode = 'n', keys = 'a', desc = '+AI' }, - { mode = 'n', keys = 'b', desc = '+Buffer' }, - { mode = 'n', keys = 'e', desc = '+Explore' }, - { mode = 'n', keys = 'f', desc = '+Find' }, - { mode = 'n', keys = 'fl', desc = '+LSP' }, - { mode = 'n', keys = 'fa', desc = '+Git' }, - { mode = 'n', keys = 'g', desc = '+Git' }, - { mode = 'n', keys = 'l', desc = '+LSP' }, - { mode = 'n', keys = 'L', desc = '+Lua/Log' }, - { mode = 'n', keys = 'o', desc = '+Other' }, - { mode = 'n', keys = 'r', desc = '+R' }, - { mode = 'n', keys = 's', desc = '+Send' }, - { mode = 'n', keys = 'd', desc = '+Debug' }, - { mode = 'n', keys = 't', desc = '+Terminal' }, - { mode = 'n', keys = 'u', desc = '+UI' }, - { mode = 'n', keys = 'v', desc = '+Visits' }, - { mode = 'n', keys = 'w', desc = '+Windows' }, - { mode = 'x', keys = 'l', desc = '+LSP' }, - { mode = 'x', keys = 'r', desc = '+R' }, - { mode = 'n', keys = 'z', desc = '+ZK' }, - { mode = 'n', keys = 'zr', desc = '+Reviews' }, - { mode = 'x', keys = 'a', desc = '+AI' }, -} diff --git a/lua/keymap/helpers.lua b/lua/keymap/helpers.lua deleted file mode 100644 index 10cdaa2..0000000 --- a/lua/keymap/helpers.lua +++ /dev/null @@ -1,25 +0,0 @@ -local M = {} - ----Create a normal-mode `` mapping. -function M.nmap_leader(suffix, rhs, desc, opts) - opts = opts or {} - opts.desc = desc - vim.keymap.set('n', '' .. suffix, rhs, opts) -end - ----Create a visual-mode `` mapping. -function M.xmap_leader(suffix, rhs, desc, opts) - opts = opts or {} - opts.desc = desc - vim.keymap.set('x', '' .. suffix, rhs, opts) -end - ----Create a normal-mode LSP keymap with an "(LSP)" suffix in the description. -function M.nmap_lsp(keys, func, desc) - if desc then - desc = desc .. "(LSP)" - end - vim.keymap.set("n", keys, func, { desc = desc }) -end - -return M diff --git a/lua/keymap/leader.lua b/lua/keymap/leader.lua deleted file mode 100644 index 795079f..0000000 --- a/lua/keymap/leader.lua +++ /dev/null @@ -1,264 +0,0 @@ -local Config = require('config') -local helpers = require('keymap.helpers') -local nmap_leader = helpers.nmap_leader -local xmap_leader = helpers.xmap_leader -local nmap_lsp = helpers.nmap_lsp - --- stylua: ignore start - --- Switch buffers -nmap_leader('', 'bnext', 'Next buffer') -nmap_leader('', 'bprev', 'Prev buffer') - --- a is for 'AI' -nmap_leader("aa", "CodeCompanion /agent", "Agent chat (@{agent} tools)") -nmap_leader("ac", "CodeCompanionChat Toggle", "Chat Toggle") -nmap_leader("aC", function() - local chat = require("codecompanion").last_chat() - if not chat then - return vim.notify("No CodeCompanion chat to compact", vim.log.levels.WARN) - end - require("codecompanion.interactions.chat.context_management.compaction").compact(chat, { min_token_savings = 0 }) -end, "Compact chat") -nmap_leader("ag", "CodeCompanion /commit", "Generate commit message") -nmap_leader("ai", "CodeCompanionActions", "Chat Action") -nmap_leader("al", "CodeCompanion /lsp", "Explain LSP Diagnostics") -nmap_leader("an", "CodeCompanionChat Add", "Chat New") -nmap_leader("as", "CodeCompanion /suggest", "Suggest Improvements") -nmap_leader("aw", "CodeCompanion /tdd", "Workflow: plan, implement, test") -nmap_leader("ax", "CodeCompanion /fixer", "Code Fixer") -xmap_leader("aa", "CodeCompanion /agent", "Agent on selection") -xmap_leader("ae", "CodeCompanion /explain", "Explain Code") -xmap_leader("af", "CodeCompanion /fix", "Fix Code") -xmap_leader("ap", "CodeCompanion /expert", "Code Expert") -xmap_leader("as", "CodeCompanion /suggest", "Suggest Improvements") -nmap_leader("ak", "CodeCompanionChat adapter=codex", "Chat with Codex") - --- b is for 'buffer' -nmap_leader('bb', 'b#', 'Alternate') -nmap_leader('bd', 'lua MiniBufremove.delete()', 'Delete') -nmap_leader('bD', 'lua MiniBufremove.delete(0, true)', 'Delete!') -nmap_leader('bs', 'lua Config.new_scratch_buffer()', 'Scratch') -nmap_leader('bw', 'lua MiniBufremove.wipeout()', 'Wipeout') -nmap_leader('bW', 'lua MiniBufremove.wipeout(0, true)', 'Wipeout!') -nmap_leader('bq', 'qall', 'Quit all') - --- e is for 'explore' and 'edit' -nmap_leader('ed', 'lua MiniFiles.open()', 'Directory') -nmap_leader('ef', 'lua Config.try_opendir()', 'File directory') -nmap_leader('es', 'lua MiniSessions.select()', 'Sessions') -nmap_leader('eq', 'lua Config.toggle_quickfix()', 'Quickfix') -nmap_leader('ez', 'lua MiniFiles.open(os.getenv("ZK_NOTEBOOK_DIR"))', 'Notes directory') - --- f is for 'fuzzy find' -nmap_leader('f/', 'Pick history scope="/"', '"/" history') -nmap_leader('f:', 'Pick history scope=":"', '":" history') -nmap_leader('f,', 'Pick visit_labels', 'Visit labels') -nmap_leader('faa', 'Pick git_hunks scope="staged"', 'Added hunks (all)') -nmap_leader('faA', 'Pick git_hunks path="%" scope="staged"', 'Added hunks (current)') -nmap_leader('fb', 'Pick buffers', 'Buffers') -nmap_leader(',', 'Pick buffers', 'Buffers') -nmap_leader('fac', 'Pick git_commits', 'Commits (all)') -nmap_leader('faC', 'Pick git_commits path="%"', 'Commits (current)') -nmap_leader('fd', 'Pick diagnostic scope="all"', 'Diagnostic workspace') -nmap_leader('fD', 'Pick diagnostic scope="current"', 'Diagnostic buffer') -nmap_leader('ff', 'Pick files', 'Files') -nmap_leader('fg', 'Pick grep_live', 'Grep live') -nmap_leader('fG', 'Pick grep pattern=""', 'Grep current word') -nmap_leader('fh', 'Pick help', 'Help tags') -nmap_leader('fH', 'Pick hl_groups', 'Highlight groups') -nmap_leader('fj', 'Pick buf_lines scope="all"', 'Lines (all)') -nmap_leader('fJ', 'Pick buf_lines scope="current"', 'Lines (current)') -nmap_leader('fam', 'Pick git_hunks', 'Modified hunks (all)') -nmap_leader('faM', 'Pick git_hunks path="%"', 'Modified hunks (current)') -nmap_leader('fm', 'Pick marks', 'Marks') -nmap_leader('fn', 'ZkNotes', "Notes") -nmap_leader('fk', 'Pick keymaps', 'Keymaps') -nmap_leader('fR', 'Pick resume', 'Resume') -nmap_leader('fp', 'Pick files', 'Files') -nmap_leader('fq', 'Pick list scope="quickfix"', 'Quickfix') -nmap_leader('fr', 'Pick lsp scope="references"', 'References (LSP)') -nmap_leader('flr', 'Pick lsp scope="references"', 'References (LSP)') -nmap_leader('fS', 'Pick lsp scope="workspace_symbol"', 'Symbols workspace (LSP)') -nmap_leader('flS', 'Pick lsp scope="workspace_symbol"', 'Symbols workspace (LSP)') -nmap_leader('fs', 'Pick lsp scope="document_symbol"', 'Symbols buffer (LSP)') -nmap_leader('fls', 'Pick lsp scope="document_symbol"', 'Symbols buffer (LSP)') -nmap_leader('fld', 'Pick lsp scope="definition"', 'Definition (LSP)') -nmap_leader('flD', 'Pick lsp scope="declaration"', 'Declaration (LSP)') -nmap_leader('flt', 'Pick lsp scope="type_definition"', 'Type Definition (LSP)') -nmap_leader('fv', 'Pick visit_paths cwd=""', 'Visit paths (all)') -nmap_leader('fV', 'Pick visit_paths', 'Visit paths (cwd)') - --- g is for git -local git_log_cmd = [[Git log --pretty=format:\%h\ \%as\ │\ \%s --topo-order]] - -nmap_leader('gc', 'Git commit', 'Commit') -nmap_leader('gC', 'Git commit --amend', 'Commit amend') -nmap_leader('gd', 'Git diff', 'Diff') -nmap_leader('gD', 'Git diff -- %', 'Diff buffer') -nmap_leader("gg", "Neogit", "Open Neogit UI") -nmap_leader('gl', '' .. git_log_cmd .. '', 'Log') -nmap_leader('gL', '' .. git_log_cmd .. ' --follow -- %', 'Log buffer') -nmap_leader('go', 'lua MiniDiff.toggle_overlay()', 'Toggle overlay') -nmap_leader('gp', 'Git pull', 'Pull') -nmap_leader('gP', 'Git push', 'Push') -nmap_leader('gs', 'lua MiniGit.show_at_cursor()', 'Show at cursor') - -xmap_leader('gs', 'lua MiniGit.show_at_cursor()', 'Show at selection') - --- j/k navigate quickfix -nmap_leader("j", 'cnextzz', "Quickfix next") -nmap_leader("k", 'cprevzz', "Quickfix prev") - --- l is for 'LSP' (Language Server Protocol) -vim.keymap.set({ 'n' }, 'grd', 'lua vim.lsp.buf.definition()', { desc = 'Definition' }) -vim.keymap.set({ 'n' }, 'grk', 'lua vim.lsp.buf.hover()', { desc = 'Documentation' }) -vim.keymap.set({ 'n' }, 'gre', 'lua vim.diagnostic.open_float()', { desc = 'Diagnostics' }) - -nmap_lsp("K", 'lua vim.lsp.buf.hover()', "Documentation") -local formatting_cmd = 'lua require("conform").format({ lsp_format = "fallback" })' -nmap_leader('la', 'lua vim.lsp.buf.code_action()', 'Actions') -nmap_leader('le', 'lua vim.diagnostic.open_float()', 'Diagnostics popup') -nmap_leader('lf', formatting_cmd, 'Format') -nmap_leader('lk', 'lua vim.lsp.buf.hover()', 'Documentation') -nmap_leader('li', 'lua vim.lsp.buf.implementation()', 'Information') --- use ]d and [d ---nmap_leader('lj', 'lua vim.diagnostic.goto_next()', 'Next diagnostic') ---nmap_leader('lk', 'lua vim.diagnostic.goto_prev()', 'Prev diagnostic') -nmap_leader('lR', 'lua vim.lsp.buf.references()', 'References') -nmap_leader('lr', 'lua vim.lsp.buf.rename()', 'Rename') -nmap_leader('ls', 'lua vim.lsp.buf.definition()', 'Source definition') - -xmap_leader('lf', formatting_cmd, 'Format selection') - --- L is for 'Lua' -nmap_leader('Lc', 'lua Config.log_clear()', 'Clear log') -nmap_leader('LL', 'luafile %echo "Sourced lua"', 'Source buffer') -nmap_leader('Ls', 'lua Config.log_print()', 'Show log') -nmap_leader('Lx', 'lua Config.execute_lua_line()', 'Execute `lua` line') - --- m is free - --- o is for 'other' -local trailspace_toggle_command = 'lua vim.b.minitrailspace_disable = not vim.b.minitrailspace_disable' -nmap_leader('oh', 'normal gxiagxila', 'Move arg left') -nmap_leader('ol', 'normal gxiagxina', 'Move arg right') -nmap_leader('or', 'lua MiniMisc.resize_window()', 'Resize to default width') -nmap_leader('ot', 'lua MiniTrailspace.trim()', 'Trim trailspace') -nmap_leader('oT', trailspace_toggle_command, 'Trailspace hl toggle') -nmap_leader('oz', 'lua MiniMisc.zoom()', 'Zoom toggle') -nmap_leader('ow', - "lua MiniSessions.write(vim.fn.input('Session name: ', string.match(vim.fn.getcwd(), \"[^/]+$\") .. '-session.vim'))", - 'Write session') - --- r is for 'R' -nmap_leader('rc', 'RSend devtools::check()', 'Check') -nmap_leader('rC', 'RSend devtools::test_coverage()', 'Coverage') -nmap_leader('rd', 'RSend devtools::document()', 'Document') -nmap_leader('ri', 'RSend devtools::install(keep_source=TRUE)', 'Install') -nmap_leader('rk', 'RSend quarto::quarto_preview("%")', 'Knit file') -nmap_leader('rl', 'RSend devtools::load_all()', 'Load all') -nmap_leader('rL', 'RSend devtools::load_all(recompile=TRUE)', 'Load all recompile') -nmap_leader('rm', 'RSend Rcpp::compileAttributes()', 'Run examples') -nmap_leader('rT', 'RSend testthat::test_file("%")', 'Test file') -nmap_leader('rt', 'RSend devtools::test()', 'Test') - --- Visual `r` bindings (dispatched by the filetype-aware REPL --- runner in `lua/keymap/repl.lua`). Previously the visual clue group was --- empty, so this restores parity between the visual and normal `r`-group. -xmap_leader('rr', function() require('keymap.repl').send_selection() end, 'Send selection to REPL') --- - Copy to clipboard and make reprex (which itself is loaded to clipboard) -xmap_leader('rx', '"+y :RSend reprex::reprex()', 'Reprex selection') - --- s is for 'send' (Send text to the active REPL/runner) -nmap_leader('s', function() require('keymap.repl').send_line() end, 'Send to REPL') -xmap_leader('s', function() require('keymap.repl').send_selection() end, 'Send selection to REPL') - --- d is for 'debug' (nvim-dap) -nmap_leader('db', 'lua require("dap").toggle_breakpoint()', 'Toggle breakpoint') -nmap_leader('dB', 'lua require("dap").set_breakpoint(vim.fn.input("Condition: "))', 'Conditional breakpoint') -nmap_leader('dc', 'lua require("dap").continue()', 'Continue') -nmap_leader('do', 'lua require("dap").step_over()', 'Step over') -nmap_leader('di', 'lua require("dap").step_into()', 'Step into') -nmap_leader('dO', 'lua require("dap").step_out()', 'Step out') -nmap_leader('dr', 'lua require("dap").repl.open()', 'Open DAP REPL') -nmap_leader('du', 'lua require("dapui").toggle()', 'Toggle DAP UI') -nmap_leader('dK', 'lua require("dapui").eval()', 'Evaluate expression') - --- u is for UI -nmap_leader('ut', 'TSContext toggle', 'Toggle TScontext') -nmap_leader('ua', 'Copilot toggle', 'Toggle AI completion') - --- v is for 'visits' -nmap_leader('vv', 'lua MiniVisits.add_label("core")', 'Add "core" label') -nmap_leader('vV', 'lua MiniVisits.remove_label("core")', 'Remove "core" label') -nmap_leader('vl', 'lua MiniVisits.add_label()', 'Add label') -nmap_leader('vL', 'lua MiniVisits.remove_label()', 'Remove label') - -local map_pick_core = function(keys, cwd, desc) - local rhs = function() - local sort_latest = MiniVisits.gen_sort.default({ recency_weight = 1 }) - MiniExtra.pickers.visit_paths({ - cwd = cwd, - filter = 'core', - sort = sort_latest - }, { source = { name = desc } }) - end - nmap_leader(keys, rhs, desc) -end -map_pick_core('vc', '', 'Core visits (all)') -map_pick_core('vC', nil, 'Core visits (cwd)') - --- w is for 'windows' -nmap_leader("wh", "h", "Go to Left Window", { remap = true }) -nmap_leader("wj", "j", "Go to Lower Window", { remap = true }) -nmap_leader("wk", "k", "Go to Upper Window", { remap = true }) -nmap_leader("wl", "l", "Go to Right Window", { remap = true }) - -nmap_leader("_", "s", "Split Window Below", { remap = true }) -nmap_leader("|", "v", "Split Window Right", { remap = true }) -nmap_leader("wd", "c", "Delete Window", { remap = true }) -nmap_leader("wo", "o", "Delete Other Windows", { remap = true }) - --- z is for 'ZettelKasten' -nmap_leader("zo", 'ZkNotes', "Notes") -nmap_leader("zt", 'ZkTags', "Tags") - -nmap_leader( - "zrd", - 'ZkNew { group = "dreviews" }', - "Daily Review" -) -nmap_leader( - "zrw", - 'ZkNew { group = "wreviews" }', - "Weekly Review" -) -nmap_leader( - "zn", - 'ZkNew { group = "inbox", title = vim.fn.input("Title: ") }', - "New" -) -nmap_leader( - "zp", - "ZkNew { group = 'permanent', title = vim.fn.input('Title: ') }", - "Permanent" -) - -nmap_leader( - "zl", - "ZkNew { group = 'literature', title = vim.fn.input('Title: '), extra.author = vim.fn.input('Author: '), extra.year = vim.fn.input('Year: ') }", - "Literature" -) - -nmap_leader( - "zd", - "ZkNew { group = 'dashboard', title = vim.fn.input('Title: ') }", - "Dashboard" -) -nmap_leader( - "zP", - "ZkNew { group = 'project', title = vim.fn.input('Title: ')}", - "Project" -) --- stylua: ignore end diff --git a/lua/keymap/repl.lua b/lua/keymap/repl.lua deleted file mode 100644 index 35425aa..0000000 --- a/lua/keymap/repl.lua +++ /dev/null @@ -1,101 +0,0 @@ ---- Filetype-aware REPL/runner dispatcher. ---- Keeps the existing terminal setup intact; it only decides *which* runner ---- to use for the current buffer/filetype. - -local M = {} - ---- Resolve the filetype to use for dispatching. ---- Quarto buffers report `quarto`; R buffers report `r`. Fallback to the ---- actual filetype if no special handling is needed. -local function dispatch_ft() - local ft = vim.bo.filetype - if ft == "quarto" or ft == "rmd" or ft == "markdown" then - return "quarto" - end - return ft -end - ---- Send the current line to the active REPL/runner. -function M.send_line() - local ft = dispatch_ft() - - if ft == "r" then - -- R.nvim v1+ exposes a Lua API; try the modern `r.send` module first, - -- then fall back to the older `r.run` module, and finally to . - local ok, rmod = pcall(require, "r.send") - if not ok or not rmod then - ok, rmod = pcall(require, "r.run") - end - if ok and rmod then - if type(rmod.line) == "function" then - rmod.line() - return - elseif type(rmod.send_line) == "function" then - rmod.send_line() - return - end - end - vim.api.nvim_feedkeys( - vim.api.nvim_replace_termcodes("RDSendLine", true, false, true), - "m", - false - ) - return - end - - if ft == "quarto" then - local ok, runner = pcall(require, "quarto.runner") - if ok and runner then - if runner.run_line then - runner.run_line() - elseif runner.run_cell then - runner.run_cell() - end - return - end - end - - -- Default: vim-slime (terminal). - local line = vim.api.nvim_get_current_line() - vim.fn["slime#send"](line .. "\n") - -- Move to the next line, matching the previous behaviour. - vim.cmd("normal! j") -end - ---- Send the current visual selection to the active REPL/runner. -function M.send_selection() - local ft = dispatch_ft() - - if ft == "r" then - -- Prefer R.nvim v1+ Lua API; try the modern `r.send` module first, - -- then fall back to the older `r.run` module, and finally to . - local ok, rmod = pcall(require, "r.send") - if not ok or not rmod then - ok, rmod = pcall(require, "r.run") - end - if ok and rmod then - if type(rmod.selection) == "function" then - rmod.selection() - return - elseif type(rmod.send_selection) == "function" then - rmod.send_selection() - return - end - end - vim.api.nvim_feedkeys( - vim.api.nvim_replace_termcodes("RSendSelection", true, false, true), - "m", - false - ) - return - end - - -- For Quarto/others, fall back to vim-slime's visual send. - vim.api.nvim_feedkeys( - vim.api.nvim_replace_termcodes("SlimeRegionSend", true, false, true), - "m", - false - ) -end - -return M diff --git a/lua/keymap/terminal.lua b/lua/keymap/terminal.lua deleted file mode 100644 index bb89596..0000000 --- a/lua/keymap/terminal.lua +++ /dev/null @@ -1,17 +0,0 @@ -local Config = require('config') -local helpers = require('keymap.helpers') -local nmap_leader = helpers.nmap_leader - --- Exit terminal insert mode with -vim.keymap.set("t", "", [[]], { desc = "Exit terminal mode" }) - --- t is for 'terminal' -nmap_leader("tc", 'lua Config.terminal.open_clickhouse_client()', 'Open Clickhouse client') -nmap_leader("tl", 'lua Config.terminal.open_clickhouse_local()', 'Open Clickhouse local') -nmap_leader("tp", 'lua Config.terminal.open_python()', 'Open Python') -nmap_leader("tj", 'lua Config.terminal.open_julia()', 'Open Julia') -nmap_leader("td", 'lua Config.terminal.open_duckdb();Config.terminal.toggle_bracket()', 'Open DuckDB') -nmap_leader("tx", 'lua Config.terminal.open_in_terminal()', 'Terminal Command') -nmap_leader("tt", 'lua Config.terminal.open_shell()', 'Terminal') -nmap_leader("tb", 'lua Config.terminal.toggle_bracket()', 'Toggle bracketed paste') -nmap_leader("up", 'lua Config.terminal.toggle_bracket()', 'Toggle bracketed paste') diff --git a/lua/nix_smart_send.lua b/lua/nix_smart_send.lua index 51e9611..1f82383 100644 --- a/lua/nix_smart_send.lua +++ b/lua/nix_smart_send.lua @@ -1,12 +1,5 @@ local M = {} --- Define comment node types as constants -local COMMENT_TYPES = { - comment = true, - block_comment = true, - line_comment = true, -} - -- Helper function to check if value exists in list (optimized with early return) local function is_in_list(list, value) if not list or not value then @@ -21,90 +14,83 @@ local function is_in_list(list, value) return false end --- Safely get the Tree-sitter node under the cursor. +-- Define comment node types as constants +local COMMENT_TYPES = { + comment = true, + block_comment = true, + line_comment = true, +} + function M.get_current_node() - local ok, node = pcall(vim.treesitter.get_node, { ignore_injections = false }) - return ok and node or nil + local cur_win = vim.api.nvim_get_current_win() + return vim.treesitter.get_node({ + winid = cur_win, + ignore_injections = true, + }) end --- Detect the root node type of the current buffer's Tree-sitter tree. function M.detect_global_node() local cur_node = M.get_current_node() local root if not cur_node then - local ok, parser = pcall(vim.treesitter.get_parser) - if not ok or not parser then + -- print("No node detected") + local parser = vim.treesitter.get_parser() + if not parser then return nil end - local trees = parser:parse() - if not trees or not trees[1] then - return nil - end - root = trees[1]:root() + root = parser:parse()[1]:root() else root = cur_node:root() end - return root and root:type() or nil -end - --- Ascend the tree from the current node until we hit a node whose parent is a --- "global" node (or the root). This is the unit of code we want to send. -local function get_target_node(global_nodes) - local root_type = M.detect_global_node() - global_nodes = global_nodes or {} - - local node = M.get_current_node() - if not node then + if not root then return nil end - while node do - local parent = node:parent() - if not parent then - break - end - - local p_type = parent:type() - if is_in_list(global_nodes, p_type) or p_type == root_type then - break - end - node = parent - end - - return node + return root:type() end --- Move the cursor to the next named sibling that is not a comment. --- Operates on the Tree-sitter AST instead of scanning lines, so it is fast and --- language-agnostic. -function M.move_to_next_non_empty_line(current_node) - local node = current_node - if not node then - node = get_target_node({}) - end - if not node then +function M.move_to_next_non_empty_line() + -- Search for the next non-empty line + local line_num = vim.fn.search("[^;\\s]", "W") + + if line_num <= 0 then + -- print("No non-empty line found below the current position") return false end - -- Walk up the tree until we find a node with a next named sibling, - -- so we escape nested blocks when we are on the last statement. - while node and not node:next_named_sibling() do - node = node:parent() + -- Get the line content and find first non-whitespace character + local line_content = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num, false)[1] + local first_non_ws = line_content:find("%S") or 1 + vim.api.nvim_win_set_cursor(0, { line_num, first_non_ws - 1 }) + + local node = M.get_current_node() + if not node or not node:type() then + -- print("No node found") + return false end - node = node:next_named_sibling() - while node do - if not COMMENT_TYPES[node:type()] then - local start_row, start_col = node:range() - pcall(vim.api.nvim_win_set_cursor, 0, { start_row + 1, start_col }) - return true, node + local global_node_type = M.detect_global_node() + + -- Skip comments and global nodes + while node and (COMMENT_TYPES[node:type()] or node:type() == global_node_type) do + line_num = line_num + 1 + local max_lines = vim.api.nvim_buf_line_count(0) + + if line_num > max_lines then + -- print("Reached end of buffer") + return false end - node = node:next_named_sibling() + + -- Get the line content and find first non-whitespace character + line_content = vim.api.nvim_buf_get_lines(0, line_num - 1, line_num, false)[1] + first_non_ws = line_content:find("%S") or 1 + vim.api.nvim_win_set_cursor(0, { line_num, first_non_ws - 1 }) + node = vim.treesitter.get_node() end - return false + return true end function M.vselect_node(node) @@ -122,52 +108,93 @@ function M.vselect_node(node) end function M.select_until_global(global_nodes) - local target = get_target_node(global_nodes) - if not target then + local root_node = M.detect_global_node() + if not root_node and global_nodes then + root_node = global_nodes[1] + end + + -- Use empty table if no global nodes provided + global_nodes = global_nodes or {} + + local node = vim.treesitter.get_node() + if not node then + -- print("No syntax node found at cursor position") return nil end - if M.vselect_node(target) then - return target + local node_type = node:type() + + if node_type == root_node then + -- print("Cursor is on the root " .. root_node .. " node or in an empty area.") + return nil + end + + -- Check if current node is a global + if is_in_list(global_nodes, node_type) then + if M.vselect_node(node) then + return node + end + end + + -- Traverse up the tree until we find a global node or reach the root + local parent = node:parent() + local parent_type = parent:type() or "" + if parent and is_in_list(global_nodes, parent_type) then + if M.vselect_node(node) then + return node + end + end + while parent and not is_in_list(global_nodes, parent:type()) do + node = parent + parent = node:parent() + end + + if M.vselect_node(node) then + return node end return nil end function M.slime_send_region() - vim.api.nvim_feedkeys( - vim.api.nvim_replace_termcodes("SlimeRegionSend", true, false, true), - "m", - false - ) + -- Check if slime plugin is available + if not vim.fn.exists('*slime#send_op') then + vim.notify("slime plugin not available", vim.log.levels.ERROR) + return + end + + local slime_command = ":call slime#send_op(visualmode(), 1)" + local termcodes = vim.api.nvim_replace_termcodes(slime_command, true, true, true) + + vim.api.nvim_feedkeys(termcodes, "x", true) end function M.send_repl(global_nodes) - local target_node = get_target_node(global_nodes) - if not target_node then - return - end + local cur_node = M.get_current_node() - -- If sitting on a comment, step forward first so we don't send comments. - if COMMENT_TYPES[target_node:type()] then - local moved, next_node = M.move_to_next_non_empty_line(target_node) - if not moved or not next_node then - return + if not cur_node then + M.move_to_next_non_empty_line() + else + local cur_type = cur_node:type() + if COMMENT_TYPES[cur_type] or is_in_list(global_nodes, cur_type) then + M.move_to_next_non_empty_line() end - target_node = next_node end - -- Extract node text and send directly to avoid visual-mode/feedkeys races. - local ok, text = pcall(vim.treesitter.get_node_text, target_node, 0) - if not ok or not text then - vim.notify("Could not extract code from Tree-sitter node", vim.log.levels.WARN) + local sel_node = M.select_until_global(global_nodes) + if not sel_node then + -- print("No node selected for REPL") return end - vim.fn["slime#send"](text .. "\n") + -- Send the selected text to the terminal using vim-slime + M.slime_send_region() - -- Jump to the next relevant AST node instead of scanning lines - M.move_to_next_non_empty_line(target_node) + -- Move cursor and continue + local _, _, er, ec = sel_node:range() + vim.api.nvim_win_set_cursor(0, { er + 1, ec }) + + M.move_to_next_non_empty_line() end return M diff --git a/modules/module/settings/cat-packages.nix b/modules/module/settings/cat-packages.nix index dbdba3f..2709ca0 100644 --- a/modules/module/settings/cat-packages.nix +++ b/modules/module/settings/cat-packages.nix @@ -5,10 +5,6 @@ ... }: let - # Include packages from a category only if that category is enabled. - # NOTE: Package list expressions are lazily evaluated, and derivations are - # not built until needed, so keep side-effecting expressions out of these - # lists. maybe = cat: pkgsList: lib.optionals (config.cats.${cat} or false) pkgsList; rPackages = (pkgs.baseRPackages or [ ]) ++ config.settings.lang_packages.r; @@ -25,14 +21,11 @@ in }; config.catPkgs = { - always = maybe "always" (with pkgs; [ - ripgrep - ]); + always = maybe "always" (with pkgs; [ ]); clickhouse = maybe "clickhouse" (with pkgs; [ clickhouse-lts ]); external = maybe "external" (with pkgs; [ - nodejs perl ruby shfmt @@ -47,13 +40,10 @@ in lua = maybe "lua" (with pkgs; [ lua-language-server ]); markdown = maybe "markdown" (with pkgs; [ - python3Packages.pylatexenc + python313Packages.pylatexenc quartoPkg zk marksman - texlab - imagemagick - harper ]); nix = maybe "nix" (with pkgs; [ @@ -98,6 +88,7 @@ in in with pkgs; [ python_with_packages + nodejs ruff basedpyright uv diff --git a/modules/module/settings/lang-packages.nix b/modules/module/settings/lang-packages.nix index 3be7a9a..a91d9a5 100644 --- a/modules/module/settings/lang-packages.nix +++ b/modules/module/settings/lang-packages.nix @@ -44,11 +44,6 @@ data_table janitor styler - # vscDebugger is not on CRAN/Bioconductor, so it is not available in - # pkgs.rpkgs.rPackages. Install it manually in your R library if you - # want to use the nvim-dap R adapter (see plugin/26_dap.lua). - # vscDebugger - lintr ]) ); julia = lib.mkDefault [ diff --git a/modules/module/specs/plugins.nix b/modules/module/specs/plugins.nix index 2b92ef4..63d32d0 100644 --- a/modules/module/specs/plugins.nix +++ b/modules/module/specs/plugins.nix @@ -3,52 +3,7 @@ pkgs, lib, ... -}: -let - parserList = [ - "bash" - "bibtex" - "c" - "cpp" - "csv" - "diff" - "dockerfile" - "git_config" - "git_rebase" - "gitattributes" - "gitcommit" - "gitignore" - "html" - "javascript" - "json" - "julia" - "latex" - "lua" - "luadoc" - "make" - "markdown" - "markdown_inline" - "matlab" - "nix" - "python" - "query" - "r" - "rnoweb" - "regex" - "sql" - "toml" - "vim" - "vimdoc" - "xml" - "yaml" - "zig" - ]; -in { - options.settings.treesitter_parsers = lib.mkOption { - type = lib.types.listOf lib.types.str; - default = parserList; - description = "Tree-sitter parser names to install when the treesitterParsers category is enabled."; - }; +}: { config.specs.gitPlugins = lib.mkIf (config.cats.gitPlugins or false) { data = []; @@ -69,7 +24,6 @@ in { lazy = true; data = [ config.nvim-lib.neovimPlugins.cmp-pandoc-references - pkgs.vimPlugins.image-nvim ]; }; @@ -78,7 +32,6 @@ in { lze lzextras plenary-nvim - vimtex neogit { data = mini-nvim; @@ -172,7 +125,42 @@ in { }; config.specs.treesitterParsers = lib.mkIf (config.cats.treesitterParsers or false) { - data = map (name: pkgs.vimPlugins.nvim-treesitter-parsers.${name}) config.settings.treesitter_parsers; + data = with pkgs.vimPlugins.nvim-treesitter-parsers; [ + bash + c + cpp + csv + diff + dockerfile + git_config + git_rebase + gitattributes + gitcommit + gitignore + html + javascript + json + julia + latex + lua + luadoc + make + markdown + markdown_inline + nix + python + query + r + rnoweb + regex + sql + toml + vim + vimdoc + xml + yaml + zig + ]; }; config.specs.utils-lazy = lib.mkIf (config.cats.utils or false) { @@ -184,21 +172,11 @@ in { colorful-menu-nvim conform-nvim copilot-lua - nvim-lint - vim-slime - ]; - }; - - # Lazy-loaded plugins needed when the `r` cat is on. Kept separate from - # `utils-lazy` so users with `r=true` and `utils=false` still get the - # nvim-dap R adapter and in-buffer image rendering for plots. - config.specs.r-lazy = lib.mkIf (config.cats.r or false) { - lazy = true; - data = with pkgs.vimPlugins; [ nvim-dap nvim-dap-ui nvim-dap-virtual-text - image-nvim + nvim-lint + vim-slime ]; }; diff --git a/plugin/01_lib.lua b/plugin/01_lib.lua index 988905c..64bd37e 100644 --- a/plugin/01_lib.lua +++ b/plugin/01_lib.lua @@ -1,5 +1,3 @@ -local Config = require('config') - -- Global Functions Config.new_scratch_buffer = function() vim.api.nvim_win_set_buf(0, vim.api.nvim_create_buf(true, true)) end @@ -34,7 +32,7 @@ end Config.execute_lua_line = function() local line = 'lua ' .. vim.api.nvim_get_current_line() vim.api.nvim_command(line) - vim.notify(line, vim.log.levels.INFO) + print(line) vim.api.nvim_input('') end diff --git a/plugin/02_startup.lua b/plugin/02_startup.lua index b4d1c7e..c4fa2a9 100644 --- a/plugin/02_startup.lua +++ b/plugin/02_startup.lua @@ -1,5 +1,3 @@ -local Config = require('config') - local M = {} -- Helper function to normalize input to a list diff --git a/plugin/03_terminal.lua b/plugin/03_terminal.lua index 95d7a29..95d25b1 100644 --- a/plugin/03_terminal.lua +++ b/plugin/03_terminal.lua @@ -1,9 +1,3 @@ -local Config = require('config') - --- vim-slime target: use Neovim's built-in terminal. --- Must be set before any slime send happens. -vim.g.slime_target = "neovim" - local M = {} -- Configuration @@ -37,15 +31,11 @@ function M.split_and_open_terminal() vim.cmd("resize " .. math.floor(vim.fn.winheight(0) * 0.9)) local term_buf = vim.api.nvim_win_get_buf(vim.api.nvim_get_current_win()) M.opt_term = term_buf - + -- Set buffer-local variables for vim-slime local job_id = vim.b[term_buf].terminal_job_id - if not job_id then - vim.notify("Terminal job id not available", vim.log.levels.WARN) - return term_buf - end vim.b[term_buf].slime_config = { jobid = job_id } - + return M.opt_term end @@ -54,45 +44,26 @@ function M.open_in_terminal(cmd) local command = cmd or "" local current_window = vim.api.nvim_get_current_win() local code_buf = vim.api.nvim_get_current_buf() - - if not vim.api.nvim_buf_is_valid(code_buf) then - vim.notify("Code buffer is not valid", vim.log.levels.ERROR) - return - end - + -- Open terminal and get buffer local term_buf = M.split_and_open_terminal() - - if not term_buf or not vim.api.nvim_buf_is_valid(term_buf) then - vim.notify("Failed to open terminal buffer", vim.log.levels.ERROR) - return - end - + -- Send command if provided - local job_id = vim.b[term_buf].terminal_job_id if command ~= "" then - if not job_id then - vim.notify("Terminal job not ready, cannot send command", vim.log.levels.WARN) - else - local ok, err = pcall(vim.api.nvim_chan_send, job_id, command .. "\r") - if not ok then - vim.notify("Failed to send command to terminal: " .. tostring(err), vim.log.levels.ERROR) - end + -- We can use standard slime sending if needed, or direct chan_send for initialization + local job_id = vim.b[term_buf].terminal_job_id + if job_id then + vim.api.nvim_chan_send(job_id, command .. "\r") end end - + -- Configure slime for the ORIGINAL code buffer to point to this new terminal -- This makes "Send to Terminal" work immediately - if job_id then - local slime_config = { jobid = job_id } - - -- Fix: Set the variable on the captured code buffer, not the current (terminal) buffer - local ok, err = pcall(vim.api.nvim_buf_set_var, code_buf, "slime_config", slime_config) - if not ok then - vim.notify("Failed to set slime_config on code buffer: " .. tostring(err), vim.log.levels.ERROR) - end - end - + local slime_config = { jobid = vim.b[term_buf].terminal_job_id } + + -- Fix: Set the variable on the captured code buffer, not the current (terminal) buffer + vim.api.nvim_buf_set_var(code_buf, "slime_config", slime_config) + -- Switch back to code buffer vim.api.nvim_set_current_win(current_window) end diff --git a/plugin/04_treesitter.lua b/plugin/04_treesitter.lua index 88d3cb7..5a8d315 100644 --- a/plugin/04_treesitter.lua +++ b/plugin/04_treesitter.lua @@ -1,5 +1,3 @@ -local Config = require('config') - local M = {} -- Default parsers list moved from startup config @@ -95,12 +93,12 @@ end function M.get_type() local cur_node = smart_send.get_current_node() if not cur_node then - vim.notify("No Tree-sitter node under cursor", vim.log.levels.WARN) + print("Not a node") return nil end local node_type = cur_node:type() - vim.notify("Node type: " .. node_type, vim.log.levels.INFO) + print("Node type: " .. node_type) return node_type end @@ -121,17 +119,11 @@ function M.setup_keybindings(global_nodes) vim.keymap.set('n', 'a', function() smart_send.send_repl(current_global_nodes) end, { noremap = true, silent = true, desc = "Send node to REPL", buffer = true }) - -- Both `` and `` were removed from `M.setup_keybindings`. They - -- were hard, implicit overrides that clobbered Vim/filetype defaults and - -- the user's snippet + insert-mode workflows (see C2 + H5 in the PR - -- review). To opt back in for a specific filetype, override per-buffer - -- from a `ftplugin/.lua`: - -- - -- -- e.g. ftplugin/r.lua or ftplugin/quarto.lua - -- vim.keymap.set('n', '', function() - -- require('config').treesitter_helpers.setup_keybindings(global_nodes) - -- require('nix_smart_send').send_repl(global_nodes) - -- end, { buffer = true, desc = 'Send node to REPL' }) + vim.keymap.set({ 'n', 'i' }, '', function() smart_send.send_repl(current_global_nodes) end, + { noremap = true, silent = true, desc = "Send node to REPL", buffer = true }) + + vim.keymap.set('n', '', function() smart_send.send_repl(current_global_nodes) end, + { noremap = true, silent = true, desc = "Send node to REPL", buffer = true }) vim.keymap.set('n', 'n', function() current_global_nodes = M.add_global_node(current_global_nodes) end, @@ -142,8 +134,8 @@ function M.setup_keybindings(global_nodes) { noremap = true, silent = true, desc = "Remove node under cursor from globals", buffer = true }) vim.keymap.set('n', 'o', function() - local pout = table.concat(global_nodes, ', ') - vim.notify("global_nodes: " .. pout, vim.log.levels.INFO) + pout = table.concat(global_nodes, ', ') .. "" + print(pout) end, { noremap = true, silent = true, desc = "Print globals", buffer = true }) vim.keymap.set('n', 'p', function() M.get_type() end, @@ -152,46 +144,4 @@ end Config.treesitter_helpers = M --- Tree-sitter text objects: functions, calls, and assignments are especially --- useful when editing R/tidyverse pipelines (e.g. `df |> mutate(...)`). -local ts_ok, treesitter = pcall(require, "nvim-treesitter.configs") -if ts_ok then - treesitter.setup({ - textobjects = { - select = { - enable = true, - lookahead = true, - keymaps = { - ["af"] = "@function.outer", - ["if"] = "@function.inner", - ["ac"] = "@call.outer", - ["ic"] = "@call.inner", - ["aa"] = "@assignment.outer", - ["ia"] = "@assignment.inner", - }, - selection_modes = { - ["@function.outer"] = "V", - ["@function.inner"] = "V", - ["@call.outer"] = "v", - ["@call.inner"] = "v", - ["@assignment.outer"] = "v", - ["@assignment.inner"] = "v", - }, - }, - move = { - enable = true, - set_jumps = true, - goto_next_start = { - ["]f"] = "@function.outer", - ["]c"] = "@call.outer", - }, - goto_previous_start = { - ["[f"] = "@function.outer", - ["[c"] = "@call.outer", - }, - }, - }, - }) -end - return M diff --git a/plugin/10_keymap.lua b/plugin/10_keymap.lua index 98074fb..8ae0a1c 100644 --- a/plugin/10_keymap.lua +++ b/plugin/10_keymap.lua @@ -1,11 +1,323 @@ -local Config = require('config') +-- Basic mappings ============================================================= +-- NOTE: Most basic mappings come from 'mini.basics' +-- Shorter version of the most frequent way of going outside of terminal window +vim.keymap.set('t', '', [[h]]) +-- Select all +-- vim.keymap.set({ "n", "v", "x" }, "", "gg3vG$", { noremap = true, silent = true, desc = "Select all" }) +-- Escape deletes highlights +vim.keymap.set("n", "", "nohlsearch") +-- Paste before/after linewise +local cmd = vim.fn.has('nvim-0.12') == 1 and 'iput' or 'put' +vim.keymap.set({ 'n', 'x' }, '[p', 'exe "' .. cmd .. '! " . v:register', { desc = 'Paste Above' }) +vim.keymap.set({ 'n', 'x' }, ']p', 'exe "' .. cmd .. ' " . v:register', { desc = 'Paste Below' }) --- Domain-specific keymap modules. Core must load first because it defines the --- leader clue groups used by the mini.clue setup in the startup plugins. -require('keymap.core') -require('keymap.leader') -require('keymap.terminal') +vim.keymap.set({ "n", "v", "x" }, "p", '"+p', { noremap = true, silent = true, desc = "Paste from clipboard" }) +vim.keymap.set({ "n", "v", "x" }, "y", '"+y', { noremap = true, silent = true, desc = "Copy toclipboard" }) +-- Leader mappings ============================================================ +-- stylua: ignore start --- `_G.Config` is set by `init.lua:2` once at start-up; no need to re-export --- here. The single source of truth is `init.lua` so future refactors don't --- have to chase which file currently publishes the alias. +-- Create global tables with information about clue groups in certain modes +-- Structure of tables is taken to be compatible with 'mini.clue'. +_G.Config.leader_group_clues = { + { mode = 'n', keys = 'a', desc = '+AI' }, + { mode = 'n', keys = 'b', desc = '+Buffer' }, + { mode = 'n', keys = 'e', desc = '+Explore' }, + { mode = 'n', keys = 'f', desc = '+Find' }, + { mode = 'n', keys = 'fl', desc = '+LSP' }, + { mode = 'n', keys = 'fa', desc = '+Git' }, + { mode = 'n', keys = 'g', desc = '+Git' }, + { mode = 'n', keys = 'l', desc = '+LSP' }, + { mode = 'n', keys = 'L', desc = '+Lua/Log' }, + { mode = 'n', keys = 'o', desc = '+Other' }, + { mode = 'n', keys = 'r', desc = '+R' }, + { mode = 'n', keys = 't', desc = '+Terminal' }, + { mode = 'n', keys = 'u', desc = '+UI' }, + { mode = 'n', keys = 'v', desc = '+Visits' }, + { mode = 'n', keys = 'w', desc = '+Windows' }, + { mode = 'x', keys = 'l', desc = '+LSP' }, + { mode = 'x', keys = 'r', desc = '+R' }, + { mode = 'n', keys = 'z', desc = '+ZK' }, + { mode = 'n', keys = 'zr', desc = '+Reviews' }, + { mode = 'x', keys = 'a', desc = '+AI' }, +} + +-- Create `` mappings +local nmap_leader = function(suffix, rhs, desc, opts) + opts = opts or {} + opts.desc = desc + vim.keymap.set('n', '' .. suffix, rhs, opts) +end +local xmap_leader = function(suffix, rhs, desc, opts) + opts = opts or {} + opts.desc = desc + vim.keymap.set('x', '' .. suffix, rhs, opts) +end +-- Other mappings +local nmap_lsp = function(keys, func, desc) + if desc then + desc = desc .. "(LSP)" + end + + vim.keymap.set("n", keys, func, { desc = desc }) +end + +-- Switch buffers +nmap_leader('', 'bnext', 'Next buffer') +nmap_leader('', 'bprev', 'Prev buffer') + +-- a is for 'AI' +nmap_leader("aa", "CodeCompanion /agent", "Agent chat (@{agent} tools)") +nmap_leader("ac", "CodeCompanionChat Toggle", "Chat Toggle") +nmap_leader("aC", function() + local chat = require("codecompanion").last_chat() + if not chat then + return vim.notify("No CodeCompanion chat to compact", vim.log.levels.WARN) + end + require("codecompanion.interactions.chat.context_management.compaction").compact(chat, { min_token_savings = 0 }) +end, "Compact chat") +nmap_leader("ag", "CodeCompanion /commit", "Generate commit message") +nmap_leader("ai", "CodeCompanionActions", "Chat Action") +nmap_leader("al", "CodeCompanion /lsp", "Explain LSP Diagnostics") +nmap_leader("an", "CodeCompanionChat Add", "Chat New") +nmap_leader("as", "CodeCompanion /suggest", "Suggest Improvements") +nmap_leader("aw", "CodeCompanion /tdd", "Workflow: plan, implement, test") +nmap_leader("ax", "CodeCompanion /fixer", "Code Fixer") +xmap_leader("aa", "CodeCompanion /agent", "Agent on selection") +xmap_leader("ae", "CodeCompanion /explain", "Explain Code") +xmap_leader("af", "CodeCompanion /fix", "Fix Code") +xmap_leader("ap", "CodeCompanion /expert", "Code Expert") +xmap_leader("as", "CodeCompanion /suggest", "Suggest Improvements") +nmap_leader("ak", "CodeCompanionChat adapter=codex", "Chat with Codex") + +-- b is for 'buffer' +nmap_leader('bb', 'b#', 'Alternate') +nmap_leader('bd', 'lua MiniBufremove.delete()', 'Delete') +nmap_leader('bD', 'lua MiniBufremove.delete(0, true)', 'Delete!') +nmap_leader('bs', 'lua Config.new_scratch_buffer()', 'Scratch') +nmap_leader('bw', 'lua MiniBufremove.wipeout()', 'Wipeout') +nmap_leader('bW', 'lua MiniBufremove.wipeout(0, true)', 'Wipeout!') +nmap_leader('bq', 'qall', 'Quit all') + +-- e is for 'explore' and 'edit' +nmap_leader('ed', 'lua MiniFiles.open()', 'Directory') +nmap_leader('ef', 'lua Config.try_opendir()', 'File directory') +nmap_leader('es', 'lua MiniSessions.select()', 'Sessions') +nmap_leader('eq', 'lua Config.toggle_quickfix()', 'Quickfix') +nmap_leader('ez', 'lua MiniFiles.open(os.getenv("ZK_NOTEBOOK_DIR"))', 'Notes directory') + +-- f is for 'fuzzy find' +nmap_leader('f/', 'Pick history scope="/"', '"/" history') +nmap_leader('f:', 'Pick history scope=":"', '":" history') +nmap_leader('f,', 'Pick visit_labels', 'Visit labels') +nmap_leader('faa', 'Pick git_hunks scope="staged"', 'Added hunks (all)') +nmap_leader('faA', 'Pick git_hunks path="%" scope="staged"', 'Added hunks (current)') +nmap_leader('fb', 'Pick buffers', 'Buffers') +nmap_leader(',', 'Pick buffers', 'Buffers') +nmap_leader('fac', 'Pick git_commits', 'Commits (all)') +nmap_leader('faC', 'Pick git_commits path="%"', 'Commits (current)') +nmap_leader('fd', 'Pick diagnostic scope="all"', 'Diagnostic workspace') +nmap_leader('fD', 'Pick diagnostic scope="current"', 'Diagnostic buffer') +nmap_leader('ff', 'Pick files', 'Files') +nmap_leader('fg', 'Pick grep_live', 'Grep live') +nmap_leader('fG', 'Pick grep pattern=""', 'Grep current word') +nmap_leader('fh', 'Pick help', 'Help tags') +nmap_leader('fH', 'Pick hl_groups', 'Highlight groups') +nmap_leader('fj', 'Pick buf_lines scope="all"', 'Lines (all)') +nmap_leader('fJ', 'Pick buf_lines scope="current"', 'Lines (current)') +nmap_leader('fam', 'Pick git_hunks', 'Modified hunks (all)') +nmap_leader('faM', 'Pick git_hunks path="%"', 'Modified hunks (current)') +nmap_leader('fm', 'Pick marks', 'Marks') +nmap_leader('fn', 'ZkNotes', "Notes") +nmap_leader('fk', 'Pick keymaps', 'Keymaps') +nmap_leader('fR', 'Pick resume', 'Resume') +nmap_leader('fp', 'Pick files', 'Files') +nmap_leader('fq', 'Pick list scope="quickfix"', 'Quickfix') +nmap_leader('fr', 'Pick lsp scope="references"', 'References (LSP)') +nmap_leader('flr', 'Pick lsp scope="references"', 'References (LSP)') +nmap_leader('fS', 'Pick lsp scope="workspace_symbol"', 'Symbols workspace (LSP)') +nmap_leader('flS', 'Pick lsp scope="workspace_symbol"', 'Symbols workspace (LSP)') +nmap_leader('fs', 'Pick lsp scope="document_symbol"', 'Symbols buffer (LSP)') +nmap_leader('fls', 'Pick lsp scope="document_symbol"', 'Symbols buffer (LSP)') +nmap_leader('fld', 'Pick lsp scope="definition"', 'Definition (LSP)') +nmap_leader('flD', 'Pick lsp scope="declaration"', 'Declaration (LSP)') +nmap_leader('flt', 'Pick lsp scope="type_definition"', 'Type Definition (LSP)') +nmap_leader('fv', 'Pick visit_paths cwd=""', 'Visit paths (all)') +nmap_leader('fV', 'Pick visit_paths', 'Visit paths (cwd)') + +-- g is for git +local git_log_cmd = [[Git log --pretty=format:\%h\ \%as\ │\ \%s --topo-order]] + +nmap_leader('gc', 'Git commit', 'Commit') +nmap_leader('gC', 'Git commit --amend', 'Commit amend') +nmap_leader('gd', 'Git diff', 'Diff') +nmap_leader('gD', 'Git diff -- %', 'Diff buffer') +nmap_leader("gg", "Neogit", "Open Neogit UI") +nmap_leader('gl', '' .. git_log_cmd .. '', 'Log') +nmap_leader('gL', '' .. git_log_cmd .. ' --follow -- %', 'Log buffer') +nmap_leader('go', 'lua MiniDiff.toggle_overlay()', 'Toggle overlay') +nmap_leader('gp', 'Git pull', 'Pull') +nmap_leader('gP', 'Git push', 'Push') +nmap_leader('gs', 'lua MiniGit.show_at_cursor()', 'Show at cursor') + +xmap_leader('gs', 'lua MiniGit.show_at_cursor()', 'Show at selection') + +-- j/k navigate quickfix +nmap_leader("j", 'cnextzz', "Quickfix next") +nmap_leader("k", 'cprevzz', "Quickfix prev") + +-- l is for 'LSP' (Language Server Protocol) +vim.keymap.set({ 'n' }, 'grd', 'lua vim.lsp.buf.definition()', { desc = 'Definition' }) +vim.keymap.set({ 'n' }, 'grk', 'lua vim.lsp.buf.hover()', { desc = 'Documentation' }) +vim.keymap.set({ 'n' }, 'gre', 'lua vim.diagnostic.open_float()', { desc = 'Diagnostics' }) + +nmap_lsp("K", 'lua vim.lsp.buf.hover()', "Documentation") +local formatting_cmd = 'lua require("conform").format({ lsp_format = "fallback" })' +nmap_leader('la', 'lua vim.lsp.buf.code_action()', 'Actions') +nmap_leader('le', 'lua vim.diagnostic.open_float()', 'Diagnostics popup') +nmap_leader('lf', formatting_cmd, 'Format') +nmap_leader('lk', 'lua vim.lsp.buf.hover()', 'Documentation') +nmap_leader('li', 'lua vim.lsp.buf.implementation()', 'Information') +-- use ]d and [d +--nmap_leader('lj', 'lua vim.diagnostic.goto_next()', 'Next diagnostic') +--nmap_leader('lk', 'lua vim.diagnostic.goto_prev()', 'Prev diagnostic') +nmap_leader('lR', 'lua vim.lsp.buf.references()', 'References') +nmap_leader('lr', 'lua vim.lsp.buf.rename()', 'Rename') +nmap_leader('ls', 'lua vim.lsp.buf.definition()', 'Source definition') + +xmap_leader('lf', formatting_cmd, 'Format selection') + +-- L is for 'Lua' +nmap_leader('Lc', 'lua Config.log_clear()', 'Clear log') +nmap_leader('LL', 'luafile %echo "Sourced lua"', 'Source buffer') +nmap_leader('Ls', 'lua Config.log_print()', 'Show log') +nmap_leader('Lx', 'lua Config.execute_lua_line()', 'Execute `lua` line') + +-- m is free + +-- o is for 'other' +local trailspace_toggle_command = 'lua vim.b.minitrailspace_disable = not vim.b.minitrailspace_disable' +nmap_leader('oh', 'normal gxiagxila', 'Move arg left') +nmap_leader('ol', 'normal gxiagxina', 'Move arg right') +nmap_leader('or', 'lua MiniMisc.resize_window()', 'Resize to default width') +nmap_leader('ot', 'lua MiniTrailspace.trim()', 'Trim trailspace') +nmap_leader('oT', trailspace_toggle_command, 'Trailspace hl toggle') +nmap_leader('oz', 'lua MiniMisc.zoom()', 'Zoom toggle') +nmap_leader('ow', + "lua MiniSessions.write(vim.fn.input('Session name: ', string.match(vim.fn.getcwd(), \"[^/]+$\") .. '-session.vim'))", + 'Write session') + +-- r is for 'R' +nmap_leader('rc', 'RSend devtools::check()', 'Check') +nmap_leader('rC', 'RSend devtools::test_coverage()', 'Coverage') +nmap_leader('rd', 'RSend devtools::document()', 'Document') +nmap_leader('ri', 'RSend devtools::install(keep_source=TRUE)', 'Install') +nmap_leader('rk', 'RSend quarto::quarto_preview("%")', 'Knit file') +nmap_leader('rl', 'RSend devtools::load_all()', 'Load all') +nmap_leader('rL', 'RSend devtools::load_all(recompile=TRUE)', 'Load all recompile') +nmap_leader('rm', 'RSend Rcpp::compileAttributes()', 'Run examples') +nmap_leader('rT', 'RSend testthat::test_file("%")', 'Test file') +nmap_leader('rt', 'RSend devtools::test()', 'Test') + +-- - Copy to clipboard and make reprex (which itself is loaded to clipboard) +xmap_leader('rx', '"+y :RSend reprex::reprex()', 'Reprex selection') + +-- s is for 'send' (Send text to neoterm buffer) +nmap_leader('s', 'SlimeSendCurrentLinej', 'Send to terminal') + +-- - In simple visual mode send text and move to the last character in +-- selection and move to the right. Otherwise (like in line or block visual +-- mode) send text and move one line down from bottom of selection. +xmap_leader('s', 'SlimeRegionSend', 'Send to terminal') + +-- t is for 'terminal' +vim.keymap.set("t", "", [[]], { desc = "Exit terminal mode" }) +vim.keymap.set("n", "tc", 'lua Config.terminal.open_clickhouse_client()', + { desc = "Open Clickhouse client" }) +vim.keymap.set("n", "tl", 'lua Config.terminal.open_clickhouse_local()', + { desc = "Open Clickhouse local" }) +vim.keymap.set("n", "tp", 'lua Config.terminal.open_python()', { desc = "Open Python" }) +vim.keymap.set("n", "tj", 'lua Config.terminal.open_julia()', { desc = "Open Julia" }) +vim.keymap.set("n", "td", 'lua Config.terminal.open_duckdb();Config.terminal.toggle_bracket()', + { desc = "Open DuckDB" }) +vim.keymap.set("n", "tx", 'lua Config.terminal.open_in_terminal()', { desc = "Terminal Command" }) +vim.keymap.set("n", "tt", 'lua Config.terminal.open_shell()', { desc = "Terminal" }) +nmap_leader("tb", 'lua Config.terminal.toggle_bracket()', "Toggle bracketed paste") +nmap_leader("up", 'lua Config.terminal.toggle_bracket()', "Toggle bracketed paste") + +-- u is for UI +nmap_leader('ut', 'TSContext toggle', 'Toggle TScontext') +nmap_leader('ua', 'Copilot toggle', 'Toggle AI completion') + +-- v is for 'visits' +nmap_leader('vv', 'lua MiniVisits.add_label("core")', 'Add "core" label') +nmap_leader('vV', 'lua MiniVisits.remove_label("core")', 'Remove "core" label') +nmap_leader('vl', 'lua MiniVisits.add_label()', 'Add label') +nmap_leader('vL', 'lua MiniVisits.remove_label()', 'Remove label') + +local map_pick_core = function(keys, cwd, desc) + local rhs = function() + local sort_latest = MiniVisits.gen_sort.default({ recency_weight = 1 }) + MiniExtra.pickers.visit_paths({ + cwd = cwd, + filter = 'core', + sort = sort_latest + }, { source = { name = desc } }) + end + nmap_leader(keys, rhs, desc) +end +map_pick_core('vc', '', 'Core visits (all)') +map_pick_core('vC', nil, 'Core visits (cwd)') + +-- w is for 'windows' +nmap_leader("wh", "h", "Go to Left Window", { remap = true }) +nmap_leader("wj", "j", "Go to Lower Window", { remap = true }) +nmap_leader("wk", "k", "Go to Upper Window", { remap = true }) +nmap_leader("wl", "l", "Go to Right Window", { remap = true }) + +nmap_leader("_", "s", "Split Window Below", { remap = true }) +nmap_leader("|", "v", "Split Window Right", { remap = true }) +nmap_leader("wd", "c", "Delete Window", { remap = true }) +nmap_leader("wo", "o", "Delete Other Windows", { remap = true }) + +-- z is for 'ZettelKasten' +nmap_leader("zo", 'ZkNotes', "Notes") +nmap_leader("zt", 'ZkTags', "Tags") + +nmap_leader( + "zrd", + 'ZkNew { group = "dreviews" }', + "Daily Review" +) +nmap_leader( + "zrw", + 'ZkNew { group = "wreviews" }', + "Weekly Review" +) +nmap_leader( + "zn", + 'ZkNew { group = "inbox", title = vim.fn.input("Title: ") }', + "New" +) +nmap_leader( + "zp", + "ZkNew { group = 'permanent', title = vim.fn.input('Title: ') }", + "Permanent" +) + +nmap_leader( + "zl", + "ZkNew { group = 'literature', title = vim.fn.input('Title: '), extra.author = vim.fn.input('Author: '), extra.year = vim.fn.input('Year: ') }", + "Literature" +) + +nmap_leader( + "zd", + "ZkNew { group = 'dashboard', title = vim.fn.input('Title: ') }", + "Dashboard" +) +nmap_leader( + "zP", + "ZkNew { group = 'project', title = vim.fn.input('Title: ')}", + "Project" +) +-- stylua: ignore end diff --git a/plugin/20_startup.lua b/plugin/20_startup.lua index 36bab13..e8d6693 100644 --- a/plugin/20_startup.lua +++ b/plugin/20_startup.lua @@ -1,4 +1,3 @@ -local Config = require('config') local now = MiniDeps.now local later = MiniDeps.later local now_if_args = Config.now_if_args diff --git a/plugin/21_datascience.lua b/plugin/21_datascience.lua index 807d8ed..cb496b9 100644 --- a/plugin/21_datascience.lua +++ b/plugin/21_datascience.lua @@ -22,6 +22,7 @@ end -- terminal later(function() + vim.g.slime_target = "neovim" vim.g.slime_no_mappings = true add("vim-slime") vim.g.slime_cell_delimiter = vim.g.slime_cell_delimiter or "# %%" diff --git a/plugin/22_languages.lua b/plugin/22_languages.lua index cd5ebed..70bec23 100644 --- a/plugin/22_languages.lua +++ b/plugin/22_languages.lua @@ -1,5 +1,3 @@ -local Config = require('config') - local add = Config.add local now_if_args = Config.now_if_args local later = MiniDeps.later @@ -32,68 +30,6 @@ later(function() end end) --- Linting (via nvim-lint) -later(function() - Config.add("nvim-lint") - local lint_ok, lint = pcall(require, "lint") - if not lint_ok then - return - end - - -- R code style via lintr (must be available in the R runtime). - -- lintr::lint() returns a "lints" object; format() turns it into the - -- standard "file:line:col: severity: message" lines. - lint.linters.lintr = { - cmd = "Rscript", - stdin = false, - args = { - "-e", - "args <- commandArgs(trailingOnly=TRUE); l <- lintr::lint(args[1]); if (length(l) > 0) cat(paste(format(l), collapse='\\n'), '\\n')", - }, - append_fname = true, - stream = "both", - ignore_exitcode = true, - parser = function(output, bufnr, linter_cwd) - local diagnostics = {} - -- Pattern: /path/file.R:10:5: style: Some message - for line in output:gmatch("[^\r\n]+") do - local path, lnum, col, severity, message = line:match("^[^:]+:(%d+):(%d+):%s*(%w+):%s*(.+)$") - if path then - local severity_map = { - style = vim.diagnostic.severity.INFO, - warning = vim.diagnostic.severity.WARN, - error = vim.diagnostic.severity.ERROR, - } - table.insert(diagnostics, { - bufnr = bufnr, - lnum = math.max(0, tonumber(lnum) - 1), - col = math.max(0, tonumber(col) - 1), - end_lnum = tonumber(lnum) - 1, - end_col = tonumber(col), - severity = severity_map[severity:lower()] or vim.diagnostic.severity.WARN, - message = message or "lintr issue", - source = "lintr", - }) - end - end - return diagnostics - end, - } - - lint.linters_by_ft = { - r = { "lintr" }, - rmd = { "lintr" }, - quarto = { "lintr" }, - } - - vim.api.nvim_create_autocmd({ "BufReadPost", "BufWritePost", "InsertLeave" }, { - group = vim.api.nvim_create_augroup("LintOnEvents", { clear = true }), - callback = function() - lint.try_lint() - end, - }) -end) - -- Markdown now_if_args(function() add("render-markdown.nvim") diff --git a/plugin/24_completion.lua b/plugin/24_completion.lua index c2291c7..f6516a1 100644 --- a/plugin/24_completion.lua +++ b/plugin/24_completion.lua @@ -1,4 +1,3 @@ -local Config = require('config') local add = Config.add local later = MiniDeps.later local now = MiniDeps.now diff --git a/plugin/25_lsp.lua b/plugin/25_lsp.lua index 5250cdd..8c40915 100644 --- a/plugin/25_lsp.lua +++ b/plugin/25_lsp.lua @@ -1,4 +1,3 @@ -local Config = require('config') local now_if_args = Config.now_if_args if not Config.isNixCats then @@ -17,73 +16,6 @@ now_if_args(function() marksman = { filetypes = { "markdown", "markdown_inline", "codecompanion" }, }, - harper_ls = { - cmd = { "harper-ls", "--stdio" }, - filetypes = { "markdown", "quarto", "text", "tex", "typst" }, - root_markers = { ".git", ".harper" }, - settings = { - ["harper-ls"] = { - linters = { - SpellCheck = true, - SpelledNumbers = false, - AnA = true, - SentenceCapitalization = true, - UnclosedQuotes = true, - WrongApostrophe = false, - LongSentences = true, - RepeatedWords = true, - Spaces = true, - CorrectNumberSuffix = true, - }, - codeActions = { - ForceStable = false, - }, - markdown = { - IgnoreLinkTitle = false, - }, - diagnosticSeverity = "hint", - isolateEnglish = false, - dialect = "American", - maxFileLength = 120000, - }, - }, - }, - nil_ls = { - settings = { - ["nil"] = { - formatting = { - command = { "alejandra" }, - }, - }, - }, - }, - nixd = { - settings = { - nixd = { - formatting = { - command = { "alejandra" }, - }, - options = { - -- Downstream flakes can override these via lib.mkMerge on the lsp config. - nixos = { expr = "(builtins.getFlake \"/etc/nixos\").nixosConfigurations.\"default\".options" }, - home_manager = { expr = "(builtins.getFlake \"/etc/nixos\").homeConfigurations.\"default\".options" }, - }, - }, - }, - }, - yamlls = { - settings = { - yaml = { - schemas = { - ["https://raw.githubusercontent.com/quarto-dev/quarto-cli/main/src/resources/schema/project.json"] = "**/_quarto.yml", - ["https://raw.githubusercontent.com/quarto-dev/quarto-cli/main/src/resources/schema/document-quarto.json"] = "**/*.qmd", - }, - }, - }, - }, - texlab = { - single_file_support = true, - }, julials = { settings = { julia = { diff --git a/plugin/26_dap.lua b/plugin/26_dap.lua deleted file mode 100644 index 73deeb8..0000000 --- a/plugin/26_dap.lua +++ /dev/null @@ -1,79 +0,0 @@ -local Config = require('config') - -local later = MiniDeps.later -local nix = require('config.nix') - -later(function() - -- Only pull in the DAP packages when R (the only cat that has a real - -- adapter for now) is enabled; otherwise the lazy load + autoload chain - -- still works but those three would sit unused on the runtime path. - if not nix.get_cat("r", false) then - return - end - - Config.add("nvim-dap") - Config.add("nvim-dap-ui") - Config.add("nvim-dap-virtual-text") -end) - -later(function() - if not nix.get_cat("r", false) then - return - end - - local dap_ok, dap = pcall(require, "dap") - if not dap_ok then - vim.notify("nvim-dap not available", vim.log.levels.WARN) - return - end - - local dapui_ok, dapui = pcall(require, "dapui") - if dapui_ok then - dapui.setup() - dap.listeners.after.event_initialized["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 - end - - local vt_ok, _ = pcall(require, "nvim-dap-virtual-text") - if vt_ok then - -- Default setup is enough; virtual text is enabled automatically. - end - - -- R adapter via vscDebugger (https://github.com/cwida/vscDebugger) - if nix.get_cat("r", false) then - dap.adapters.r = { - type = "executable", - command = "R", - args = { - "--quiet", - "--no-save", - "-e", - "vscDebugger::main()", - }, - } - - dap.configurations.r = { - { - type = "r", - name = "Debug current R script", - request = "launch", - program = "${file}", - debugMode = "function", - }, - { - type = "r", - name = "Attach to R process", - request = "attach", - hostName = "localhost", - port = 18721, - }, - } - end -end) diff --git a/plugin/27_image.lua b/plugin/27_image.lua deleted file mode 100644 index 89e0d2f..0000000 --- a/plugin/27_image.lua +++ /dev/null @@ -1,50 +0,0 @@ -local Config = require('config') - -local later = MiniDeps.later -local nix = require('config.nix') - --- Only load image-nvim when a cat that benefits from in-buffer plots is on. -later(function() - if not nix.get_cat({ "r", "markdown" }, false) then - return - end - - Config.add("image-nvim") -end) - -later(function() - if not nix.get_cat({ "r", "markdown" }, false) then - return - end - - local ok, image = pcall(require, "image") - if not ok then - vim.notify("image.nvim not available", vim.log.levels.DEBUG) - return - end - - image.setup({ - -- Backend is intentionally NOT set so image.nvim auto-detects the - -- graphics protocol (kitty / wezterm / iterm / sixel) at runtime and - -- falls back to no rendering on unsupported terminals. The literal - -- strings "auto" / "none" are not accepted by image.nvim.setup(), so - -- setting either would silently disable rendering everywhere. - integrations = { - markdown = { - enabled = true, - clear_in_insert_mode = false, - download_remote_images = true, - only_render_image_at_cursor = false, - filetypes = { "markdown", "quarto" }, - }, - }, - max_width = nil, - max_height = nil, - max_width_window_percentage = nil, - max_height_window_percentage = 50, - window_overlap_clear_enabled = false, - window_overlap_clear_ft_ignore = { "cmp_menu", "cmp_docs" }, - editor_only_render_when_focused = false, - hijack_file_patterns = { "*.png", "*.jpg", "*.jpeg", "*.gif", "*.webp" }, - }) -end) diff --git a/plugin/28_latex.lua b/plugin/28_latex.lua deleted file mode 100644 index 3b24f9e..0000000 --- a/plugin/28_latex.lua +++ /dev/null @@ -1,38 +0,0 @@ --- vimtex integration for raw .tex workflows (paper drafts, AEA submissions, --- beamer slides). Rides in the `markdown` cat because Quarto users routinely --- also write standalone .tex. - -local Config = require('config') -local later = MiniDeps.later -local nix = require('config.nix') - -later(function() - if not nix.get_cat("markdown", false) then - return - end - - -- vimtex is a VimL plugin: it does not expose a Lua module. Configure it - -- via globals before loading so the plugin picks them up on startup. - vim.g.vimtex_compiler_method = "latexmk" - vim.g.vimtex_compiler_latexmk = { - -- Keep conservative defaults: no continuous background compilation and no - -- callback chatter. Manual :VimtexCompile still works on demand. - continuous = 0, - callback = 0, - } - -- Let vimtex choose the first available viewer (zathura, Skim, Evince, ...). - - Config.add("vimtex") - - -- Filetype detection is normally on, but force it explicitly so .tex files - -- opened outside Quarto still pick up the LSP + viewer hooks. - vim.api.nvim_create_autocmd("BufReadPost", { - pattern = { "*.tex", "*.sty", "*.cls" }, - callback = function(args) - local buf = args.buf - if vim.api.nvim_buf_is_loaded(buf) then - vim.bo[buf].filetype = "tex" - end - end, - }) -end)