implement scroll to anchor without page load

This commit is contained in:
yggverse 2026-03-10 03:26:43 +02:00
parent 02bfc90a39
commit 36568004e8

View file

@ -8,7 +8,7 @@ use gtk::{
TextView, TextWindowType, UriLauncher, Window, WrapMode, TextView, TextWindowType, UriLauncher, Window, WrapMode,
gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY, BUTTON_SECONDARY, RGBA}, gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY, BUTTON_SECONDARY, RGBA},
gio::{Cancellable, SimpleAction, SimpleActionGroup}, gio::{Cancellable, SimpleAction, SimpleActionGroup},
glib::{ControlFlow, Uri, idle_add_local, uri_unescape_string, uuid_string_random}, glib::{ControlFlow, GString, Uri, idle_add_local, uri_unescape_string, uuid_string_random},
prelude::{PopoverExt, TextBufferExt, TextTagExt, TextViewExt, WidgetExt}, prelude::{PopoverExt, TextBufferExt, TextTagExt, TextViewExt, WidgetExt},
}; };
use gutter::Gutter; use gutter::Gutter;
@ -203,7 +203,11 @@ impl Markdown {
for tag in iter.tags() { for tag in iter.tags() {
// Tag is link // Tag is link
if let Some(uri) = links.get(&tag) { if let Some(uri) = links.get(&tag) {
return open_link_in_current_tab(&uri.to_string(), &item_action); return if let Some(fragment) = uri.fragment() {
scroll_to_anchor(&text_view, fragment);
} else {
open_link_in_current_tab(&uri.to_string(), &item_action);
};
} }
} }
} }
@ -308,12 +312,23 @@ impl Markdown {
} }
}); // @TODO may be expensive for CPU, add timeout? }); // @TODO may be expensive for CPU, add timeout?
// Anchor auto-scroll behavior (@TODO navigate without page reload) // Anchor auto-scroll behavior
idle_add_local({ idle_add_local({
let base = base.clone(); let base = base.clone();
let text_view = text_view.clone(); let text_view = text_view.clone();
move || { move || {
if let Some(fragment) = base.fragment() { if let Some(fragment) = base.fragment() {
scroll_to_anchor(&text_view, fragment);
}
ControlFlow::Break
}
});
Self { text_view, title }
}
}
fn scroll_to_anchor(text_view: &TextView, fragment: GString) -> bool {
let query = uri_unescape_string(&fragment, None::<&str>) let query = uri_unescape_string(&fragment, None::<&str>)
.unwrap_or(fragment) .unwrap_or(fragment)
.replace("-", " "); .replace("-", " ");
@ -326,18 +341,11 @@ impl Markdown {
.iter() .iter()
.any(|t| t.name().is_some_and(|n| n.starts_with("h"))) .any(|t| t.name().is_some_and(|n| n.starts_with("h")))
{ {
text_view.scroll_to_iter(&mut match_start, 0.0, true, 0.0, 0.0); return text_view.scroll_to_iter(&mut match_start, 0.0, true, 0.0, 0.0);
break;
} }
cursor = match_end; cursor = match_end;
} }
} false
ControlFlow::Break
}
});
Self { text_view, title }
}
} }
fn is_internal_link(request: &str) -> bool { fn is_internal_link(request: &str) -> bool {