Files
Verso/services/web/frontend/js/features/settings/components/compiler-settings/compiler-setting.tsx
T
claude b0b389dc4c
Build and Deploy Verso / deploy (push) Successful in 14m56s
feat: set-as-main for .typ/.qmd; fix compiler filter; fix ZIP import compiler
Set as main document (context menu):
- canSetRootDocId used selectedEntityIds so .typ/.qmd files couldn't be
  set as main via right-click on an unselected file.
  Now computed locally from contextMenuEntityId (same pattern as convert)
  using isValidTeXFile which already covers .typ, .qmd, .tex etc.

Compiler filter (editor settings):
- docs?.find(id) could return undefined due to ID format mismatch,
  causing all engines to show as available for non-LaTeX projects.
  Added findInTree fallback so the root doc name is always resolved.

ZIP import compiler:
- Projects created from ZIP always got defaultLatexCompiler ('quarto')
  regardless of content.
- findRootDocFileFromDirectory now also searches for .typ and .qmd root
  files after finding no .tex file.
- ProjectUploadManager now infers the compiler from the root doc
  extension and sets it on the project after import.

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
2026-06-17 21:56:39 +00:00

84 lines
3.1 KiB
TypeScript

import { useMemo, useState } from 'react'
import { useProjectSettingsContext } from '@/features/editor-left-menu/context/project-settings-context'
import DropdownSetting from '../dropdown-setting'
import type { Option } from '../dropdown-setting'
import { useTranslation } from 'react-i18next'
import { usePermissionsContext } from '@/features/ide-react/context/permissions-context'
import { ProjectCompiler } from '@ol-types/project-settings'
import { useSetCompilationSettingWithEvent } from '@/features/editor-left-menu/hooks/use-set-compilation-setting'
import { useFileTreeData } from '@/shared/context/file-tree-data-context'
import { findInTree } from '@/features/file-tree/util/find-in-tree'
// Which compiler engines make sense for a given root-file extension. CLSI
// dispatches the real engine from this extension (.qmd → Quarto, .typ → Typst,
// .tex → latexmk), so offering, say, XeLaTeX for a .qmd root is meaningless.
const ENGINES_BY_EXTENSION: Record<string, ProjectCompiler[]> = {
tex: ['pdflatex', 'latex', 'xelatex', 'lualatex'],
qmd: ['quarto'],
rmd: ['quarto'],
typ: ['typst'],
}
function getCompilerOptions(): Option<ProjectCompiler>[] {
return [
{ value: 'quarto', label: 'Quarto' },
{ value: 'typst', label: 'Typst' },
{ value: 'pdflatex', label: 'pdfLaTeX' },
{ value: 'latex', label: 'LaTeX' },
{ value: 'xelatex', label: 'XeLaTeX' },
{ value: 'lualatex', label: 'LuaLaTeX' },
]
}
export default function CompilerSetting() {
const { compiler, setCompiler, rootDocId } = useProjectSettingsContext()
const [compilerOptions] = useState(() => getCompilerOptions())
const { t } = useTranslation()
const { write } = usePermissionsContext()
const { docs, fileTreeData } = useFileTreeData()
const changeCompiler = useSetCompilationSettingWithEvent(
'compiler',
setCompiler
)
// Disable the engines that don't apply to the current root file's extension.
// The currently-selected engine is always left enabled so it keeps showing.
const options = useMemo(() => {
let rootDocName: string | undefined
if (rootDocId) {
const fromDocs = docs?.find(doc => doc.doc.id === rootDocId)
if (fromDocs) {
rootDocName = fromDocs.doc.name
} else if (fileTreeData) {
// Fallback: look up directly in tree in case of ID format mismatch
const found = findInTree(fileTreeData, rootDocId)
if (found?.type === 'doc') rootDocName = found.entity.name
}
}
const extension = rootDocName?.split('.').pop()?.toLowerCase()
const allowed = extension ? ENGINES_BY_EXTENSION[extension] : undefined
if (!allowed) {
return compilerOptions
}
return compilerOptions.map(option => ({
...option,
disabled: !allowed.includes(option.value) && option.value !== compiler,
}))
}, [compilerOptions, docs, rootDocId, compiler])
return (
<DropdownSetting
id="compiler"
label={t('compiler')}
description={t('the_latex_engine_used_for_compiling')}
disabled={!write}
options={options}
onChange={changeCompiler}
value={compiler}
translateOptions="no"
/>
)
}