Created
January 16, 2023 02:56
-
-
Save brad-jones/a01f01ad0bdf0f3255b61ccce13bc1d3 to your computer and use it in GitHub Desktop.
xdg-open (WSL)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/bin/bash | |
exec deno run --cached-only -qA /usr/bin/xdg-open.ts "$@" |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
import { Command } from "https://deno.land/x/[email protected]/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