Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,11 @@
# Changelog

## [2.12.0](https://github.com/akinsho/toggleterm.nvim/compare/...

### Features

* add bracketed paste support to `send_lines_to_terminal` and Terminal:send.

## [2.11.0](https://github.com/akinsho/toggleterm.nvim/compare/v2.10.0...v2.11.0) (2024-04-22)


Expand Down
13 changes: 8 additions & 5 deletions lua/toggleterm.lua
Original file line number Diff line number Diff line change
Expand Up @@ -175,7 +175,8 @@ end
--- @param name string?
--- @param go_back boolean? whether or not to return to original window
--- @param open boolean? whether or not to open terminal window
function M.exec(cmd, num, size, dir, direction, name, go_back, open)
--- @param use_bracketed_paste boolean? whether or not to use bracketed paste mode for send
function M.exec(cmd, num, size, dir, direction, name, go_back, open, use_bracketed_paste)
vim.validate({
cmd = { cmd, "string" },
num = { num, "number", true },
Expand All @@ -185,6 +186,7 @@ function M.exec(cmd, num, size, dir, direction, name, go_back, open)
name = { name, "string", true },
go_back = { go_back, "boolean", true },
open = { open, "boolean", true },
use_bracketed_paste = { use_bracketed_paste, "boolean", true },
})
num = (num and num >= 1) and num or terms.get_toggled_id()
open = open == nil or open
Expand All @@ -197,13 +199,14 @@ function M.exec(cmd, num, size, dir, direction, name, go_back, open)
term:close()
go_back = false
end
term:send(cmd, go_back)
term:send(cmd, go_back, use_bracketed_paste)
end

--- @param selection_type string
--- @param trim_spaces boolean
--- @param cmd_data table<string, any>
function M.send_lines_to_terminal(selection_type, trim_spaces, cmd_data)
--- @param use_bracketed_paste boolean?
function M.send_lines_to_terminal(selection_type, trim_spaces, cmd_data, use_bracketed_paste)
local id = tonumber(cmd_data.args) or 1
trim_spaces = trim_spaces == nil or trim_spaces

Expand Down Expand Up @@ -244,11 +247,11 @@ function M.send_lines_to_terminal(selection_type, trim_spaces, cmd_data)
if not lines or not next(lines) then return end

if not trim_spaces then
M.exec(table.concat(lines, "\n"), id)
M.exec(table.concat(lines, "\n"), id, nil, nil, nil, nil, nil, nil, use_bracketed_paste)
else
for _, line in ipairs(lines) do
local l = trim_spaces and line:gsub("^%s+", ""):gsub("%s+$", "") or line
M.exec(l, id)
M.exec(l, id, nil, nil, nil, nil, nil, nil, use_bracketed_paste)
end
end

Expand Down
8 changes: 6 additions & 2 deletions lua/toggleterm/terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -322,10 +322,14 @@ end
---Send a command to a running terminal
---@param cmd string|string[]
---@param go_back boolean? whether or not to return to original window
function Terminal:send(cmd, go_back)
---@param use_bracketed_paste boolean? Whether or not to add bracketed paste characters to send sequence
function Terminal:send(cmd, go_back, use_bracketed_paste)
local start_seq = use_bracketed_paste and "\x1b[200~" or ""
local end_seq = use_bracketed_paste and "\x1b[201~" .. self.newline_chr or ""

cmd = type(cmd) == "table" and with_cr(self.newline_chr, unpack(cmd))
or with_cr(self.newline_chr, cmd --[[@as string]])
fn.chansend(self.job_id, cmd)
fn.chansend(self.job_id, start_seq .. cmd .. end_seq)
self:scroll_bottom()
if go_back and self:is_focused() then
ui.goto_previous()
Expand Down
26 changes: 21 additions & 5 deletions tests/terminal_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -305,9 +305,25 @@ describe("ToggleTerm tests:", function()
local test1 = Terminal:new():toggle()
local _ = match._
spy.on(test1, "send")
spy.on(vim.fn, "chansend")
toggleterm.exec('echo "hello world"', 1)
assert.spy(test1.send).was_called()
assert.spy(test1.send).was_called_with(_, 'echo "hello world"', true)
assert.spy(test1.send).was_called_with(_, 'echo "hello world"', true, match.is_nil())
assert.spy(vim.fn.chansend).was_called_with(test1.job_id, 'echo "hello world"\n')
assert.is_true(vim.tbl_contains(api.nvim_list_wins(), test1.window))
end)

it("should send commands to a terminal with bracketed paste characters when specified", function()
local start_seq = "\x1b[200~"
local end_seq = "\x1b[201~"
local test1 = Terminal:new():toggle()
local _ = match._
spy.on(test1, "send")
spy.on(vim.fn, "chansend")
toggleterm.exec("def hello():\n print('foo')", 1, nil, nil, nil, nil, nil, nil, true)
assert.spy(test1.send).was_called()
assert.spy(test1.send).was_called_with(_, "def hello():\n print('foo')", true, true)
assert.spy(vim.fn.chansend).was_called_with(test1.job_id, start_seq .. "def hello():\n print('foo')\n" .. end_seq .. "\n")
assert.is_true(vim.tbl_contains(api.nvim_list_wins(), test1.window))
end)

Expand All @@ -316,7 +332,7 @@ describe("ToggleTerm tests:", function()
test1:close()
spy.on(test1, "send")
toggleterm.exec_command("cmd='echo \"hello world\"' open=0", 1)
assert.spy(test1.send).was_called_with(test1, 'echo "hello world"', false)
assert.spy(test1.send).was_called_with(test1, 'echo "hello world"', false, match.is_nil())
assert.is_false(vim.tbl_contains(api.nvim_list_wins(), test1.window))
end)

Expand All @@ -327,7 +343,7 @@ describe("ToggleTerm tests:", function()
spy.on(test1, "send")
toggleterm.exec('echo "hello world"', 1)
assert.spy(test1.send).was_called()
assert.spy(test1.send).was_called_with(_, 'echo "hello world"', true)
assert.spy(test1.send).was_called_with(_, 'echo "hello world"', true, match.is_nil())
assert.is_true(vim.tbl_contains(api.nvim_list_wins(), test1.window))
end)

Expand All @@ -338,7 +354,7 @@ describe("ToggleTerm tests:", function()
vim.cmd("wincmd w")
spy.on(test1, "send")
toggleterm.exec_command("cmd='echo %'", 1)
assert.spy(test1.send).was_called_with(test1, fmt("echo %s", file), true)
assert.spy(test1.send).was_called_with(test1, fmt("echo %s", file), true, match.is_nil())
end)

it("should handle nested quotes in cmd args", function()
Expand All @@ -348,7 +364,7 @@ describe("ToggleTerm tests:", function()
vim.cmd("wincmd w")
spy.on(test1, "send")
toggleterm.exec_command("cmd='g++ -std=c++17 % -o run'", 1)
assert.spy(test1.send).was_called_with(test1, fmt("g++ -std=c++17 %s -o run", file), true)
assert.spy(test1.send).was_called_with(test1, fmt("g++ -std=c++17 %s -o run", file), true, match.is_nil())
end)
end)

Expand Down