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
1 change: 1 addition & 0 deletions .gitattributes
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
* text=auto eol=lf
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,2 +1,3 @@
tests/vendor/*
bin/richclip
bin/richclip.exe
8 changes: 4 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,10 +15,10 @@ with extra features:

## Installing

The plugin requires [richchip](https://github.com/beeender/richclip) command
The plugin requires [richclip](https://github.com/beeender/richclip) command
line utility to be installed. The plugin will try to download the utility if
necessary. Or it can be installed separately.
See [richchip#install](https://github.com/beeender/richclip?tab=readme-ov-file#installing).
necessary on Linux, macOS, and Windows. Or it can be installed separately.
See [richclip#install](https://github.com/beeender/richclip?tab=readme-ov-file#installing).

### lazy.nvim

Expand Down Expand Up @@ -49,7 +49,7 @@ require("richclip").setup({

### Copy the highlighted code

By default, `richchip.nvim` will set itself as the Neovim clipboard provider,
By default, `richclip.nvim` will set itself as the Neovim clipboard provider,
`"+y` (or other hotkeys set by users) will copy the current selection to the
clipboard in both `text/plain` and `text/html` format. So the paste client, like
a word processor, can choose the preferred format to use.
Expand Down
29 changes: 29 additions & 0 deletions bin/install.ps1
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
param(
[Parameter(Mandatory = $true)]
[string]$Version,

[Parameter(Mandatory = $true)]
[string]$TargetDir
)

$ErrorActionPreference = "Stop"

$architecture = [System.Runtime.InteropServices.RuntimeInformation]::OSArchitecture.ToString()
$target = switch ($architecture) {
"X64" { "x86_64-pc-windows-msvc" }
"Arm64" { "aarch64-pc-windows-msvc" }
default { throw "Unsupported Windows architecture: '$architecture'" }
}

$archiveName = "richclip_v${Version}_${target}.zip"
$url = "https://github.com/beeender/richclip/releases/download/v${Version}/${archiveName}"
$archivePath = Join-Path ([System.IO.Path]::GetTempPath()) $archiveName

New-Item -ItemType Directory -Force -Path $TargetDir | Out-Null
try {
Invoke-WebRequest -Uri $url -OutFile $archivePath
Expand-Archive -LiteralPath $archivePath -DestinationPath $TargetDir -Force
}
finally {
Remove-Item -LiteralPath $archivePath -Force -ErrorAction SilentlyContinue
}
21 changes: 20 additions & 1 deletion bin/install.sh
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,26 @@ download() {
popd
;;
CYGWIN* | MINGW* | MSYS_NT*)
echoerr "Windows build is not available yet."
pushd "$TARGET_DIR"
arch="$(uname -m)"
case "${arch}" in
arm64|aarch64)
target="aarch64-pc-windows-msvc"
;;
x86_64)
target="x86_64-pc-windows-msvc"
;;
*)
echoerr "Unsupported Windows architecture: '${arch}'"
exit 1
;;
esac
archive="richclip_v${VERSION_STR}_${target}.zip"
curl -fsSLO \
"https://github.com/beeender/richclip/releases/download/v${VERSION_STR}/${archive}"
tar -xf "$archive"
rm "$archive"
popd
;;
*)
echoerr "Unknown system '$unameOut'"
Expand Down
8 changes: 6 additions & 2 deletions lua/richclip/api.lua
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ local ser = require("richclip.ser")
local utils = require("richclip.utils")
local binary = require("richclip.binary")

local function use_primary(is_primary)
return is_primary and vim.fn.has("win32") == 0
end

---Copy the selections to the clipboard.
---The {SELECTION} should be a table like:
---{
Expand All @@ -15,7 +19,7 @@ local binary = require("richclip.binary")
---@param selections SELECTION[]
API.to_clip = function(is_primary, selections)
local args = { "copy" }
if is_primary then
if use_primary(is_primary) then
table.insert(args, "--primary")
end

Expand All @@ -37,7 +41,7 @@ end
---@return [string]
API.from_clip = function(is_primary, mime_type)
local args = { "paste" }
if is_primary then
if use_primary(is_primary) then
table.insert(args, "--primary")
end

Expand Down
83 changes: 58 additions & 25 deletions lua/richclip/binary.lua
Original file line number Diff line number Diff line change
Expand Up @@ -5,20 +5,26 @@ local config = require("richclip.config")
local utils = require("richclip.utils")

M._major_ver = "0"
M._minor_ver = "3"
M._minor_ver = "4"
M._patch_ver = "0"

local current_file_dir = debug.getinfo(1).source:match('@?(.*/)')
local current_file_dir_parts = vim.split(current_file_dir, '/')
local root_dir = table.concat(utils.table_slice(current_file_dir_parts, 1, #current_file_dir_parts - 3), '/')
local current_file = debug.getinfo(1).source:gsub("^@", "")
local root_dir = vim.fs.dirname(vim.fs.dirname(vim.fs.dirname(current_file)))
local installer_dir = vim.fs.joinpath(root_dir, "bin")
-- Need to mock in test
M._bin_dir = root_dir .. "/bin"
local install_script_path = M._bin_dir .. "/install.sh"
local richclip_bin_path = M._bin_dir .. "/richclip"
M._bin_dir = installer_dir

M._exe_path = nil
M.tried_download = false

local function is_windows()
return vim.fn.has("win32") ~= 0
end

local function richclip_bin_path()
return vim.fs.joinpath(M._bin_dir, is_windows() and "richclip.exe" or "richclip")
end

local function check_richclip_version(path)
if vim.fn['executable'](path) == 0 then
return false
Expand All @@ -37,23 +43,58 @@ local function check_richclip_version(path)
return false
end

local pattern = "(%d+%.%d+%.[^ ]*)"
local ver_str = string.match(ret.stdout, pattern)
local pattern_parts = "(%d+)%.(%d+)%.(%d+)"
local major, minor, _ = ver_str:match(pattern_parts)
if (M._major_ver > major) or (M._major_ver == major and M._minor_ver > minor) then
local ver_str = ret.stdout:match("(%d+%.%d+%.[^%s]+)")
local major, minor, patch
if ver_str ~= nil then
major, minor, patch = ver_str:match("(%d+)%.(%d+)%.(%d+)")
end
if patch == nil then
utils.notify("binary.check_richclip_version", {
msg = string.format("\"%s\" is at version '%s', which is lower than the required version '%s.%s.x'", path,
ver_str, M._major_ver, M._minor_ver),
msg = string.format("Could not determine the version of \"%s\" from:\n%s", path, ret.stdout),
level = "WARN"
})
return false
end

local installed = { tonumber(major), tonumber(minor), tonumber(patch) }
local required = { tonumber(M._major_ver), tonumber(M._minor_ver), tonumber(M._patch_ver) }
local supported = false
for i = 1, 3 do
if installed[i] ~= required[i] then
supported = installed[i] > required[i]
break
end
supported = true
end
if not supported then
utils.notify("binary.check_richclip_version", {
msg = string.format("\"%s\" is at version '%s', which is lower than the required version '%s.%s.%s'",
path, ver_str, M._major_ver, M._minor_ver, M._patch_ver),
level = "WARN"
})
return false
end
return true
end

M.download_richclip_binary = function()
local ver_str = string.format("%d.%d.%d", M._major_ver, M._minor_ver, M._patch_ver)
local cmd_line = { install_script_path, ver_str, M._bin_dir }
local cmd_line
if is_windows() then
cmd_line = {
"powershell.exe",
"-NoProfile",
"-NonInteractive",
"-ExecutionPolicy",
"Bypass",
"-File",
vim.fs.joinpath(installer_dir, "install.ps1"),
ver_str,
M._bin_dir,
}
else
cmd_line = { vim.fs.joinpath(installer_dir, "install.sh"), ver_str, M._bin_dir }
end

-- Set the flag to avoid infinite download & check loop
M.tried_download = true
Expand All @@ -73,14 +114,6 @@ M.download_richclip_binary = function()
end

M.get_richclip_exe_path = function()
if vim.fn['has']("win32") ~= 0 then
utils.notify("binary.get_richclip_exe_path", {
msg = '"richclip" does not support Windows yet',
level = "ERROR"
})
return nil
end

if M._exe_path ~= nil then
return M._exe_path
end
Expand All @@ -96,8 +129,8 @@ M.get_richclip_exe_path = function()
end
elseif check_richclip_version("richclip") then
M._exe_path = "richclip"
elseif check_richclip_version(richclip_bin_path) then
M._exe_path = richclip_bin_path
elseif check_richclip_version(richclip_bin_path()) then
M._exe_path = richclip_bin_path()
end
if M._exe_path == nil and (not M.tried_download) then
utils.notify("binary.get_richclip_exe_path", {
Expand Down
9 changes: 1 addition & 8 deletions lua/richclip/init.lua
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ function M.setup(options)
config.with_defaults(options)

if config.enable_debug then
vim.env.RICHCLIP_LOG_FILE = "/tmp/richclip.log"
vim.env.RICHCLIP_LOG_FILE = vim.fs.joinpath(vim.fn.stdpath("log"), "richclip.log")
end

if config.set_g_clipboard then
Expand Down Expand Up @@ -48,13 +48,6 @@ end

---Takes over the g.clipboard
function M.set_g_clipboard()
if vim.fn['has']("win32") ~= 0 then
utils.notify("richclip.set_g_clipboard", {
msg = '"richclip" does not support Windows yet',
level = "WARN"
})
return
end
if vim.g.clipboard ~= nil then
utils.notify("richclip.set_g_clipboard", {
msg =
Expand Down
2 changes: 1 addition & 1 deletion tests/spec/binary_spec.lua
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,7 @@ describe("binary tests", function()

it('download_richclip_binary', function()
local old_dir = binary._bin_dir
local exe_path = "/tmp/richclip"
local exe_path = "/tmp/richclip" .. (vim.fn.has("win32") ~= 0 and ".exe" or "")
vim.fn['delete'](exe_path)
binary._bin_dir = "/tmp"

Expand Down
Loading