Fix LaTeX projects failing to compile (HTTP 500, no logs)
Build and Deploy Verso / deploy (push) Successful in 7m44s

Project.compiler defaults to settings.defaultLatexCompiler ('quarto' in this
fork), so every .tex project carried compiler='quarto'. Since the CLSI runner
is chosen by file extension, a .tex root still goes to LatexRunner, whose
_buildLatexCommand threw `unknown compiler: quarto` — surfacing as an opaque
HTTP 500 with no compile log.

- LatexRunner: fall back to pdfLaTeX when the compiler isn't a known TeX engine
  instead of throwing. Universal safety net (covers existing projects, uploads
  and GitHub imports already saved with compiler='quarto').
- ProjectCreationHandler: store a sensible compiler per flavour at creation via
  a shared _flavourConfig helper — blank/example LaTeX → 'pdflatex',
  Typst → 'typst', Quarto → 'quarto' — so the compiler dropdown reflects the
  engine and LatexRunner receives a valid one directly.

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
claude
2026-06-01 13:08:57 +00:00
parent d67bc77b0e
commit 2d4ca6f13a
2 changed files with 39 additions and 23 deletions
+7 -7
View File
@@ -197,13 +197,13 @@ function _buildLatexCommand(mainFile, opts = {}) {
command.push(...opts.flags)
}
// TeX Engine selection
const compilerFlag = COMPILER_FLAGS[opts.compiler]
if (compilerFlag) {
command.push(compilerFlag)
} else {
throw new Error(`unknown compiler: ${opts.compiler}`)
}
// TeX Engine selection. A .tex project may carry a non-LaTeX compiler value
// (e.g. 'quarto', the fork-wide default for Project.compiler) because the
// runner is chosen by file extension, not by this setting. In that case fall
// back to pdfLaTeX rather than throwing — throwing here surfaces as an opaque
// HTTP 500 with no compile log.
const compilerFlag = COMPILER_FLAGS[opts.compiler] || COMPILER_FLAGS.pdflatex
command.push(compilerFlag)
// We want to run latexmk on the tex file which we will automatically
// generate from the Rtex/Rmd/md file.
@@ -85,26 +85,38 @@ async function createProjectFromSnippet(ownerId, projectName, docLines) {
return project
}
async function createBasicProject(ownerId, projectName, flavour = 'quarto') {
const project = await _createBlankProject(ownerId, projectName)
// Verso compiles .qmd with Quarto, .tex with latexmk and .typ with Typst;
// the root file's extension selects the runner (see CompileManager in CLSI),
// so a blank project's flavour is just a choice of template + root name.
let templateName, rootDocName
// Per-flavour blank-project template, root document name and stored compiler.
function _flavourConfig(flavour) {
switch (flavour) {
case 'latex':
templateName = 'mainbasic.tex'
rootDocName = 'main.tex'
break
return {
templateName: 'mainbasic.tex',
rootDocName: 'main.tex',
compiler: 'pdflatex',
}
case 'typst':
templateName = 'mainbasic.typ'
rootDocName = 'main.typ'
break
return {
templateName: 'mainbasic.typ',
rootDocName: 'main.typ',
compiler: 'typst',
}
default:
templateName = 'mainbasic.qmd'
rootDocName = 'main.qmd'
return {
templateName: 'mainbasic.qmd',
rootDocName: 'main.qmd',
compiler: 'quarto',
}
}
}
async function createBasicProject(ownerId, projectName, flavour = 'quarto') {
// Verso compiles .qmd with Quarto, .tex with latexmk and .typ with Typst;
// the root file's extension selects the runner (see CompileManager in CLSI).
// Each flavour is a choice of template + root name + the compiler stored on
// the project (so the compiler dropdown reflects the engine and LatexRunner
// never receives a non-LaTeX compiler for a .tex project).
const { templateName, rootDocName, compiler } = _flavourConfig(flavour)
const project = await _createBlankProject(ownerId, projectName, { compiler })
const docLines = await _buildTemplate(templateName, ownerId, projectName)
await _createRootDoc(project, ownerId, docLines, rootDocName)
@@ -187,7 +199,11 @@ async function createExampleProject(
attributes = {},
flavour = 'latex'
) {
const project = await _createBlankProject(ownerId, projectName, attributes)
const { compiler } = _flavourConfig(flavour)
const project = await _createBlankProject(ownerId, projectName, {
...attributes,
compiler,
})
let result
switch (flavour) {