Replace makePDF with direct XeLaTeX processing to eliminate API mismatch
- Remove Text.Pandoc.PDF dependency and dummy Pandoc document - Add direct xelatex invocation with temporary file handling - Improve error reporting with LaTeX log file parsing - Add temporary package dependency for proper temp file cleanup - Maintain same external API while cleaning internal architecture - Eliminate architectural mismatch between our pipeline and Pandoc's expectations The previous code used makePDF in a way that fought against its intended usage, requiring a dummy Pandoc document. Now we directly call xelatex after our custom LaTeX template processing, creating a cleaner separation of concerns. 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <noreply@anthropic.com>
This commit is contained in:
parent
303f347243
commit
bf6f82abe5
@ -42,7 +42,8 @@ library
|
||||
hashable >=1.4 && <1.6,
|
||||
pandoc >=3.0 && <3.2,
|
||||
pandoc-types >=1.23 && <1.25,
|
||||
bytestring >=0.11 && <0.13
|
||||
bytestring >=0.11 && <0.13,
|
||||
temporary >=1.3 && <1.4
|
||||
default-language: Haskell2010
|
||||
|
||||
executable docster
|
||||
|
@ -12,13 +12,14 @@ import Docster.Types
|
||||
import Docster.Transform (transformDocument)
|
||||
import Docster.LaTeX (latexTemplate)
|
||||
import Text.Pandoc
|
||||
import Text.Pandoc.PDF (makePDF)
|
||||
import Data.Text (Text)
|
||||
import qualified Data.Text as T
|
||||
import qualified Data.Text.IO as TIO
|
||||
import qualified Data.ByteString.Lazy as BL
|
||||
import System.FilePath (takeDirectory, replaceExtension)
|
||||
import System.Process (callProcess)
|
||||
import System.FilePath (takeDirectory, replaceExtension, (</>))
|
||||
import System.Process (callProcess, readProcessWithExitCode)
|
||||
import System.IO.Temp (withSystemTempDirectory)
|
||||
import System.Directory (copyFile, doesFileExist)
|
||||
import System.Exit (ExitCode(..))
|
||||
import Control.Exception (throwIO)
|
||||
import Control.Monad (void)
|
||||
|
||||
@ -56,20 +57,53 @@ htmlStrategy = CompilationStrategy
|
||||
, csSuccessMessage = \path -> successEmoji <> " HTML written to " <> T.pack path
|
||||
}
|
||||
|
||||
-- | Process PDF output: LaTeX template application and PDF generation
|
||||
-- | Process PDF output: LaTeX template application and direct XeLaTeX compilation
|
||||
processPDFOutput :: Text -> String -> IO (Either DocsterError ())
|
||||
processPDFOutput latexOutput outputPath = do
|
||||
let completeLatex = latexTemplate latexOutput
|
||||
-- We need a Pandoc document for makePDF, but it's not used in the template function
|
||||
-- Create a minimal document for the API
|
||||
let dummyDoc = Pandoc nullMeta []
|
||||
pdfResult <- runIO $ makePDF "xelatex" [] (\_ _ -> return completeLatex) def dummyDoc
|
||||
case pdfResult of
|
||||
Left err -> return $ Left $ PDFGenerationError $ T.pack $ show err
|
||||
Right (Left err) -> return $ Left $ PDFGenerationError $ T.pack $ show err
|
||||
Right (Right bs) -> do
|
||||
BL.writeFile outputPath bs
|
||||
return $ Right ()
|
||||
|
||||
-- Use temporary directory for LaTeX compilation
|
||||
withSystemTempDirectory "docster-latex" $ \tempDir -> do
|
||||
let texFile = tempDir </> "document.tex"
|
||||
pdfFile = tempDir </> "document.pdf"
|
||||
logFile = tempDir </> "document.log"
|
||||
|
||||
-- Write LaTeX content to temporary file
|
||||
TIO.writeFile texFile completeLatex
|
||||
|
||||
-- Run XeLaTeX compilation
|
||||
(exitCode, _stdout, stderr) <- readProcessWithExitCode "xelatex"
|
||||
[ "-output-directory=" <> tempDir
|
||||
, "-interaction=nonstopmode" -- Don't stop on errors
|
||||
, texFile
|
||||
] ""
|
||||
|
||||
case exitCode of
|
||||
ExitSuccess -> do
|
||||
-- Check if PDF was actually generated
|
||||
pdfExists <- doesFileExist pdfFile
|
||||
if pdfExists
|
||||
then do
|
||||
-- Copy the generated PDF to the final location
|
||||
copyFile pdfFile outputPath
|
||||
return $ Right ()
|
||||
else do
|
||||
-- PDF generation failed, read log for details
|
||||
logExists <- doesFileExist logFile
|
||||
logContent <- if logExists
|
||||
then TIO.readFile logFile
|
||||
else return "No log file generated"
|
||||
return $ Left $ PDFGenerationError $
|
||||
"PDF file not generated. LaTeX log:\n" <> logContent
|
||||
ExitFailure code -> do
|
||||
-- LaTeX compilation failed, read log for details
|
||||
logExists <- doesFileExist logFile
|
||||
logContent <- if logExists
|
||||
then TIO.readFile logFile
|
||||
else return (T.pack stderr)
|
||||
return $ Left $ PDFGenerationError $
|
||||
"XeLaTeX compilation failed (exit code " <> T.pack (show code) <> "):\n" <>
|
||||
T.pack stderr <> "\n\nLaTeX log:\n" <> logContent
|
||||
|
||||
-- | Process HTML output: file writing and browser opening
|
||||
processHTMLOutput :: Text -> String -> IO (Either DocsterError ())
|
||||
|
Loading…
x
Reference in New Issue
Block a user