Skip to content

Commit

Permalink
Support <Code inline /> to output inline code (#6959)
Browse files Browse the repository at this point in the history
* Support `<Code inline />` to output inline code

* Fix typo

* Fix typo again

* Remove expected error

---------

Co-authored-by: Matthew Phillips <[email protected]>
  • Loading branch information
bluwy and matthewp authored May 3, 2023
1 parent 6916e5c commit cac4a32
Show file tree
Hide file tree
Showing 4 changed files with 71 additions and 21 deletions.
5 changes: 5 additions & 0 deletions .changeset/nine-geckos-act.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
---
'astro': minor
---

Support `<Code inline />` to output inline code HTML (no `pre` tag)
67 changes: 46 additions & 21 deletions packages/astro/components/Code.astro
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
---
import type * as shiki from 'shiki';
import { renderToHtml } from 'shiki';
import { getHighlighter } from './Shiki.js';
export interface Props {
Expand Down Expand Up @@ -30,36 +31,60 @@ export interface Props {
* @default false
*/
wrap?: boolean | null;
/**
* Generate inline code element only, without the pre element wrapper.
*
* @default false
*/
inline?: boolean;
}
const { code, lang = 'plaintext', theme = 'github-dark', wrap = false } = Astro.props;
/** Replace the shiki class name with a custom astro class name. */
function repairShikiTheme(html: string): string {
// Replace "shiki" class naming with "astro"
html = html.replace(/<pre class="(.*?)shiki(.*?)"/, '<pre class="$1astro-code$2"');
// Handle code wrapping
// if wrap=null, do nothing.
if (wrap === false) {
html = html.replace(/style="(.*?)"/, 'style="$1; overflow-x: auto;"');
} else if (wrap === true) {
html = html.replace(
/style="(.*?)"/,
'style="$1; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"'
);
}
return html;
}
const {
code,
lang = 'plaintext',
theme = 'github-dark',
wrap = false,
inline = false,
} = Astro.props;
// 1. Get the shiki syntax highlighter
const highlighter = await getHighlighter({
theme,
// Load custom lang if passed an object, otherwise load the default
langs: typeof lang !== 'string' ? [lang] : undefined,
});
const _html = highlighter.codeToHtml(code, {
lang: typeof lang === 'string' ? lang : lang.id,
// 2. Turn code into shiki theme tokens
const tokens = highlighter.codeToThemedTokens(code, typeof lang === 'string' ? lang : lang.id);
// 3. Get shiki theme object
const _theme = highlighter.getTheme();
// 4. Render the theme tokens as html
const html = renderToHtml(tokens, {
themeName: _theme.name,
fg: _theme.fg,
bg: _theme.bg,
elements: {
pre({ className, style, children }) {
// Swap to `code` tag if inline
const tag = inline ? 'code' : 'pre';
// Replace "shiki" class naming with "astro-code"
className = className.replace(/shiki/g, 'astro-code');
// Handle code wrapping
// if wrap=null, do nothing.
if (wrap === false) {
style += '; overflow-x: auto;"';
} else if (wrap === true) {
style += '; overflow-x: auto; white-space: pre-wrap; word-wrap: break-word;"';
}
return `<${tag} class="${className}" style="${style}" tabindex="0">${children}</${tag}>`;
},
code({ children }) {
return inline ? children : `<code>${children}</code>`;
},
},
});
const html = repairShikiTheme(_html);
---

<Fragment set:html={html} />
10 changes: 10 additions & 0 deletions packages/astro/test/astro-component-code.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -100,4 +100,14 @@ describe('<Code>', () => {
expect($('#lang > pre')).to.have.lengthOf(1);
expect($('#lang > pre > code span').length).to.equal(3);
});

it('<Code inline> has no pre tag', async () => {
let html = await fixture.readFile('/inline/index.html');
const $ = cheerio.load(html);
const codeEl = $('.astro-code');

expect(codeEl.prop('tagName')).to.eq('CODE');
expect(codeEl.attr('style')).to.include('background-color:');
expect($('pre')).to.have.lengthOf(0);
});
});
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
---
import {Code} from 'astro/components';
---
<html>
<head><title>Code component</title></head>
<body>
Simple:
<Code code="console.log('inline code');" lang="js" inline />
</body>
</html>

0 comments on commit cac4a32

Please sign in to comment.