Skip to content
Merged
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
44 changes: 29 additions & 15 deletions lua/neocrush/terminal.lua
Original file line number Diff line number Diff line change
Expand Up @@ -257,18 +257,38 @@ function M.restart()
M.open()
end

--- Paste text into the Crush terminal.
--- Can paste from a register or the current visual selection.
---@param register? string Register to paste from (default: '+' for system clipboard)
function M.paste(register)
--- Return the channel of the running Crush terminal, or nil after warning.
---@return integer?
local function get_term_chan()
if not crush_buf or not vim.api.nvim_buf_is_valid(crush_buf) then
vim.notify('Crush terminal not running', vim.log.levels.WARN)
return
return nil
end

local term_chan = vim.bo[crush_buf].channel
if term_chan == 0 then
vim.notify('Crush terminal channel not found', vim.log.levels.WARN)
return nil
end

return term_chan
end

--- Wrap text in bracketed paste markers (ESC[200~ ... ESC[201~).
--- Lets the terminal application receive the text as one paste event instead
--- of interpreting it as individual keystrokes.
---@param text string
---@return string
function M.bracketed(text)
return '\27[200~' .. text .. '\27[201~'
end

--- Paste text into the Crush terminal.
--- Can paste from a register or the current visual selection.
---@param register? string Register to paste from (default: '+' for system clipboard)
function M.paste(register)
local term_chan = get_term_chan()
if not term_chan then
return
end

Expand All @@ -280,19 +300,13 @@ function M.paste(register)
return
end

vim.api.nvim_chan_send(term_chan, content)
vim.api.nvim_chan_send(term_chan, M.bracketed(content))
end

--- Paste the current visual selection into the Crush terminal.
function M.paste_selection()
if not crush_buf or not vim.api.nvim_buf_is_valid(crush_buf) then
vim.notify('Crush terminal not running', vim.log.levels.WARN)
return
end

local term_chan = vim.bo[crush_buf].channel
if term_chan == 0 then
vim.notify('Crush terminal channel not found', vim.log.levels.WARN)
local term_chan = get_term_chan()
if not term_chan then
return
end

Expand All @@ -302,7 +316,7 @@ function M.paste_selection()
return
end

vim.api.nvim_chan_send(term_chan, text)
vim.api.nvim_chan_send(term_chan, M.bracketed(text))
end

-------------------------------------------------------------------------------
Expand Down
10 changes: 10 additions & 0 deletions tests/terminal_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -94,6 +94,16 @@ describe('neocrush.terminal', function()
end)
end)

describe('bracketed', function()
it('should wrap text in bracketed paste markers', function()
assert.equals('\27[200~hello\nworld\27[201~', terminal.bracketed 'hello\nworld')
end)

it('should wrap empty text', function()
assert.equals('\27[200~\27[201~', terminal.bracketed '')
end)
end)

describe('paste', function()
it('should warn when no terminal is running', function()
assert.has_no.errors(function()
Expand Down
Loading