From 6edd3b8035503bf8e9dadb6df057b3bf03eaee82 Mon Sep 17 00:00:00 2001 From: Axel Dahlberg Date: Mon, 23 Dec 2024 21:45:22 -0800 Subject: [PATCH] feat: support multiple targets --- README.md | 3 ++- lua/ts-node-action/init.lua | 35 +++++++++++++++++++++++++++++++++-- 2 files changed, 35 insertions(+), 3 deletions(-) diff --git a/README.md b/README.md index 042a578..1bf3dbb 100644 --- a/README.md +++ b/README.md @@ -182,8 +182,9 @@ Boolean value. If `true`, will run `=` operator on new buffer text. Requires #### `target` -TSNode. If present, this node will be used as the target for replacement instead +TSNode or list of TSNodes. If present, this node will be used as the target for replacement instead of the node under your cursor. +If list of nodes their combined range will be used for replacement. Note that in this case if the target nodes specified are not next to each other, any thing in between will also be replaced. Here's a simplified example of how a node-action function gets called: diff --git a/lua/ts-node-action/init.lua b/lua/ts-node-action/init.lua index 1dc7f5b..f4b8d5c 100644 --- a/lua/ts-node-action/init.lua +++ b/lua/ts-node-action/init.lua @@ -1,15 +1,46 @@ local M = {} +--- @private +--- @param targets TSNode[] +--- @return integer start_row +--- @return integer start_col +--- @return integer end_row +--- @return integer end_col +local function combined_range(targets) + local start_row, start_col, end_row, end_col + for _, target in ipairs(targets) do + local sr, sc, er, ec = target:range() + if start_row == nil or sr < start_row then + start_row = sr + end + if start_col == nil or sc < start_col then + start_col = sc + end + if end_row == nil or er > end_row then + end_row = er + end + if end_col == nil or ec > end_col then + end_col = ec + end + end + return start_row, start_col, end_row, end_col +end + --- @private --- @param replacement string|table ---- @param opts { cursor: { col: number, row: number }, callback: function, format: boolean, target: TSNode } +--- @param opts { cursor: { col: number, row: number }, callback: function, format: boolean, target: TSNode | TSNode[] } --- All opts fields are optional local function replace_node(node, replacement, opts) if type(replacement) ~= "table" then replacement = { replacement } end - local start_row, start_col, end_row, end_col = (opts.target or node):range() + local start_row, start_col, end_row, end_col + if vim.islist(opts.target) then + start_row, start_col, end_row, end_col = combined_range(opts.target) + else + start_row, start_col, end_row, end_col = (opts.target or node):range() + end vim.api.nvim_buf_set_text( vim.api.nvim_get_current_buf(), start_row,