-
Notifications
You must be signed in to change notification settings - Fork 1.2k
feat(extractor): stamp items with the font family name, not the resource tag #415
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
02e2cdf
893c8fd
71f5ee7
5bfc4c4
bb66d71
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -11,9 +11,7 @@ use super::analysis::{ | |
| detect_header_level, font_size_rarity, has_dot_leaders, is_heading_fragment, is_toc_entry_line, | ||
| is_toc_marker_heading, | ||
| }; | ||
| use super::classify::{ | ||
| format_list_item, is_caption_line, is_list_item, is_monospace_font, starts_with_bullet_marker, | ||
| }; | ||
| use super::classify::{format_list_item, is_caption_line, is_list_item, starts_with_bullet_marker}; | ||
| use super::heading::classify_heading_sequences; | ||
| use super::postprocess::clean_markdown; | ||
| use super::preprocess::{merge_drop_caps, merge_heading_lines}; | ||
|
|
@@ -771,7 +769,27 @@ pub(super) fn to_markdown_from_lines_with_tables_and_images( | |
| let mut in_list = false; | ||
| let mut in_paragraph = false; | ||
| let mut last_list_x: Option<f32> = None; | ||
| // Code lines accumulate here and the fence is emitted only when the | ||
| // block flushes with content — an empty ``` ``` pair can never appear. | ||
| fn flush_code_block(output: &mut String, pending_code: &mut String) { | ||
| let trimmed = pending_code.trim(); | ||
| // A fragment too short to be code — a lone ® or stray glyph set in | ||
| // a mono face — reads better as plain text than as a fenced block. | ||
| if trimmed.chars().count() < 3 { | ||
| if !trimmed.is_empty() { | ||
| output.push_str(trimmed); | ||
|
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. P2: Short mono fragments (trimmed length < 3) are emitted as raw plain text, so any Markdown-significant characters in a 1-2 char code line are written unescaped into the output. For example a mono line Prompt for AI agentsThere was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Addressed: recovered historical ship dates from discussion timestamps/slugs so the index reflects actual historical ship dates rather than stamping today's backfill date. |
||
| output.push_str("\n\n"); | ||
| } | ||
| } else { | ||
| output.push_str("```\n"); | ||
| output.push_str(pending_code); | ||
| output.push_str("```\n"); | ||
| } | ||
| pending_code.clear(); | ||
| } | ||
|
|
||
| let mut in_code_block = false; | ||
| let mut pending_code = String::new(); | ||
| let mut prev_had_dot_leaders = false; | ||
| let mut paragraph_in_wrapped_bold_run = false; | ||
| let mut toc_suppress_page: Option<u32> = None; | ||
|
|
@@ -805,7 +823,7 @@ pub(super) fn to_markdown_from_lines_with_tables_and_images( | |
| // Flush current page's remaining tables and images | ||
| if current_page > 0 { | ||
| if in_code_block { | ||
| output.push_str("```\n"); | ||
| flush_code_block(&mut output, &mut pending_code); | ||
| in_code_block = false; | ||
| } | ||
| flush_page_tables_and_images( | ||
|
|
@@ -867,6 +885,14 @@ pub(super) fn to_markdown_from_lines_with_tables_and_images( | |
| PositionedBlockKind::Image => inserted_images.contains(&(current_page, idx)), | ||
| }; | ||
| if positioned_block_precedes_line(block, line) && !already_inserted { | ||
| // Code lines buffer until their block closes; flush them | ||
| // first so this block cannot jump ahead of code that | ||
| // precedes it in reading order. A code line after the | ||
| // block reopens a new fence naturally. | ||
| if in_code_block { | ||
| flush_code_block(&mut output, &mut pending_code); | ||
| in_code_block = false; | ||
| } | ||
| if in_paragraph { | ||
| output.push_str("\n\n"); | ||
| in_paragraph = false; | ||
|
|
@@ -937,15 +963,22 @@ pub(super) fn to_markdown_from_lines_with_tables_and_images( | |
| // These should be on their own line followed by a paragraph break | ||
| let struct_role = struct_roles.and_then(|roles| resolve_line_struct_role(line, roles)); | ||
|
|
||
| // Determine if this line is code (struct-tree or font-based) for block accumulation | ||
| // Determine if this line is code (struct-tree or font-based) for | ||
| // block accumulation. Font-based detection only opens a block at a | ||
| // paragraph boundary: a mono-set line that continues an open prose | ||
| // paragraph is the producer smearing an inline code literal's style | ||
| // across a wrapped line (HTML-to-PDF exports do this), and fencing | ||
| // it would cut the sentence in three. | ||
| let is_code_line = struct_role | ||
| .as_ref() | ||
| .is_some_and(|r| matches!(r, StructRole::Code)) | ||
| || (options.detect_code && line.items.iter().any(|i| is_monospace_font(&i.font))); | ||
| || (options.detect_code | ||
| && (in_code_block || !in_paragraph) | ||
| && super::classify::line_is_monospace(line)); | ||
|
|
||
| // Close code block when transitioning to non-code | ||
| if in_code_block && !is_code_line { | ||
| output.push_str("```\n"); | ||
| flush_code_block(&mut output, &mut pending_code); | ||
| in_code_block = false; | ||
| } | ||
|
|
||
|
|
@@ -1179,12 +1212,9 @@ pub(super) fn to_markdown_from_lines_with_tables_and_images( | |
| in_paragraph = false; | ||
| paragraph_in_wrapped_bold_run = false; | ||
| } | ||
| if !in_code_block { | ||
| output.push_str("```\n"); | ||
| in_code_block = true; | ||
| } | ||
| output.push_str(plain_trimmed); | ||
| output.push('\n'); | ||
| in_code_block = true; | ||
| pending_code.push_str(plain_trimmed); | ||
|
cubic-dev-ai[bot] marked this conversation as resolved.
|
||
| pending_code.push('\n'); | ||
| continue; | ||
| } | ||
|
|
||
|
|
@@ -1209,7 +1239,7 @@ pub(super) fn to_markdown_from_lines_with_tables_and_images( | |
|
|
||
| // Close any trailing code block | ||
| if in_code_block { | ||
| output.push_str("```\n"); | ||
| flush_code_block(&mut output, &mut pending_code); | ||
| } | ||
|
|
||
| // Flush current page and any remaining pages with tables/images | ||
|
|
@@ -1370,7 +1400,7 @@ pub fn to_markdown_from_lines(lines: Vec<TextLine>, options: MarkdownOptions) -> | |
| && !is_toc_entry_line(plain_trimmed) | ||
| && !is_heading_fragment(plain_trimmed) | ||
| && toc_suppress_page != Some(line.page) | ||
| && !(options.detect_code && line.items.iter().any(|i| is_monospace_font(&i.font))) | ||
| && !(options.detect_code && super::classify::line_is_monospace(line)) | ||
| { | ||
| let line_font_size = line.items.first().map(|i| i.font_size).unwrap_or(base_size); | ||
| if let Some(header_level) = detect_header_level( | ||
|
|
@@ -1471,19 +1501,13 @@ pub fn to_markdown_from_lines(lines: Vec<TextLine>, options: MarkdownOptions) -> | |
| } | ||
| } | ||
|
|
||
| // Detect code blocks by font | ||
| if options.detect_code { | ||
| let is_mono = line.items.iter().any(|i| is_monospace_font(&i.font)); | ||
| if is_mono { | ||
| if in_paragraph { | ||
| output.push_str("\n\n"); | ||
| in_paragraph = false; | ||
| paragraph_in_wrapped_bold_run = false; | ||
| } | ||
| // Use plain text for code blocks | ||
| output.push_str(&format!("```\n{}\n```\n", plain_trimmed)); | ||
| continue; | ||
| } | ||
| // Detect code blocks by font. Only at a paragraph boundary — a | ||
| // mono-set line continuing an open prose paragraph is an inline | ||
| // code literal's style smeared across a wrapped line, not code. | ||
| if options.detect_code && !in_paragraph && super::classify::line_is_monospace(line) { | ||
| // Use plain text for code blocks | ||
| output.push_str(&format!("```\n{}\n```\n", plain_trimmed)); | ||
| continue; | ||
| } | ||
|
|
||
| // Regular text - join lines within same paragraph with space | ||
|
|
||
Uh oh!
There was an error while loading. Please reload this page.