abstutil/
cli.rs

1use std::ffi::OsString;
2
3/// Returns arguments passed in from the command-line, starting with the program name.
4///
5/// On web, this transforms URL query parameters into command-line arguments, by treating `&` as
6/// the separator between arguments. So for instance "?--dev&--color_scheme=night%20mode" becomes
7/// vec!["dummy program name", "--dev", "--color_scheme=night mode"].
8pub fn cli_args() -> impl Iterator<Item = OsString> {
9    #[cfg(target_arch = "wasm32")]
10    {
11        match parse_args() {
12            Ok(mut args) => {
13                args.insert(0, "dummy program name".to_string());
14                let x: Vec<OsString> = args.into_iter().map(|x| x.into()).collect();
15                return x.into_iter();
16            }
17            Err(err) => {
18                warn!("Didn't parse arguments from URL query params: {}", err);
19                Vec::new().into_iter()
20            }
21        }
22    }
23    #[cfg(not(target_arch = "wasm32"))]
24    {
25        std::env::args_os()
26    }
27}
28
29/// Transforms some command-line arguments into URL query parameters, using `&` as the separator
30/// between arguments. The string returned starts with `?`, unless the arguments are all empty.
31pub fn args_to_query_string(args: Vec<String>) -> String {
32    // TODO Similar to parse_args forgoing a URL decoding crate, just handle this one
33    // transformation
34    let result = args
35        .into_iter()
36        .map(|x| x.replace(" ", "%20"))
37        .collect::<Vec<_>>()
38        .join("&");
39    if result.is_empty() {
40        result
41    } else {
42        format!("?{}", result)
43    }
44}
45
46#[cfg(target_arch = "wasm32")]
47fn parse_args() -> anyhow::Result<Vec<String>> {
48    let window = web_sys::window().ok_or(anyhow!("no window?"))?;
49    let url = window.location().href().map_err(|err| {
50        anyhow!(err
51            .as_string()
52            .unwrap_or("window.location.href failed".to_string()))
53    })?;
54    // Consider using a proper url parsing crate. This works fine for now, though.
55    let url_parts = url.split("?").collect::<Vec<_>>();
56    if url_parts.len() != 2 {
57        bail!("URL {url} doesn't seem to have query params");
58    }
59    let parts = url_parts[1]
60        .split("&")
61        .map(|x| x.replace("%20", " ").to_string())
62        .collect::<Vec<_>>();
63    Ok(parts)
64}