mirror of
https://github.com/akinsho/toggleterm.nvim
synced 2024-09-16 21:34:03 +02:00
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:
parent
c80844fd52
commit
5b84866498
3 changed files with 67 additions and 11 deletions
38
README.md
38
README.md
|
@ -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:
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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
|
||||
|
|
Loading…
Reference in a new issue