Fix broken diagram links by implementing format-aware image paths
Problem: HTML output contained broken image links because all formats used the same full path (e.g., living-documentation/diagram-536389.png). This worked for PDFs but failed for HTML since both files are in the same directory and need relative paths. Solution: - Add output format detection with isHTMLOutput function - Update processMermaidBlock to take OutputPath parameter - Generate context-appropriate paths: * HTML: relative path (diagram-536389.png) * PDF: full path (living-documentation/diagram-536389.png) - Update transformDocument and compilation functions to pass output path Both HTML and PDF generation now work correctly with proper image embedding. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
1a92427b90
commit
4aab281f4b
42
app/Main.hs
42
app/Main.hs
@ -9,7 +9,7 @@ import Text.Pandoc.PDF (makePDF)
|
|||||||
import Text.Pandoc.Walk (walkM)
|
import Text.Pandoc.Walk (walkM)
|
||||||
import Text.Pandoc.Extensions (getDefaultExtensions)
|
import Text.Pandoc.Extensions (getDefaultExtensions)
|
||||||
import System.Environment (getArgs)
|
import System.Environment (getArgs)
|
||||||
import System.FilePath (replaceExtension, takeDirectory, (</>))
|
import System.FilePath (replaceExtension, takeDirectory, takeFileName, takeExtension, (</>))
|
||||||
import System.Process (callProcess)
|
import System.Process (callProcess)
|
||||||
import System.Directory (removeFile)
|
import System.Directory (removeFile)
|
||||||
import Data.Text (Text)
|
import Data.Text (Text)
|
||||||
@ -52,13 +52,17 @@ generateDiagramId explicitId contents
|
|||||||
| otherwise = DiagramId explicitId
|
| otherwise = DiagramId explicitId
|
||||||
|
|
||||||
-- | Transform Mermaid code blocks into image embeds with resource cleanup
|
-- | Transform Mermaid code blocks into image embeds with resource cleanup
|
||||||
processMermaidBlock :: SourceDir -> Block -> IO Block
|
processMermaidBlock :: SourceDir -> OutputPath -> Block -> IO Block
|
||||||
processMermaidBlock (SourceDir sourceDir) (CodeBlock (id', classes, _) contents)
|
processMermaidBlock (SourceDir sourceDir) (OutputPath outputPath) (CodeBlock (id', classes, _) contents)
|
||||||
| "mermaid" `elem` classes = do
|
| "mermaid" `elem` classes = do
|
||||||
let DiagramId diagId = generateDiagramId id' contents
|
let DiagramId diagId = generateDiagramId id' contents
|
||||||
diagIdStr = T.unpack diagId
|
diagIdStr = T.unpack diagId
|
||||||
mmdFile = sourceDir </> diagIdStr <> ".mmd"
|
mmdFile = sourceDir </> diagIdStr <> ".mmd"
|
||||||
pngFile = sourceDir </> diagIdStr <> ".png"
|
pngFile = sourceDir </> diagIdStr <> ".png"
|
||||||
|
-- Determine the correct image path based on output format
|
||||||
|
imagePath = if isHTMLOutput outputPath
|
||||||
|
then takeFileName pngFile -- Just filename for HTML
|
||||||
|
else pngFile -- Full path for PDF/LaTeX
|
||||||
|
|
||||||
-- Use bracket to ensure cleanup of temporary mermaid file
|
-- Use bracket to ensure cleanup of temporary mermaid file
|
||||||
bracket
|
bracket
|
||||||
@ -67,12 +71,16 @@ processMermaidBlock (SourceDir sourceDir) (CodeBlock (id', classes, _) contents)
|
|||||||
(\_ -> do
|
(\_ -> do
|
||||||
void $ callProcess mermaidCommand ["-i", mmdFile, "-o", pngFile]
|
void $ callProcess mermaidCommand ["-i", mmdFile, "-o", pngFile]
|
||||||
putStrLn $ successEmoji <> " Generated " <> pngFile
|
putStrLn $ successEmoji <> " Generated " <> pngFile
|
||||||
return $ Para [Image nullAttr [] (T.pack pngFile, "Mermaid diagram")])
|
return $ Para [Image nullAttr [] (T.pack imagePath, "Mermaid diagram")])
|
||||||
processMermaidBlock _ block = return block
|
processMermaidBlock _ _ block = return block
|
||||||
|
|
||||||
|
-- | Check if output is HTML format based on file extension
|
||||||
|
isHTMLOutput :: FilePath -> Bool
|
||||||
|
isHTMLOutput path = takeExtension path == ".html"
|
||||||
|
|
||||||
-- | Walk the Pandoc AST and process blocks using walkM
|
-- | Walk the Pandoc AST and process blocks using walkM
|
||||||
transformDocument :: SourceDir -> Pandoc -> IO Pandoc
|
transformDocument :: SourceDir -> OutputPath -> Pandoc -> IO Pandoc
|
||||||
transformDocument sourceDir = walkM (processMermaidBlock sourceDir)
|
transformDocument sourceDir outputPath = walkM (processMermaidBlock sourceDir outputPath)
|
||||||
|
|
||||||
-- | LaTeX template with comprehensive package support
|
-- | LaTeX template with comprehensive package support
|
||||||
latexTemplate :: Text -> Text
|
latexTemplate :: Text -> Text
|
||||||
@ -154,12 +162,12 @@ compileToPDF path = do
|
|||||||
|
|
||||||
-- | Safe PDF compilation with proper error handling
|
-- | Safe PDF compilation with proper error handling
|
||||||
compileToPDFSafe :: SourceDir -> OutputPath -> OutputPath -> IO (Either DocsterError ())
|
compileToPDFSafe :: SourceDir -> OutputPath -> OutputPath -> IO (Either DocsterError ())
|
||||||
compileToPDFSafe sourceDir (OutputPath inputPath) (OutputPath outputPath) = do
|
compileToPDFSafe sourceDir (OutputPath inputPath) outputPath@(OutputPath outputPathStr) = do
|
||||||
content <- TIO.readFile inputPath
|
content <- TIO.readFile inputPath
|
||||||
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
|
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
|
||||||
|
|
||||||
pandoc <- runIOorExplode $ readMarkdown readerOptions content
|
pandoc <- runIOorExplode $ readMarkdown readerOptions content
|
||||||
transformed <- transformDocument sourceDir pandoc
|
transformed <- transformDocument sourceDir outputPath pandoc
|
||||||
|
|
||||||
-- Generate LaTeX with proper template
|
-- Generate LaTeX with proper template
|
||||||
latexOutput <- runIOorExplode $ writeLaTeX def transformed
|
latexOutput <- runIOorExplode $ writeLaTeX def transformed
|
||||||
@ -169,8 +177,8 @@ compileToPDFSafe sourceDir (OutputPath inputPath) (OutputPath outputPath) = do
|
|||||||
case result of
|
case result of
|
||||||
Left err -> return $ Left $ PDFGenerationError $ T.pack $ show err
|
Left err -> return $ Left $ PDFGenerationError $ T.pack $ show err
|
||||||
Right bs -> do
|
Right bs -> do
|
||||||
BL.writeFile outputPath bs
|
BL.writeFile outputPathStr bs
|
||||||
putStrLn $ successEmoji <> " PDF written to " <> outputPath
|
putStrLn $ successEmoji <> " PDF written to " <> outputPathStr
|
||||||
return $ Right ()
|
return $ Right ()
|
||||||
|
|
||||||
-- | Compile markdown to HTML
|
-- | Compile markdown to HTML
|
||||||
@ -186,20 +194,20 @@ compileToHTML path = do
|
|||||||
|
|
||||||
-- | Safe HTML compilation with proper error handling
|
-- | Safe HTML compilation with proper error handling
|
||||||
compileToHTMLSafe :: SourceDir -> OutputPath -> OutputPath -> IO (Either DocsterError ())
|
compileToHTMLSafe :: SourceDir -> OutputPath -> OutputPath -> IO (Either DocsterError ())
|
||||||
compileToHTMLSafe sourceDir (OutputPath inputPath) (OutputPath outputPath) = do
|
compileToHTMLSafe sourceDir (OutputPath inputPath) outputPath@(OutputPath outputPathStr) = do
|
||||||
content <- TIO.readFile inputPath
|
content <- TIO.readFile inputPath
|
||||||
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
|
let readerOptions = def { readerExtensions = getDefaultExtensions "markdown" }
|
||||||
|
|
||||||
pandoc <- runIOorExplode $ readMarkdown readerOptions content
|
pandoc <- runIOorExplode $ readMarkdown readerOptions content
|
||||||
transformed <- transformDocument sourceDir pandoc
|
transformed <- transformDocument sourceDir outputPath pandoc
|
||||||
|
|
||||||
html <- runIOorExplode $ writeHtml5String def transformed
|
html <- runIOorExplode $ writeHtml5String def transformed
|
||||||
TIO.writeFile outputPath html
|
TIO.writeFile outputPathStr html
|
||||||
putStrLn $ successEmoji <> " HTML written to " <> outputPath
|
putStrLn $ successEmoji <> " HTML written to " <> outputPathStr
|
||||||
|
|
||||||
-- Open the generated HTML file in browser
|
-- Open the generated HTML file in browser
|
||||||
putStrLn $ "🌐 Opening " <> outputPath <> " in browser for error checking..."
|
putStrLn $ "🌐 Opening " <> outputPathStr <> " in browser for error checking..."
|
||||||
void $ callProcess "open" [outputPath]
|
void $ callProcess "open" [outputPathStr]
|
||||||
|
|
||||||
return $ Right ()
|
return $ Right ()
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user