From:

JavaScript Based Code Prettification

It appears that the recent syntax highlighting enhancementsto Google Code’s source browser are implemented with a slightly modified version of Mike Samuel’s JavaScript Code Prettifier: a 100% browser-side JavaScript/CSS syntax highlighting engine with a sufficiently simple implementation (~750 LOC / 37KB unpacked / 12KB gzipped), a liberal license, and decent language support. The READMEclaims that C (and friends), Java, Python, Bash, SQL, HTML, XML, CSS, JavaScript, and Makefiles are highlighted well and Ruby, PHP, Awk, and Perl are handled passably. As luck would have it, I just went through the process of wiring this script up last week with a few interesting tweaks to get automatic highlighting on all my posts.

The prescribed usage was fairly simple: bring in the stylesheet and external script, add a “prettyprint” class to <pre>and/or <code>blocks, and call prettyPrint()on load/ready.

This setup has a few (easily remedied) drawbacks, however:

  1. Manually adding a “prettyprint” class is a bit of a pain with Markdown since there’s no way to add a class name to a code block.

  2. Manually adding a “prettyprint” class is a bit of a pain because I don’t feel like flipping through looking for every post I’ve ever written with a code block in it.

  3. Adding prettify.jsto a all pages means a 37K download even when no syntax highlighting is required.

  4. The stock stylesheet’s color palette is somewhat lacking.

Making it Automatic

The following wee bit of codeis running on each page to automatically highlight all code blocks on the page. I used jQuerybut this should be easily ported to other JavaScript libraries or standard DOM.

$(document).ready(function() {

    // add prettyprint class to all <pre><code></code></pre> blocks
    var prettify = false;
    $("pre code").parent().each(function() {
        $(this).addClass('prettyprint');
        prettify = true;
    });

    // if code blocks were found, bring in the prettifier ...
    if ( prettify ) {
        $.getScript("/js/prettify.js", function() { prettyPrint() });
    }

}); 

We run through the DOM after a page is fully loaded and look for <code>elements nestled within a <pre>(this is what Markdown puts out for code blocks). We add the “prettyprint” class to each of the <pre>parent elements and note that the prettifier is required. Lastly, we use jQuery’s getScriptmethod to bring in the prettifier but only if we’ve detected that it’s required ( jQuery.getScriptis implemented by appending a <script>tag to <head>).

More Prettier

As a finishing touch, we’ll add a bit of flavor to the highlighting color pallette. There are 10 syntactical elements that can be styled. The meaning of each should be fairly obvious from the abbreviated class name. Here’s what I’m rolling with, at the moment:

.str { color:#181; font-style:italic }
.kwd { color:#369 }
.com { color:#666 }
.typ { color:#c40 }
.lit { color:#900 }
.pun { color:#000; font-weight:bold  }
.pln { color:#333 }
.tag { color:#369; font-weight:bold  }
.atn { color:#939; font-weight:bold  }
.atv { color:#181 }
.dec { color:#606 } 

Examples

And without further ado, here’s a few fibs to get a feel for how well the highlighting works with different languages:

Python:

import sys

# calculate the nth fibonacci number
def fib(n):
  if n < 2:
    return 1
  else:
    return fib(n-2) + fib(n-1)

for i in range(int(sys.argv[1])):
  print "the %dth fibonacci number is %d" % (i, fib(i)) 

Ruby:

# calculate the nth fibonacci number
def fib(n)
  if n < 2
    1
  else
    fib(n-2) + fib(n-1)
  end
end

ARGV[0].to_i.times do |i|
  puts "the #{i}th fibonacci number is #{fib(i)}"
end 

PHP:

<?php
  // calculate the nth fibonacci number
  function fib($n)
  {
      if( $n < 2 )
          return 1;
      else
          return fib($n-2) + fib($n-1);
  }

  for( $i=0; $i < 36; $i++)
  {
       printf("the %d'th fibonacci number is %d\n", $i, fib($i));
  }
?> 

HTML and JavaScript:

<!DOCTYPE html>
<html>
  <head>
    <title>Fibonacci</title>
    <script type='text/javascript'>
      /* calculate the nth fibonacci number */
      function fib(n) {
          if ( n &lt; 2 )
              return 1;
          else
              return fib(n-2) + fib(n-1);
      }

      $(document).ready(function() {
        for(var i = 0; i < 36; i++)
          $("p#output").append("the " + i + "th fibonacci number is " + 
            fib(i) + "\n");
      });
    </script>
  </head>
  <body>
    <pre id='output'></pre>
  </body>
</html> 

Perl:

use strict;
use warnings;

for ( 0..36 ) {
    print "the " . $_ . "th fibonacci number is " . fib($_) . "\n";
}

# calculate the nth fibonacci number
sub fib {
  my $n = shift || 0;
  return 1 if ( $n < 2 );
  return fib( $n-2 ) + fib( $n-1 );
} 

C:

#include <stdio.h>

/* calculate nth fibonacci number */
int fib(int n) {
    if (n < 2)
        return 1;
    return fib(n - 2) + fib(n - 1);
}

int main(int argc, char ** argv) {
    int i = 0;
    for (i = 0, i < atoi(argv[1]), i++)
        printf("the %dth fibonacci number is %d\n", i, fib(i));
    return 0;
} 

Bourne Shell

#!/bin/sh

# calculate the nth fibonacci number
fib() {
  if [ "$1" -lt 2 ]; then
    echo 1
    return 0
  else
    expr $(fib $(expr "$1" - 2)) + $(fib $(expr "$1" - 1))
    return 0
  fi
}

for i in $(seq 1 $1)
do
  printf "the %dth fibonacci number is %d\n" $i $(fib $i)
done 

Not too shabby under Minefield - how’s it look in your browser?

UPDATE: jQuery.getScript Is Cache-Breaking

When loading external scripts dynamically with jQuery’s getScript, a cache bustingparameter is added to the request URL. So, instead of writing something like <script src='/js/foo.js'>, it writes something like <script src='/js/foo.js?_=ts2477874287'>, causing the script to be pulled anew each time. I assume this is so that calling getScriptrepeatedly on a single page causes the script to be executed multiple times.

Boo. In reducing the amount of data fetched for pages that don’t require syntax highlighting, we inadvertently increased the amount of data fetched across multiple pages with highlighting.

Under the hood, the getScriptmethod calls jQuery.ajax, explicitly setting cacheto false. We can turn caching back on by replacing the call to getScriptwith the following:

$.ajax({
  type: 'GET',
  url: '/js/prettify.js',
  cache: true,
  success: function() { prettyPrint() },
  dataType: 'script',
  data: null
}); 

It might actually be easier to bypass jQuery altogether here and just add in the <script>element using basic DOM stuff.

Related Articles

Relatd Projects

olft

1)Have you already been tired of reading the colorless code online?2)Do you want the online code to be shown with line-number,indentation,syntax-highlighting, brace-matching as well as in some developing tools?3)Do you need a transition of a formatted?
oscal
Oscal is a flexible scripting language similar to JavaScript. Oscal allows composers to use hierarchical data structures, function closures, and scheduled blocks of code to sequence Open Sound Control messages.
petty
This project deals with two things. It allows easier and new ways of deployment for existing software by 1. providing an installer and first class desktop integration of Java applications and 2. shrinking the download size. As a first example we do this
bitvector4j
BitVector4J is a general purpose bit array replacement for the standard Java BitSet class. It is more flexible and integrates better with support for streamed input/output, conversion to BitSets and conversion to arrays of int�s, byte�s, or long�s.
autoproxy4j
Currently Java does not support the execution of autoproxy scripts. I wrote some Java code with the help of Mozilla's Rhino (implementation of JavaScript written entirely in Java) to get the result of an autoproxy script.
jssplitter
jsSplitter - toolbox for javascript preprocessing (Concatenates a .js file, or a series of .js files, to a single file .Compress a js code by removing comments,blank spaces,linefeeds .) Include GUI and commandline utility programs,ant task,jsp tag.
yuba
yUba is a programming language for easy Web-application development: (1) yUba creates both client-side code(Javascript) and server-side code(Perl) at once. (2) XML/HTML can be embedded directly in yUba codes without any quotations.
jsuml
JS/UML is a plugin for the Eclipse IDE that reverse-engineers JavaScript code to a UML model which can then be used to generate documentation and other artifacts.
pnx
PNX system develops the middle-ware source code to glue Asterisk with a number of powerful telephony products such as: 1) OpenH323 H.323 stack 2) Vovida SIP stack 3) Bayonne Voice Automation Platform The advantages? An advanced IP PBX supporting the wide
dynapyide
The DynAPI <!-- I D E --> is aimed at being an extensible tool for easy and correct development of dynamic webpages with client-side scripting with focus on the HTML Document Object Model as controlled by ECMA/Javascript.