feat(clipboard): initial support (#279)
Signed-off-by: Aaron Pham <contact@aarnphm.xyz>
This commit is contained in:
59
lua/avante/clipboard/darwin.lua
Normal file
59
lua/avante/clipboard/darwin.lua
Normal 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
|
||||
27
lua/avante/clipboard/init.lua
Normal file
27
lua/avante/clipboard/init.lua
Normal 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,
|
||||
})
|
||||
59
lua/avante/clipboard/linux.lua
Normal file
59
lua/avante/clipboard/linux.lua
Normal 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
|
||||
51
lua/avante/clipboard/windows.lua
Normal file
51
lua/avante/clipboard/windows.lua
Normal 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
|
||||
Reference in New Issue
Block a user