Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
6 changes: 6 additions & 0 deletions news/changelog-1.10.md
Original file line number Diff line number Diff line change
Expand Up @@ -6,3 +6,9 @@ All changes included in 1.10:

- ([#14261](https://github.com/quarto-dev/quarto-cli/issues/14261)): Fix theorem/example block titles containing inline code producing invalid Typst markup when syntax highlighting is applied.

## Commands

### `quarto check`

- ([#14265](https://github.com/quarto-dev/quarto-cli/issues/14265)): Fix `quarto check` not detecting MiKTeX on Windows even when available in system PATH.

66 changes: 64 additions & 2 deletions src/command/check/check.ts
Original file line number Diff line number Diff line change
Expand Up @@ -414,8 +414,23 @@ async function checkInstall(conf: CheckConfiguration) {
latexOutput.push(`${kIndent}Version: ${version}`);
latexJson["version"] = version;
} else {
latexOutput.push(`${kIndent}Tex: (not detected)`);
latexJson["installed"] = false;
// Check for MiKTeX (uses initexmf instead of tlmgr)
const miktexDetection = await detectMiktex();
if (miktexDetection) {
latexOutput.push(`${kIndent}Using: MiKTeX`);
if (miktexDetection.path) {
latexOutput.push(`${kIndent}Path: ${miktexDetection.path}`);
latexJson["path"] = miktexDetection.path;
}
latexJson["source"] = "miktex";
if (miktexDetection.version) {
latexOutput.push(`${kIndent}Version: ${miktexDetection.version}`);
latexJson["version"] = miktexDetection.version;
}
} else {
latexOutput.push(`${kIndent}Tex: (not detected)`);
latexJson["installed"] = false;
}
}
};
if (conf.jsonResult) {
Expand Down Expand Up @@ -561,3 +576,50 @@ async function detectChromeForCheck(): Promise<ChromeCheckInfo> {

return result;
}

interface MiktexDetectionResult {
path?: string;
version?: string;
}

async function detectMiktex(): Promise<MiktexDetectionResult | undefined> {
try {
const initexmfPath = await which("initexmf");
if (!initexmfPath) {
return undefined;
}

const result: MiktexDetectionResult = {
path: dirname(initexmfPath),
};

// Get MiKTeX version via initexmf --version
try {
const versionResult = await execProcess({
cmd: "initexmf",
args: ["--version"],
stdout: "piped",
stderr: "piped",
});
Comment on lines +598 to +603
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

detectMiktex() records path based on the resolved initexmfPath, but the version check runs execProcess with cmd: "initexmf" (re-resolved from PATH). If multiple initexmf entries exist (or PATH changes), this can report a path from one install and a version from another. Use the resolved initexmfPath for the execProcess call (and/or set cwd appropriately) to keep path/version consistent.

Copilot uses AI. Check for mistakes.
if (versionResult.code === 0 && versionResult.stdout) {
// initexmf --version outputs lines like:
// MiKTeX Configuration Utility 4.12 (MiKTeX 24.1)
// The parenthesized version is the distribution version
const distVersionMatch = versionResult.stdout.match(
/\(MiKTeX\s+(\d[\d.]*)\)/i,
);
const versionMatch = distVersionMatch ||
versionResult.stdout.match(/MiKTeX\s+(\d[\d.]*)/i);
if (versionMatch) {
result.version = versionMatch[1];
}
Comment on lines +605 to +615
Copy link

Copilot AI Mar 25, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The new MiKTeX version parsing logic is currently untested. There are existing smoke tests for quarto check --output (JSON parsing) but nothing exercises/validates the MiKTeX detection/version extraction path; consider adding a unit test for the initexmf --version parsing (and ideally path/source population) to prevent regressions when MiKTeX changes its output format.

Copilot uses AI. Check for mistakes.
}
} catch {
// Version detection is best-effort
}

return result;
} catch {
return undefined;
}
}
Loading