mirror of
https://github.com/YGGverse/Yoda.git
synced 2026-03-31 16:45:27 +00:00
fix buffer tag search by the fragment
This commit is contained in:
parent
a1d9c080d1
commit
6a491751b6
3 changed files with 34 additions and 36 deletions
|
|
@ -4,11 +4,11 @@ mod tags;
|
||||||
use super::{ItemAction, WindowAction};
|
use super::{ItemAction, WindowAction};
|
||||||
use crate::{app::browser::window::action::Position, profile::Profile};
|
use crate::{app::browser::window::action::Position, profile::Profile};
|
||||||
use gtk::{
|
use gtk::{
|
||||||
EventControllerMotion, GestureClick, PopoverMenu, TextBuffer, TextSearchFlags, TextTag,
|
EventControllerMotion, GestureClick, PopoverMenu, TextBuffer, TextTag, TextTagTable, TextView,
|
||||||
TextTagTable, TextView, TextWindowType, UriLauncher, Window, WrapMode,
|
TextWindowType, UriLauncher, Window, WrapMode,
|
||||||
gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY, BUTTON_SECONDARY, Display, RGBA},
|
gdk::{BUTTON_MIDDLE, BUTTON_PRIMARY, BUTTON_SECONDARY, Display, RGBA},
|
||||||
gio::{Cancellable, Menu, SimpleAction, SimpleActionGroup},
|
gio::{Cancellable, Menu, SimpleAction, SimpleActionGroup},
|
||||||
glib::{ControlFlow, GString, Uri, idle_add_local, uri_unescape_string, uuid_string_random},
|
glib::{ControlFlow, GString, Uri, idle_add_local, uuid_string_random},
|
||||||
prelude::{PopoverExt, TextBufferExt, TextTagExt, TextViewExt, WidgetExt},
|
prelude::{PopoverExt, TextBufferExt, TextTagExt, TextViewExt, WidgetExt},
|
||||||
};
|
};
|
||||||
use gutter::Gutter;
|
use gutter::Gutter;
|
||||||
|
|
@ -312,6 +312,7 @@ impl Markdown {
|
||||||
|
|
||||||
// Init events
|
// Init events
|
||||||
primary_button_controller.connect_released({
|
primary_button_controller.connect_released({
|
||||||
|
let headers = headers.clone();
|
||||||
let item_action = item_action.clone();
|
let item_action = item_action.clone();
|
||||||
let links = links.clone();
|
let links = links.clone();
|
||||||
let text_view = text_view.clone();
|
let text_view = text_view.clone();
|
||||||
|
|
@ -327,7 +328,7 @@ impl Markdown {
|
||||||
// Tag is link
|
// Tag is link
|
||||||
if let Some(uri) = links.get(&tag) {
|
if let Some(uri) = links.get(&tag) {
|
||||||
return if let Some(fragment) = uri.fragment() {
|
return if let Some(fragment) = uri.fragment() {
|
||||||
scroll_to_anchor(&text_view, fragment);
|
scroll_to_anchor(&text_view, &headers, fragment);
|
||||||
} else {
|
} else {
|
||||||
open_link_in_current_tab(&uri.to_string(), &item_action);
|
open_link_in_current_tab(&uri.to_string(), &item_action);
|
||||||
};
|
};
|
||||||
|
|
@ -338,10 +339,10 @@ impl Markdown {
|
||||||
});
|
});
|
||||||
|
|
||||||
secondary_button_controller.connect_pressed({
|
secondary_button_controller.connect_pressed({
|
||||||
let links = links.clone();
|
|
||||||
let headers = headers.clone();
|
let headers = headers.clone();
|
||||||
let text_view = text_view.clone();
|
|
||||||
let link_context = link_context.clone();
|
let link_context = link_context.clone();
|
||||||
|
let links = links.clone();
|
||||||
|
let text_view = text_view.clone();
|
||||||
move |_, _, window_x, window_y| {
|
move |_, _, window_x, window_y| {
|
||||||
let x = window_x as i32;
|
let x = window_x as i32;
|
||||||
let y = window_y as i32;
|
let y = window_y as i32;
|
||||||
|
|
@ -518,7 +519,7 @@ impl Markdown {
|
||||||
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);
|
scroll_to_anchor(&text_view, &headers, fragment);
|
||||||
}
|
}
|
||||||
ControlFlow::Break
|
ControlFlow::Break
|
||||||
}
|
}
|
||||||
|
|
@ -528,29 +529,20 @@ impl Markdown {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn scroll_to_anchor(text_view: &TextView, fragment: GString) -> bool {
|
fn scroll_to_anchor(
|
||||||
fn try_scroll(text_view: &TextView, query: &str) -> bool {
|
text_view: &TextView,
|
||||||
let mut cursor = text_view.buffer().start_iter();
|
headers: &HashMap<TextTag, (String, Uri)>,
|
||||||
while let Some((mut match_start, match_end)) =
|
fragment: GString,
|
||||||
cursor.forward_search(query, TextSearchFlags::CASE_INSENSITIVE, None)
|
) {
|
||||||
{
|
if let Some((tag, _)) = headers.iter().find(|(_, (_, uri))| {
|
||||||
if match_start
|
uri.fragment()
|
||||||
.tags()
|
.is_some_and(|f| fragment == tags::format_header_fragment(&f))
|
||||||
.iter()
|
}) {
|
||||||
.any(|t| t.name().is_some_and(|n| n.starts_with("h")))
|
let mut iter = text_view.buffer().start_iter();
|
||||||
{
|
if iter.starts_tag(Some(tag)) || iter.forward_to_tag_toggle(Some(tag)) {
|
||||||
return text_view.scroll_to_iter(&mut match_start, 0.0, true, 0.0, 0.0);
|
text_view.scroll_to_iter(&mut iter, 0.0, true, 0.0, 0.0);
|
||||||
}
|
}
|
||||||
cursor = match_end;
|
|
||||||
}
|
}
|
||||||
false
|
|
||||||
}
|
|
||||||
let query = uri_unescape_string(&fragment, None::<&str>).unwrap_or(fragment);
|
|
||||||
let result = try_scroll(text_view, &query); // exact match
|
|
||||||
if !result {
|
|
||||||
return try_scroll(text_view, &query.replace(" ", "-")); // alt syntax
|
|
||||||
}
|
|
||||||
result
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn is_internal_link(request: &str) -> bool {
|
fn is_internal_link(request: &str) -> bool {
|
||||||
|
|
|
||||||
|
|
@ -10,7 +10,12 @@ mod underline;
|
||||||
|
|
||||||
use bold::Bold;
|
use bold::Bold;
|
||||||
use code::Code;
|
use code::Code;
|
||||||
use gtk::{TextBuffer, TextSearchFlags, TextTag, gdk::RGBA, glib::Uri, prelude::TextBufferExt};
|
use gtk::{
|
||||||
|
TextBuffer, TextSearchFlags, TextTag,
|
||||||
|
gdk::RGBA,
|
||||||
|
glib::{GString, Uri},
|
||||||
|
prelude::TextBufferExt,
|
||||||
|
};
|
||||||
use header::Header;
|
use header::Header;
|
||||||
use pre::Pre;
|
use pre::Pre;
|
||||||
use quote::Quote;
|
use quote::Quote;
|
||||||
|
|
@ -99,4 +104,9 @@ impl Tags {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Shared URL #fragment logic (for the Header tags ref)
|
||||||
|
pub fn format_header_fragment(value: &str) -> GString {
|
||||||
|
Uri::escape_string(&value.to_lowercase().replace(" ", "-"), None, true)
|
||||||
|
}
|
||||||
|
|
||||||
const ESC: &str = "\\";
|
const ESC: &str = "\\";
|
||||||
|
|
|
||||||
|
|
@ -126,8 +126,8 @@ impl Header {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create unique phantom tag for each header
|
// Create unique phantom tag for each header
|
||||||
// * it is required for context menu relationships
|
// * for the #fragment references implementation
|
||||||
let h = TextTag::builder().build();
|
let h = TextTag::new(Some(&format!("h{}", gtk::glib::uuid_string_random())));
|
||||||
assert!(table.add(&h));
|
assert!(table.add(&h));
|
||||||
|
|
||||||
// Render header in text buffer
|
// Render header in text buffer
|
||||||
|
|
@ -158,11 +158,7 @@ impl Header {
|
||||||
base.port(),
|
base.port(),
|
||||||
&base.path(),
|
&base.path(),
|
||||||
base.query().as_deref(),
|
base.query().as_deref(),
|
||||||
Some(&Uri::escape_string(
|
Some(&super::format_header_fragment(&cap["title"])),
|
||||||
&cap["title"].to_lowercase().replace(" ", "-"),
|
|
||||||
None,
|
|
||||||
true
|
|
||||||
)),
|
|
||||||
)
|
)
|
||||||
),
|
),
|
||||||
)
|
)
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue