generated from nhcarrigan/template
feat: convert WSL Linux paths to Windows UNC paths when opening binary files
Adds open_binary_file Tauri command that translates WSL Linux-style paths (e.g. /tmp/mcp_output_abc123.pdf) to Windows UNC paths via wslpath -w before opening, so binary file links work correctly on Windows/WSL. Non-Windows platforms pass the path through unchanged. Markdown.svelte now invokes this command instead of calling openPath directly.
This commit is contained in:
@@ -2578,6 +2578,32 @@ pub async fn scan_project(working_dir: String) -> Result<ProjectScan, String> {
|
||||
})
|
||||
}
|
||||
|
||||
#[tauri::command]
|
||||
pub async fn open_binary_file(app: AppHandle, path: String) -> Result<(), String> {
|
||||
use tauri_plugin_opener::OpenerExt;
|
||||
|
||||
#[cfg(target_os = "windows")]
|
||||
{
|
||||
// Convert the WSL Linux path (e.g. /tmp/file.pdf) to a Windows UNC path
|
||||
// (e.g. \\wsl.localhost\Ubuntu\tmp\file.pdf) so the Windows shell can open it.
|
||||
let output = std::process::Command::new("wsl")
|
||||
.args(["wslpath", "-w", &path])
|
||||
.output()
|
||||
.map_err(|e| e.to_string())?;
|
||||
let windows_path = String::from_utf8_lossy(&output.stdout).trim().to_string();
|
||||
app.opener()
|
||||
.open_path(windows_path, None::<&str>)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
|
||||
#[cfg(not(target_os = "windows"))]
|
||||
{
|
||||
app.opener()
|
||||
.open_path(path, None::<&str>)
|
||||
.map_err(|e| e.to_string())
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
use super::*;
|
||||
@@ -3292,4 +3318,39 @@ gitea: gitea-mcp -t stdio (STDIO) - ✓ Connected"#;
|
||||
Some("Indented Heading".to_string())
|
||||
);
|
||||
}
|
||||
|
||||
// ==================== open_binary_file E2E path conversion tests ====================
|
||||
|
||||
/// Build the wslpath command structure without executing it, for cross-platform CI testing.
|
||||
#[cfg(test)]
|
||||
fn build_wslpath_command(path: &str) -> (String, Vec<String>) {
|
||||
(
|
||||
"wsl".to_string(),
|
||||
vec!["wslpath".to_string(), "-w".to_string(), path.to_string()],
|
||||
)
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_e2e_wslpath_command_structure_pdf() {
|
||||
let (command, args) = build_wslpath_command("/tmp/mcp_output_abc123.pdf");
|
||||
assert_eq!(command, "wsl");
|
||||
assert_eq!(args.len(), 3);
|
||||
assert_eq!(args[0], "wslpath");
|
||||
assert_eq!(args[1], "-w");
|
||||
assert_eq!(args[2], "/tmp/mcp_output_abc123.pdf");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_e2e_wslpath_command_structure_audio() {
|
||||
let (command, args) = build_wslpath_command("/tmp/mcp_output_xyz789.mp3");
|
||||
assert_eq!(command, "wsl");
|
||||
assert_eq!(args[2], "/tmp/mcp_output_xyz789.mp3");
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_e2e_wslpath_command_structure_preserves_path() {
|
||||
let path = "/home/naomi/documents/report with spaces.pdf";
|
||||
let (_, args) = build_wslpath_command(path);
|
||||
assert_eq!(args[2], path);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -223,6 +223,7 @@ pub fn run() {
|
||||
delete_draft,
|
||||
delete_all_drafts,
|
||||
scan_project,
|
||||
open_binary_file,
|
||||
])
|
||||
.run(tauri::generate_context!())
|
||||
.expect("error while running tauri application");
|
||||
|
||||
@@ -2,7 +2,8 @@
|
||||
import { marked } from "marked";
|
||||
import hljs from "highlight.js";
|
||||
import { onMount } from "svelte";
|
||||
import { openUrl, openPath } from "@tauri-apps/plugin-opener";
|
||||
import { openUrl } from "@tauri-apps/plugin-opener";
|
||||
import { invoke } from "@tauri-apps/api/core";
|
||||
import { clipboardStore } from "$lib/stores/clipboard";
|
||||
import { linkifyFilePaths } from "$lib/utils/filePaths";
|
||||
|
||||
@@ -148,7 +149,7 @@
|
||||
|
||||
const filePath = anchor.dataset.filepath;
|
||||
if (filePath) {
|
||||
void openPath(filePath);
|
||||
void invoke("open_binary_file", { path: filePath });
|
||||
return;
|
||||
}
|
||||
|
||||
|
||||
@@ -9,7 +9,8 @@
|
||||
* - [ ] Code blocks render with syntax highlighting and a copy button
|
||||
* - [ ] ||spoiler text|| renders as a hidden span revealed on click
|
||||
* - [ ] Search query highlights matching text in non-code content
|
||||
* - [ ] Links open in the system browser via the Tauri opener
|
||||
* - [ ] Regular links open in the system browser via the Tauri opener
|
||||
* - [ ] Binary file links invoke open_binary_file (WSL-path-aware) instead of openPath
|
||||
*/
|
||||
|
||||
import { describe, it, expect } from "vitest";
|
||||
|
||||
Reference in New Issue
Block a user