quad_url/
lib.rs

1#![allow(unused_variables)]
2
3//! # quad-url
4//! This is the crate to work with URL and open links in miniquad/macroquad environment.
5//!
6//! [Web demo.](https://optozorax.github.io/quad-url/?a&b=1&cd=e+f&gh#myhash)
7//!
8//! # Usage
9//! Add this to your `Cargo.toml` dependencies:
10//! ```text
11//! quad-url = "0.1.0"
12//! ```
13//! # Usage in WASM
14//! Add file [`quad-url/js/quad-url.js`](https://github.com/optozorax/quad-url/blob/368519c488aac55b73d3f29ed99c1afb9091d989/js/quad-url.js) to your project.
15//!
16//! Add file [`sapp-jsutils/js/sapp_jsutils.js`](https://github.com/not-fl3/sapp-jsutils/blob/4aa083662bfea725bf6e30453c009c6d02d667db/js/sapp_jsutils.js) file to your project. (version `0.1.4`, compatible with current crate)
17//!
18//!
19//! Add this lines after loading of `gl.js` and before loading of your wasm in your `index.html`:
20//! ```html
21//! <script src="sapp_jsutils.js"></script>
22//! <script src="quad-url.js"></script>
23//! ```
24//! Done! Now you can use this crate.
25
26#[cfg(target_arch = "wasm32")]
27use sapp_jsutils::{JsObject, JsObjectWeak};
28
29#[no_mangle]
30extern "C" fn quad_url_crate_version() -> u32 {
31    let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u32>().unwrap();
32    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u32>().unwrap();
33    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u32>().unwrap();
34
35    (major << 24) + (minor << 16) + patch
36}
37
38#[cfg(target_arch = "wasm32")]
39extern "C" {
40    fn quad_url_path(full: u32) -> JsObject;
41
42    fn quad_url_param_count() -> i32;
43    fn quad_url_get_key(pos: i32) -> JsObject;
44    fn quad_url_get_value(pos: i32) -> JsObject;
45
46    fn quad_url_delete_program_parameter(name: JsObjectWeak);
47    fn quad_url_set_program_parameter(name: JsObjectWeak, value: JsObjectWeak);
48
49    fn quad_url_get_hash() -> JsObject;
50    fn quad_url_set_hash(value: JsObjectWeak);
51
52    fn quad_url_link_open(url: JsObjectWeak, new_tab: u32);
53}
54
55/// Function to get «command line parameters» from query string in URL.
56///
57/// This function just returns `env::args().collect()` for non-WASM. But for WASM with link `https://.../index.html?k=1&begin&something=spa%20ce` it has same effect like running this program with command line parameters: `myprog -k=1 --begin --something="spa ce"`.
58///
59/// This works just by replacing key and value in this manner:
60/// * `k=1` → `-k=1`
61/// * `begin` → `--begin`
62/// * `something=spa%20ce` → `--something="spa ce"`
63///
64/// Also, this plugin supports unicode in query.
65///
66/// Notice that one-leters keys in URL treated as single-dash always. So, you can't present `myprog --k=1` in the address.
67///
68/// # Usage with `clap`
69///
70/// ```rust
71/// use quad_url::get_program_parameters;
72///
73/// let app = App::new("myapp");
74///
75/// // ...
76///
77/// let matches = app.get_matches_from_safe_borrow(get_program_parameters().iter());
78/// ```
79pub fn get_program_parameters() -> Vec<String> {
80    #[cfg(target_arch = "wasm32")]
81    {
82        let count = unsafe { quad_url_param_count() };
83        let mut path = String::new();
84        unsafe {
85            quad_url_path(0).to_string(&mut path);
86        }
87        let mut result = vec![path];
88        for i in 0..count {
89            let mut key = String::new();
90            unsafe {
91                quad_url_get_key(i).to_string(&mut key);
92            }
93
94            let mut value = String::new();
95            unsafe {
96                quad_url_get_value(i).to_string(&mut value);
97            }
98
99            let dash = if key.chars().count() == 1 { "-" } else { "--" };
100            if value == "" {
101                result.push(format!("{}{}", dash, key));
102            } else {
103                result.push(format!("{}{}={}", dash, key, &value));
104            }
105        }
106        result
107    }
108
109    #[cfg(not(target_arch = "wasm32"))]
110    {
111        std::env::args().collect()
112    }
113}
114
115/// Returns path to current program. Returns just `std::env::args().nth(0)` for non-WASM. And returns current URL before search params and before hash with `full = false`, returns full url with `full = true`.
116pub fn path(full: bool) -> String {
117    #[cfg(target_arch = "wasm32")]
118    {
119        let mut path = String::new();
120        unsafe {
121            quad_url_path(full as u32).to_string(&mut path);
122        }
123        path
124    }
125
126    #[cfg(not(target_arch = "wasm32"))]
127    {
128        if full {
129            std::env::args().collect::<Vec<_>>().join(" ")
130        } else {
131            std::env::args().next().unwrap()
132        }
133    }
134}
135
136/// Parses result from `get_program_parameters` returning `(name, value)`.
137///
138/// In case if you don't want to use `clap` to parse this parameters.
139///
140/// Returns `None` when parameter is not started from one or two dashes.
141pub fn easy_parse(param: &str) -> Option<(&str, Option<&str>)> {
142    let skip_len = if param.starts_with("--") {
143        "--".len()
144    } else if param.starts_with('-') {
145        "-".len()
146    } else {
147        return None;
148    };
149
150    if let Some(pos) = param.chars().position(|x| x == '=') {
151        let name = &param[skip_len..pos];
152        let value = &param[pos + '='.len_utf8()..];
153        if value.is_empty() {
154            Some((name, None))
155        } else {
156            Some((name, Some(value)))
157        }
158    } else {
159        Some((&param[skip_len..], None))
160    }
161}
162
163/// Deletes «command line parameters» in URL. Has no effect outside WASM.
164pub fn delete_program_parameter(name: &str) {
165    #[cfg(target_arch = "wasm32")]
166    {
167        let name = JsObject::string(name);
168        unsafe {
169            quad_url_delete_program_parameter(name.weak());
170        }
171        drop(name);
172    }
173}
174
175/// Set «command line parameters» in URL. Has no effect outside WASM.
176pub fn set_program_parameter(name: &str, value: &str) {
177    #[cfg(target_arch = "wasm32")]
178    {
179        let name = JsObject::string(name);
180        let value = JsObject::string(value);
181        unsafe {
182            quad_url_set_program_parameter(name.weak(), value.weak());
183        }
184        drop(name);
185        drop(value);
186    }
187}
188
189/// Returns string after hash in URL. Returns empty string on non-WASM target.
190pub fn get_hash() -> String {
191    #[cfg(target_arch = "wasm32")]
192    {
193        let mut value = String::new();
194        unsafe {
195            quad_url_get_hash().to_string(&mut value);
196        }
197        value
198    }
199
200    #[cfg(not(target_arch = "wasm32"))]
201    {
202        String::new()
203    }
204}
205
206/// Set string after hash in URL. Has no effect on non-WASM target.
207pub fn set_hash(value: &str) {
208    #[cfg(target_arch = "wasm32")]
209    {
210        let value = JsObject::string(value);
211        unsafe {
212            quad_url_set_hash(value.weak());
213        }
214        drop(value);
215    }
216}
217
218/// If not WASM, then open link in browser. If target is WASM, then link can be opened in the same tab, or in a new tab. But when link is opened in a new tab, browser may block it and ask user permission to do it.
219pub fn link_open(url: &str, new_tab: bool) {
220    #[cfg(target_arch = "wasm32")]
221    {
222        let url = JsObject::string(url);
223        unsafe {
224            quad_url_link_open(url.weak(), new_tab as u32);
225        }
226        drop(url);
227    }
228
229    #[cfg(any(
230        target_os = "linux",
231        target_os = "windows",
232        target_os = "macos",
233        target_os = "android",
234    ))]
235    {
236        if let Err(err) = webbrowser::open(url) {
237            eprintln!("Failed to open url: {}, url: `{}`", err, url);
238        }
239    }
240}