highlightjs/highlight.js

Support Prism.js grammar parsing but use the Highlight.js HTML/theme pipeline

Open

#3,619 opened on Sep 13, 2022

View on GitHub
 (5 comments) (0 reactions) (0 assignees)JavaScript (3,497 forks)batch import
enhancementgood first issuehelp welcomeparser

Repository metrics

Stars
 (22,960 stars)
PR merge metrics
 (Avg merge 6m) (2 merged PRs in 30d)

Description

Related #2212.

I'm not sure this belongs in core yet, and I don't necessarily want a hard or soft Prism dependency. I suppose perhaps you could also pass Prism into the function itself though so it's late binding?

Caveats

  • Using custom parsers is still private API since the Emitter API is public yet. Hence the __emitTokens name of the property.
  • See #3620

What needs to be done

Example Usage

To replace our JavaScript support with Prism's:

import Prism from 'prismjs'
const prismJS = fromPrism(Prism.languages.javascript)
hljs.registerLanguage("javascript", prismJS)

Code

function prismTypeToScope(name) {
  // very poor results, must be improved
  return name;
}

function prismTokensToEmitter(tokens, emitter) {
  tokens.forEach(token => {
    if (typeof(token) === "string") {
      emitter.addText(token)
    } else if (token.type) {
      let scope = prismTypeToScope(token.type)
      if (typeof(token.content) === "string") {
        emitter.addKeyword(token.content, scope)
      } else { // array of tokens
        emitter.openNode(scope)
        prismTokensToEmitter(token.content, emitter)
        emitter.closeNode()
      }
    }
  })
}

function prismParserWrapper(code, emitter) {
  const tokens = Prism.tokenize(code, this._prism)
  prismTokensToEmitter(tokens, emitter)
}

function fromPrism(prismGrammar) {
  return function(hljs) {
    let self = {}

    Object.assign(self, {
      _prism: prismGrammar,
      __emitTokens: prismParserWrapper.bind(self)
    })
    return self
  }
}

Contributor guide