osc52.lua (2136B)
1 local M = {} 2 3 --- Return the OSC 52 escape sequence 4 --- 5 --- @param clipboard string The clipboard to read from or write to 6 --- @param contents string The Base64 encoded contents to write to the clipboard, or '?' to read 7 --- from the clipboard 8 local function osc52(clipboard, contents) 9 return string.format('\027]52;%s;%s\027\\', clipboard, contents) 10 end 11 12 function M.copy(reg) 13 local clipboard = reg == '+' and 'c' or 'p' 14 return function(lines) 15 local s = table.concat(lines, '\n') 16 -- The data to be written here can be quite long. 17 vim.api.nvim_ui_send(osc52(clipboard, vim.base64.encode(s))) 18 end 19 end 20 21 function M.paste(reg) 22 local clipboard = reg == '+' and 'c' or 'p' 23 return function() 24 local contents = nil --- @type string? 25 local id = vim.api.nvim_create_autocmd('TermResponse', { 26 callback = function(args) 27 local resp = args.data.sequence ---@type string 28 local encoded = resp:match('\027%]52;%w?;([A-Za-z0-9+/=]*)') 29 if encoded then 30 contents = vim.base64.decode(encoded) 31 return true 32 end 33 end, 34 }) 35 36 vim.api.nvim_ui_send(osc52(clipboard, '?')) 37 38 local ok, res 39 40 -- Wait 1s first for terminals that respond quickly 41 ok, res = vim.wait(1000, function() 42 return contents ~= nil 43 end) 44 45 if res == -1 then 46 -- If no response was received after 1s, print a message and keep waiting 47 vim.api.nvim_echo( 48 { { 'Waiting for OSC 52 response from the terminal. Press Ctrl-C to interrupt...' } }, 49 false, 50 {} 51 ) 52 ok, res = vim.wait(9000, function() 53 return contents ~= nil 54 end) 55 end 56 57 if not ok then 58 vim.api.nvim_del_autocmd(id) 59 if res == -1 then 60 vim.notify( 61 'Timed out waiting for a clipboard response from the terminal', 62 vim.log.levels.WARN 63 ) 64 elseif res == -2 then 65 -- Clear message area 66 vim.api.nvim_echo({ { '' } }, false, {}) 67 end 68 return 0 69 end 70 71 -- If we get here, contents should be non-nil 72 return vim.split(assert(contents), '\n') 73 end 74 end 75 76 return M