5

I am trying to get the rainbow syntax highlighting library to work with the marked markdown rendering engine. The marked documentation states that a syntax highlighter is supported through the following configuration option:

marked.setOptions({
  highlight: function(code, lang) {
    return highlighter.javascript(code);
  }
});

The rainbow source code indicates that passing in a string to highlight is supported via the following syntax:

Rainbow.color(code, lang, success);

I'm a bit at a loss as to how to put the two together. Specifically, success is a callback that will be called asynchronously, and I can't simply return the value from the Rainbow.color code inside the highlight callback. How would this be accomplished?

user2398029
  • 6,699
  • 8
  • 48
  • 80
  • You need something like http://www.usbfirewire.com/uconverters.html but for CPS transformations... – 6502 Feb 17 '13 at 22:09
  • Cool. Does that have anything to do with `$.Deferred`? – user2398029 Feb 17 '13 at 22:10
  • I don't think so. The problem is that marked seems to require a synchronous syntax highlighter and there's no way to transform an asynchronous one like rainbow in a synchronous one (that's why for example many `node.js` lib functions provide also a "...Synch" version... there's no way to build one from Javascript). See http://stackoverflow.com/q/6842256/320726 – 6502 Feb 17 '13 at 22:14

4 Answers4

9

Author of marked here. I addressed this a while ago on the issue tracker: https://github.com/chjj/marked/issues/47

It's more than possible to use an asynchronous highlighter with marked. You'll just have to iterate over the tokens the lexer spits out.

Example here: https://github.com/chjj/marked/issues/47#issuecomment-5297067 (Keep in mind this is an example. You'll have to modify it a bit.)

I might just implement this natively in marked using the method in the link above. It will be a performance hit to the people using async highlighters, but if you need an async highlighter, that means the highlighter is doing some kind of IO and you're already taking a performance hit.

chjj
  • 14,322
  • 3
  • 32
  • 24
4

You could try using another highlighting library, such as highlight.js - It has synchronous highlighting methods (hljs.highlight(lang, code).value and hljs.highlightAuto(code).value) that you can use in the browser like this:

marked.setOptions({
  highlight: function(code) {
    return hljs.highlightAuto(code).value;
  }
});

Here's a working JsFiddle example.

Daiz
  • 328
  • 2
  • 6
2

Unfortunately there's no way to solve the problem.

marked seems to require a synchronous syntax highlighter, and rainbow is an asynchronous syntax highlighter.

In Javascript there's no way to convert the latter to the former.

This is for example the reason why in node.js for many library functions there are both a synchronous and an asynchronous version. There's no way in Javascript to build a synchronous one given only the asynchronous one because you cannot create a "nested event loop" (in some cases the opposite conversion instead can be done using web workers).

May be it's not difficult to add the synchronous version to rainbow (e.g. by providing beforehand the external resources that it is probably loading asynchronously).

6502
  • 112,025
  • 15
  • 165
  • 265
  • Thanks for the explanations. Looks like it's already been [proposed](https://github.com/ccampbell/rainbow/issues/43), but the [pull request](https://github.com/ccampbell/rainbow/pull/79) has been forgotten. – user2398029 Feb 17 '13 at 22:31
1

Not the perfect solution, but until the synchronous API has been merged into rainbow.js I solved it with the code below:

// ... after marked() has converted the markdown to html 
// (the highlight option of marked should be unchanged!)

// find all <code> elements and go through each
$('body')
     .find('code')
     .each(function() {
            var $code = $(this),
                cls = $code.attr('class'),
                language;

            // no language information at all
            if(typeof cls === 'undefined') {
                return;
            }

            // actually we should also check if a valid "lang-" class 
            // (which is by default set through marked) is given
            language = cls.split('-')[1];

            // add the data-language to the <code> element
            $code.data('language', language);
        });

// let the rainbows shine
Rainbow.color();

This runs client side and uses jQuery.

padakuro
  • 11
  • 1