-
Download
What is this?
Rainbow is a code syntax highlighting library written in Javascript.
It was designed to be lightweight
(1.4kb), easy to use, and extendable.It is completely themable via CSS.
-
What does it look like?
/* * do some jQuery magic on load */ $(document).ready(function() { function showHiddenParagraphs() { $("p.hidden").fadeIn(500); } setTimeout(showHiddenParagraphs, 1000); }); -
How do I use it?
First include some markup for code you want to be highlighted:
<!-- you can use a code tag or a pre tag* --> <pre><code data-language="python">def openFile(path): file = open(path, "r") content = file.read() file.close() return content</code></pre>After this all you have to do is include a css theme file
<!-- this should go in your <head> --> <link href="/assets/css/theme.css" rel="stylesheet" type="text/css">And include rainbow js + whatever languages you want
<!-- you can create a custom build with specific languages this should go before the closing </body> --> <script src="/assets/js/rainbow.min.js"></script> <script src="/assets/js/language/generic.js"></script> <script src="/assets/js/language/python.js"></script>* Please note that the CSS themes for highlighting depend on having a
<pre>block present. If you want to highlight inline code with language specific patterns then you will have to modify your CSS to support this. -
How does it work?
Rainbow on its own is very simple. It goes through code blocks, processes regex patterns, and wraps matching patterns in
<span>tags. All the theming is left up to CSS.A simple set of language patterns looks like this:
Rainbow.extend('css', [ { 'name': 'comment', 'pattern': /\/\*[\s\S]*?\*\//gm }, { 'name': 'constant.hex-color', 'pattern': /#([a-f0-9]{3}|[a-f0-9]{6})(?=;|\s)/gi }, { 'matches': { 1: 'constant.numeric', 2: 'keyword.unit' }, 'pattern': /(\d+)(px|cm|s|%)?/g } ], true); -
Documentation
Specifying a language
In your markup the
data-languageattribute is used to specify what language to use for highlighting.<pre><code data-language="javascript">var testing = true;</code></pre>On sites such as Tumblr where
<code>tags get stripped you can set the attribute to the<pre>tag.Rainbow API methods
Rainbow has four public methods:
Rainbow.colorThis method is called to highlight all the blocks on the page on load. If you would like to highlight stuff that is not in the DOM you can call it on its own. There are three ways to use it.
One option is adding new code blocks to the DOM and then calling the method again:
// alone Rainbow.color(); // or with a call back Rainbow.color(function() { console.log('the new blocks are now highlighted!'); });Another option is wrapping the code blocks in a div and highlighting before adding it to the DOM:
var div = document.createElement('div'); div.innerHTML = '<p>code:</p><pre><code data-language="javascript">var foo = true;</code></pre>'; Rainbow.color(div, function() { document.getElementById('other_div').appendChild(div); });The third option is to pass a string directly:
Rainbow.color('var foo = true;', 'javascript', function(highlighted_code) { console.log(highlighted_code); });Rainbow.addClassThis method allows you to specify a global CSS class that will be applied to every span that gets created by Rainbow:
Rainbow.addClass('from-rainbow');Rainbow.onHighlightThis method notifies you as soon as a block of code has been highlighted.
Rainbow.onHighlight(function(block, language) { console.log(block, 'for language', language, 'was highlighted'); });The first parameter returns a reference to that code block in the DOM. The second parameter returns a string of the language being highlighted
Rainbow.extendThis method is used to define custom language patterns and to extend existing patterns.
Rainbow.extend('language-name', [ { 'name': 'keyword', 'pattern': /function|return|continue|break/g } ], true);Any pattern used with extend will take precedence over an existing pattern that matches the same block. It will also take precedence over any pattern that is included as part of the generic patterns.
Passing
trueas the third parameter will make it so this language does not inherit any rules from the generic language patterns.If you would like to remove the default boolean values you could do something like this:
Rainbow.extend([ { 'name': '', 'pattern': /true|false/g } ]);When you don't pass in a language name as the first argument in
Rainbow.extend()the patterns are treated as extending the default patterns.The "
name" value determines what classes will be added to the span. For example if you name a pattern 'constant.hex-color' the code that matches will be wrapped in<span class="constant hex-color"></span>. This allows you to share common base style but add more customization in your themes for more specific matches.There are four different ways to match a pattern:
Match by name
Rainbow.extend([ { 'name': 'constant.boolean', 'pattern': /true|false/g } ]);Match by group
Rainbow.extend([ { 'matches': { 1: 'constant.boolean.true', 2: 'constant.boolean.false' }, 'pattern': /(true)|(false)/g } ]);Match by array of sub-patterns
Rainbow.extend([ { 'matches': [ { 'name': 'constant.boolean.true', 'pattern': /true/ }, { 'name': 'constant.boolean.false', 'pattern': /false/ } ], 'pattern': /true|false/g } ]);Match using another language
The following allows php code to be embedded into an HTML block:
Rainbow.extend('html', [ { 'name': 'source.php.embedded', 'matches': { 2: { 'language': 'php' } }, 'pattern': /<\?(php)?([\s\S]*?)(\?>)/gm } ], true);You should be able to nest sub-patterns as many levels deep as you would like.
How Rainbow chooses a match
In general the best practice is to make your patterns as specific as possible (for example targetting specific keywords).
When you create a new language it gets pushed to the front of the generic patterns (unless you bypass them). This means your language rules will always be processed first.
Rainbow chooses the first match it finds for a block. If another pattern overlaps with a pattern that has already been chosen then it is ignored
There is one exception to this. If a match that comes later is more specific (the start AND end points stretch beyond another pattern already matched) then the new match will take precedence and the old one will be discarded.
That means if you have a pattern that matches
function test()and you add a pattern that matchespublic function test()the new one will be used instead.Known issues
Javascript does not allow positive or negative lookbehind assertions so this means it is possible to have conflicts with the starting and end positions of matches. If you want to match a pattern that ends with a specific character it is recommended that you use a positive lookahead for that character instead of including it in the regex. This means that character can be included in the start of another pattern without overlapping.
You cannot currently match using subgroups. You can include subgroups in your regex, and it will work, but you can't explicitly map them to certain classes without using sub-patterns.
-
How can I contribute?
If you would like to contribute or submit a bug check out the project on GitHub.
Download
Select what languages you want to include to build a custom package.
CSS themes are included when you download the development version.
Otherwise they are available here.