feat: allow operator mapping to send to terminal (#507)

* Fix: Send correct visual range when using lua mapping

Fixes #458, I think

* Docs: Document using lua function directly in a mapping

Especially useful for python users

* feat: Add support for opfunc motions

* docs: document use of motion opfunc

---------

Co-authored-by: bluedrink9 <bluedrink9@github.com>
This commit is contained in:
Silico_Biomancer 2023-11-23 05:49:09 +13:00 committed by GitHub
parent c80844fd52
commit 5b84866498
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 67 additions and 11 deletions

View file

@ -297,6 +297,44 @@ You can "send lines" to the toggled terminals with the following commands:
(`<T_ID` is an optional terminal ID parameter, which defines where should we send the lines.
If the parameter is not provided, then the default is the `first terminal`)
Alternatively, for more fine-grained control and use in mappings, in lua:
```lua
local trim_spaces = true
vim.keymap.set("v", "<space>s", function()
require("toggleterm").send_lines_to_terminal("single_line", trim_spaces, { args = vim.v.count })
end
-- Replace with these for the other two options
-- require("toggleterm").send_lines_to_terminal("visual_line", trim_spaces, { args = vim.v.count })
-- require("toggleterm").send_lines_to_terminal("visual_selection", trim_spaces, { args = vim.v.count })
-- For use as an operator map:
-- Send motion to terminal
vim.keymap.set("n", [[<leader><c-\>]], function()
set_opfunc(function(motion_type)
require("toggleterm").send_lines_to_terminal(motion_type, false, { args = vim.v.count })
end)
vim.api.nvim_feedkeys("g@", "n", false)
end)
-- Double the command to send line to terminal
vim.keymap.set("n", [[<leader><c-\><c-\>]], function()
set_opfunc(function(motion_type)
require("toggleterm").send_lines_to_terminal(motion_type, false, { args = vim.v.count })
end)
vim.api.nvim_feedkeys("g@_", "n", false)
end)
-- Send whole file
vim.keymap.set("n", [[<leader><leader><c-\>]], function()
set_opfunc(function(motion_type)
require("toggleterm").send_lines_to_terminal(motion_type, false, { args = vim.v.count })
end)
vim.api.nvim_feedkeys("ggg@G''", "n", false)
end)
```
Set `trim_spaces=false` for sending to REPLs for whitespace-sensitive languages like python.
(For python, you probably want to start ipython with `ipython --no-autoindent`.)
<!-- panvimdoc-ignore-start -->
Example:

View file

@ -221,21 +221,31 @@ function M.send_lines_to_terminal(selection_type, trim_spaces, cmd_data)
if selection_type == "single_line" then
start_line, start_col = unpack(api.nvim_win_get_cursor(0))
table.insert(lines, fn.getline(start_line))
elseif selection_type == "visual_lines" then
local res = utils.get_line_selection("visual")
else
local res = nil
if string.match(selection_type, "visual") then
res = utils.get_line_selection("visual")
else
res = utils.get_line_selection("motion")
end
start_line, start_col = unpack(res.start_pos)
lines = res.selected_lines
elseif selection_type == "visual_selection" then
local res = utils.get_line_selection("visual")
start_line, start_col = unpack(res.start_pos)
lines = utils.get_visual_selection(res)
-- char, line and block are used for motion/operatorfunc. 'block' is ignored
if selection_type == "visual_lines" or selection_type == "line" then
lines = res.selected_lines
elseif selection_type == "visual_selection" or selection_type == "char" then
lines = utils.get_visual_selection(res, true)
end
end
if not lines or not next(lines) then return end
for _, line in ipairs(lines) do
local l = trim_spaces and line:gsub("^%s+", ""):gsub("%s+$", "") or line
M.exec(l, id)
if not trim_spaces then
M.exec(table.concat(lines, "\n"))
else
for _, line in ipairs(lines) do
local l = trim_spaces and line:gsub("^%s+", ""):gsub("%s+$", "") or line
M.exec(l, id)
end
end
-- Jump back with the cursor where we were at the beginning of the selection

View file

@ -55,6 +55,11 @@ function M.get_line_selection(mode)
visual = { "'<", "'>" },
motion = { "'[", "']" },
})[mode])
-- '< marks are only updated when one leaves visual mode.
-- When calling lua functions directly from a mapping, need to
-- explicitly exit visual with the escape key to ensure those marks are
-- accurate.
vim.cmd("normal! ")
-- Get the start and the end of the selection
local start_line, start_col = unpack(fn.getpos(start_char), 2, 3)
@ -67,8 +72,11 @@ function M.get_line_selection(mode)
}
end
function M.get_visual_selection(res)
function M.get_visual_selection(res, motion)
motion = motion or false
local mode = fn.visualmode()
if motion then mode = "v" end
-- line-visual
-- return lines encompassed by the selection; already in res object
if mode == "V" then return res.selected_lines end