fix: TOC anchor navigation - remove anchor text from parsed content
- Fix parse_blocks: after extracting anchor from \\x03..\\x04 markers, remove the anchor text too (was contaminating display text) - When TOC jump occurs, clear pending_anchor to prevent saved position from overriding the TOC navigation on first frame - Add tests for heading with/without anchor parsing
This commit is contained in:
@@ -382,6 +382,7 @@ BgType::Custom(ref path) if !path.is_empty() => {
|
|||||||
if let Some(section) = action.jump_to_section {
|
if let Some(section) = action.jump_to_section {
|
||||||
self.state.current_section = section;
|
self.state.current_section = section;
|
||||||
self.state.current_page = 0;
|
self.state.current_page = 0;
|
||||||
|
self.state.pending_anchor = None;
|
||||||
if let Some(ref anchor) = action.jump_to_anchor {
|
if let Some(ref anchor) = action.jump_to_anchor {
|
||||||
if let Some(ref book) = self.state.book {
|
if let Some(ref book) = self.state.book {
|
||||||
if section < book.sections.len() {
|
if section < book.sections.len() {
|
||||||
|
|||||||
@@ -26,11 +26,14 @@ fn parse_blocks(raw_text: &str) -> Vec<ContentBlock> {
|
|||||||
if let Some(anchor_end) = after_level.find('\x04') {
|
if let Some(anchor_end) = after_level.find('\x04') {
|
||||||
let anchor_str = &after_level[anchor_start + 1..anchor_end];
|
let anchor_str = &after_level[anchor_start + 1..anchor_end];
|
||||||
anchor = Some(anchor_str.to_string());
|
anchor = Some(anchor_str.to_string());
|
||||||
|
// Remove \x03<anchor>\x04 from text to prevent anchor ID contamination
|
||||||
|
let rm_start = pos + 2 + anchor_start;
|
||||||
|
let rm_end = pos + 2 + anchor_end + 1;
|
||||||
|
text.replace_range(rm_start..rm_end, "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
text.drain(pos..pos + 2);
|
text.drain(pos..pos + 2);
|
||||||
}
|
}
|
||||||
text = text.replace(&['\x03', '\x04'][..], "");
|
|
||||||
text = text.replace('\x02', "");
|
text = text.replace('\x02', "");
|
||||||
}
|
}
|
||||||
let text = text.trim().to_string();
|
let text = text.trim().to_string();
|
||||||
@@ -682,4 +685,26 @@ mod tests {
|
|||||||
assert_eq!(blocks[0].text, "段一");
|
assert_eq!(blocks[0].text, "段一");
|
||||||
assert_eq!(blocks[1].text, "段二");
|
assert_eq!(blocks[1].text, "段二");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_blocks_heading_with_anchor() {
|
||||||
|
// \x011\x03toc1\x04Chapter 1\x02 → heading_level=1, anchor="toc1", text="Chapter 1"
|
||||||
|
let blocks = parse_blocks("\x011\x03toc1\x04Chapter 1\x02\n\nbody text");
|
||||||
|
assert_eq!(blocks.len(), 2);
|
||||||
|
assert_eq!(blocks[0].heading_level, 1);
|
||||||
|
assert_eq!(blocks[0].anchor.as_deref(), Some("toc1"));
|
||||||
|
assert_eq!(blocks[0].text, "Chapter 1");
|
||||||
|
assert_eq!(blocks[1].heading_level, 0);
|
||||||
|
assert_eq!(blocks[1].text, "body text");
|
||||||
|
}
|
||||||
|
|
||||||
|
#[test]
|
||||||
|
fn test_parse_blocks_heading_without_anchor() {
|
||||||
|
// \x011Title\x02 → heading_level=1, anchor=None, text="Title"
|
||||||
|
let blocks = parse_blocks("\x011Title\x02");
|
||||||
|
assert_eq!(blocks.len(), 1);
|
||||||
|
assert_eq!(blocks[0].heading_level, 1);
|
||||||
|
assert_eq!(blocks[0].anchor, None);
|
||||||
|
assert_eq!(blocks[0].text, "Title");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user