Vigemus / iron.nvim

Interactive Repl Over Neovim
BSD 3-Clause "New" or "Revised" License
978 stars 81 forks source link

[Feature Request] Send a valid Treesitter node to REPL #339

Closed sei40kr closed 1 year ago

sei40kr commented 1 year ago

I want a function that automatically select a valid Treesitter node from cursor position and send its contents to REPL.

Actually I already wrote this on my own:

Code
```lua local function is_ts_highlighter_active(bufnr) if bufnr == 0 then bufnr = vim.api.nvim_get_current_buf() end return require("vim.treesitter.highlighter").active[bufnr] ~= nil end local function send() if not is_ts_highlighter_active(0) then vim.notify( "Treesitter is not active for this buffer", vim.log.levels.WARN ) return end -- Get the range of the current line (normal mode) or -- selection (visual mode) local mode = vim.api.nvim_get_mode().mode local range if mode == "n" then local row = vim.api.nvim_win_get_cursor(0)[1] - 1 -- Exclude the indent of the current line from the range local start_col = vim.fn.indent(row + 1) local end_col = vim.fn.charcol("$") - 1 range = { row, start_col, row, end_col } elseif mode == "v" or mode == "V" then local _, start_lnum, start_col, _ = unpack(vim.fn.getcharpos("'<")) local _, end_lnum, end_col, _ = unpack(vim.fn.getcharpos("'>")) local start_row, end_row = start_lnum - 1, end_lnum - 1 start_col = start_col - 1 -- Exclude the indent of the first line from the range start_col = start_col + vim.fn.indent(start_row + 1) range = { start_row, start_col, end_row, end_col } else vim.notify("Unsupported mode: " .. mode, vim.log.levels.ERROR) return end -- Get the node at the first non-blank character of the current -- line (normal mode) or selection (visual mode) local node = vim.treesitter.get_node({ pos = { range[1], range[2] }, }) -- Get the smallest node that contains -- the current line (normal mode) or selection (visual mode) while not vim.treesitter.node_contains(node, range) and node:parent() ~= nil do node = node:parent() end -- Extract the text of the node local data = vim.treesitter.get_node_text(node, 0, {}) require("iron.core").send(vim.bo.filetype, data) end ```
milanglacier commented 1 year ago

Iron has support for iron_send_motion.

You can just create your own text objects like this TSNode and then make it an operator mode mapping like this vim.keymap.set('o', "aT", function() your_ts_node_implementation() end), then use iron_send_motion (say defined as <Leader>s) to send the text to the REPL (<Leader>saT).

This is the universal way of how vim handles text: decouples the commands and the range of the text it operates on.

hkupty commented 1 year ago

Thanks @milanglacier for stepping up to answer. It pretty much aligns with my point of view. Treesitter is a fantastic tool, but there's no need to couple it to iron more that what is done and supported already, through regular vim text objects.

Having that said, I'm closing the issue, but don't hesitate to open issues or start discussions if you have questions or ideas.

Best regards, Henry