diff --git a/.vscode/launch.json b/.vscode/launch.json index 932257407b..82cb69aec5 100644 --- a/.vscode/launch.json +++ b/.vscode/launch.json @@ -22,7 +22,9 @@ ], "env": { "QUARTO_BIN_PATH": "${workspaceFolder}/package/dist/bin", - "QUARTO_SHARE_PATH": "${workspaceFolder}/src/resources" + "QUARTO_SHARE_PATH": "${workspaceFolder}/src/resources", + "QUARTO_ROOT": "${workspaceFolder}", + "QUARTO_DEBUG": "true" }, "attachSimplePort": 9229, "windows": { diff --git a/news/changelog-1.5.md b/news/changelog-1.5.md index 867cf03e3e..83e83da8d1 100644 --- a/news/changelog-1.5.md +++ b/news/changelog-1.5.md @@ -57,6 +57,7 @@ All changes included in 1.5: - ([#8851](https://github.com/quarto-dev/quarto-cli/issues/8851)): Don't strip `index.html` from external paths. - ([#8977](https://github.com/quarto-dev/quarto-cli/issues/8977)): Don't decorate about links within external link icons. - ([#9356](https://github.com/quarto-dev/quarto-cli/issues/9356)): Don't process column classes for figures inside the About divs. +- ([#9781](https://github.com/quarto-dev/quarto-cli/issues/9781)): Correctly hide elements from click event in collapsed margin sidebar. ## Book @@ -122,6 +123,7 @@ All changes included in 1.5: - ([#9635](https://github.com/quarto-dev/quarto-cli/issues/9635)): Respect `{shortcodes=false}` when resolving `include` shortcodes. - ([#9664](https://github.com/quarto-dev/quarto-cli/pull/9664)): Add `placeholder` shortcode to produce placeholder images. - ([#9665](https://github.com/quarto-dev/quarto-cli/issues/9665)): Fix issue with key-value arguments of shortcode handlers in code contexts. +- ([#9793](https://github.com/quarto-dev/quarto-cli/issues/9793)): `embed` shortcode now correctly retrieve svg image from embdedded cell. ## Lightbox Images @@ -144,6 +146,7 @@ All changes included in 1.5: ## Publishing - ([#9308](https://github.com/quarto-dev/quarto-cli/issues/9308)): Improved error message when trying to publish to Github pages with `quarto publish gh-pages`. +- ([#9585](https://github.com/quarto-dev/quarto-cli/issues/9585)): Improved `quarto publish gh-pages` workflow when existing gh-pages branch is present or problem with the remote repository. ## `quarto inspect` diff --git a/src/command/check/check.ts b/src/command/check/check.ts index 46a8523f76..448ac70477 100644 --- a/src/command/check/check.ts +++ b/src/command/check/check.ts @@ -131,9 +131,9 @@ async function checkVersions(_services: RenderServices) { let typstVersion = lines( (await execProcess({ cmd: [typstBinaryPath(), "--version"], - stdout: "piped" + stdout: "piped", })).stdout!, - )[0].split(' ')[1]; + )[0].split(" ")[1]; checkVersion(typstVersion, ">=0.10.0", "Typst"); completeMessage("Checking versions of quarto dependencies......OK"); @@ -141,19 +141,24 @@ async function checkVersions(_services: RenderServices) { async function checkInstall(services: RenderServices) { completeMessage("Checking Quarto installation......OK"); - info(` Version: ${quartoConfig.version()}`); + info(`${kIndent}Version: ${quartoConfig.version()}`); if (quartoConfig.version() === "99.9.9") { // if they're running a dev version, we assume git is installed + // and QUARTO_ROOT is set to the root of the quarto-cli repo // print the output of git rev-parse HEAD - const gitHead = await execProcess({ - cmd: ["git", "rev-parse", "HEAD"], - stdout: "piped", - }); - if (gitHead.stdout) { - info(` commit: ${gitHead.stdout.trim()}`); + const quartoRoot = Deno.env.get("QUARTO_ROOT"); + if (quartoRoot) { + const gitHead = await execProcess({ + cmd: ["git", "-C", quartoRoot, "rev-parse", "HEAD"], + stdout: "piped", + stderr: "piped", // to not show error if not in a git repo + }); + if (gitHead.success && gitHead.stdout) { + info(`${kIndent}commit: ${gitHead.stdout.trim()}`); + } } } - info(` Path: ${quartoConfig.binPath()}`); + info(`${kIndent}Path: ${quartoConfig.binPath()}`); if (Deno.build.os === "windows") { try { const codePage = readCodePage(); @@ -161,10 +166,10 @@ async function checkInstall(services: RenderServices) { await cacheCodePage(); const codePage2 = readCodePage(); - info(` CodePage: ${codePage2 || "unknown"}`); + info(`${kIndent}CodePage: ${codePage2 || "unknown"}`); if (codePage && codePage !== codePage2) { info( - ` NOTE: Code page updated from ${codePage} to ${codePage2}. Previous rendering may have been affected.`, + `${kIndent}NOTE: Code page updated from ${codePage} to ${codePage2}. Previous rendering may have been affected.`, ); } // if non-standard code page, check for non-ascii characters in path @@ -172,11 +177,11 @@ async function checkInstall(services: RenderServices) { const nonAscii = /[^\x00-\x7F]+/; if (nonAscii.test(quartoConfig.binPath())) { info( - ` ERROR: Non-ASCII characters in Quarto path causes rendering problems.`, + `${kIndent}ERROR: Non-ASCII characters in Quarto path causes rendering problems.`, ); } } catch { - info(` CodePage: Unable to read code page`); + info(`${kIndent}CodePage: Unable to read code page`); } } @@ -191,10 +196,10 @@ async function checkInstall(services: RenderServices) { for (const tool of tools.installed) { const version = await tool.installedVersion() || "(external install)"; - toolsOutput.push(` ${tool.name}: ${version}`); + toolsOutput.push(`${kIndent}${tool.name}: ${version}`); } for (const tool of tools.notInstalled) { - toolsOutput.push(` ${tool.name}: (not installed)`); + toolsOutput.push(`${kIndent}${tool.name}: (not installed)`); } }); toolsOutput.forEach((out) => info(out)); @@ -213,19 +218,19 @@ async function checkInstall(services: RenderServices) { if (tlContext.usingGlobal) { const tlMgrPath = await which("tlmgr"); - latexOutput.push(` Using: Installation From Path`); + latexOutput.push(`${kIndent}Using: Installation From Path`); if (tlMgrPath) { - latexOutput.push(` Path: ${dirname(tlMgrPath)}`); + latexOutput.push(`${kIndent}Path: ${dirname(tlMgrPath)}`); } } else { - latexOutput.push(` Using: TinyTex`); + latexOutput.push(`${kIndent}Using: TinyTex`); if (tlContext.binDir) { - latexOutput.push(` Path: ${tlContext.binDir}`); + latexOutput.push(`${kIndent}Path: ${tlContext.binDir}`); } } - latexOutput.push(` Version: ${version}`); + latexOutput.push(`${kIndent}Version: ${version}`); } else { - latexOutput.push(` Tex: (not detected)`); + latexOutput.push(`${kIndent}Tex: (not detected)`); } }); latexOutput.forEach((out) => info(out)); diff --git a/src/core/devconfig.ts b/src/core/devconfig.ts index dcf8d09b7e..4ab0f9176b 100644 --- a/src/core/devconfig.ts +++ b/src/core/devconfig.ts @@ -82,7 +82,7 @@ export function readInstalledDevConfig(): DevConfig | null { export function readSourceDevConfig(): DevConfig { const rootDir = Deno.env.get("QUARTO_ROOT") || - join(quartoConfig.sharePath(), "../../src"); + join(quartoConfig.sharePath(), "../.."); const configurationScript = join( rootDir, "configuration", diff --git a/src/core/git.ts b/src/core/git.ts index 6a102dd0ff..7749743931 100644 --- a/src/core/git.ts +++ b/src/core/git.ts @@ -64,3 +64,21 @@ export async function lsFiles( return Promise.resolve(undefined); } + +export async function gitBranchExists( + branch: string, + cwd?: string, +): Promise { + if (await which("git")) { + const result = await execProcess({ + cmd: ["git", "show-ref", "--verify", "--quiet", `refs/heads/${branch}`], + cwd, + stdout: "piped", + stderr: "piped", + }); + + return result.code === 0; + } + + return Promise.resolve(undefined); +} diff --git a/src/core/github-types.ts b/src/core/github-types.ts index b04583847a..27399b5145 100644 --- a/src/core/github-types.ts +++ b/src/core/github-types.ts @@ -9,7 +9,8 @@ export type GitHubContext = { repo: boolean; originUrl?: string; repoUrl?: string; - ghPages?: boolean; + ghPagesRemote?: boolean; + ghPagesLocal?: boolean; siteUrl?: string; browse?: boolean; organization?: string; diff --git a/src/core/github.ts b/src/core/github.ts index 273469906f..fdaeda10b2 100644 --- a/src/core/github.ts +++ b/src/core/github.ts @@ -11,6 +11,7 @@ import { join } from "../deno_ral/path.ts"; import { existsSync } from "fs/mod.ts"; import { isHttpUrl } from "./url.ts"; import { GitHubContext } from "./github-types.ts"; +import { gitBranchExists } from "./git.ts"; export async function gitHubContext(dir: string) { // establish dir @@ -43,7 +44,7 @@ export async function gitHubContext(dir: string) { context.originUrl = result.stdout?.trim(); // check for a gh-pages branch - context.ghPages = (await execProcess({ + const ghPagesRemote = await execProcess({ cmd: [ "git", "ls-remote", @@ -54,7 +55,22 @@ export async function gitHubContext(dir: string) { ], stdout: "piped", stderr: "piped", - })).success; + }); + + context.ghPagesRemote = ghPagesRemote.success; + if (!ghPagesRemote.success) { + // when no gh-pages branch on remote, check local to avoid creation error + // as if local branch exists, we don't want to create a new one + // https://git-scm.com/docs/git-ls-remote#Documentation/git-ls-remote.txt---exit-code + if (ghPagesRemote.code === 2) { + context.ghPagesLocal = await gitBranchExists("gh-pages"); + } else { + // if we go there, this means something is not right with the remote origin + throw new Error( + `There is an error while retrieving information from remote 'origin'.\n Git error: ${ghPagesRemote.stderr}. \n Git status code: ${ghPagesRemote.code}.`, + ); + } + } // determine siteUrl context.siteUrl = siteUrl( diff --git a/src/core/jupyter/jupyter.ts b/src/core/jupyter/jupyter.ts index 81ca3a2910..3519f7dee9 100644 --- a/src/core/jupyter/jupyter.ts +++ b/src/core/jupyter/jupyter.ts @@ -1930,9 +1930,15 @@ function mdImageOutput( ? (data as string[]).join("") : data as string; - // base64 decode if it's not svg const outputFile = join(options.assets.base_dir, imageFile); - if (mimeType !== kImageSvg) { + if ( + // base64 decode if it's not svg + mimeType !== kImageSvg || + // or if it is encoded svg; this could happen when used in embed context, + // as Pandoc will generate ipynb with base64 encoded svg data + // https://github.com/quarto-dev/quarto-cli/issues/9793 + !/ { const ghContext = await gitHubContextForPublish(input); - if (ghContext.ghPages) { + if (ghContext.ghPagesRemote) { return { id: "gh-pages", url: ghContext.siteUrl || ghContext.originUrl, @@ -114,17 +114,27 @@ async function publish( const ghContext = await gitHubContextForPublish(options.input); verifyContext(ghContext, "GitHub Pages"); - // create gh pages branch if there is none yet - const createGhPagesBranch = !ghContext.ghPages; - if (createGhPagesBranch) { + // create gh pages branch on remote and local if there is none yet + const createGhPagesBranchRemote = !ghContext.ghPagesRemote; + const createGhPagesBranchLocal = !ghContext.ghPagesLocal; + if (createGhPagesBranchRemote) { // confirm - const confirmed = await Confirm.prompt({ + let confirmed = await Confirm.prompt({ indent: "", message: `Publish site to ${ ghContext.siteUrl || ghContext.originUrl } using gh-pages?`, default: true, }); + if (confirmed && !createGhPagesBranchLocal) { + confirmed = await Confirm.prompt({ + indent: "", + message: + `A local gh-pages branch already exists. Should it be pushed to remote 'origin'?`, + default: true, + }); + } + if (!confirmed) { throw new Error(); } @@ -135,9 +145,29 @@ async function publish( } const oldBranch = await gitCurrentBranch(input); try { - await gitCreateGhPages(input); + // Create and push if necessary, or just push local branch + if (createGhPagesBranchLocal) { + await gitCreateGhPages(input); + } else { + await gitPushGhPages(input); + } + } catch { + // Something failed so clean up, i.e + // if we created the branch then delete it. + // Example of failure: Auth error on push (https://github.com/quarto-dev/quarto-cli/issues/9585) + if (createGhPagesBranchLocal && await gitBranchExists("gh-pages")) { + await gitCmds(input, [ + ["checkout", oldBranch], + ["branch", "-D", "gh-pages"], + ]); + } + throw new Error( + "Publishing to gh-pages with `quarto publish gh-pages` failed.", + ); } finally { - await gitCmds(input, [["checkout", oldBranch]]); + if (await gitCurrentBranch(input) !== oldBranch) { + await gitCmds(input, [["checkout", oldBranch]]); + } if (stash) { await gitStashApply(input); } @@ -191,7 +221,7 @@ async function publish( /^https:\/\/(.+?)\.github\.io\/$/, ); if (defaultSiteMatch) { - if (createGhPagesBranch) { + if (createGhPagesBranchRemote) { notifyGhPagesBranch = true; } else { try { @@ -207,7 +237,7 @@ async function publish( } // if this is an update then warn that updates may require a browser refresh - if (!createGhPagesBranch && !notifyGhPagesBranch) { + if (!createGhPagesBranchRemote && !notifyGhPagesBranch) { info(colors.yellow( "NOTE: GitHub Pages sites use caching so you might need to click the refresh\n" + "button within your web browser to see changes after deployment.\n", @@ -360,7 +390,14 @@ async function gitCreateGhPages(dir: string) { await gitCmds(dir, [ ["checkout", "--orphan", "gh-pages"], ["rm", "-rf", "--quiet", "."], - ["commit", "--allow-empty", "-m", `Initializing gh-pages branch`], - ["push", "origin", `HEAD:gh-pages`], + ["commit", "--allow-empty", "-m", "Initializing gh-pages branch"], ]); + await gitPushGhPages(dir); +} + +async function gitPushGhPages(dir: string) { + if (await gitCurrentBranch(dir) !== "gh-pages") { + await gitCmds(dir, [["checkout", "gh-pages"]]); + } + await gitCmds(dir, [["push", "origin", "HEAD:gh-pages"]]); } diff --git a/src/publish/huggingface/huggingface.ts b/src/publish/huggingface/huggingface.ts index 33e067e5a2..e2bb61e7ef 100644 --- a/src/publish/huggingface/huggingface.ts +++ b/src/publish/huggingface/huggingface.ts @@ -70,7 +70,7 @@ async function publishRecord( input: string | ProjectContext, ): Promise { const ghContext = await gitHubContextForPublish(input); - if (ghContext.ghPages) { + if (ghContext.ghPagesRemote) { return { id: kHuggingFace, url: ghContext.siteUrl || ghContext.originUrl, diff --git a/src/resources/formats/html/quarto.js b/src/resources/formats/html/quarto.js index 260f0af417..39e6869927 100644 --- a/src/resources/formats/html/quarto.js +++ b/src/resources/formats/html/quarto.js @@ -319,6 +319,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) { for (const child of el.children) { child.style.opacity = 0; child.style.overflow = "hidden"; + child.style.pointerEvents = "none"; } nexttick(() => { @@ -360,6 +361,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) { const clone = child.cloneNode(true); clone.style.opacity = 1; + clone.style.pointerEvents = null; clone.style.display = null; toggleContents.append(clone); } @@ -434,6 +436,7 @@ window.document.addEventListener("DOMContentLoaded", function (_event) { for (const child of el.children) { child.style.opacity = 1; child.style.overflow = null; + child.style.pointerEvents = null; } const placeholderEl = window.document.getElementById( diff --git a/src/resources/julia/Project.toml b/src/resources/julia/Project.toml index 08ee15cdbd..aadc4cf738 100644 --- a/src/resources/julia/Project.toml +++ b/src/resources/julia/Project.toml @@ -2,4 +2,4 @@ QuartoNotebookRunner = "4c0109c6-14e9-4c88-93f0-2b974d3468f4" [compat] -QuartoNotebookRunner = "=0.10.2" +QuartoNotebookRunner = "=0.11.0" diff --git a/src/webui/quarto-preview/deno.lock b/src/webui/quarto-preview/deno.lock index 4fa5943586..dffe2c701b 100644 --- a/src/webui/quarto-preview/deno.lock +++ b/src/webui/quarto-preview/deno.lock @@ -203,7 +203,7 @@ "workspace": { "packageJson": { "dependencies": [ - "npm:@fluentui/react-components@^9.19.1", + "npm:@fluentui/react-components@~9.48.0", "npm:@fluentui/react-icons@^2.0.201", "npm:@types/react-dom@^18.2.0", "npm:@types/react@^18.2.0", diff --git a/src/webui/quarto-preview/package.json b/src/webui/quarto-preview/package.json index 9717e98c90..c70d60d689 100644 --- a/src/webui/quarto-preview/package.json +++ b/src/webui/quarto-preview/package.json @@ -19,7 +19,7 @@ }, "dependencies": { "@fluentui/react-icons": "^2.0.201", - "@fluentui/react-components": "^9.19.1", + "@fluentui/react-components": "~9.48.0", "react": "^18.2.0", "react-dom": "^18.2.0", "ansi-output": "^0.0.1" @@ -37,4 +37,4 @@ "vite-plugin-css-injected-by-js": "^3.1.0", "vite-plugin-static-copy": "^0.13.0" } -} \ No newline at end of file +} diff --git a/tests/docs/smoke-all/2024/05/29/9713/main.qmd b/tests/docs/smoke-all/2024/05/29/9713/main.qmd new file mode 100644 index 0000000000..3f9018787c --- /dev/null +++ b/tests/docs/smoke-all/2024/05/29/9713/main.qmd @@ -0,0 +1,8 @@ +--- +format: typst +_quarto: + tests: + typst: null +--- + +{{< embed plots.qmd#plot >}} diff --git a/tests/docs/smoke-all/2024/05/29/9713/plots.qmd b/tests/docs/smoke-all/2024/05/29/9713/plots.qmd new file mode 100644 index 0000000000..aedb3d45e6 --- /dev/null +++ b/tests/docs/smoke-all/2024/05/29/9713/plots.qmd @@ -0,0 +1,10 @@ +--- +title: "Plots" +fig-format: svg +--- + +```{r} +#| label: plot +plot(1:10) +``` + diff --git a/tests/new-smoke-all-test.ps1 b/tests/new-smoke-all-test.ps1 index 84e4280fa4..638a95bd6f 100644 --- a/tests/new-smoke-all-test.ps1 +++ b/tests/new-smoke-all-test.ps1 @@ -41,6 +41,13 @@ _quarto: noErrors: default fileExists: supportPath: mediabag/lter_penguins.png + typst: + ensureFileRegexMatches: + - [] + - [] + ensureTypstFileRegexMatches: + - [] + - [] docx: ensureDocxRegexMatches: - [] diff --git a/tests/new-smoke-all-test.sh b/tests/new-smoke-all-test.sh index a1f5b064d8..fa6f2f4cdc 100755 --- a/tests/new-smoke-all-test.sh +++ b/tests/new-smoke-all-test.sh @@ -39,6 +39,13 @@ _quarto: noErrors: default fileExists: supportPath: mediabag/lter_penguins.png + typst: + ensureFileRegexMatches: + - [] + - [] + ensureTypstFileRegexMatches: + - [] + - [] docx: ensureDocxRegexMatches: - []