Repository: sxyazi/yazi (language: rust)

Issue:
Add Option to Choose Path Separator for Copy Path Functionality
### `yazi --debug` output

```Shell
Yazi
    Version: 0.3.3 (7c445ce 2024-09-04)
    Debug  : false
    OS     : windows-x86_64 (windows)

Ya
    Version: 0.3.3 (7c445ce 2024-09-04)

Emulator
    Emulator.via_env: ("", "")
    Emulator.via_csi: Ok(Unknown([Sixel]))
    Emulator.detect : Microsoft

Adapter
    Adapter.matches: Sixel

Desktop
    XDG_SESSION_TYPE           : None
    WAYLAND_DISPLAY            : None
    DISPLAY                    : None
    SWAYSOCK                   : None
    HYPRLAND_INSTANCE_SIGNATURE: None
    WAYFIRE_SOCKET             : None

SSH
    shared.in_ssh_connection: false

WSL
    WSL: false

Variables
    SHELL              : None
    EDITOR             : None
    VISUAL             : None
    YAZI_FILE_ONE      : Some("C:/Users/Administrator/scoop/apps/git/2.45.2/usr/bin/file.exe")
    YAZI_CONFIG_HOME   : None

Text Opener
    default: Some(Opener { run: "nvim %*", block: true, orphan: false, desc: "$EDITOR", for_: None, spread: true })
    block  : Some(Opener { run: "nvim %*", block: true, orphan: false, desc: "$EDITOR", for_: None, spread: true })

Multiplexers
    TMUX               : false
    tmux version       : program not found
    ZELLIJ_SESSION_NAME: None
    Zellij version     : program not found

Dependencies
    file             : 5.45
    ueberzugpp       : program not found
    ffmpegthumbnailer: program not found
    magick           : 7.1.1-39
    fzf              : 0.55.0
    fd               : 10.2.0
    rg               : 14.1.0
    chafa            : program not found
    zoxide           : 0.9.6
    7z               : 24.07
    7zz              : program not found
    jq               : 1.7.1


--------------------------------------------------
When reporting a bug, please also upload the `yazi.log` log file - only upload the most recent content by time.
You can find it in the "C:\\Users\\Administrator\\AppData\\Roaming\\yazi\\state" directory.
```


### Please describe the problem you're trying to solve

Hello,

I would like to propose a feature enhancement for the "Copy Path" functionality in your project. Currently, when copying paths, the separator is fixed, which can lead to issues when using backslashes in code. It would be beneficial to include an option that allows users to choose between forward slashes (/) and backslashes (\\) as the path separator.

This feature would help avoid the need for manual string escaping when pasting backslash paths into code, improving the overall user experience.

Thank you for considering this suggestion!

Best regards,

### Would you be willing to contribute this feature?

- [ ] Yes, I'll give it a shot

### Describe the solution you'd like

Maybe
`yazi.toml`
```
[manager]
path_separator = "/"
```

### Additional context

_No response_

### Validations

- [X] I have searched the existing issues/discussions
- [X] The [latest nightly build](https://yazi-rs.github.io/docs/installation/#official-binaries) doesn't already have this feature


Discussion / hints:
I like this idea, we can add a new `--separator` option to [the `copy` command](https://yazi-rs.github.io/docs/configuration/keymap/#manager.copy):

```sh
copy path --separator=unix
```

where `--separator` can be:

- `"unix"`: Use `/` as path separator
- `"auto"`: Default. Use `/` on Unix and `\` on Windows

Anyone want to give it a go? The `copy` command can be found at:

https://github.com/sxyazi/yazi/blob/a8bd21ad5fadce0a9c718fb25609e1e34f2e3d06/yazi-core/src/tab/commands/copy.rs#L18-L36

> Anyone want to give it a go? The `copy` command can be found at:

Hi @sxyazi! I'd like to work on this issue. Thanks!

Sure, go for it! @alan910127 

Fix patch:
diff --git a/yazi-core/src/tab/commands/copy.rs b/yazi-core/src/tab/commands/copy.rs
index af797ce54..806845f79 100644
--- a/yazi-core/src/tab/commands/copy.rs
+++ b/yazi-core/src/tab/commands/copy.rs
@@ -1,4 +1,4 @@
-use std::ffi::{OsStr, OsString};
+use std::{borrow::Cow, ffi::{OsStr, OsString}, path::Path};
 
 use yazi_plugin::CLIPBOARD;
 use yazi_shared::event::Cmd;
@@ -6,11 +6,17 @@ use yazi_shared::event::Cmd;
 use crate::tab::Tab;
 
 struct Opt {
-	type_: String,
+	type_:     String,
+	separator: Separator,
 }
 
 impl From<Cmd> for Opt {
-	fn from(mut c: Cmd) -> Self { Self { type_: c.take_first_str().unwrap_or_default() } }
+	fn from(mut c: Cmd) -> Self {
+		Self {
+			type_:     c.take_first_str().unwrap_or_default(),
+			separator: c.str("separator").unwrap_or_default().into(),
+		}
+	}
 }
 
 impl Tab {
@@ -24,10 +30,10 @@ impl Tab {
 		let mut it = self.selected_or_hovered(true).peekable();
 		while let Some(u) = it.next() {
 			s.push(match opt.type_.as_str() {
-				"path" => u.as_os_str(),
-				"dirname" => u.parent().map_or(OsStr::new(""), |p| p.as_os_str()),
-				"filename" => u.name(),
-				"name_without_ext" => u.file_stem().unwrap_or(OsStr::new("")),
+				"path" => opt.separator.transform(u),
+				"dirname" => opt.separator.transform(u.parent().unwrap_or(Path::new(""))),
+				"filename" => opt.separator.transform(u.name()),
+				"name_without_ext" => opt.separator.transform(u.file_stem().unwrap_or_default()),
 				_ => return,
 			});
 			if it.peek().is_some() {
@@ -43,3 +49,32 @@ impl Tab {
 		futures::executor::block_on(CLIPBOARD.set(s));
 	}
 }
+
+// --- Separator
+#[derive(Clone, Copy, PartialEq, Eq)]
+enum Separator {
+	Auto,
+	Unix,
+}
+
+impl From<&str> for Separator {
+	fn from(value: &str) -> Self {
+		match value {
+			"unix" => Self::Unix,
+			_ => Self::Auto,
+		}
+	}
+}
+
+impl Separator {
+	fn transform<T: AsRef<Path> + ?Sized>(self, p: &T) -> Cow<OsStr> {
+		#[cfg(windows)]
+		if self == Self::Unix {
+			return match yazi_shared::fs::backslash_to_slash(p.as_ref()) {
+				Cow::Owned(p) => Cow::Owned(p.into_os_string()),
+				Cow::Borrowed(p) => Cow::Borrowed(p.as_os_str()),
+			};
+		}
+		Cow::Borrowed(p.as_ref().as_os_str())
+	}
+}


Test patch: