Skip to content

Commit

Permalink
Mise à jour de ThatLatexLib.
Browse files Browse the repository at this point in the history
  • Loading branch information
Skyost committed Nov 27, 2024
1 parent c7fe8ee commit b38ca22
Show file tree
Hide file tree
Showing 5 changed files with 7,896 additions and 8,342 deletions.
80 changes: 29 additions & 51 deletions modules/latex-pdf-generator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ import path from 'path'
import AdmZip from 'adm-zip'
import { Octokit } from '@octokit/core'
import { createResolver, defineNuxtModule, type Resolver, useLogger } from '@nuxt/kit'
import * as latex from 'that-latex-lib'
import { LatexChecksumsCalculator, LatexIncludeCommand, PdfGenerator } from 'that-latex-lib'
import { getFileName } from '../utils/utils'
import { type GithubRepository, siteMeta } from '../site/meta'
import { latexOptions, type LatexGenerateOptions } from '../site/latex'
Expand Down Expand Up @@ -250,80 +250,58 @@ const generatePdf = (
logger.info(`Processing "${filePath}"...`)

// Generate PDF and checksums files.
const { wasCached, builtFilePath, checksumsFilePath } = latex.generatePdf(
filePath,
{
includeGraphicsDirectories: options.getIncludeGraphicsDirectories(texDirectoryRelativePath),
cacheDirectoryPath: previousBuildDirectory == null ? undefined : previousBuildDirectory,
generateIfExists: !debug,
checksumsCalculator: (texFilePath, includeGraphicsDirectories) => latex.calculateTexFileChecksums(
texFilePath,
includeGraphicsDirectories,
null,
[
...latex.defaultLatexIncludeCommands,
// inputcontent command for other LaTeX files.
{
command: 'inputcontent',
directories: [],
extensions: ['.tex'],
excludes: [],
hasIncludes: true,
targetIsDirectory: false,
},
// inputcontent* command for other LaTeX files.
const pdfGenerator = new PdfGenerator({
generateIfExists: !debug,
checksumsCalculator: new LatexChecksumsCalculator({
latexIncludeCommands: [
LatexIncludeCommand.includeGraphics(options.getIncludeGraphicsDirectories(texDirectoryRelativePath)),
...LatexIncludeCommand.defaultLatexIncludeCommands,
// inputcontent command for other LaTeX files.
new LatexIncludeCommand('inputcontent'),
new LatexIncludeCommand('inputcontent\\*'),
new LatexIncludeCommand(
'setbibliographypath\\*',
{
command: 'inputcontent\\*',
directories: [],
extensions: ['.tex'],
excludes: [],
hasIncludes: true,
targetIsDirectory: false,
},
// setbibliographypath command for bibliography files.
{
command: 'setbibliographypath',
directories: [],
extensions: ['.bib'],
excludes: [],
hasIncludes: false,
targetIsDirectory: true,
},
// inputalgorithm command for bibliography files.
),
new LatexIncludeCommand(
'inputalgorithm',
{
command: 'inputalgorithm',
directories: [],
extensions: ['.py'],
excludes: [],
hasIncludes: false,
targetIsDirectory: false,
},
],
),
},
),
],
}),
})
const result = pdfGenerator.generate(
filePath,
previousBuildDirectory,
)

// If PDF generation is successful, copy files to the destination directory.
if (builtFilePath) {
if (result.builtFilePath) {
fs.mkdirSync(destinationDirectoryPath, { recursive: true })
fs.copyFileSync(builtFilePath, resolver.resolve(destinationDirectoryPath, path.parse(builtFilePath).base))
fs.copyFileSync(result.builtFilePath, resolver.resolve(destinationDirectoryPath, path.parse(result.builtFilePath).base))

// Optionally move files instead of copying.
if (options.moveFiles) {
fs.unlinkSync(builtFilePath)
fs.unlinkSync(result.builtFilePath)
}

// Copy checksums file if available.
if (checksumsFilePath) {
fs.copyFileSync(checksumsFilePath, resolver.resolve(destinationDirectoryPath, path.parse(checksumsFilePath).base))
if (result.checksumsFilePath) {
fs.copyFileSync(result.checksumsFilePath, resolver.resolve(destinationDirectoryPath, path.parse(result.checksumsFilePath).base))

// Optionally move checksums file instead of copying.
if (options.moveFiles) {
fs.unlinkSync(checksumsFilePath)
fs.unlinkSync(result.checksumsFilePath)
}
}

if (wasCached) {
if (result.wasCached) {
logger.success(`Fully cached PDF found in ${previousBuildDirectory}.`)
}
else {
Expand Down
170 changes: 122 additions & 48 deletions modules/nuxt-content-latex/transformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,10 @@ import fs from 'fs'
import { defineTransformer } from '@nuxt/content/transformers'
import { consola } from 'consola'
import type { HTMLElement } from 'node-html-parser'
import * as latex from 'that-latex-lib'
import { KatexRenderer, LatexImageExtractor, PandocCommand, PandocTransformer, SvgGenerator } from 'that-latex-lib'
import { name } from './common'
import { normalizeString, getFileName } from '~/utils/utils'
import { latexOptions } from '~/site/latex'
import { latexOptions, type LatexTransformOptions } from '~/site/latex'
import { debug } from '~/site/debug'

/**
Expand Down Expand Up @@ -44,47 +44,55 @@ export default defineTransformer({

// Parse the Pandoc HTML output.
const assetsRootDirectoryPath = path.resolve(sourceDirectoryPath, options.assetsDestinationDirectory)
const templates: { [key: string]: string } = {}
for (const image in options.picturesTemplate) {
templates[image] = fs.readFileSync(path.resolve(sourceDirectoryPath, options.picturesTemplate.tikzpicture), { encoding: 'utf8' })
}
const { htmlResult: root } // Transforms the raw content into HTML.
= latex.transformToHtml(
filePath,
const pandocTransformer = new PandocTransformer({
imageSrcResolver: PandocTransformer.resolveFromAssetsRoot(
assetsRootDirectoryPath,
{
pandocHeader,
getExtractedImageCacheDirectoryPath: (_extractedFrom, extractedImageTexFilePath) => path.resolve(sourceDirectoryPath, options.cacheDirectory, path.relative(assetsRootDirectoryPath, path.dirname(extractedImageTexFilePath))),
getExtractedImageTargetDirectory: (_extractedFrom, assetName) => path.dirname(options.getAssetDestination(path.relative(contentDirectoryPath, path.resolve(path.dirname(filePath), assetName)))).replace(/\\/g, '/') + '/' + getFileName(filePath),
assetsRootDirectoryPath,
getResolvedImageCacheDirectoryPath: resolvedImageTexFilePath => path.resolve(sourceDirectoryPath, options.cacheDirectory, path.relative(assetsRootDirectoryPath, path.dirname(resolvedImageTexFilePath))),
getImageCacheDirectoryPath: resolvedImageTexFilePath => path.resolve(sourceDirectoryPath, options.cacheDirectory, path.relative(assetsRootDirectoryPath, path.dirname(resolvedImageTexFilePath))),
imagePathToSrc: resolvedImageFilePath => '/' + path.relative(assetsRootDirectoryPath, resolvedImageFilePath).replace(/\\/g, '/'),
renderMathElement,
imagesTemplate: templates,
generateIfExists: !debug,
},
true,
rawContent,
)
),
imageExtractors: [
new TikzPictureImageExtractor(
options,
sourceDirectoryPath,
contentDirectoryPath,
),
],
mathRenderer: new MathRendererWithMacros(),
pandoc: new PandocCommand({
header: pandocHeader,
}),
})
// Transforms the raw content into HTML.
const { htmlResult: root } = pandocTransformer.transform(filePath, rawContent)

// Remove empty titles from the HTML content.
removeEmptyTitles(root)
if (root) {
// Remove empty titles from the HTML content.
removeEmptyTitles(root)

// Replace vspace elements in the HTML content.
replaceVspaceElements(root)
// Replace vspace elements in the HTML content.
replaceVspaceElements(root)

// Handle proofs in the HTML content.
handleProofs(root)
// Handle proofs in the HTML content.
handleProofs(root)

// Handle references in the HTML content.
handleReferences(root)
// Handle references in the HTML content.
handleReferences(root)

logger.success(`Successfully processed ${texFileRelativePath} !`)
logger.success(`Successfully processed ${texFileRelativePath} !`)

// Return the parsed content object.
// Return the parsed content object.
return {
_id,
body: root.outerHTML,
...getHeader(path.parse(filePath).name, root),
}
}
console.error(`Failed to parse ${_id}.`)
return {
_id,
body: root.outerHTML,
...getHeader(path.parse(filePath).name, root),
body: `Unable to parse ${_id}.`,
}
},
})
Expand Down Expand Up @@ -232,22 +240,6 @@ const findRefName = (element: HTMLElement | null): string | null => {
return null
}

/**
* Renders a given math element.
* @param {HTMLElement} element The element.
* @returns {string} The result.
*/
const renderMathElement = (element: HTMLElement): string => latex.renderMathElement(
element,
{
'\\parallelslant': '\\mathbin{\\!/\\mkern-5mu/\\!}',
'\\ensuremath': '#1',
},
math => math
.replace(/(\\left *|\\right *)*\\VERT/g, '$1 | $1 | $1 |')
.replace(/\\overset{(.*)}&{(.*)}/g, '&\\overset{$1}{$2}'),
)

/**
* Extract header information from the HTML structure of a LaTeX document.
*
Expand Down Expand Up @@ -290,3 +282,85 @@ const getHeader = (slug: string, root: HTMLElement): { [key: string]: any } => {

return header
}

/**
* Extracts Tikz pictures from a file.
*/
class TikzPictureImageExtractor extends LatexImageExtractor {
/**
* The Latex transform options.
*/
options: LatexTransformOptions
/**
* The source directory path.
*/
sourceDirectoryPath: string
/**
* The content directory path.
*/
contentDirectoryPath: string

/**
* Creates a new `TikzPictureImageExtractor` instance.
*
* @param {LatexTransformOptions} options The Latex transform options.
* @param {string} sourceDirectoryPath The source directory path.
* @param {string} contentDirectoryPath The content directory path.
*/
constructor(options: LatexTransformOptions, sourceDirectoryPath: string, contentDirectoryPath: string) {
super(
'tikzpicture',
{
svgGenerator: new SvgGenerator({
generateIfExists: !debug,
}),
},
)
this.options = options
this.sourceDirectoryPath = sourceDirectoryPath
this.contentDirectoryPath = contentDirectoryPath
}

override getExtractedImageDirectoryPath(extractedFrom: string, extractedFileName: string): string | null {
return path.resolve(
this.sourceDirectoryPath,
this.options.assetsDestinationDirectory,
path.dirname(
this.options.getAssetDestination(
path.relative(
this.contentDirectoryPath,
path.resolve(path.dirname(extractedFrom), extractedFileName),
),
),
).replace(/\\/g, '/') + '/' + getFileName(extractedFrom),
)
}

override renderContent(extractedImageTexFilePath: string, latexContent: string): string {
const content = fs.readFileSync(path.resolve(this.sourceDirectoryPath, this.options.tikzPictureTemplate), { encoding: 'utf8' })
return content
.replace('{graphicsPath}', '')
// .replace('{grahicsPath}', '\\graphicspath{' + includeGraphicsDirectories
// .map(directory => `{${directory.replaceAll('\\', '\\\\')}}`)
// .join('\n') + '}')
.replace('{content}', latexContent)
}
}

/**
* A math renderer with some custom macros.
*/
class MathRendererWithMacros extends KatexRenderer {
override renderMathElement(element: HTMLElement): string {
return super.renderMathElement(
element,
{
'\\parallelslant': '\\mathbin{\\!/\\mkern-5mu/\\!}',
'\\ensuremath': '#1',
},
math => math
.replace(/(\\left *|\\right *)*\\VERT/g, '$1 | $1 | $1 |')
.replace(/\\overset{(.*)}&{(.*)}/g, '&\\overset{$1}{$2}'),
)
}
}
Loading

0 comments on commit b38ca22

Please sign in to comment.