diff --git a/src/app/browser/window/tab/item/page.rs b/src/app/browser/window/tab/item/page.rs index 13516fb2..f26d8341 100644 --- a/src/app/browser/window/tab/item/page.rs +++ b/src/app/browser/window/tab/item/page.rs @@ -26,10 +26,7 @@ use gtk::{ gdk::Texture, gdk_pixbuf::Pixbuf, gio::SocketClientEvent, - glib::{ - gformat, GString, Priority, Regex, RegexCompileFlags, RegexMatchFlags, Uri, UriFlags, - UriHideFlags, - }, + glib::{gformat, GString, Priority, Uri, UriFlags, UriHideFlags}, prelude::{EditableExt, FileExt, SocketClientExt, WidgetExt}, }; use sqlite::Transaction; @@ -225,41 +222,15 @@ impl Page { } } Request::Search(ref query) => { - // Try interpret URI manually - if Regex::match_simple( - r"^[^\/\s]+\.[\w]{2,}", - query, - RegexCompileFlags::DEFAULT, - RegexMatchFlags::DEFAULT, - ) { - // Seems request contain some host, try append default scheme - // * make sure new request conversable to valid URI - match Uri::parse(&format!("gemini://{query}"), UriFlags::NONE) { - Ok(uri) => { - // Update navigation entry - self.navigation - .request - .widget - .entry - .set_text(&uri.to_string()); - - // Load page (without history record) - self.load(false); - } - Err(_) => { - // @TODO any action here? - } - } - } else { - // Plain text given, make search request to default provider + // try autocomplete scheme prefix @TODO optional resolve timeout + if self.navigation.request.to_gemini(500).is_none() { + // make search request to default provider @TODO optional self.navigation.request.widget.entry.set_text(&format!( "gemini://tlgs.one/search?{}", Uri::escape_string(query, None, false) )); - - // Load page (without history record) - self.load(false); } + self.load(true) } }; } diff --git a/src/app/browser/window/tab/item/page/navigation/request.rs b/src/app/browser/window/tab/item/page/navigation/request.rs index ed47b292..54a8cfc0 100644 --- a/src/app/browser/window/tab/item/page/navigation/request.rs +++ b/src/app/browser/window/tab/item/page/navigation/request.rs @@ -5,8 +5,9 @@ use widget::Widget; use crate::app::browser::{window::tab::item::Action as TabAction, Action as BrowserAction}; use gtk::{ + gio::{Cancellable, NetworkAddress, Resolver}, glib::{gformat, GString, Uri, UriFlags}, - prelude::EditableExt, + prelude::{EditableExt, NetworkAddressExt, ResolverExt}, }; use sqlite::Transaction; use std::rc::Rc; @@ -98,6 +99,13 @@ impl Request { self.widget.entry.set_text(&self.source()); } + pub fn to_gemini(&self, resolver_timeout: u32) -> Option { + self.gemini(resolver_timeout).and_then(|url| { + self.widget.entry.set_text(&url); + Some(url) + }) + } + // Getters pub fn uri(&self) -> Option { @@ -118,6 +126,14 @@ impl Request { text = postfix.into() }; + if let Some(postfix) = text.strip_prefix("file://") { + text = postfix.into() + }; + + if let Some(postfix) = text.strip_prefix("gemini://") { + text = postfix.into() + }; + text } @@ -128,6 +144,28 @@ impl Request { pub fn source(&self) -> GString { gformat!("source:{}", self.strip_prefix()) } + + pub fn gemini(&self, resolver_timeout: u32) -> Option { + // suggest scheme + let url = gformat!("gemini://{}", self.strip_prefix().trim()); + + // setup default resolver + // * wanted to detect value contain **resolvable** hostname + let resolver = Resolver::default(); + resolver.set_timeout(resolver_timeout); + + // is connectable + if let Ok(connectable) = NetworkAddress::parse_uri(&url, 1965) { + // is resolvable @TODO async + if resolver + .lookup_by_name(&connectable.hostname(), Cancellable::NONE) + .is_ok() + { + return Some(url); + } + } + None + } } // Tools