summaryrefslogtreecommitdiff
path: root/converter
diff options
context:
space:
mode:
author魏曹先生 <1992414357@qq.com>2026-02-10 17:15:49 +0800
committer魏曹先生 <1992414357@qq.com>2026-02-10 17:16:17 +0800
commit5b40f44e53d8616b15756c623233abf6b2083899 (patch)
tree63cfdaa6661c6aaf690b4b7eb115cb5c5eab9004 /converter
parentef2db26b7309f929282ebd46acf82dc5a87614f8 (diff)
Disable pipeline steps and improve include/image resolution
- Comment out several markdown processing steps for debugging - Enhance `unwrap_includes` to recursively search for included markdown files - Add support for Obsidian image syntax `![[image.png]]` with recursive file search - Implement caching for resolved file paths to improve performance - Search upward and downward from current directory for both includes and images
Diffstat (limited to 'converter')
-rw-r--r--converter/src/parse.rs169
1 files changed, 163 insertions, 6 deletions
diff --git a/converter/src/parse.rs b/converter/src/parse.rs
index f5b0170..292a761 100644
--- a/converter/src/parse.rs
+++ b/converter/src/parse.rs
@@ -29,21 +29,37 @@ pub fn parse(input: PathBuf, ir_output: PathBuf) -> Result<(), Exit> {
pub mod unwrap_includes {
use crate::{error::Exit, utils::path_fmt::format_path};
+ use regex::Regex;
+ use std::collections::HashMap;
use std::path::{Path, PathBuf};
- /// Expand text includes of [[Dialog.md]]
+ /// Expand text includes of [[markdown]] (searches for markdown.md) and image paths
pub fn proc(input: String, self_path: PathBuf) -> Result<String, Exit> {
let mut stack = Vec::<PathBuf>::new();
- expand_recursive(input, &self_path, &mut stack)
+ let mut cache = HashMap::<String, PathBuf>::new();
+ let mut img_cache = HashMap::<String, PathBuf>::new();
+ let root_path = self_path.clone();
+ expand_recursive(
+ input,
+ &self_path,
+ &root_path,
+ &mut stack,
+ &mut cache,
+ &mut img_cache,
+ )
}
fn expand_recursive(
content: String,
current_path: &Path,
+ root_path: &Path,
stack: &mut Vec<PathBuf>,
+ cache: &mut HashMap<String, PathBuf>,
+ img_cache: &mut HashMap<String, PathBuf>,
) -> Result<String, Exit> {
let mut output = String::new();
let mut in_code_block = false;
+ let obsidian_image_re = Regex::new(r"!\[\[([^\]]+)\]\]").unwrap();
let current_norm = format_path(current_path)?;
@@ -67,8 +83,68 @@ pub mod unwrap_includes {
continue;
}
- if let Some(include_path) = extract_include(line) {
- let include_abs = format_path(&current_path.parent().unwrap().join(include_path))?;
+ if let Some(include_name) = extract_include(line) {
+ let include_abs = if let Some(cached_path) = cache.get(include_name) {
+ cached_path.clone()
+ } else {
+ let base_dir = current_path.parent().unwrap();
+ let mut queue = vec![base_dir.to_path_buf()];
+ let mut visited = std::collections::HashSet::new();
+ let mut found_path = None;
+
+ while let Some(dir) = queue.pop() {
+ if visited.contains(&dir) {
+ continue;
+ }
+ visited.insert(dir.clone());
+
+ let candidate1 = dir.join(include_name);
+ if candidate1.exists()
+ && candidate1.extension().map_or(false, |ext| ext == "md")
+ {
+ found_path = Some(format_path(&candidate1)?);
+ break;
+ }
+
+ // Try add .md extension
+ let candidate2 = dir.join(format!("{}.md", include_name));
+ if candidate2.exists() {
+ found_path = Some(format_path(&candidate2)?);
+ break;
+ }
+
+ if let Some(parent) = dir.parent() {
+ queue.push(parent.to_path_buf());
+ }
+
+ if let Ok(entries) = std::fs::read_dir(&dir) {
+ for entry in entries.flatten() {
+ if let Ok(file_type) = entry.file_type() {
+ if file_type.is_dir() {
+ queue.push(entry.path());
+ }
+ }
+ }
+ }
+ }
+
+ match found_path {
+ Some(path) => {
+ cache.insert(include_name.to_string(), path.clone());
+ path
+ }
+ None => {
+ return Err(Exit::FileNotFound(
+ format!(
+ "{} or {}.md (searched from {:?})",
+ include_name, include_name, base_dir
+ )
+ .into(),
+ ));
+ }
+ }
+ };
+
let include_content = std::fs::read_to_string(&include_abs).map_err(|e| {
if e.kind() == std::io::ErrorKind::NotFound {
Exit::FileNotFound(include_abs.clone())
@@ -77,10 +153,91 @@ pub mod unwrap_includes {
}
})?;
- let expanded = expand_recursive(include_content, &include_abs, stack)?;
+ let expanded = expand_recursive(
+ include_content,
+ &include_abs,
+ root_path,
+ stack,
+ cache,
+ img_cache,
+ )?;
output.push_str(&expanded);
} else {
- output.push_str(line);
+ // Process image links
+ let mut processed_line = line.to_string();
+
+ // First process Obsidian image syntax ![[...]]
+ let mut obsidian_matches: Vec<(usize, usize, String)> = Vec::new();
+
+ for caps in obsidian_image_re.captures_iter(line) {
+ let full_match = caps.get(0).unwrap();
+ let image_ref = caps.get(1).unwrap().as_str();
+
+ // Try to get from img_cache first
+ let image_abs = if let Some(cached_path) = img_cache.get(image_ref) {
+ cached_path.clone()
+ } else {
+ // Start search from root directory for Obsidian syntax
+ let root_dir = root_path.parent().unwrap();
+ let mut queue = vec![root_dir.to_path_buf()];
+ let mut visited = std::collections::HashSet::new();
+ let mut found_image_path = None;
+
+ while let Some(dir) = queue.pop() {
+ if visited.contains(&dir) {
+ continue;
+ }
+ visited.insert(dir.clone());
+
+ // Check if file exists in this directory
+ let candidate = dir.join(image_ref);
+ if candidate.exists() {
+ found_image_path = Some(format_path(&candidate)?);
+ break;
+ }
+
+ // Add parent directory to queue (breadth-first upward)
+ if let Some(parent) = dir.parent() {
+ queue.push(parent.to_path_buf());
+ }
+
+ // Add subdirectories to queue (breadth-first downward)
+ if let Ok(entries) = std::fs::read_dir(&dir) {
+ for entry in entries.flatten() {
+ if let Ok(file_type) = entry.file_type() {
+ if file_type.is_dir() {
+ queue.push(entry.path());
+ }
+ }
+ }
+ }
+ }
+
+ match found_image_path {
+ Some(path) => {
+ img_cache.insert(image_ref.to_string(), path.clone());
+ path
+ }
+ None => {
+ // If image not found, keep the original syntax
+ continue;
+ }
+ }
+ };
+
+ // Store the replacement information
+ let start = full_match.start();
+ let end = full_match.end();
+ let new_image_markdown = format!("![]({})", image_abs.display());
+ obsidian_matches.push((start, end, new_image_markdown));
+ }
+
+ // Apply Obsidian replacements in reverse order to maintain correct indices
+ for (start, end, replacement) in obsidian_matches.into_iter().rev() {
+ processed_line.replace_range(start..end, &replacement);
+ }
+
+ output.push_str(&processed_line);
output.push('\n');
}
}