replace static regex condition with resolvable hostname detection, add gemini/to_gemini api

This commit is contained in:
yggverse 2024-12-12 19:07:04 +02:00
parent 9411208c74
commit 325d5505d7
2 changed files with 44 additions and 35 deletions

View File

@ -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)
}
};
}

View File

@ -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<GString> {
self.gemini(resolver_timeout).and_then(|url| {
self.widget.entry.set_text(&url);
Some(url)
})
}
// Getters
pub fn uri(&self) -> Option<Uri> {
@ -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<GString> {
// 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