1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
use std::ffi::OsString;

/// Returns arguments passed in from the command-line, starting with the program name.
///
/// On web, this transforms URL query parameters into command-line arguments, by treating `&` as
/// the separator between arguments. So for instance "?--dev&--color_scheme=night%20mode" becomes
/// vec!["dummy program name", "--dev", "--color_scheme=night mode"].
pub fn cli_args() -> impl Iterator<Item = OsString> {
    #[cfg(target_arch = "wasm32")]
    {
        match parse_args() {
            Ok(mut args) => {
                args.insert(0, "dummy program name".to_string());
                let x: Vec<OsString> = args.into_iter().map(|x| x.into()).collect();
                return x.into_iter();
            }
            Err(err) => {
                warn!("Didn't parse arguments from URL query params: {}", err);
                Vec::new().into_iter()
            }
        }
    }
    #[cfg(not(target_arch = "wasm32"))]
    {
        std::env::args_os()
    }
}

/// Transforms some command-line arguments into URL query parameters, using `&` as the separator
/// between arguments. The string returned starts with `?`, unless the arguments are all empty.
pub fn args_to_query_string(args: Vec<String>) -> String {
    // TODO Similar to parse_args forgoing a URL decoding crate, just handle this one
    // transformation
    let result = args
        .into_iter()
        .map(|x| x.replace(" ", "%20"))
        .collect::<Vec<_>>()
        .join("&");
    if result.is_empty() {
        result
    } else {
        format!("?{}", result)
    }
}

#[cfg(target_arch = "wasm32")]
fn parse_args() -> anyhow::Result<Vec<String>> {
    let window = web_sys::window().ok_or(anyhow!("no window?"))?;
    let url = window.location().href().map_err(|err| {
        anyhow!(err
            .as_string()
            .unwrap_or("window.location.href failed".to_string()))
    })?;
    // Consider using a proper url parsing crate. This works fine for now, though.
    let url_parts = url.split("?").collect::<Vec<_>>();
    if url_parts.len() != 2 {
        bail!("URL {url} doesn't seem to have query params");
    }
    let parts = url_parts[1]
        .split("&")
        .map(|x| x.replace("%20", " ").to_string())
        .collect::<Vec<_>>();
    Ok(parts)
}