Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[Feat] adding support to copy to clipboard in WSL #83

Open
wants to merge 14 commits into
base: main
Choose a base branch
from
Open
11 changes: 11 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@
- [Usage](#usage)
- [Copy into the clipboard](#copy-into-the-clipboard)
- [Copy into clipboard on Linux Wayland](#copy-into-clipboard-on-linux-wayland)
- [Copy into clipboard on WSL](#copy-into-clipboard-on-wsl)
jhonnyV-V marked this conversation as resolved.
Show resolved Hide resolved
- [Save the snapshot](#save-the-snapshot)
- [Highlight code block](#highlight-code-block)
- [How to use](#how-to-use)
Expand Down Expand Up @@ -169,6 +170,14 @@ Copy screenshots directly into the clipboard is cool, however, it doesn't work w

If you using CodeSnap.nvim on wl-clipboard, you can refer [wl-clip-persist](https://github.com/Linus789/wl-clip-persist), it reads all the clipboard data into memory and then overwrites the clipboard with the data from our memory to persist copied data.


#### Copy into clipboard on WSL
currently copy to clipboard in WSL works, but it has some potencial issues, inside of wsl normally is not possible to copy an image to the clipboard,
how this works in wsl at this moment is the following, we create an image in the /tmp directory, then we try to execute powershell commands
to copy the image to the clipboard
> [!WARNING]
> If the WSL distro name is not the default or the pretty_name/name in the /etc/os-release this feature will fai

### Save the snapshot

Of course, you can use `CodeSnapSave` command to save the snapshot to path where you defined it in `config.save_path`
Expand All @@ -181,6 +190,8 @@ require("codesnap").setup({
-- parsed: "~/Pictures/CodeSnap_y-m-d_at_h:m:s.png"
-- save_path = "~/Pictures/foo.png"
-- parsed: "~/Pictures/foo.png"
-- if you are on wsl and do you want to use a windows path
-- save_path="/mnt/c/Users/user/Pictures/"
save_path = ...
})
```
Expand Down
18 changes: 18 additions & 0 deletions generator/Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 2 additions & 0 deletions generator/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,8 @@ thiserror = "1.0.58"
regex = "1.10.3"
two-face = "0.3.0"
cached = "0.49.3"
wsl = "0.1.0"
sys-info = "0.9.1"

[lib]
crate-type = ["cdylib"]
147 changes: 137 additions & 10 deletions generator/src/copy.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,8 +2,7 @@ use crate::{config::TakeSnapshotParams, snapshot::take_snapshot};
#[cfg(target_os = "linux")]
use arboard::SetExtLinux;
use arboard::{Clipboard, ImageData};

use nvim_oxi::Result;
use nvim_oxi::{lua::Error::RuntimeError, Error, Result};

pub fn copy_into_clipboard(config: TakeSnapshotParams) -> Result<()> {
let pixmap = take_snapshot(config.clone())?;
Expand All @@ -28,17 +27,145 @@ pub fn copy_into_clipboard(config: TakeSnapshotParams) -> Result<()> {
};

#[cfg(target_os = "linux")]
std::thread::spawn(move || {
Clipboard::new()
.unwrap()
.set()
.wait()
.image(img_data)
.unwrap();
});
if wsl::is_wsl() {
let temp_dir = std::env::temp_dir();
let filename = generate_random_filename();

let path = format!("{}/{}", String::from(temp_dir.to_str().unwrap()), filename);
mistricky marked this conversation as resolved.
Show resolved Hide resolved
let _ = pixmap
.save_png(path.clone())
.map_err(|err| Error::Lua(RuntimeError(err.to_string())));

//getting mounted vdisk location of linux install
let os_linux_release = sys_info::linux_os_release().unwrap();
let mut wsl_path = format!(
"\\\\wsl$\\{}",
os_linux_release.pretty_name()
);
if !powershell_folder_exist(wsl_path.clone()) {
wsl_path = format!(
"\\\\wsl$\\{}",
os_linux_release.name()
);
}
let src_path = format!(
"{}\\tmp\\{}",
wsl_path,
filename
);

let _ = copy_to_wsl_clipboard(&src_path);
//delete the file when done?
} else {
std::thread::spawn(move || {
Clipboard::new()
.unwrap()
.set()
.wait()
.image(img_data)
.unwrap();
});
}
#[cfg(not(target_os = "linux"))]
Clipboard::new().unwrap().set_image(img_data).unwrap();

Ok(())
}

fn copy_to_wsl_clipboard(src_path: &str) -> Result<()> {
println!("{}", src_path);
let powershell = Command::new("/mnt/c/Windows//System32/WindowsPowerShell/v1.0/powershell.exe")
.arg("-NoProfile")
.arg("-Command")
.arg(&format!("Get-ChildItem \"{}\" | Set-Clipboard", src_path))
.stdout(Stdio::null())
.stderr(Stdio::null())
.spawn();

// Wait until the powershell process is finished before returning
let _ = powershell.unwrap().wait().unwrap();

Ok(())
}

use std::{
process::{Command, Stdio}, time::Instant
};

fn powershell_folder_exist(src_path: String) -> bool {
let powershell = Command::new("/mnt/c/Windows//System32/WindowsPowerShell/v1.0/powershell.exe")
.arg("-NoProfile")
.arg("-Command")
.arg(&format!("Test-Path -path \"{}\"", src_path))
.stdout(Stdio::piped())
.stderr(Stdio::null())
.output();

let stdout = String::from_utf8(powershell.unwrap().stdout).unwrap();

let result = stdout == "True\r\n";

return result;
}

fn generate_random_filename() -> String {
// Get nanoseconds since epoch for randomness
let now = Instant::now();
let random_part = format!("{:016x}", now.elapsed().as_nanos() % u128::MAX);

// Combine prefix, random part, and extension
format!("codesnap_{}.png", random_part)
}
mistricky marked this conversation as resolved.
Show resolved Hide resolved

#[cfg(test)]
mod test {
use std::process::{Command, Stdio};

use super::copy_to_wsl_clipboard;

#[test]
#[cfg(target_os = "linux")]
fn copy_to_wsl_test() -> std::result::Result<(), nvim_oxi::Error> {

if !wsl::is_wsl() {
return Ok(());
}

//not sure about the best way to test this in a dynamic way
//dir example
//"\\\\wsl$\\DistroName\\\\home\\username\\path\\test.png";
let src_path = "";// your director here
return copy_to_wsl_clipboard(src_path);
}

#[test]
#[cfg(target_os = "linux")]
fn check_if_folder_exist() {
if !wsl::is_wsl() {
return;
}

let os_linux_release = sys_info::linux_os_release().unwrap();
let wsl_path = format!(
"\\\\wsl$\\{}",
os_linux_release.name()
);

println!("path {}", wsl_path);

let powershell = Command::new("/mnt/c/Windows//System32/WindowsPowerShell/v1.0/powershell.exe")
.arg("-NoProfile")
.arg("-Command")
.arg(&format!("Test-Path -path \"{}\"", wsl_path))
.stdout(Stdio::piped())
.stderr(Stdio::null())
.output();

let stdout = String::from_utf8(powershell.unwrap().stdout).unwrap();

println!("output {:?}", stdout);
println!("exist {}", stdout == "True\r\n");
println!("does not exist {}", stdout == "False\r\n");
}
}

Binary file modified lua/linux-x86_64generator.so
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

These .so files should not be committed, because them is created by CI, I'll add the them into .gitignore

Binary file not shown.
Binary file modified lua/mac-aarch64generator.so
Binary file not shown.
Binary file modified lua/mac-x86_64generator.so
Binary file not shown.