1 | # gatsby-remark-prismjs
|
2 |
|
3 | Adds syntax highlighting to code blocks in markdown files using
|
4 | [PrismJS](http://prismjs.com/).
|
5 |
|
6 | ## Install
|
7 |
|
8 | `npm install gatsby-transformer-remark gatsby-remark-prismjs prismjs`
|
9 |
|
10 | ## How to use
|
11 |
|
12 | ```javascript
|
13 | // In your gatsby-config.js
|
14 | plugins: [
|
15 | {
|
16 | resolve: `gatsby-transformer-remark`,
|
17 | options: {
|
18 | plugins: [
|
19 | {
|
20 | resolve: `gatsby-remark-prismjs`,
|
21 | options: {
|
22 | // Class prefix for <pre> tags containing syntax highlighting;
|
23 | // defaults to 'language-' (e.g. <pre class="language-js">).
|
24 | // If your site loads Prism into the browser at runtime,
|
25 | // (e.g. for use with libraries like react-live),
|
26 | // you may use this to prevent Prism from re-processing syntax.
|
27 | // This is an uncommon use-case though;
|
28 | // If you're unsure, it's best to use the default value.
|
29 | classPrefix: "language-",
|
30 | // This is used to allow setting a language for inline code
|
31 | // (i.e. single backticks) by creating a separator.
|
32 | // This separator is a string and will do no white-space
|
33 | // stripping.
|
34 | // A suggested value for English speakers is the non-ascii
|
35 | // character '›'.
|
36 | inlineCodeMarker: null,
|
37 | // This lets you set up language aliases. For example,
|
38 | // setting this to '{ sh: "bash" }' will let you use
|
39 | // the language "sh" which will highlight using the
|
40 | // bash highlighter.
|
41 | aliases: {},
|
42 | // This toggles the display of line numbers globally alongside the code.
|
43 | // To use it, add the following line in gatsby-browser.js
|
44 | // right after importing the prism color scheme:
|
45 | // require("prismjs/plugins/line-numbers/prism-line-numbers.css")
|
46 | // Defaults to false.
|
47 | // If you wish to only show line numbers on certain code blocks,
|
48 | // leave false and use the {numberLines: true} syntax below
|
49 | showLineNumbers: false,
|
50 | // If setting this to true, the parser won't handle and highlight inline
|
51 | // code used in markdown i.e. single backtick code like `this`.
|
52 | noInlineHighlight: false,
|
53 | // This adds a new language definition to Prism or extend an already
|
54 | // existing language definition. More details on this option can be
|
55 | // found under the header "Add new language definition or extend an
|
56 | // existing language" below.
|
57 | languageExtensions: [
|
58 | {
|
59 | language: "superscript",
|
60 | extend: "javascript",
|
61 | definition: {
|
62 | superscript_types: /(SuperType)/,
|
63 | },
|
64 | insertBefore: {
|
65 | function: {
|
66 | superscript_keywords: /(superif|superelse)/,
|
67 | },
|
68 | },
|
69 | },
|
70 | ],
|
71 | // Customize the prompt used in shell output
|
72 | // Values below are default
|
73 | prompt: {
|
74 | user: "root",
|
75 | host: "localhost",
|
76 | global: false,
|
77 | },
|
78 | // By default the HTML entities <>&'" are escaped.
|
79 | // Add additional HTML escapes by providing a mapping
|
80 | // of HTML entities and their escape value IE: { '}': '{' }
|
81 | escapeEntities: {},
|
82 | },
|
83 | },
|
84 | ],
|
85 | },
|
86 | },
|
87 | ]
|
88 | ```
|
89 |
|
90 | ### Include CSS
|
91 |
|
92 | #### Required: Pick a PrismJS theme or create your own
|
93 |
|
94 | PrismJS ships with a number of [themes][5] (previewable on the [PrismJS
|
95 | website][6]) that you can easily include in your Gatsby site, or you can build
|
96 | your own by copying and modifying an example (which is what we've done for
|
97 | [gatsbyjs.org](https://gatsbyjs.org)).
|
98 |
|
99 | To load a theme, just require its CSS file in your `gatsby-browser.js` file, e.g.
|
100 |
|
101 | ```javascript
|
102 | // gatsby-browser.js
|
103 | require("prismjs/themes/prism-solarizedlight.css")
|
104 | ```
|
105 |
|
106 | #### Optional: Add line highlighting styles
|
107 |
|
108 | If you want to highlight lines of code, you also need to add some additional CSS
|
109 | that targets our _custom line highlighting implementation_ (which slightly
|
110 | differs from PrismJS's own plugin for that – more on that later).
|
111 |
|
112 | For line highlights similar to PrismJS's, try:
|
113 |
|
114 | ```css
|
115 | .gatsby-highlight-code-line {
|
116 | background-color: #feb;
|
117 | display: block;
|
118 | margin-right: -1em;
|
119 | margin-left: -1em;
|
120 | padding-right: 1em;
|
121 | padding-left: 0.75em;
|
122 | border-left: 0.25em solid #f99;
|
123 | }
|
124 | ```
|
125 |
|
126 | This should work out quite nicely for the "Solarized Light" PrismJS theme we
|
127 | just added in the previous part. However, you will notice that when a
|
128 | highlighted line runs wider than the surrounding code block container (causing a
|
129 | horizontal scrollbar), its background won't be drawn for the initially hidden,
|
130 | overflowing part. :(
|
131 |
|
132 | We saw others fix that problem and decided to do so, too. Just add the following
|
133 | CSS along your PrismJS theme and the styles for `.gatsby-highlight-code-line`:
|
134 |
|
135 | ```css
|
136 | /**
|
137 | * Add back the container background-color, border-radius, padding, margin
|
138 | * and overflow that we removed from <pre>.
|
139 | */
|
140 | .gatsby-highlight {
|
141 | background-color: #fdf6e3;
|
142 | border-radius: 0.3em;
|
143 | margin: 0.5em 0;
|
144 | padding: 1em;
|
145 | overflow: auto;
|
146 | }
|
147 |
|
148 | /**
|
149 | * Remove the default PrismJS theme background-color, border-radius, margin,
|
150 | * padding and overflow.
|
151 | * 1. Make the element just wide enough to fit its content.
|
152 | * 2. Always fill the visible space in .gatsby-highlight.
|
153 | * 3. Adjust the position of the line numbers
|
154 | */
|
155 | .gatsby-highlight pre[class*="language-"] {
|
156 | background-color: transparent;
|
157 | margin: 0;
|
158 | padding: 0;
|
159 | overflow: initial;
|
160 | float: left; /* 1 */
|
161 | min-width: 100%; /* 2 */
|
162 | }
|
163 | ```
|
164 |
|
165 | #### Optional: Add line numbering
|
166 |
|
167 | If you want to add line numbering alongside your code, you need to
|
168 | import the corresponding CSS file from PrismJS, right after importing your
|
169 | colorscheme in `gatsby-browser.js`:
|
170 |
|
171 | ```javascript
|
172 | // gatsby-browser.js
|
173 | require("prismjs/plugins/line-numbers/prism-line-numbers.css")
|
174 | ```
|
175 |
|
176 | Then add in the corresponding CSS:
|
177 |
|
178 | ```css
|
179 | /**
|
180 | * If you already use line highlighting
|
181 | */
|
182 |
|
183 | /* Adjust the position of the line numbers */
|
184 | .gatsby-highlight pre[class*="language-"].line-numbers {
|
185 | padding-left: 2.8em;
|
186 | }
|
187 |
|
188 | /**
|
189 | * If you only want to use line numbering
|
190 | */
|
191 |
|
192 | .gatsby-highlight {
|
193 | background-color: #fdf6e3;
|
194 | border-radius: 0.3em;
|
195 | margin: 0.5em 0;
|
196 | padding: 1em;
|
197 | overflow: auto;
|
198 | }
|
199 |
|
200 | .gatsby-highlight pre[class*="language-"].line-numbers {
|
201 | padding: 0;
|
202 | padding-left: 2.8em;
|
203 | overflow: initial;
|
204 | }
|
205 | ```
|
206 |
|
207 | #### Optional: Add shell prompt
|
208 |
|
209 | If you want a fancy prompt on anything with `shell` or `bash`, you need to import
|
210 | the following CSS file in `gatsby-browser.js`:
|
211 |
|
212 | ```javascript
|
213 | // gatsby-browser.js
|
214 | require("prismjs/plugins/command-line/prism-command-line.css")
|
215 | ```
|
216 |
|
217 | If you want to change the resulting prompt, use the following CSS:
|
218 |
|
219 | ```css
|
220 | .command-line-prompt > span:before {
|
221 | color: #999;
|
222 | content: " ";
|
223 | display: block;
|
224 | padding-right: 0.8em;
|
225 | }
|
226 |
|
227 | /* Prompt for all users */
|
228 | .command-line-prompt > span[data-user]:before {
|
229 | content: "[" attr(data-user) "@" attr(data-host) "] $";
|
230 | }
|
231 |
|
232 | /* Prompt for root */
|
233 | .command-line-prompt > span[data-user="root"]:before {
|
234 | content: "[" attr(data-user) "@" attr(data-host) "] #";
|
235 | }
|
236 |
|
237 | .command-line-prompt > span[data-prompt]:before {
|
238 | content: attr(data-prompt);
|
239 | }
|
240 | ```
|
241 |
|
242 | ### Usage in Markdown
|
243 |
|
244 | This is some beautiful code:
|
245 |
|
246 | ```javascript
|
247 | // In your gatsby-config.js
|
248 | plugins: [
|
249 | {
|
250 | resolve: `gatsby-transformer-remark`,
|
251 | options: {
|
252 | plugins: [
|
253 | `gatsby-remark-prismjs`,
|
254 | ]
|
255 | }
|
256 | }
|
257 | ]
|
258 | ```
|
259 |
|
260 | ### Line numbering
|
261 |
|
262 | To see the line numbers alongside your code, you can use the `numberLines` option:
|
263 |
|
264 | ```javascript{numberLines: true}
|
265 | // In your gatsby-config.js
|
266 | plugins: [
|
267 | {
|
268 | resolve: `gatsby-transformer-remark`,
|
269 | options: {
|
270 | plugins: [
|
271 | `gatsby-remark-prismjs`,
|
272 | ]
|
273 | }
|
274 | }
|
275 | ]
|
276 | ```
|
277 |
|
278 | You can also start numbering at any index you wish (here, numbering
|
279 | will start at index 5):
|
280 |
|
281 | ```javascript{numberLines: 5}
|
282 | // In your gatsby-config.js
|
283 | plugins: [
|
284 | {
|
285 | resolve: `gatsby-transformer-remark`,
|
286 | options: {
|
287 | plugins: [
|
288 | `gatsby-remark-prismjs`,
|
289 | ]
|
290 | }
|
291 | }
|
292 | ]
|
293 | ```
|
294 |
|
295 | ### Line highlighting
|
296 |
|
297 | You can also add line highlighting. It adds a span around lines of code with a
|
298 | special class `.gatsby-highlight-code-line` that you can target with styles. See
|
299 | this README for more info.
|
300 |
|
301 | To highlight lines, you can use one of the following directives as comments in your
|
302 | code:
|
303 |
|
304 | - `highlight-line` highlights the current line;
|
305 | - `highlight-next-line` highlights the next line;
|
306 | - `highlight-start` highlights the lines until the matching `hightlight-end`;
|
307 | - `highlight-range{1, 4-6}` will highlight the next line, and the fourth, fifth and sixth lines.
|
308 |
|
309 | ````
|
310 | ```jsx
|
311 | class FlavorForm extends React.Component { // highlight-line
|
312 | constructor(props) {
|
313 | super(props);
|
314 | this.state = {value: 'coconut'};
|
315 |
|
316 | this.handleChange = this.handleChange.bind(this);
|
317 | this.handleSubmit = this.handleSubmit.bind(this);
|
318 | }
|
319 |
|
320 | handleChange(event) {
|
321 | // highlight-next-line
|
322 | this.setState({value: event.target.value});
|
323 | }
|
324 |
|
325 | // highlight-start
|
326 | handleSubmit(event) {
|
327 | alert('Your favorite flavor is: ' + this.state.value);
|
328 | event.preventDefault();
|
329 | }
|
330 | // highlight-end
|
331 |
|
332 | render() {
|
333 | return (
|
334 | { /* highlight-range{1,4-9,12} */ }
|
335 | <form onSubmit={this.handleSubmit}>
|
336 | <label>
|
337 | Pick your favorite flavor:
|
338 | <select value={this.state.value} onChange={this.handleChange}>
|
339 | <option value="grapefruit">Grapefruit</option>
|
340 | <option value="lime">Lime</option>
|
341 | <option value="coconut">Coconut</option>
|
342 | <option value="mango">Mango</option>
|
343 | </select>
|
344 | </label>
|
345 | <input type="submit" value="Submit" />
|
346 | </form>
|
347 | );
|
348 | }
|
349 | }
|
350 | ```
|
351 | ````
|
352 |
|
353 | You can also specify the highlighted lines outside of the code block.
|
354 | In the following code snippet, lines 1 and 4 through 6 will get the line
|
355 | highlighting. The line range parsing is done with
|
356 | <https://www.npmjs.com/package/parse-numeric-range>.
|
357 |
|
358 | ````
|
359 | ```javascript{1,4-6}
|
360 | // In your gatsby-config.js
|
361 | plugins: [
|
362 | {
|
363 | resolve: `gatsby-transformer-remark`,
|
364 | options: {
|
365 | plugins: [
|
366 | `gatsby-remark-prismjs`,
|
367 | ]
|
368 | }
|
369 | }
|
370 | ]
|
371 | ```
|
372 | ````
|
373 |
|
374 | ### Shell prompt
|
375 |
|
376 | To show fancy prompts next to shell commands (only triggers on `bash` and `shell`), either set `prompt.global` to `true` in `gatsby-config.js`,
|
377 | or pass at least one of `{outputLines: <range>}`, `{promptUser: <user>}`, or `{promptHost: <host>}` to a snippet
|
378 |
|
379 | By default, every line gets a prompt appended to the start, this behaviour can be changed by specifying `{outputLines: <range>}`
|
380 | to the language.
|
381 |
|
382 | ````
|
383 | ```shell{outputLines: 2-10,12}
|
384 | ````
|
385 |
|
386 | The user and host used in the appended prompt is pulled from the `prompt.user` and `prompt.host` values,
|
387 | unless explicitly overridden by the `promptUser` and `promptHost` options in the snippet, e.g.:
|
388 |
|
389 | ````
|
390 | ```shell{promptUser: alice}{promptHost: dev.localhost}
|
391 | ````
|
392 |
|
393 | ### Diff code blocks
|
394 |
|
395 | You can specify language for `diff` code blocks by using `diff-[language]` to enable syntax highlighting in diffs:
|
396 |
|
397 | ````
|
398 | ```diff-javascript
|
399 | ````
|
400 |
|
401 | ### Line hiding
|
402 |
|
403 | As well as highlighting lines, it's possible to _hide_ lines from the rendered output. Often this is handy when using `gatsby-remark-prismjs` along with [`gatsby-remark-embed-snippet`](https://www.gatsbyjs.org/packages/gatsby-remark-embed-snippet/).
|
404 |
|
405 | As with highlighting lines, you can control which lines to hide by adding directives as comments in your source code.
|
406 |
|
407 | The available directives are:
|
408 |
|
409 | - `hide-line` hides the current line;
|
410 | - `hide-next-line` hides the next line;
|
411 | - `hide-start` hides the lines until the matching `hide-end`;
|
412 | - `hide-range{1, 4-6}` will hide the next line, and the fourth, fifth and sixth lines.
|
413 |
|
414 | The hide-line directives will always be hidden too. Check out [the using-remark example site](https://using-remark.gatsbyjs.org/embed-snippets/) to see how this looks on a live site.
|
415 |
|
416 | ### Inline code blocks
|
417 |
|
418 | In addition to fenced code blocks, inline code blocks will be passed through
|
419 | PrismJS as well.
|
420 |
|
421 | If you set the `inlineCodeMarker`, then you can also specify a format style.
|
422 |
|
423 | Here's an example of how to use this if the `inlineCodeMarker` was set to `±`:
|
424 |
|
425 | I can highlight `css±.some-class { background-color: red }` with CSS syntax.
|
426 |
|
427 | This will be rendered in a `<code class=language-css>` with just the (syntax
|
428 | highlighted) text of `.some-class { background-color: red }`
|
429 |
|
430 | ### Disabling syntax highlighting
|
431 |
|
432 | If you need to prevent any escaping or highlighting, you can use the `none`
|
433 | language; the inner contents will not be changed at all.
|
434 |
|
435 | ### Add new language definition or extend an existing language
|
436 |
|
437 | You can provide a language extension by giving a single object or an array of
|
438 | language extension objects as the `languageExtensions` option.
|
439 |
|
440 | A language extension object looks like this:
|
441 |
|
442 | ```javascript
|
443 | languageExtensions: [
|
444 | {
|
445 | language: "superscript",
|
446 | extend: "javascript",
|
447 | definition: {
|
448 | superscript_types: /(SuperType)/,
|
449 | },
|
450 | insertBefore: {
|
451 | function: {
|
452 | superscript_keywords: /(superif|superelse)/,
|
453 | },
|
454 | },
|
455 | },
|
456 | ]
|
457 | ```
|
458 |
|
459 | used options:
|
460 |
|
461 | - `language` (optional) The name of the new language.
|
462 | - `extend` (optional) The language you wish to extend.
|
463 | - `definition` (optional) This is the Prism language definition.
|
464 | - `insertBefore` (optional) Is used to define where in the language definition we want to insert our extension.
|
465 |
|
466 | More information of the format can be found here:
|
467 | https://prismjs.com/extending.html
|
468 |
|
469 | Note:
|
470 |
|
471 | - One of the parameters `language` and `extend` is needed.
|
472 | - If only `language` is given, a new language will be defined from scratch.
|
473 | - If only `extend` is given, an extension will be made to the given language.
|
474 | - If both `language` and `extend` is given, a new language that extends the `extend` language will
|
475 | be defined.
|
476 |
|
477 | In case a language is extended, note that the definitions will not be merged.
|
478 | If the extended language definition and the given definition contains the same
|
479 | token, the original pattern will be overwritten.
|
480 |
|
481 | One of the parameters `definition` and `insertBefore` needs to be defined.
|
482 | `insertBefore` needs to be combined with `definition` or `extend` (otherwise
|
483 | there will not be any language definition tokens to insert before).
|
484 |
|
485 | In addition to this extension parameters the css also needs to be updated to
|
486 | get a style for the new tokens. Prism will wrap the matched tokens with a
|
487 | `span` element and give it the classes `token` and the token name you defined.
|
488 | In the example above we would match `superif` and `superelse`. In the html
|
489 | it would result in the following when a match is found:
|
490 |
|
491 | ```html
|
492 | <span class="token superscript_keywords">superif</span>
|
493 | ```
|
494 |
|
495 | ## Implementation notes
|
496 |
|
497 | ### Line highlighting
|
498 |
|
499 | Please note that we do _not_ use PrismJS's
|
500 | [line highlighting plugin](http://prismjs.com/plugins/line-highlight/). Here's
|
501 | why:
|
502 |
|
503 | - [PrismJS plugins][3] assume you're running things client side, but we are
|
504 | _build-time folks_.
|
505 | - PrismJS's line highlighting plugin [implementation][1] does not allow for
|
506 | solid background colors or 100% wide backgrounds that are drawn beyond the
|
507 | _visible part_ of the container when content is overflowing.
|
508 |
|
509 | Our approach follows the [Pygments-based][2] implementation of the [React
|
510 | Tutorial/Documentation][4] for line highlights:
|
511 |
|
512 | - It uses a wrapper element `<div class="gatsby-highlight">` around the
|
513 | PrismJS-formatted `<pre><code>`-blocks.
|
514 | - Highlighted lines are wrapped in `<span class="gatsby-highlight-code-line">`.
|
515 | - We insert a linebreak before the closing tag of `.gatsby-highlight-code-line`
|
516 | so it ends up at the start of the following line.
|
517 |
|
518 | With all of this in place, we can apply `float:left; min-width:100%` to `<pre>`,
|
519 | throw our overflow and background on `.gatsby-highlight`, and use
|
520 | `display:block` on `.gatsby-highlight-code-line` – all of this coming together
|
521 | to facilitate the desired line highlight behavior.
|
522 |
|
523 | ### Line numbering
|
524 |
|
525 | Because [the line numbering PrismJS plugin][7] runs client-side, a few adaptations were required to make it work:
|
526 |
|
527 | - A class `.line-numbers` is dynamically added to the `<pre>` element.
|
528 | - A new node `<span class="line-numbers-rows">` is added right before the closing `</pre>`
|
529 | containing as many empty `<span>`s as there are lines.
|
530 |
|
531 | See the [client-side PrismJS implementation][8] for reference.
|
532 |
|
533 | [1]: https://github.com/PrismJS/prism/tree/8eb0ab6f76484ca47fa7acbf77657fab17b03ca7/plugins/line-highlight
|
534 | [2]: https://github.com/facebook/react/blob/00ba97a354e841701b4b83983c3a3904895e7b87/docs/_config.yml#L10
|
535 | [3]: http://prismjs.com/#plugins
|
536 | [4]: https://reactjs.org/tutorial/tutorial.html
|
537 | [5]: https://github.com/PrismJS/prism/tree/1d5047df37aacc900f8270b1c6215028f6988eb1/themes
|
538 | [6]: http://prismjs.com/
|
539 | [7]: https://prismjs.com/plugins/line-numbers/
|
540 | [8]: https://github.com/PrismJS/prism/blob/master/plugins/line-numbers/prism-line-numbers.js#L69-L115
|