highlight.js 2.1 KB

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