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 = { tex: ['pdflatex', 'latex', 'xelatex', 'lualatex'], qmd: ['quarto'], rmd: ['quarto'], typ: ['typst'], } function getCompilerOptions(): Option[] { 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 ( ) }