Skip to content

Instantly share code, notes, and snippets.

@brad-jones
Created January 16, 2023 02:56
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save brad-jones/a01f01ad0bdf0f3255b61ccce13bc1d3 to your computer and use it in GitHub Desktop.
Save brad-jones/a01f01ad0bdf0f3255b61ccce13bc1d3 to your computer and use it in GitHub Desktop.
xdg-open (WSL)
#!/bin/bash
exec deno run --cached-only -qA /usr/bin/xdg-open.ts "$@"
import { Command } from "https://deno.land/x/cliffy@v0.25.7/command/mod.ts#^";
const CMD_EXE = `/mnt/c/Windows/System32/cmd.exe`;
const EXPLORER_EXE = `/mnt/c/Windows/explorer.exe`;
/**
* Converts a POSIX (eg: /mnt/c/Windows) to a WIN32 (eg: C:\Windows) path.
*/
const convertPosixToWin32Path = async (input: string) => {
const p = Deno.run({ cmd: ["wslpath", "-aw", input], stdout: "piped", stderr: "piped" });
const r = await Promise.all([p.status(), p.output(), p.stderrOutput()]);
if (!r[0].success) {
throw new Error(`failed to convert '${input}' to a win32 path: ${new TextDecoder().decode(r[2])}`);
}
return new TextDecoder().decode(r[1]);
};
/**
* Escape an argument string to be suitable to be passed to cmd.exe on Windows
*
* see: https://stackoverflow.com/questions/29213106
*/
const escapeForCmdExe = (input: string) =>
(input.match(/(["\s])/) ? `"${input.replace('"', '\\"')}"` : input)
.replace(/([()%!^"<>&|])/, "^$1");
await new Command()
.name("xdg-open")
.version(import.meta.url)
.description(`
Drop-in replacement for xdg-open on WSL systems that will,
via WSL Interop., open native Windows applications.
If the argument is a url starting with http(s) it is opened
with the default Windows handler, typically your browser.
If the argument is a filename, first its true location is determined.
Then if the file is on the NTFS filesystem, it is passed as a win32
path (eg: C:\\\\Users\\\\foo) to Windows for handling.
However if it is on the WSL filesystem, it is transformed to a WSL UNC path
(eg: \\\\wsl.localhost\\\\Ubuntu\\\\home\\\\foo) and passed to Windows for handling.
credit: <https://github.com/cpbotha/xdg-open-wsl>
FWIW: The only real reason I re-wrote it is for packaging purposes.
Python is just such a pain in the arse IMO. Deno on the other is a
super simple, single binary install.
`)
.arguments("<path-or-url:string>")
.action(async (_, pathOrUrl) => {
// Detect file:// URLs strip the prefix so we don't think it's some other URL.
pathOrUrl = pathOrUrl.startsWith("file://") ? pathOrUrl.replace("file://", "") : pathOrUrl;
// Detect URLs of the form protocol://address
// Pass them directly to Windows as is & hope it knows what to do.
if (pathOrUrl.match(/^.*:\/\/.*$/)) {
Deno.exit(
(await Deno.run({
cmd: [
CMD_EXE,
"/c",
"start",
escapeForCmdExe(pathOrUrl),
],
cwd: `/mnt/c`,
}).status()).code,
);
}
// Otherwise assume we have a filesystem path.
// Pass it to explorer.exe
Deno.exit(
(await Deno.run({
cmd: [
EXPLORER_EXE,
await convertPosixToWin32Path(pathOrUrl),
],
}).status()).code,
);
})
.parse();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment