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]
30#[cfg(target_arch = "wasm32")]
31extern "C" fn quad_url_crate_version() -> u32 {
32    let major = env!("CARGO_PKG_VERSION_MAJOR").parse::<u32>().unwrap();
33    let minor = env!("CARGO_PKG_VERSION_MINOR").parse::<u32>().unwrap();
34    let patch = env!("CARGO_PKG_VERSION_PATCH").parse::<u32>().unwrap();
35
36    (major << 24) + (minor << 16) + patch
37}
38
39#[cfg(target_arch = "wasm32")]
40extern "C" {
41    fn quad_url_path(full: u32) -> JsObject;
42
43    fn quad_url_param_count() -> i32;
44    fn quad_url_get_key(pos: i32) -> JsObject;
45    fn quad_url_get_value(pos: i32) -> JsObject;
46
47    fn quad_url_delete_program_parameter(name: JsObjectWeak);
48    fn quad_url_set_program_parameter(name: JsObjectWeak, value: JsObjectWeak);
49
50    fn quad_url_get_hash() -> JsObject;
51    fn quad_url_set_hash(value: JsObjectWeak);
52
53    fn quad_url_link_open(url: JsObjectWeak, new_tab: u32);
54}
55
56/// Function to get «command line parameters» from query string in URL.
57///
58/// 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"`.
59///
60/// This works just by replacing key and value in this manner:
61/// * `k=1` → `-k=1`
62/// * `begin` → `--begin`
63/// * `something=spa%20ce` → `--something="spa ce"`
64///
65/// Also, this plugin supports unicode in query.
66///
67/// Notice that one-leters keys in URL treated as single-dash always. So, you can't present `myprog --k=1` in the address.
68///
69/// # Usage with `clap`
70///
71/// ```rust
72/// use quad_url::get_program_parameters;
73///
74/// let app = App::new("myapp");
75///
76/// // ...
77///
78/// let matches = app.get_matches_from_safe_borrow(get_program_parameters().iter());
79/// ```
80pub fn get_program_parameters() -> Vec<String> {
81    #[cfg(target_arch = "wasm32")]
82    {
83        let count = unsafe { quad_url_param_count() };
84        let mut path = String::new();
85        unsafe {
86            quad_url_path(0).to_string(&mut path);
87        }
88        let mut result = vec![path];
89        for i in 0..count {
90            let mut key = String::new();
91            unsafe {
92                quad_url_get_key(i).to_string(&mut key);
93            }
94
95            let mut value = String::new();
96            unsafe {
97                quad_url_get_value(i).to_string(&mut value);
98            }
99
100            let dash = if key.chars().count() == 1 { "-" } else { "--" };
101            if value == "" {
102                result.push(format!("{}{}", dash, key));
103            } else {
104                result.push(format!("{}{}={}", dash, key, &value));
105            }
106        }
107        result
108    }
109
110    #[cfg(not(target_arch = "wasm32"))]
111    {
112        std::env::args().collect()
113    }
114}
115
116/// 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`.
117pub fn path(full: bool) -> String {
118    #[cfg(target_arch = "wasm32")]
119    {
120        let mut path = String::new();
121        unsafe {
122            quad_url_path(full as u32).to_string(&mut path);
123        }
124        path
125    }
126
127    #[cfg(not(target_arch = "wasm32"))]
128    {
129        if full {
130            std::env::args().collect::<Vec<_>>().join(" ")
131        } else {
132            std::env::args().next().unwrap()
133        }
134    }
135}
136
137/// Parses result from `get_program_parameters` returning `(name, value)`.
138///
139/// In case if you don't want to use `clap` to parse this parameters.
140///
141/// Returns `None` when parameter is not started from one or two dashes.
142pub fn easy_parse(param: &str) -> Option<(&str, Option<&str>)> {
143    let skip_len = if param.starts_with("--") {
144        "--".len()
145    } else if param.starts_with('-') {
146        "-".len()
147    } else {
148        return None;
149    };
150
151    if let Some(pos) = param.chars().position(|x| x == '=') {
152        let name = &param[skip_len..pos];
153        let value = &param[pos + '='.len_utf8()..];
154        if value.is_empty() {
155            Some((name, None))
156        } else {
157            Some((name, Some(value)))
158        }
159    } else {
160        Some((&param[skip_len..], None))
161    }
162}
163
164/// Deletes «command line parameters» in URL. Has no effect outside WASM.
165pub fn delete_program_parameter(name: &str) {
166    #[cfg(target_arch = "wasm32")]
167    {
168        let name = JsObject::string(name);
169        unsafe {
170            quad_url_delete_program_parameter(name.weak());
171        }
172        drop(name);
173    }
174}
175
176/// Set «command line parameters» in URL. Has no effect outside WASM.
177pub fn set_program_parameter(name: &str, value: &str) {
178    #[cfg(target_arch = "wasm32")]
179    {
180        let name = JsObject::string(name);
181        let value = JsObject::string(value);
182        unsafe {
183            quad_url_set_program_parameter(name.weak(), value.weak());
184        }
185        drop(name);
186        drop(value);
187    }
188}
189
190/// Returns string after hash in URL. Returns empty string on non-WASM target.
191pub fn get_hash() -> String {
192    #[cfg(target_arch = "wasm32")]
193    {
194        let mut value = String::new();
195        unsafe {
196            quad_url_get_hash().to_string(&mut value);
197        }
198        value
199    }
200
201    #[cfg(not(target_arch = "wasm32"))]
202    {
203        String::new()
204    }
205}
206
207/// Set string after hash in URL. Has no effect on non-WASM target.
208pub fn set_hash(value: &str) {
209    #[cfg(target_arch = "wasm32")]
210    {
211        let value = JsObject::string(value);
212        unsafe {
213            quad_url_set_hash(value.weak());
214        }
215        drop(value);
216    }
217}
218
219/// 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.
220pub fn link_open(url: &str, new_tab: bool) {
221    #[cfg(target_arch = "wasm32")]
222    {
223        let url = JsObject::string(url);
224        unsafe {
225            quad_url_link_open(url.weak(), new_tab as u32);
226        }
227        drop(url);
228    }
229
230    #[cfg(any(
231        target_os = "linux",
232        target_os = "windows",
233        target_os = "macos",
234        target_os = "android",
235    ))]
236    {
237        if let Err(err) = webbrowser::open(url) {
238            eprintln!("Failed to open url: {}, url: `{}`", err, url);
239        }
240    }
241}