Highlighting Haskell with SHJS
by Nicolas Wu
Posted on 14 October 2010
I like to have colourful syntax highlighting, since I find it makes it quicker to read code: a lot of the parsing in my head gets done by simply looking at the colour of some fragment of syntax, and that helps me get the gist of what’s going on quickly.
SHJS
If you want to highlight code for your website, then you might consider using SHJS, a JavaScript program that does syntax highlighting on the client side.
SHJS takes its syntax rules from a GNU Src-Highlite file, and produces JavaScript that marks up your HTML with classes that can then be coloured by a CSS file. This means that any language supported by GNU source-highlight can get highlighted consistently on your website.
There are a number of basic classes that are highlighted by SHJS:
keyword type usertype string regexp specialchar comment number preproc symbol function cbracket predef_var predef_func classname todo
Highlighted Haskell
The Haskell definition file supplied by default has the comment “Quick and dirty Haskell highlight rules for GNU Source-highlight and SHJS”, which doesn’t sound like good news to me. As a result, I’ve written my own haskell.lang file that’s a lot more comprehensive.
To demonstrate how SHJS highlights code, here are a few snippets, some of which come from Johan Tibell’s Haskell Style Guide.
Simple code:
fibs :: [Int]
= fibs' + fibs''
fibs where
= 1 : fibs''
fibs' = 0 : fibs fibs''
Data declarations:
data Tree a = Branch a (Tree a) (Tree a)
| Leaf
Records:
data Person = Person
firstName :: String -- ^ First name
{ lastName :: String -- ^ Last name
, age :: Int -- ^ Age
,deriving (Eq, Show) }
Some do notation:
main :: IO ()
= do putStrLn "Hello World!"
main return ()
A type signature:
div :: Int -> Int -> Int
Language pragmas:
{-# LANGUAGE pragma #-}
id :: a -> a
id x = x
{-# INLINE id #-}
Class definitions:
class Functor f where
fmap :: (a -> b) -> f a -> f b
Constants:
True False 1 0x0010 3.1415 "A string!" 'A'
Comments:
-- None of the following symbols should be parsed as comments:
--> <-- ->- --<-
{- multiple
line
comments {- should allow nesting -} -}
Hopefully the examples above should cover most of the cases you’ll be interested in, but here’s a summary of features of the script I wrote:
- Operators are supported (
++, !, >>=
and any other combination of legal operator characters) - Special symbols are recognised (
=>, <-, ->, ::, ..
) - Unicode support for
→, ←, ∷, ‥,⇒, ∀, ∃
and others - Support for qualified module functions (
List.sort
, etc) - Support for qualified module types
- Support for literate code (using
>
and\begin{code} \end{code}
) - Support for literate specifications (using
<
and\begin{spec} \end{spec}
)
Setup
Setting up SHJS to work on your website should be really easy. You’ll probably need most of these files:
sh_haskell.min.js
andsh_init.min.js
from my github account.sh_main.min.js
from SHJS.- A CSS file from SHJS.
You should include the CSS file in the header of your HTML, and place the scripts at the end of the body, so that they are the last things to load on a page:
<html>
<head>
...
<link rel="stylesheet" type="text/css" href="$root/css/sh_style.min.css" />
...
</head>
<body>
...
<script type="text/javascript" src="$root/js/sh_main.min.js" > </script>
<script type="text/javascript" src="$root/js/sh_haskell.min.js" > </script>
<script type="text/javascript" src="$root/js/sh_init.min.js" > </script>
</body>
</html>
I use Pandoc to generate HTML for me from literate Haskell source.
The problem is that Pandoc encloses haskell code in <pre class="sourceCode literate haskell"><code>
tags,
and for SHJS to work, the class should be sh_haskell
. To fix this I use the
sh_init.min.js
script to change the classes as needed. The sh_init.min.js
file also includes a line that makes the highlighting start, so if you’re generating your own HTML with the sh_haskell
baked in, you won’t need to use sh_init.min.js
, and instead, you should include something like the following line in your code:
<body onload="sh_highlightDocument();">
With these in place, all the Haskell code on your website should get highlighted in browsers with JavaScript enabled. If someone doesn’t have JavaScript enabled, then they’ll get a lightweight version of your site that’s not quite as pretty, but that takes up a lot less space than a statically highlighted file.