Skip to content

Commit

Permalink
feat: allow file paths as input (#41)
Browse files Browse the repository at this point in the history
* refactor(wip): refactor code so it can handle file paths as input

* feat: call setup when plugin is loaded

* feat: handle text/uri-list target

* fix: add pasteImage function back

* feat: support base64 embedding for file paths

* feat: support base64 embedding for URLs

* test: fix broken tests (missing paste_spec)

* fix: luacheck

* feat(clipboard): get content of clipboard for wayland, macos and windows

* refactor: remove powershell arg from util.execute

* feat(base64): add windows support for generating base64 images from file

* test: add paste_image tests

* feat: provide paste_image function along with pasteImage (legacy)

* docs: provide docs for paste_image function

* test: add tests for incomptabile os

* chore: rename to "content is not an image"

* fix: adjust powershell commands

* fix: use pbpaste for mac

* test: fix broken tests

* docs: add new api method
  • Loading branch information
HakonHarnes authored Mar 1, 2024
1 parent c93f0d6 commit 24cbf88
Show file tree
Hide file tree
Showing 14 changed files with 567 additions and 533 deletions.
8 changes: 7 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -59,7 +59,13 @@ Consider binding `PasteImage` to something like `<leader>p`.
You can also use the Lua equivalent, which allows you to override your configuration by passing the options directly to the function:

```lua
require("img-clip").pasteImage({ use_absolute_path = false, file_name = "image.png" })
require("img-clip").paste_image(opts?, input?) -- input is optional and can be a file path or URL
```

Example:

```lua
require("img-clip").paste_image({ use_absolute_path = false, file_name = "image.png" }, "/path/to/file.png")
```

## Configuration
Expand Down
87 changes: 70 additions & 17 deletions lua/img-clip/clipboard.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,35 +2,43 @@ local util = require("img-clip.util")

local M = {}

M.clip_cmd = nil

---@return string | nil
M.get_clip_cmd = function()
if M.clip_cmd then
return M.clip_cmd

-- Windows
if (util.has("win32") or util.has("wsl")) and util.executable("powershell.exe") then
return "powershell.exe"
elseif (util.has("win32") or util.has("wsl")) and util.executable("powershell.exe") then
M.clip_cmd = "powershell.exe"

-- Linux (Wayland)
elseif os.getenv("WAYLAND_DISPLAY") and util.executable("wl-paste") then
return "wl-paste"
M.clip_cmd = "wl-paste"

-- Linux (X11)
elseif os.getenv("DISPLAY") and util.executable("xclip") then
return "xclip"
M.clip_cmd = "xclip"

-- MacOS
elseif util.has("mac") then
if util.executable("pngpaste") then
return "pngpaste"
M.clip_cmd = "pngpaste"
elseif util.executable("osascript") then
return "osascript"
M.clip_cmd = "osascript"
end
else
return nil
end

return nil
return M.clip_cmd
end

---@param cmd string
---@return boolean
M.content_is_image = function(cmd)
M.content_is_image = function()
local cmd = M.get_clip_cmd()

-- Linux (X11)
if cmd == "xclip" then
local output = util.execute("xclip -selection clipboard -t TARGETS -o")
Expand All @@ -47,25 +55,25 @@ M.content_is_image = function(cmd)
return exit_code == 0

-- MacOS (osascript) as a fallback
-- TODO: Add correct quotes aroudn class PNGf
elseif cmd == "osascript" then
local output = util.execute("osascript -e 'clipboard info'")
return output ~= nil and output:find("class PNGf") ~= nil

-- Windows
elseif cmd == "powershell.exe" then
local output =
util.execute("Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Clipboard]::GetImage()", true)
util.execute("Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Clipboard]::GetImage()")
return output ~= nil and output:find("Width") ~= nil
end

return false
end

---@param cmd string
---@param file_path string
---@return boolean
M.save_image = function(cmd, file_path)
M.save_image = function(file_path)
local cmd = M.get_clip_cmd()

-- Linux (X11)
if cmd == "xclip" then
local command = string.format('xclip -selection clipboard -o -t image/png > "%s"', file_path)
Expand Down Expand Up @@ -101,14 +109,60 @@ M.save_image = function(cmd, file_path)
"Add-Type -AssemblyName System.Windows.Forms; [System.Windows.Forms.Clipboard]::GetImage().Save('%s')",
file_path
)
local _, exit_code = util.execute(command, true)
local _, exit_code = util.execute(command)
return exit_code == 0
end

return false
end

M.get_base64_encoded_image = function(cmd)
---@return string | nil
M.get_content = function()
local cmd = M.get_clip_cmd()

-- Linux (X11)
if cmd == "xclip" then
for _, target in ipairs({ "text/plain", "text/uri-list" }) do
local command = string.format("xclip -selection clipboard -t %s -o", target)
local output, exit_code = util.execute(command)
if exit_code == 0 then
return output:match("^[^\n]+") -- only return first line
end
end

-- Linux (Wayland)
elseif cmd == "wl-paste" then
local output, exit_code = util.execute("wl-paste")
if exit_code == 0 then
return output:match("^[^\n]+")
end

-- MacOS
elseif cmd == "pngpaste" or cmd == "osascript" then
local output, exit_code = util.execute("pbpaste")
if exit_code == 0 then
return output:match("^[^\n]+")
end

output, exit_code = util.execute([[osascript -e 'get the clipboard as text']])
if exit_code == 0 then
return output:match("^[^\n]+")
end

-- Windows
elseif cmd == "powershell.exe" then
local output, exit_code = util.execute([[powershell -command "Get-Clipboard"]])
if exit_code == 0 then
return output:match("^[^\n]+")
end
end

return nil
end

M.get_base64_encoded_image = function()
local cmd = M.get_clip_cmd()

-- Linux (X11)
if cmd == "xclip" then
local output, exit_code = util.execute("xclip -selection clipboard -o -t image/png | base64 | tr -d '\n'")
Expand Down Expand Up @@ -146,8 +200,7 @@ M.get_base64_encoded_image = function(cmd)
local output, exit_code = util.execute(
[[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())]],
true
.. [[ [System.Convert]::ToBase64String($ms.ToArray())]]
)
if exit_code == 0 then
return output:gsub("\r\n", ""):gsub("\n", ""):gsub("\r", "")
Expand Down
21 changes: 10 additions & 11 deletions lua/img-clip/config.lua
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,7 @@ M.sort_config = function(opts)
return opts
end

---Gets the config
---get the config
---Can be either the default config or the config from the config file
---@return table
M.get_config = function()
Expand Down Expand Up @@ -156,7 +156,7 @@ M.get_config = function()
return M.opts
end

---Recursively gets the value of the option (e.g. "default.debug")
---recursively gets the value of the option (e.g. "default.debug")
---@param key string
---@param opts table
---@return string | nil
Expand All @@ -174,7 +174,7 @@ local function recursive_get_opt(key, opts)
return opts
end

---Gets the value of the option, executing it if it's a function
---get the value of the option, executing it if it's a function
---@param val any
---@param args? table
---@return string | nil
Expand All @@ -186,7 +186,7 @@ local function get_val(val, args)
end
end

---Gets the option from the custom table
---get the option from the custom table
---@param key string
---@param args? table
---@return string | nil
Expand All @@ -202,7 +202,7 @@ local function get_custom_opt(key, opts, args)
end
end

---Gets the option from the files table
---get the option from the files table
---@param key string
---@param args? table
---@return string | nil
Expand All @@ -224,7 +224,7 @@ local function get_file_opt(key, opts, args, file)
return nil
end

---Gets the option from the dirs table
---get the option from the dirs table
---@param key string
---@param args? table
---@return string | nil
Expand All @@ -246,21 +246,21 @@ local function get_dir_opt(key, opts, args, dir)
return nil
end

---Gets the option from the filetypes table
---get the option from the filetypes table
---@param key string
---@return string | nil
local function get_filetype_opt(key, opts, ft)
return recursive_get_opt("filetypes." .. ft .. "." .. key, opts)
end

---Gets the option from the default table
---get the option from the default table
---@param key string
---@return string | nil
local function get_default_opt(key, opts)
return recursive_get_opt("default." .. key, opts)
end

---Gets the option from the main opts table
---get the option from the main opts table
---@param key string
---@return string | nil
local function get_unscoped_opt(key, opts)
Expand Down Expand Up @@ -304,11 +304,10 @@ M.get_opt = function(key, api_opts, args, opts)
return get_val(val, args)
end

---@param config_opts? table
function M.setup(config_opts)
M.opts = vim.tbl_deep_extend("force", {}, defaults, config_opts or {})
M.opts = M.sort_config(M.opts)
end

M.setup()

return M
111 changes: 0 additions & 111 deletions lua/img-clip/drag_and_drop.lua

This file was deleted.

Loading

0 comments on commit 24cbf88

Please sign in to comment.