diff --git a/lua/r/send.lua b/lua/r/send.lua index f515c192..92a6c5c8 100644 --- a/lua/r/send.lua +++ b/lua/r/send.lua @@ -645,22 +645,94 @@ M.line = function(m) end end --- Function to check if a string ends with a specific suffix ----@param str string ----@param suffix string ----@return boolean -local function ends_with(str, suffix) return str:sub(-#suffix) == suffix end +M.chain = function() + local bufnr = create_r_buffer() + if not bufnr then return end local function trim_lines(array) local result = {} -- Create a new table to store the trimmed lines - for i = 1, #array do - local line = array[i] - local trimmedLine = line:match("^%s*(.-)%s*$") -- Remove leading and trailing whitespace - table.insert(result, trimmedLine) -- Add the trimmed line to the result table + local tree = parser:parse()[1] + if not tree then return end + + local root = tree:root() + local query = vim.treesitter.query.parse( + "r", + [[ + (_ + (binary_operator + lhs: (_) + operator: ([("|>") ("<-") ("+") ("special")]) + rhs: (call) + ) @pipeline_no_assign + (#not-has-parent? @pipeline_no_assign binary_operator) + ) + + (_ + ; Handle when the pipeline is assignment to a variable + (binary_operator + lhs: (identifier) + rhs: (binary_operator + lhs: (_) + operator: ([("|>") ("+") ("special")]) + rhs: (call) + ) @pipeline_with_assign + ) + ) + ]] + ) + + local cursor_row = vim.api.nvim_win_get_cursor(0)[1] - 1 + local pipe_block_node + + for _, node in query:iter_captures(root, bufnr, 0, -1) do + local start_row, _, end_row = node:range() + if cursor_row >= start_row and cursor_row <= end_row then + pipe_block_node = node + break + end + end + + if not pipe_block_node then + inform("The cursor is not inside a piped expression.") + return end - return result + local call_query = vim.treesitter.query.parse( + "r", + [[ + (_ + (binary_operator + lhs: (_) + operator: (["|>" "+" "special"] @operator) + rhs: (call) @call + (#not-has-ancestor? @call call) ;; Ensure the rhs is not inside another call + ) + ) + ]] + ) + + local sibling = nil + local visited = false + + for id, node, _ in call_query:iter_captures(pipe_block_node, bufnr, 0, -1) do + local capture_name = call_query.captures[id] + local start_row, _, end_row = node:range() + + if + capture_name == "operator" and visited + or cursor_row == pipe_block_node:range() + then + sibling = node:prev_sibling() + break + elseif capture_name == "call" then + if cursor_row >= start_row and cursor_row <= end_row then visited = true end + end + end + + local captured_node = sibling or pipe_block_node + + M.source_lines({ vim.treesitter.get_node_text(captured_node, bufnr) }, nil) end -- Remove the <-, |>/%>% or + from the text