Ceiling cat is watching you unsafePerformIO

GitHub Haskell colours for GeSHi

GeSHi is the php-based syntax highlighter that I use for this blog. The Haskell highlighting included with GeSHi is a bit below par compared to say GitHub, which uses pygments for highlighting.

Not to be outdone, I though I’d delve in to GeSHi’s regular expression features to see if I could improve upon the default. I struggled a bit with things getting highlighted that had already been processed and matched to an alternate regular expression until I dug in to the GeSHi source to and found out how it escapes potential highlights. This led to some lovely regex like the one below as I attempted to work around things like <PIPE>, <SEMI> and other magical GeSHi escapes like <|!REG3XP1!>.

/<[A-Z]+>|<\|!REG3XP\d*!>.*?\|>/

One I figured this out things got a lot easier and I was able to get to a point that I’m pretty happy with. The symbol highlighting is still a bit hacky and I’d like to get to a point where all non-alphanumeric character groups are highlighted as symbols. For now though I’ve just added a few more (<$>, <|>, etc) to the hardcoded list that comes with GeSHi out of the box. So without any further ado, here are the results.

Before

module Main where
 
import Control.Monad.Identity
import Text.Parsec (ParseError,parse,char,oneOf,(<?>),(<|>))
import Text.Parsec.ByteString
import Text.Parsec.Expr
import qualified Data.ByteString.Char8 as S
 
data Expr = Op Char Expr Expr
          | Value Char
          deriving Show
 
-- This is a comment
main :: IO ()
main = do
  xs <- S.getContents
  let f = S.unlines . translate . (drop 1) . S.lines
  S.putStr $ f xs
  return ()
 
{- This is a multiline
    comment -}
translate :: [S.ByteString] -> [S.ByteString]
translate = map $ f . readExpr
  where f (Left err) = S.pack $ show err
        f (Right val) = showRPN val
 
showRPN :: Expr -> S.ByteString
showRPN (Value v)  = S.singleton v
showRPN (Op o a b) = showRPN a `S.append` showRPN b `S.append` S.singleton o
 
table :: [[Operator S.ByteString st Identity Expr]]
table = [[op '^', op '/', op '*', op '-', op '+']]
  where op c = Infix (liftM Op $ char c) AssocLeft
 
term :: Parser Expr
term = brackets <|> value <?> "term"
 
brackets :: Parser Expr
brackets = char '(' >> expr >>= \x -> char ')' >> return x

After

module Main where
 
import Control.Monad.Identity
import Text.Parsec (ParseError,parse,char,oneOf,(<?>),(<|>))
import Text.Parsec.ByteString
import Text.Parsec.Expr
import qualified Data.ByteString.Char8 as S
 
data Expr = Op Char Expr Expr
          | Value Char
          deriving Show
 
-- This is a comment
main :: IO ()
main = do
  xs <- S.getContents
  let f = S.unlines . translate . (drop 1) . S.lines
  S.putStr $ f xs
  return ()
 
{- This is a multiline
    comment -}
translate :: [S.ByteString] -> [S.ByteString]
translate = map $ f . readExpr
  where f (Left err) = S.pack $ show err
        f (Right val) = showRPN val
 
showRPN :: Expr -> S.ByteString
showRPN (Value v)  = S.singleton v
showRPN (Op o a b) = showRPN a `S.append` showRPN b `S.append` S.singleton o
 
table :: [[Operator S.ByteString st Identity Expr]]
table = [[op '^', op '/', op '*', op '-', op '+']]
  where op c = Infix (liftM Op $ char c) AssocLeft
 
term :: Parser Expr
term = brackets <|> value <?> "term"
 
brackets :: Parser Expr
brackets = char '(' >> expr >>= \x -> char ')' >> return x

You can download my modifications to the Haskell syntax file for GeSHi here. If I get some more time I’ll probably submit it back to the GeSHi project as a replacement or an alternative for Haskell.

One thing to note is that I’ve stripped out the url linking of Prelude functions. I felt that it wasn’t really that useful as I rarely want to know the details of those functions, it’s all the other ones that I want to know about! I toyed with the idea of linking functions and types to Hoogle or Hayoo!, that might be worthwhile in the future.

Download haskell.php

The syntax file above was built and tested on GeSHi 1.0.8.7, it will probably work on other versions, but you never know :)

Leave a comment for: "GitHub Haskell colours for GeSHi"