Function bodies 13 total
App function · typescript · L8-L124 (117 LOC)src/App.tsx
function App() {
const [markdown, setMarkdown] = useState("");
const [isConverting, setIsConverting] = useState(false);
const [progress, setProgress] = useState(0);
const [status, setStatus] = useState("");
const [result, setResult] = useState<{ path: string } | null>(null);
const [error, setError] = useState<string | null>(null);
const handleConvert = async () => {
if (!markdown.trim()) {
setError("请先输入 Markdown 内容");
return;
}
setIsConverting(true);
setProgress(0);
setStatus("正在准备转换...");
setError(null);
setResult(null);
console.log("[App] Starting conversion");
try {
const response = await convertToDocx(markdown, (p, s) => {
setProgress(p);
setStatus(s);
});
console.log("[App] Conversion response:", response);
if (response.success && response.file_path) {
setResult({ path: response.file_path });
setStatus(`转换成功!文件路径:${response.file_path}`);
} else {
DropZone function · typescript · L8-L91 (84 LOC)src/components/DropZone.tsx
export default function DropZone({ onFileLoaded }: DropZoneProps) {
const [isDragging, setIsDragging] = useState(false);
const handleFile = useCallback(
(file: File) => {
if (file.type === "text/markdown" || file.name.endsWith(".md")) {
const reader = new FileReader();
reader.onload = (e) => {
const content = e.target?.result as string;
onFileLoaded(content);
};
reader.readAsText(file);
}
},
[onFileLoaded]
);
const onDragOver = useCallback((e: React.DragEvent) => {
e.preventDefault();
setIsDragging(true);
}, []);
const onDragLeave = useCallback((e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
}, []);
const onDrop = useCallback(
(e: React.DragEvent) => {
e.preventDefault();
setIsDragging(false);
const file = e.dataTransfer.files[0];
if (file) {
handleFile(file);
}
},
[handleFile]
);
const onFileChange = Editor function · typescript · L12-L107 (96 LOC)src/components/Editor.tsx
export default function Editor({ value, onChange }: EditorProps) {
const [previewMode, setPreviewMode] = useState(false);
// Parse markdown with marked and process LaTeX
const html = useMemo(() => {
if (!value) return "";
// Step 1: Extract and protect LaTeX blocks (both $$ and $)
const latexBlocks: string[] = [];
let protectedText = value;
// Extract display math $$...$$ first
protectedText = protectedText.replace(/\$\$([\s\S]+?)\$\$/g, (match, math) => {
const index = latexBlocks.length;
latexBlocks.push({ type: 'display', content: math.trim() });
// Use a placeholder that won't be interpreted by markdown
return `\u0000LATEX_BLOCK_${index}\u0000`;
});
// Extract inline math $...$
protectedText = protectedText.replace(/\$([^$\n]+?)\$/g, (match, math) => {
const index = latexBlocks.length;
latexBlocks.push({ type: 'inline', content: math.trim() });
// Use a placeholder that won't be interpreted by mProgressBar function · typescript · L8-L20 (13 LOC)src/components/ProgressBar.tsx
export default function ProgressBar({ progress, status }: ProgressBarProps) {
return (
<div className="progress-container">
<div className="progress-bar">
<div
className="progress-fill"
style={{ width: `${Math.min(100, Math.max(0, progress))}%` }}
/>
</div>
<p className="progress-status">{status}</p>
</div>
);
}main function · rust · L1-L3 (3 LOC)src-tauri/build.rs
fn main() {
tauri_build::build()
}find_pandoc function · rust · L35-L75 (41 LOC)src-tauri/src/commands/convert.rs
fn find_pandoc(app: &AppHandle) -> Result<PathBuf, String> {
// In development, try system pandoc first
if cfg!(dev) {
if let Ok(output) = Command::new("pandoc").arg("--version").output() {
if output.status.success() {
log::info!("Using system pandoc (dev mode)");
return Ok(PathBuf::from("pandoc"));
}
}
}
// Try to resolve from app resources (production)
let resource_path = app
.path()
.resolve("binaries/pandoc", tauri::path::BaseDirectory::Resource)
.map_err(|e| format!("Failed to resolve resource path: {}", e))?;
if resource_path.exists() {
log::info!("Found pandoc at resource path: {:?}", resource_path);
return Ok(resource_path);
}
// Fallback: try common installation paths
let fallback_paths = [
PathBuf::from("pandoc"), // System PATH
app.path()
.resolve("pandoc", tauri::path::BaseDirectory::Resource)
convert_markdown_to_docx function · rust · L78-L162 (85 LOC)src-tauri/src/commands/convert.rs
pub async fn convert_markdown_to_docx(
app: AppHandle,
request: ConvertRequest,
) -> Result<ConvertResponse, String> {
// Create a temporary file for the markdown input
let temp_dir = std::env::temp_dir();
let md_filename = format!("md2docx_{}.md", uuid::Uuid::new_v4());
let md_path = temp_dir.join(&md_filename);
// Write markdown content to temp file
let mut md_file = fs::File::create(&md_path).map_err(|e| e.to_string())?;
md_file.write_all(request.markdown.as_bytes()).map_err(|e| e.to_string())?;
log::info!("Created temp markdown file: {:?}", md_path);
// Determine output path
let output_path = if let Some(path) = request.output_path {
PathBuf::from(path)
} else {
let docx_filename = format!("md2docx_{}.docx", uuid::Uuid::new_v4());
temp_dir.join(&docx_filename)
};
log::info!("Output path will be: {:?}", output_path);
// Find pandoc - try multiple locations
let pandoc_path = find_pandoc(&apWant fix-PRs on findings? Install Repobility's GitHub App · github.com/apps/repobility-bot
save_file_to_location function · rust · L166-L188 (23 LOC)src-tauri/src/commands/convert.rs
pub async fn save_file_to_location(
_app: AppHandle,
request: SaveFileRequest,
) -> Result<SaveFileResponse, String> {
let source = PathBuf::from(&request.source_path);
let dest = PathBuf::from(&request.destination_path);
if !source.exists() {
return Ok(SaveFileResponse {
success: false,
saved_path: None,
error: Some("Source file does not exist".to_string()),
});
}
fs::copy(&source, &dest).map_err(|e| format!("Failed to copy file: {}", e))?;
Ok(SaveFileResponse {
success: true,
saved_path: Some(dest.to_string_lossy().to_string()),
error: None,
})
}test_find_pandoc_exists function · rust · L195-L199 (5 LOC)src-tauri/src/commands/convert.rs
fn test_find_pandoc_exists() {
// Test that pandoc is available on the system
let result = Command::new("pandoc").arg("--version").output();
assert!(result.is_ok(), "Pandoc should be available on the system");
}run function · rust · L6-L18 (13 LOC)src-tauri/src/lib.rs
pub fn run() {
tauri::Builder::default()
.plugin(tauri_plugin_opener::init())
.plugin(tauri_plugin_dialog::init())
.plugin(tauri_plugin_fs::init())
.plugin(tauri_plugin_process::init())
.invoke_handler(tauri::generate_handler![
convert_markdown_to_docx,
save_file_to_location
])
.run(tauri::generate_context!())
.expect("error while running tauri application");
}main function · rust · L3-L6 (4 LOC)src-tauri/src/main.rs
fn main() {
tauri_app_lib::run()
}convertToDocx function · typescript · L15-L46 (32 LOC)src/utils/convert.ts
export async function convertToDocx(
markdown: string,
onProgress?: (progress: number, status: string) => void
): Promise<ConvertResponse> {
try {
onProgress?.(10, "正在准备转换...");
console.log("[convert] Starting conversion with markdown length:", markdown.length);
// Call the Tauri command
onProgress?.(30, "正在调用 Pandoc 转换...");
console.log("[convert] Invoking convert_markdown_to_docx command");
const result = await invoke<ConvertResponse>("convert_markdown_to_docx", {
request: {
markdown,
output_path: null,
},
});
console.log("[convert] Raw result:", result);
onProgress?.(100, "转换完成!");
return result;
} catch (error) {
console.error("[convert] Error during conversion:", error);
return {
success: false,
file_path: null,
error: error instanceof Error ? error.message : String(error),
};
}
}saveFileToPath function · typescript · L48-L72 (25 LOC)src/utils/convert.ts
export async function saveFileToPath(
sourcePath: string,
destinationPath: string
): Promise<SaveFileResponse> {
try {
console.log("[save] Copying file from", sourcePath, "to", destinationPath);
const result = await invoke<SaveFileResponse>("save_file_to_location", {
request: {
source_path: sourcePath,
destination_path: destinationPath,
},
});
console.log("[save] Save result:", result);
return result;
} catch (error) {
console.error("[save] Error saving file:", error);
return {
success: false,
saved_path: null,
error: error instanceof Error ? error.message : String(error),
};
}
}