Adam Foltzer's Blog

Scheme brush for SyntaxHighlighter

with 6 comments

Last week, I added Alex Gorbatchev’s excellent SyntaxHighlighter to my Blogger template, which is why the code snippets in various posts appear in nice highlighted, scrollable boxes. Using SyntaxHighlighter depends on choosing a correct brush for your code’s syntax; fortunately, there are many brushes included.

However, seeing as it’s very likely I’ll be posting a lot of Scheme code here, I was disappointed by the lack of any Scheme/Lisp/Clojure modes, and decided to throw together my own:

(define foo
  (lambda (x)
    (if (= x 1337) ;; obligatory
        #t
        #| I thought about a bunch of things
        to say in this multi-line comment, but
        none of them were interesting |#
        (begin (printf "Hello world!") 'bar))))

Right now, it highlights keywords based on the core subset of Scheme, as well as some of the more frequent PLT extensions.

The biggest problem I’ve found so far is that it doesn’t recognize new bindings as keywords, e.g., foo in the example above. The Quack emacs mode for Scheme uses lookbehind regular expressions to find these keywords, but JavaScript doesn’t support these. Suggestions are welcome on this!

Here’s the code so far for the Scheme brush. I’ll be submitting it to Alex for inclusion in future releases.

/**
 * Scheme brush for SyntaxHighlighter
 *
 * @copyright
 * Copyright (C) 2010 Adam Foltzer.
 */
;(function()
{
 // CommonJS
 typeof(require) != 'undefined' ? SyntaxHighlighter = require('shCore').SyntaxHighlighter : null;

 function Brush()
 {

  var keywords = 'and begin begin0 c-declare c-lambda call-with-current-continuation ' +
                       'call-with-input-file call-with-output-file call/cc case case-lambda ' +
                       'class class* class*/names class100 class100* compound-unit/sig cond ' +
                       'cond-expand define define-macro define-module define-public ' +
                       'define-signature define-struct define-syntax define-syntax-set ' +
                       'define-values define-values/invoke-unit/sig define/contract ' +
                       'define/override define/private define/public delay do else exit-handler ' +
                       'field if import inherit inherit-field init init-field init-rest ' +
                       'instantiate interface lambda let let* let*-values let+ let-syntax ' +
                       'let-values let/ec letrec letrec-values letrec-syntax match match-lambda ' +
                       'match-lambda* match-let match-let* match-letrec match-define mixin module ' +
                       'opt-lambda or override override* namespace-variable-bind/invoke-unit/sig ' +
                       'parameterize private private* protect provide provide-signature-elements ' +
                       'provide/contract public public* quote receive rename require ' +
                       'require-for-syntax send send* set! set!-values signature-<symbols ' +
                       'super-instantiate syntax-case syntax-case* syntax-error syntax-rules ' +
                       'unit/sig unless when with-handlers with-method with-syntax';

  this.regexList = [
   { regex: new RegExp(';.*', 'g'),                              css: 'comments' },  // one line comments
   { regex: new RegExp('#\\|[\\s\\S]*?\\|#', 'gm'),         css: 'comments' },  // multiline comments
   { regex: new RegExp('\'[^\(\\]\\)\|\\s\)]+', 'g'),                  css: 'constants' },  // symbols
            { regex: /(\s|^)#(?!\|)[^(\]\)|\s)]+/g,                                 css: 'constants' },     // #-preceded constants
   { regex: SyntaxHighlighter.regexLib.doubleQuotedString,     css: 'string' },  // strings
   { regex: new RegExp('\\b([\\d]+(\\.[\\d]+)?|0x[a-f0-9]+)\\b', 'gi'), css: 'value' },   // numbers
   { regex: new RegExp(this.getKeywords(keywords), 'gm'),     css: 'keyword' }  // Scheme keyword
   ];

 }

 Brush.prototype = new SyntaxHighlighter.Highlighter();
 Brush.aliases = ['scheme'];

 SyntaxHighlighter.brushes.Scheme = Brush;

 // CommonJS
 typeof(exports) != 'undefined' ? exports.Brush = Brush : null;
})();

Edit: Updated with working #-preceded constants like #t… whoops!
Edit x2: Double quotes on strings instead of single.

Written by Adam Foltzer

August 20, 2010 at 7:35 pm

Posted in Code

Tagged with , ,

6 Responses

Subscribe to comments with RSS.

  1. I’ve googled this brush. It worked but seems like that there are some problem.
    So, I’m revising the code. Would you mind to check it?
    revising code (in Gist):
    https://gist.github.com/1007407
    test code:
    https://tomesoft.net/blog/?page_id=242

    Junichi OKADOME

    June 3, 2011 at 10:14 pm

  2. Hi, Adam
    Now i have progressed the work, the brush recognizes almost all the R6RS (also includes R5RS) keywords. It has improved to identify S-expression comments, number values, and more.

    And i have prepared a Mercurial repository that based on the alexg’s SyntaxHighlighter;
    https://tomesoft.net/hg/syntaxhighlighter/

    I forgot to say, i’m not a Schemer (just a beginner). So, Could you point out any problem?
    I wish that the brush going to be adopt officially with some efforts. :-)

    Junichi OKADOME

    June 12, 2011 at 2:10 am


Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>