Skip to content
Open
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
19 changes: 19 additions & 0 deletions _latex-template/template.tex
Original file line number Diff line number Diff line change
Expand Up @@ -211,6 +211,25 @@
}
\makeatother

% Inline-image \par swallow. myst-to-tex's image handler always emits
% "\n\n" after \includegraphics (its closeBlock), which LaTeX reads as
% \par and breaks the surrounding paragraph after an inline image. The
% latex-shims plugin inserts \snapinlineparhook just before every inline
% image that has more content following it in the same parent. The hook
% installs a one-shot redefinition of \par that fires for the very next
% \par, undoes the trailing space the end-of-line inserted, restores the
% real \par, and lets the paragraph continue.
\makeatletter
\newcommand{\snapinlineparhook}{%
\let\snap@par@orig\par%
\let\par\snap@par@swallow%
}
\def\snap@par@swallow{%
\let\par\snap@par@orig%
\unskip%
}
\makeatother

% --- <kbd> rendering ----------------------------------------------------
% Used by the latex-shims plugin to render the MyST `keyboard` node.
\newcommand{\kbd}[1]{%
Expand Down
36 changes: 36 additions & 0 deletions _support/plugins/latex-shims.mjs
Original file line number Diff line number Diff line change
Expand Up @@ -380,9 +380,45 @@ const latexShimsTransform = {
imageNode.width = normalizeWidth(imageNode.width);
}
});

// 6. Inline-image paragraph-break suppression.
// myst-to-tex's image handler unconditionally emits "\n\n" after each
// \includegraphics, which LaTeX reads as \par and ends the surrounding
// paragraph. For inline images that have following content in the same
// parent (text, more inline images, etc.) that produces an unwanted
// line break right after the image. We can't override the handler from
// a plugin, so instead we insert a raw \snapinlineparhook node before
// each such image; the macro (defined in template.tex) installs a
// one-shot \par redefinition that swallows the next \par (and the
// space the end-of-line generates immediately before it). Inline
// images that are the last child of their parent are left alone so
// legitimate paragraph breaks still happen.
walkWithParent(tree, null, (node, parent) => {
if (node.type !== 'image') return;
if (inlineSentinel(node) == null) return;
if (!parent || !Array.isArray(parent.children)) return;
const idx = parent.children.indexOf(node);
if (idx < 0 || idx === parent.children.length - 1) return;
parent.children.splice(idx, 0, {
type: 'raw',
lang: 'tex',
tex: '\\snapinlineparhook ',
});
});
},
};

// Walk the tree calling fn(node, parent) on each node. The walk records
// children before recursing so mutations to parent.children inside fn (e.g.,
// splicing a sibling before `node`) don't double-visit or skip nodes.
function walkWithParent(node, parent, fn) {
if (!node) return;
fn(node, parent);
const children = Array.isArray(node.children) ? node.children.slice() : null;
if (!children) return;
for (const child of children) walkWithParent(child, node, fn);
}

export default {
name: 'LaTeX shims (kbd, grid, image, index, lightning)',
transforms: [latexShimsTransform],
Expand Down
Loading