@@ -16,6 +16,7 @@ use gtk::TemplateChild;
1616use log:: { debug, error, info} ;
1717use once_cell:: sync:: Lazy ;
1818use std:: cell:: RefCell ;
19+ use std:: collections:: HashMap ;
1920use std:: marker:: PhantomData ;
2021use std:: pin:: Pin ;
2122use 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