Skip to content

Commit 5258ef2

Browse files
committed
Store links in a HashMap inside the tab
1 parent dc82f88 commit 5258ef2

File tree

2 files changed

+39
-53
lines changed

2 files changed

+39
-53
lines changed

src/text_extensions/gemini.rs

Lines changed: 9 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -87,9 +87,8 @@ impl Gemini {
8787
.or(default_config.fonts.paragraph.as_ref())
8888
.unwrap(),
8989
);
90-
90+
tag_a.set_line_height(1.4);
9191
tag_a.set_foreground(Some("blue"));
92-
tag_a.set_underline(gtk::pango::Underline::Low);
9392

9493
let tag_pre = Self::create_tag(
9594
"pre",
@@ -170,55 +169,23 @@ impl Gemini {
170169
pub fn insert_link(
171170
&mut self,
172171
text_iter: &mut gtk::TextIter,
173-
link: String,
172+
link: &str,
174173
label: Option<&str>,
175-
) {
174+
) -> gtk::TextTag {
176175
let start = text_iter.offset();
177-
let default_config = &config::DEFAULT_CONFIG;
178-
179-
let config = self
180-
.config
181-
.fonts
182-
.paragraph
183-
.as_ref()
184-
.or(default_config.fonts.paragraph.as_ref())
185-
.unwrap();
186-
187-
let tag = gtk::builders::TextTagBuilder::new()
188-
.family(&config.family)
189-
.weight(config.weight)
190-
.line_height(1.4)
191-
.build();
192-
193-
tag.set_foreground_rgba(
194-
self.text_view
195-
.style_context()
196-
.lookup_color("accent_color")
197-
.as_ref(),
198-
);
199176

200-
Self::set_linkhandler(&tag, link.clone());
177+
let tag = gtk::TextTag::new(None);
178+
self.text_buffer.tag_table().add(&tag);
201179

202-
let label = label.unwrap_or(&link);
180+
let label = label.unwrap_or(link);
203181
self.insert_paragraph(text_iter, label);
204182
self.insert_paragraph(text_iter, "\n");
205183

206-
let tag_table = self.text_buffer.tag_table();
207-
tag_table.add(&tag);
208-
209184
self.text_buffer
210185
.apply_tag(&tag, &self.text_buffer.iter_at_offset(start), text_iter);
211-
}
212-
fn set_linkhandler(tag: &gtk::TextTag, l: String) {
213-
unsafe {
214-
tag.set_data("linkhandler", l);
215-
}
216-
}
217-
pub fn linkhandler(tag: &gtk::TextTag) -> Option<&String> {
218-
unsafe {
219-
let handler: Option<std::ptr::NonNull<String>> = tag.data("linkhandler");
220-
handler.map(|n| n.as_ref())
221-
}
186+
self.text_buffer
187+
.apply_tag_by_name("a", &self.text_buffer.iter_at_offset(start), text_iter);
188+
tag
222189
}
223190
pub fn clear(&mut self) {
224191
let b = &self.text_buffer;

src/widgets/tab.rs

Lines changed: 30 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,7 @@ use gtk::TemplateChild;
1616
use log::{debug, error, info};
1717
use once_cell::sync::Lazy;
1818
use std::cell::RefCell;
19+
use std::collections::HashMap;
1920
use std::marker::PhantomData;
2021
use std::pin::Pin;
2122
use std::rc::Rc;
@@ -64,6 +65,7 @@ pub mod imp {
6465
pub(crate) right_click_ctrl: RefCell<Option<gtk::GestureClick>>,
6566
pub(crate) motion_ctrl: RefCell<Option<gtk::EventControllerMotion>>,
6667
pub(crate) req_handle: RefCell<Option<RemoteHandle<()>>>,
68+
pub(crate) links: RefCell<HashMap<gtk::TextTag, String>>,
6769
#[property(get = Self::history_status, builder(HistoryStatus::static_type()))]
6870
pub(crate) history_status: PhantomData<HistoryStatus>,
6971
#[property(get, set)]
@@ -175,8 +177,12 @@ impl Tab {
175177
if has_selection {
176178
return Ok(());
177179
}
178-
let link = Self::extract_linkhandler(gemini_text_ext.as_ref().unwrap(), x, y)?;
179-
let url = self.parse_link(&link)?;
180+
let url = {
181+
let links = imp.links.borrow();
182+
let (_, link) =
183+
Self::extract_linkhandler(&*links, gemini_text_ext.as_ref().unwrap(), x, y)?;
184+
self.parse_link(&link)?
185+
};
180186
if ctrl
181187
.current_event()
182188
.unwrap()
@@ -195,8 +201,13 @@ impl Tab {
195201
let imp = self.imp();
196202
let gemini_text_ext = imp.gemini_text_ext.borrow();
197203
let text_view = &gemini_text_ext.as_ref().unwrap().text_view;
198-
let link = Self::extract_linkhandler(gemini_text_ext.as_ref().unwrap(), x, y)?;
199-
let link = self.parse_link(&link)?;
204+
205+
let link = {
206+
let links = imp.links.borrow();
207+
let (_, link) =
208+
Self::extract_linkhandler(&*links, gemini_text_ext.as_ref().unwrap(), x, y)?;
209+
self.parse_link(&link)?
210+
};
200211
let link_variant = link.as_str().to_variant();
201212

202213
let menu = gio::Menu::new();
@@ -215,9 +226,10 @@ impl Tab {
215226
let imp = self.imp();
216227
let gemini_text_ext = imp.gemini_text_ext.borrow();
217228
let gemini_text_ext = gemini_text_ext.as_ref().unwrap();
218-
let link = Self::extract_linkhandler(gemini_text_ext, x, y);
229+
let links = imp.links.borrow();
230+
let entry = Self::extract_linkhandler(&*links, gemini_text_ext, x, y);
219231

220-
let link_ref = link.as_ref().map(|x| x.as_ref()).unwrap_or("");
232+
let link_ref = entry.as_ref().map(|x| x.1).unwrap_or("");
221233

222234
// May need optimization. Comparing two strings for each motion event is expensive
223235
if *imp.hover_url.borrow() != link_ref {
@@ -231,7 +243,7 @@ impl Tab {
231243
.set_cursor_from_name(Some("pointer"));
232244
}
233245
}
234-
imp.hover_url.replace(link.unwrap_or_default());
246+
imp.hover_url.replace(link_ref.to_owned());
235247
self.notify("hover-url");
236248
}
237249

@@ -283,6 +295,7 @@ impl Tab {
283295
fn spawn_request(&self, fut: impl Future<Output = ()> + 'static) {
284296
let imp = self.imp();
285297
self.clear_stack_widgets();
298+
imp.links.borrow_mut().clear();
286299
imp.req_handle
287300
.replace(Some(glibctx().spawn_local_with_handle(fut).unwrap()));
288301
}
@@ -430,7 +443,12 @@ impl Tab {
430443
}),
431444
);
432445
}
433-
fn extract_linkhandler(gemini_text_ext: &GeminiTextExt, x: f64, y: f64) -> Result<String> {
446+
fn extract_linkhandler<'a>(
447+
m: &'a HashMap<gtk::TextTag, String>,
448+
gemini_text_ext: &GeminiTextExt,
449+
x: f64,
450+
y: f64,
451+
) -> Result<(&'a gtk::TextTag, &'a str)> {
434452
let text_view = &gemini_text_ext.text_view;
435453
let (x, y) =
436454
text_view.window_to_buffer_coords(gtk::TextWindowType::Widget, x as i32, y as i32);
@@ -440,8 +458,8 @@ impl Tab {
440458

441459
iter.tags()
442460
.iter()
443-
.find_map(GeminiTextExt::linkhandler)
444-
.cloned()
461+
.find_map(|x| x.name().is_none().then(|| m.get_key_value(x)).flatten())
462+
.map(|(k, v)| (k, v.as_str()))
445463
.ok_or_else(|| anyhow::Error::msg("Clicked text doesn't have a link tag"))
446464
}
447465
async fn open_file_url(&self, url: Url) -> Result<()> {
@@ -755,7 +773,8 @@ impl Tab {
755773
"⇗"
756774
};
757775
let label = format!("{link_char} {}", label.as_deref().unwrap_or(&url));
758-
gemini_text_ext.insert_link(&mut text_iter, url.clone(), Some(&label));
776+
let tag = gemini_text_ext.insert_link(&mut text_iter, &url, Some(&label));
777+
imp.links.borrow_mut().insert(tag, url.clone());
759778
}
760779
PageElement::Preformatted(_) => unreachable!("handled before"),
761780
}

0 commit comments

Comments
 (0)