diff --git a/CHANGELOG.md b/CHANGELOG.md index 9a6c5eb..6708432 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,34 @@ # Changelog +## [3.11.0](https://github.com/jmbuhr/quarto-nvim-kickstarter/compare/v3.10.0...v3.11.0) (2024-07-05) + + +### Features + +* use telescope for some lsp handlers ([f1a04a5](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/f1a04a56be42e6e24c0af93b3d600653138f7988)) + +## [3.10.0](https://github.com/jmbuhr/quarto-nvim-kickstarter/compare/v3.9.0...v3.10.0) (2024-06-29) + + +### Features + +* json ls ([887f798](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/887f7986091c386fba8d44f0414930250b4022d5)) + +## [3.9.0](https://github.com/jmbuhr/quarto-nvim-kickstarter/compare/v3.8.1...v3.9.0) (2024-05-18) + + +### Features + +* kanagawa colorscheme ([a9995a0](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/a9995a0cecc5f16a041c1b5259b99bb91a8b6cdd)) +* oil.nvim to edit the filesystem as a buffer ([69b73eb](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/69b73ebb52ab5f794af31fa345aa590137045771)) +* virtual text for dap ([1bdaab3](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/1bdaab3f54ee03084e291bb7cf1b2fab37f7401a)) + + +### Bug Fixes + +* full screen image preview ([ef0bbee](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/ef0bbeee56434969a8c0c4cec86527a6e820c199)) +* no signcolumn for terminal windows ([bb3fa64](https://github.com/jmbuhr/quarto-nvim-kickstarter/commit/bb3fa644d6516b4fc060042c74878f1af81d0774)) + ## [3.8.1](https://github.com/jmbuhr/quarto-nvim-kickstarter/compare/v3.8.0...v3.8.1) (2024-05-13) diff --git a/README.md b/README.md index fcefb03..e86b88c 100644 --- a/README.md +++ b/README.md @@ -40,6 +40,7 @@ sudo apt install imagemagick sudo apt install libmagickwand-dev sudo apt install liblua5.1-0-dev sudo apt install luajit +sudo apt install tree-sitter-cli ``` Manually installing luarocks and the magick rock is no longer required, this is handled by [luarocks.nvim](https://github.com/vhyrro/luarocks.nvim). diff --git a/after/queries/python/injections.scm b/after/queries/python/injections.scm new file mode 100644 index 0000000..2629c61 --- /dev/null +++ b/after/queries/python/injections.scm @@ -0,0 +1,25 @@ +; extends +((call + function: (identifier) @function_name (#eq? @function_name "Style") + arguments: (argument_list + (string + (string_content) @injection.content))) + + (#set! injection.language "css")) + +((call + function: (identifier) @function_name (#eq? @function_name "Script") + arguments: (argument_list + (string + (string_content) @injection.content))) + + (#set! injection.language "javascript")) + +((call + function: (identifier) @function_name (#eq? @function_name "On") + arguments: (argument_list + + (string + (string_content) @injection.content)) + + (#set! injection.language "javascript"))) diff --git a/ftplugin/python.lua b/ftplugin/python.lua index 64762dc..4e4b6b1 100644 --- a/ftplugin/python.lua +++ b/ftplugin/python.lua @@ -1 +1,3 @@ vim.b.slime_cell_delimiter = '#\\s\\=%%' + +require("otter").activate() diff --git a/init.lua b/init.lua index 20e0803..1fdb26d 100644 --- a/init.lua +++ b/init.lua @@ -13,3 +13,9 @@ require 'config.global' require 'config.lazy' require 'config.autocommands' +require 'config.redir' + + +vim.treesitter.language.add('pandoc_markdown', { path = "/usr/local/lib/libtree-sitter-pandoc-markdown.so" }) +vim.treesitter.language.add('pandoc_markdown_inline', { path = "/usr/local/lib/libtree-sitter-pandoc-markdown-inline.so" }) +vim.treesitter.language.register('pandoc_markdown', { 'quarto', 'rmarkdown' }) diff --git a/lua/config/global.lua b/lua/config/global.lua index 0861819..24b1cfb 100644 --- a/lua/config/global.lua +++ b/lua/config/global.lua @@ -114,6 +114,8 @@ vim.diagnostic.config { vim.filetype.add { extension = { ojs = 'javascript', + pyodide = 'python', + webr = 'r', }, } diff --git a/lua/config/keymap.lua b/lua/config/keymap.lua index ddad173..6fb15d3 100644 --- a/lua/config/keymap.lua +++ b/lua/config/keymap.lua @@ -1,5 +1,6 @@ -- required in which-key plugin spec in plugins/ui.lua as `require 'config.keymap'` local wk = require 'which-key' +local ms = vim.lsp.protocol.Methods P = vim.print @@ -53,9 +54,24 @@ nmap('Q', '') --- and will handle python code via reticulate when sent --- from a python chunk. --- TODO: incorpoarate this into quarto-nvim plugin ---- such that QuartoRun functions get the same capabilities +--- such that QuartoSend functions get the same capabilities --- TODO: figure out bracketed paste for reticulate python repl. local function send_cell() + local has_molten, molten_status = pcall(require, 'molten.status') + local molten_works = false + local molten_active = "" + if has_molten then + molten_works, molten_active = pcall(molten_status.kernels) + end + if molten_works and molten_active ~= vim.NIL and molten_active ~= "" then + molten_active = molten_status.initialized() + end + if molten_active ~= vim.NIL and molten_active ~= "" and molten_status.kernels() ~= "Molten" then + vim.cmd.QuartoSend() + return + end + + if vim.b['quarto_is_r_mode'] == nil then vim.fn['slime#send_cell']() return @@ -202,46 +218,52 @@ end --show up in the popup as well -- normal mode -wk.register({ - [''] = { 'lua vim.lsp.buf.definition()', 'go to definition' }, - [''] = { 'q', 'close buffer' }, - [''] = { 'noh', 'remove search highlight' }, - ['n'] = { 'nzzzv', 'center search' }, - ['gN'] = { 'Nzzzv', 'center search' }, - ['gl'] = { '', 'open help link' }, - ['gf'] = { ':e ', 'edit file' }, - [''] = { insert_r_chunk, 'r code chunk' }, - [''] = { insert_py_chunk, 'python code chunk' }, - [''] = { insert_py_chunk, 'python code chunk' }, - [']q'] = { ':silent cnext', '[q]uickfix next' }, - ['[q'] = { ':silent cprev', '[q]uickfix prev' }, - ['z?'] = { ':setlocal spell!', 'toggle [z]pellcheck' }, - ['zl'] = { ':Telescope spell_suggest', '[l]ist spelling suggestions' }, +wk.add({ + { "", "lua vim.lsp.buf.definition()", desc = "go to definition" }, + { "", "q", desc = "close buffer" }, + { "", insert_py_chunk, desc = "python code chunk" }, + { "", "noh", desc = "remove search highlight" }, + { "", insert_py_chunk, desc = "python code chunk" }, + { "", insert_r_chunk, desc = "r code chunk" }, + { "[q", ":silent cprev", desc = "[q]uickfix prev" }, + { "]q", ":silent cnext", desc = "[q]uickfix next" }, + { "gN", "Nzzzv", desc = "center search" }, + { "gf", ":e ", desc = "edit file" }, + { "gl", "", desc = "open help link" }, + { "n", "nzzzv", desc = "center search" }, + { "z?", ":setlocal spell!", desc = "toggle [z]pellcheck" }, + { "zl", ":Telescope spell_suggest", desc = "[l]ist spelling suggestions" }, }, { mode = 'n', silent = true }) -- visual mode -wk.register({ - [''] = { send_region, 'run code region' }, - [''] = { ":m'>+`mzgv`yo`z", 'move line down' }, - [''] = { ":m'<-2`>my`', 'repat last normal mode command' }, - ['q'] = { ':norm @q', 'repat q macro' }, -}, { mode = 'v' }) +wk.add({ + { + mode = { "v" }, + { ".", ":norm .", desc = "repat last normal mode command" }, + { "", ":m'>+`mzgv`yo`z", desc = "move line down" }, + { "", ":m'<-2`>my`", send_region, desc = "run code region" }, + { "q", ":norm @q", desc = "repat q macro" }, + }, +}) -- visual with -wk.register({ - p = { '"_dP', 'replace without overwriting reg' }, - d = { '"_d', 'delete without overwriting reg' }, -}, { mode = 'v', prefix = '' }) +wk.add({ + { "d", '"_d', desc = "delete without overwriting reg", mode = "v" }, + { "p", '"_dP', desc = "replace without overwriting reg", mode = "v" }, +}, { mode = 'v' }) -- insert mode -wk.register({ - [''] = { ' <- ', 'assign' }, - [''] = { ' |>', 'pipe' }, - [''] = { insert_r_chunk, 'r code chunk' }, - [''] = { insert_py_chunk, 'python code chunk' }, - [''] = { insert_py_chunk, 'python code chunk' }, - [''] = { '', 'omnifunc completion' }, +wk.add({ + { + mode = { "i" }, + { "", "", desc = "omnifunc completion" }, + { "", insert_py_chunk, desc = "python code chunk" }, + { "", " <- ", desc = "assign" }, + { "", insert_py_chunk, desc = "python code chunk" }, + { "", insert_r_chunk, desc = "r code chunk" }, + { "", " |>", desc = "pipe" }, + }, }, { mode = 'i' }) local function new_terminal(lang) @@ -268,144 +290,113 @@ local function new_terminal_shell() new_terminal '$SHELL' end +local function get_otter_symbols_lang() + local otterkeeper = require 'otter.keeper' + local main_nr = vim.api.nvim_get_current_buf() + local langs = {} + for i, l in ipairs(otterkeeper.rafts[main_nr].languages) do + langs[i] = i .. ': ' .. l + end + -- promt to choose one of langs + local i = vim.fn.inputlist(langs) + local lang = otterkeeper.rafts[main_nr].languages[i] + local params = { + textDocument = vim.lsp.util.make_text_document_params(), + otter = { + lang = lang + } + } + -- don't pass a handler, as we want otter to use it's own handlers + vim.lsp.buf_request(main_nr, ms.textDocument_documentSymbol, params, nil) +end + +vim.keymap.set("n", "os", get_otter_symbols_lang, { desc = "otter [s]ymbols" }) + + -- normal mode with -wk.register({ - [''] = { send_cell, 'run code cell' }, - c = { - name = '[c]ode / [c]ell / [c]hunk', - n = { new_terminal_shell, '[n]ew terminal with shell' }, - r = { - function() - vim.b['quarto_is_r_mode'] = true - new_terminal_r() - end, - 'new [R] terminal', - }, - p = { new_terminal_python, 'new [p]ython terminal' }, - i = { new_terminal_ipython, 'new [i]python terminal' }, - j = { new_terminal_julia, 'new [j]ulia terminal' }, - }, - e = { - name = '[e]dit', - }, - d = { - name = '[d]ebug', - t = { - name = '[t]est', - }, - }, - f = { - name = '[f]ind (telescope)', - f = { 'Telescope find_files', '[f]iles' }, - h = { 'Telescope help_tags', '[h]elp' }, - k = { 'Telescope keymaps', '[k]eymaps' }, - r = { 'Telescope lsp_references', '[r]eferences' }, - g = { 'Telescope live_grep', '[g]rep' }, - b = { 'Telescope current_buffer_fuzzy_find', '[b]uffer fuzzy find' }, - m = { 'Telescope marks', '[m]arks' }, - M = { 'Telescope man_pages', '[M]an pages' }, - c = { 'Telescope git_commits', 'git [c]ommits' }, - s = { 'Telescope lsp_document_symbols', 'document [s]ymbols' }, - [''] = { 'Telescope buffers', '[ ] buffers' }, - d = { 'Telescope buffers', '[d] buffers' }, - q = { 'Telescope quickfix', '[q]uickfix' }, - l = { 'Telescope loclist', '[l]oclist' }, - j = { 'Telescope jumplist', '[j]umplist' }, - }, - g = { - name = '[g]it', - c = { ':GitConflictRefresh', '[c]onflict' }, - s = { ':Gitsigns', 'git [s]igns' }, - wc = { ":lua require('telescope').extensions.git_worktree.create_git_worktree()", 'worktree create' }, - ws = { ":lua require('telescope').extensions.git_worktree.git_worktrees()", 'worktree switch' }, - d = { - name = '[d]iff', - o = { ':DiffviewOpen', '[o]pen' }, - c = { ':DiffviewClose', '[c]lose' }, - }, - b = { - name = '[b]lame', - b = { ':GitBlameToggle', '[b]lame toggle virtual text' }, - o = { ':GitBlameOpenCommitURL', '[o]pen' }, - c = { ':GitBlameCopyCommitURL', '[c]opy' }, - }, - }, - h = { - name = '[h]elp / [h]ide / debug', - c = { - name = '[c]onceal', - h = { ':set conceallevel=1', '[h]ide/conceal' }, - s = { ':set conceallevel=0', '[s]how/unconceal' }, - }, - t = { - name = '[t]reesitter', - t = { vim.treesitter.inspect_tree, 'show [t]ree' }, - }, - }, - i = { - name = '[i]mage', - }, - l = { - name = '[l]anguage/lsp', - r = { 'Telescope lsp_references', '[r]eferences' }, - R = { '[R]ename' }, - D = { vim.lsp.buf.type_definition, 'type [D]efinition' }, - a = { vim.lsp.buf.code_action, 'code [a]ction' }, - e = { vim.diagnostic.open_float, 'diagnostics (show hover [e]rror)' }, - d = { - name = '[d]iagnostics', - d = { vim.diagnostic.disable, '[d]isable' }, - e = { vim.diagnostic.enable, '[e]nable' }, - }, - g = { ':Neogen', 'neo[g]en docstring' }, - }, - o = { - name = '[o]tter & c[o]de', - a = { require('otter').dev_setup, 'otter [a]ctivate' }, - d = { require('otter').deactivate, 'otter [d]eactivate' }, - c = { 'O# %%', 'magic [c]omment code chunk # %%' }, - r = { insert_r_chunk, '[r] code chunk' }, - p = { insert_py_chunk, '[p]ython code chunk' }, - j = { insert_julia_chunk, '[j]ulia code chunk' }, - b = { insert_bash_chunk, '[b]ash code chunk' }, - o = { insert_ojs_chunk, '[o]bservable js code chunk' }, - l = { insert_lua_chunk, '[l]lua code chunk' }, - }, - q = { - name = '[q]uarto', - a = { ':QuartoActivate', '[a]ctivate' }, - p = { ":lua require'quarto'.quartoPreview()", '[p]review' }, - q = { ":lua require'quarto'.quartoClosePreview()", '[q]uiet preview' }, - h = { ':QuartoHelp ', '[h]elp' }, - r = { - name = '[r]un', - r = { ':QuartoSendAbove', 'to cu[r]sor' }, - a = { ':QuartoSendAll', 'run [a]ll' }, - b = { ':QuartoSendBelow', 'run [b]elow' }, - }, - e = { require('otter').export, '[e]xport' }, - E = { - function() - require('otter').export(true) - end, - '[E]xport with overwrite', - }, - }, - r = { - name = '[r] R specific tools', - t = { show_r_table, 'show [t]able' }, - }, - v = { - name = '[v]im', - t = { toggle_light_dark_theme, '[t]oggle light/dark theme' }, - c = { ':Telescope colorscheme', '[c]olortheme' }, - l = { ':Lazy', '[l]azy package manager' }, - m = { ':Mason', '[m]ason software installer' }, - s = { ':e $MYVIMRC | :cd %:p:h | split . | wincmd k', '[s]ettings, edit vimrc' }, - h = { ':execute "h " . expand("")', 'vim [h]elp for current word' }, - }, - x = { - name = 'e[x]ecute', - x = { ':w:source %', '[x] source %' }, - }, -}, { mode = 'n', prefix = '' }) +wk.add({ + { + { "", send_cell, desc = "run code cell" }, + { "c", group = "[c]ode / [c]ell / [c]hunk" }, + { "ci", new_terminal_ipython, desc = "new [i]python terminal" }, + { "cj", new_terminal_julia, desc = "new [j]ulia terminal" }, + { "cn", new_terminal_shell, desc = "[n]ew terminal with shell" }, + { "cp", new_terminal_python, desc = "new [p]ython terminal" }, + { "cr", new_terminal_r, desc = "new [R] terminal" }, + { "d", group = "[d]ebug" }, + { "dt", group = "[t]est" }, + { "e", group = "[e]dit" }, + { "f", group = "[f]ind (telescope)" }, + { "f", "Telescope buffers", desc = "[ ] buffers" }, + { "fM", "Telescope man_pages", desc = "[M]an pages" }, + { "fb", "Telescope current_buffer_fuzzy_find", desc = "[b]uffer fuzzy find" }, + { "fc", "Telescope git_commits", desc = "git [c]ommits" }, + { "fd", "Telescope buffers", desc = "[d] buffers" }, + { "ff", "Telescope find_files", desc = "[f]iles" }, + { "fg", "Telescope live_grep", desc = "[g]rep" }, + { "fh", "Telescope help_tags", desc = "[h]elp" }, + { "fj", "Telescope jumplist", desc = "[j]umplist" }, + { "fk", "Telescope keymaps", desc = "[k]eymaps" }, + { "fl", "Telescope loclist", desc = "[l]oclist" }, + { "fm", "Telescope marks", desc = "[m]arks" }, + { "fq", "Telescope quickfix", desc = "[q]uickfix" }, + { "g", group = "[g]it" }, + { "gb", group = "[b]lame" }, + { "gbb", ":GitBlameToggle", desc = "[b]lame toggle virtual text" }, + { "gbc", ":GitBlameCopyCommitURL", desc = "[c]opy" }, + { "gbo", ":GitBlameOpenCommitURL", desc = "[o]pen" }, + { "gc", ":GitConflictRefresh", desc = "[c]onflict" }, + { "gd", group = "[d]iff" }, + { "gdc", ":DiffviewClose", desc = "[c]lose" }, + { "gdo", ":DiffviewOpen", desc = "[o]pen" }, + { "gs", ":Gitsigns", desc = "git [s]igns" }, + { "gwc", ":lua require('telescope').extensions.git_worktree.create_git_worktree()", desc = "worktree create" }, + { "gws", ":lua require('telescope').extensions.git_worktree.git_worktrees()", desc = "worktree switch" }, + { "h", group = "[h]elp / [h]ide / debug" }, + { "hc", group = "[c]onceal" }, + { "hch", ":set conceallevel=1", desc = "[h]ide/conceal" }, + { "hcs", ":set conceallevel=0", desc = "[s]how/unconceal" }, + { "ht", group = "[t]reesitter" }, + { "htt", vim.treesitter.inspect_tree, desc = "show [t]ree" }, + { "i", group = "[i]mage" }, + { "l", group = "[l]anguage/lsp" }, + { "la", vim.lsp.buf.code_action, desc = "code [a]ction" }, + { "ld", group = "[d]iagnostics" }, + { "ldd", function() vim.diagnostic.enable(false) end, desc = "[d]isable" }, + { "lde", vim.diagnostic.enable, desc = "[e]nable" }, + { "le", vim.diagnostic.open_float, desc = "diagnostics (show hover [e]rror)" }, + { "lg", ":Neogen", desc = "neo[g]en docstring" }, + { "o", group = "[o]tter & c[o]de" }, + { "oa", require 'otter'.activate, desc = "otter [a]ctivate" }, + { "ob", insert_bash_chunk, desc = "[b]ash code chunk" }, + { "oc", "O# %%", desc = "magic [c]omment code chunk # %%" }, + { "od", require 'otter'.activate, desc = "otter [d]eactivate" }, + { "oj", insert_julia_chunk, desc = "[j]ulia code chunk" }, + { "ol", insert_lua_chunk, desc = "[l]lua code chunk" }, + { "oo", insert_ojs_chunk, desc = "[o]bservable js code chunk" }, + { "op", insert_py_chunk, desc = "[p]ython code chunk" }, + { "or", insert_r_chunk, desc = "[r] code chunk" }, + { "q", group = "[q]uarto" }, + { "qE", function() require('otter').export(true) end, desc = "[E]xport with overwrite" }, + { "qa", ":QuartoActivate", desc = "[a]ctivate" }, + { "qe", require('otter').export, desc = "[e]xport" }, + { "qh", ":QuartoHelp ", desc = "[h]elp" }, + { "qp", ":lua require'quarto'.quartoPreview()", desc = "[p]review" }, + { "qq", ":lua require'quarto'.quartoClosePreview()", desc = "[q]uiet preview" }, + { "qr", group = "[r]un" }, + { "qra", ":QuartoSendAll", desc = "run [a]ll" }, + { "qrb", ":QuartoSendBelow", desc = "run [b]elow" }, + { "qrr", ":QuartoSendAbove", desc = "to cu[r]sor" }, + { "r", group = "[r] R specific tools" }, + { "rt", show_r_table, desc = "show [t]able" }, + { "v", group = "[v]im" }, + { "vc", ":Telescope colorscheme", desc = "[c]olortheme" }, + { "vh", ':execute "h " . expand("")', desc = "vim [h]elp for current word" }, + { "vl", ":Lazy", desc = "[l]azy package manager" }, + { "vm", ":Mason", desc = "[m]ason software installer" }, + { "vs", ":e $MYVIMRC | :cd %:p:h | split . | wincmd k", desc = "[s]ettings, edit vimrc" }, + { "vt", toggle_light_dark_theme, desc = "[t]oggle light/dark theme" }, + { "x", group = "e[x]ecute" }, + { "xx", ":w:source %", desc = "[x] source %" }, + } +}, { mode = 'n' }) diff --git a/lua/config/redir.lua b/lua/config/redir.lua new file mode 100644 index 0000000..7757b93 --- /dev/null +++ b/lua/config/redir.lua @@ -0,0 +1,178 @@ +-- by: https://gist.github.com/Leenuus/7a2ea47b88bfe16430b42e4e48122718 + +vim.g.DEBUG = false +local log = require("plenary.log").new({ + plugin = "redir", +}) + +local function redir_open_win(buf, vertical, stderr_p) + local wn = stderr_p and "redir_sterr_win" or "redir_win" + if vim.g[wn] == nil then + local win = vim.api.nvim_open_win(buf, true, { + vertical = vertical, + }) + vim.api.nvim_create_autocmd("WinClosed", { + pattern = { string.format("%d", win) }, + callback = function() + vim.g[wn] = nil + end, + }) + vim.g[wn] = win + else + vim.api.nvim_win_set_buf(vim.g[wn], buf) + end +end + +local function redir_vim_command(cmd, vertical) + vim.cmd("redir => output") + vim.cmd("silent " .. cmd) + vim.cmd("redir END") + local output = vim.fn.split(vim.g.output, "\n") + local buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_buf_set_lines(buf, 0, 0, false, output) + + redir_open_win(buf, vertical) +end + +local function redir_shell_command(cmd, lines, vertical, stderr_p) + local shell_cmd = { + "sh", + "-c", + cmd, + } + + local stdin = nil + if #lines ~= 0 then + stdin = lines + end + + local stdout_buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value("ft", "redir_stdout", { buf = stdout_buf }) + redir_open_win(stdout_buf, vertical) + + local stderr = nil + if stderr_p then + local stderr_buf = vim.api.nvim_create_buf(false, true) + vim.api.nvim_set_option_value("ft", "redir_sterr", { buf = stderr_buf }) + redir_open_win(stderr_buf, vertical, true) + stderr = function(err, data) + vim.schedule_wrap(function() + if data ~= nil then + local output = vim.fn.split(data, "\n") + if vim.g.DEBUG then + log.info("stdout: " .. vim.inspect(output)) + end + vim.api.nvim_buf_set_lines(stderr_buf, -2, -1, false, output) + end + end)() + end + end + + if vim.g.DEBUG then + local report = string.format( + [[lines: %s +stdin: %s +buf: %d +cmd_str: %s +shell_cmd: %s +]], + vim.inspect(lines), + vim.inspect(stdin), + stdout_buf, + cmd, + vim.inspect(shell_cmd) + ) + log.info(report) + end + + vim.system(shell_cmd, { + text = true, + stdout = function(err, stdout) + vim.schedule_wrap(function() + if stdout ~= nil then + local output = vim.fn.split(stdout, "\n") + if vim.g.DEBUG then + log.info("stdout: " .. vim.inspect(output)) + end + vim.api.nvim_buf_set_lines(stdout_buf, -2, -1, false, output) + end + end)() + end, + stderr = stderr, + stdin = stdin, + }, function(completed) + -- NOTE: + -- placeholder to make call async + end) +end + +local function redir(args) + local cmd = args.args + local vertical = args.smods.vertical + local stderr_p = args.bang + + if vim.g.DEBUG then + log.info(vim.inspect(args)) + end + + if cmd:sub(1, 1) == "!" then + local range = args.range + local lines + if range == 0 then + lines = {} + else + local line1 = args.line1 - 1 + local line2 = args.line2 + line2 = line1 == line2 and line1 + 1 or line2 + lines = vim.api.nvim_buf_get_lines(0, line1, line2, false) + end + + cmd = cmd:sub(2) + redir_shell_command(cmd, lines, vertical, stderr_p) + else + redir_vim_command(cmd, vertical) + end +end + +vim.api.nvim_create_user_command("Redir", redir, { + nargs = "+", + complete = "command", + range = true, + bang = true, +}) +vim.cmd([[cabbrev R Redir]]) + +vim.api.nvim_create_user_command("Mes", function() + vim.cmd("Redir messages") +end, { bar = true }) +vim.cmd([[cabbrev M Mes]]) + +local function evaler(range) + return function(bang) + local line = vim.fn.getline(1) + local it = string.match(line, "^#!(.*)") + + local cmd = string.format("%sRedir%s !", range, bang and "!" or "") + + if it and it ~= "" then + vim.cmd(cmd .. it) + else + vim.fn.feedkeys(":" .. cmd, "tn") + end + end +end + +vim.api.nvim_create_user_command("EvalFile", function(args) + local bang = args.bang + evaler("%")(bang) +end, { bar = true, bang = true }) + +vim.api.nvim_create_user_command("EvalLine", function(args) + local bang = args.bang + evaler(".")(bang) +end, { bar = true, bang = true }) + +vim.api.nvim_create_user_command("EvalRange", function(args) + local bang = args.bang + evaler("'<,'>")(bang) +end, { bar = true, bang = true, range = true }) diff --git a/lua/misc/handlers.lua b/lua/misc/handlers.lua new file mode 100644 index 0000000..10b2991 --- /dev/null +++ b/lua/misc/handlers.lua @@ -0,0 +1,216 @@ +-- Custom handlers for LSP actions +-- using telescope.nvim +-- TODO: Some of theses don't work reliably +-- so they are not used, yet. +local pickers = require "telescope.pickers" +local conf = require("telescope.config").values +local finders = require "telescope.finders" +local make_entry = require "telescope.make_entry" +local utils = require "telescope.utils" +local ms = vim.lsp.protocol.Methods + +local M = {} + +---@param action telescope.lsp.list_or_jump_action +---@param items vim.lsp.util.locations_to_items.ret[] +---@param opts table +---@return vim.lsp.util.locations_to_items.ret[] +local apply_action_handler = function(action, items, opts) + if action == "textDocument/references" and not opts.include_current_line then + local lnum = vim.api.nvim_win_get_cursor(opts.winnr)[1] + items = vim.tbl_filter(function(v) + return not (v.filename == opts.curr_filepath and v.lnum == lnum) + end, items) + end + + return items +end + + +--- convert `item` type back to something we can pass to `vim.lsp.util.jump_to_location` +--- stopgap for pre-nvim 0.10 - after which we can simply use the `user_data` +--- field on the items in `vim.lsp.util.locations_to_items` +---@param item vim.lsp.util.locations_to_items.ret +---@param offset_encoding string|nil utf-8|utf-16|utf-32 +---@return lsp.Location +local function item_to_location(item, offset_encoding) + local line = item.lnum - 1 + local character = vim.lsp.util._str_utfindex_enc(item.text, item.col, offset_encoding) - 1 + local uri + if utils.is_uri(item.filename) then + uri = item.filename + else + uri = vim.uri_from_fname(item.filename) + end + return { + uri = uri, + range = { + start = { + line = line, + character = character, + }, + ["end"] = { + line = line, + character = character, + }, + }, + } +end + +local symbols_sorter = function(symbols) + if vim.tbl_isempty(symbols) then + return symbols + end + + local current_buf = vim.api.nvim_get_current_buf() + + -- sort adequately for workspace symbols + local filename_to_bufnr = {} + for _, symbol in ipairs(symbols) do + if filename_to_bufnr[symbol.filename] == nil then + filename_to_bufnr[symbol.filename] = vim.uri_to_bufnr(vim.uri_from_fname(symbol.filename)) + end + symbol.bufnr = filename_to_bufnr[symbol.filename] + end + + table.sort(symbols, function(a, b) + if a.bufnr == b.bufnr then + return a.lnum < b.lnum + end + if a.bufnr == current_buf then + return true + end + if b.bufnr == current_buf then + return false + end + return a.bufnr < b.bufnr + end) + + return symbols +end + + +M.telescope_handler_factory = function(action, title) + + local opts = { + winnr = vim.api.nvim_get_current_win() + } + + if action == ms.textDocument_documentSymbol then + return function(err, result, _, _) + if err then + vim.api.nvim_err_writeln("Error when finding document symbols: " .. err.message) + return + end + + if not result or vim.tbl_isempty(result) then + utils.notify("builtin.lsp_document_symbols", { + msg = "No results from textDocument/documentSymbol", + level = "INFO", + }) + return + end + + local locations = vim.lsp.util.symbols_to_items(result or {}, opts.bufnr) or {} + locations = utils.filter_symbols(locations, opts, symbols_sorter) + if locations == nil then + -- error message already printed in `utils.filter_symbols` + return + end + + if vim.tbl_isempty(locations) then + utils.notify("builtin.lsp_document_symbols", { + msg = "No document_symbol locations found", + level = "INFO", + }) + return + end + + opts.path_display = { "hidden" } + pickers + .new(opts, { + prompt_title = "LSP Document Symbols", + finder = finders.new_table { + results = locations, + entry_maker = opts.entry_maker or make_entry.gen_from_lsp_symbols(opts), + }, + previewer = conf.qflist_previewer(opts), + sorter = conf.prefilter_sorter { + tag = "symbol_type", + sorter = conf.generic_sorter(opts), + }, + push_cursor_on_edit = true, + push_tagstack_on_edit = true, + }) + :find() + end + else + return function(err, result, ctx, _) + if err then + vim.api.nvim_err_writeln("Error when executing " .. action .. " : " .. err.message) + return + end + + if result == nil then + return + end + local locations = {} + if not utils.islist(result) then + locations = { result } + end + vim.list_extend(locations, result) + + local offset_encoding = vim.lsp.get_client_by_id(ctx.client_id).offset_encoding + local items = vim.lsp.util.locations_to_items(locations, offset_encoding) + items = apply_action_handler(action, items, opts) + + if vim.tbl_isempty(items) then + utils.notify(title, { + msg = string.format("No %s found", title), + level = "INFO", + }) + return + end + + if #items == 1 and opts.jump_type ~= "never" then + local item = items[1] + if opts.curr_filepath ~= item.filename then + local cmd + if opts.jump_type == "tab" then + cmd = "tabedit" + elseif opts.jump_type == "split" then + cmd = "new" + elseif opts.jump_type == "vsplit" then + cmd = "vnew" + elseif opts.jump_type == "tab drop" then + cmd = "tab drop" + end + + if cmd then + vim.cmd(string.format("%s %s", cmd, item.filename)) + end + end + + local location = item_to_location(item, offset_encoding) + vim.lsp.util.jump_to_location(location, offset_encoding, opts.reuse_win) + else + pickers + .new(opts, { + prompt_title = title, + finder = finders.new_table { + results = items, + entry_maker = opts.entry_maker or make_entry.gen_from_quickfix(opts), + }, + previewer = conf.qflist_previewer(opts), + sorter = conf.generic_sorter(opts), + push_cursor_on_edit = true, + push_tagstack_on_edit = true, + }) + :find() + end + end + end +end + + +return M diff --git a/lua/plugins/completion.lua b/lua/plugins/completion.lua index 95199de..119e756 100644 --- a/lua/plugins/completion.lua +++ b/lua/plugins/completion.lua @@ -12,7 +12,8 @@ return { event = 'InsertEnter', dependencies = { 'hrsh7th/cmp-nvim-lsp', - 'hrsh7th/cmp-nvim-lsp-signature-help', + -- TODO: wait for PR merge to revert back to hrsh7th upstream + 'jmbuhr/cmp-nvim-lsp-signature-help', 'hrsh7th/cmp-buffer', 'hrsh7th/cmp-path', 'hrsh7th/cmp-calc', @@ -25,7 +26,6 @@ return { 'L3MON4D3/LuaSnip', 'rafamadriz/friendly-snippets', 'onsails/lspkind-nvim', - 'jmbuhr/otter.nvim', }, config = function() local cmp = require 'cmp' @@ -104,8 +104,8 @@ return { format = lspkind.cmp_format { mode = 'symbol', menu = { - otter = '[🦦]', nvim_lsp = '[LSP]', + nvim_lsp_signature_help = '[sig]', luasnip = '[snip]', buffer = '[buf]', path = '[path]', @@ -120,15 +120,14 @@ return { }, }, sources = { - { name = 'otter' }, -- for code chunks in quarto { name = 'path' }, - { name = 'nvim_lsp' }, { name = 'nvim_lsp_signature_help' }, - { name = 'luasnip', keyword_length = 3, max_item_count = 3 }, + { name = 'nvim_lsp' }, + { name = 'luasnip', keyword_length = 3, max_item_count = 3 }, { name = 'pandoc_references' }, - { name = 'buffer', keyword_length = 5, max_item_count = 3 }, + { name = 'buffer', keyword_length = 5, max_item_count = 3 }, { name = 'spell' }, - { name = 'treesitter', keyword_length = 5, max_item_count = 3 }, + { name = 'treesitter', keyword_length = 5, max_item_count = 3 }, { name = 'calc' }, { name = 'latex_symbols' }, { name = 'emoji' }, @@ -175,4 +174,44 @@ return { } end, }, + + { -- LLMs + "olimorris/codecompanion.nvim", + dependencies = { + "nvim-lua/plenary.nvim", + "nvim-treesitter/nvim-treesitter", + "nvim-telescope/telescope.nvim", + { + "stevearc/dressing.nvim", -- Optional: Improves the default Neovim UI + opts = {}, + }, + }, + keys = { + { 'ac', ':CodeCompanionChat', desc = '[a]i chat' }, + }, + config = function() + require("codecompanion").setup({ + strategies = { + chat = { + adapter = "anthropic", + }, + inline = { + adapter = "anthropic", + }, + agent = { + adapter = "anthropic", + }, + }, + adapters = { + anthropic = function() + return require("codecompanion.adapters").extend("anthropic", { + env = { + api_key = os.getenv("ANTHROPIC_API_KEY") + }, + }) + end, + }, + }) + end + } } diff --git a/lua/plugins/editing.lua b/lua/plugins/editing.lua index e5fee6b..33e09b5 100644 --- a/lua/plugins/editing.lua +++ b/lua/plugins/editing.lua @@ -29,16 +29,20 @@ return { { -- Autoformat 'stevearc/conform.nvim', enabled = true, + keys = { + { 'cf', 'lua require("conform").format()', desc = "[f]ormat" }, + }, config = function() require('conform').setup { notify_on_error = false, - format_on_save = { - timeout_ms = 500, - lsp_fallback = true, - }, + -- format_on_save = { + -- timeout_ms = 500, + -- lsp_fallback = true, + -- }, formatters_by_ft = { lua = { 'mystylua' }, python = { 'isort', 'black' }, + quarto = { 'injected' }, }, formatters = { mystylua = { @@ -89,7 +93,6 @@ return { { 'chrishrb/gx.nvim', enabled = false, - -- default gx sometimes more useful keys = { { 'gx', 'Browse', mode = { 'n', 'x' } } }, cmd = { 'Browse' }, init = function() diff --git a/lua/plugins/lsp.lua b/lua/plugins/lsp.lua index beb2a4b..215bfaf 100644 --- a/lua/plugins/lsp.lua +++ b/lua/plugins/lsp.lua @@ -1,4 +1,6 @@ + return { + { -- for lsp features in code cells / embedded code @@ -8,20 +10,12 @@ return { { 'neovim/nvim-lspconfig', 'nvim-treesitter/nvim-treesitter', - 'hrsh7th/nvim-cmp', }, }, opts = { - lsp = { - hover = { - border = require('misc.style').border, - }, - }, - buffers = { - set_filetype = true, - write_to_disk = false, - }, - handle_leading_whitespace = true, + verbose = { + no_code_found = false, + } }, }, @@ -37,7 +31,31 @@ return { enabled = false, opts = {}, }, - { 'folke/neodev.nvim', opts = {}, enabled = true }, + { + { + 'folke/lazydev.nvim', + ft = 'lua', -- only load on lua files + opts = { + library = { + -- See the configuration section for more details + -- Load luvit types when the `vim.uv` word is found + { path = 'luvit-meta/library', words = { 'vim%.uv' } }, + }, + }, + }, + { 'Bilal2453/luvit-meta', lazy = true }, -- optional `vim.uv` typings + { -- optional completion source for require statements and module annotations + 'hrsh7th/nvim-cmp', + opts = function(_, opts) + opts.sources = opts.sources or {} + table.insert(opts.sources, { + name = 'lazydev', + group_index = 0, -- set group index to 0 to skip loading LuaLS completions + }) + end, + }, + -- { "folke/neodev.nvim", enabled = false }, -- make sure to uninstall or disable neodev.nvim + }, { 'folke/neoconf.nvim', opts = {}, enabled = false }, }, config = function() @@ -62,10 +80,12 @@ return { vim.api.nvim_create_autocmd('LspAttach', { group = vim.api.nvim_create_augroup('kickstart-lsp-attach', { clear = true }), callback = function(event) - local telescope = require 'telescope.builtin' local function map(keys, func, desc) vim.keymap.set('n', keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) end + local function vmap(keys, func, desc) + vim.keymap.set('v', keys, func, { buffer = event.buf, desc = 'LSP: ' .. desc }) + end local client = vim.lsp.get_client_by_id(event.data.client_id) assert(client, 'LSP client not found') @@ -73,18 +93,19 @@ return { ---@diagnostic disable-next-line: inject-field client.server_capabilities.document_formatting = true - map('gS', telescope.lsp_document_symbols, '[g]o so [S]ymbols') - map('gD', telescope.lsp_type_definitions, '[g]o to type [D]efinition') - map('gd', telescope.lsp_definitions, '[g]o to [d]efinition') - map('K', 'lua vim.lsp.buf.hover()', '[K] hover documentation') - map('gh', 'lua vim.lsp.buf.signature_help()', '[g]o to signature [h]elp') - map('gI', telescope.lsp_implementations, '[g]o to [I]mplementation') - map('gr', telescope.lsp_references, '[g]o to [r]eferences') - map('[d', vim.diagnostic.goto_prev, 'previous [d]iagnostic ') - map(']d', vim.diagnostic.goto_next, 'next [d]iagnostic ') + map('gS', vim.lsp.buf.document_symbol, '[g]o so [S]ymbols') + map('gD', vim.lsp.buf.type_definition, '[g]o to type [D]efinition') + map('gd', vim.lsp.buf.definition, '[g]o to [d]efinition') + map('K', vim.lsp.buf.hover, '[K] hover documentation') + map('gh', vim.lsp.buf.signature_help, '[g]o to signature [h]elp') + map('gI', vim.lsp.buf.implementation, '[g]o to [I]mplementation') + map('gr', vim.lsp.buf.references, '[g]o to [r]eferences') + map(']d', function () if vim.fn.has("nvim-0.11.0") == 1 then vim.diagnostic.jump({count = 1}) else vim.diagnostic.goto_next() end end,'next [d]iagnostic ') + map('[d', function () if vim.fn.has("nvim-1.11.0") == 1 then vim.diagnostic.jump({count = -1}) else vim.diagnostic.goto_prev() end end,'previous [d]iagnostic ') map('ll', vim.lsp.codelens.run, '[l]ens run') map('lR', vim.lsp.buf.rename, '[l]sp [R]ename') map('lf', vim.lsp.buf.format, '[l]sp [f]ormat') + vmap('lf', vim.lsp.buf.format, '[l]sp [f]ormat') map('lq', vim.diagnostic.setqflist, '[l]sp diagnostic [q]uickfix') end, }) @@ -93,6 +114,7 @@ return { allow_incremental_sync = true, debounce_text_changes = 150, } + vim.lsp.handlers['textDocument/hover'] = vim.lsp.with(vim.lsp.handlers.hover, { border = require('misc.style').border }) vim.lsp.handlers['textDocument/signatureHelp'] = vim.lsp.with(vim.lsp.handlers.signature_help, { border = require('misc.style').border }) @@ -150,12 +172,17 @@ return { }, } + lspconfig.jsonls.setup { + capabilities = capabilities, + flags = lsp_flags, + } + lspconfig.dotls.setup { capabilities = capabilities, flags = lsp_flags, } - lspconfig.tsserver.setup { + lspconfig.ts_ls.setup { capabilities = capabilities, flags = lsp_flags, filetypes = { 'js', 'javascript', 'typescript', 'ojs' }, @@ -196,16 +223,18 @@ return { }, runtime = { version = 'LuaJIT', - plugin = lua_plugin_paths, + -- plugin = lua_plugin_paths, -- handled by lazydev }, diagnostics = { - globals = { 'vim', 'quarto', 'pandoc', 'io', 'string', 'print', 'require', 'table' }, disable = { 'trailing-space' }, }, workspace = { - library = lua_library_files, + -- library = lua_library_files, -- handled by lazydev checkThirdParty = false, }, + doc = { + privateName = { '^_' }, + }, telemetry = { enable = false, }, @@ -213,6 +242,12 @@ return { }, } + lspconfig.vimls.setup { + capabilities = capabilities, + flags = lsp_flags, + } + + lspconfig.julials.setup { capabilities = capabilities, flags = lsp_flags, @@ -237,15 +272,14 @@ return { -- flags = lsp_flags, -- } - -- lspconfig.rust_analyzer.setup{ + lspconfig.rust_analyzer.setup{ + capabilities = capabilities, + flags = lsp_flags, + } + + -- lspconfig.ruff_lsp.setup { -- capabilities = capabilities, - -- settings = { - -- ['rust-analyzer'] = { - -- diagnostics = { - -- enable = false; - -- } - -- } - -- } + -- flags = lsp_flags, -- } -- See https://github.com/neovim/neovim/issues/23291 diff --git a/lua/plugins/notes.lua b/lua/plugins/notes.lua index 52bbf4c..07a0b44 100644 --- a/lua/plugins/notes.lua +++ b/lua/plugins/notes.lua @@ -21,7 +21,7 @@ return { { 'epwalsh/obsidian.nvim', - enabled = false, + enabled = true, ft = 'markdown', event = { -- If you want to use the home shortcut '~' here you need to call 'vim.fn.expand'. diff --git a/lua/plugins/quarto.lua b/lua/plugins/quarto.lua index 7b33333..1cc831b 100644 --- a/lua/plugins/quarto.lua +++ b/lua/plugins/quarto.lua @@ -6,13 +6,10 @@ return { ft = { 'quarto' }, dev = false, opts = { - lspFeatures = { - languages = { 'r', 'python', 'julia', 'bash', 'lua', 'html', 'dot', 'javascript', 'typescript', 'ojs' }, - }, codeRunner = { enabled = true, - default_method = 'slime', - }, + default_method = "molten" + } }, dependencies = { -- for language features in code cells @@ -130,15 +127,17 @@ return { { 'benlubas/molten-nvim', - enabled = false, + dev = true, + 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 + vim.g.molten_auto_open_output = true end, keys = { { 'mi', ':MoltenInit', desc = '[m]olten [i]nit' }, + { 'md', ':MoltenDeinit', desc = '[m]olten [d]einit' }, { 'mv', ':MoltenEvaluateVisual', diff --git a/lua/plugins/treesitter.lua b/lua/plugins/treesitter.lua index 82f6f58..f2c6178 100644 --- a/lua/plugins/treesitter.lua +++ b/lua/plugins/treesitter.lua @@ -1,8 +1,11 @@ return { { 'nvim-treesitter/nvim-treesitter', + dev = false, dependencies = { - { 'nvim-treesitter/nvim-treesitter-textobjects' }, + { + 'nvim-treesitter/nvim-treesitter-textobjects', + }, }, run = ':TSUpdate', config = function() diff --git a/lua/plugins/ui.lua b/lua/plugins/ui.lua index 9ec17c0..dcdad35 100644 --- a/lua/plugins/ui.lua +++ b/lua/plugins/ui.lua @@ -51,7 +51,6 @@ return { vimgrep_arguments = vimgrep_arguments, file_ignore_patterns = { 'node_modules', - '%_files/', '%_cache', '.git/', 'site_libs', @@ -96,10 +95,10 @@ return { require('telescope.themes').get_dropdown(), }, fzf = { - fuzzy = true, -- false will only do exact matching + fuzzy = true, -- false will only do exact matching override_generic_sorter = true, -- override the generic sorter - override_file_sorter = true, -- override the file sorter - case_mode = 'smart_case', -- or "ignore_case" or "respect_case" + override_file_sorter = true, -- override the file sorter + case_mode = 'smart_case', -- or "ignore_case" or "respect_case" }, }, } @@ -130,7 +129,7 @@ return { }, dependencies = { 'nvim-tree/nvim-web-devicons' }, keys = { - { '-', ':Oil', desc = 'oil' }, + { '-', ':Oil', desc = 'oil' }, { 'ef', ':Oil', desc = 'edit [f]iles' }, }, cmd = 'Oil', @@ -191,6 +190,11 @@ return { enabled = false, }, + { + "NStefan002/screenkey.nvim", + lazy = false, + }, + { -- filetree 'nvim-tree/nvim-tree.lua', enabled = true, @@ -242,12 +246,25 @@ return { }, { -- show tree of symbols in the current file - 'simrat39/symbols-outline.nvim', - cmd = 'SymbolsOutline', + 'hedyhli/outline.nvim', + cmd = 'Outline', keys = { - { 'lo', ':SymbolsOutline', desc = 'symbols outline' }, + { 'lo', ':Outline', desc = 'symbols outline' }, + }, + opts = { + providers = { + priority = { 'markdown', 'lsp', 'norg' }, + -- Configuration for each provider (3rd party providers are supported) + lsp = { + -- Lsp client names to ignore + blacklist_clients = {}, + }, + markdown = { + -- List of supported ft's to use the markdown provider + filetypes = { 'markdown', 'quarto' }, + }, + }, }, - opts = {}, }, { -- or show symbols in the current file as breadcrumbs @@ -333,15 +350,14 @@ return { '3rd/image.nvim', enabled = true, dev = false, + -- fix to commit to keep using the rockspeck for image magick ft = { 'markdown', 'quarto', 'vimwiki' }, + cond = function() + -- Disable on Windows system + return vim.fn.has 'win32' ~= 1 + end, dependencies = { - { - 'vhyrro/luarocks.nvim', - priority = 1001, -- this plugin needs to run before anything else - opts = { - rocks = { 'magick' }, - }, - }, + 'leafo/magick', -- that's a lua rock }, config = function() -- Requirements @@ -351,7 +367,8 @@ return { -- sudo apt install imagemagick -- sudo apt install libmagickwand-dev -- sudo apt install liblua5.1-0-dev - -- sudo apt installl luajit + -- sudo apt install lua5.1 + -- sudo apt install luajit local image = require 'image' image.setup { @@ -360,12 +377,12 @@ return { markdown = { enabled = true, only_render_image_at_cursor = true, + -- only_render_image_at_cursor_mode = "popup", filetypes = { 'markdown', 'vimwiki', 'quarto' }, }, }, editor_only_render_when_focused = false, window_overlap_clear_enabled = true, - -- window_overlap_clear_ft_ignore = { 'cmp_menu', 'cmp_docs', 'scrollview' }, tmux_show_only_in_active_window = true, window_overlap_clear_ft_ignore = { 'cmp_menu', 'cmp_docs', 'scrollview', 'scrollview_sign' }, max_width = nil, @@ -431,7 +448,13 @@ return { handle_zoom(bufnr) end, { buffer = true, desc = 'image [o]pen' }) - vim.keymap.set('n', 'ic', clear_all_images, { buffer = true, desc = 'image [c]lear' }) + vim.keymap.set('n', 'ic', clear_all_images, { desc = 'image [c]lear' }) end, }, + + { -- interface with databases + 'tpope/vim-dadbod', + 'kristijanhusak/vim-dadbod-completion', + 'kristijanhusak/vim-dadbod-ui', + }, } diff --git a/queries/r/textobjects.scm b/queries/r/textobjects.scm new file mode 100644 index 0000000..2b834de --- /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 + diff --git a/snips/snippets/quarto.json b/snips/snippets/quarto.json index a78a9e1..83a400b 100644 --- a/snips/snippets/quarto.json +++ b/snips/snippets/quarto.json @@ -1,4 +1,16 @@ { + "ipython_interactive": { + "prefix": ["ipyinteractive"], + "body": [ + "```{python}", + "from IPython.core.getipython import get_ipython", + "ip = get_ipython()", + "interactive = False", + "if ip is not None and 'interactiveshell.TerminalInteractiveShell' in str(ip):", + " interactive = True", + "```" + ] + }, "iframe": { "prefix": ["iframe"], "body": [