From a0a5a2fb225a4850983d37db4fc4017efa67cebe Mon Sep 17 00:00:00 2001 From: GStudiosX2 Date: Wed, 5 Jun 2024 02:22:04 +0100 Subject: [PATCH 01/19] should fix a few issues --- napture/Cargo.toml | 4 ++-- napture/src/b9/html.rs | 5 +++-- napture/src/main.rs | 2 +- 3 files changed, 6 insertions(+), 5 deletions(-) diff --git a/napture/Cargo.toml b/napture/Cargo.toml index 9da098b7..85990569 100644 --- a/napture/Cargo.toml +++ b/napture/Cargo.toml @@ -6,12 +6,12 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -adw = { version = "0.6.0", package = "libadwaita", features = ["v1_5"] } +adw = { version = "0.6.0", package = "libadwaita", features = ["v1_4"] } base64 = "0.22.1" chrono = "0.4.38" directories = "5.0.1" glib = "0.19.4" -gtk = { version = "0.8.1", package = "gtk4", features = ["v4_14"] } +gtk = { version = "0.8.1", package = "gtk4", features = ["v4_12"] } html-escape = "0.2.13" html_parser = "0.7.0" lazy_static = "1.4.0" diff --git a/napture/src/b9/html.rs b/napture/src/b9/html.rs index e40b2300..46a72ba3 100644 --- a/napture/src/b9/html.rs +++ b/napture/src/b9/html.rs @@ -810,8 +810,9 @@ async fn fetch_file(url: String) -> String { if url.starts_with("file://") { let path = url - .replace("file:///", "") - .replace("file://", ""); + .replace("file://", "") + .replace("/", std::path::MAIN_SEPARATOR_STR) + .trim_start_matches("\\").to_string(); println!("{path}"); diff --git a/napture/src/main.rs b/napture/src/main.rs index e42f1ec4..fee15fbe 100644 --- a/napture/src/main.rs +++ b/napture/src/main.rs @@ -21,7 +21,7 @@ macro_rules! lualog { "[{}] | {} {}\n", now.format("%Y-%m-%d %H:%M:%S"), problem_type, - $s + html_escape::encode_double_quoted_attribute(&$s) ); if let Ok(mut lua_logs) = $crate::globals::LUA_LOGS.lock() { From 98115048178026e4f8f60767eb8da41ff785c49c Mon Sep 17 00:00:00 2001 From: GStudiosX2 Date: Wed, 5 Jun 2024 03:56:55 +0100 Subject: [PATCH 02/19] feat: require now supports relative paths (eg: scripts/module.lua) --- napture/src/b9/css.rs | 12 +-- napture/src/b9/html.rs | 124 ++++++++++++++++-------- napture/src/b9/lua.rs | 171 +++++++++++++++++++--------------- napture/src/b9/mod.rs | 2 +- napture/src/globals.rs | 2 +- napture/src/historymod/imp.rs | 2 +- napture/src/historymod/mod.rs | 7 +- napture/src/imp/mod.rs | 2 - napture/src/main.rs | 61 +++++++----- napture/src/parser/mod.rs | 27 ++++-- 10 files changed, 249 insertions(+), 161 deletions(-) diff --git a/napture/src/b9/css.rs b/napture/src/b9/css.rs index 8db6349f..60154a16 100644 --- a/napture/src/b9/css.rs +++ b/napture/src/b9/css.rs @@ -507,7 +507,7 @@ impl Styleable for gtk::Entry { let width = properties.width; let height = properties.height; - + if width > 0 || height > 0 { let normalized_width = if width > 0 { width } else { -1 }; let normalized_height = if height > 0 { height } else { -1 }; @@ -558,7 +558,7 @@ impl Styleable for gtk::Button { self.set_margin_bottom(properties.margin_bottom.parse::().unwrap_or(0)); self.set_margin_start(properties.margin_left.parse::().unwrap_or(0)); self.set_margin_end(properties.margin_right.parse::().unwrap_or(0)); - + self.set_opacity(properties.opacity); final_css += &compute_styling(class, &properties); @@ -658,7 +658,7 @@ fn compute_styling(class: GString, properties: &Properties) -> String { if properties.border_style != "none" { borders.push_str(&format!("border-style: {};", properties.border_style)); } - + format!( " .{} {{ @@ -726,8 +726,8 @@ fn get_properties(rules: &[(String, String)]) -> Properties { .parse::() .unwrap_or(0); let opacity = get_rule(rules, "opacity", "1.0") - .parse::() - .unwrap_or(1.0); + .parse::() + .unwrap_or(1.0); Properties { direction, @@ -757,6 +757,6 @@ fn get_properties(rules: &[(String, String)]) -> Properties { padding, gap, font_size, - opacity + opacity, } } diff --git a/napture/src/b9/html.rs b/napture/src/b9/html.rs index 46a72ba3..1212b097 100644 --- a/napture/src/b9/html.rs +++ b/napture/src/b9/html.rs @@ -1,6 +1,6 @@ extern crate html_parser; -use crate::{lualog, Tab, globals::LUA_TIMEOUTS}; +use crate::{globals::LUA_TIMEOUTS, lualog, Tab}; use super::{ css::{self, Styleable}, @@ -31,29 +31,34 @@ async fn parse_html(mut url: String) -> Result<(Node, Node)> { let mut file_name = String::new(); if let Ok(mut uri) = Url::parse(&url) { - let last_seg = { - uri.path_segments() - .map(|seg| seg.last().unwrap_or("")) - .unwrap_or("").to_string() - }; - if let Ok(mut segments) = uri.path_segments_mut() { - if !last_seg.contains(".") { - segments.pop_if_empty(); - segments.push("index.html"); - } else { - if !last_seg.ends_with(".html") { - is_html = false; - } - } - file_name += &last_seg; - } - url = uri.into(); + let last_seg = { + uri.path_segments() + .map(|seg| seg.last().unwrap_or("")) + .unwrap_or("") + .to_string() + }; + if let Ok(mut segments) = uri.path_segments_mut() { + if !last_seg.contains(".") { + segments.pop_if_empty(); + segments.push("index.html"); + } else { + if !last_seg.ends_with(".html") { + is_html = false; + } + } + file_name += &last_seg; + } + url = uri.into(); } let mut html = fetch_file(url).await; if !is_html { - html = format!("{}

{}

", file_name, html_escape::encode_double_quoted_attribute(&html)); + html = format!( + "{}

{}

", + file_name, + html_escape::encode_double_quoted_attribute(&html) + ); } let dom = match !html.is_empty() { @@ -103,13 +108,19 @@ pub async fn build_ui( scroll: Rc>, searchbar: Rc>, ) -> Result<(gtk::Box, CssProvider)> { - let furl = tab.url.split("?").nth(0).unwrap_or(&tab.url).strip_suffix("/").unwrap_or(&tab.url); + let furl = tab + .url + .split("?") + .nth(0) + .unwrap_or(&tab.url) + .strip_suffix("/") + .unwrap_or(&tab.url); css::reset_css(); { let mut timeouts = LUA_TIMEOUTS.lock().unwrap(); - for timeout in timeouts.drain(..) { + for timeout in timeouts.drain(..) { timeout.destroy(); } } @@ -127,7 +138,7 @@ pub async fn build_ui( .build(); let mut css: String = css::reset_css(); - + let (head, body) = match parse_html(furl.to_string()).await { Ok(ok) => ok, Err(e) => { @@ -248,7 +259,12 @@ pub async fn build_ui( Ok((html_view, provider)) } -async fn render_head(element: &Element, contents: Option<&Node>, tab: Rc>, furl: &String) { +async fn render_head( + element: &Element, + contents: Option<&Node>, + tab: Rc>, + furl: &String, +) { match element.name.as_str() { "title" => { if let Some(contents) = contents { @@ -569,7 +585,9 @@ fn render_html( } let dropdown = gtk::DropDown::builder() - .model(>k::StringList::new(&strings.iter().map(|s| &**s).collect::>())) + .model(>k::StringList::new( + &strings.iter().map(|s| &**s).collect::>(), + )) .css_name("select") .css_classes(element.classes.clone()) .halign(gtk::Align::Start) @@ -596,9 +614,14 @@ fn render_html( css.push_str(&textview.style()); - textview - .buffer() - .set_text(&decode_html_entities(element.children.first().unwrap_or(&Node::Text(String::new())).text().unwrap_or(""))); + textview.buffer().set_text(&decode_html_entities( + element + .children + .first() + .unwrap_or(&Node::Text(String::new())) + .text() + .unwrap_or(""), + )); html_view.append(&textview); @@ -610,14 +633,14 @@ fn render_html( } "button" => { let button = gtk::Button::builder() - .label( - &decode_html_entities(element + .label(&decode_html_entities( + element .children .first() .unwrap_or(&Node::Text("".to_owned())) .text() - .unwrap_or("")), - ) + .unwrap_or(""), + )) .css_name("button") .css_classes(element.classes.clone()) .halign(gtk::Align::Start) @@ -659,7 +682,13 @@ fn render_a( }; let link_button = gtk::LinkButton::builder() - .label(&decode_html_entities(el.children.first().unwrap_or(&Node::Text(String::new())).text().unwrap_or(""))) + .label(&decode_html_entities( + el.children + .first() + .unwrap_or(&Node::Text(String::new())) + .text() + .unwrap_or(""), + )) .uri(uri) .css_name("a") .css_classes(el.classes.clone()) @@ -727,7 +756,13 @@ fn render_list( .build(); let label = gtk::Label::builder() - .label(&decode_html_entities(el.children.first().unwrap_or(&Node::Text(String::new())).text().unwrap_or(""))) + .label(&decode_html_entities( + el.children + .first() + .unwrap_or(&Node::Text(String::new())) + .text() + .unwrap_or(""), + )) .css_name("li") .css_classes(el.classes.clone()) .halign(gtk::Align::Start) @@ -812,8 +847,9 @@ async fn fetch_file(url: String) -> String { let path = url .replace("file://", "") .replace("/", std::path::MAIN_SEPARATOR_STR) - .trim_start_matches("\\").to_string(); - + .trim_start_matches("\\") + .to_string(); + println!("{path}"); match fs::read_to_string(&format!("{}", path)) { @@ -857,19 +893,23 @@ async fn fetch_from_github(url: String) -> String { let branch = if url.contains("tree") { url.split('/').nth(6).unwrap_or("main") - } else { "main" }; + } else { + "main" + }; let path = (if url.contains("tree") { url.split('/').skip(7).collect::>() } else { url.split('/').skip(5).collect::>() - }).join("/"); + }) + .join("/"); let url = format!( "https://raw.githubusercontent.com/{}/{}/{}/{}", url.split('/').nth(3).unwrap_or(""), url.split('/').nth(4).unwrap_or(""), - branch, path, + branch, + path, ); let client = match client.build() { @@ -914,7 +954,13 @@ async fn fetch_from_github(url: String) -> String { } } -fn render_p(child: &Node, element: &Element, label_box: >k::Box, css: &mut String, tags: &Rc>>){ +fn render_p( + child: &Node, + element: &Element, + label_box: >k::Box, + css: &mut String, + tags: &Rc>>, +) { let label = gtk::Label::builder() .label(&decode_html_entities(child.text().unwrap_or(""))) .css_name(element.name.as_str()) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index a832971b..1a99b3b8 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -13,7 +13,7 @@ use mlua::{OwnedFunction, Value}; use reqwest::header::{HeaderMap, HeaderName, HeaderValue}; use serde_json::Map; -use crate::{lualog, globals::LUA_TIMEOUTS}; +use crate::{globals::LUA_TIMEOUTS, lualog}; use glib::translate::FromGlib; use glib::SourceId; @@ -46,20 +46,28 @@ fn set_timeout(_lua: &Lua, func: LuaOwnedFunction, ms: u64) -> LuaResult { if let Ok(mut timeouts) = LUA_TIMEOUTS.lock() { if ms == 0 { if let Err(e) = func.call::<_, ()>(()) { - lualog!("error", format!("error calling function in set_timeout: {}", e)); + lualog!( + "error", + format!("error calling function in set_timeout: {}", e) + ); } return Ok(-1); } else { let handle = glib::spawn_future_local(async move { glib::timeout_future(std::time::Duration::from_millis(ms)).await; if let Err(e) = func.call::<_, ()>(()) { - lualog!("error", format!("error calling function in set_timeout: {}", e)); + lualog!( + "error", + format!("error calling function in set_timeout: {}", e) + ); } }); timeouts.push(handle.source().clone()); if let Some(id) = handle.as_raw_source_id() { return Ok(id as i32); - } else { return Ok(-1); } + } else { + return Ok(-1); + } } } Err(LuaError::runtime("couldn't create timeout")) @@ -67,21 +75,15 @@ fn set_timeout(_lua: &Lua, func: LuaOwnedFunction, ms: u64) -> LuaResult { pub(crate) fn clear_timeout(id: i32) -> LuaResult<()> { if id > 0 { - let id = unsafe {SourceId::from_glib(id.try_into().unwrap())}; - if let Some(source) = glib::MainContext::default() - .find_source_by_id(&id) { + let id = unsafe { SourceId::from_glib(id.try_into().unwrap()) }; + if let Some(source) = glib::MainContext::default().find_source_by_id(&id) { source.destroy(); } } Ok(()) } -fn get( - lua: &Lua, - class: String, - tags: Rc>>, - multi: bool -) -> LuaResult> { +fn get(lua: &Lua, class: String, tags: Rc>>, multi: bool) -> LuaResult { let global_table = lua.create_table()?; let tags_ref = tags.borrow(); @@ -121,7 +123,9 @@ fn get( lua.create_function(move |_, label: Option| { let label = if let Some(label) = label { label - } else { "".to_string()}; + } else { + "".to_string() + }; tags2.borrow()[i].widget.set_contents_(label); Ok(()) })?, @@ -231,12 +235,16 @@ fn print(_lua: &Lua, msg: LuaMultiValue) -> LuaResult<()> { } // todo: make this async if shit breaks -pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: String) -> LuaResult<()> { +pub(crate) async fn run( + luacode: String, + tags: Rc>>, + taburl: String, +) -> LuaResult<()> { let lua = Lua::new_with( /*StdLib::COROUTINE | StdLib::STRING | StdLib::TABLE | StdLib::MATH,*/ StdLib::ALL_SAFE, - LuaOptions::new().catch_rust_panics(true) + LuaOptions::new().catch_rust_panics(true), )?; let globals = lua.globals(); @@ -347,8 +355,8 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St lua.to_value(&json) })?; - let json_stringify = lua.create_function(|lua, table: LuaTable| { - match serde_json::to_string(&table) { + let json_stringify = + lua.create_function(|lua, table: LuaTable| match serde_json::to_string(&table) { Ok(value) => Ok(lua.to_value(&value)?), Err(_) => { lualog!( @@ -357,91 +365,102 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St ); Ok(lua.null()) } - } - })?; + })?; let json_parse = lua.create_function(|lua, json: String| { match serde_json::from_str::(&json) { Ok(value) => Ok(lua.to_value(&value)?), Err(_) => { - lualog!( - "error", - format!("Failed to parse JSON. Returning null.") - ); + lualog!("error", format!("Failed to parse JSON. Returning null.")); Ok(lua.null()) } } })?; - let require = lua.create_async_function(|lua, module: String| async move { - if !module.starts_with("http://") && !module.starts_with("https://") { - lualog!("error", "Module argument must be a URL."); - return Ok(lua.null()); - } - - let handle = thread::spawn(move || { - let client = reqwest::blocking::Client::new(); - - let req = client.get(module); + window_table.set("link", taburl.clone())?; + window_table.set("query", query_table)?; - let res = match req.send() { - Ok(res) => res, - Err(e) => { - return format!("Failed to send request: {}", e).into(); + let require = lua.create_async_function(move |lua, module: String| { + let taburl = taburl.clone(); + async move { + if let Ok(mut uri) = url::Url::parse(&taburl) { + let result = if uri.scheme() == "file" { + if let Ok(mut segments) = uri.path_segments_mut() { + segments.pop_if_empty(); + segments.push(&module); + } + + if let Ok(path) = uri.to_file_path() { + if let Ok(contents) = std::fs::read_to_string(path) { + contents + } else { + lualog!("error", format!("file does not exist")); + return Ok(lua.null()); + } + } else { + lualog!("error", format!("invalid file path")); + return Ok(lua.null()); + } + } else { + let handle = thread::spawn(move || { + let client = reqwest::blocking::Client::new(); + let req = client.get(module); + let res = match req.send() { + Ok(res) => res, + Err(e) => { + return format!("Failed to send request: {}", e).into(); + } + }; + + let text = res.text().unwrap_or_default(); + text + }); + + match handle.join() { + Ok(result) => result, + Err(_) => { + lualog!( + "error", + format!("Failed to join request thread at fetch request. Originates from the Lua runtime. Returning null.") + ); + "null".to_string() + } + } + }; + + if let Err(e) = lua.sandbox(true) { + lualog!("error", format!("failed to enable sandbox: {}", e)); + return Err(LuaError::runtime("failed to enable sandbox")); + } else { + let load = lua.load(result); + return load.eval::(); } - }; - - let errcode = Rc::new(RefCell::new(res.status().as_u16())); - - let text = res.text().unwrap_or_default(); - - text - }); - - let result = match handle.join() { - Ok(result) => result, - Err(_) => { - lualog!( - "error", - format!("Failed to join request thread at fetch request. Originates from the Lua runtime. Returning null.") - ); - "null".to_string() } - }; - if let Err(e) = lua.sandbox(true) { - lualog!("error", format!("failed to enable sandbox: {}", e)); - Err(LuaError::runtime("failed to enable sandbox")) - } else { - let load = lua.load(result); - load.eval::() + lualog!("error", "invalid url"); + Ok(lua.null()) } })?; - window_table.set("link", taburl)?; - window_table.set("query", query_table)?; - json_table.set("stringify", json_stringify)?; json_table.set("parse", json_parse)?; globals.set("print", lua.create_function(print)?)?; globals.set( "get", - lua.create_function(move |lua, (class, multiple): (String, Option) | { + lua.create_function(move |lua, (class, multiple): (String, Option)| { get(lua, class, tags.clone(), multiple.unwrap_or(false)) - })? + })?, )?; globals.set( "set_timeout", - lua.create_function(move |lua, (func, ms): (LuaOwnedFunction, u64) | { - set_timeout(lua, func, ms) - })? + lua.create_function(move |lua, (func, ms): (LuaOwnedFunction, u64)| { + set_timeout(lua, func, ms) + })?, )?; globals.set( "clear_timeout", - lua.create_function(move |_lua, id: i32| { - clear_timeout(id) - })? + lua.create_function(move |_lua, id: i32| clear_timeout(id))?, )?; globals.set("fetch", fetchtest)?; globals.set("json", json_table)?; @@ -463,7 +482,7 @@ pub(crate) async fn run(luacode: String, tags: Rc>>, taburl: St ); Err(LuaError::runtime("Failed to run script!")) } - } + } } } @@ -967,7 +986,9 @@ impl Luable for gtk::Picture { self.set_visible(visible); } fn get_source_(&self) -> String { - self.alternative_text().unwrap_or(GString::new()).to_string() + self.alternative_text() + .unwrap_or(GString::new()) + .to_string() } fn set_source_(&self, source: String) { let stream = match crate::b9::html::fetch_image_to_pixbuf(source.clone()) { diff --git a/napture/src/b9/mod.rs b/napture/src/b9/mod.rs index 4398aaa4..e030d2bf 100644 --- a/napture/src/b9/mod.rs +++ b/napture/src/b9/mod.rs @@ -1,3 +1,3 @@ pub(crate) mod css; +pub(crate) mod html; pub(crate) mod lua; -pub(crate) mod html; \ No newline at end of file diff --git a/napture/src/globals.rs b/napture/src/globals.rs index 16284531..3b0bbebc 100644 --- a/napture/src/globals.rs +++ b/napture/src/globals.rs @@ -1,5 +1,5 @@ -use std::sync::{Mutex, Arc}; use glib::Source; +use std::sync::{Arc, Mutex}; use lazy_static::lazy_static; diff --git a/napture/src/historymod/imp.rs b/napture/src/historymod/imp.rs index 439c930c..48d0b88c 100644 --- a/napture/src/historymod/imp.rs +++ b/napture/src/historymod/imp.rs @@ -12,7 +12,7 @@ pub struct HistoryObject { #[property(name = "url", get, set, type = String, member = url)] #[property(name = "position", get, set, type = i32, member = position)] #[property(name = "date", get, set, type = String, member = date)] - history: RefCell + history: RefCell, } #[glib::object_subclass] diff --git a/napture/src/historymod/mod.rs b/napture/src/historymod/mod.rs index 4dfd852b..09e90734 100644 --- a/napture/src/historymod/mod.rs +++ b/napture/src/historymod/mod.rs @@ -57,12 +57,7 @@ impl History { self.items.is_empty() } - pub(crate) fn add_to_history( - &mut self, - url: String, - date: String, - save_to_disk: bool, - ) { + pub(crate) fn add_to_history(&mut self, url: String, date: String, save_to_disk: bool) { while self.items.len() > self.current_position + 1 { self.items.pop_back(); } diff --git a/napture/src/imp/mod.rs b/napture/src/imp/mod.rs index 32cdbd4d..106ff94e 100644 --- a/napture/src/imp/mod.rs +++ b/napture/src/imp/mod.rs @@ -18,14 +18,12 @@ impl ObjectSubclass for Window { impl ObjectImpl for Window { fn constructed(&self) { self.parent_constructed(); - } } impl WidgetImpl for Window {} impl WindowImpl for Window { // Save window state right before the window will be closed fn close_request(&self) -> glib::Propagation { - glib::Propagation::Proceed } } diff --git a/napture/src/main.rs b/napture/src/main.rs index fee15fbe..539883f8 100644 --- a/napture/src/main.rs +++ b/napture/src/main.rs @@ -57,8 +57,8 @@ use historymod::HistoryObject; use globals::APPDATA_PATH; use globals::DNS_SERVER; -use globals::LUA_TIMEOUTS; use globals::LUA_LOGS; +use globals::LUA_TIMEOUTS; use gtk::gdk; use gtk::gdk::Display; use gtk::gio; @@ -184,12 +184,19 @@ fn get_time() -> String { chrono::Utc::now().format("%Y-%m-%d %H:%M:%S").to_string() } -fn build_ui(app: &adw::Application, args: Rc>>, config: Rc>) { +fn build_ui( + app: &adw::Application, + args: Rc>>, + config: Rc>, +) { let history = Rc::new(RefCell::new(History::new())); - let default_url = if let Some(dev_build) = args.borrow().get(1) { // cli + let default_url = if let Some(dev_build) = args.borrow().get(1) { + // cli dev_build.to_string() - } else { DEFAULT_URL.to_string() }; + } else { + DEFAULT_URL.to_string() + }; let default_dns_url = fetch_dns(default_url.clone()); @@ -221,7 +228,7 @@ fn build_ui(app: &adw::Application, args: Rc>>, config: Rc>>, config: Rc>>, config: Rc>>, config: Rc String { "https://{}/domain/{}/{}", DNS_SERVER.lock().unwrap().as_str(), url.split('.').next().unwrap_or(""), - url.split('.').nth(1).unwrap_or("") - .split('/').next().unwrap_or(""), + url.split('.') + .nth(1) + .unwrap_or("") + .split('/') + .next() + .unwrap_or(""), ); let client = match client.build() { @@ -608,8 +622,7 @@ fn fetch_dns(url: String) -> String { let status = response.status(); if let Ok(json) = response.json::() { - let path = url.split_once('/') - .unwrap_or(("", "")).1; + let path = url.split_once('/').unwrap_or(("", "")).1; json.ip + &format!("/{}", path) } else { lualog!( @@ -740,7 +753,11 @@ fn display_settings_page(app: &Rc>) { // set the DNS server to the new value DNS_SERVER.lock().unwrap().clear(); DNS_SERVER.lock().unwrap().push_str(&dns); - set_config(String::from("dns"), serde_json::Value::String(dns.to_string()), false) + set_config( + String::from("dns"), + serde_json::Value::String(dns.to_string()), + false, + ) }); let scroll = gtk::ScrolledWindow::builder().build(); @@ -879,7 +896,8 @@ fn get_config() -> serde_json::Value { let contents = fs::read_to_string(&json_path).expect("Failed to read configuration for theme."); println!("{:?}", json_path); - let json_contents: serde_json::Value = serde_json::from_str(&contents).expect("Failed to parse JSON"); + let json_contents: serde_json::Value = + serde_json::from_str(&contents).expect("Failed to parse JSON"); json_contents } @@ -888,7 +906,8 @@ fn set_config(property: String, value: serde_json::Value, array: bool) { let json_path = PathBuf::from(APPDATA_PATH.lock().unwrap().clone()).join("config.json"); let contents = fs::read_to_string(&json_path).expect("Failed to read configuration for theme."); - let mut json_contents: serde_json::Value = serde_json::from_str(&contents).expect("Failed to parse JSON"); + let mut json_contents: serde_json::Value = + serde_json::from_str(&contents).expect("Failed to parse JSON"); if array { if json_contents[property.clone()].is_array() { @@ -900,7 +919,7 @@ fn set_config(property: String, value: serde_json::Value, array: bool) { if let Ok(updated_json) = serde_json::to_string_pretty(&json_contents) { match fs::write(&json_path, &updated_json) { - Ok(_) => {}, + Ok(_) => {} Err(err) => { eprintln!("ERROR: Failed to save config to disk. Error: {}", err); } diff --git a/napture/src/parser/mod.rs b/napture/src/parser/mod.rs index e9c3722f..3611a631 100644 --- a/napture/src/parser/mod.rs +++ b/napture/src/parser/mod.rs @@ -31,13 +31,18 @@ pub fn parse(input: &str) -> Result>, Pa current_declarations.clear(); } else if line.ends_with('}') { if let Some(selector) = current_selector.take() { - result.entry(selector).and_modify(|val: &mut HashMap| { - for (key, value) in current_declarations.iter() { - val.insert(key.clone(), value.clone()); - } - }).or_insert(current_declarations.clone()); + result + .entry(selector) + .and_modify(|val: &mut HashMap| { + for (key, value) in current_declarations.iter() { + val.insert(key.clone(), value.clone()); + } + }) + .or_insert(current_declarations.clone()); } else { - return Err(ParseError { message: String::from("Closing brace without opening selector") } ); + return Err(ParseError { + message: String::from("Closing brace without opening selector"), + }); } } else { let parts: Vec<&str> = line.split(':').collect(); @@ -46,14 +51,18 @@ pub fn parse(input: &str) -> Result>, Pa let value = parts[1].trim_end_matches(';').trim().to_string(); current_declarations.insert(property, value); } else { - return Err(ParseError { message: String::from("Closing brace without opening selector") } ); + return Err(ParseError { + message: String::from("Closing brace without opening selector"), + }); } } } if current_selector.is_some() { - return Err(ParseError { message: String::from("Closing brace without opening selector") } ); + return Err(ParseError { + message: String::from("Closing brace without opening selector"), + }); } Ok(result) -} \ No newline at end of file +} From 0e080dd1b13c99111b37418ed7b7256aa29ab86d Mon Sep 17 00:00:00 2001 From: GStudiosX2 Date: Wed, 5 Jun 2024 04:58:19 +0100 Subject: [PATCH 03/19] feat: require relative paths should fully work in all cases --- napture/src/b9/html.rs | 12 +++++++----- napture/src/b9/lua.rs | 22 ++++++++++++++++------ 2 files changed, 23 insertions(+), 11 deletions(-) diff --git a/napture/src/b9/html.rs b/napture/src/b9/html.rs index 1212b097..63de6220 100644 --- a/napture/src/b9/html.rs +++ b/napture/src/b9/html.rs @@ -888,9 +888,7 @@ async fn fetch_file(url: String) -> String { } } -async fn fetch_from_github(url: String) -> String { - let client: reqwest::ClientBuilder = reqwest::Client::builder(); - +pub(crate) fn get_github_url(url: String) -> String { let branch = if url.contains("tree") { url.split('/').nth(6).unwrap_or("main") } else { @@ -904,14 +902,18 @@ async fn fetch_from_github(url: String) -> String { }) .join("/"); - let url = format!( + format!( "https://raw.githubusercontent.com/{}/{}/{}/{}", url.split('/').nth(3).unwrap_or(""), url.split('/').nth(4).unwrap_or(""), branch, path, - ); + ) +} +async fn fetch_from_github(url: String) -> String { + let client: reqwest::ClientBuilder = reqwest::Client::builder(); + let url = get_github_url(url); let client = match client.build() { Ok(client) => client, Err(e) => { diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index 1a99b3b8..ed9f2ff0 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -384,12 +384,14 @@ pub(crate) async fn run( let taburl = taburl.clone(); async move { if let Ok(mut uri) = url::Url::parse(&taburl) { - let result = if uri.scheme() == "file" { - if let Ok(mut segments) = uri.path_segments_mut() { - segments.pop_if_empty(); - segments.push(&module); - } + if let Ok(mut segments) = uri.path_segments_mut() { + segments.pop_if_empty(); + segments.extend(&module.split("/").collect::>()); + } + + println!("{}", uri); + let result = if uri.scheme() == "file" { if let Ok(path) = uri.to_file_path() { if let Ok(contents) = std::fs::read_to_string(path) { contents @@ -404,7 +406,15 @@ pub(crate) async fn run( } else { let handle = thread::spawn(move || { let client = reqwest::blocking::Client::new(); - let req = client.get(module); + let req = client.get(if let Ok(_) = url::Url::parse(&module) { + module + } else { + if uri.domain().unwrap_or("").to_lowercase() == "github.com" { + crate::b9::html::get_github_url(uri.to_string()) + } else { + uri.to_string() + } + }); let res = match req.send() { Ok(res) => res, Err(e) => { From f2e981198becc026ecafbad5ea4cf64cc0a55ba3 Mon Sep 17 00:00:00 2001 From: GStudiosX2 Date: Wed, 5 Jun 2024 04:58:36 +0100 Subject: [PATCH 04/19] feat: require relative paths should fully work in all cases --- napture/src/b9/lua.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/napture/src/b9/lua.rs b/napture/src/b9/lua.rs index ed9f2ff0..5b1524b7 100644 --- a/napture/src/b9/lua.rs +++ b/napture/src/b9/lua.rs @@ -389,8 +389,6 @@ pub(crate) async fn run( segments.extend(&module.split("/").collect::>()); } - println!("{}", uri); - let result = if uri.scheme() == "file" { if let Ok(path) = uri.to_file_path() { if let Ok(contents) = std::fs::read_to_string(path) { From 273071f1d494612f84c6e01a706102615b1c9833 Mon Sep 17 00:00:00 2001 From: GStudiosX2 Date: Wed, 5 Jun 2024 23:07:57 +0100 Subject: [PATCH 05/19] add a few more examples and move napture/test to napture/examples/full --- napture/examples/base64_images/index.html | 9 ++++++++ napture/examples/clear_timeout/index.html | 15 +++++++++++++ napture/examples/clear_timeout/script.lua | 26 ++++++++++++++++++++++ napture/{test => examples/full}/index.html | 0 napture/{test => examples/full}/script.lua | 0 napture/{test => examples/full}/styles.css | 0 napture/examples/set_timeout/index.html | 1 - 7 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 napture/examples/base64_images/index.html create mode 100644 napture/examples/clear_timeout/index.html create mode 100644 napture/examples/clear_timeout/script.lua rename napture/{test => examples/full}/index.html (100%) rename napture/{test => examples/full}/script.lua (100%) rename napture/{test => examples/full}/styles.css (100%) diff --git a/napture/examples/base64_images/index.html b/napture/examples/base64_images/index.html new file mode 100644 index 00000000..4ff0b1fa --- /dev/null +++ b/napture/examples/base64_images/index.html @@ -0,0 +1,9 @@ + + + base64_images + + +

base64 images

+ + + diff --git a/napture/examples/clear_timeout/index.html b/napture/examples/clear_timeout/index.html new file mode 100644 index 00000000..9a2ff271 --- /dev/null +++ b/napture/examples/clear_timeout/index.html @@ -0,0 +1,15 @@ + + + clear_timeout +