feat(clipboard): initial support (#279)

Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
This commit is contained in:
Aaron Pham
2024-08-27 06:57:29 -04:00
committed by GitHub
parent 77551ce734
commit cf68572494
10 changed files with 244 additions and 10 deletions

View File

@@ -0,0 +1,59 @@
local Utils = require("avante.utils")
---@class AvanteClipboard
local M = {}
M.clip_cmd = nil
M.get_clip_cmd = function()
if M.clip_cmd then
return M.clip_cmd
end
if vim.fn.executable("pngpaste") == 1 then
M.clip_cmd = "pngpaste"
elseif vim.fn.executable("osascript") == 1 then
M.clip_cmd = "osascript"
end
return M.clip_cmd
end
M.has_content = function()
local cmd = M.get_clip_cmd()
---@type vim.SystemCompleted
local output
if cmd == "pngpaste" then
output = Utils.shell_run("pngpaste -")
return output.code == 0
elseif cmd == "osascript" then
output = Utils.shell_run("osascript -e 'clipboard info'")
return output.code == 0 and output.stdout ~= nil and output.stdout:find("class PNGf") ~= nil
end
Utils.warn("Failed to validate clipboard content", { title = "Avante" })
return false
end
M.get_content = function()
local cmd = M.get_clip_cmd()
---@type vim.SystemCompleted
local output
if cmd == "pngpaste" then
output = Utils.shell_run("pngpaste - | base64 | tr -d '\n'")
if output.code == 0 then
return output.stdout
end
elseif cmd == "osascript" then
output = Utils.shell_run(
[[osascript -e 'set theFile to (open for access POSIX file "/tmp/image.png" with write permission)' -e 'try' -e 'write (the clipboard as «class PNGf») to theFile' -e 'end try' -e 'close access theFile'; ]]
.. [[cat /tmp/image.png | base64 | tr -d '\n']]
)
if output.code == 0 then
return output.stdout
end
end
error("Failed to get clipboard content")
end
return M

View File

@@ -0,0 +1,27 @@
---NOTE: this module is inspired by https://github.com/HakonHarnes/img-clip.nvim/tree/main
local Utils = require("avante.utils")
---@class AvanteClipboard
---@field clip_cmd string
---@field get_clip_cmd fun(): string
---@field has_content fun(): boolean
---@field get_content fun(): string
---
---@class avante.Clipboard: AvanteClipboard
local M = {}
return setmetatable(M, {
__index = function(t, k)
local os_mapping = Utils.get_os_name()
---@type AvanteClipboard
local impl = require("avante.clipboard." .. os_mapping)
if impl[k] ~= nil then
return impl[k]
elseif t[k] ~= nil then
return t[k]
else
error("Failed to find clipboard implementation for " .. os_mapping)
end
end,
})

View File

@@ -0,0 +1,59 @@
local Utils = require("avante.utils")
---@class AvanteClipboard
local M = {}
M.clip_cmd = nil
M.get_clip_cmd = function()
if M.clip_cmd then
return M.clip_cmd
end
-- Wayland
if os.getenv("WAYLAND_DISPLAY") ~= nil and vim.fn.executable("wl-paste") == 1 then
M.clip_cmd = "wl-paste"
-- X11
elseif os.getenv("DISPLAY") ~= nil and vim.fn.executable("xclip") == 1 then
M.clip_cmd = "xclip"
end
return M.clip_cmd
end
M.has_content = function()
local cmd = M.get_clip_cmd()
---@type vim.SystemCompleted
local output
-- X11
if cmd == "xclip" then
output = Utils.shell_run("xclip -selection clipboard -t TARGETS -o")
return output.code == 0 and output.stdout:find("image/png") ~= nil
elseif cmd == "wl-paste" then
output = Utils.shell_run("wl-paste --list-types")
return output.code == 0 and output.stdout:find("image/png") ~= nil
end
Utils.warn("Failed to validate clipboard content", { title = "Avante" })
return false
end
M.get_content = function()
local cmd = M.get_clip_cmd()
---@type vim.SystemCompleted
local output
if cmd == "xclip" then
output = Utils.shell_run("xclip -selection clipboard -o -t image/png | base64 | tr -d '\n'")
if output.code == 0 then
return output.stdout
end
elseif cmd == "osascript" then
output = Utils.shell_run("wl-paste --type image/png | base64 | tr -d '\n'")
if output.code == 0 then
return output.stdout
end
end
error("Failed to get clipboard content")
end
return M

View File

@@ -0,0 +1,51 @@
local Utils = require("avante.utils")
---@class AvanteClipboard
local M = {}
M.clip_cmd = nil
M.get_clip_cmd = function()
if M.clip_cmd then
return M.clip_cmd
end
if (vim.fn.has("win32") > 0 or vim.fn.has("wsl") > 0) and vim.fn.executable("powershell.exe") then
M.clip_cmd = "powershell.exe"
end
return M.clip_cmd
end
M.has_content = function()
local cmd = M.get_clip_cmd()
---@type vim.SystemCompleted
local output
if cmd == "powershell.exe" then
output =
Utils.shell_run("Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Clipboard]::GetImage()")
return output.code == 0 and output.stdout:find("Width") ~= nil
end
Utils.warn("Failed to validate clipboard content", { title = "Avante" })
return false
end
M.get_content = function()
local cmd = M.get_clip_cmd()
---@type vim.SystemCompleted
local output
if cmd == "powershell.exe" then
output = Utils.shell_run(
[[Add-Type -AssemblyName System.Windows.Forms; $ms = New-Object System.IO.MemoryStream;]]
.. [[ [System.Windows.Forms.Clipboard]::GetImage().Save($ms, [System.Drawing.Imaging.ImageFormat]::Png);]]
.. [[ [System.Convert]::ToBase64String($ms.ToArray())]]
)
if output.code == 0 then
return output.stdout:gsub("\r\n", ""):gsub("\n", ""):gsub("\r", "")
end
end
error("Failed to get clipboard content")
end
return M