From 68f28d21e6c1c9a8202fad4e1ec682c64f058ab6 Mon Sep 17 00:00:00 2001 From: Yeoh Joer Date: Sat, 12 Oct 2024 03:39:35 +0800 Subject: [PATCH] feat: create a proxy program to start the code editor with unc paths for files and folders in wsl --- Cargo.toml | 20 ++++++++- src/main.rs | 123 ++++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 142 insertions(+), 1 deletion(-) create mode 100644 src/main.rs diff --git a/Cargo.toml b/Cargo.toml index 73d357e..a8e4882 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,10 +1,28 @@ [package] name = "camp" edition = "2021" +default-run = "camp" [lib] crate-type = ["cdylib", "lib"] +[[bin]] +name = "camp" +path = "src/main.rs" + +[[bin]] +name = "camp-nw" +path = "src/main.rs" +required-features = ["windows_subsystem"] + +[features] +windows_subsystem = [] + [dependencies] -clap = { version = "4.5.4", features = ["derive"] } +clap = { version = "4.5.20", features = ["derive"] } pyo3 = { version = "0.21.2", features = ["extension-module"] } +regex = "1.11.0" + +[dependencies.windows] +version = "0.57" +features = ["Win32_Foundation", "Win32_System_Console", "Win32_UI_WindowsAndMessaging"] diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..1653b0a --- /dev/null +++ b/src/main.rs @@ -0,0 +1,123 @@ +#![cfg_attr(feature = "windows_subsystem", windows_subsystem = "windows")] + +use clap::CommandFactory; +use clap::Parser; +use clap::Subcommand; +use regex::Regex; +use std::process::Command; +use windows::Win32::Foundation::HWND; +use windows::Win32::System::Console::GetConsoleWindow; +use windows::Win32::UI::WindowsAndMessaging::ShowWindow; +use windows::Win32::UI::WindowsAndMessaging::SW_HIDE; + +#[cfg(target_os = "windows")] +use std::os::windows::process::CommandExt; + +#[derive(Parser, Debug)] +#[command(version, about, long_about = None)] +struct Args { + #[command(subcommand)] + command: Option, + + #[arg(short = None, long, help = "Hide the console window.")] + hide_console: bool, +} + +#[derive(Subcommand, Debug)] +enum Commands { + #[clap(about = "Work with Visual Studio Code.")] + Code { + #[command(subcommand)] + subcommand: Option, + }, +} + +#[derive(Subcommand, Debug)] +enum CodeSubcommands { + #[clap(about = "Launch Visual Studio Code for files or folders within WSL.")] + Launch { path: String }, +} + +fn hide_console_window() { + let window = unsafe { GetConsoleWindow() }; + + if window == HWND(0) { + return; + } + + unsafe { + let _ = ShowWindow(window, SW_HIDE); + } +} + +fn main() { + let cli = Args::parse(); + + if cli.hide_console && cfg!(target_os = "windows") { + hide_console_window(); + } + + match cli.command { + Some(Commands::Code { subcommand }) => match subcommand { + Some(CodeSubcommands::Launch { path }) => { + if !path.starts_with("\\\\wsl$") { + return; + } + + let pattern = r"\\\\wsl\$\\(.*?)(\\.*)"; + let re = Regex::new(pattern).unwrap(); + + if let Some(captures) = re.captures(&path) { + let distro_name = captures.get(1).unwrap().as_str(); + let path = captures.get(2).unwrap().as_str(); + + let remote = format!("wsl+{}", distro_name); + let new_path = path.replace("\\", "/"); + + let program = if cfg!(target_os = "windows") { + "code.cmd" + } else if cfg!(target_os = "linux") { + "code" + } else { + "" + }; + + if program.is_empty() { + return; + } + + #[cfg(target_os = "windows")] + { + const CREATE_NO_WINDOW: u32 = 0x08000000; + + Command::new(program) + .arg("--remote") + .arg(&remote) + .arg(&new_path) + .creation_flags(CREATE_NO_WINDOW) + .spawn() + .expect(""); + } + + #[cfg(not(target_os = "windows"))] + Command::new(program) + .arg("--remote") + .arg(&remote) + .arg(&new_path) + .spawn() + .expect(""); + } + } + None => { + Args::command() + .find_subcommand_mut("code") + .unwrap() + .print_help() + .unwrap(); + } + }, + None => { + Args::command().print_help().unwrap(); + } + } +}