highlight.js 2.3 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071
  1. const Prism = require('prismjs')
  2. const entities = require('he')
  3. const { readFile } = require('fs/promises')
  4. const path = require('path')
  5. // oof
  6. // I think this is the way to add Prism components that it doesn't include
  7. // in the default build?
  8. global.Prism = Prism
  9. // the / is needed to force it to resolve to the directory
  10. require('prismjs/components/')()
  11. const unhighlightedCodeRx = /<pre><code class="([^"]*)?">([\s\S]*?)<\/code><\/pre>/igm
  12. // eslint-disable-next-line no-shadow
  13. function highlight (lang, code) {
  14. const startTag = `<figure class="highlight ${lang}"><table><tr><td class="code"><pre>`
  15. const endTag = '</pre></td></tr></table></figure>'
  16. let parsedCode = ''
  17. if (Prism.languages[lang]) {
  18. parsedCode = Prism.highlight(code, Prism.languages[lang])
  19. } else {
  20. parsedCode = code
  21. }
  22. return startTag + parsedCode + endTag
  23. }
  24. function prismify (data) {
  25. // eslint-disable-next-line no-param-reassign
  26. data.content = data.content.replace(unhighlightedCodeRx,
  27. // eslint-disable-next-line no-shadow
  28. (_, lang, code) => highlight(lang, entities.decode(code)))
  29. // eslint-disable-next-line no-param-reassign
  30. data.excerpt = data.excerpt.replace(unhighlightedCodeRx,
  31. // eslint-disable-next-line no-shadow
  32. (_, lang, code) => highlight(lang, entities.decode(code)))
  33. return data
  34. }
  35. function code (args, content) {
  36. let lang = ''
  37. if (args[0].startsWith('lang:')) {
  38. lang = args.shift().replace(/^lang:/, '')
  39. }
  40. return highlight(lang, content)
  41. }
  42. async function includeCode (args) {
  43. let lang = ''
  44. if (args[0].startsWith('lang:')) {
  45. lang = args.shift().replace(/^lang:/, '')
  46. }
  47. const file = path.join(hexo.source_dir, hexo.config.code_dir, args.join(' '))
  48. const content = await readFile(file, 'utf8')
  49. return highlight(lang, content.trim())
  50. }
  51. // Highlight as many things as we possibly can
  52. hexo.extend.tag.register('code', code, true)
  53. hexo.extend.tag.register('codeblock', code, true)
  54. hexo.extend.tag.register('include_code', includeCode, { async: true })
  55. hexo.extend.tag.register('include-code', includeCode, { async: true })
  56. // Hexo includes its own code block handling by default which may
  57. // cause the above to miss some things, so do another pass when the page
  58. // is done rendering to pick up any code blocks we may have missed.
  59. hexo.extend.filter.register('after_post_render', prismify)